Skip to content

Commit

Permalink
Added Dat structures and tests for UILayout and DbProperties (#4208)
Browse files Browse the repository at this point in the history
  • Loading branch information
OptimShi authored Aug 13, 2024
1 parent 89e023c commit ed7af65
Show file tree
Hide file tree
Showing 13 changed files with 563 additions and 47 deletions.
32 changes: 20 additions & 12 deletions Source/ACE.DatLoader.Tests/DatTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,15 @@ namespace ACE.DatLoader.Tests
[TestClass]
public class DatTests
{
private static string cellDatLocation = @"C:\Turbine\Asheron's Call\client_cell_1.dat";
private static string DAT_PATH = @"C:\Turbine\Asheron's Call\";

private static string cellDatLocation = DAT_PATH + "client_cell_1.dat";
private static int expectedCellDatFileCount = 805003;

private static string portalDatLocation = @"C:\Turbine\Asheron's Call\client_portal.dat";
private static string portalDatLocation = DAT_PATH + "client_portal.dat";
private static int expectedPortalDatFileCount = 79694;

private static string localEnglishDatLocation = @"C:\Turbine\Asheron's Call\client_local_English.dat";
private static string localEnglishDatLocation = DAT_PATH + "client_local_English.dat";
private static int expectedLocalEnglishDatFileCount = 118;


Expand Down Expand Up @@ -114,6 +116,11 @@ public void UnpackCellDatFiles_NoExceptions()
[TestMethod]
public void UnpackPortalDatFiles_NoExceptions()
{
// We need to init the DatManager to load PortalDat.MasterProperty for the BaseProperty references for DbProperties
// And we need the code page for some of the PortalDat autoload types
System.Text.Encoding.RegisterProvider(System.Text.CodePagesEncodingProvider.Instance);
DatManager.Initialize(DAT_PATH, true, false);

var assembly = typeof(DatDatabase).GetTypeInfo().Assembly;
var types = assembly.GetTypes().Where(t => t.GetCustomAttributes(typeof(DatFileTypeAttribute), false).Length > 0).ToList();

Expand All @@ -133,12 +140,11 @@ public void UnpackPortalDatFiles_NoExceptions()
Assert.IsNotNull(fileType, $"Key: 0x{kvp.Key:X8}, ObjectID: 0x{kvp.Value.ObjectId:X8}, FileSize: {kvp.Value.FileSize}");

// These file types aren't converted yet
if (fileType == DatFileType.KeyMap) continue;
if (fileType == DatFileType.RenderMaterial) continue;
if (fileType == DatFileType.MaterialModifier) continue;
if (fileType == DatFileType.MaterialInstance) continue;
if (fileType == DatFileType.ActionMap) continue;
if (fileType == DatFileType.DbProperties) continue;
if (fileType == DatFileType.KeyMap) continue; // 0x14, 2 files
if (fileType == DatFileType.RenderMaterial) continue; // 0x16, 1 file
if (fileType == DatFileType.MaterialModifier) continue; // 0x17, 1 file
if (fileType == DatFileType.MaterialInstance) continue; // 0x18, 1 file
if (fileType == DatFileType.ActionMap) continue; // 0x26, 1 file

var type = types
.SelectMany(m => m.GetCustomAttributes(typeof(DatFileTypeAttribute), false), (m, a) => new { m, a })
Expand Down Expand Up @@ -173,6 +179,11 @@ public void UnpackPortalDatFiles_NoExceptions()
[TestMethod]
public void UnpackLocalEnglishDatFiles_NoExceptions()
{
// We need to init the DatManager to load PortalDat.MasterProperty for the BaseProperty references for UiLayout/LayoutDesc
// And we need the code page for some of the PortalDat autoload types
System.Text.Encoding.RegisterProvider(System.Text.CodePagesEncodingProvider.Instance);
DatManager.Initialize(DAT_PATH, true, false);

var assembly = typeof(DatDatabase).GetTypeInfo().Assembly;
var types = assembly.GetTypes().Where(t => t.GetCustomAttributes(typeof(DatFileTypeAttribute), false).Length > 0).ToList();

Expand All @@ -191,9 +202,6 @@ public void UnpackLocalEnglishDatFiles_NoExceptions()
//Assert.IsNotNull(fileType, $"Key: 0x{kvp.Key:X8}, ObjectID: 0x{kvp.Value.ObjectId:X8}, FileSize: {kvp.Value.FileSize}, BitFlags:, 0x{kvp.Value.BitFlags:X8}");
Assert.IsNotNull(fileType, $"Key: 0x{kvp.Key:X8}, ObjectID: 0x{kvp.Value.ObjectId:X8}, FileSize: {kvp.Value.FileSize}");

// These file types aren't converted yet
if (fileType == DatFileType.UiLayout) continue;

var type = types
.SelectMany(m => m.GetCustomAttributes(typeof(DatFileTypeAttribute), false), (m, a) => new { m, a })
.Where(t => ((DatFileTypeAttribute)t.a).FileType == fileType)
Expand Down
108 changes: 108 additions & 0 deletions Source/ACE.DatLoader/Entity/BaseProperty.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
using ACE.Entity.Enum;
using System;
using System.Collections.Generic;
using System.IO;
using System.Numerics;

namespace ACE.DatLoader.Entity
{
public class BaseProperty : IUnpackable
{
// If this is in a collection/hashtable, this will actually match the key in that table.
// The enum value of this can be looked up in MasterProperty
public uint Id;

public BasePropertyType PropertyType; // This is read from the MasterProperty table

// Depending on the PropertyType, one of these values will be populated
public uint ValueEnum;
public bool ValueBool;
public uint ValueDataFile;
public float ValueFloat;
public StringInfo ValueString;
public uint ValueColor;
public List<BaseProperty> ValueArray;
public int ValueInt;
public Dictionary<uint, BaseProperty> ValueStruct;
public Vector3 ValueVector;
public uint ValueBitfield32;
public ulong ValueBitfield64;
public uint ValueInstanceId;

public void Unpack(BinaryReader reader)
{
Id = reader.ReadUInt32();

if (!DatManager.PortalDat.MasterProperty.m_properties.ContainsKey(Id))
throw (new Exception("Unable to locate BaseProperty type in the MasterProperty table"));

PropertyType = DatManager.PortalDat.MasterProperty.m_properties[Id].m_propertyType;
switch(PropertyType)
{
case BasePropertyType.Enum:
ValueEnum = reader.ReadUInt32();
break;
case BasePropertyType.Bool:
ValueBool = reader.ReadBoolean();
break;
case BasePropertyType.DataFile:
ValueDataFile = reader.ReadUInt32();
break;
case BasePropertyType.Float:
ValueFloat = reader.ReadSingle();
break;
case BasePropertyType.StringInfo:
ValueString = new StringInfo();
ValueString.Unpack(reader);
break;
case BasePropertyType.Color:
ValueColor = reader.ReadUInt32();
break;
case BasePropertyType.Array:
ValueArray = new List<BaseProperty>();
ValueArray.Unpack(reader);
break;
case BasePropertyType.Integer:
ValueInt = reader.ReadInt32();
break;
case BasePropertyType.Struct:
ValueStruct = new Dictionary<uint, BaseProperty>();

// This packed list uses a little different format not handled in the unpackable extensions
reader.ReadByte(); // bucketSize?
var totalObjects = reader.ReadByte();
for (int i = 0; i < totalObjects; i++)
{
var key = reader.ReadUInt32();

var item = new BaseProperty();
item.Unpack(reader);
ValueStruct.Add(key, item);
}
break;
case BasePropertyType.String:
// No use cases in end-of-retail Dat files.
// While there are a couple of MasterProperty entries of this type, there are no BaseProperty entries that use them.
break;
case BasePropertyType.Vector:
ValueVector = reader.ReadVector3();
break;
case BasePropertyType.Bitfield32:
ValueBitfield32 = reader.ReadUInt32();
break;
case BasePropertyType.Bitfield64:
ValueBitfield64 = reader.ReadUInt64();
break;
case BasePropertyType.InstanceID:
ValueInstanceId = reader.ReadUInt32();
break;
default:
// Should never hit this!
throw new NotImplementedException();
break;
}


}
}
}
70 changes: 35 additions & 35 deletions Source/ACE.DatLoader/Entity/BasePropertyDesc.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,53 +8,53 @@ namespace ACE.DatLoader.Entity
{
public class BasePropertyDesc : IUnpackable
{
uint m_propertyName;
BasePropertyType m_propertyType;
PropertyGroupName m_propertyGroup;
uint m_propertyProvider;
uint m_data;
int unknown_int_1; // Is this `m_ePatchFlags`?
public uint m_propertyName;
public BasePropertyType m_propertyType;
public PropertyGroupName m_propertyGroup;
public uint m_propertyProvider;
public uint m_data;
public int unknown_int_1; // Is this `m_ePatchFlags`?

bool has_default_value; // Guessed Var Name based on usage
bool hasMax; // Guessed Var Name based on usage
bool hasMin; // Guessed Var Name based on usage
float minFloat;
float maxFloat;
int min;
int max;
public bool has_default_value; // Guessed Var Name based on usage
public bool hasMax; // Guessed Var Name based on usage
public bool hasMin; // Guessed Var Name based on usage
public float minFloat;
public float maxFloat;
public int min;
public int max;

// These are technically all extended BasePropertyValue types, e.g. BoolPropertyValue
bool defaultValueBool;
uint defaultValueColor;
Vector3 defaultValueVector;
int defaultValueInt;
float defaultValueFloat;
uint defaultValueEnum;
uint defaultValueDataFile;
public bool defaultValueBool;
public uint defaultValueColor;
public Vector3 defaultValueVector;
public int defaultValueInt;
public float defaultValueFloat;
public uint defaultValueEnum;
public uint defaultValueDataFile;

float m_fPredictionTimeout;
PropertyInheritanceType m_inheritanceType;
PropertyDatFileType m_datFileType;
PropertyPropagationType m_propagationType;
//PropertyCachingType m_cachingType;
PropertyCachingType m_cachingType;

bool m_bRequired;
bool m_bReadOnly;
bool m_bPropagateToChildren;
bool m_bNoCheckpoint;
bool m_bAbsoluteTimeStamp;
bool m_bGroupable;
bool m_bAllAvailable;
bool m_bDoNotReplay;
bool m_bRecorded;
bool m_bToolOnly;
public bool m_bRequired;
public bool m_bReadOnly;
public bool m_bPropagateToChildren;
public bool m_bNoCheckpoint;
public bool m_bAbsoluteTimeStamp;
public bool m_bGroupable;
public bool m_bAllAvailable;
public bool m_bDoNotReplay;
public bool m_bRecorded;
public bool m_bToolOnly;

Dictionary<uint, uint> m_availableProperties = new Dictionary<uint, uint>();
public Dictionary<uint, uint> m_availableProperties = new Dictionary<uint, uint>();

public void Unpack(BinaryReader reader)
{
// This is a reference to the m_emapper of the MasterProperty. It also matches the SmartArray key
m_propertyName = reader.ReadUInt32();
m_propertyName = reader.ReadUInt32();
m_propertyType = (BasePropertyType)reader.ReadUInt32();
m_propertyGroup = (PropertyGroupName)reader.ReadUInt32();
m_propertyProvider = reader.ReadUInt32();
Expand Down Expand Up @@ -110,7 +110,7 @@ public void Unpack(BinaryReader reader)
}
hasMin = reader.ReadBoolean();
if (hasMax)
{
{
switch (m_propertyType)
{
case BasePropertyType.Float:
Expand Down Expand Up @@ -141,7 +141,7 @@ public void Unpack(BinaryReader reader)
m_bToolOnly = reader.ReadBoolean(); // Always true

var numItems = reader.ReadByte();
for(var i = 0; i < numItems; i++)
for (var i = 0; i < numItems; i++)
{
m_availableProperties.Add(reader.ReadUInt32(), reader.ReadUInt32());
}
Expand Down
88 changes: 88 additions & 0 deletions Source/ACE.DatLoader/Entity/ElementDesc.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
using ACE.Entity.Enum;
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;

namespace ACE.DatLoader.Entity
{
public class ElementDesc : StateDesc
{
public uint UiReadOrder;

// Enum names for these are in EnumMapper 0x2200001B (UIElementID)
public uint ElementId;
public uint Type;
public uint BaseElement;
public uint BaseLayout;
public uint DefaultState;

public uint X;
public uint Y;
public uint Width;
public uint Height;
public uint ZLevel;
public uint LeftEdge;
public uint TopEdge;
public uint RightEdge;
public uint BottomEdge;

public Dictionary<uint, StateDesc> States = new Dictionary<uint, StateDesc>();
public Dictionary<uint, ElementDesc> Children = new Dictionary<uint, ElementDesc>();

public override void Unpack(BinaryReader reader)
{
base.Unpack(reader);
UnpackElementDesc(reader);
}

public void UnpackElementDesc(BinaryReader reader)
{
UiReadOrder = reader.ReadUInt32();
ElementId = reader.ReadUInt32();
Type = reader.ReadUInt32();
BaseElement = reader.ReadUInt32();
BaseLayout = reader.ReadUInt32();
DefaultState = reader.ReadUInt32();

if ((UiIncorporationFlags & IncorporationFlags.X) != 0)
X = reader.ReadUInt32();
if ((UiIncorporationFlags & IncorporationFlags.Y) != 0)
Y = reader.ReadUInt32();
if ((UiIncorporationFlags & IncorporationFlags.Width) != 0)
Width = reader.ReadUInt32();
if ((UiIncorporationFlags & IncorporationFlags.Height) != 0)
Height = reader.ReadUInt32();
if ((UiIncorporationFlags & IncorporationFlags.ZLevel) != 0)
ZLevel = reader.ReadUInt32();

LeftEdge = reader.ReadUInt32();
TopEdge = reader.ReadUInt32();
RightEdge = reader.ReadUInt32();
BottomEdge = reader.ReadUInt32();

reader.ReadByte();
var totalObjects = reader.ReadByte();
for (int i = 0; i < totalObjects; i++)
{
var key = reader.ReadUInt32();

var item = new StateDesc();
item.Unpack(reader);
States.Add(key, item);
}

reader.ReadByte();
var totalChildren = reader.ReadByte();
for (int i = 0; i < totalChildren; i++)
{
var key = reader.ReadUInt32();

var item = new ElementDesc();
item.Unpack(reader);
Children.Add(key, item);
}

}
}
}
Loading

0 comments on commit ed7af65

Please sign in to comment.