diff --git a/Source/Game/Collision/Management/VMapManager.cs b/Source/Game/Collision/Management/VMapManager.cs index 226add0fd..0536fcc17 100644 --- a/Source/Game/Collision/Management/VMapManager.cs +++ b/Source/Game/Collision/Management/VMapManager.cs @@ -183,13 +183,15 @@ namespace Game.Collision public WorldModel AcquireModelInstance(string filename) { + ManagedModel worldmodel; // this is intentionally declared before lock so that it is destroyed after it to prevent deadlocks in releaseModelInstance + lock (LoadedModelFilesLock) { filename = filename.TrimEnd('\0'); - if (iLoadedModelFiles.TryGetValue(filename, out ManagedModel worldmodel)) + if (iLoadedModelFiles.TryGetValue(filename, out worldmodel)) return worldmodel.Model; - var model = new ManagedModel(); + var model = new ManagedModel(filename); if (!model.Model.ReadFile(VMapPath + filename)) { Log.outError(LogFilter.Server, $"VMapManager: could not load '{filename}'"); @@ -198,8 +200,6 @@ namespace Game.Collision Log.outDebug(LogFilter.Maps, $"VMapManager: loading file '{filename}'"); - worldmodel.Model.SetName(filename); - model = worldmodel; iLoadedModelFiles.Add(filename, model); @@ -212,14 +212,15 @@ namespace Game.Collision lock (LoadedModelFilesLock) { filename = filename.TrimEnd('\0'); + + Log.outDebug(LogFilter.Maps, $"VMapManager: unloading file '{filename}'"); + var erased = iLoadedModelFiles.Remove(filename); if (!erased) { Log.outError(LogFilter.Server, $"VMapManager: trying to unload non-loaded file '{filename}'"); return; } - - Log.outDebug(LogFilter.Maps, $"VMapManager: unloading file '{filename}'"); } } @@ -271,10 +272,16 @@ namespace Game.Collision public class ManagedModel { public WorldModel Model; + string _name; // valid only while model is held in VMapManager2::iLoadedModelFiles + + public ManagedModel(string name) + { + _name = name; + } ~ManagedModel() { - Global.VMapMgr.ReleaseModelInstance(Model.GetName()); + Global.VMapMgr.ReleaseModelInstance(_name); } } diff --git a/Source/Game/Collision/Maps/MapTree.cs b/Source/Game/Collision/Maps/MapTree.cs index 06fe4ba2c..19f6f9a60 100644 --- a/Source/Game/Collision/Maps/MapTree.cs +++ b/Source/Game/Collision/Maps/MapTree.cs @@ -123,6 +123,7 @@ namespace Game.Collision if (referencedVal >= iTreeValues.Length) { Log.outError(LogFilter.Maps, $"StaticMapTree::LoadMapTile() : invalid tree element ({referencedVal}/{iTreeValues.Length}) referenced in tile {fileResult.Name}"); + result = LoadResult.ReadFromFileFailed; continue; } @@ -175,23 +176,22 @@ namespace Game.Collision for (uint i = 0; i < numSpawns && result; ++i) { // read model spawns - ModelSpawn spawn; - result = ModelSpawn.ReadFromFile(reader, out spawn); - if (result) - { - // update tree - int referencedNode = spawnIndicesReader.ReadInt32(); - if (referencedNode >= iTreeValues.Length) - { - Log.outError(LogFilter.Maps, $"StaticMapTree::LoadMapTile() : invalid tree element ({referencedNode}/{iTreeValues.Length}) referenced in tile {fileResult.Name}"); - continue; - } + if (!ModelSpawn.ReadFromFile(reader, out ModelSpawn spawn)) + break; - if (iTreeValues[referencedNode].GetWorldModel() == null) - Log.outError(LogFilter.Misc, $"StaticMapTree::UnloadMapTile() : trying to unload non-referenced model '{spawn.name}' (ID:{spawn.Id})"); - else if (iTreeValues[referencedNode].RemoveTileReference() == 0) - iTreeValues[referencedNode].SetUnloaded(); + // update tree + int referencedNode = spawnIndicesReader.ReadInt32(); + if (referencedNode >= iTreeValues.Length) + { + Log.outError(LogFilter.Maps, $"StaticMapTree::LoadMapTile() : invalid tree element ({referencedNode}/{iTreeValues.Length}) referenced in tile {fileResult.Name}"); + result = false; + continue; } + + if (iTreeValues[referencedNode].GetWorldModel() == null) + Log.outError(LogFilter.Misc, $"StaticMapTree::UnloadMapTile() : trying to unload non-referenced model '{spawn.name}' (ID:{spawn.Id})"); + else if (iTreeValues[referencedNode].RemoveTileReference() == 0) + iTreeValues[referencedNode].SetUnloaded(); } } } diff --git a/Source/Game/Collision/Models/WorldModel.cs b/Source/Game/Collision/Models/WorldModel.cs index 8cd88264b..426ec13a9 100644 --- a/Source/Game/Collision/Models/WorldModel.cs +++ b/Source/Game/Collision/Models/WorldModel.cs @@ -331,7 +331,6 @@ namespace Game.Collision uint RootWMOID; List groupModels = new(); BIH groupTree = new(); - string name; // valid only while model is held in VMapManager2::iLoadedModelFiles public override bool IntersectRay(Ray ray, ref float distance, bool stopAtFirstHit, ModelIgnoreFlags ignoreFlags) { @@ -423,9 +422,6 @@ namespace Game.Collision return groupTree.ReadFromFile(reader); } - public string GetName() { return name; } - public void SetName(string newName) { name = newName; } - public bool IsM2() { return Flags.HasFlag(ModelFlags.IsM2); } }