Core/Maps: Removed MapInstanced - no longer neccessary for grid data reference counting (moved to TerrainInfo)
Port From (https://github.com/TrinityCore/TrinityCore/commit/fbe0b8efebca3bc2662b477bdf45627f9783d6c2)
This commit is contained in:
@@ -575,19 +575,24 @@ namespace Game.Chat
|
||||
[Command("loadcells", RBACPermissions.CommandDebug, true)]
|
||||
static bool HandleDebugLoadCellsCommand(CommandHandler handler, uint? mapId, uint? tileX, uint? tileY)
|
||||
{
|
||||
Map map = null;
|
||||
if (mapId.HasValue)
|
||||
map = Global.MapMgr.FindBaseNonInstanceMap(mapId.Value);
|
||||
else
|
||||
{
|
||||
Player player = handler.GetPlayer();
|
||||
if (player != null)
|
||||
{
|
||||
// Fallback to player's map if no map has been specified
|
||||
map = player.GetMap();
|
||||
}
|
||||
Global.MapMgr.DoForAllMapsWithMapId(mapId.Value, map => HandleDebugLoadCellsCommandHelper(handler, map, tileX, tileY));
|
||||
return true;
|
||||
}
|
||||
|
||||
Player player = handler.GetPlayer();
|
||||
if (player != null)
|
||||
{
|
||||
// Fallback to player's map if no map has been specified
|
||||
return HandleDebugLoadCellsCommandHelper(handler, player.GetMap(), tileX, tileY);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool HandleDebugLoadCellsCommandHelper(CommandHandler handler, Map map, uint? tileX, uint? tileY)
|
||||
{
|
||||
if (!map)
|
||||
return false;
|
||||
|
||||
|
||||
@@ -205,8 +205,8 @@ namespace Game.Chat.Commands
|
||||
else
|
||||
player.SaveRecallPosition(); // save only in non-flight case
|
||||
|
||||
Map map = Global.MapMgr.CreateBaseMap(mapId);
|
||||
float z = Math.Max(map.GetStaticHeight(PhasingHandler.EmptyPhaseShift, x, y, MapConst.MaxHeight), map.GetWaterLevel(PhasingHandler.EmptyPhaseShift, x, y));
|
||||
TerrainInfo terrain = Global.TerrainMgr.LoadTerrain(mapId);
|
||||
float z = Math.Max(terrain.GetStaticHeight(PhasingHandler.EmptyPhaseShift, x, y, MapConst.MaxHeight), terrain.GetWaterLevel(PhasingHandler.EmptyPhaseShift, x, y));
|
||||
|
||||
player.TeleportTo(mapId, x, y, z, player.GetOrientation());
|
||||
return true;
|
||||
@@ -352,8 +352,8 @@ namespace Game.Chat.Commands
|
||||
else
|
||||
player.SaveRecallPosition(); // save only in non-flight case
|
||||
|
||||
Map map = Global.MapMgr.CreateBaseMap(mapId);
|
||||
z = Math.Max(map.GetStaticHeight(PhasingHandler.EmptyPhaseShift, x, y, MapConst.MaxHeight), map.GetWaterLevel(PhasingHandler.EmptyPhaseShift, x, y));
|
||||
TerrainInfo terrain = Global.TerrainMgr.LoadTerrain(mapId);
|
||||
z = Math.Max(terrain.GetStaticHeight(PhasingHandler.EmptyPhaseShift, x, y, MapConst.MaxHeight), terrain.GetWaterLevel(PhasingHandler.EmptyPhaseShift, x, y));
|
||||
|
||||
player.TeleportTo(mapId, x, y, z, 0.0f);
|
||||
return true;
|
||||
@@ -398,8 +398,8 @@ namespace Game.Chat.Commands
|
||||
handler.SendSysMessage(CypherStrings.InvalidTargetCoord, x, y, mapId);
|
||||
return false;
|
||||
}
|
||||
Map map = Global.MapMgr.CreateBaseMap(mapId);
|
||||
z = Math.Max(map.GetStaticHeight(PhasingHandler.EmptyPhaseShift, x, y, MapConst.MaxHeight), map.GetWaterLevel(PhasingHandler.EmptyPhaseShift, x, y));
|
||||
TerrainInfo terrain = Global.TerrainMgr.LoadTerrain(mapId);
|
||||
z = Math.Max(terrain.GetStaticHeight(PhasingHandler.EmptyPhaseShift, x, y, MapConst.MaxHeight), terrain.GetWaterLevel(PhasingHandler.EmptyPhaseShift, x, y));
|
||||
}
|
||||
|
||||
return DoTeleport(handler, new Position(x, y, z.Value, o.Value), mapId);
|
||||
@@ -427,10 +427,10 @@ namespace Game.Chat.Commands
|
||||
x /= 100.0f;
|
||||
y /= 100.0f;
|
||||
|
||||
Map map = Global.MapMgr.CreateBaseMap(zoneEntry.ContinentID);
|
||||
TerrainInfo terrain = Global.TerrainMgr.LoadTerrain(zoneEntry.ContinentID);
|
||||
if (!Global.DB2Mgr.Zone2MapCoordinates(areaEntry.ParentAreaID != 0 ? areaEntry.ParentAreaID : areaId, ref x, ref y))
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.InvalidZoneMap, areaId, areaEntry.AreaName[handler.GetSessionDbcLocale()], map.GetId(), map.GetMapName());
|
||||
handler.SendSysMessage(CypherStrings.InvalidZoneMap, areaId, areaEntry.AreaName[handler.GetSessionDbcLocale()], terrain.GetId(), terrain.GetMapName());
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -446,7 +446,7 @@ namespace Game.Chat.Commands
|
||||
else
|
||||
player.SaveRecallPosition(); // save only in non-flight case
|
||||
|
||||
float z = Math.Max(map.GetStaticHeight(PhasingHandler.EmptyPhaseShift, x, y, MapConst.MaxHeight), map.GetWaterLevel(PhasingHandler.EmptyPhaseShift, x, y));
|
||||
float z = Math.Max(terrain.GetStaticHeight(PhasingHandler.EmptyPhaseShift, x, y, MapConst.MaxHeight), terrain.GetWaterLevel(PhasingHandler.EmptyPhaseShift, x, y));
|
||||
|
||||
player.TeleportTo(zoneEntry.ContinentID, x, y, z, player.GetOrientation());
|
||||
return true;
|
||||
|
||||
@@ -72,27 +72,17 @@ namespace Game.Chat.Commands
|
||||
bool liveFound = false;
|
||||
|
||||
// Get map (only support base map from console)
|
||||
Map thisMap;
|
||||
Map thisMap = null;
|
||||
if (handler.GetSession() != null)
|
||||
thisMap = handler.GetSession().GetPlayer().GetMap();
|
||||
else
|
||||
thisMap = Global.MapMgr.FindBaseNonInstanceMap(mapId);
|
||||
|
||||
// If map found, try to find active version of this creature
|
||||
if (thisMap)
|
||||
{
|
||||
var creBounds = thisMap.GetCreatureBySpawnIdStore().LookupByKey(guid);
|
||||
if (!creBounds.Empty())
|
||||
{
|
||||
foreach (var creature in creBounds)
|
||||
{
|
||||
if (handler.GetSession())
|
||||
handler.SendSysMessage(CypherStrings.CreatureListChat, guid, guid, cInfo.Name, x, y, z, mapId, creature.GetGUID().ToString(), creature.IsAlive() ? "*" : " ");
|
||||
else
|
||||
handler.SendSysMessage(CypherStrings.CreatureListConsole, guid, cInfo.Name, x, y, z, mapId, creature.GetGUID().ToString(), creature.IsAlive() ? "*" : " ");
|
||||
}
|
||||
liveFound = true;
|
||||
}
|
||||
foreach (var creature in creBounds)
|
||||
handler.SendSysMessage(CypherStrings.CreatureListChat, guid, guid, cInfo.Name, x, y, z, mapId, creature.GetGUID().ToString(), creature.IsAlive() ? "*" : " ");
|
||||
liveFound = !creBounds.Empty();
|
||||
}
|
||||
|
||||
if (!liveFound)
|
||||
@@ -422,27 +412,17 @@ namespace Game.Chat.Commands
|
||||
bool liveFound = false;
|
||||
|
||||
// Get map (only support base map from console)
|
||||
Map thisMap;
|
||||
Map thisMap = null;
|
||||
if (handler.GetSession() != null)
|
||||
thisMap = handler.GetSession().GetPlayer().GetMap();
|
||||
else
|
||||
thisMap = Global.MapMgr.FindBaseNonInstanceMap(mapId);
|
||||
|
||||
// If map found, try to find active version of this object
|
||||
if (thisMap)
|
||||
{
|
||||
var goBounds = thisMap.GetGameObjectBySpawnIdStore().LookupByKey(guid);
|
||||
if (!goBounds.Empty())
|
||||
{
|
||||
foreach (var go in goBounds)
|
||||
{
|
||||
if (handler.GetSession())
|
||||
handler.SendSysMessage(CypherStrings.GoListChat, guid, entry, guid, gInfo.name, x, y, z, mapId, go.GetGUID(), go.IsSpawned() ? "*" : " ");
|
||||
else
|
||||
handler.SendSysMessage(CypherStrings.GoListConsole, guid, gInfo.name, x, y, z, mapId, go.GetGUID(), go.IsSpawned() ? "*" : " ");
|
||||
}
|
||||
liveFound = true;
|
||||
}
|
||||
foreach (var go in goBounds)
|
||||
handler.SendSysMessage(CypherStrings.GoListChat, guid, entry, guid, gInfo.name, x, y, z, mapId, go.GetGUID().ToString(), go.IsSpawned() ? "*" : " ");
|
||||
liveFound = !goBounds.Empty();
|
||||
}
|
||||
|
||||
if (!liveFound)
|
||||
|
||||
@@ -1776,7 +1776,7 @@ namespace Game.Entities
|
||||
|
||||
// Check enter rights before map getting to avoid creating instance copy for player
|
||||
// this check not dependent from map instance copy and same for all instance copies of selected map
|
||||
if (Global.MapMgr.PlayerCannotEnter(mapid, this, false) != 0)
|
||||
if (Map.PlayerCannotEnter(mapid, this, false) != 0)
|
||||
return false;
|
||||
|
||||
// Seamless teleport can happen only if cosmetic maps match
|
||||
|
||||
@@ -24,8 +24,7 @@ namespace Game.Garrisons
|
||||
{
|
||||
class GarrisonMap : Map
|
||||
{
|
||||
public GarrisonMap(uint id, long expiry, uint instanceId, Map parent, ObjectGuid owner)
|
||||
: base(id, expiry, instanceId, Difficulty.Normal, parent)
|
||||
public GarrisonMap(uint id, long expiry, uint instanceId, ObjectGuid owner) : base(id, expiry, instanceId, Difficulty.Normal)
|
||||
{
|
||||
_owner = owner;
|
||||
InitVisibilityDistance();
|
||||
|
||||
@@ -274,7 +274,7 @@ namespace Game
|
||||
bool teleported = false;
|
||||
if (player.GetMapId() != at.target_mapId)
|
||||
{
|
||||
EnterState denyReason = Global.MapMgr.PlayerCannotEnter(at.target_mapId, player, false);
|
||||
EnterState denyReason = Map.PlayerCannotEnter(at.target_mapId, player, false);
|
||||
if (denyReason != 0)
|
||||
{
|
||||
bool reviveAtTrigger = false; // should we revive the player if he is trying to enter the correct instance?
|
||||
|
||||
@@ -453,7 +453,7 @@ namespace Game.Maps
|
||||
void _ResetInstance(uint mapid, uint instanceId)
|
||||
{
|
||||
Log.outDebug(LogFilter.Maps, "InstanceSaveMgr._ResetInstance {0}, {1}", mapid, instanceId);
|
||||
Map map = Global.MapMgr.CreateBaseMap(mapid);
|
||||
var map = CliDB.MapStorage.LookupByKey(mapid);
|
||||
if (!map.IsDungeon())
|
||||
return;
|
||||
|
||||
@@ -463,7 +463,7 @@ namespace Game.Maps
|
||||
|
||||
DeleteInstanceFromDB(instanceId); // even if save not loaded
|
||||
|
||||
Map iMap = ((MapInstanced)map).FindInstanceMap(instanceId);
|
||||
Map iMap = Global.MapMgr.FindMap(mapid, instanceId);
|
||||
if (iMap != null)
|
||||
{
|
||||
((InstanceMap)iMap).Reset(InstanceResetMethod.RespawnDelay);
|
||||
@@ -539,27 +539,23 @@ namespace Game.Maps
|
||||
}
|
||||
|
||||
// note: this isn't fast but it's meant to be executed very rarely
|
||||
Map map = Global.MapMgr.CreateBaseMap(mapid); // _not_ include difficulty
|
||||
var instMaps = ((MapInstanced)map).GetInstancedMaps();
|
||||
uint timeLeft;
|
||||
|
||||
foreach (var pair in instMaps)
|
||||
if (mapEntry.IsDungeon())
|
||||
{
|
||||
Map map2 = pair.Value;
|
||||
if (!map2.IsDungeon())
|
||||
continue;
|
||||
|
||||
if (warn)
|
||||
Global.MapMgr.DoForAllMapsWithMapId(mapid, map =>
|
||||
{
|
||||
if (now >= resetTime)
|
||||
timeLeft = 0;
|
||||
else
|
||||
timeLeft = (uint)(resetTime - now);
|
||||
if (warn)
|
||||
{
|
||||
uint timeLeft;
|
||||
if (now >= resetTime)
|
||||
timeLeft = 0;
|
||||
else
|
||||
timeLeft = (uint)(resetTime - now);
|
||||
|
||||
((InstanceMap)map2).SendResetWarnings(timeLeft);
|
||||
}
|
||||
else
|
||||
((InstanceMap)map2).Reset(InstanceResetMethod.Global);
|
||||
((InstanceMap)map).SendResetWarnings(timeLeft);
|
||||
}
|
||||
else
|
||||
((InstanceMap)map).Reset(InstanceResetMethod.Global);
|
||||
});
|
||||
}
|
||||
|
||||
// @todo delete creature/gameobject respawn times even if the maps are not loaded
|
||||
@@ -583,7 +579,6 @@ namespace Game.Maps
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
public long GetResetTimeFor(uint mapid, Difficulty d)
|
||||
{
|
||||
return m_resetTimeByMapDifficulty.LookupByKey(MathFunctions.MakePair64(mapid, (uint)d));
|
||||
@@ -767,4 +762,17 @@ namespace Game.Maps
|
||||
bool m_canReset;
|
||||
bool m_toDelete;
|
||||
}
|
||||
|
||||
public class InstanceTemplate
|
||||
{
|
||||
public uint Parent;
|
||||
public uint ScriptId;
|
||||
}
|
||||
|
||||
public class InstanceBind
|
||||
{
|
||||
public InstanceSave save;
|
||||
public bool perm;
|
||||
public BindExtensionState extendState;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,293 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2012-2020 CypherCore <http://github.com/CypherCore>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
using Framework.Constants;
|
||||
using Game.BattleGrounds;
|
||||
using Game.DataStorage;
|
||||
using Game.Entities;
|
||||
using Game.Garrisons;
|
||||
using Game.Groups;
|
||||
using Game.Scenarios;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Game.Maps
|
||||
{
|
||||
public class MapInstanced : Map
|
||||
{
|
||||
public MapInstanced(uint id, uint expiry) : base(id, expiry, 0, Difficulty.Normal) { }
|
||||
|
||||
public override void InitVisibilityDistance()
|
||||
{
|
||||
if (m_InstancedMaps.Empty())
|
||||
return;
|
||||
//initialize visibility distances for all instance copies
|
||||
foreach (var i in m_InstancedMaps)
|
||||
i.Value.InitVisibilityDistance();
|
||||
}
|
||||
|
||||
public override void Update(uint diff)
|
||||
{
|
||||
base.Update(diff);
|
||||
|
||||
foreach (var pair in m_InstancedMaps.ToList())
|
||||
{
|
||||
if (pair.Value.CanUnload(diff))
|
||||
{
|
||||
if (!DestroyInstance(pair))
|
||||
{
|
||||
//m_unloadTimer
|
||||
}
|
||||
}
|
||||
else
|
||||
pair.Value.Update(diff);
|
||||
}
|
||||
}
|
||||
|
||||
public override void DelayedUpdate(uint t_diff)
|
||||
{
|
||||
foreach (var i in m_InstancedMaps)
|
||||
i.Value.DelayedUpdate(t_diff);
|
||||
|
||||
base.DelayedUpdate(t_diff);
|
||||
}
|
||||
|
||||
public override void UnloadAll()
|
||||
{
|
||||
// Unload instanced maps
|
||||
foreach (var i in m_InstancedMaps)
|
||||
i.Value.UnloadAll();
|
||||
|
||||
m_InstancedMaps.Clear();
|
||||
|
||||
base.UnloadAll();
|
||||
}
|
||||
|
||||
public Map CreateInstanceForPlayer(uint mapId, Player player, uint loginInstanceId = 0)
|
||||
{
|
||||
if (GetId() != mapId || player == null)
|
||||
return null;
|
||||
|
||||
Map map = null;
|
||||
uint newInstanceId; // instanceId of the resulting map
|
||||
|
||||
if (IsBattlegroundOrArena())
|
||||
{
|
||||
// instantiate or find existing bg map for player
|
||||
// the instance id is set in Battlegroundid
|
||||
newInstanceId = player.GetBattlegroundId();
|
||||
if (newInstanceId == 0)
|
||||
return null;
|
||||
|
||||
map = Global.MapMgr.FindMap(mapId, newInstanceId);
|
||||
if (map == null)
|
||||
{
|
||||
Battleground bg = player.GetBattleground();
|
||||
if (bg)
|
||||
map = CreateBattleground(newInstanceId, bg);
|
||||
else
|
||||
{
|
||||
player.TeleportToBGEntryPoint();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(IsDungeon())
|
||||
{
|
||||
InstanceBind pBind = player.GetBoundInstance(GetId(), player.GetDifficultyID(GetEntry()));
|
||||
InstanceSave pSave = pBind != null ? pBind.save : null;
|
||||
|
||||
// priority:
|
||||
// 1. player's permanent bind
|
||||
// 2. player's current instance id if this is at login
|
||||
// 3. group's current bind
|
||||
// 4. player's current bind
|
||||
if (pBind == null || !pBind.perm)
|
||||
{
|
||||
if (loginInstanceId != 0) // if the player has a saved instance id on login, we either use this instance or relocate him out (return null)
|
||||
{
|
||||
map = FindInstanceMap(loginInstanceId);
|
||||
if (map == null && pSave != null && pSave.GetInstanceId() == loginInstanceId)
|
||||
map = CreateInstance(loginInstanceId, pSave, pSave.GetDifficultyID(), player.GetTeamId());
|
||||
return map;
|
||||
}
|
||||
|
||||
InstanceBind groupBind;
|
||||
Group group = player.GetGroup();
|
||||
// use the player's difficulty setting (it may not be the same as the group's)
|
||||
if (group)
|
||||
{
|
||||
groupBind = group.GetBoundInstance(this);
|
||||
if (groupBind != null)
|
||||
{
|
||||
// solo saves should be reset when entering a group's instance
|
||||
player.UnbindInstance(GetId(), player.GetDifficultyID(GetEntry()));
|
||||
pSave = groupBind.save;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (pSave != null)
|
||||
{
|
||||
// solo/perm/group
|
||||
newInstanceId = pSave.GetInstanceId();
|
||||
map = FindInstanceMap(newInstanceId);
|
||||
// it is possible that the save exists but the map doesn't
|
||||
if (map == null)
|
||||
map = CreateInstance(newInstanceId, pSave, pSave.GetDifficultyID(), player.GetTeamId());
|
||||
}
|
||||
else
|
||||
{
|
||||
// if no instanceId via group members or instance saves is found
|
||||
// the instance will be created for the first time
|
||||
newInstanceId = Global.MapMgr.GenerateInstanceId();
|
||||
|
||||
Difficulty diff = player.GetGroup() != null ? player.GetGroup().GetDifficultyID(GetEntry()) : player.GetDifficultyID(GetEntry());
|
||||
//Seems it is now possible, but I do not know if it should be allowed
|
||||
map = FindInstanceMap(newInstanceId);
|
||||
if (map == null)
|
||||
map = CreateInstance(newInstanceId, null, diff, player.GetTeamId());
|
||||
}
|
||||
}
|
||||
else if (IsGarrison())
|
||||
{
|
||||
newInstanceId = (uint)player.GetGUID().GetCounter();
|
||||
map = FindInstanceMap(newInstanceId);
|
||||
if (!map)
|
||||
map = CreateGarrison(newInstanceId, player);
|
||||
}
|
||||
|
||||
return map;
|
||||
}
|
||||
|
||||
InstanceMap CreateInstance(uint InstanceId, InstanceSave save, Difficulty difficulty, int teamId)
|
||||
{
|
||||
lock (_mapLock)
|
||||
{
|
||||
// make sure we have a valid map id
|
||||
MapRecord entry = CliDB.MapStorage.LookupByKey(GetId());
|
||||
if (entry == null)
|
||||
{
|
||||
Log.outError(LogFilter.Maps, "CreateInstance: no record for map {0}", GetId());
|
||||
Cypher.Assert(false);
|
||||
}
|
||||
|
||||
// some instances only have one difficulty
|
||||
Global.DB2Mgr.GetDownscaledMapDifficultyData(GetId(), ref difficulty);
|
||||
|
||||
Log.outDebug(LogFilter.Maps, "MapInstanced.CreateInstance: {0} map instance {1} for {2} created with difficulty {3}", save != null ? "" : "new ", InstanceId, GetId(), difficulty);
|
||||
|
||||
InstanceMap map = new(GetId(), GetGridExpiry(), InstanceId, difficulty, this, teamId);
|
||||
Cypher.Assert(map.IsDungeon());
|
||||
|
||||
map.LoadRespawnTimes();
|
||||
map.LoadCorpseData();
|
||||
|
||||
bool load_data = save != null;
|
||||
map.CreateInstanceData(load_data);
|
||||
InstanceScenario instanceScenario = Global.ScenarioMgr.CreateInstanceScenario(map, teamId);
|
||||
if (instanceScenario != null)
|
||||
map.SetInstanceScenario(instanceScenario);
|
||||
|
||||
if (WorldConfig.GetBoolValue(WorldCfg.InstancemapLoadGrids))
|
||||
map.LoadAllCells();
|
||||
|
||||
m_InstancedMaps[InstanceId] = map;
|
||||
return map;
|
||||
}
|
||||
}
|
||||
|
||||
BattlegroundMap CreateBattleground(uint InstanceId, Battleground bg)
|
||||
{
|
||||
lock (_mapLock)
|
||||
{
|
||||
Log.outDebug(LogFilter.Maps, "MapInstanced.CreateBattleground: map bg {0} for {1} created.", InstanceId, GetId());
|
||||
|
||||
BattlegroundMap map = new(GetId(), (uint)GetGridExpiry(), InstanceId, this, Difficulty.None);
|
||||
Cypher.Assert(map.IsBattlegroundOrArena());
|
||||
map.SetBG(bg);
|
||||
bg.SetBgMap(map);
|
||||
|
||||
m_InstancedMaps[InstanceId] = map;
|
||||
return map;
|
||||
}
|
||||
}
|
||||
|
||||
GarrisonMap CreateGarrison(uint instanceId, Player owner)
|
||||
{
|
||||
lock (_mapLock)
|
||||
{
|
||||
GarrisonMap map = new(GetId(), GetGridExpiry(), instanceId, this, owner.GetGUID());
|
||||
Cypher.Assert(map.IsGarrison());
|
||||
|
||||
m_InstancedMaps[instanceId] = map;
|
||||
return map;
|
||||
}
|
||||
}
|
||||
|
||||
bool DestroyInstance(KeyValuePair<uint, Map> pair)
|
||||
{
|
||||
pair.Value.RemoveAllPlayers();
|
||||
if (pair.Value.HavePlayers())
|
||||
return false;
|
||||
|
||||
pair.Value.UnloadAll();
|
||||
// should only unload VMaps if this is the last instance and grid unloading is enabled
|
||||
if (m_InstancedMaps.Count <= 1 && WorldConfig.GetBoolValue(WorldCfg.GridUnload))
|
||||
{
|
||||
Global.VMapMgr.UnloadMap(pair.Value.GetId());
|
||||
Global.MMapMgr.UnloadMap(pair.Value.GetId());
|
||||
// in that case, unload grids of the base map, too
|
||||
// so in the next map creation, (EnsureGridCreated actually) VMaps will be reloaded
|
||||
base.UnloadAll();
|
||||
}
|
||||
|
||||
// Free up the instance id and allow it to be reused for bgs and arenas (other instances are handled in the InstanceSaveMgr)
|
||||
if (pair.Value.IsBattlegroundOrArena())
|
||||
Global.MapMgr.FreeInstanceId(pair.Value.GetInstanceId());
|
||||
|
||||
// erase map
|
||||
pair.Value.Dispose();
|
||||
m_InstancedMaps.Remove(pair.Key);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public override EnterState CannotEnter(Player player) { return EnterState.CanEnter; }
|
||||
|
||||
public Map FindInstanceMap(uint instanceId)
|
||||
{
|
||||
return m_InstancedMaps.LookupByKey(instanceId);
|
||||
}
|
||||
|
||||
public Dictionary<uint, Map> GetInstancedMaps() { return m_InstancedMaps; }
|
||||
|
||||
Dictionary<uint, Map> m_InstancedMaps = new();
|
||||
}
|
||||
|
||||
public class InstanceTemplate
|
||||
{
|
||||
public uint Parent;
|
||||
public uint ScriptId;
|
||||
}
|
||||
|
||||
public class InstanceBind
|
||||
{
|
||||
public InstanceSave save;
|
||||
public bool perm;
|
||||
public BindExtensionState extendState;
|
||||
}
|
||||
}
|
||||
+194
-131
@@ -37,7 +37,7 @@ namespace Game.Maps
|
||||
{
|
||||
public class Map : IDisposable
|
||||
{
|
||||
public Map(uint id, long expiry, uint instanceId, Difficulty spawnmode, Map parent = null)
|
||||
public Map(uint id, long expiry, uint instanceId, Difficulty spawnmode)
|
||||
{
|
||||
i_mapRecord = CliDB.MapStorage.LookupByKey(id);
|
||||
i_spawnMode = spawnmode;
|
||||
@@ -227,14 +227,6 @@ namespace Game.Maps
|
||||
}
|
||||
|
||||
void EnsureGridCreated(GridCoord p)
|
||||
{
|
||||
lock (_gridLock)
|
||||
{
|
||||
EnsureGridCreated_i(p);
|
||||
}
|
||||
}
|
||||
|
||||
void EnsureGridCreated_i(GridCoord p)
|
||||
{
|
||||
if (GetGrid(p.X_coord, p.Y_coord) == null)
|
||||
{
|
||||
@@ -1662,6 +1654,93 @@ namespace Game.Maps
|
||||
return result;
|
||||
}
|
||||
|
||||
public static EnterState PlayerCannotEnter(uint mapid, Player player, bool loginCheck)
|
||||
{
|
||||
var entry = CliDB.MapStorage.LookupByKey(mapid);
|
||||
if (entry == null)
|
||||
return EnterState.CannotEnterNoEntry;
|
||||
|
||||
if (!entry.IsDungeon())
|
||||
return EnterState.CanEnter;
|
||||
|
||||
Difficulty targetDifficulty, requestedDifficulty;
|
||||
targetDifficulty = requestedDifficulty = player.GetDifficultyID(entry);
|
||||
// Get the highest available difficulty if current setting is higher than the instance allows
|
||||
var mapDiff = Global.DB2Mgr.GetDownscaledMapDifficultyData(mapid, ref targetDifficulty);
|
||||
if (mapDiff == null)
|
||||
return EnterState.CannotEnterDifficultyUnavailable;
|
||||
|
||||
//Bypass checks for GMs
|
||||
if (player.IsGameMaster())
|
||||
return EnterState.CanEnter;
|
||||
|
||||
//Other requirements
|
||||
if (!player.Satisfy(Global.ObjectMgr.GetAccessRequirement(mapid, targetDifficulty), mapid, true))
|
||||
return EnterState.CannotEnterUnspecifiedReason;
|
||||
|
||||
string mapName = entry.MapName[Global.WorldMgr.GetDefaultDbcLocale()];
|
||||
|
||||
Group group = player.GetGroup();
|
||||
if (entry.IsRaid() && (int)entry.Expansion() >= WorldConfig.GetIntValue(WorldCfg.Expansion)) // can only enter in a raid group but raids from old expansion don't need a group
|
||||
if ((!group || !group.IsRaidGroup()) && !WorldConfig.GetBoolValue(WorldCfg.InstanceIgnoreRaid))
|
||||
return EnterState.CannotEnterNotInRaid;
|
||||
|
||||
if (!player.IsAlive())
|
||||
{
|
||||
if (player.HasCorpse())
|
||||
{
|
||||
// let enter in ghost mode in instance that connected to inner instance with corpse
|
||||
uint corpseMap = player.GetCorpseLocation().GetMapId();
|
||||
do
|
||||
{
|
||||
if (corpseMap == mapid)
|
||||
break;
|
||||
|
||||
InstanceTemplate corpseInstance = Global.ObjectMgr.GetInstanceTemplate(corpseMap);
|
||||
corpseMap = corpseInstance != null ? corpseInstance.Parent : 0;
|
||||
} while (corpseMap != 0);
|
||||
|
||||
if (corpseMap == 0)
|
||||
return EnterState.CannotEnterCorpseInDifferentInstance;
|
||||
|
||||
Log.outDebug(LogFilter.Maps, $"MAP: Player '{player.GetName()}' has corpse in instance '{mapName}' and can enter.");
|
||||
}
|
||||
else
|
||||
Log.outDebug(LogFilter.Maps, $"Map::CanPlayerEnter - player '{player.GetName()}' is dead but does not have a corpse!");
|
||||
}
|
||||
|
||||
//Get instance where player's group is bound & its map
|
||||
if (!loginCheck && group)
|
||||
{
|
||||
InstanceBind boundInstance = group.GetBoundInstance(entry);
|
||||
if (boundInstance != null && boundInstance.save != null)
|
||||
{
|
||||
Map boundMap = Global.MapMgr.FindMap(mapid, boundInstance.save.GetInstanceId());
|
||||
if (boundMap != null)
|
||||
{
|
||||
EnterState denyReason = boundMap.CannotEnter(player);
|
||||
if (denyReason != 0)
|
||||
return denyReason;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// players are only allowed to enter 5 instances per hour
|
||||
if (entry.IsDungeon() && (!player.GetGroup() || (player.GetGroup() && !player.GetGroup().IsLFGGroup())))
|
||||
{
|
||||
uint instanceIdToCheck = 0;
|
||||
InstanceSave save = player.GetInstanceSave(mapid);
|
||||
if (save != null)
|
||||
instanceIdToCheck = save.GetInstanceId();
|
||||
|
||||
// instanceId can never be 0 - will not be found
|
||||
if (!player.CheckInstanceCount(instanceIdToCheck) && !player.IsDead())
|
||||
return EnterState.CannotEnterTooManyInstances;
|
||||
}
|
||||
|
||||
return EnterState.CanEnter;
|
||||
}
|
||||
|
||||
public string GetMapName()
|
||||
{
|
||||
return i_mapRecord.MapName[Global.WorldMgr.GetDefaultDbcLocale()];
|
||||
@@ -3328,7 +3407,6 @@ namespace Game.Maps
|
||||
return _corpsesByPlayer.LookupByKey(ownerGuid);
|
||||
}
|
||||
|
||||
public MapInstanced ToMapInstanced() { return Instanceable() ? (this as MapInstanced) : null; }
|
||||
public InstanceMap ToInstanceMap() { return IsDungeon() ? (this as InstanceMap) : null; }
|
||||
public BattlegroundMap ToBattlegroundMap() { return IsBattlegroundOrArena() ? (this as BattlegroundMap) : null; }
|
||||
|
||||
@@ -4601,12 +4679,10 @@ namespace Game.Maps
|
||||
Global.MapMgr.DecreaseScheduledScriptCount();
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Fields
|
||||
internal object _mapLock = new();
|
||||
object _gridLock = new();
|
||||
|
||||
bool _creatureToMoveLock;
|
||||
List<Creature> creaturesToMove = new();
|
||||
@@ -4677,8 +4753,7 @@ namespace Game.Maps
|
||||
|
||||
public class InstanceMap : Map
|
||||
{
|
||||
public InstanceMap(uint id, long expiry, uint InstanceId, Difficulty spawnMode, Map parent, int instanceTeam)
|
||||
: base(id, expiry, InstanceId, spawnMode, parent)
|
||||
public InstanceMap(uint id, long expiry, uint InstanceId, Difficulty spawnMode, int instanceTeam) : base(id, expiry, InstanceId, spawnMode)
|
||||
{
|
||||
scriptTeam = instanceTeam;
|
||||
|
||||
@@ -4734,133 +4809,123 @@ namespace Game.Maps
|
||||
|
||||
public override bool AddPlayerToMap(Player player, bool initPlayer = true)
|
||||
{
|
||||
// @todo Not sure about checking player level: already done in HandleAreaTriggerOpcode
|
||||
// GMs still can teleport player in instance.
|
||||
// Is it needed?
|
||||
lock (_mapLock)
|
||||
Group group = player.GetGroup();
|
||||
|
||||
// increase current instances (hourly limit)
|
||||
if (!group || !group.IsLFGGroup())
|
||||
player.AddInstanceEnterTime(GetInstanceId(), GameTime.GetGameTime());
|
||||
|
||||
// get or create an instance save for the map
|
||||
InstanceSave mapSave = Global.InstanceSaveMgr.GetInstanceSave(GetInstanceId());
|
||||
if (mapSave == null)
|
||||
{
|
||||
// Dungeon only code
|
||||
if (IsDungeon())
|
||||
Log.outInfo(LogFilter.Maps, "InstanceMap.Add: creating instance save for map {0} spawnmode {1} with instance id {2}", GetId(), GetDifficultyID(), GetInstanceId());
|
||||
mapSave = Global.InstanceSaveMgr.AddInstanceSave(GetId(), GetInstanceId(), GetDifficultyID(), 0, 0, true);
|
||||
}
|
||||
|
||||
Cypher.Assert(mapSave != null);
|
||||
|
||||
// check for existing instance binds
|
||||
InstanceBind playerBind = player.GetBoundInstance(GetId(), GetDifficultyID());
|
||||
if (playerBind != null && playerBind.perm)
|
||||
{
|
||||
// cannot enter other instances if bound permanently
|
||||
if (playerBind.save != mapSave)
|
||||
{
|
||||
Group group = player.GetGroup();
|
||||
|
||||
// increase current instances (hourly limit)
|
||||
if (!group || !group.IsLFGGroup())
|
||||
player.AddInstanceEnterTime(GetInstanceId(), GameTime.GetGameTime());
|
||||
|
||||
// get or create an instance save for the map
|
||||
InstanceSave mapSave = Global.InstanceSaveMgr.GetInstanceSave(GetInstanceId());
|
||||
if (mapSave == null)
|
||||
Log.outError(LogFilter.Maps, "InstanceMap.Add: player {0}({1}) is permanently bound to instance {2} {3}, {4}, {5}, {6}, {7}, {8} but he is being put into instance {9} {10}, {11}, {12}, {13}, {14}, {15}",
|
||||
player.GetName(), player.GetGUID().ToString(), GetMapName(), playerBind.save.GetMapId(),
|
||||
playerBind.save.GetInstanceId(), playerBind.save.GetDifficultyID(),
|
||||
playerBind.save.GetPlayerCount(), playerBind.save.GetGroupCount(),
|
||||
playerBind.save.CanReset(), GetMapName(), mapSave.GetMapId(), mapSave.GetInstanceId(),
|
||||
mapSave.GetDifficultyID(), mapSave.GetPlayerCount(), mapSave.GetGroupCount(),
|
||||
mapSave.CanReset());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (group)
|
||||
{
|
||||
// solo saves should have been reset when the map was loaded
|
||||
InstanceBind groupBind = group.GetBoundInstance(this);
|
||||
if (playerBind != null && playerBind.save != mapSave)
|
||||
{
|
||||
Log.outInfo(LogFilter.Maps, "InstanceMap.Add: creating instance save for map {0} spawnmode {1} with instance id {2}", GetId(), GetDifficultyID(), GetInstanceId());
|
||||
mapSave = Global.InstanceSaveMgr.AddInstanceSave(GetId(), GetInstanceId(), GetDifficultyID(), 0, 0, true);
|
||||
}
|
||||
|
||||
Cypher.Assert(mapSave != null);
|
||||
|
||||
// check for existing instance binds
|
||||
InstanceBind playerBind = player.GetBoundInstance(GetId(), GetDifficultyID());
|
||||
if (playerBind != null && playerBind.perm)
|
||||
{
|
||||
// cannot enter other instances if bound permanently
|
||||
if (playerBind.save != mapSave)
|
||||
{
|
||||
Log.outError(LogFilter.Maps, "InstanceMap.Add: player {0}({1}) is permanently bound to instance {2} {3}, {4}, {5}, {6}, {7}, {8} but he is being put into instance {9} {10}, {11}, {12}, {13}, {14}, {15}",
|
||||
player.GetName(), player.GetGUID().ToString(), GetMapName(), playerBind.save.GetMapId(),
|
||||
playerBind.save.GetInstanceId(), playerBind.save.GetDifficultyID(),
|
||||
playerBind.save.GetPlayerCount(), playerBind.save.GetGroupCount(),
|
||||
playerBind.save.CanReset(), GetMapName(), mapSave.GetMapId(), mapSave.GetInstanceId(),
|
||||
mapSave.GetDifficultyID(), mapSave.GetPlayerCount(), mapSave.GetGroupCount(),
|
||||
mapSave.CanReset());
|
||||
return false;
|
||||
}
|
||||
Log.outError(LogFilter.Maps,
|
||||
"InstanceMapAdd: player {0}({1}) is being put into instance {2} {3}, {4}, {5}, {6}, {7}, {8} but he is in group {9} and is bound to instance {10}, {11}, {12}, {13}, {14}, {15}!",
|
||||
player.GetName(), player.GetGUID().ToString(), GetMapName(), mapSave.GetMapId(), mapSave.GetInstanceId(),
|
||||
mapSave.GetDifficultyID(), mapSave.GetPlayerCount(), mapSave.GetGroupCount(),
|
||||
mapSave.CanReset(), group.GetLeaderGUID().ToString(),
|
||||
playerBind.save.GetMapId(), playerBind.save.GetInstanceId(),
|
||||
playerBind.save.GetDifficultyID(), playerBind.save.GetPlayerCount(),
|
||||
playerBind.save.GetGroupCount(), playerBind.save.CanReset());
|
||||
if (groupBind != null)
|
||||
Log.outError(LogFilter.Maps,
|
||||
"InstanceMap.Add: the group is bound to the instance {0} {1}, {2}, {3}, {4}, {5}, {6}",
|
||||
GetMapName(), groupBind.save.GetMapId(), groupBind.save.GetInstanceId(),
|
||||
groupBind.save.GetDifficultyID(), groupBind.save.GetPlayerCount(),
|
||||
groupBind.save.GetGroupCount(), groupBind.save.CanReset());
|
||||
Cypher.Assert(false);
|
||||
return false;
|
||||
}
|
||||
// bind to the group or keep using the group save
|
||||
if (groupBind == null)
|
||||
group.BindToInstance(mapSave, false);
|
||||
else
|
||||
{
|
||||
if (group)
|
||||
// cannot jump to a different instance without resetting it
|
||||
if (groupBind.save != mapSave)
|
||||
{
|
||||
// solo saves should have been reset when the map was loaded
|
||||
InstanceBind groupBind = group.GetBoundInstance(this);
|
||||
if (playerBind != null && playerBind.save != mapSave)
|
||||
{
|
||||
Log.outError(LogFilter.Maps,
|
||||
"InstanceMapAdd: player {0}({1}) is being put into instance {2} {3}, {4}, {5}, {6}, {7}, {8} but he is in group {9} and is bound to instance {10}, {11}, {12}, {13}, {14}, {15}!",
|
||||
player.GetName(), player.GetGUID().ToString(), GetMapName(), mapSave.GetMapId(), mapSave.GetInstanceId(),
|
||||
mapSave.GetDifficultyID(), mapSave.GetPlayerCount(), mapSave.GetGroupCount(),
|
||||
mapSave.CanReset(), group.GetLeaderGUID().ToString(),
|
||||
playerBind.save.GetMapId(), playerBind.save.GetInstanceId(),
|
||||
playerBind.save.GetDifficultyID(), playerBind.save.GetPlayerCount(),
|
||||
playerBind.save.GetGroupCount(), playerBind.save.CanReset());
|
||||
if (groupBind != null)
|
||||
Log.outError(LogFilter.Maps,
|
||||
"InstanceMap.Add: the group is bound to the instance {0} {1}, {2}, {3}, {4}, {5}, {6}",
|
||||
GetMapName(), groupBind.save.GetMapId(), groupBind.save.GetInstanceId(),
|
||||
groupBind.save.GetDifficultyID(), groupBind.save.GetPlayerCount(),
|
||||
groupBind.save.GetGroupCount(), groupBind.save.CanReset());
|
||||
Cypher.Assert(false);
|
||||
return false;
|
||||
}
|
||||
// bind to the group or keep using the group save
|
||||
if (groupBind == null)
|
||||
group.BindToInstance(mapSave, false);
|
||||
Log.outError(LogFilter.Maps,
|
||||
"InstanceMap.Add: player {0}({1}) is being put into instance {2}, {3}, {4} but he is in group {5} which is bound to instance {6}, {7}, {8}!",
|
||||
player.GetName(), player.GetGUID().ToString(), mapSave.GetMapId(), mapSave.GetInstanceId(),
|
||||
mapSave.GetDifficultyID(), group.GetLeaderGUID().ToString(),
|
||||
groupBind.save.GetMapId(), groupBind.save.GetInstanceId(),
|
||||
groupBind.save.GetDifficultyID());
|
||||
Log.outError(LogFilter.Maps, "MapSave players: {0}, group count: {1}",
|
||||
mapSave.GetPlayerCount(), mapSave.GetGroupCount());
|
||||
if (groupBind.save != null)
|
||||
Log.outError(LogFilter.Maps, "GroupBind save players: {0}, group count: {1}",
|
||||
groupBind.save.GetPlayerCount(), groupBind.save.GetGroupCount());
|
||||
else
|
||||
{
|
||||
// cannot jump to a different instance without resetting it
|
||||
if (groupBind.save != mapSave)
|
||||
{
|
||||
Log.outError(LogFilter.Maps,
|
||||
"InstanceMap.Add: player {0}({1}) is being put into instance {2}, {3}, {4} but he is in group {5} which is bound to instance {6}, {7}, {8}!",
|
||||
player.GetName(), player.GetGUID().ToString(), mapSave.GetMapId(), mapSave.GetInstanceId(),
|
||||
mapSave.GetDifficultyID(), group.GetLeaderGUID().ToString(),
|
||||
groupBind.save.GetMapId(), groupBind.save.GetInstanceId(),
|
||||
groupBind.save.GetDifficultyID());
|
||||
Log.outError(LogFilter.Maps, "MapSave players: {0}, group count: {1}",
|
||||
mapSave.GetPlayerCount(), mapSave.GetGroupCount());
|
||||
if (groupBind.save != null)
|
||||
Log.outError(LogFilter.Maps, "GroupBind save players: {0}, group count: {1}",
|
||||
groupBind.save.GetPlayerCount(), groupBind.save.GetGroupCount());
|
||||
else
|
||||
Log.outError(LogFilter.Maps, "GroupBind save NULL");
|
||||
return false;
|
||||
}
|
||||
// if the group/leader is permanently bound to the instance
|
||||
// players also become permanently bound when they enter
|
||||
if (groupBind.perm)
|
||||
{
|
||||
PendingRaidLock pendingRaidLock = new();
|
||||
pendingRaidLock.TimeUntilLock = 60000;
|
||||
pendingRaidLock.CompletedMask = i_data != null ? i_data.GetCompletedEncounterMask() : 0;
|
||||
pendingRaidLock.Extending = false;
|
||||
pendingRaidLock.WarningOnly = false; // events it throws: 1 : INSTANCE_LOCK_WARNING 0 : INSTANCE_LOCK_STOP / INSTANCE_LOCK_START
|
||||
player.SendPacket(pendingRaidLock);
|
||||
player.SetPendingBind(mapSave.GetInstanceId(), 60000);
|
||||
}
|
||||
}
|
||||
Log.outError(LogFilter.Maps, "GroupBind save NULL");
|
||||
return false;
|
||||
}
|
||||
else
|
||||
// if the group/leader is permanently bound to the instance
|
||||
// players also become permanently bound when they enter
|
||||
if (groupBind.perm)
|
||||
{
|
||||
// set up a solo bind or continue using it
|
||||
if (playerBind == null)
|
||||
player.BindToInstance(mapSave, false);
|
||||
else
|
||||
// cannot jump to a different instance without resetting it
|
||||
Cypher.Assert(playerBind.save == mapSave);
|
||||
PendingRaidLock pendingRaidLock = new();
|
||||
pendingRaidLock.TimeUntilLock = 60000;
|
||||
pendingRaidLock.CompletedMask = i_data != null ? i_data.GetCompletedEncounterMask() : 0;
|
||||
pendingRaidLock.Extending = false;
|
||||
pendingRaidLock.WarningOnly = false; // events it throws: 1 : INSTANCE_LOCK_WARNING 0 : INSTANCE_LOCK_STOP / INSTANCE_LOCK_START
|
||||
player.SendPacket(pendingRaidLock);
|
||||
player.SetPendingBind(mapSave.GetInstanceId(), 60000);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// for normal instances cancel the reset schedule when the
|
||||
// first player enters (no players yet)
|
||||
SetResetSchedule(false);
|
||||
|
||||
Log.outInfo(LogFilter.Maps, "MAP: Player '{0}' entered instance '{1}' of map '{2}'", player.GetName(),
|
||||
GetInstanceId(), GetMapName());
|
||||
// initialize unload state
|
||||
m_unloadTimer = 0;
|
||||
m_resetAfterUnload = false;
|
||||
m_unloadWhenEmpty = false;
|
||||
else
|
||||
{
|
||||
// set up a solo bind or continue using it
|
||||
if (playerBind == null)
|
||||
player.BindToInstance(mapSave, false);
|
||||
else
|
||||
// cannot jump to a different instance without resetting it
|
||||
Cypher.Assert(playerBind.save == mapSave);
|
||||
}
|
||||
}
|
||||
|
||||
// for normal instances cancel the reset schedule when the
|
||||
// first player enters (no players yet)
|
||||
SetResetSchedule(false);
|
||||
|
||||
Log.outInfo(LogFilter.Maps, "MAP: Player '{0}' entered instance '{1}' of map '{2}'", player.GetName(),
|
||||
GetInstanceId(), GetMapName());
|
||||
// initialize unload state
|
||||
m_unloadTimer = 0;
|
||||
m_resetAfterUnload = false;
|
||||
m_unloadWhenEmpty = false;
|
||||
|
||||
// this will acquire the same mutex so it cannot be in the previous block
|
||||
base.AddPlayerToMap(player, initPlayer);
|
||||
|
||||
@@ -5146,8 +5211,8 @@ namespace Game.Maps
|
||||
|
||||
public class BattlegroundMap : Map
|
||||
{
|
||||
public BattlegroundMap(uint id, uint expiry, uint InstanceId, Map _parent, Difficulty spawnMode)
|
||||
: base(id, expiry, InstanceId, spawnMode, _parent)
|
||||
public BattlegroundMap(uint id, uint expiry, uint InstanceId, Difficulty spawnMode)
|
||||
: base(id, expiry, InstanceId, spawnMode)
|
||||
{
|
||||
InitVisibilityDistance();
|
||||
}
|
||||
@@ -5175,9 +5240,7 @@ namespace Game.Maps
|
||||
|
||||
public override bool AddPlayerToMap(Player player, bool initPlayer = true)
|
||||
{
|
||||
lock (_mapLock)
|
||||
player.m_InstanceValid = true;
|
||||
|
||||
player.m_InstanceValid = true;
|
||||
return base.AddPlayerToMap(player, initPlayer);
|
||||
}
|
||||
|
||||
|
||||
+212
-193
@@ -17,12 +17,15 @@
|
||||
|
||||
using Framework.Constants;
|
||||
using Framework.Database;
|
||||
using Game.BattleGrounds;
|
||||
using Game.DataStorage;
|
||||
using Game.Garrisons;
|
||||
using Game.Groups;
|
||||
using Game.Maps;
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Game.Entities
|
||||
{
|
||||
@@ -49,161 +52,202 @@ namespace Game.Entities
|
||||
pair.Value.InitVisibilityDistance();
|
||||
}
|
||||
|
||||
public Map CreateBaseMap(uint id)
|
||||
Map FindMap_i(uint mapId, uint instanceId)
|
||||
{
|
||||
Map map = FindBaseMap(id);
|
||||
if (map == null)
|
||||
{
|
||||
var entry = CliDB.MapStorage.LookupByKey(id);
|
||||
Cypher.Assert(entry != null);
|
||||
if (entry.ParentMapID != -1 || entry.CosmeticParentMapID != -1)
|
||||
{
|
||||
CreateBaseMap((uint)(entry.ParentMapID != -1 ? entry.ParentMapID : entry.CosmeticParentMapID));
|
||||
|
||||
// must have been created by parent map
|
||||
map = FindBaseMap(id);
|
||||
return map;
|
||||
}
|
||||
|
||||
lock(_mapsLock)
|
||||
map = CreateBaseMap_i(entry);
|
||||
}
|
||||
Cypher.Assert(map != null);
|
||||
return map;
|
||||
return i_maps.LookupByKey((mapId, instanceId));
|
||||
}
|
||||
|
||||
Map CreateBaseMap_i(MapRecord mapEntry)
|
||||
Map CreateWorldMap(uint mapId, uint instanceId)
|
||||
{
|
||||
Map map;
|
||||
if (mapEntry.Instanceable())
|
||||
map = new MapInstanced(mapEntry.Id, i_gridCleanUpDelay);
|
||||
else
|
||||
map = new Map(mapEntry.Id, i_gridCleanUpDelay, 0, Difficulty.None);
|
||||
Map map = new Map(mapId, i_gridCleanUpDelay, instanceId, Difficulty.None);
|
||||
map.LoadRespawnTimes();
|
||||
map.LoadCorpseData();
|
||||
|
||||
i_maps[mapEntry.Id] = map;
|
||||
|
||||
if (!mapEntry.Instanceable())
|
||||
{
|
||||
map.LoadRespawnTimes();
|
||||
map.LoadCorpseData();
|
||||
}
|
||||
if (WorldConfig.GetBoolValue(WorldCfg.BasemapLoadGrids))
|
||||
map.LoadAllCells();
|
||||
|
||||
return map;
|
||||
}
|
||||
|
||||
public Map FindBaseNonInstanceMap(uint mapId)
|
||||
InstanceMap CreateInstance(uint mapId, uint instanceId, InstanceSave save, Difficulty difficulty, int team)
|
||||
{
|
||||
Map map = FindBaseMap(mapId);
|
||||
if (map != null && map.Instanceable())
|
||||
return null;
|
||||
return map;
|
||||
}
|
||||
|
||||
public Map CreateMap(uint id, Player player, uint loginInstanceId = 0)
|
||||
{
|
||||
Map m = CreateBaseMap(id);
|
||||
|
||||
if (m != null && m.Instanceable())
|
||||
m = ((MapInstanced)m).CreateInstanceForPlayer(id, player, loginInstanceId);
|
||||
|
||||
return m;
|
||||
}
|
||||
|
||||
public Map FindMap(uint mapid, uint instanceId)
|
||||
{
|
||||
Map map = FindBaseMap(mapid);
|
||||
if (map == null)
|
||||
return null;
|
||||
|
||||
if (!map.Instanceable())
|
||||
return instanceId == 0 ? map : null;
|
||||
|
||||
return ((MapInstanced)map).FindInstanceMap(instanceId);
|
||||
}
|
||||
|
||||
public EnterState PlayerCannotEnter(uint mapid, Player player, bool loginCheck = false)
|
||||
{
|
||||
MapRecord entry = CliDB.MapStorage.LookupByKey(mapid);
|
||||
// make sure we have a valid map id
|
||||
var entry = CliDB.MapStorage.LookupByKey(mapId);
|
||||
if (entry == null)
|
||||
return EnterState.CannotEnterNoEntry;
|
||||
|
||||
if (!entry.IsDungeon())
|
||||
return EnterState.CanEnter;
|
||||
|
||||
Difficulty targetDifficulty = player.GetDifficultyID(entry);
|
||||
// Get the highest available difficulty if current setting is higher than the instance allows
|
||||
MapDifficultyRecord mapDiff = Global.DB2Mgr.GetDownscaledMapDifficultyData(entry.Id, ref targetDifficulty);
|
||||
if (mapDiff == null)
|
||||
return EnterState.CannotEnterDifficultyUnavailable;
|
||||
|
||||
//Bypass checks for GMs
|
||||
if (player.IsGameMaster())
|
||||
return EnterState.CanEnter;
|
||||
|
||||
//Other requirements
|
||||
if (!player.Satisfy(Global.ObjectMgr.GetAccessRequirement(mapid, targetDifficulty), mapid, true))
|
||||
return EnterState.CannotEnterUnspecifiedReason;
|
||||
|
||||
string mapName = entry.MapName[Global.WorldMgr.GetDefaultDbcLocale()];
|
||||
|
||||
Group group = player.GetGroup();
|
||||
if (entry.IsRaid() && entry.Expansion() >= (Expansion)WorldConfig.GetIntValue(WorldCfg.Expansion)) // can only enter in a raid group but raids from old expansion don't need a group
|
||||
if ((!group || !group.IsRaidGroup()) && WorldConfig.GetBoolValue(WorldCfg.InstanceIgnoreRaid))
|
||||
return EnterState.CannotEnterNotInRaid;
|
||||
|
||||
if (!player.IsAlive())
|
||||
{
|
||||
if (player.HasCorpse())
|
||||
{
|
||||
// let enter in ghost mode in instance that connected to inner instance with corpse
|
||||
uint corpseMap = player.GetCorpseLocation().GetMapId();
|
||||
do
|
||||
{
|
||||
if (corpseMap == mapid)
|
||||
break;
|
||||
|
||||
InstanceTemplate corpseInstance = Global.ObjectMgr.GetInstanceTemplate(corpseMap);
|
||||
corpseMap = corpseInstance != null ? corpseInstance.Parent : 0;
|
||||
} while (corpseMap != 0);
|
||||
|
||||
if (corpseMap == 0)
|
||||
return EnterState.CannotEnterCorpseInDifferentInstance;
|
||||
|
||||
Log.outDebug(LogFilter.Maps, "MAP: Player '{0}' has corpse in instance '{1}' and can enter.", player.GetName(), mapName);
|
||||
}
|
||||
else
|
||||
Log.outDebug(LogFilter.Maps, "Map.CanPlayerEnter - player '{0}' is dead but does not have a corpse!", player.GetName());
|
||||
Log.outError(LogFilter.Maps, $"CreateInstance: no entry for map {mapId}");
|
||||
//ABORT();
|
||||
return null;
|
||||
}
|
||||
|
||||
//Get instance where player's group is bound & its map
|
||||
if (!loginCheck && group)
|
||||
// some instances only have one difficulty
|
||||
Global.DB2Mgr.GetDownscaledMapDifficultyData(mapId, ref difficulty);
|
||||
|
||||
Log.outDebug(LogFilter.Maps, $"MapInstanced::CreateInstance: {(save != null ? "" : "new ")} map instance {instanceId} for {mapId} created with difficulty {difficulty}");
|
||||
|
||||
InstanceMap map = new InstanceMap(mapId, i_gridCleanUpDelay, instanceId, difficulty, team);
|
||||
Cypher.Assert(map.IsDungeon());
|
||||
|
||||
map.LoadRespawnTimes();
|
||||
map.LoadCorpseData();
|
||||
|
||||
bool load_data = save != null;
|
||||
map.CreateInstanceData(load_data);
|
||||
var instanceScenario = Global.ScenarioMgr.CreateInstanceScenario(map, team);
|
||||
if (instanceScenario != null)
|
||||
map.SetInstanceScenario(instanceScenario);
|
||||
|
||||
if (WorldConfig.GetBoolValue(WorldCfg.InstancemapLoadGrids))
|
||||
map.LoadAllCells();
|
||||
|
||||
return map;
|
||||
}
|
||||
|
||||
BattlegroundMap CreateBattleground(uint mapId, uint instanceId, Battleground bg)
|
||||
{
|
||||
Log.outDebug(LogFilter.Maps, $"MapInstanced::CreateBattleground: map bg {instanceId} for {mapId} created.");
|
||||
|
||||
BattlegroundMap map = new BattlegroundMap(mapId, i_gridCleanUpDelay, instanceId, Difficulty.None);
|
||||
Cypher.Assert(map.IsBattlegroundOrArena());
|
||||
map.SetBG(bg);
|
||||
bg.SetBgMap(map);
|
||||
return map;
|
||||
}
|
||||
|
||||
GarrisonMap CreateGarrison(uint mapId, uint instanceId, Player owner)
|
||||
{
|
||||
GarrisonMap map = new GarrisonMap(mapId, i_gridCleanUpDelay, instanceId, owner.GetGUID());
|
||||
Cypher.Assert(map.IsGarrison());
|
||||
return map;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// create the instance if it's not created already
|
||||
/// the player is not actually added to the instance(only in InstanceMap::Add)
|
||||
/// </summary>
|
||||
/// <param name="mapId"></param>
|
||||
/// <param name="player"></param>
|
||||
/// <param name="loginInstanceId"></param>
|
||||
/// <returns>the right instance for the object, based on its InstanceId</returns>
|
||||
public Map CreateMap(uint mapId, Player player, uint loginInstanceId = 0)
|
||||
{
|
||||
if (!player)
|
||||
return null;
|
||||
|
||||
var entry = CliDB.MapStorage.LookupByKey(mapId);
|
||||
if (entry == null)
|
||||
return null;
|
||||
|
||||
lock (_mapsLock)
|
||||
{
|
||||
InstanceBind boundInstance = group.GetBoundInstance(entry);
|
||||
if (boundInstance != null && boundInstance.save != null)
|
||||
Map map = null;
|
||||
uint newInstanceId = 0; // instanceId of the resulting map
|
||||
|
||||
if (entry.IsBattlegroundOrArena())
|
||||
{
|
||||
Map boundMap = FindMap(mapid, boundInstance.save.GetInstanceId());
|
||||
if (boundMap != null)
|
||||
// instantiate or find existing bg map for player
|
||||
// the instance id is set in battlegroundid
|
||||
newInstanceId = player.GetBattlegroundId();
|
||||
if (newInstanceId == 0)
|
||||
return null;
|
||||
|
||||
map = FindMap(mapId, newInstanceId);
|
||||
if (!map)
|
||||
{
|
||||
EnterState denyReason = boundMap.CannotEnter(player);
|
||||
if (denyReason != 0)
|
||||
return denyReason;
|
||||
Battleground bg = player.GetBattleground();
|
||||
if (bg != null)
|
||||
map = CreateBattleground(mapId, newInstanceId, bg);
|
||||
else
|
||||
{
|
||||
player.TeleportToBGEntryPoint();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// players are only allowed to enter 10 instances per hour
|
||||
if (entry.IsDungeon() && (player.GetGroup() == null || (player.GetGroup() != null && !player.GetGroup().IsLFGGroup())))
|
||||
{
|
||||
uint instaceIdToCheck = 0;
|
||||
InstanceSave save = player.GetInstanceSave(mapid);
|
||||
if (save != null)
|
||||
instaceIdToCheck = save.GetInstanceId();
|
||||
else if (entry.IsDungeon())
|
||||
{
|
||||
InstanceBind pBind = player.GetBoundInstance(mapId, player.GetDifficultyID(entry));
|
||||
InstanceSave pSave = pBind != null ? pBind.save : null;
|
||||
|
||||
// instanceId can never be 0 - will not be found
|
||||
if (!player.CheckInstanceCount(instaceIdToCheck) && !player.IsDead())
|
||||
return EnterState.CannotEnterTooManyInstances;
|
||||
}
|
||||
// priority:
|
||||
// 1. player's permanent bind
|
||||
// 2. player's current instance id if this is at login
|
||||
// 3. group's current bind
|
||||
// 4. player's current bind
|
||||
if (pBind == null || !pBind.perm)
|
||||
{
|
||||
if (loginInstanceId != 0) // if the player has a saved instance id on login, we either use this instance or relocate him out (return null)
|
||||
{
|
||||
map = FindMap_i(mapId, loginInstanceId);
|
||||
if (map == null && pSave != null && pSave.GetInstanceId() == loginInstanceId)
|
||||
map = CreateInstance(mapId, loginInstanceId, pSave, pSave.GetDifficultyID(), player.GetTeamId());
|
||||
return map;
|
||||
}
|
||||
|
||||
return EnterState.CanEnter;
|
||||
InstanceBind groupBind = null;
|
||||
Group group = player.GetGroup();
|
||||
// use the player's difficulty setting (it may not be the same as the group's)
|
||||
if (group != null)
|
||||
{
|
||||
groupBind = group.GetBoundInstance(entry);
|
||||
if (groupBind != null)
|
||||
{
|
||||
// solo saves should be reset when entering a group's instance
|
||||
player.UnbindInstance(mapId, player.GetDifficultyID(entry));
|
||||
pSave = groupBind.save;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (pSave != null)
|
||||
{
|
||||
// solo/perm/group
|
||||
newInstanceId = pSave.GetInstanceId();
|
||||
map = FindMap_i(mapId, newInstanceId);
|
||||
// it is possible that the save exists but the map doesn't
|
||||
if (!map)
|
||||
map = CreateInstance(mapId, newInstanceId, pSave, pSave.GetDifficultyID(), player.GetTeamId());
|
||||
}
|
||||
else
|
||||
{
|
||||
Difficulty diff = player.GetGroup() ? player.GetGroup().GetDifficultyID(entry) : player.GetDifficultyID(entry);
|
||||
|
||||
// if no instanceId via group members or instance saves is found
|
||||
// the instance will be created for the first time
|
||||
newInstanceId = GenerateInstanceId();
|
||||
|
||||
//Seems it is now possible, but I do not know if it should be allowed
|
||||
//ASSERT(!FindInstanceMap(NewInstanceId));
|
||||
map = FindMap_i(mapId, newInstanceId);
|
||||
if (!map)
|
||||
map = CreateInstance(mapId, newInstanceId, null, diff, player.GetTeamId());
|
||||
}
|
||||
}
|
||||
else if (entry.IsGarrison())
|
||||
{
|
||||
newInstanceId = (uint)player.GetGUID().GetCounter();
|
||||
map = FindMap_i(mapId, newInstanceId);
|
||||
if (!map)
|
||||
map = CreateGarrison(mapId, newInstanceId, player);
|
||||
}
|
||||
else
|
||||
{
|
||||
newInstanceId = 0;
|
||||
map = FindMap_i(mapId, newInstanceId);
|
||||
if (!map)
|
||||
map = CreateWorldMap(mapId, newInstanceId);
|
||||
}
|
||||
|
||||
if (map)
|
||||
i_maps[(map.GetId(), map.GetInstanceId())] = map;
|
||||
|
||||
return map;
|
||||
}
|
||||
}
|
||||
|
||||
public Map FindMap(uint mapId, uint instanceId)
|
||||
{
|
||||
lock (_mapsLock)
|
||||
return FindMap_i(mapId, instanceId);
|
||||
}
|
||||
|
||||
public void Update(uint diff)
|
||||
@@ -213,8 +257,16 @@ namespace Game.Entities
|
||||
return;
|
||||
|
||||
var time = (uint)i_timer.GetCurrent();
|
||||
foreach (var map in i_maps.Values)
|
||||
foreach (var (key, map) in i_maps)
|
||||
{
|
||||
if (map.CanUnload(diff))
|
||||
{
|
||||
if (DestroyMap(map))
|
||||
i_maps.Remove(key);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (m_updater != null)
|
||||
m_updater.ScheduleUpdate(map, (uint)i_timer.GetCurrent());
|
||||
else
|
||||
@@ -230,6 +282,23 @@ namespace Game.Entities
|
||||
i_timer.SetCurrent(0);
|
||||
}
|
||||
|
||||
bool DestroyMap(Map map)
|
||||
{
|
||||
map.RemoveAllPlayers();
|
||||
if (map.HavePlayers())
|
||||
return false;
|
||||
|
||||
map.UnloadAll();
|
||||
|
||||
// Free up the instance id and allow it to be reused for bgs and arenas (other instances are handled in the InstanceSaveMgr)
|
||||
if (map.IsBattlegroundOrArena())
|
||||
FreeInstanceId(map.GetInstanceId());
|
||||
|
||||
// erase map
|
||||
map.Dispose();
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool IsValidMAP(uint mapId)
|
||||
{
|
||||
return CliDB.MapStorage.ContainsKey(mapId);
|
||||
@@ -253,38 +322,13 @@ namespace Game.Entities
|
||||
public uint GetNumInstances()
|
||||
{
|
||||
lock (_mapsLock)
|
||||
{
|
||||
uint ret = 0;
|
||||
foreach (var pair in i_maps)
|
||||
{
|
||||
Map map = pair.Value;
|
||||
if (!map.IsDungeon())
|
||||
continue;
|
||||
|
||||
var maps = ((MapInstanced)map).GetInstancedMaps();
|
||||
ret += (uint)maps.Count;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
return (uint)i_maps.Count(pair => pair.Value.IsDungeon());
|
||||
}
|
||||
|
||||
public uint GetNumPlayersInInstances()
|
||||
{
|
||||
lock (_mapsLock)
|
||||
{
|
||||
uint ret = 0;
|
||||
foreach (var pair in i_maps)
|
||||
{
|
||||
Map map = pair.Value;
|
||||
if (!map.IsDungeon())
|
||||
continue;
|
||||
|
||||
var maps = ((MapInstanced)map).GetInstancedMaps();
|
||||
foreach (var imap in maps)
|
||||
ret += (uint)imap.Value.GetPlayers().Count;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
return (uint)i_maps.Sum(pair => pair.Value.IsDungeon() ? pair.Value.GetPlayers().Count : 0);
|
||||
}
|
||||
|
||||
public void InitInstanceIds()
|
||||
@@ -375,27 +419,12 @@ namespace Game.Entities
|
||||
|
||||
public void SetNextInstanceId(uint nextInstanceId) { _nextInstanceId = nextInstanceId; }
|
||||
|
||||
Map FindBaseMap(uint mapId)
|
||||
{
|
||||
return i_maps.LookupByKey(mapId);
|
||||
}
|
||||
|
||||
public void DoForAllMaps(Action<Map> worker)
|
||||
{
|
||||
lock (_mapsLock)
|
||||
{
|
||||
foreach (var map in i_maps.Values)
|
||||
{
|
||||
MapInstanced mapInstanced = map.ToMapInstanced();
|
||||
if (mapInstanced)
|
||||
{
|
||||
var instances = mapInstanced.GetInstancedMaps();
|
||||
foreach (var instance in instances.Values)
|
||||
worker(instance);
|
||||
}
|
||||
else
|
||||
worker(map);
|
||||
}
|
||||
foreach (var (_, map) in i_maps)
|
||||
worker(map);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -403,19 +432,9 @@ namespace Game.Entities
|
||||
{
|
||||
lock (_mapsLock)
|
||||
{
|
||||
var map = i_maps.LookupByKey(mapId);
|
||||
if (map != null)
|
||||
{
|
||||
MapInstanced mapInstanced = map.ToMapInstanced();
|
||||
if (mapInstanced)
|
||||
{
|
||||
var instances = mapInstanced.GetInstancedMaps();
|
||||
foreach (var instance in instances)
|
||||
worker(instance.Value);
|
||||
}
|
||||
else
|
||||
worker(map);
|
||||
}
|
||||
var list = i_maps.Where(pair => pair.Key.mapId == mapId && pair.Key.instanceId >= 0);
|
||||
foreach (var (_, map) in list)
|
||||
worker(map);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -424,7 +443,7 @@ namespace Game.Entities
|
||||
public void DecreaseScheduledScriptCount(uint count) { _scheduledScripts -= count; }
|
||||
public bool IsScriptScheduled() { return _scheduledScripts > 0; }
|
||||
|
||||
Dictionary<uint, Map> i_maps = new();
|
||||
Dictionary<(uint mapId, uint instanceId), Map> i_maps = new();
|
||||
IntervalTimer i_timer = new();
|
||||
object _mapsLock= new();
|
||||
uint i_gridCleanUpDelay;
|
||||
|
||||
@@ -146,10 +146,11 @@ namespace Game.Maps
|
||||
TerrainInfo _parentTerrain;
|
||||
List<TerrainInfo> _childTerrain = new();
|
||||
|
||||
object _loadMutex = new();
|
||||
object _loadLock = new();
|
||||
GridMap[][] _gridMap = new GridMap[MapConst.MaxGrids][];
|
||||
ushort[][] _referenceCountFromMap = new ushort[MapConst.MaxGrids][];
|
||||
|
||||
BitSet _loadedGrids = new(MapConst.MaxGrids * MapConst.MaxGrids);
|
||||
BitSet _gridFileExists = new(MapConst.MaxGrids * MapConst.MaxGrids); // cache what grids are available for this map (not including parent/child maps)
|
||||
|
||||
static TimeSpan CleanupInterval = TimeSpan.FromMinutes(1);
|
||||
@@ -187,9 +188,9 @@ namespace Game.Maps
|
||||
{
|
||||
var build = reader.ReadUInt32();
|
||||
byte[] tilesData = reader.ReadArray<byte>(MapConst.MaxGrids * MapConst.MaxGrids);
|
||||
for (uint gx = 0; gx < MapConst.MaxGrids; ++gx)
|
||||
for (uint gy = 0; gy < MapConst.MaxGrids; ++gy)
|
||||
_gridFileExists[(int)(gx * MapConst.MaxGrids + gy)] = tilesData[(int)(gx * MapConst.MaxGrids + gy)] == 49; // char of 1
|
||||
for (int gx = 0; gx < MapConst.MaxGrids; ++gx)
|
||||
for (int gy = 0; gy < MapConst.MaxGrids; ++gy)
|
||||
_gridFileExists[GetBitsetIndex(gx, gy)] = tilesData[GetBitsetIndex(gx, gy)] == 49; // char of 1
|
||||
|
||||
return;
|
||||
}
|
||||
@@ -197,7 +198,7 @@ namespace Game.Maps
|
||||
|
||||
for (int gx = 0; gx < MapConst.MaxGrids; ++gx)
|
||||
for (int gy = 0; gy < MapConst.MaxGrids; ++gy)
|
||||
_gridFileExists[gx * MapConst.MaxGrids + gy] = ExistMap(GetId(), gx, gy, false);
|
||||
_gridFileExists[GetBitsetIndex(gx, gy)] = ExistMap(GetId(), gx, gy, false);
|
||||
}
|
||||
|
||||
public static bool ExistMap(uint mapid, int gx, int gy, bool log = true)
|
||||
@@ -264,7 +265,7 @@ namespace Game.Maps
|
||||
public bool HasChildTerrainGridFile(uint mapId, int gx, int gy)
|
||||
{
|
||||
var childMap = _childTerrain.Find(childTerrain => childTerrain.GetId() == mapId);
|
||||
return childMap != null && childMap._gridFileExists[gx * MapConst.MaxGrids + gy];
|
||||
return childMap != null && childMap._gridFileExists[GetBitsetIndex(gx, gy)];
|
||||
}
|
||||
|
||||
public void AddChildTerrain(TerrainInfo childTerrain)
|
||||
@@ -278,8 +279,8 @@ namespace Game.Maps
|
||||
if (++_referenceCountFromMap[gx][gy] != 1) // check if already loaded
|
||||
return;
|
||||
|
||||
//std::lock_guard < std::mutex > lock (_loadMutex) ;
|
||||
LoadMapAndVMapImpl(gx, gy);
|
||||
lock(_loadLock)
|
||||
LoadMapAndVMapImpl(gx, gy);
|
||||
}
|
||||
|
||||
public void LoadMapAndVMapImpl(int gx, int gy)
|
||||
@@ -290,6 +291,8 @@ namespace Game.Maps
|
||||
|
||||
foreach (TerrainInfo childTerrain in _childTerrain)
|
||||
childTerrain.LoadMapAndVMapImpl(gx, gy);
|
||||
|
||||
_loadedGrids[GetBitsetIndex(gx, gy)] = true;
|
||||
}
|
||||
|
||||
public void LoadMap(int gx, int gy)
|
||||
@@ -297,7 +300,7 @@ namespace Game.Maps
|
||||
if (_gridMap[gx][gy] != null)
|
||||
return;
|
||||
|
||||
if (!_gridFileExists[gx * MapConst.MaxGrids + gy])
|
||||
if (!_gridFileExists[GetBitsetIndex(gx, gy)])
|
||||
return;
|
||||
|
||||
// map file name
|
||||
@@ -310,7 +313,7 @@ namespace Game.Maps
|
||||
if (gridMapLoadResult == LoadResult.Success)
|
||||
_gridMap[gx][gy] = gridMap;
|
||||
else
|
||||
_gridFileExists[gx * MapConst.MaxGrids + gy] = false;
|
||||
_gridFileExists[GetBitsetIndex(gx, gy)] = false;
|
||||
|
||||
if (gridMapLoadResult == LoadResult.ReadFromFileFailed)
|
||||
Log.outError(LogFilter.Maps, $"Error loading map file: {fileName}");
|
||||
@@ -328,7 +331,8 @@ namespace Game.Maps
|
||||
case LoadResult.Success:
|
||||
Log.outDebug(LogFilter.Maps, $"VMAP loaded name:{GetMapName()}, id:{GetId()}, x:{gx}, y:{gy} (vmap rep.: x:{gx}, y:{gy})");
|
||||
break;
|
||||
default:
|
||||
case LoadResult.VersionMismatch:
|
||||
case LoadResult.ReadFromFileFailed:
|
||||
Log.outError(LogFilter.Maps, $"Could not load VMAP name:{GetMapName()}, id:{GetId()}, x:{gx}, y:{gy} (vmap rep.: x:{gx}, y:{gy})");
|
||||
break;
|
||||
case LoadResult.DisabledInConfig:
|
||||
@@ -363,6 +367,8 @@ namespace Game.Maps
|
||||
|
||||
foreach (var childTerrain in _childTerrain)
|
||||
childTerrain.UnloadMapImpl(gx, gy);
|
||||
|
||||
_loadedGrids[GetBitsetIndex(gx, gy)] = false;
|
||||
}
|
||||
|
||||
public GridMap GetGrid(uint mapId, float x, float y, bool loadIfMissing = true)
|
||||
@@ -372,10 +378,10 @@ namespace Game.Maps
|
||||
int gy = (int)(MapConst.CenterGridId - y / MapConst.SizeofGrids); //grid y
|
||||
|
||||
// ensure GridMap is loaded
|
||||
if (_gridMap[gx][gy] == null && loadIfMissing)
|
||||
if (_loadedGrids[GetBitsetIndex(gx, gy)] && loadIfMissing)
|
||||
{
|
||||
//std::lock_guard < std::mutex > lock (_loadMutex) ;
|
||||
LoadMapAndVMapImpl(gx, gy);
|
||||
lock(_loadLock)
|
||||
LoadMapAndVMapImpl(gx, gy);
|
||||
}
|
||||
|
||||
GridMap grid = _gridMap[gx][gy];
|
||||
@@ -398,7 +404,7 @@ namespace Game.Maps
|
||||
// delete those GridMap objects which have refcount = 0
|
||||
for (int x = 0; x < MapConst.MaxGrids; ++x)
|
||||
for (int y = 0; y < MapConst.MaxGrids; ++y)
|
||||
if (_gridMap[x][y] != null && _referenceCountFromMap[x][y] == 0)
|
||||
if (_loadedGrids[GetBitsetIndex(x, y)] && _referenceCountFromMap[x][y] == 0)
|
||||
UnloadMapImpl(x, y);
|
||||
|
||||
_cleanupTimer.Reset(CleanupInterval);
|
||||
@@ -889,5 +895,7 @@ namespace Game.Maps
|
||||
}
|
||||
|
||||
public uint GetId() { return _mapId; }
|
||||
|
||||
static int GetBitsetIndex(int gx, int gy) { return gx * MapConst.MaxGrids + gy; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -109,7 +109,7 @@ namespace Game.Movement
|
||||
break;
|
||||
|
||||
if (_currentNode == _preloadTargetNode)
|
||||
PreloadEndGrid();
|
||||
PreloadEndGrid(owner);
|
||||
|
||||
_currentNode += (departureEvent ? 1 : 0);
|
||||
departureEvent = !departureEvent;
|
||||
@@ -262,14 +262,17 @@ namespace Game.Movement
|
||||
else
|
||||
_preloadTargetNode = (uint)nodeCount - 3;
|
||||
|
||||
while (_path[(int)_preloadTargetNode].ContinentID != _endMapId)
|
||||
++_preloadTargetNode;
|
||||
|
||||
_endGridX = _path[nodeCount - 1].Loc.X;
|
||||
_endGridY = _path[nodeCount - 1].Loc.Y;
|
||||
}
|
||||
|
||||
void PreloadEndGrid()
|
||||
void PreloadEndGrid(Player owner)
|
||||
{
|
||||
// Used to preload the final grid where the flightmaster is
|
||||
Map endMap = Global.MapMgr.FindBaseNonInstanceMap(_endMapId);
|
||||
Map endMap = owner.GetMap();
|
||||
|
||||
// Load the grid
|
||||
if (endMap != null)
|
||||
|
||||
@@ -1116,19 +1116,6 @@ namespace Game
|
||||
|
||||
Log.outInfo(LogFilter.ServerLoading, "Loading phase names...");
|
||||
Global.ObjectMgr.LoadPhaseNames();
|
||||
|
||||
// Preload all cells, if required for the base maps
|
||||
if (WorldConfig.GetBoolValue(WorldCfg.BasemapLoadGrids))
|
||||
{
|
||||
Global.MapMgr.DoForAllMaps(map =>
|
||||
{
|
||||
if (!map.Instanceable())
|
||||
{
|
||||
Log.outInfo(LogFilter.ServerLoading, "Pre-loading base map data for map {0}", map.GetId());
|
||||
map.LoadAllCells();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public void LoadConfigSettings(bool reload = false)
|
||||
|
||||
Reference in New Issue
Block a user