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)]
|
[Command("loadcells", RBACPermissions.CommandDebug, true)]
|
||||||
static bool HandleDebugLoadCellsCommand(CommandHandler handler, uint? mapId, uint? tileX, uint? tileY)
|
static bool HandleDebugLoadCellsCommand(CommandHandler handler, uint? mapId, uint? tileX, uint? tileY)
|
||||||
{
|
{
|
||||||
Map map = null;
|
|
||||||
if (mapId.HasValue)
|
if (mapId.HasValue)
|
||||||
map = Global.MapMgr.FindBaseNonInstanceMap(mapId.Value);
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
Player player = handler.GetPlayer();
|
Global.MapMgr.DoForAllMapsWithMapId(mapId.Value, map => HandleDebugLoadCellsCommandHelper(handler, map, tileX, tileY));
|
||||||
if (player != null)
|
return true;
|
||||||
{
|
|
||||||
// Fallback to player's map if no map has been specified
|
|
||||||
map = player.GetMap();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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)
|
if (!map)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
|||||||
@@ -205,8 +205,8 @@ namespace Game.Chat.Commands
|
|||||||
else
|
else
|
||||||
player.SaveRecallPosition(); // save only in non-flight case
|
player.SaveRecallPosition(); // save only in non-flight case
|
||||||
|
|
||||||
Map map = Global.MapMgr.CreateBaseMap(mapId);
|
TerrainInfo terrain = Global.TerrainMgr.LoadTerrain(mapId);
|
||||||
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(mapId, x, y, z, player.GetOrientation());
|
player.TeleportTo(mapId, x, y, z, player.GetOrientation());
|
||||||
return true;
|
return true;
|
||||||
@@ -352,8 +352,8 @@ namespace Game.Chat.Commands
|
|||||||
else
|
else
|
||||||
player.SaveRecallPosition(); // save only in non-flight case
|
player.SaveRecallPosition(); // save only in non-flight case
|
||||||
|
|
||||||
Map map = Global.MapMgr.CreateBaseMap(mapId);
|
TerrainInfo terrain = Global.TerrainMgr.LoadTerrain(mapId);
|
||||||
z = Math.Max(map.GetStaticHeight(PhasingHandler.EmptyPhaseShift, x, y, MapConst.MaxHeight), map.GetWaterLevel(PhasingHandler.EmptyPhaseShift, x, y));
|
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);
|
player.TeleportTo(mapId, x, y, z, 0.0f);
|
||||||
return true;
|
return true;
|
||||||
@@ -398,8 +398,8 @@ namespace Game.Chat.Commands
|
|||||||
handler.SendSysMessage(CypherStrings.InvalidTargetCoord, x, y, mapId);
|
handler.SendSysMessage(CypherStrings.InvalidTargetCoord, x, y, mapId);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
Map map = Global.MapMgr.CreateBaseMap(mapId);
|
TerrainInfo terrain = Global.TerrainMgr.LoadTerrain(mapId);
|
||||||
z = Math.Max(map.GetStaticHeight(PhasingHandler.EmptyPhaseShift, x, y, MapConst.MaxHeight), map.GetWaterLevel(PhasingHandler.EmptyPhaseShift, x, y));
|
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);
|
return DoTeleport(handler, new Position(x, y, z.Value, o.Value), mapId);
|
||||||
@@ -427,10 +427,10 @@ namespace Game.Chat.Commands
|
|||||||
x /= 100.0f;
|
x /= 100.0f;
|
||||||
y /= 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))
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -446,7 +446,7 @@ namespace Game.Chat.Commands
|
|||||||
else
|
else
|
||||||
player.SaveRecallPosition(); // save only in non-flight case
|
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());
|
player.TeleportTo(zoneEntry.ContinentID, x, y, z, player.GetOrientation());
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@@ -72,27 +72,17 @@ namespace Game.Chat.Commands
|
|||||||
bool liveFound = false;
|
bool liveFound = false;
|
||||||
|
|
||||||
// Get map (only support base map from console)
|
// Get map (only support base map from console)
|
||||||
Map thisMap;
|
Map thisMap = null;
|
||||||
if (handler.GetSession() != null)
|
if (handler.GetSession() != null)
|
||||||
thisMap = handler.GetSession().GetPlayer().GetMap();
|
thisMap = handler.GetSession().GetPlayer().GetMap();
|
||||||
else
|
|
||||||
thisMap = Global.MapMgr.FindBaseNonInstanceMap(mapId);
|
|
||||||
|
|
||||||
// If map found, try to find active version of this creature
|
// If map found, try to find active version of this creature
|
||||||
if (thisMap)
|
if (thisMap)
|
||||||
{
|
{
|
||||||
var creBounds = thisMap.GetCreatureBySpawnIdStore().LookupByKey(guid);
|
var creBounds = thisMap.GetCreatureBySpawnIdStore().LookupByKey(guid);
|
||||||
if (!creBounds.Empty())
|
foreach (var creature in creBounds)
|
||||||
{
|
handler.SendSysMessage(CypherStrings.CreatureListChat, guid, guid, cInfo.Name, x, y, z, mapId, creature.GetGUID().ToString(), creature.IsAlive() ? "*" : " ");
|
||||||
foreach (var creature in creBounds)
|
liveFound = !creBounds.Empty();
|
||||||
{
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!liveFound)
|
if (!liveFound)
|
||||||
@@ -422,27 +412,17 @@ namespace Game.Chat.Commands
|
|||||||
bool liveFound = false;
|
bool liveFound = false;
|
||||||
|
|
||||||
// Get map (only support base map from console)
|
// Get map (only support base map from console)
|
||||||
Map thisMap;
|
Map thisMap = null;
|
||||||
if (handler.GetSession() != null)
|
if (handler.GetSession() != null)
|
||||||
thisMap = handler.GetSession().GetPlayer().GetMap();
|
thisMap = handler.GetSession().GetPlayer().GetMap();
|
||||||
else
|
|
||||||
thisMap = Global.MapMgr.FindBaseNonInstanceMap(mapId);
|
|
||||||
|
|
||||||
// If map found, try to find active version of this object
|
// If map found, try to find active version of this object
|
||||||
if (thisMap)
|
if (thisMap)
|
||||||
{
|
{
|
||||||
var goBounds = thisMap.GetGameObjectBySpawnIdStore().LookupByKey(guid);
|
var goBounds = thisMap.GetGameObjectBySpawnIdStore().LookupByKey(guid);
|
||||||
if (!goBounds.Empty())
|
foreach (var go in goBounds)
|
||||||
{
|
handler.SendSysMessage(CypherStrings.GoListChat, guid, entry, guid, gInfo.name, x, y, z, mapId, go.GetGUID().ToString(), go.IsSpawned() ? "*" : " ");
|
||||||
foreach (var go in goBounds)
|
liveFound = !goBounds.Empty();
|
||||||
{
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!liveFound)
|
if (!liveFound)
|
||||||
|
|||||||
@@ -1776,7 +1776,7 @@ namespace Game.Entities
|
|||||||
|
|
||||||
// Check enter rights before map getting to avoid creating instance copy for player
|
// 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
|
// 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;
|
return false;
|
||||||
|
|
||||||
// Seamless teleport can happen only if cosmetic maps match
|
// Seamless teleport can happen only if cosmetic maps match
|
||||||
|
|||||||
@@ -24,8 +24,7 @@ namespace Game.Garrisons
|
|||||||
{
|
{
|
||||||
class GarrisonMap : Map
|
class GarrisonMap : Map
|
||||||
{
|
{
|
||||||
public GarrisonMap(uint id, long expiry, uint instanceId, Map parent, ObjectGuid owner)
|
public GarrisonMap(uint id, long expiry, uint instanceId, ObjectGuid owner) : base(id, expiry, instanceId, Difficulty.Normal)
|
||||||
: base(id, expiry, instanceId, Difficulty.Normal, parent)
|
|
||||||
{
|
{
|
||||||
_owner = owner;
|
_owner = owner;
|
||||||
InitVisibilityDistance();
|
InitVisibilityDistance();
|
||||||
|
|||||||
@@ -274,7 +274,7 @@ namespace Game
|
|||||||
bool teleported = false;
|
bool teleported = false;
|
||||||
if (player.GetMapId() != at.target_mapId)
|
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)
|
if (denyReason != 0)
|
||||||
{
|
{
|
||||||
bool reviveAtTrigger = false; // should we revive the player if he is trying to enter the correct instance?
|
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)
|
void _ResetInstance(uint mapid, uint instanceId)
|
||||||
{
|
{
|
||||||
Log.outDebug(LogFilter.Maps, "InstanceSaveMgr._ResetInstance {0}, {1}", mapid, 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())
|
if (!map.IsDungeon())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@@ -463,7 +463,7 @@ namespace Game.Maps
|
|||||||
|
|
||||||
DeleteInstanceFromDB(instanceId); // even if save not loaded
|
DeleteInstanceFromDB(instanceId); // even if save not loaded
|
||||||
|
|
||||||
Map iMap = ((MapInstanced)map).FindInstanceMap(instanceId);
|
Map iMap = Global.MapMgr.FindMap(mapid, instanceId);
|
||||||
if (iMap != null)
|
if (iMap != null)
|
||||||
{
|
{
|
||||||
((InstanceMap)iMap).Reset(InstanceResetMethod.RespawnDelay);
|
((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
|
// note: this isn't fast but it's meant to be executed very rarely
|
||||||
Map map = Global.MapMgr.CreateBaseMap(mapid); // _not_ include difficulty
|
if (mapEntry.IsDungeon())
|
||||||
var instMaps = ((MapInstanced)map).GetInstancedMaps();
|
|
||||||
uint timeLeft;
|
|
||||||
|
|
||||||
foreach (var pair in instMaps)
|
|
||||||
{
|
{
|
||||||
Map map2 = pair.Value;
|
Global.MapMgr.DoForAllMapsWithMapId(mapid, map =>
|
||||||
if (!map2.IsDungeon())
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (warn)
|
|
||||||
{
|
{
|
||||||
if (now >= resetTime)
|
if (warn)
|
||||||
timeLeft = 0;
|
{
|
||||||
else
|
uint timeLeft;
|
||||||
timeLeft = (uint)(resetTime - now);
|
if (now >= resetTime)
|
||||||
|
timeLeft = 0;
|
||||||
|
else
|
||||||
|
timeLeft = (uint)(resetTime - now);
|
||||||
|
|
||||||
((InstanceMap)map2).SendResetWarnings(timeLeft);
|
((InstanceMap)map).SendResetWarnings(timeLeft);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
((InstanceMap)map2).Reset(InstanceResetMethod.Global);
|
((InstanceMap)map).Reset(InstanceResetMethod.Global);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// @todo delete creature/gameobject respawn times even if the maps are not loaded
|
// @todo delete creature/gameobject respawn times even if the maps are not loaded
|
||||||
@@ -583,7 +579,6 @@ namespace Game.Maps
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public long GetResetTimeFor(uint mapid, Difficulty d)
|
public long GetResetTimeFor(uint mapid, Difficulty d)
|
||||||
{
|
{
|
||||||
return m_resetTimeByMapDifficulty.LookupByKey(MathFunctions.MakePair64(mapid, (uint)d));
|
return m_resetTimeByMapDifficulty.LookupByKey(MathFunctions.MakePair64(mapid, (uint)d));
|
||||||
@@ -767,4 +762,17 @@ namespace Game.Maps
|
|||||||
bool m_canReset;
|
bool m_canReset;
|
||||||
bool m_toDelete;
|
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
+209
-146
@@ -37,7 +37,7 @@ namespace Game.Maps
|
|||||||
{
|
{
|
||||||
public class Map : IDisposable
|
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_mapRecord = CliDB.MapStorage.LookupByKey(id);
|
||||||
i_spawnMode = spawnmode;
|
i_spawnMode = spawnmode;
|
||||||
@@ -227,14 +227,6 @@ namespace Game.Maps
|
|||||||
}
|
}
|
||||||
|
|
||||||
void EnsureGridCreated(GridCoord p)
|
void EnsureGridCreated(GridCoord p)
|
||||||
{
|
|
||||||
lock (_gridLock)
|
|
||||||
{
|
|
||||||
EnsureGridCreated_i(p);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void EnsureGridCreated_i(GridCoord p)
|
|
||||||
{
|
{
|
||||||
if (GetGrid(p.X_coord, p.Y_coord) == null)
|
if (GetGrid(p.X_coord, p.Y_coord) == null)
|
||||||
{
|
{
|
||||||
@@ -330,7 +322,7 @@ namespace Game.Maps
|
|||||||
{
|
{
|
||||||
EnsureGridLoadedForActiveObject(new Cell(x, y), obj);
|
EnsureGridLoadedForActiveObject(new Cell(x, y), obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual bool AddPlayerToMap(Player player, bool initPlayer = true)
|
public virtual bool AddPlayerToMap(Player player, bool initPlayer = true)
|
||||||
{
|
{
|
||||||
CellCoord cellCoord = GridDefines.ComputeCellCoord(player.GetPositionX(), player.GetPositionY());
|
CellCoord cellCoord = GridDefines.ComputeCellCoord(player.GetPositionX(), player.GetPositionY());
|
||||||
@@ -416,7 +408,7 @@ namespace Game.Maps
|
|||||||
player.SendPacket(updateWorldState);
|
player.SendPacket(updateWorldState);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void InitializeObject(WorldObject obj)
|
void InitializeObject(WorldObject obj)
|
||||||
{
|
{
|
||||||
if (!obj.IsTypeId(TypeId.Unit) || !obj.IsTypeId(TypeId.GameObject))
|
if (!obj.IsTypeId(TypeId.Unit) || !obj.IsTypeId(TypeId.GameObject))
|
||||||
@@ -1529,7 +1521,7 @@ namespace Game.Maps
|
|||||||
_corpsesByCell.Clear();
|
_corpsesByCell.Clear();
|
||||||
_corpsesByPlayer.Clear();
|
_corpsesByPlayer.Clear();
|
||||||
_corpseBones.Clear();
|
_corpseBones.Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static bool IsInWMOInterior(uint mogpFlags)
|
public static bool IsInWMOInterior(uint mogpFlags)
|
||||||
{
|
{
|
||||||
@@ -1662,6 +1654,93 @@ namespace Game.Maps
|
|||||||
return result;
|
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()
|
public string GetMapName()
|
||||||
{
|
{
|
||||||
return i_mapRecord.MapName[Global.WorldMgr.GetDefaultDbcLocale()];
|
return i_mapRecord.MapName[Global.WorldMgr.GetDefaultDbcLocale()];
|
||||||
@@ -1960,7 +2039,7 @@ namespace Game.Maps
|
|||||||
if ((types & SpawnObjectTypeMask.GameObject) != 0)
|
if ((types & SpawnObjectTypeMask.GameObject) != 0)
|
||||||
PushRespawnInfoFrom(respawnData, _gameObjectRespawnTimesBySpawnId);
|
PushRespawnInfoFrom(respawnData, _gameObjectRespawnTimesBySpawnId);
|
||||||
}
|
}
|
||||||
|
|
||||||
public RespawnInfo GetRespawnInfo(SpawnObjectType type, ulong spawnId)
|
public RespawnInfo GetRespawnInfo(SpawnObjectType type, ulong spawnId)
|
||||||
{
|
{
|
||||||
var map = GetRespawnMapForType(type);
|
var map = GetRespawnMapForType(type);
|
||||||
@@ -1987,7 +2066,7 @@ namespace Game.Maps
|
|||||||
default:
|
default:
|
||||||
Cypher.Assert(false);
|
Cypher.Assert(false);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void UnloadAllRespawnInfos() // delete everything from memory
|
void UnloadAllRespawnInfos() // delete everything from memory
|
||||||
@@ -2150,7 +2229,7 @@ namespace Game.Maps
|
|||||||
}
|
}
|
||||||
|
|
||||||
public bool ShouldBeSpawnedOnGridLoad<T>(ulong spawnId) { return ShouldBeSpawnedOnGridLoad(SpawnData.TypeFor<T>(), spawnId); }
|
public bool ShouldBeSpawnedOnGridLoad<T>(ulong spawnId) { return ShouldBeSpawnedOnGridLoad(SpawnData.TypeFor<T>(), spawnId); }
|
||||||
|
|
||||||
bool ShouldBeSpawnedOnGridLoad(SpawnObjectType type, ulong spawnId)
|
bool ShouldBeSpawnedOnGridLoad(SpawnObjectType type, ulong spawnId)
|
||||||
{
|
{
|
||||||
Cypher.Assert(SpawnData.TypeHasData(type));
|
Cypher.Assert(SpawnData.TypeHasData(type));
|
||||||
@@ -3100,7 +3179,7 @@ namespace Game.Maps
|
|||||||
{
|
{
|
||||||
return $"Id: {GetId()} InstanceId: {GetInstanceId()} Difficulty: {GetDifficultyID()} HasPlayers: {HavePlayers()}";
|
return $"Id: {GetId()} InstanceId: {GetInstanceId()} Difficulty: {GetDifficultyID()} HasPlayers: {HavePlayers()}";
|
||||||
}
|
}
|
||||||
|
|
||||||
public MapRecord GetEntry()
|
public MapRecord GetEntry()
|
||||||
{
|
{
|
||||||
return i_mapRecord;
|
return i_mapRecord;
|
||||||
@@ -3152,7 +3231,7 @@ namespace Game.Maps
|
|||||||
}
|
}
|
||||||
|
|
||||||
public TerrainInfo GetTerrain() { return m_terrain; }
|
public TerrainInfo GetTerrain() { return m_terrain; }
|
||||||
|
|
||||||
public uint GetInstanceId()
|
public uint GetInstanceId()
|
||||||
{
|
{
|
||||||
return i_InstanceId;
|
return i_InstanceId;
|
||||||
@@ -3246,7 +3325,7 @@ namespace Game.Maps
|
|||||||
{
|
{
|
||||||
return i_mapRecord != null && i_mapRecord.IsScenario();
|
return i_mapRecord != null && i_mapRecord.IsScenario();
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool IsGarrison()
|
public bool IsGarrison()
|
||||||
{
|
{
|
||||||
return i_mapRecord != null && i_mapRecord.IsGarrison();
|
return i_mapRecord != null && i_mapRecord.IsGarrison();
|
||||||
@@ -3309,7 +3388,7 @@ namespace Game.Maps
|
|||||||
{
|
{
|
||||||
return m_activeNonPlayers.Count;
|
return m_activeNonPlayers.Count;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Dictionary<ObjectGuid, WorldObject> GetObjectsStore() { return _objectsStore; }
|
public Dictionary<ObjectGuid, WorldObject> GetObjectsStore() { return _objectsStore; }
|
||||||
|
|
||||||
public MultiMap<ulong, Creature> GetCreatureBySpawnIdStore() { return _creatureBySpawnIdStore; }
|
public MultiMap<ulong, Creature> GetCreatureBySpawnIdStore() { return _creatureBySpawnIdStore; }
|
||||||
@@ -3328,7 +3407,6 @@ namespace Game.Maps
|
|||||||
return _corpsesByPlayer.LookupByKey(ownerGuid);
|
return _corpsesByPlayer.LookupByKey(ownerGuid);
|
||||||
}
|
}
|
||||||
|
|
||||||
public MapInstanced ToMapInstanced() { return Instanceable() ? (this as MapInstanced) : null; }
|
|
||||||
public InstanceMap ToInstanceMap() { return IsDungeon() ? (this as InstanceMap) : null; }
|
public InstanceMap ToInstanceMap() { return IsDungeon() ? (this as InstanceMap) : null; }
|
||||||
public BattlegroundMap ToBattlegroundMap() { return IsBattlegroundOrArena() ? (this as BattlegroundMap) : null; }
|
public BattlegroundMap ToBattlegroundMap() { return IsBattlegroundOrArena() ? (this as BattlegroundMap) : null; }
|
||||||
|
|
||||||
@@ -3376,7 +3454,7 @@ namespace Game.Maps
|
|||||||
public long GetCreatureRespawnTime(ulong spawnId) { return GetRespawnTime(SpawnObjectType.Creature, spawnId); }
|
public long GetCreatureRespawnTime(ulong spawnId) { return GetRespawnTime(SpawnObjectType.Creature, spawnId); }
|
||||||
|
|
||||||
public long GetGORespawnTime(ulong spawnId) { return GetRespawnTime(SpawnObjectType.GameObject, spawnId); }
|
public long GetGORespawnTime(ulong spawnId) { return GetRespawnTime(SpawnObjectType.GameObject, spawnId); }
|
||||||
|
|
||||||
void SetTimer(uint t)
|
void SetTimer(uint t)
|
||||||
{
|
{
|
||||||
i_gridExpiry = t < MapConst.MinGridDelay ? MapConst.MinGridDelay : t;
|
i_gridExpiry = t < MapConst.MinGridDelay ? MapConst.MinGridDelay : t;
|
||||||
@@ -3412,7 +3490,7 @@ namespace Game.Maps
|
|||||||
{
|
{
|
||||||
return _objectsStore.LookupByKey(guid) as SceneObject;
|
return _objectsStore.LookupByKey(guid) as SceneObject;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Conversation GetConversation(ObjectGuid guid)
|
public Conversation GetConversation(ObjectGuid guid)
|
||||||
{
|
{
|
||||||
return (Conversation)_objectsStore.LookupByKey(guid);
|
return (Conversation)_objectsStore.LookupByKey(guid);
|
||||||
@@ -3858,7 +3936,7 @@ namespace Game.Maps
|
|||||||
}
|
}
|
||||||
return gameobject;
|
return gameobject;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Unit _GetScriptUnit(WorldObject obj, bool isSource, ScriptInfo scriptInfo)
|
private Unit _GetScriptUnit(WorldObject obj, bool isSource, ScriptInfo scriptInfo)
|
||||||
{
|
{
|
||||||
Unit unit = null;
|
Unit unit = null;
|
||||||
@@ -4601,12 +4679,10 @@ namespace Game.Maps
|
|||||||
Global.MapMgr.DecreaseScheduledScriptCount();
|
Global.MapMgr.DecreaseScheduledScriptCount();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Fields
|
#region Fields
|
||||||
internal object _mapLock = new();
|
internal object _mapLock = new();
|
||||||
object _gridLock = new();
|
|
||||||
|
|
||||||
bool _creatureToMoveLock;
|
bool _creatureToMoveLock;
|
||||||
List<Creature> creaturesToMove = new();
|
List<Creature> creaturesToMove = new();
|
||||||
@@ -4677,8 +4753,7 @@ namespace Game.Maps
|
|||||||
|
|
||||||
public class InstanceMap : Map
|
public class InstanceMap : Map
|
||||||
{
|
{
|
||||||
public InstanceMap(uint id, long expiry, uint InstanceId, Difficulty spawnMode, Map parent, int instanceTeam)
|
public InstanceMap(uint id, long expiry, uint InstanceId, Difficulty spawnMode, int instanceTeam) : base(id, expiry, InstanceId, spawnMode)
|
||||||
: base(id, expiry, InstanceId, spawnMode, parent)
|
|
||||||
{
|
{
|
||||||
scriptTeam = instanceTeam;
|
scriptTeam = instanceTeam;
|
||||||
|
|
||||||
@@ -4734,133 +4809,123 @@ namespace Game.Maps
|
|||||||
|
|
||||||
public override bool AddPlayerToMap(Player player, bool initPlayer = true)
|
public override bool AddPlayerToMap(Player player, bool initPlayer = true)
|
||||||
{
|
{
|
||||||
// @todo Not sure about checking player level: already done in HandleAreaTriggerOpcode
|
Group group = player.GetGroup();
|
||||||
// GMs still can teleport player in instance.
|
|
||||||
// Is it needed?
|
// increase current instances (hourly limit)
|
||||||
lock (_mapLock)
|
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
|
Log.outInfo(LogFilter.Maps, "InstanceMap.Add: creating instance save for map {0} spawnmode {1} with instance id {2}", GetId(), GetDifficultyID(), GetInstanceId());
|
||||||
if (IsDungeon())
|
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();
|
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(),
|
||||||
// increase current instances (hourly limit)
|
playerBind.save.GetInstanceId(), playerBind.save.GetDifficultyID(),
|
||||||
if (!group || !group.IsLFGGroup())
|
playerBind.save.GetPlayerCount(), playerBind.save.GetGroupCount(),
|
||||||
player.AddInstanceEnterTime(GetInstanceId(), GameTime.GetGameTime());
|
playerBind.save.CanReset(), GetMapName(), mapSave.GetMapId(), mapSave.GetInstanceId(),
|
||||||
|
mapSave.GetDifficultyID(), mapSave.GetPlayerCount(), mapSave.GetGroupCount(),
|
||||||
// get or create an instance save for the map
|
mapSave.CanReset());
|
||||||
InstanceSave mapSave = Global.InstanceSaveMgr.GetInstanceSave(GetInstanceId());
|
return false;
|
||||||
if (mapSave == null)
|
}
|
||||||
|
}
|
||||||
|
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());
|
Log.outError(LogFilter.Maps,
|
||||||
mapSave = Global.InstanceSaveMgr.AddInstanceSave(GetId(), GetInstanceId(), GetDifficultyID(), 0, 0, true);
|
"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(),
|
||||||
Cypher.Assert(mapSave != null);
|
mapSave.CanReset(), group.GetLeaderGUID().ToString(),
|
||||||
|
playerBind.save.GetMapId(), playerBind.save.GetInstanceId(),
|
||||||
// check for existing instance binds
|
playerBind.save.GetDifficultyID(), playerBind.save.GetPlayerCount(),
|
||||||
InstanceBind playerBind = player.GetBoundInstance(GetId(), GetDifficultyID());
|
playerBind.save.GetGroupCount(), playerBind.save.CanReset());
|
||||||
if (playerBind != null && playerBind.perm)
|
if (groupBind != null)
|
||||||
{
|
Log.outError(LogFilter.Maps,
|
||||||
// cannot enter other instances if bound permanently
|
"InstanceMap.Add: the group is bound to the instance {0} {1}, {2}, {3}, {4}, {5}, {6}",
|
||||||
if (playerBind.save != mapSave)
|
GetMapName(), groupBind.save.GetMapId(), groupBind.save.GetInstanceId(),
|
||||||
{
|
groupBind.save.GetDifficultyID(), groupBind.save.GetPlayerCount(),
|
||||||
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}",
|
groupBind.save.GetGroupCount(), groupBind.save.CanReset());
|
||||||
player.GetName(), player.GetGUID().ToString(), GetMapName(), playerBind.save.GetMapId(),
|
Cypher.Assert(false);
|
||||||
playerBind.save.GetInstanceId(), playerBind.save.GetDifficultyID(),
|
return false;
|
||||||
playerBind.save.GetPlayerCount(), playerBind.save.GetGroupCount(),
|
|
||||||
playerBind.save.CanReset(), GetMapName(), mapSave.GetMapId(), mapSave.GetInstanceId(),
|
|
||||||
mapSave.GetDifficultyID(), mapSave.GetPlayerCount(), mapSave.GetGroupCount(),
|
|
||||||
mapSave.CanReset());
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
// bind to the group or keep using the group save
|
||||||
|
if (groupBind == null)
|
||||||
|
group.BindToInstance(mapSave, false);
|
||||||
else
|
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
|
Log.outError(LogFilter.Maps,
|
||||||
InstanceBind groupBind = group.GetBoundInstance(this);
|
"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}!",
|
||||||
if (playerBind != null && playerBind.save != mapSave)
|
player.GetName(), player.GetGUID().ToString(), mapSave.GetMapId(), mapSave.GetInstanceId(),
|
||||||
{
|
mapSave.GetDifficultyID(), group.GetLeaderGUID().ToString(),
|
||||||
Log.outError(LogFilter.Maps,
|
groupBind.save.GetMapId(), groupBind.save.GetInstanceId(),
|
||||||
"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}!",
|
groupBind.save.GetDifficultyID());
|
||||||
player.GetName(), player.GetGUID().ToString(), GetMapName(), mapSave.GetMapId(), mapSave.GetInstanceId(),
|
Log.outError(LogFilter.Maps, "MapSave players: {0}, group count: {1}",
|
||||||
mapSave.GetDifficultyID(), mapSave.GetPlayerCount(), mapSave.GetGroupCount(),
|
mapSave.GetPlayerCount(), mapSave.GetGroupCount());
|
||||||
mapSave.CanReset(), group.GetLeaderGUID().ToString(),
|
if (groupBind.save != null)
|
||||||
playerBind.save.GetMapId(), playerBind.save.GetInstanceId(),
|
Log.outError(LogFilter.Maps, "GroupBind save players: {0}, group count: {1}",
|
||||||
playerBind.save.GetDifficultyID(), playerBind.save.GetPlayerCount(),
|
groupBind.save.GetPlayerCount(), groupBind.save.GetGroupCount());
|
||||||
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
|
else
|
||||||
{
|
Log.outError(LogFilter.Maps, "GroupBind save NULL");
|
||||||
// cannot jump to a different instance without resetting it
|
return false;
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
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
|
PendingRaidLock pendingRaidLock = new();
|
||||||
if (playerBind == null)
|
pendingRaidLock.TimeUntilLock = 60000;
|
||||||
player.BindToInstance(mapSave, false);
|
pendingRaidLock.CompletedMask = i_data != null ? i_data.GetCompletedEncounterMask() : 0;
|
||||||
else
|
pendingRaidLock.Extending = false;
|
||||||
// cannot jump to a different instance without resetting it
|
pendingRaidLock.WarningOnly = false; // events it throws: 1 : INSTANCE_LOCK_WARNING 0 : INSTANCE_LOCK_STOP / INSTANCE_LOCK_START
|
||||||
Cypher.Assert(playerBind.save == mapSave);
|
player.SendPacket(pendingRaidLock);
|
||||||
|
player.SetPendingBind(mapSave.GetInstanceId(), 60000);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else
|
||||||
// for normal instances cancel the reset schedule when the
|
{
|
||||||
// first player enters (no players yet)
|
// set up a solo bind or continue using it
|
||||||
SetResetSchedule(false);
|
if (playerBind == null)
|
||||||
|
player.BindToInstance(mapSave, false);
|
||||||
Log.outInfo(LogFilter.Maps, "MAP: Player '{0}' entered instance '{1}' of map '{2}'", player.GetName(),
|
else
|
||||||
GetInstanceId(), GetMapName());
|
// cannot jump to a different instance without resetting it
|
||||||
// initialize unload state
|
Cypher.Assert(playerBind.save == mapSave);
|
||||||
m_unloadTimer = 0;
|
}
|
||||||
m_resetAfterUnload = false;
|
|
||||||
m_unloadWhenEmpty = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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
|
// this will acquire the same mutex so it cannot be in the previous block
|
||||||
base.AddPlayerToMap(player, initPlayer);
|
base.AddPlayerToMap(player, initPlayer);
|
||||||
|
|
||||||
@@ -5117,7 +5182,7 @@ namespace Game.Maps
|
|||||||
public int GetTeamIdInInstance() { return scriptTeam; }
|
public int GetTeamIdInInstance() { return scriptTeam; }
|
||||||
|
|
||||||
public Team GetTeamInInstance() { return scriptTeam == TeamId.Alliance ? Team.Alliance : Team.Horde; }
|
public Team GetTeamInInstance() { return scriptTeam == TeamId.Alliance ? Team.Alliance : Team.Horde; }
|
||||||
|
|
||||||
public uint GetScriptId()
|
public uint GetScriptId()
|
||||||
{
|
{
|
||||||
return i_script_id;
|
return i_script_id;
|
||||||
@@ -5127,7 +5192,7 @@ namespace Game.Maps
|
|||||||
{
|
{
|
||||||
return $"{base.GetDebugInfo()}\nScriptId: {GetScriptId()} ScriptName: {GetScriptName()}";
|
return $"{base.GetDebugInfo()}\nScriptId: {GetScriptId()} ScriptName: {GetScriptName()}";
|
||||||
}
|
}
|
||||||
|
|
||||||
public InstanceScript GetInstanceScript()
|
public InstanceScript GetInstanceScript()
|
||||||
{
|
{
|
||||||
return i_data;
|
return i_data;
|
||||||
@@ -5146,8 +5211,8 @@ namespace Game.Maps
|
|||||||
|
|
||||||
public class BattlegroundMap : Map
|
public class BattlegroundMap : Map
|
||||||
{
|
{
|
||||||
public BattlegroundMap(uint id, uint expiry, uint InstanceId, Map _parent, Difficulty spawnMode)
|
public BattlegroundMap(uint id, uint expiry, uint InstanceId, Difficulty spawnMode)
|
||||||
: base(id, expiry, InstanceId, spawnMode, _parent)
|
: base(id, expiry, InstanceId, spawnMode)
|
||||||
{
|
{
|
||||||
InitVisibilityDistance();
|
InitVisibilityDistance();
|
||||||
}
|
}
|
||||||
@@ -5175,9 +5240,7 @@ namespace Game.Maps
|
|||||||
|
|
||||||
public override bool AddPlayerToMap(Player player, bool initPlayer = true)
|
public override bool AddPlayerToMap(Player player, bool initPlayer = true)
|
||||||
{
|
{
|
||||||
lock (_mapLock)
|
player.m_InstanceValid = true;
|
||||||
player.m_InstanceValid = true;
|
|
||||||
|
|
||||||
return base.AddPlayerToMap(player, initPlayer);
|
return base.AddPlayerToMap(player, initPlayer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+212
-193
@@ -17,12 +17,15 @@
|
|||||||
|
|
||||||
using Framework.Constants;
|
using Framework.Constants;
|
||||||
using Framework.Database;
|
using Framework.Database;
|
||||||
|
using Game.BattleGrounds;
|
||||||
using Game.DataStorage;
|
using Game.DataStorage;
|
||||||
|
using Game.Garrisons;
|
||||||
using Game.Groups;
|
using Game.Groups;
|
||||||
using Game.Maps;
|
using Game.Maps;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections;
|
using System.Collections;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
namespace Game.Entities
|
namespace Game.Entities
|
||||||
{
|
{
|
||||||
@@ -49,161 +52,202 @@ namespace Game.Entities
|
|||||||
pair.Value.InitVisibilityDistance();
|
pair.Value.InitVisibilityDistance();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Map CreateBaseMap(uint id)
|
Map FindMap_i(uint mapId, uint instanceId)
|
||||||
{
|
{
|
||||||
Map map = FindBaseMap(id);
|
return i_maps.LookupByKey((mapId, instanceId));
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Map CreateBaseMap_i(MapRecord mapEntry)
|
Map CreateWorldMap(uint mapId, uint instanceId)
|
||||||
{
|
{
|
||||||
Map map;
|
Map map = new Map(mapId, i_gridCleanUpDelay, instanceId, Difficulty.None);
|
||||||
if (mapEntry.Instanceable())
|
map.LoadRespawnTimes();
|
||||||
map = new MapInstanced(mapEntry.Id, i_gridCleanUpDelay);
|
map.LoadCorpseData();
|
||||||
else
|
|
||||||
map = new Map(mapEntry.Id, i_gridCleanUpDelay, 0, Difficulty.None);
|
|
||||||
|
|
||||||
i_maps[mapEntry.Id] = map;
|
if (WorldConfig.GetBoolValue(WorldCfg.BasemapLoadGrids))
|
||||||
|
map.LoadAllCells();
|
||||||
if (!mapEntry.Instanceable())
|
|
||||||
{
|
|
||||||
map.LoadRespawnTimes();
|
|
||||||
map.LoadCorpseData();
|
|
||||||
}
|
|
||||||
|
|
||||||
return map;
|
return map;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Map FindBaseNonInstanceMap(uint mapId)
|
InstanceMap CreateInstance(uint mapId, uint instanceId, InstanceSave save, Difficulty difficulty, int team)
|
||||||
{
|
{
|
||||||
Map map = FindBaseMap(mapId);
|
// make sure we have a valid map id
|
||||||
if (map != null && map.Instanceable())
|
var entry = CliDB.MapStorage.LookupByKey(mapId);
|
||||||
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);
|
|
||||||
if (entry == null)
|
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())
|
Log.outError(LogFilter.Maps, $"CreateInstance: no entry for map {mapId}");
|
||||||
{
|
//ABORT();
|
||||||
// let enter in ghost mode in instance that connected to inner instance with corpse
|
return null;
|
||||||
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());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//Get instance where player's group is bound & its map
|
// some instances only have one difficulty
|
||||||
if (!loginCheck && group)
|
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);
|
Map map = null;
|
||||||
if (boundInstance != null && boundInstance.save != null)
|
uint newInstanceId = 0; // instanceId of the resulting map
|
||||||
|
|
||||||
|
if (entry.IsBattlegroundOrArena())
|
||||||
{
|
{
|
||||||
Map boundMap = FindMap(mapid, boundInstance.save.GetInstanceId());
|
// instantiate or find existing bg map for player
|
||||||
if (boundMap != null)
|
// 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);
|
Battleground bg = player.GetBattleground();
|
||||||
if (denyReason != 0)
|
if (bg != null)
|
||||||
return denyReason;
|
map = CreateBattleground(mapId, newInstanceId, bg);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
player.TeleportToBGEntryPoint();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
else if (entry.IsDungeon())
|
||||||
// players are only allowed to enter 10 instances per hour
|
{
|
||||||
if (entry.IsDungeon() && (player.GetGroup() == null || (player.GetGroup() != null && !player.GetGroup().IsLFGGroup())))
|
InstanceBind pBind = player.GetBoundInstance(mapId, player.GetDifficultyID(entry));
|
||||||
{
|
InstanceSave pSave = pBind != null ? pBind.save : null;
|
||||||
uint instaceIdToCheck = 0;
|
|
||||||
InstanceSave save = player.GetInstanceSave(mapid);
|
|
||||||
if (save != null)
|
|
||||||
instaceIdToCheck = save.GetInstanceId();
|
|
||||||
|
|
||||||
// instanceId can never be 0 - will not be found
|
// priority:
|
||||||
if (!player.CheckInstanceCount(instaceIdToCheck) && !player.IsDead())
|
// 1. player's permanent bind
|
||||||
return EnterState.CannotEnterTooManyInstances;
|
// 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)
|
public void Update(uint diff)
|
||||||
@@ -213,8 +257,16 @@ namespace Game.Entities
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
var time = (uint)i_timer.GetCurrent();
|
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)
|
if (m_updater != null)
|
||||||
m_updater.ScheduleUpdate(map, (uint)i_timer.GetCurrent());
|
m_updater.ScheduleUpdate(map, (uint)i_timer.GetCurrent());
|
||||||
else
|
else
|
||||||
@@ -230,6 +282,23 @@ namespace Game.Entities
|
|||||||
i_timer.SetCurrent(0);
|
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)
|
public bool IsValidMAP(uint mapId)
|
||||||
{
|
{
|
||||||
return CliDB.MapStorage.ContainsKey(mapId);
|
return CliDB.MapStorage.ContainsKey(mapId);
|
||||||
@@ -253,38 +322,13 @@ namespace Game.Entities
|
|||||||
public uint GetNumInstances()
|
public uint GetNumInstances()
|
||||||
{
|
{
|
||||||
lock (_mapsLock)
|
lock (_mapsLock)
|
||||||
{
|
return (uint)i_maps.Count(pair => pair.Value.IsDungeon());
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public uint GetNumPlayersInInstances()
|
public uint GetNumPlayersInInstances()
|
||||||
{
|
{
|
||||||
lock (_mapsLock)
|
lock (_mapsLock)
|
||||||
{
|
return (uint)i_maps.Sum(pair => pair.Value.IsDungeon() ? pair.Value.GetPlayers().Count : 0);
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void InitInstanceIds()
|
public void InitInstanceIds()
|
||||||
@@ -375,27 +419,12 @@ namespace Game.Entities
|
|||||||
|
|
||||||
public void SetNextInstanceId(uint nextInstanceId) { _nextInstanceId = nextInstanceId; }
|
public void SetNextInstanceId(uint nextInstanceId) { _nextInstanceId = nextInstanceId; }
|
||||||
|
|
||||||
Map FindBaseMap(uint mapId)
|
|
||||||
{
|
|
||||||
return i_maps.LookupByKey(mapId);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void DoForAllMaps(Action<Map> worker)
|
public void DoForAllMaps(Action<Map> worker)
|
||||||
{
|
{
|
||||||
lock (_mapsLock)
|
lock (_mapsLock)
|
||||||
{
|
{
|
||||||
foreach (var map in i_maps.Values)
|
foreach (var (_, map) in i_maps)
|
||||||
{
|
worker(map);
|
||||||
MapInstanced mapInstanced = map.ToMapInstanced();
|
|
||||||
if (mapInstanced)
|
|
||||||
{
|
|
||||||
var instances = mapInstanced.GetInstancedMaps();
|
|
||||||
foreach (var instance in instances.Values)
|
|
||||||
worker(instance);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
worker(map);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -403,19 +432,9 @@ namespace Game.Entities
|
|||||||
{
|
{
|
||||||
lock (_mapsLock)
|
lock (_mapsLock)
|
||||||
{
|
{
|
||||||
var map = i_maps.LookupByKey(mapId);
|
var list = i_maps.Where(pair => pair.Key.mapId == mapId && pair.Key.instanceId >= 0);
|
||||||
if (map != null)
|
foreach (var (_, map) in list)
|
||||||
{
|
worker(map);
|
||||||
MapInstanced mapInstanced = map.ToMapInstanced();
|
|
||||||
if (mapInstanced)
|
|
||||||
{
|
|
||||||
var instances = mapInstanced.GetInstancedMaps();
|
|
||||||
foreach (var instance in instances)
|
|
||||||
worker(instance.Value);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
worker(map);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -424,7 +443,7 @@ namespace Game.Entities
|
|||||||
public void DecreaseScheduledScriptCount(uint count) { _scheduledScripts -= count; }
|
public void DecreaseScheduledScriptCount(uint count) { _scheduledScripts -= count; }
|
||||||
public bool IsScriptScheduled() { return _scheduledScripts > 0; }
|
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();
|
IntervalTimer i_timer = new();
|
||||||
object _mapsLock= new();
|
object _mapsLock= new();
|
||||||
uint i_gridCleanUpDelay;
|
uint i_gridCleanUpDelay;
|
||||||
|
|||||||
@@ -146,10 +146,11 @@ namespace Game.Maps
|
|||||||
TerrainInfo _parentTerrain;
|
TerrainInfo _parentTerrain;
|
||||||
List<TerrainInfo> _childTerrain = new();
|
List<TerrainInfo> _childTerrain = new();
|
||||||
|
|
||||||
object _loadMutex = new();
|
object _loadLock = new();
|
||||||
GridMap[][] _gridMap = new GridMap[MapConst.MaxGrids][];
|
GridMap[][] _gridMap = new GridMap[MapConst.MaxGrids][];
|
||||||
ushort[][] _referenceCountFromMap = new ushort[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)
|
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);
|
static TimeSpan CleanupInterval = TimeSpan.FromMinutes(1);
|
||||||
@@ -187,9 +188,9 @@ namespace Game.Maps
|
|||||||
{
|
{
|
||||||
var build = reader.ReadUInt32();
|
var build = reader.ReadUInt32();
|
||||||
byte[] tilesData = reader.ReadArray<byte>(MapConst.MaxGrids * MapConst.MaxGrids);
|
byte[] tilesData = reader.ReadArray<byte>(MapConst.MaxGrids * MapConst.MaxGrids);
|
||||||
for (uint gx = 0; gx < MapConst.MaxGrids; ++gx)
|
for (int gx = 0; gx < MapConst.MaxGrids; ++gx)
|
||||||
for (uint gy = 0; gy < MapConst.MaxGrids; ++gy)
|
for (int gy = 0; gy < MapConst.MaxGrids; ++gy)
|
||||||
_gridFileExists[(int)(gx * MapConst.MaxGrids + gy)] = tilesData[(int)(gx * MapConst.MaxGrids + gy)] == 49; // char of 1
|
_gridFileExists[GetBitsetIndex(gx, gy)] = tilesData[GetBitsetIndex(gx, gy)] == 49; // char of 1
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -197,7 +198,7 @@ namespace Game.Maps
|
|||||||
|
|
||||||
for (int gx = 0; gx < MapConst.MaxGrids; ++gx)
|
for (int gx = 0; gx < MapConst.MaxGrids; ++gx)
|
||||||
for (int gy = 0; gy < MapConst.MaxGrids; ++gy)
|
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)
|
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)
|
public bool HasChildTerrainGridFile(uint mapId, int gx, int gy)
|
||||||
{
|
{
|
||||||
var childMap = _childTerrain.Find(childTerrain => childTerrain.GetId() == mapId);
|
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)
|
public void AddChildTerrain(TerrainInfo childTerrain)
|
||||||
@@ -278,8 +279,8 @@ namespace Game.Maps
|
|||||||
if (++_referenceCountFromMap[gx][gy] != 1) // check if already loaded
|
if (++_referenceCountFromMap[gx][gy] != 1) // check if already loaded
|
||||||
return;
|
return;
|
||||||
|
|
||||||
//std::lock_guard < std::mutex > lock (_loadMutex) ;
|
lock(_loadLock)
|
||||||
LoadMapAndVMapImpl(gx, gy);
|
LoadMapAndVMapImpl(gx, gy);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void LoadMapAndVMapImpl(int gx, int gy)
|
public void LoadMapAndVMapImpl(int gx, int gy)
|
||||||
@@ -290,6 +291,8 @@ namespace Game.Maps
|
|||||||
|
|
||||||
foreach (TerrainInfo childTerrain in _childTerrain)
|
foreach (TerrainInfo childTerrain in _childTerrain)
|
||||||
childTerrain.LoadMapAndVMapImpl(gx, gy);
|
childTerrain.LoadMapAndVMapImpl(gx, gy);
|
||||||
|
|
||||||
|
_loadedGrids[GetBitsetIndex(gx, gy)] = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void LoadMap(int gx, int gy)
|
public void LoadMap(int gx, int gy)
|
||||||
@@ -297,7 +300,7 @@ namespace Game.Maps
|
|||||||
if (_gridMap[gx][gy] != null)
|
if (_gridMap[gx][gy] != null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (!_gridFileExists[gx * MapConst.MaxGrids + gy])
|
if (!_gridFileExists[GetBitsetIndex(gx, gy)])
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// map file name
|
// map file name
|
||||||
@@ -310,7 +313,7 @@ namespace Game.Maps
|
|||||||
if (gridMapLoadResult == LoadResult.Success)
|
if (gridMapLoadResult == LoadResult.Success)
|
||||||
_gridMap[gx][gy] = gridMap;
|
_gridMap[gx][gy] = gridMap;
|
||||||
else
|
else
|
||||||
_gridFileExists[gx * MapConst.MaxGrids + gy] = false;
|
_gridFileExists[GetBitsetIndex(gx, gy)] = false;
|
||||||
|
|
||||||
if (gridMapLoadResult == LoadResult.ReadFromFileFailed)
|
if (gridMapLoadResult == LoadResult.ReadFromFileFailed)
|
||||||
Log.outError(LogFilter.Maps, $"Error loading map file: {fileName}");
|
Log.outError(LogFilter.Maps, $"Error loading map file: {fileName}");
|
||||||
@@ -328,7 +331,8 @@ namespace Game.Maps
|
|||||||
case LoadResult.Success:
|
case LoadResult.Success:
|
||||||
Log.outDebug(LogFilter.Maps, $"VMAP loaded name:{GetMapName()}, id:{GetId()}, x:{gx}, y:{gy} (vmap rep.: x:{gx}, y:{gy})");
|
Log.outDebug(LogFilter.Maps, $"VMAP loaded name:{GetMapName()}, id:{GetId()}, x:{gx}, y:{gy} (vmap rep.: x:{gx}, y:{gy})");
|
||||||
break;
|
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})");
|
Log.outError(LogFilter.Maps, $"Could not load VMAP name:{GetMapName()}, id:{GetId()}, x:{gx}, y:{gy} (vmap rep.: x:{gx}, y:{gy})");
|
||||||
break;
|
break;
|
||||||
case LoadResult.DisabledInConfig:
|
case LoadResult.DisabledInConfig:
|
||||||
@@ -363,6 +367,8 @@ namespace Game.Maps
|
|||||||
|
|
||||||
foreach (var childTerrain in _childTerrain)
|
foreach (var childTerrain in _childTerrain)
|
||||||
childTerrain.UnloadMapImpl(gx, gy);
|
childTerrain.UnloadMapImpl(gx, gy);
|
||||||
|
|
||||||
|
_loadedGrids[GetBitsetIndex(gx, gy)] = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public GridMap GetGrid(uint mapId, float x, float y, bool loadIfMissing = true)
|
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
|
int gy = (int)(MapConst.CenterGridId - y / MapConst.SizeofGrids); //grid y
|
||||||
|
|
||||||
// ensure GridMap is loaded
|
// ensure GridMap is loaded
|
||||||
if (_gridMap[gx][gy] == null && loadIfMissing)
|
if (_loadedGrids[GetBitsetIndex(gx, gy)] && loadIfMissing)
|
||||||
{
|
{
|
||||||
//std::lock_guard < std::mutex > lock (_loadMutex) ;
|
lock(_loadLock)
|
||||||
LoadMapAndVMapImpl(gx, gy);
|
LoadMapAndVMapImpl(gx, gy);
|
||||||
}
|
}
|
||||||
|
|
||||||
GridMap grid = _gridMap[gx][gy];
|
GridMap grid = _gridMap[gx][gy];
|
||||||
@@ -398,7 +404,7 @@ namespace Game.Maps
|
|||||||
// delete those GridMap objects which have refcount = 0
|
// delete those GridMap objects which have refcount = 0
|
||||||
for (int x = 0; x < MapConst.MaxGrids; ++x)
|
for (int x = 0; x < MapConst.MaxGrids; ++x)
|
||||||
for (int y = 0; y < MapConst.MaxGrids; ++y)
|
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);
|
UnloadMapImpl(x, y);
|
||||||
|
|
||||||
_cleanupTimer.Reset(CleanupInterval);
|
_cleanupTimer.Reset(CleanupInterval);
|
||||||
@@ -889,5 +895,7 @@ namespace Game.Maps
|
|||||||
}
|
}
|
||||||
|
|
||||||
public uint GetId() { return _mapId; }
|
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;
|
break;
|
||||||
|
|
||||||
if (_currentNode == _preloadTargetNode)
|
if (_currentNode == _preloadTargetNode)
|
||||||
PreloadEndGrid();
|
PreloadEndGrid(owner);
|
||||||
|
|
||||||
_currentNode += (departureEvent ? 1 : 0);
|
_currentNode += (departureEvent ? 1 : 0);
|
||||||
departureEvent = !departureEvent;
|
departureEvent = !departureEvent;
|
||||||
@@ -262,14 +262,17 @@ namespace Game.Movement
|
|||||||
else
|
else
|
||||||
_preloadTargetNode = (uint)nodeCount - 3;
|
_preloadTargetNode = (uint)nodeCount - 3;
|
||||||
|
|
||||||
|
while (_path[(int)_preloadTargetNode].ContinentID != _endMapId)
|
||||||
|
++_preloadTargetNode;
|
||||||
|
|
||||||
_endGridX = _path[nodeCount - 1].Loc.X;
|
_endGridX = _path[nodeCount - 1].Loc.X;
|
||||||
_endGridY = _path[nodeCount - 1].Loc.Y;
|
_endGridY = _path[nodeCount - 1].Loc.Y;
|
||||||
}
|
}
|
||||||
|
|
||||||
void PreloadEndGrid()
|
void PreloadEndGrid(Player owner)
|
||||||
{
|
{
|
||||||
// Used to preload the final grid where the flightmaster is
|
// Used to preload the final grid where the flightmaster is
|
||||||
Map endMap = Global.MapMgr.FindBaseNonInstanceMap(_endMapId);
|
Map endMap = owner.GetMap();
|
||||||
|
|
||||||
// Load the grid
|
// Load the grid
|
||||||
if (endMap != null)
|
if (endMap != null)
|
||||||
|
|||||||
@@ -1116,19 +1116,6 @@ namespace Game
|
|||||||
|
|
||||||
Log.outInfo(LogFilter.ServerLoading, "Loading phase names...");
|
Log.outInfo(LogFilter.ServerLoading, "Loading phase names...");
|
||||||
Global.ObjectMgr.LoadPhaseNames();
|
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)
|
public void LoadConfigSettings(bool reload = false)
|
||||||
|
|||||||
Reference in New Issue
Block a user