Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -17,5 +17,7 @@ public enum MapEnvironmentFormatVersion
{
/// <summary>The initial version.</summary>
v11 = 11,
/// <summary>Introduced in v2.0.3.23052.</summary>
v12 = 12,
}
}
122 changes: 105 additions & 17 deletions src/War3Net.Build.Core/Environment/TerrainTile.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,22 +14,20 @@ public sealed partial class TerrainTile
public const int TileWidth = 128;
public const int TileHeight = 128;

/// <summary>
/// Size in bytes.
/// </summary>
public const int Size = 7;

private ushort _heightData;
private ushort _waterDataAndEdgeFlag;
private byte _textureDataAndFlags;
private ushort _textureDataAndFlags;

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it would be better to turn this into two separate bytes, one for texture (6 bits), and one for the flags (4 bits, this could even be a Flags enum). Even though it doesn't match the binary data, it would be a cleaner solution because you don't need to store the _formatVersion for every tile, and it'll keep the property getters/setters simple.

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is basically what @Luashine suggested as well. Makes me wonder why Blizzard didn't just increase the limit to 256, they got 6 bits to spare anyways.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Retera went off talking about his renderer being limited to 16 tiles/textures etc. It's possible there's truth to that point and the WC3 render is the limiting factor in the end.

private byte _variationData;
private byte _cliffData;

private MapEnvironmentFormatVersion _formatVersion;

/// <summary>
/// Initializes a new instance of the <see cref="TerrainTile"/> class.
/// </summary>
public TerrainTile()
public TerrainTile(MapEnvironmentFormatVersion formatVersion)
{
_formatVersion = formatVersion;
}

public float Height
Expand All @@ -52,32 +50,122 @@ public bool IsEdgeTile

public int Texture
{
get => _textureDataAndFlags & 0x0F;
set => _textureDataAndFlags = (value >= 0 && value <= 0x0F) ? (byte)(value | (_textureDataAndFlags & 0xF0)) : throw new ArgumentOutOfRangeException(nameof(value));
get
{
if (_formatVersion >= MapEnvironmentFormatVersion.v12)
{
return _textureDataAndFlags & 0x3F;
}
return _textureDataAndFlags & 0x0F;
}

set
{
if (_formatVersion >= MapEnvironmentFormatVersion.v12)
{
_textureDataAndFlags = (value >= 0 && value <= 0x3F) ? (ushort)(value | (_textureDataAndFlags & 0xFFC0)) : throw new ArgumentOutOfRangeException(nameof(value));
}
else
{
_textureDataAndFlags = (value >= 0 && value <= 0x0F) ? (ushort)(value | (_textureDataAndFlags & 0xF0)) : throw new ArgumentOutOfRangeException(nameof(value));
}
}
}

public bool IsRamp
{
get => (_textureDataAndFlags & 0x10) != 0;
set => _textureDataAndFlags = (byte)(value ? _textureDataAndFlags | 0x10 : _textureDataAndFlags & 0xEF);
get
{
if (_formatVersion >= MapEnvironmentFormatVersion.v12)
{
return (_textureDataAndFlags & 0x40) != 0;
}
return (_textureDataAndFlags & 0x10) != 0;
}

set
{
if (_formatVersion >= MapEnvironmentFormatVersion.v12)
{
_textureDataAndFlags = (ushort)(value ? _textureDataAndFlags | 0x40 : _textureDataAndFlags & 0xBF);
}
else
{
_textureDataAndFlags = (ushort)(value ? _textureDataAndFlags | 0x10 : _textureDataAndFlags & 0xEF);
}
}
}

public bool IsBlighted
{
get => (_textureDataAndFlags & 0x20) != 0;
set => _textureDataAndFlags = (byte)(value ? _textureDataAndFlags | 0x20 : _textureDataAndFlags & 0xDF);
get
{
if (_formatVersion >= MapEnvironmentFormatVersion.v12)
{
return (_textureDataAndFlags & 0x80) != 0;
}
return (_textureDataAndFlags & 0x20) != 0;
}

set
{
if (_formatVersion >= MapEnvironmentFormatVersion.v12)
{
_textureDataAndFlags = (ushort)(value ? _textureDataAndFlags | 0x80 : _textureDataAndFlags & 0x7F);
}
else
{
_textureDataAndFlags = (ushort)(value ? _textureDataAndFlags | 0x20 : _textureDataAndFlags & 0xDF);
}
}
}

