Core/Maps: Updated vmaps and some cleaups
This commit is contained in:
@@ -61,16 +61,16 @@ namespace Framework.Constants
|
||||
public const float MaxHeight = 100000.0f;
|
||||
public const float MaxFallDistance = 250000.0f;
|
||||
|
||||
public const string MapMagic = "MAPS";
|
||||
public const string MapVersionMagic = "v1.9";
|
||||
public const string MapAreaMagic = "AREA";
|
||||
public const string MapHeightMagic = "MHGT";
|
||||
public const string MapLiquidMagic = "MLIQ";
|
||||
public const uint MapMagic = 0x5350414D; //"MAPS";
|
||||
public const uint MapVersionMagic = 0x392E3176; //"v1.9";
|
||||
public const uint MapAreaMagic = 0x41455241; //"AREA";
|
||||
public const uint MapHeightMagic = 0x5447484D; //"MHGT";
|
||||
public const uint MapLiquidMagic = 0x51494C4D; //"MLIQ";
|
||||
|
||||
public const string mmapMagic = "MMAP";
|
||||
public const uint mmapMagic = 0x4D4D4150; // 'MMAP'
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
@@ -294,27 +294,6 @@ namespace System
|
||||
#endregion
|
||||
|
||||
#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)
|
||||
{
|
||||
byte num;
|
||||
@@ -337,9 +316,9 @@ namespace System
|
||||
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);
|
||||
|
||||
|
||||
@@ -276,14 +276,10 @@ namespace Game.Collision
|
||||
bounds = new AxisAlignedBox(lo, hi);
|
||||
|
||||
uint treeSize = reader.ReadUInt32();
|
||||
tree = new uint[treeSize];
|
||||
for (var i = 0; i < treeSize; i++)
|
||||
tree[i] = reader.ReadUInt32();
|
||||
tree = reader.ReadArray<uint>(treeSize);
|
||||
|
||||
var count = reader.ReadUInt32();
|
||||
objects = new uint[count];
|
||||
for (var i = 0; i < count; i++)
|
||||
objects[i] = reader.ReadUInt32();
|
||||
objects = reader.ReadArray<uint>(count);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -70,7 +70,7 @@ namespace Game.Collision
|
||||
{
|
||||
string filename = VMapPath + getMapFileName(mapId);
|
||||
StaticMapTree newTree = new StaticMapTree(mapId);
|
||||
if (!newTree.InitMap(filename, this))
|
||||
if (!newTree.InitMap(filename))
|
||||
return false;
|
||||
|
||||
iInstanceMapTrees.Add(mapId, newTree);
|
||||
@@ -235,36 +235,42 @@ namespace Game.Collision
|
||||
|
||||
public WorldModel acquireModelInstance(string filename)
|
||||
{
|
||||
var model = iLoadedModelFiles.LookupByKey(filename);
|
||||
if (model == null)
|
||||
lock (LoadedModelFilesLock)
|
||||
{
|
||||
WorldModel worldmodel = new WorldModel();
|
||||
if (!worldmodel.readFile(VMapPath + filename + ".vmo"))
|
||||
var model = iLoadedModelFiles.LookupByKey(filename);
|
||||
if (model == null)
|
||||
{
|
||||
Log.outError(LogFilter.Server, "VMapManager: could not load '{0}.vmo'", filename);
|
||||
return null;
|
||||
WorldModel worldmodel = new WorldModel();
|
||||
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);
|
||||
iLoadedModelFiles.Add(filename, new ManagedModel());
|
||||
model = iLoadedModelFiles.LookupByKey(filename);
|
||||
model.setModel(worldmodel);
|
||||
model.incRefCount();
|
||||
return model.getModel();
|
||||
}
|
||||
model.incRefCount();
|
||||
return model.getModel();
|
||||
}
|
||||
|
||||
public void releaseModelInstance(string filename)
|
||||
{
|
||||
var model = iLoadedModelFiles.LookupByKey(filename);
|
||||
if (model == null)
|
||||
lock (LoadedModelFilesLock)
|
||||
{
|
||||
Log.outError(LogFilter.Server, "VMapManager: trying to unload non-loaded file '{0}'", filename);
|
||||
return;
|
||||
}
|
||||
if (model.decRefCount() == 0)
|
||||
{
|
||||
Log.outDebug(LogFilter.Maps, "VMapManager: unloading file '{0}'", filename);
|
||||
iLoadedModelFiles.Remove(filename);
|
||||
var model = iLoadedModelFiles.LookupByKey(filename);
|
||||
if (model == null)
|
||||
{
|
||||
Log.outError(LogFilter.Server, "VMapManager: trying to unload non-loaded file '{0}'", filename);
|
||||
return;
|
||||
}
|
||||
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>();
|
||||
bool _enableLineOfSightCalc;
|
||||
bool _enableHeightCalc;
|
||||
|
||||
object LoadedModelFilesLock = new object();
|
||||
}
|
||||
|
||||
public class ManagedModel
|
||||
|
||||
@@ -58,47 +58,23 @@ namespace Game.Collision
|
||||
iMapID = mapId;
|
||||
}
|
||||
|
||||
public bool InitMap(string fname, VMapManager vm)
|
||||
public bool InitMap(string fname)
|
||||
{
|
||||
Log.outDebug(LogFilter.Maps, "StaticMapTree.InitMap() : initializing StaticMapTree '{0}'", fname);
|
||||
bool success = false;
|
||||
if (!File.Exists(fname))
|
||||
return false;
|
||||
|
||||
char tiled = '0';
|
||||
using (BinaryReader reader = new BinaryReader(new FileStream(fname, FileMode.Open, FileAccess.Read)))
|
||||
{
|
||||
var magic = reader.ReadStringFromChars(8);
|
||||
tiled = reader.ReadChar();
|
||||
var node = reader.ReadStringFromChars(4);
|
||||
|
||||
if (magic == MapConst.VMapMagic && node == "NODE" && iTree.readFromFile(reader))
|
||||
{
|
||||
iNTreeValues = iTree.primCount();
|
||||
iTreeValues = new ModelInstance[iNTreeValues];
|
||||
success = reader.ReadStringFromChars(4) == "GOBJ";
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
success = true;
|
||||
}
|
||||
|
||||
if (success)
|
||||
@@ -107,7 +83,7 @@ namespace Game.Collision
|
||||
if (success)
|
||||
{
|
||||
uint spawnIndicesSize = reader.ReadUInt32();
|
||||
for (uint i = 0; i < spawnIndicesSize && success; ++i)
|
||||
for (uint i = 0; i < spawnIndicesSize; ++i)
|
||||
{
|
||||
uint spawnId = reader.ReadUInt32();
|
||||
uint spawnIndex = reader.ReadUInt32();
|
||||
@@ -133,13 +109,6 @@ namespace Game.Collision
|
||||
|
||||
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)
|
||||
{
|
||||
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)
|
||||
return false;
|
||||
}
|
||||
|
||||
char tiled = reader.ReadChar();
|
||||
if (tiled == 1)
|
||||
{
|
||||
FileStream stream = OpenMapTileFile(vmapPath, mapID, tileX, tileY, vm);
|
||||
if (stream == null)
|
||||
return false;
|
||||
|
||||
FileStream stream = OpenMapTileFile(vmapPath, mapID, tileX, tileY, vm);
|
||||
if (stream == null)
|
||||
return false;
|
||||
|
||||
using (BinaryReader reader1 = new BinaryReader(stream))
|
||||
{
|
||||
if (reader1.ReadStringFromChars(8) != MapConst.VMapMagic)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
using (BinaryReader reader = new BinaryReader(stream))
|
||||
{
|
||||
if (reader.ReadStringFromChars(8) != MapConst.VMapMagic)
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static string getTileFileName(uint mapID, uint tileX, uint tileY)
|
||||
{
|
||||
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; }
|
||||
|
||||
uint iMapID;
|
||||
bool iIsTiled;
|
||||
BIH iTree = new BIH();
|
||||
ModelInstance[] iTreeValues;
|
||||
uint iNTreeValues;
|
||||
|
||||
@@ -24,8 +24,8 @@ namespace Game.Collision
|
||||
public enum ModelFlags
|
||||
{
|
||||
M2 = 1,
|
||||
WorldSpawn = 1 << 1,
|
||||
HasBound = 1 << 2
|
||||
HasBound = 1 << 1,
|
||||
ParentSpawn = 1 << 2
|
||||
}
|
||||
|
||||
public class ModelSpawn
|
||||
|
||||
@@ -139,14 +139,10 @@ namespace Game.Collision
|
||||
if (liquid.iTilesX != 0 && liquid.iTilesY != 0)
|
||||
{
|
||||
uint size = (liquid.iTilesX + 1) * (liquid.iTilesY + 1);
|
||||
liquid.iHeight = new float[size];
|
||||
for (var i = 0; i < size; i++)
|
||||
liquid.iHeight[i] = reader.ReadSingle();
|
||||
liquid.iHeight = reader.ReadArray<float>(size);
|
||||
|
||||
size = liquid.iTilesX * liquid.iTilesY;
|
||||
liquid.iFlags = new byte[size];
|
||||
for (var i = 0; i < size; i++)
|
||||
liquid.iFlags[i] = reader.ReadByte();
|
||||
liquid.iFlags = reader.ReadArray<byte>(size);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -210,7 +206,9 @@ namespace Game.Collision
|
||||
vertices.Clear();
|
||||
iLiquid = null;
|
||||
|
||||
iBound = reader.ReadStruct<AxisAlignedBox>();
|
||||
var lo = reader.Read<Vector3>();
|
||||
var hi = reader.Read<Vector3>();
|
||||
iBound = new AxisAlignedBox(lo, hi);
|
||||
iMogpFlags = reader.ReadUInt32();
|
||||
iGroupWMOID = reader.ReadUInt32();
|
||||
|
||||
@@ -234,7 +232,7 @@ namespace Game.Collision
|
||||
count = reader.ReadUInt32();
|
||||
|
||||
for (var i = 0; i < count; ++i)
|
||||
triangles.Add(reader.ReadStruct<MeshTriangle>());
|
||||
triangles.Add(reader.Read<MeshTriangle>());
|
||||
|
||||
// read mesh BIH
|
||||
if (reader.ReadStringFromChars(4) != "MBIH")
|
||||
|
||||
@@ -76,7 +76,7 @@ namespace Game.DataStorage
|
||||
if (fieldInfo.IsArray)
|
||||
{
|
||||
Array array = (Array)fieldInfo.Getter(obj);
|
||||
SetArrayValue(obj, array.Length, fieldInfo, dataReader);
|
||||
SetArrayValue(obj, (uint)array.Length, fieldInfo, dataReader);
|
||||
|
||||
arrayLength -= array.Length;
|
||||
}
|
||||
@@ -123,7 +123,7 @@ namespace Game.DataStorage
|
||||
if (fieldInfo.IsArray)
|
||||
{
|
||||
Array array = (Array)fieldInfo.Getter(obj);
|
||||
SetArrayValue(obj, array.Length, fieldInfo, dataReader);
|
||||
SetArrayValue(obj, (uint)array.Length, fieldInfo, dataReader);
|
||||
|
||||
dataFieldIndex += array.Length - 1;
|
||||
}
|
||||
@@ -258,11 +258,7 @@ namespace Game.DataStorage
|
||||
|
||||
// IndexTable
|
||||
if (Header.HasIndexTable())
|
||||
{
|
||||
m_indexes = new int[Header.RecordCount];
|
||||
for (int i = 0; i < Header.RecordCount; i++)
|
||||
m_indexes[i] = reader.ReadInt32();
|
||||
}
|
||||
m_indexes = reader.ReadArray<int>(Header.RecordCount);
|
||||
|
||||
// Copytable
|
||||
if (Header.CopyTableSize > 0)
|
||||
@@ -508,7 +504,7 @@ namespace Game.DataStorage
|
||||
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))
|
||||
{
|
||||
|
||||
@@ -56,14 +56,14 @@ namespace Game.DataStorage
|
||||
for (uint k = 0; k < cam.target_positions.timestamps.number; ++k)
|
||||
{
|
||||
// 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;
|
||||
uint[] targTimestamps = new uint[targTsArray.number];
|
||||
for (var i = 0; i < targTsArray.number; ++i)
|
||||
targTimestamps[i] = reader.ReadUInt32();
|
||||
uint[] targTimestamps = reader.ReadArray<uint>(targTsArray.number);
|
||||
|
||||
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;
|
||||
M2SplineKey[] targPositions = new M2SplineKey[targArray.number];
|
||||
@@ -90,14 +90,14 @@ namespace Game.DataStorage
|
||||
for (uint k = 0; k < cam.positions.timestamps.number; ++k)
|
||||
{
|
||||
// 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;
|
||||
uint[] posTimestamps = new uint[posTsArray.number];
|
||||
for (var i = 0; i < posTsArray.number; ++i)
|
||||
posTimestamps[i] = reader.ReadUInt32();
|
||||
uint[] posTimestamps = reader.ReadArray<uint>(posTsArray.number);
|
||||
|
||||
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;
|
||||
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)))
|
||||
{
|
||||
// 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);
|
||||
continue;
|
||||
@@ -190,10 +190,11 @@ namespace Game.DataStorage
|
||||
var unknownSize = m2file.ReadUInt32(); //unknown size
|
||||
|
||||
// Read header
|
||||
M2Header header = m2file.ReadStruct<M2Header>();
|
||||
M2Header header = m2file.Read<M2Header>();
|
||||
|
||||
// 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;
|
||||
readCamera(cam, new BinaryReader(new MemoryStream(m2file.ReadBytes((int)m2file.BaseStream.Length - 8))), cameraEntry);
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
|
||||
using Framework.GameMath;
|
||||
using System.IO;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Game.DataStorage
|
||||
{
|
||||
@@ -37,8 +36,7 @@ namespace Game.DataStorage
|
||||
|
||||
public struct M2Header
|
||||
{
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
|
||||
public char[] Magic; // "MD20"
|
||||
public uint Magic; // "MD20"
|
||||
public uint Version; // The version of the format.
|
||||
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.
|
||||
@@ -110,15 +108,6 @@ namespace Game.DataStorage
|
||||
|
||||
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 offset_elements;
|
||||
}
|
||||
|
||||
+53
-62
@@ -46,22 +46,33 @@ namespace Game.Maps
|
||||
_fileExists = true;
|
||||
using (BinaryReader reader = new BinaryReader(new FileStream(filename, FileMode.Open, FileAccess.Read)))
|
||||
{
|
||||
mapFileHeader header = reader.ReadStruct<mapFileHeader>();
|
||||
if (new string(header.mapMagic) != MapConst.MapMagic || new string(header.versionMagic) != MapConst.MapVersionMagic)
|
||||
mapFileHeader header = reader.Read<mapFileHeader>();
|
||||
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;
|
||||
}
|
||||
if (header.areaMapOffset != 0)
|
||||
LoadAreaData(reader, header.areaMapOffset);
|
||||
|
||||
if (header.heightMapOffset != 0)
|
||||
LoadHeightData(reader, header.heightMapOffset);
|
||||
if (header.areaMapOffset != 0 && !LoadAreaData(reader, header.areaMapOffset))
|
||||
{
|
||||
Log.outError(LogFilter.Maps, "Error loading map area data");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (header.liquidMapOffset != 0)
|
||||
LoadLiquidData(reader, header.liquidMapOffset);
|
||||
if (header.heightMapOffset != 0 && !LoadHeightData(reader, header.heightMapOffset))
|
||||
{
|
||||
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()
|
||||
@@ -76,25 +87,28 @@ namespace Game.Maps
|
||||
_fileExists = false;
|
||||
}
|
||||
|
||||
void LoadAreaData(BinaryReader reader, uint offset)
|
||||
bool LoadAreaData(BinaryReader reader, uint offset)
|
||||
{
|
||||
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;
|
||||
|
||||
if (!areaHeader.flags.HasAnyFlag(AreaHeaderFlags.NoArea))
|
||||
{
|
||||
_areaMap = new ushort[16 * 16];
|
||||
for (var i = 0; i < _areaMap.Length; ++i)
|
||||
_areaMap[i] = reader.ReadUInt16();
|
||||
}
|
||||
_areaMap = reader.ReadArray<ushort>(16 * 16);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void LoadHeightData(BinaryReader reader, uint offset)
|
||||
bool LoadHeightData(BinaryReader reader, uint offset)
|
||||
{
|
||||
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;
|
||||
_flags = (uint)mapHeader.flags;
|
||||
@@ -103,13 +117,8 @@ namespace Game.Maps
|
||||
{
|
||||
if (mapHeader.flags.HasAnyFlag(HeightHeaderFlags.HeightAsInt16))
|
||||
{
|
||||
m_uint16_V9 = new ushort[129 * 129];
|
||||
for (var i = 0; i < m_uint16_V9.Length; ++i)
|
||||
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();
|
||||
m_uint16_V9 = reader.ReadArray<ushort>(129 * 129);
|
||||
m_uint16_V8 = reader.ReadArray<ushort>(128 * 128);
|
||||
|
||||
_gridIntHeightMultiplier = (mapHeader.gridMaxHeight - mapHeader.gridHeight) / 65535;
|
||||
_gridGetHeight = getHeightFromUint16;
|
||||
@@ -123,13 +132,8 @@ namespace Game.Maps
|
||||
}
|
||||
else
|
||||
{
|
||||
m_V9 = new float[129 * 129];
|
||||
for (var i = 0; i < m_V9.Length; ++i)
|
||||
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();
|
||||
m_V9 = reader.ReadArray<float>(129 * 129);
|
||||
m_V8 = reader.ReadArray<float>(128 * 128);
|
||||
|
||||
_gridGetHeight = getHeightFromFloat;
|
||||
}
|
||||
@@ -139,13 +143,8 @@ namespace Game.Maps
|
||||
|
||||
if (mapHeader.flags.HasAnyFlag(HeightHeaderFlags.HeightHasFlightBounds))
|
||||
{
|
||||
short[] maxHeights = new short[3 * 3];
|
||||
short[] minHeights = new 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();
|
||||
short[] maxHeights = reader.ReadArray<short>(3 * 3);
|
||||
short[] minHeights = reader.ReadArray<short>(3 * 3);
|
||||
|
||||
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]])
|
||||
);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void LoadLiquidData(BinaryReader reader, uint offset)
|
||||
bool LoadLiquidData(BinaryReader reader, uint offset)
|
||||
{
|
||||
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;
|
||||
_liquidGlobalFlags = (byte)liquidHeader.liquidFlags;
|
||||
_liquidGlobalFlags = liquidHeader.liquidFlags;
|
||||
_liquidOffX = liquidHeader.offsetX;
|
||||
_liquidOffY = liquidHeader.offsetY;
|
||||
_liquidWidth = liquidHeader.width;
|
||||
@@ -197,19 +201,14 @@ namespace Game.Maps
|
||||
|
||||
if (!liquidHeader.flags.HasAnyFlag(LiquidHeaderFlags.LiquidNoType))
|
||||
{
|
||||
_liquidEntry = new ushort[16 * 16];
|
||||
for (var i = 0; i < _liquidEntry.Length; ++i)
|
||||
_liquidEntry[i] = reader.ReadUInt16();
|
||||
|
||||
_liquidEntry = reader.ReadArray<ushort>(16 * 16);
|
||||
_liquidFlags = reader.ReadBytes(16 * 16);
|
||||
}
|
||||
|
||||
if (!liquidHeader.flags.HasAnyFlag(LiquidHeaderFlags.LiquidNoHeight))
|
||||
{
|
||||
_liquidMap = new float[_liquidWidth * _liquidHeight];
|
||||
for (var i = 0; i < _liquidMap.Length; ++i)
|
||||
_liquidMap[i] = reader.ReadSingle();
|
||||
}
|
||||
_liquidMap = reader.ReadArray<float>((uint)(_liquidWidth * _liquidHeight));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public ushort getArea(float x, float y)
|
||||
@@ -636,14 +635,10 @@ namespace Game.Maps
|
||||
#endregion
|
||||
}
|
||||
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct mapFileHeader
|
||||
{
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
|
||||
public char[] mapMagic;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
|
||||
public char[] versionMagic;
|
||||
public uint mapMagic;
|
||||
public uint versionMagic;
|
||||
public uint buildMagic;
|
||||
public uint areaMapOffset;
|
||||
public uint areaMapSize;
|
||||
@@ -655,7 +650,6 @@ namespace Game.Maps
|
||||
public uint holesSize;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct map_AreaHeader
|
||||
{
|
||||
public uint fourcc;
|
||||
@@ -663,7 +657,6 @@ namespace Game.Maps
|
||||
public ushort gridArea;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct map_HeightHeader
|
||||
{
|
||||
public uint fourcc;
|
||||
@@ -672,7 +665,6 @@ namespace Game.Maps
|
||||
public float gridMaxHeight;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct map_LiquidHeader
|
||||
{
|
||||
public uint fourcc;
|
||||
@@ -686,7 +678,6 @@ namespace Game.Maps
|
||||
public float liquidLevel;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public class LiquidData
|
||||
{
|
||||
public uint type_flags;
|
||||
|
||||
@@ -178,64 +178,73 @@ namespace Game.Maps
|
||||
|
||||
InstanceMap CreateInstance(uint InstanceId, InstanceSave save, Difficulty difficulty, int teamId)
|
||||
{
|
||||
// make sure we have a valid map id
|
||||
MapRecord entry = CliDB.MapStorage.LookupByKey(GetId());
|
||||
if (entry == null)
|
||||
lock (_mapLock)
|
||||
{
|
||||
Log.outError(LogFilter.Maps, "CreateInstance: no record for map {0}", GetId());
|
||||
Contract.Assert(false);
|
||||
// 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());
|
||||
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)
|
||||
{
|
||||
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);
|
||||
Contract.Assert(map.IsBattlegroundOrArena());
|
||||
map.SetBG(bg);
|
||||
bg.SetBgMap(map);
|
||||
BattlegroundMap map = new BattlegroundMap(GetId(), (uint)GetGridExpiry(), InstanceId, this, Difficulty.None);
|
||||
Contract.Assert(map.IsBattlegroundOrArena());
|
||||
map.SetBG(bg);
|
||||
bg.SetBgMap(map);
|
||||
|
||||
m_InstancedMaps[InstanceId] = map;
|
||||
return map;
|
||||
m_InstancedMaps[InstanceId] = map;
|
||||
return map;
|
||||
}
|
||||
}
|
||||
|
||||
GarrisonMap CreateGarrison(uint instanceId, Player owner)
|
||||
{
|
||||
GarrisonMap map = new GarrisonMap(GetId(), GetGridExpiry(), instanceId, this, owner.GetGUID());
|
||||
Contract.Assert(map.IsGarrison());
|
||||
lock (_mapLock)
|
||||
{
|
||||
GarrisonMap map = new GarrisonMap(GetId(), GetGridExpiry(), instanceId, this, owner.GetGUID());
|
||||
Contract.Assert(map.IsGarrison());
|
||||
|
||||
m_InstancedMaps[instanceId] = map;
|
||||
return map;
|
||||
m_InstancedMaps[instanceId] = map;
|
||||
return map;
|
||||
}
|
||||
}
|
||||
|
||||
bool DestroyInstance(KeyValuePair<uint, Map> pair)
|
||||
|
||||
@@ -139,9 +139,8 @@ namespace Game
|
||||
|
||||
using (BinaryReader reader = new BinaryReader(new FileStream(fileName, FileMode.Open, FileAccess.Read)))
|
||||
{
|
||||
MmapTileHeader fileHeader = reader.ReadStruct<MmapTileHeader>();
|
||||
Array.Reverse(fileHeader.mmapMagic);
|
||||
if (new string(fileHeader.mmapMagic) != MapConst.mmapMagic)
|
||||
MmapTileHeader fileHeader = reader.Read<MmapTileHeader>();
|
||||
if (fileHeader.mmapMagic != MapConst.mmapMagic)
|
||||
{
|
||||
Log.outError(LogFilter.Maps, "MMAP:loadMap: Bad header in mmap {0:D4}{1:D2}{2:D2}.mmtile", mapId, x, y);
|
||||
return false;
|
||||
@@ -356,16 +355,12 @@ namespace Game
|
||||
public Dictionary<uint, ulong> loadedTileRefs = new Dictionary<uint, ulong>(); // maps [map grid coords] to [dtTile]
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct MmapTileHeader
|
||||
{
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
|
||||
public char[] mmapMagic;
|
||||
public uint mmapMagic;
|
||||
public uint dtVersion;
|
||||
public uint mmapVersion;
|
||||
public uint size;
|
||||
public byte usesLiquids;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
|
||||
public byte[] padding;
|
||||
}
|
||||
}
|
||||
|
||||
+14
-5
@@ -96,11 +96,11 @@ namespace Game.Maps
|
||||
|
||||
using (var reader = new BinaryReader(new FileStream(fileName, FileMode.Open, FileAccess.Read)))
|
||||
{
|
||||
var header = reader.ReadStruct<mapFileHeader>();
|
||||
if (new string(header.mapMagic) != MapConst.MapMagic || new string(header.versionMagic) != MapConst.MapVersionMagic)
|
||||
var header = reader.Read<mapFileHeader>();
|
||||
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.",
|
||||
fileName, new string(header.versionMagic), MapConst.MapVersionMagic);
|
||||
fileName, header.versionMagic, MapConst.MapVersionMagic);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
@@ -136,6 +136,9 @@ namespace Game.Maps
|
||||
|
||||
void LoadVMap(uint gx, uint gy)
|
||||
{
|
||||
if (!Global.VMapMgr.isMapLoadingEnabled())
|
||||
return;
|
||||
|
||||
// x and y are swapped !!
|
||||
VMAPLoadResult vmapLoadResult = Global.VMapMgr.loadMap(GetId(), gx, gy);
|
||||
switch (vmapLoadResult)
|
||||
@@ -363,7 +366,7 @@ namespace Game.Maps
|
||||
|
||||
void EnsureGridCreated(GridCoord p)
|
||||
{
|
||||
lock (this)
|
||||
lock (_gridLock)
|
||||
{
|
||||
EnsureGridCreated_i(p);
|
||||
}
|
||||
@@ -4338,6 +4341,9 @@ namespace Game.Maps
|
||||
#endregion
|
||||
|
||||
#region Fields
|
||||
internal object _mapLock = new object();
|
||||
object _gridLock = new object();
|
||||
|
||||
bool _creatureToMoveLock;
|
||||
List<Creature> creaturesToMove = new List<Creature>();
|
||||
|
||||
@@ -4455,6 +4461,7 @@ namespace Game.Maps
|
||||
/// @todo Not sure about checking player level: already done in HandleAreaTriggerOpcode
|
||||
// GMs still can teleport player in instance.
|
||||
// Is it needed?
|
||||
lock(_mapLock)
|
||||
{
|
||||
// Dungeon only code
|
||||
if (IsDungeon())
|
||||
@@ -4878,7 +4885,9 @@ namespace Game.Maps
|
||||
|
||||
public override bool AddPlayerToMap(Player player, bool initPlayer = true)
|
||||
{
|
||||
player.m_InstanceValid = true;
|
||||
lock (_mapLock)
|
||||
player.m_InstanceValid = true;
|
||||
|
||||
return base.AddPlayerToMap(player, initPlayer);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user