Skip to content
Merged
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
6 changes: 4 additions & 2 deletions src/Imcodec.CoreObject/BehaviorInstance.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,12 @@ contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
*/

using Imcodec.ObjectProperty;

namespace Imcodec.CoreObject;

public partial record BehaviorInstance {
public partial record BehaviorInstance : PropertyClass {

public override uint GetHash() => 1578701589;


}
6 changes: 4 additions & 2 deletions src/Imcodec.CoreObject/BehaviorTemplate.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,12 @@ contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
*/

using Imcodec.ObjectProperty;

namespace Imcodec.CoreObject;

public partial record BehaviorTemplate {
public partial record BehaviorTemplate : PropertyClass {

public override uint GetHash() => 360231646;

}
8 changes: 0 additions & 8 deletions src/Imcodec.CoreObject/CoreObject.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,12 +31,4 @@ public partial record CoreObject : PropertyClass {
public CoreObject(CoreTemplate coreTemplate)
=> m_coreTemplate = coreTemplate;

public override void EncodeIdentifier(BitWriter writer) {
var id = m_coreTemplate.m_templateID;

writer.WriteUInt8(id.MParts.Block);
writer.WriteUInt8(id.MParts.Type);
writer.WriteUInt32(id.MParts.TemplateId);
}

}
60 changes: 34 additions & 26 deletions src/Imcodec.CoreObject/CoreObjectSerializer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -32,11 +32,23 @@ namespace Imcodec.CoreObject;
/// <param name="Versionable">States whether the object is versionable.</param>
/// <param name="Behaviors">States the behaviors of the serializer.</param>
/// <param name="typeRegistry">The type registry to use for serialization.</param>
public sealed class CoreObjectSerializer(bool Versionable = false,
SerializerFlags Behaviors = SerializerFlags.UseFlags | SerializerFlags.Compress,
TypeRegistry? typeRegistry = null) : ObjectSerializer(Versionable, Behaviors, typeRegistry) {

protected override bool PreloadObject(BitReader inputBuffer, out PropertyClass? propertyClass) {
public sealed class CoreObjectSerializer(
bool versionable = false,
SerializerFlags behaviors = SerializerFlags.UseFlags | SerializerFlags.Compress,
TypeRegistry? typeRegistry = null
) : ObjectSerializer(versionable, behaviors, typeRegistry) {

private static readonly Dictionary<int, (byte, byte)> s_blockAndTypeMap = new() {
{ 350837933, (2, 2) }, // ClientObject
{ 766500222, (104, 2) }, // WizClientObject
{ 1653772158, (115, 9) }, // WizClientObjectItem
{ 1167581154, (106, 2) }, // WizClientPet
{ 2109552587, (108, 2) }, // WizClientMount
{ 398229815, (132, 9) }, // ClientReagentItem
{ 958775582, (131, 131) } // ClientRecipe
};

public override bool PreloadObject(BitReader inputBuffer, out PropertyClass? propertyClass) {
propertyClass = null;
var block = inputBuffer.ReadUInt8();
var type = inputBuffer.ReadUInt8();
Expand All @@ -49,18 +61,20 @@ protected override bool PreloadObject(BitReader inputBuffer, out PropertyClass?
return propertyClass != null;
}

// Otherwise, treat it as a CoreObject.
// We can dispatch the type based on the template ID.
return false; // todo: fixme
var hash = GetHashFromBlockAndType(block, type);
propertyClass = DispatchType(hash);

return propertyClass != null;
}

protected override bool PreWriteObject(BitWriter writer, PropertyClass propertyClass) {
public override bool PreWriteObject(BitWriter writer, PropertyClass propertyClass) {
if (propertyClass is null) {
writer.WriteUInt8(0);
writer.WriteUInt8(0);
writer.WriteUInt32(0);

return true;
return false;
}

var (block, type) = GetBlockAndType(propertyClass);
Expand All @@ -84,23 +98,17 @@ private static (byte, byte) GetBlockAndType(PropertyClass propClass) {
return (0, 0);
}

return propClass.GetHash() switch {
350837933 => // ClientObject
(2, 2),
766500222 => // WizClientObject
(104, 2),
1653772158 => // WizClientObjectItem
(115, 9),
1167581154 => // WizClientPet
(106, 2),
2109552587 => // WizClientMount
(108, 2),
398229815 => // ClientReagentItem
(132, 9),
958775582 => // ClientRecipe
(131, 131),
_ => (0, 0)
};
return ((byte, byte)) (s_blockAndTypeMap.TryGetValue((int) propClass.GetHash(), out var blockAndType) ? blockAndType : (0, 0));
}

private static uint GetHashFromBlockAndType(byte block, byte type) {
foreach (var (key, value) in s_blockAndTypeMap) {
if (value == (block, type)) {
return (uint) key;
}
}

return 0;
}

}
5 changes: 4 additions & 1 deletion src/Imcodec.CoreObject/CoreTemplate.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,14 @@ 3. Neither the name of the copyright holder nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
*/
using Imcodec.ObjectProperty;
using Imcodec.Types;

namespace Imcodec.CoreObject;

public partial record CoreTemplate {
public partial record CoreTemplate : PropertyClass {

public override uint GetHash() => 1068918295;

public GID m_templateID { get; init; }

Expand Down
6 changes: 3 additions & 3 deletions src/Imcodec.ObjectProperty/BindSerializer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -74,8 +74,8 @@ public override bool Serialize(PropertyClass input, PropertyFlags propertyMask,
return false;
}

// Create a new buffer with the size of the output buffer plus the size of the magic.
var buffer = new byte[baseOutput!.Length + sizeof(uint)];
// Create a new buffer with the size of the output buffer plus the size of the magic and flags.
var buffer = new byte[baseOutput!.Length + sizeof(uint) * 2];

// Write the magic header and serializer flags.
BinaryPrimitives.WriteUInt32LittleEndian(buffer, BiNDMagic);
Expand Down Expand Up @@ -114,7 +114,7 @@ public override bool Deserialize<T>(byte[] inputBuffer, PropertyFlags propertyMa
var reader = new BitReader(inputBuffer);

// Check if the input buffer is too small to contain the magic header.
if (inputBuffer.Length < sizeof(uint)) {
if (inputBuffer.Length < sizeof(uint) * 2) {
return false;
}

Expand Down
79 changes: 46 additions & 33 deletions src/Imcodec.ObjectProperty/ObjectSerializer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ public enum SerializerFlags {
/// <summary>
/// States the serializer should use these flags for deserialization.
/// </summary>
UseFlags = 1 << 0,
UseFlags = 1 << 0,

/// <summary>
/// States the serializer should use compact length prefixes.
Expand All @@ -44,17 +44,17 @@ public enum SerializerFlags {
/// <summary>
/// States the serializer should use string enums.
/// </summary>
StringEnums = 1 << 2,
StringEnums = 1 << 2,

/// <summary>
/// States the serializer should use ZLib compression.
/// </summary>
Compress = 1 << 3,
Compress = 1 << 3,

/// <summary>
/// Properties are dirty encoded.
/// </summary>
DirtyEncode = 1 << 4,
DirtyEncode = 1 << 4,

}

Expand Down Expand Up @@ -202,7 +202,47 @@ public virtual bool Deserialize<T>(byte[] inputBuffer,

propertyClass?.Decode(reader, this);

output = (T)propertyClass!;
output = (T) propertyClass!;

return true;
}

/// <summary>
/// Preloads an object from the input buffer based on the provided hash value.
/// </summary>
/// <param name="inputBuffer">The input buffer containing the serialized data.</param>
/// <param name="propertyClass">The loaded property class, if found.</param>
/// <returns><c>true</c> if the object was preloaded successfully; otherwise, <c>false</c>.</returns>
public virtual bool PreloadObject(BitReader inputBuffer,
out PropertyClass? propertyClass) {
var hash = inputBuffer.ReadUInt32();
if (hash == 0) {
propertyClass = null;

return false;
}

propertyClass = DispatchType(hash);

return propertyClass != null;
}

/// <summary>
/// Writes the object identifier to the specified <see cref="BitWriter"/>.
/// </summary>
/// <param name="writer">The <see cref="BitWriter"/> to write to.</param>
/// <param name="propertyClass">The <see cref="PropertyClass"/> to write.</param>
/// <returns><c>true</c> if the object identifier was written successfully; otherwise, <c>false</c>.</returns>
public virtual bool PreWriteObject(BitWriter writer,
PropertyClass propertyClass) {
if (propertyClass == null) {
writer.WriteUInt32(0);

return false;
}

writer.WriteUInt32(propertyClass.GetHash());

return true;
}

Expand Down Expand Up @@ -247,33 +287,6 @@ protected virtual BitWriter Compress(BitWriter writer) {
return new BitReader(decompressedData);
}

/// <summary>
/// Preloads an object from the input buffer based on the provided hash value.
/// </summary>
/// <param name="inputBuffer">The input buffer containing the serialized data.</param>
/// <param name="propertyClass">The loaded property class, if found.</param>
/// <returns><c>true</c> if the object was preloaded successfully; otherwise, <c>false</c>.</returns>
protected virtual bool PreloadObject(BitReader inputBuffer,
out PropertyClass? propertyClass) {
var hash = inputBuffer.ReadUInt32();
propertyClass = DispatchType(hash);

return propertyClass != null;
}

/// <summary>
/// Writes the object identifier to the specified <see cref="BitWriter"/>.
/// </summary>
/// <param name="writer">The <see cref="BitWriter"/> to write to.</param>
/// <param name="propertyClass">The <see cref="PropertyClass"/> to write.</param>
/// <returns><c>true</c> if the object identifier was written successfully; otherwise, <c>false</c>.</returns>
protected virtual bool PreWriteObject(BitWriter writer,
PropertyClass propertyClass) {
propertyClass.EncodeIdentifier(writer);

return true;
}

/// <summary>
/// Dispatches the type based on the provided hash value.
/// </summary>
Expand All @@ -285,7 +298,7 @@ protected virtual bool PreWriteObject(BitWriter writer,
return null;
}

return (PropertyClass)Activator.CreateInstance(lookupType)!;
return (PropertyClass) Activator.CreateInstance(lookupType)!;
}

}
34 changes: 7 additions & 27 deletions src/Imcodec.ObjectProperty/Property.cs
Original file line number Diff line number Diff line change
Expand Up @@ -105,17 +105,11 @@ private static Type InnerType
bool IProperty.Encode(BitWriter writer, ObjectSerializer serializer) {
if (IsVector) {
var list = Getter?.Invoke(TargetObject, null);
if (!EncodeVector(writer, list, serializer)) {
return false;
}
return EncodeVector(writer, list, serializer);
}
else {
if (!EncodeElement(writer, serializer, Getter?.Invoke(TargetObject, null))) {
return false;
}
return EncodeElement(writer, serializer, Getter?.Invoke(TargetObject, null));
}

return true;
}

bool IProperty.Decode(BitReader reader, ObjectSerializer serializer) {
Expand Down Expand Up @@ -159,7 +153,7 @@ private static bool EncodeVector(BitWriter writer, object? val, ObjectSerializer

private static bool EncodeElement(BitWriter writer, ObjectSerializer serializer, object? val) {
if (InnerType.IsSubclassOf(typeof(PropertyClass))) {
return Property<T>.EncodePropertyClass(writer,(PropertyClass) val!, serializer);
return Property<T>.EncodePropertyClass(writer, (PropertyClass) val!, serializer);
}
else if (IsEnum) {
return Property<T>.EncodeEnum(writer, val!, serializer);
Expand Down Expand Up @@ -188,10 +182,8 @@ private static bool EncodeEnum(BitWriter writer, object val, ObjectSerializer se
private static bool EncodePropertyClass(BitWriter writer,
PropertyClass propertyClass,
ObjectSerializer serializer) {
if (propertyClass == null) {
writer.WriteUInt32(0);

return true;
if (!serializer.PreWriteObject(writer, propertyClass)) {
return false;
}

return propertyClass.Encode(writer, serializer);
Expand Down Expand Up @@ -297,23 +289,11 @@ private static bool DecodeEnum(BitReader reader, out object val, ObjectSerialize
private static bool DecodePropertyClass(BitReader reader,
ObjectSerializer serializer,
out PropertyClass? propertyClass) {
propertyClass = null;

var hash = reader.ReadUInt32();
if (hash == 0) {
return true;
}

// Dispatch this hash and see what property class we need to create.
var fetchedType = serializer.TypeRegistry.LookupType(hash);
if (fetchedType == null) {
if (!serializer.PreloadObject(reader, out propertyClass)) {
return false;
}

// Create a new instance of the property class.
propertyClass = (PropertyClass) Activator.CreateInstance(fetchedType)!;

return propertyClass.Decode(reader, serializer);
return propertyClass!.Decode(reader, serializer);
}

private static object? CastDecodedValue(object? value) {
Expand Down
8 changes: 0 additions & 8 deletions src/Imcodec.ObjectProperty/PropertyClass.cs
Original file line number Diff line number Diff line change
Expand Up @@ -132,14 +132,6 @@ internal bool Decode(BitReader reader, ObjectSerializer serializer) {
return true;
}

/// <summary>
/// Encodes the object identifier using the specified <see cref="BitWriter"/>.
/// </summary>
/// <param name="writer">The <see cref="BitWriter"/> used to write the
/// encoded identifier.</param>
public virtual void EncodeIdentifier(BitWriter writer)
=> writer.WriteUInt32(GetHash());

private bool EncodeVersionable(BitWriter writer, ObjectSerializer serializer) {
writer.WriteUInt32(0); // Placeholder for the size.

Expand Down
5 changes: 5 additions & 0 deletions test/CodeGen/CodeGenTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,11 @@ public void GenerateFromJsonManifestTest() {
var classDefinitions = compiler.Compile(jsonDump);

Assert.NotEmpty(classDefinitions);
Assert.Equal(2239, classDefinitions.Length);

var classDefinition = classDefinitions[23];
Assert.Equal("PetSnackBehaviorTemplate", classDefinition.Name);
Assert.Equal((double) 1956226406, classDefinition.Hash);
}

private static string? GetJsonDump() {
Expand Down
Loading
Loading