public bool IsWater
{
get => (_textureDataAndFlags & 0x40) != 0;
set => _textureDataAndFlags = (byte)(value ? _textureDataAndFlags | 0x40 : _textureDataAndFlags & 0xBF);
get
{
if (_formatVersion >= MapEnvironmentFormatVersion.v12)
{
return (_textureDataAndFlags & 0x100) != 0;
}
return (_textureDataAndFlags & 0x40) != 0;
}

set
{
if (_formatVersion >= MapEnvironmentFormatVersion.v12)
{
_textureDataAndFlags = (ushort)(value ? _textureDataAndFlags | 0x100 : _textureDataAndFlags & 0xEFF);
}
else
{
_textureDataAndFlags = (ushort)(value ? _textureDataAndFlags | 0x40 : _textureDataAndFlags & 0xBF);
}
}
}

public bool IsBoundary
{
get => (_textureDataAndFlags & 0x80) != 0;
set => _textureDataAndFlags = (byte)(value ? _textureDataAndFlags | 0x80 : _textureDataAndFlags & 0x7F);
get
{
if (_formatVersion >= MapEnvironmentFormatVersion.v12)
{
return (_textureDataAndFlags & 0x200) != 0;
}
return (_textureDataAndFlags & 0x80) != 0;
}

set
{
if (_formatVersion >= MapEnvironmentFormatVersion.v12)
{
_textureDataAndFlags = (ushort)(value ? _textureDataAndFlags | 0x200 : _textureDataAndFlags & 0xDFF);
}
else
{
_textureDataAndFlags = (ushort)(value ? _textureDataAndFlags | 0x80 : _textureDataAndFlags & 0x7F);
}
}
}

public int Variation
Expand Down
2 changes: 1 addition & 1 deletion src/War3Net.Build.Core/MapFactory/Environment.cs
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ public static MapEnvironment Environment(
{
var isEdgeTile = x != width && y != height && (x < leftBound || x >= rightEdge || y < bottomBound || y >= topEdge);

mapEnvironment.TerrainTiles.Add(new TerrainTile
mapEnvironment.TerrainTiles.Add(new TerrainTile(mapEnvironment.FormatVersion)
{
Height = 0,
WaterHeight = 0,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,22 @@ public sealed partial class TerrainTile
{
internal TerrainTile(BinaryReader reader, MapEnvironmentFormatVersion formatVersion)
{
_formatVersion = formatVersion;
ReadFrom(reader, formatVersion);
}

internal void ReadFrom(BinaryReader reader, MapEnvironmentFormatVersion formatVersion)
{
_heightData = reader.ReadUInt16();
_waterDataAndEdgeFlag = reader.ReadUInt16();
_textureDataAndFlags = reader.ReadByte();
if (formatVersion >= MapEnvironmentFormatVersion.v12)
{
_textureDataAndFlags = reader.ReadUInt16();
}
else
{
_textureDataAndFlags = reader.ReadByte();
}
_variationData = reader.ReadByte();
_cliffData = reader.ReadByte();
}
Expand All @@ -29,7 +37,14 @@ internal void WriteTo(BinaryWriter writer, MapEnvironmentFormatVersion formatVer
{
writer.Write(_heightData);
writer.Write(_waterDataAndEdgeFlag);
writer.Write(_textureDataAndFlags);
if (formatVersion >= MapEnvironmentFormatVersion.v12)
{
writer.Write(_textureDataAndFlags);
}
else
{
writer.Write((byte)_textureDataAndFlags);
}
writer.Write(_variationData);
writer.Write(_cliffData);
}
Expand Down
Loading