diff --git a/Source/Framework/Constants/MapConst.cs b/Source/Framework/Constants/MapConst.cs index c861a4258..7b55deac9 100644 --- a/Source/Framework/Constants/MapConst.cs +++ b/Source/Framework/Constants/MapConst.cs @@ -49,7 +49,6 @@ namespace Framework.Constants public const int MapLiquidTypeMagma = 0x04; public const int MapLiquidTypeSlime = 0x08; public const int MapLiquidTypeDarkWater = 0x10; - public const int MapLiquidTypeWMOWater = 0x20; public const int MapAllLiquidTypes = (MapLiquidTypeWater | MapLiquidTypeOcean | MapLiquidTypeMagma | MapLiquidTypeSlime); public const float LiquidTileSize = (533.333f / 128.0f); @@ -63,7 +62,7 @@ namespace Framework.Constants public const float MaxFallDistance = 250000.0f; public const string MapMagic = "MAPS"; - public const string MapVersionMagic = "v1.8"; + public const string MapVersionMagic = "v1.9"; public const string MapAreaMagic = "AREA"; public const string MapHeightMagic = "MHGT"; public const string MapLiquidMagic = "MLIQ"; @@ -71,7 +70,7 @@ namespace Framework.Constants public const string mmapMagic = "MMAP"; public const int mmapVersion = 8; - public const string VMapMagic = "VMAP_4.6"; + public const string VMapMagic = "VMAP_4.7"; public const float VMAPInvalidHeightValue = -200000.0f; } diff --git a/Source/Game/Collision/Models/GameObjectModel.cs b/Source/Game/Collision/Models/GameObjectModel.cs index a15eab954..d08153c4e 100644 --- a/Source/Game/Collision/Models/GameObjectModel.cs +++ b/Source/Game/Collision/Models/GameObjectModel.cs @@ -19,6 +19,7 @@ using Framework.GameMath; using System; using System.Collections.Generic; using System.IO; +using Framework.Constants; namespace Game.Collision { @@ -27,40 +28,40 @@ namespace Game.Collision public static Dictionary models = new Dictionary(); } - public class GameObjectModelOwnerBase + public abstract class GameObjectModelOwnerBase { - public virtual bool IsSpawned() { return false; } - public virtual uint GetDisplayId() { return 0; } - public virtual byte GetNameSetId() { return 0; } - public virtual bool IsInPhase(PhaseShift phaseShift) { return false; } - public virtual Vector3 GetPosition() { return Vector3.Zero; } - public virtual float GetOrientation() { return 0.0f; } - public virtual float GetScale() { return 1.0f; } - public virtual void DebugVisualizeCorner(Vector3 corner) { } + public abstract bool IsSpawned(); + public abstract uint GetDisplayId(); + public abstract byte GetNameSetId(); + public abstract bool IsInPhase(PhaseShift phaseShift); + public abstract Vector3 GetPosition(); + public abstract float GetOrientation(); + public abstract float GetScale(); + public abstract void DebugVisualizeCorner(Vector3 corner); } public class GameObjectModel : IModel { bool initialize(GameObjectModelOwnerBase modelOwner) { - var it = StaticModelList.models.LookupByKey(modelOwner.GetDisplayId()); - if (it == null) + var modelData = StaticModelList.models.LookupByKey(modelOwner.GetDisplayId()); + if (modelData == null) return false; - AxisAlignedBox mdl_box = new AxisAlignedBox(it.bound); + AxisAlignedBox mdl_box = new AxisAlignedBox(modelData.bound); // ignore models with no bounds if (mdl_box == AxisAlignedBox.Zero()) { - Log.outError(LogFilter.Server, "GameObject model {0} has zero bounds, loading skipped", it.name); + Log.outError(LogFilter.Server, "GameObject model {0} has zero bounds, loading skipped", modelData.name); return false; } - iModel = Global.VMapMgr.acquireModelInstance(it.name); + iModel = Global.VMapMgr.acquireModelInstance(modelData.name); if (iModel == null) return false; - name = it.name; + name = modelData.name; iPos = modelOwner.GetPosition(); iScale = modelOwner.GetScale(); iInvScale = 1.0f / iScale; @@ -75,6 +76,7 @@ namespace Game.Collision iBound = rotated_bounds + iPos; owner = modelOwner; + isWmo = modelData.isWmo; return true; } @@ -114,7 +116,7 @@ namespace Game.Collision public override void IntersectPoint(Vector3 point, AreaInfo info, PhaseShift phaseShift) { - if (!isCollisionEnabled() || !owner.IsSpawned()) + if (!isCollisionEnabled() || !owner.IsSpawned() || !isMapObject()) return; if (!owner.IsInPhase(phaseShift)) @@ -176,6 +178,7 @@ namespace Game.Collision public void enableCollision(bool enable) { _collisionEnabled = enable; } bool isCollisionEnabled() { return _collisionEnabled; } + bool isMapObject() { return isWmo; } public static void LoadGameObjectModelList() { @@ -190,8 +193,12 @@ namespace Game.Collision { using (BinaryReader reader = new BinaryReader(new FileStream(filename, FileMode.Open, FileAccess.Read))) { - uint name_length, displayId; - string name; + string magic = reader.ReadStringFromChars(8); + if (magic != MapConst.VMapMagic) + { + Log.outError(LogFilter.Misc, $"File '{MapConst.GAMEOBJECT_MODELS}' has wrong header, expected {MapConst.VMapMagic}."); + return; + } long length = reader.BaseStream.Length; while (true) @@ -199,14 +206,14 @@ namespace Game.Collision if (reader.BaseStream.Position >= length) break; - Vector3 v1, v2; - displayId = reader.ReadUInt32(); - name_length = reader.ReadUInt32(); - name = reader.ReadString((int)name_length); - v1 = reader.Read(); - v2 = reader.Read(); + uint displayId = reader.ReadUInt32(); + bool isWmo = reader.ReadBoolean(); + int name_length = reader.ReadInt32(); + string name = reader.ReadString(name_length); + Vector3 v1 = reader.Read(); + Vector3 v2 = reader.Read(); - StaticModelList.models.Add(displayId, new GameobjectModelData(name, new AxisAlignedBox(v1, v2))); + StaticModelList.models.Add(displayId, new GameobjectModelData(name, v1, v2, isWmo)); } } } @@ -227,17 +234,20 @@ namespace Game.Collision float iScale; WorldModel iModel; GameObjectModelOwnerBase owner; + bool isWmo; } public class GameobjectModelData { - public GameobjectModelData(string name_, AxisAlignedBox box) + public GameobjectModelData(string name_, Vector3 lowBound, Vector3 highBound, bool isWmo_) { - bound = box; + bound = new AxisAlignedBox(lowBound, highBound); name = name_; + isWmo = isWmo_; } public AxisAlignedBox bound; public string name; + public bool isWmo; } } diff --git a/Source/Game/Collision/Models/WorldModel.cs b/Source/Game/Collision/Models/WorldModel.cs index e34c5c991..e58545abe 100644 --- a/Source/Game/Collision/Models/WorldModel.cs +++ b/Source/Game/Collision/Models/WorldModel.cs @@ -47,8 +47,16 @@ namespace Game.Collision iCorner = corner; iType = type; - iHeight = new float[(width + 1) * (height + 1)]; - iFlags = new byte[width * height]; + if (width != 0 && height != 0) + { + iHeight = new float[(width + 1) * (height + 1)]; + iFlags = new byte[width * height]; + } + else + { + iHeight = new float[1]; + iFlags = null; + } } public WmoLiquid(WmoLiquid other) { @@ -77,6 +85,13 @@ namespace Game.Collision public bool GetLiquidHeight(Vector3 pos, out float liqHeight) { + // simple case + if (iFlags == null) + { + liqHeight = iHeight[0]; + return true; + } + liqHeight = 0f; float tx_f = (pos.X - iCorner.X) / MapConst.LiquidTileSize; uint tx = (uint)tx_f; @@ -112,27 +127,6 @@ namespace Game.Collision return true; } - bool writeToFile(BinaryWriter writer) - { - writer.Write(iTilesX); - writer.Write(iTilesY); - - writer.Write(iCorner.X); - writer.Write(iCorner.Y); - writer.Write(iCorner.Z); - writer.Write(iType); - - uint size = (iTilesX + 1) * (iTilesY + 1); - for (var i = 0; i < size; i++) - writer.Write(iHeight[i]); - - size = iTilesX * iTilesY; - for (var i = 0; i < size; i++) - writer.Write(iFlags[0]); - - return true; - } - public static WmoLiquid readFromFile(BinaryReader reader) { WmoLiquid liquid = new WmoLiquid(); @@ -142,15 +136,23 @@ namespace Game.Collision liquid.iCorner = reader.Read(); liquid.iType = reader.ReadUInt32(); - 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(); + 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(); - size = liquid.iTilesX * liquid.iTilesY; - liquid.iFlags = new byte[size]; - for (var i = 0; i < size; i++) - liquid.iFlags[i] = reader.ReadByte(); + size = liquid.iTilesX * liquid.iTilesY; + liquid.iFlags = new byte[size]; + for (var i = 0; i < size; i++) + liquid.iFlags[i] = reader.ReadByte(); + } + else + { + liquid.iHeight = new float[1]; + liquid.iHeight[0] = reader.ReadSingle(); + } return liquid; } diff --git a/Source/Game/Maps/GridMap.cs b/Source/Game/Maps/GridMap.cs index dc5b1a2d3..cee848c5c 100644 --- a/Source/Game/Maps/GridMap.cs +++ b/Source/Game/Maps/GridMap.cs @@ -187,7 +187,8 @@ namespace Game.Maps reader.BaseStream.Seek(offset, SeekOrigin.Begin); map_LiquidHeader liquidHeader = reader.ReadStruct(); - _liquidType = liquidHeader.liquidType; + _liquidGlobalEntry = liquidHeader.liquidType; + _liquidGlobalFlags = (byte)liquidHeader.liquidFlags; _liquidOffX = liquidHeader.offsetX; _liquidOffY = liquidHeader.offsetY; _liquidWidth = liquidHeader.width; @@ -506,7 +507,7 @@ namespace Game.Maps public ZLiquidStatus getLiquidStatus(float x, float y, float z, byte ReqLiquidType, LiquidData data) { // Check water type (if no water return) - if (_liquidType == 0 && _liquidFlags == null) + if (_liquidGlobalFlags == 0 && _liquidFlags == null) return ZLiquidStatus.NoWater; // Get cell @@ -518,38 +519,34 @@ namespace Game.Maps // Check water type in cell int idx = (x_int >> 3) * 16 + (y_int >> 3); - byte type = _liquidFlags != null ? _liquidFlags[idx] : (byte)_liquidType; - uint entry = 0; - if (_liquidEntry != null) + byte type = _liquidFlags != null ? _liquidFlags[idx] : _liquidGlobalFlags; + uint entry = _liquidEntry != null ? _liquidEntry[idx] : _liquidGlobalEntry; + LiquidTypeRecord liquidEntry = CliDB.LiquidTypeStorage.LookupByKey(entry); + if (liquidEntry != null) { - var liquidEntry = CliDB.LiquidTypeStorage.LookupByKey(_liquidEntry[idx]); - if (liquidEntry != null) + type &= MapConst.MapLiquidTypeDarkWater; + uint liqTypeIdx = liquidEntry.SoundBank; + if (entry < 21) { - entry = liquidEntry.Id; - type &= MapConst.MapLiquidTypeDarkWater; - uint liqTypeIdx = liquidEntry.SoundBank; - if (entry < 21) + var area = CliDB.AreaTableStorage.LookupByKey(getArea(x, y)); + if (area != null) { - var area = CliDB.AreaTableStorage.LookupByKey(getArea(x, y)); - if (area != null) + uint overrideLiquid = area.LiquidTypeID[liquidEntry.SoundBank]; + if (overrideLiquid == 0 && area.ParentAreaID == 0) { - uint overrideLiquid = area.LiquidTypeID[liquidEntry.SoundBank]; - if (overrideLiquid == 0 && area.ParentAreaID == 0) - { - area = CliDB.AreaTableStorage.LookupByKey(area.ParentAreaID); - if (area != null) - overrideLiquid = area.LiquidTypeID[liquidEntry.SoundBank]; - } - var liq = CliDB.LiquidTypeStorage.LookupByKey(overrideLiquid); - if (liq != null) - { - entry = overrideLiquid; - liqTypeIdx = liq.SoundBank; - } + area = CliDB.AreaTableStorage.LookupByKey(area.ParentAreaID); + if (area != null) + overrideLiquid = area.LiquidTypeID[liquidEntry.SoundBank]; + } + var liq = CliDB.LiquidTypeStorage.LookupByKey(overrideLiquid); + if (liq != null) + { + entry = overrideLiquid; + liqTypeIdx = liq.SoundBank; } } - type |= (byte)(1 << (int)liqTypeIdx); } + type |= (byte)(1 << (int)liqTypeIdx); } if (type == 0) @@ -629,7 +626,8 @@ namespace Game.Maps byte[] _liquidFlags; float[] _liquidMap; ushort _gridArea; - ushort _liquidType; + ushort _liquidGlobalEntry; + byte _liquidGlobalFlags; byte _liquidOffX; byte _liquidOffY; byte _liquidWidth; @@ -679,6 +677,7 @@ namespace Game.Maps { public uint fourcc; public LiquidHeaderFlags flags; + public byte liquidFlags; public ushort liquidType; public byte offsetX; public byte offsetY; @@ -712,7 +711,7 @@ namespace Game.Maps } [Flags] - public enum LiquidHeaderFlags : ushort + public enum LiquidHeaderFlags : byte { LiquidNoType = 0x0001, LiquidNoHeight = 0x0002