Core/Maps: Updated vmaps and some cleaups

This commit is contained in:
hondacrx
2018-05-03 00:05:50 -04:00
parent 3ca70aae30
commit 1a7f31d4f2
14 changed files with 204 additions and 269 deletions
+7 -7
View File
@@ -61,16 +61,16 @@ namespace Framework.Constants
public const float MaxHeight = 100000.0f; public const float MaxHeight = 100000.0f;
public const float MaxFallDistance = 250000.0f; public const float MaxFallDistance = 250000.0f;
public const string MapMagic = "MAPS"; public const uint MapMagic = 0x5350414D; //"MAPS";
public const string MapVersionMagic = "v1.9"; public const uint MapVersionMagic = 0x392E3176; //"v1.9";
public const string MapAreaMagic = "AREA"; public const uint MapAreaMagic = 0x41455241; //"AREA";
public const string MapHeightMagic = "MHGT"; public const uint MapHeightMagic = 0x5447484D; //"MHGT";
public const string MapLiquidMagic = "MLIQ"; public const uint MapLiquidMagic = 0x51494C4D; //"MLIQ";
public const string mmapMagic = "MMAP"; public const uint mmapMagic = 0x4D4D4150; // 'MMAP'
public const int mmapVersion = 9; public const int mmapVersion = 9;
public const string VMapMagic = "VMAP_4.7"; public const string VMapMagic = "VMAP_4.8";
public const float VMAPInvalidHeightValue = -200000.0f; public const float VMAPInvalidHeightValue = -200000.0f;
} }
+2 -23
View File
@@ -294,27 +294,6 @@ namespace System
#endregion #endregion
#region BinaryReader #region BinaryReader
public static T ReadStruct<T>(this BinaryReader reader) where T : struct
{
byte[] data = reader.ReadBytes(Marshal.SizeOf(typeof(T)));
GCHandle handle = GCHandle.Alloc(data, GCHandleType.Pinned);
T returnObject = (T)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(T));
handle.Free();
return returnObject;
}
public static T ReadStruct<T>(this BinaryReader reader, uint offset) where T : struct
{
reader.BaseStream.Position = offset;
byte[] data = reader.ReadBytes(Marshal.SizeOf(typeof(T)));
GCHandle handle = GCHandle.Alloc(data, GCHandleType.Pinned);
T returnObject = (T)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(T));
handle.Free();
return returnObject;
}
public static string ReadCString(this BinaryReader reader) public static string ReadCString(this BinaryReader reader)
{ {
byte num; byte num;
@@ -337,9 +316,9 @@ namespace System
return new string(reader.ReadChars(count)); return new string(reader.ReadChars(count));
} }
public static T[] ReadArray<T>(this BinaryReader reader, int size) where T : struct public static T[] ReadArray<T>(this BinaryReader reader, uint size) where T : struct
{ {
int numBytes = FastStruct<T>.Size * size; int numBytes = FastStruct<T>.Size * (int)size;
byte[] result = reader.ReadBytes(numBytes); byte[] result = reader.ReadBytes(numBytes);
@@ -276,14 +276,10 @@ namespace Game.Collision
bounds = new AxisAlignedBox(lo, hi); bounds = new AxisAlignedBox(lo, hi);
uint treeSize = reader.ReadUInt32(); uint treeSize = reader.ReadUInt32();
tree = new uint[treeSize]; tree = reader.ReadArray<uint>(treeSize);
for (var i = 0; i < treeSize; i++)
tree[i] = reader.ReadUInt32();
var count = reader.ReadUInt32(); var count = reader.ReadUInt32();
objects = new uint[count]; objects = reader.ReadArray<uint>(count);
for (var i = 0; i < count; i++)
objects[i] = reader.ReadUInt32();
return true; return true;
} }
+30 -22
View File
@@ -70,7 +70,7 @@ namespace Game.Collision
{ {
string filename = VMapPath + getMapFileName(mapId); string filename = VMapPath + getMapFileName(mapId);
StaticMapTree newTree = new StaticMapTree(mapId); StaticMapTree newTree = new StaticMapTree(mapId);
if (!newTree.InitMap(filename, this)) if (!newTree.InitMap(filename))
return false; return false;
iInstanceMapTrees.Add(mapId, newTree); iInstanceMapTrees.Add(mapId, newTree);
@@ -235,36 +235,42 @@ namespace Game.Collision
public WorldModel acquireModelInstance(string filename) public WorldModel acquireModelInstance(string filename)
{ {
var model = iLoadedModelFiles.LookupByKey(filename); lock (LoadedModelFilesLock)
if (model == null)
{ {
WorldModel worldmodel = new WorldModel(); var model = iLoadedModelFiles.LookupByKey(filename);
if (!worldmodel.readFile(VMapPath + filename + ".vmo")) if (model == null)
{ {
Log.outError(LogFilter.Server, "VMapManager: could not load '{0}.vmo'", filename); WorldModel worldmodel = new WorldModel();
return null; if (!worldmodel.readFile(VMapPath + filename + ".vmo"))
{
Log.outError(LogFilter.Server, "VMapManager: could not load '{0}.vmo'", filename);
return null;
}
Log.outDebug(LogFilter.Maps, "VMapManager: loading file '{0}'", filename);
iLoadedModelFiles.Add(filename, new ManagedModel());
model = iLoadedModelFiles.LookupByKey(filename);
model.setModel(worldmodel);
} }
Log.outDebug(LogFilter.Maps, "VMapManager: loading file '{0}'", filename); model.incRefCount();
iLoadedModelFiles.Add(filename, new ManagedModel()); return model.getModel();
model = iLoadedModelFiles.LookupByKey(filename);
model.setModel(worldmodel);
} }
model.incRefCount();
return model.getModel();
} }
public void releaseModelInstance(string filename) public void releaseModelInstance(string filename)
{ {
var model = iLoadedModelFiles.LookupByKey(filename); lock (LoadedModelFilesLock)
if (model == null)
{ {
Log.outError(LogFilter.Server, "VMapManager: trying to unload non-loaded file '{0}'", filename); var model = iLoadedModelFiles.LookupByKey(filename);
return; if (model == null)
} {
if (model.decRefCount() == 0) Log.outError(LogFilter.Server, "VMapManager: trying to unload non-loaded file '{0}'", filename);
{ return;
Log.outDebug(LogFilter.Maps, "VMapManager: unloading file '{0}'", filename); }
iLoadedModelFiles.Remove(filename); if (model.decRefCount() == 0)
{
Log.outDebug(LogFilter.Maps, "VMapManager: unloading file '{0}'", filename);
iLoadedModelFiles.Remove(filename);
}
} }
} }
@@ -310,6 +316,8 @@ namespace Game.Collision
Dictionary<uint, uint> iParentMapData = new Dictionary<uint, uint>(); Dictionary<uint, uint> iParentMapData = new Dictionary<uint, uint>();
bool _enableLineOfSightCalc; bool _enableLineOfSightCalc;
bool _enableHeightCalc; bool _enableHeightCalc;
object LoadedModelFilesLock = new object();
} }
public class ManagedModel public class ManagedModel
+12 -48
View File
@@ -58,47 +58,23 @@ namespace Game.Collision
iMapID = mapId; iMapID = mapId;
} }
public bool InitMap(string fname, VMapManager vm) public bool InitMap(string fname)
{ {
Log.outDebug(LogFilter.Maps, "StaticMapTree.InitMap() : initializing StaticMapTree '{0}'", fname); Log.outDebug(LogFilter.Maps, "StaticMapTree.InitMap() : initializing StaticMapTree '{0}'", fname);
bool success = false; bool success = false;
if (!File.Exists(fname)) if (!File.Exists(fname))
return false; return false;
char tiled = '0';
using (BinaryReader reader = new BinaryReader(new FileStream(fname, FileMode.Open, FileAccess.Read))) using (BinaryReader reader = new BinaryReader(new FileStream(fname, FileMode.Open, FileAccess.Read)))
{ {
var magic = reader.ReadStringFromChars(8); var magic = reader.ReadStringFromChars(8);
tiled = reader.ReadChar();
var node = reader.ReadStringFromChars(4); var node = reader.ReadStringFromChars(4);
if (magic == MapConst.VMapMagic && node == "NODE" && iTree.readFromFile(reader)) if (magic == MapConst.VMapMagic && node == "NODE" && iTree.readFromFile(reader))
{ {
iNTreeValues = iTree.primCount(); iNTreeValues = iTree.primCount();
iTreeValues = new ModelInstance[iNTreeValues]; iTreeValues = new ModelInstance[iNTreeValues];
success = reader.ReadStringFromChars(4) == "GOBJ"; success = true;
}
iIsTiled = (tiled == 1);
// global model spawns
// only non-tiled maps have them, and if so exactly one (so far at least...)
ModelSpawn spawn;
if (!iIsTiled && ModelSpawn.readFromFile(reader, out spawn))
{
WorldModel model = vm.acquireModelInstance(spawn.name);
Log.outDebug(LogFilter.Maps, "StaticMapTree.InitMap() : loading {0}", spawn.name);
if (model != null)
{
// assume that global model always is the first and only tree value (could be improved...)
iTreeValues[0] = new ModelInstance(spawn, model);
iLoadedSpawns[0] = 1;
}
else
{
success = false;
Log.outError(LogFilter.Server, "StaticMapTree.InitMap() : could not acquire WorldModel for '{0}'", spawn.name);
}
} }
if (success) if (success)
@@ -107,7 +83,7 @@ namespace Game.Collision
if (success) if (success)
{ {
uint spawnIndicesSize = reader.ReadUInt32(); uint spawnIndicesSize = reader.ReadUInt32();
for (uint i = 0; i < spawnIndicesSize && success; ++i) for (uint i = 0; i < spawnIndicesSize; ++i)
{ {
uint spawnId = reader.ReadUInt32(); uint spawnId = reader.ReadUInt32();
uint spawnIndex = reader.ReadUInt32(); uint spawnIndex = reader.ReadUInt32();
@@ -133,13 +109,6 @@ namespace Game.Collision
public bool LoadMapTile(uint tileX, uint tileY, VMapManager vm) public bool LoadMapTile(uint tileX, uint tileY, VMapManager vm)
{ {
if (!iIsTiled)
{
// currently, core creates grids for all maps, whether it has terrain tiles or not
// so we need "fake" tile loads to know when we can unload map geometry
iLoadedTiles[packTileID(tileX, tileY)] = false;
return true;
}
if (iTreeValues == null) if (iTreeValues == null)
{ {
Log.outError(LogFilter.Server, "StaticMapTree.LoadMapTile() : tree has not been initialized [{0}, {1}]", tileX, tileY); Log.outError(LogFilter.Server, "StaticMapTree.LoadMapTile() : tree has not been initialized [{0}, {1}]", tileX, tileY);
@@ -285,25 +254,21 @@ namespace Game.Collision
{ {
if (reader.ReadStringFromChars(8) != MapConst.VMapMagic) if (reader.ReadStringFromChars(8) != MapConst.VMapMagic)
return false; return false;
}
char tiled = reader.ReadChar(); FileStream stream = OpenMapTileFile(vmapPath, mapID, tileX, tileY, vm);
if (tiled == 1) if (stream == null)
{ return false;
FileStream stream = OpenMapTileFile(vmapPath, mapID, tileX, tileY, vm); using (BinaryReader reader = new BinaryReader(stream))
if (stream == null) {
return false; if (reader.ReadStringFromChars(8) != MapConst.VMapMagic)
return false;
using (BinaryReader reader1 = new BinaryReader(stream))
{
if (reader1.ReadStringFromChars(8) != MapConst.VMapMagic)
return false;
}
}
} }
return true; return true;
} }
public static string getTileFileName(uint mapID, uint tileX, uint tileY) public static string getTileFileName(uint mapID, uint tileX, uint tileY)
{ {
return string.Format("{0:D4}_{1:D2}_{2:D2}.vmtile", mapID, tileY, tileX); return string.Format("{0:D4}_{1:D2}_{2:D2}.vmtile", mapID, tileY, tileX);
@@ -425,7 +390,6 @@ namespace Game.Collision
public int numLoadedTiles() { return iLoadedTiles.Count; } public int numLoadedTiles() { return iLoadedTiles.Count; }
uint iMapID; uint iMapID;
bool iIsTiled;
BIH iTree = new BIH(); BIH iTree = new BIH();
ModelInstance[] iTreeValues; ModelInstance[] iTreeValues;
uint iNTreeValues; uint iNTreeValues;
@@ -24,8 +24,8 @@ namespace Game.Collision
public enum ModelFlags public enum ModelFlags
{ {
M2 = 1, M2 = 1,
WorldSpawn = 1 << 1, HasBound = 1 << 1,
HasBound = 1 << 2 ParentSpawn = 1 << 2
} }
public class ModelSpawn public class ModelSpawn
+6 -8
View File
@@ -139,14 +139,10 @@ namespace Game.Collision
if (liquid.iTilesX != 0 && liquid.iTilesY != 0) if (liquid.iTilesX != 0 && liquid.iTilesY != 0)
{ {
uint size = (liquid.iTilesX + 1) * (liquid.iTilesY + 1); uint size = (liquid.iTilesX + 1) * (liquid.iTilesY + 1);
liquid.iHeight = new float[size]; liquid.iHeight = reader.ReadArray<float>(size);
for (var i = 0; i < size; i++)
liquid.iHeight[i] = reader.ReadSingle();
size = liquid.iTilesX * liquid.iTilesY; size = liquid.iTilesX * liquid.iTilesY;
liquid.iFlags = new byte[size]; liquid.iFlags = reader.ReadArray<byte>(size);
for (var i = 0; i < size; i++)
liquid.iFlags[i] = reader.ReadByte();
} }
else else
{ {
@@ -210,7 +206,9 @@ namespace Game.Collision
vertices.Clear(); vertices.Clear();
iLiquid = null; iLiquid = null;
iBound = reader.ReadStruct<AxisAlignedBox>(); var lo = reader.Read<Vector3>();
var hi = reader.Read<Vector3>();
iBound = new AxisAlignedBox(lo, hi);
iMogpFlags = reader.ReadUInt32(); iMogpFlags = reader.ReadUInt32();
iGroupWMOID = reader.ReadUInt32(); iGroupWMOID = reader.ReadUInt32();
@@ -234,7 +232,7 @@ namespace Game.Collision
count = reader.ReadUInt32(); count = reader.ReadUInt32();
for (var i = 0; i < count; ++i) for (var i = 0; i < count; ++i)
triangles.Add(reader.ReadStruct<MeshTriangle>()); triangles.Add(reader.Read<MeshTriangle>());
// read mesh BIH // read mesh BIH
if (reader.ReadStringFromChars(4) != "MBIH") if (reader.ReadStringFromChars(4) != "MBIH")
@@ -76,7 +76,7 @@ namespace Game.DataStorage
if (fieldInfo.IsArray) if (fieldInfo.IsArray)
{ {
Array array = (Array)fieldInfo.Getter(obj); Array array = (Array)fieldInfo.Getter(obj);
SetArrayValue(obj, array.Length, fieldInfo, dataReader); SetArrayValue(obj, (uint)array.Length, fieldInfo, dataReader);
arrayLength -= array.Length; arrayLength -= array.Length;
} }
@@ -123,7 +123,7 @@ namespace Game.DataStorage
if (fieldInfo.IsArray) if (fieldInfo.IsArray)
{ {
Array array = (Array)fieldInfo.Getter(obj); Array array = (Array)fieldInfo.Getter(obj);
SetArrayValue(obj, array.Length, fieldInfo, dataReader); SetArrayValue(obj, (uint)array.Length, fieldInfo, dataReader);
dataFieldIndex += array.Length - 1; dataFieldIndex += array.Length - 1;
} }
@@ -258,11 +258,7 @@ namespace Game.DataStorage
// IndexTable // IndexTable
if (Header.HasIndexTable()) if (Header.HasIndexTable())
{ m_indexes = reader.ReadArray<int>(Header.RecordCount);
m_indexes = new int[Header.RecordCount];
for (int i = 0; i < Header.RecordCount; i++)
m_indexes[i] = reader.ReadInt32();
}
// Copytable // Copytable
if (Header.CopyTableSize > 0) if (Header.CopyTableSize > 0)
@@ -508,7 +504,7 @@ namespace Game.DataStorage
return bits.ToArray(); return bits.ToArray();
} }
static void SetArrayValue(object obj, int arraySize, DB6FieldInfo fieldInfo, BinaryReader reader) static void SetArrayValue(object obj, uint arraySize, DB6FieldInfo fieldInfo, BinaryReader reader)
{ {
switch (Type.GetTypeCode(fieldInfo.FieldType)) switch (Type.GetTypeCode(fieldInfo.FieldType))
{ {
+14 -13
View File
@@ -56,14 +56,14 @@ namespace Game.DataStorage
for (uint k = 0; k < cam.target_positions.timestamps.number; ++k) for (uint k = 0; k < cam.target_positions.timestamps.number; ++k)
{ {
// Extract Target positions // Extract Target positions
M2Array targTsArray = new M2Array(reader, cam.target_positions.timestamps.offset_elements); reader.BaseStream.Position = cam.target_positions.timestamps.offset_elements;
M2Array targTsArray = reader.Read<M2Array>();
reader.BaseStream.Position = targTsArray.offset_elements; reader.BaseStream.Position = targTsArray.offset_elements;
uint[] targTimestamps = new uint[targTsArray.number]; uint[] targTimestamps = reader.ReadArray<uint>(targTsArray.number);
for (var i = 0; i < targTsArray.number; ++i)
targTimestamps[i] = reader.ReadUInt32();
M2Array targArray = new M2Array(reader, cam.target_positions.values.offset_elements); reader.BaseStream.Position = cam.target_positions.values.offset_elements;
M2Array targArray = reader.Read<M2Array>();
reader.BaseStream.Position = targArray.offset_elements; reader.BaseStream.Position = targArray.offset_elements;
M2SplineKey[] targPositions = new M2SplineKey[targArray.number]; M2SplineKey[] targPositions = new M2SplineKey[targArray.number];
@@ -90,14 +90,14 @@ namespace Game.DataStorage
for (uint k = 0; k < cam.positions.timestamps.number; ++k) for (uint k = 0; k < cam.positions.timestamps.number; ++k)
{ {
// Extract Camera positions for this set // Extract Camera positions for this set
M2Array posTsArray = reader.ReadStruct<M2Array>(cam.positions.timestamps.offset_elements); reader.BaseStream.Position = cam.positions.timestamps.offset_elements;
M2Array posTsArray = reader.Read<M2Array>();
reader.BaseStream.Position = posTsArray.offset_elements; reader.BaseStream.Position = posTsArray.offset_elements;
uint[] posTimestamps = new uint[posTsArray.number]; uint[] posTimestamps = reader.ReadArray<uint>(posTsArray.number);
for (var i = 0; i < posTsArray.number; ++i)
posTimestamps[i] = reader.ReadUInt32();
M2Array posArray = new M2Array(reader, cam.positions.values.offset_elements); reader.BaseStream.Position = cam.positions.values.offset_elements;
M2Array posArray = reader.Read<M2Array>();
reader.BaseStream.Position = posArray.offset_elements; reader.BaseStream.Position = posArray.offset_elements;
M2SplineKey[] positions = new M2SplineKey[posTsArray.number]; M2SplineKey[] positions = new M2SplineKey[posTsArray.number];
@@ -181,7 +181,7 @@ namespace Game.DataStorage
using (BinaryReader m2file = new BinaryReader(new FileStream(filename, FileMode.Open, FileAccess.Read))) using (BinaryReader m2file = new BinaryReader(new FileStream(filename, FileMode.Open, FileAccess.Read)))
{ {
// Check file has correct magic (MD21) // Check file has correct magic (MD21)
if (m2file.ReadStringFromChars(4) != "MD21") if (m2file.ReadUInt32() != 0x3132444D) //"MD21"
{ {
Log.outError(LogFilter.ServerLoading, "Camera file {0} is damaged. File identifier not found.", filename); Log.outError(LogFilter.ServerLoading, "Camera file {0} is damaged. File identifier not found.", filename);
continue; continue;
@@ -190,10 +190,11 @@ namespace Game.DataStorage
var unknownSize = m2file.ReadUInt32(); //unknown size var unknownSize = m2file.ReadUInt32(); //unknown size
// Read header // Read header
M2Header header = m2file.ReadStruct<M2Header>(); M2Header header = m2file.Read<M2Header>();
// Get camera(s) - Main header, then dump them. // Get camera(s) - Main header, then dump them.
M2Camera cam = m2file.ReadStruct<M2Camera>(8 + header.ofsCameras); m2file.BaseStream.Position = 8 + header.ofsCameras;
M2Camera cam = m2file.Read<M2Camera>();
m2file.BaseStream.Position = 8; m2file.BaseStream.Position = 8;
readCamera(cam, new BinaryReader(new MemoryStream(m2file.ReadBytes((int)m2file.BaseStream.Length - 8))), cameraEntry); readCamera(cam, new BinaryReader(new MemoryStream(m2file.ReadBytes((int)m2file.BaseStream.Length - 8))), cameraEntry);
+1 -12
View File
@@ -17,7 +17,6 @@
using Framework.GameMath; using Framework.GameMath;
using System.IO; using System.IO;
using System.Runtime.InteropServices;
namespace Game.DataStorage namespace Game.DataStorage
{ {
@@ -37,8 +36,7 @@ namespace Game.DataStorage
public struct M2Header public struct M2Header
{ {
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)] public uint Magic; // "MD20"
public char[] Magic; // "MD20"
public uint Version; // The version of the format. public uint Version; // The version of the format.
public uint lName; // Length of the model's name including the trailing \0 public uint lName; // Length of the model's name including the trailing \0
public uint ofsName; // Offset to the name, it seems like models can get reloaded by this name.should be unique, i guess. public uint ofsName; // Offset to the name, it seems like models can get reloaded by this name.should be unique, i guess.
@@ -110,15 +108,6 @@ namespace Game.DataStorage
public struct M2Array public struct M2Array
{ {
public M2Array(BinaryReader reader, uint offset)
{
if (offset != 0)
reader.BaseStream.Position = offset;
number = reader.ReadUInt32();
offset_elements = reader.ReadUInt32();
}
public uint number; public uint number;
public uint offset_elements; public uint offset_elements;
} }
+53 -62
View File
@@ -46,22 +46,33 @@ namespace Game.Maps
_fileExists = true; _fileExists = true;
using (BinaryReader reader = new BinaryReader(new FileStream(filename, FileMode.Open, FileAccess.Read))) using (BinaryReader reader = new BinaryReader(new FileStream(filename, FileMode.Open, FileAccess.Read)))
{ {
mapFileHeader header = reader.ReadStruct<mapFileHeader>(); mapFileHeader header = reader.Read<mapFileHeader>();
if (new string(header.mapMagic) != MapConst.MapMagic || new string(header.versionMagic) != MapConst.MapVersionMagic) if (header.mapMagic != MapConst.MapMagic || header.versionMagic != MapConst.MapVersionMagic)
{ {
Log.outError(LogFilter.Maps, "Map file '{0}' is from an incompatible map version. Please recreate using the mapextractor.", filename); Log.outError(LogFilter.Maps, $"Map file '{filename}' is from an incompatible map version. Please recreate using the mapextractor.");
return false; return false;
} }
if (header.areaMapOffset != 0)
LoadAreaData(reader, header.areaMapOffset);
if (header.heightMapOffset != 0) if (header.areaMapOffset != 0 && !LoadAreaData(reader, header.areaMapOffset))
LoadHeightData(reader, header.heightMapOffset); {
Log.outError(LogFilter.Maps, "Error loading map area data");
return false;
}
if (header.liquidMapOffset != 0) if (header.heightMapOffset != 0 && !LoadHeightData(reader, header.heightMapOffset))
LoadLiquidData(reader, header.liquidMapOffset); {
Log.outError(LogFilter.Maps, "Error loading map height data");
return false;
}
if (header.liquidMapOffset != 0 && !LoadLiquidData(reader, header.liquidMapOffset))
{
Log.outError(LogFilter.Maps, "Error loading map liquids data");
return false;
}
return true;
} }
return true;
} }
public void unloadData() public void unloadData()
@@ -76,25 +87,28 @@ namespace Game.Maps
_fileExists = false; _fileExists = false;
} }
void LoadAreaData(BinaryReader reader, uint offset) bool LoadAreaData(BinaryReader reader, uint offset)
{ {
reader.BaseStream.Seek(offset, SeekOrigin.Begin); reader.BaseStream.Seek(offset, SeekOrigin.Begin);
map_AreaHeader areaHeader = reader.ReadStruct<map_AreaHeader>(); map_AreaHeader areaHeader = reader.Read<map_AreaHeader>();
if (areaHeader.fourcc != MapConst.MapAreaMagic)
return false;
_gridArea = areaHeader.gridArea; _gridArea = areaHeader.gridArea;
if (!areaHeader.flags.HasAnyFlag(AreaHeaderFlags.NoArea)) if (!areaHeader.flags.HasAnyFlag(AreaHeaderFlags.NoArea))
{ _areaMap = reader.ReadArray<ushort>(16 * 16);
_areaMap = new ushort[16 * 16];
for (var i = 0; i < _areaMap.Length; ++i) return true;
_areaMap[i] = reader.ReadUInt16();
}
} }
void LoadHeightData(BinaryReader reader, uint offset) bool LoadHeightData(BinaryReader reader, uint offset)
{ {
reader.BaseStream.Seek(offset, SeekOrigin.Begin); reader.BaseStream.Seek(offset, SeekOrigin.Begin);
map_HeightHeader mapHeader = reader.ReadStruct<map_HeightHeader>(); map_HeightHeader mapHeader = reader.Read<map_HeightHeader>();
if (mapHeader.fourcc != MapConst.MapHeightMagic)
return false;
_gridHeight = mapHeader.gridHeight; _gridHeight = mapHeader.gridHeight;
_flags = (uint)mapHeader.flags; _flags = (uint)mapHeader.flags;
@@ -103,13 +117,8 @@ namespace Game.Maps
{ {
if (mapHeader.flags.HasAnyFlag(HeightHeaderFlags.HeightAsInt16)) if (mapHeader.flags.HasAnyFlag(HeightHeaderFlags.HeightAsInt16))
{ {
m_uint16_V9 = new ushort[129 * 129]; m_uint16_V9 = reader.ReadArray<ushort>(129 * 129);
for (var i = 0; i < m_uint16_V9.Length; ++i) m_uint16_V8 = reader.ReadArray<ushort>(128 * 128);
m_uint16_V9[i] = reader.ReadUInt16();
m_uint16_V8 = new ushort[128 * 128];
for (var i = 0; i < m_uint16_V8.Length; ++i)
m_uint16_V8[i] = reader.ReadUInt16();
_gridIntHeightMultiplier = (mapHeader.gridMaxHeight - mapHeader.gridHeight) / 65535; _gridIntHeightMultiplier = (mapHeader.gridMaxHeight - mapHeader.gridHeight) / 65535;
_gridGetHeight = getHeightFromUint16; _gridGetHeight = getHeightFromUint16;
@@ -123,13 +132,8 @@ namespace Game.Maps
} }
else else
{ {
m_V9 = new float[129 * 129]; m_V9 = reader.ReadArray<float>(129 * 129);
for (var i = 0; i < m_V9.Length; ++i) m_V8 = reader.ReadArray<float>(128 * 128);
m_V9[i] = reader.ReadSingle();
m_V8 = new float[128 * 128];
for (var i = 0; i < m_V8.Length; ++i)
m_V8[i] = reader.ReadSingle();
_gridGetHeight = getHeightFromFloat; _gridGetHeight = getHeightFromFloat;
} }
@@ -139,13 +143,8 @@ namespace Game.Maps
if (mapHeader.flags.HasAnyFlag(HeightHeaderFlags.HeightHasFlightBounds)) if (mapHeader.flags.HasAnyFlag(HeightHeaderFlags.HeightHasFlightBounds))
{ {
short[] maxHeights = new short[3 * 3]; short[] maxHeights = reader.ReadArray<short>(3 * 3);
short[] minHeights = new short[3 * 3]; short[] minHeights = reader.ReadArray<short>(3 * 3);
for (var i = 0; i < maxHeights.Length; ++i)
maxHeights[i] = reader.ReadInt16();
for (var i = 0; i < minHeights.Length; ++i)
minHeights[i] = reader.ReadInt16();
uint[][] indices = uint[][] indices =
{ {
@@ -180,15 +179,20 @@ namespace Game.Maps
new Vector3(boundGridCoords[indices[quarterIndex][2]][0], boundGridCoords[indices[quarterIndex][2]][1], minHeights[indices[quarterIndex][2]]) new Vector3(boundGridCoords[indices[quarterIndex][2]][0], boundGridCoords[indices[quarterIndex][2]][1], minHeights[indices[quarterIndex][2]])
); );
} }
return true;
} }
void LoadLiquidData(BinaryReader reader, uint offset) bool LoadLiquidData(BinaryReader reader, uint offset)
{ {
reader.BaseStream.Seek(offset, SeekOrigin.Begin); reader.BaseStream.Seek(offset, SeekOrigin.Begin);
map_LiquidHeader liquidHeader = reader.ReadStruct<map_LiquidHeader>(); map_LiquidHeader liquidHeader = reader.Read<map_LiquidHeader>();
if (liquidHeader.fourcc != MapConst.MapLiquidMagic)
return false;
_liquidGlobalEntry = liquidHeader.liquidType; _liquidGlobalEntry = liquidHeader.liquidType;
_liquidGlobalFlags = (byte)liquidHeader.liquidFlags; _liquidGlobalFlags = liquidHeader.liquidFlags;
_liquidOffX = liquidHeader.offsetX; _liquidOffX = liquidHeader.offsetX;
_liquidOffY = liquidHeader.offsetY; _liquidOffY = liquidHeader.offsetY;
_liquidWidth = liquidHeader.width; _liquidWidth = liquidHeader.width;
@@ -197,19 +201,14 @@ namespace Game.Maps
if (!liquidHeader.flags.HasAnyFlag(LiquidHeaderFlags.LiquidNoType)) if (!liquidHeader.flags.HasAnyFlag(LiquidHeaderFlags.LiquidNoType))
{ {
_liquidEntry = new ushort[16 * 16]; _liquidEntry = reader.ReadArray<ushort>(16 * 16);
for (var i = 0; i < _liquidEntry.Length; ++i)
_liquidEntry[i] = reader.ReadUInt16();
_liquidFlags = reader.ReadBytes(16 * 16); _liquidFlags = reader.ReadBytes(16 * 16);
} }
if (!liquidHeader.flags.HasAnyFlag(LiquidHeaderFlags.LiquidNoHeight)) if (!liquidHeader.flags.HasAnyFlag(LiquidHeaderFlags.LiquidNoHeight))
{ _liquidMap = reader.ReadArray<float>((uint)(_liquidWidth * _liquidHeight));
_liquidMap = new float[_liquidWidth * _liquidHeight];
for (var i = 0; i < _liquidMap.Length; ++i) return true;
_liquidMap[i] = reader.ReadSingle();
}
} }
public ushort getArea(float x, float y) public ushort getArea(float x, float y)
@@ -636,14 +635,10 @@ namespace Game.Maps
#endregion #endregion
} }
[StructLayout(LayoutKind.Sequential)]
public struct mapFileHeader public struct mapFileHeader
{ {
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)] public uint mapMagic;
public char[] mapMagic; public uint versionMagic;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
public char[] versionMagic;
public uint buildMagic; public uint buildMagic;
public uint areaMapOffset; public uint areaMapOffset;
public uint areaMapSize; public uint areaMapSize;
@@ -655,7 +650,6 @@ namespace Game.Maps
public uint holesSize; public uint holesSize;
} }
[StructLayout(LayoutKind.Sequential)]
public struct map_AreaHeader public struct map_AreaHeader
{ {
public uint fourcc; public uint fourcc;
@@ -663,7 +657,6 @@ namespace Game.Maps
public ushort gridArea; public ushort gridArea;
} }
[StructLayout(LayoutKind.Sequential)]
public struct map_HeightHeader public struct map_HeightHeader
{ {
public uint fourcc; public uint fourcc;
@@ -672,7 +665,6 @@ namespace Game.Maps
public float gridMaxHeight; public float gridMaxHeight;
} }
[StructLayout(LayoutKind.Sequential)]
public struct map_LiquidHeader public struct map_LiquidHeader
{ {
public uint fourcc; public uint fourcc;
@@ -686,7 +678,6 @@ namespace Game.Maps
public float liquidLevel; public float liquidLevel;
} }
[StructLayout(LayoutKind.Sequential)]
public class LiquidData public class LiquidData
{ {
public uint type_flags; public uint type_flags;
+54 -45
View File
@@ -178,64 +178,73 @@ namespace Game.Maps
InstanceMap CreateInstance(uint InstanceId, InstanceSave save, Difficulty difficulty, int teamId) InstanceMap CreateInstance(uint InstanceId, InstanceSave save, Difficulty difficulty, int teamId)
{ {
// make sure we have a valid map id lock (_mapLock)
MapRecord entry = CliDB.MapStorage.LookupByKey(GetId());
if (entry == null)
{ {
Log.outError(LogFilter.Maps, "CreateInstance: no record for map {0}", GetId()); // make sure we have a valid map id
Contract.Assert(false); MapRecord entry = CliDB.MapStorage.LookupByKey(GetId());
if (entry == null)
{
Log.outError(LogFilter.Maps, "CreateInstance: no record for map {0}", GetId());
Contract.Assert(false);
}
InstanceTemplate iTemplate = Global.ObjectMgr.GetInstanceTemplate(GetId());
if (iTemplate == null)
{
Log.outError(LogFilter.Maps, "CreateInstance: no instance template for map {0}", GetId());
Contract.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 InstanceMap(GetId(), GetGridExpiry(), InstanceId, difficulty, this);
Contract.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;
} }
InstanceTemplate iTemplate = Global.ObjectMgr.GetInstanceTemplate(GetId());
if (iTemplate == null)
{
Log.outError(LogFilter.Maps, "CreateInstance: no instance template for map {0}", GetId());
Contract.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 InstanceMap(GetId(), GetGridExpiry(), InstanceId, difficulty, this);
Contract.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) BattlegroundMap CreateBattleground(uint InstanceId, Battleground bg)
{ {
Log.outDebug(LogFilter.Maps, "MapInstanced.CreateBattleground: map bg {0} for {1} created.", InstanceId, GetId()); lock (_mapLock)
{
Log.outDebug(LogFilter.Maps, "MapInstanced.CreateBattleground: map bg {0} for {1} created.", InstanceId, GetId());
BattlegroundMap map = new BattlegroundMap(GetId(), (uint)GetGridExpiry(), InstanceId, this, Difficulty.None); BattlegroundMap map = new BattlegroundMap(GetId(), (uint)GetGridExpiry(), InstanceId, this, Difficulty.None);
Contract.Assert(map.IsBattlegroundOrArena()); Contract.Assert(map.IsBattlegroundOrArena());
map.SetBG(bg); map.SetBG(bg);
bg.SetBgMap(map); bg.SetBgMap(map);
m_InstancedMaps[InstanceId] = map; m_InstancedMaps[InstanceId] = map;
return map; return map;
}
} }
GarrisonMap CreateGarrison(uint instanceId, Player owner) GarrisonMap CreateGarrison(uint instanceId, Player owner)
{ {
GarrisonMap map = new GarrisonMap(GetId(), GetGridExpiry(), instanceId, this, owner.GetGUID()); lock (_mapLock)
Contract.Assert(map.IsGarrison()); {
GarrisonMap map = new GarrisonMap(GetId(), GetGridExpiry(), instanceId, this, owner.GetGUID());
Contract.Assert(map.IsGarrison());
m_InstancedMaps[instanceId] = map; m_InstancedMaps[instanceId] = map;
return map; return map;
}
} }
bool DestroyInstance(KeyValuePair<uint, Map> pair) bool DestroyInstance(KeyValuePair<uint, Map> pair)
+3 -8
View File
@@ -139,9 +139,8 @@ namespace Game
using (BinaryReader reader = new BinaryReader(new FileStream(fileName, FileMode.Open, FileAccess.Read))) using (BinaryReader reader = new BinaryReader(new FileStream(fileName, FileMode.Open, FileAccess.Read)))
{ {
MmapTileHeader fileHeader = reader.ReadStruct<MmapTileHeader>(); MmapTileHeader fileHeader = reader.Read<MmapTileHeader>();
Array.Reverse(fileHeader.mmapMagic); if (fileHeader.mmapMagic != MapConst.mmapMagic)
if (new string(fileHeader.mmapMagic) != MapConst.mmapMagic)
{ {
Log.outError(LogFilter.Maps, "MMAP:loadMap: Bad header in mmap {0:D4}{1:D2}{2:D2}.mmtile", mapId, x, y); Log.outError(LogFilter.Maps, "MMAP:loadMap: Bad header in mmap {0:D4}{1:D2}{2:D2}.mmtile", mapId, x, y);
return false; return false;
@@ -356,16 +355,12 @@ namespace Game
public Dictionary<uint, ulong> loadedTileRefs = new Dictionary<uint, ulong>(); // maps [map grid coords] to [dtTile] public Dictionary<uint, ulong> loadedTileRefs = new Dictionary<uint, ulong>(); // maps [map grid coords] to [dtTile]
} }
[StructLayout(LayoutKind.Sequential)]
public struct MmapTileHeader public struct MmapTileHeader
{ {
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)] public uint mmapMagic;
public char[] mmapMagic;
public uint dtVersion; public uint dtVersion;
public uint mmapVersion; public uint mmapVersion;
public uint size; public uint size;
public byte usesLiquids; public byte usesLiquids;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
public byte[] padding;
} }
} }
+14 -5
View File
@@ -96,11 +96,11 @@ namespace Game.Maps
using (var reader = new BinaryReader(new FileStream(fileName, FileMode.Open, FileAccess.Read))) using (var reader = new BinaryReader(new FileStream(fileName, FileMode.Open, FileAccess.Read)))
{ {
var header = reader.ReadStruct<mapFileHeader>(); var header = reader.Read<mapFileHeader>();
if (new string(header.mapMagic) != MapConst.MapMagic || new string(header.versionMagic) != MapConst.MapVersionMagic) if (header.mapMagic != MapConst.MapMagic || header.versionMagic != MapConst.MapVersionMagic)
{ {
Log.outError(LogFilter.Maps, "Map file '{0}' is from an incompatible map version ({1}), {2} is expected. Please recreate using the mapextractor.", Log.outError(LogFilter.Maps, "Map file '{0}' is from an incompatible map version ({1}), {2} is expected. Please recreate using the mapextractor.",
fileName, new string(header.versionMagic), MapConst.MapVersionMagic); fileName, header.versionMagic, MapConst.MapVersionMagic);
return false; return false;
} }
return true; return true;
@@ -136,6 +136,9 @@ namespace Game.Maps
void LoadVMap(uint gx, uint gy) void LoadVMap(uint gx, uint gy)
{ {
if (!Global.VMapMgr.isMapLoadingEnabled())
return;
// x and y are swapped !! // x and y are swapped !!
VMAPLoadResult vmapLoadResult = Global.VMapMgr.loadMap(GetId(), gx, gy); VMAPLoadResult vmapLoadResult = Global.VMapMgr.loadMap(GetId(), gx, gy);
switch (vmapLoadResult) switch (vmapLoadResult)
@@ -363,7 +366,7 @@ namespace Game.Maps
void EnsureGridCreated(GridCoord p) void EnsureGridCreated(GridCoord p)
{ {
lock (this) lock (_gridLock)
{ {
EnsureGridCreated_i(p); EnsureGridCreated_i(p);
} }
@@ -4338,6 +4341,9 @@ namespace Game.Maps
#endregion #endregion
#region Fields #region Fields
internal object _mapLock = new object();
object _gridLock = new object();
bool _creatureToMoveLock; bool _creatureToMoveLock;
List<Creature> creaturesToMove = new List<Creature>(); List<Creature> creaturesToMove = new List<Creature>();
@@ -4455,6 +4461,7 @@ namespace Game.Maps
/// @todo Not sure about checking player level: already done in HandleAreaTriggerOpcode /// @todo Not sure about checking player level: already done in HandleAreaTriggerOpcode
// GMs still can teleport player in instance. // GMs still can teleport player in instance.
// Is it needed? // Is it needed?
lock(_mapLock)
{ {
// Dungeon only code // Dungeon only code
if (IsDungeon()) if (IsDungeon())
@@ -4878,7 +4885,9 @@ namespace Game.Maps
public override bool AddPlayerToMap(Player player, bool initPlayer = true) public override bool AddPlayerToMap(Player player, bool initPlayer = true)
{ {
player.m_InstanceValid = true; lock (_mapLock)
player.m_InstanceValid = true;
return base.AddPlayerToMap(player, initPlayer); return base.AddPlayerToMap(player, initPlayer);
} }