fix: Adds generic entity persistence support and BOBEntry as entities (#1527)

### Summary
Adds a generic entity persistence. This can be used to create new entity types that have a `Serial`.

Here is an example:

```cs
public class BOBEntries : GenericEntitySerialization<IBOBEntry>
{
    public static void Configure()
    {
        Configure("BOBEntries");
    }
}
```

The annotation tells the system what folder to serialize the entries to. The class/interface (`IBOBEntry`) is the root type that implements `ISerializable`.
This commit is contained in:
Kamron Batman 2023-10-01 17:38:52 -07:00 • committed by GitHub
parent 666b83a3dd
commit e0225c6e59
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
22 changed files with 666 additions and 311 deletions

View file

@ -290,9 +290,6 @@ namespace Server.Accounting
[CommandProperty(AccessLevel.GameMaster, readOnly: true)]
public DateTime Created { get; set; } = Core.Now;
[CommandProperty(AccessLevel.GameMaster)]
DateTime ISerializable.LastSerialized { get; set; } = Core.Now;
public Serial Serial { get; set; }
[AfterDeserialization(false)]

View file

@ -0,0 +1,9 @@
namespace Server.Engines.BulkOrders;
public class BOBEntries : GenericEntitySerialization<IBOBEntry>
{
public static void Configure()
{
Configure("BOBEntries");
}
}

View file

@ -1,119 +1,83 @@
namespace Server.Engines.BulkOrders
using ModernUO.Serialization;
namespace Server.Engines.BulkOrders;
[SerializationGenerator(1)]
public partial class BOBLargeEntry : BaseBOBEntry
{
public class BOBLargeEntry : IBOBEntry
[SerializableField(0, setter: "private")]
private BOBLargeSubEntry[] _entries;
public BOBLargeEntry(LargeBOD bod)
{
public BOBLargeEntry(LargeBOD bod)
RequireExceptional = bod.RequireExceptional;
DeedType = bod switch
{
RequireExceptional = bod.RequireExceptional;
LargeTailorBOD => BODType.Tailor,
LargeSmithBOD => BODType.Smith,
_ => DeedType
};
DeedType = bod switch
{
LargeTailorBOD => BODType.Tailor,
LargeSmithBOD => BODType.Smith,
_ => DeedType
};
Material = bod.Material;
AmountMax = bod.AmountMax;
Material = bod.Material;
AmountMax = bod.AmountMax;
_entries = new BOBLargeSubEntry[bod.Entries.Length];
Entries = new BOBLargeSubEntry[bod.Entries.Length];
for (var i = 0; i < _entries.Length; ++i)
{
_entries[i] = new BOBLargeSubEntry(bod.Entries[i]);
}
}
for (var i = 0; i < Entries.Length; ++i)
{
Entries[i] = new BOBLargeSubEntry(bod.Entries[i]);
}
public override Item Reconstruct()
{
LargeBOD bod = DeedType switch
{
BODType.Smith => new LargeSmithBOD(AmountMax, RequireExceptional, Material, ReconstructEntries()),
BODType.Tailor => new LargeTailorBOD(AmountMax, RequireExceptional, Material, ReconstructEntries()),
_ => null
};
for (var i = 0; i < bod?.Entries.Length; ++i)
{
bod.Entries[i].Owner = bod;
}
public BOBLargeEntry(IGenericReader reader)
return bod;
}
private LargeBulkEntry[] ReconstructEntries()
{
var entries = new LargeBulkEntry[Entries.Length];
for (var i = 0; i < Entries.Length; ++i)
{
var version = reader.ReadEncodedInt();
switch (version)
{
case 0:
{
RequireExceptional = reader.ReadBool();
DeedType = (BODType)reader.ReadEncodedInt();
Material = (BulkMaterialType)reader.ReadEncodedInt();
AmountMax = reader.ReadEncodedInt();
Price = reader.ReadEncodedInt();
Entries = new BOBLargeSubEntry[reader.ReadEncodedInt()];
for (var i = 0; i < Entries.Length; ++i)
{
Entries[i] = new BOBLargeSubEntry(reader);
}
break;
}
}
entries[i] = new LargeBulkEntry(
null,
new SmallBulkEntry(Entries[i].ItemType, Entries[i].Number, Entries[i].Graphic)
)
{ Amount = Entries[i].AmountCur };
}
public BOBLargeSubEntry[] Entries { get; }
return entries;
}
public bool RequireExceptional { get; }
private void Deserialize(IGenericReader reader, int version)
{
RequireExceptional = reader.ReadBool();
public BODType DeedType { get; }
DeedType = (BODType)reader.ReadEncodedInt();
Material = (BulkMaterialType)reader.ReadEncodedInt();
AmountMax = reader.ReadEncodedInt();
Price = reader.ReadEncodedInt();
public BulkMaterialType Material { get; }
_entries = new BOBLargeSubEntry[reader.ReadEncodedInt()];
public int AmountMax { get; }
public int Price { get; set; }
public Item Reconstruct()
for (var i = 0; i < Entries.Length; ++i)
{
LargeBOD bod = DeedType switch
{
BODType.Smith => new LargeSmithBOD(AmountMax, RequireExceptional, Material, ReconstructEntries()),
BODType.Tailor => new LargeTailorBOD(AmountMax, RequireExceptional, Material, ReconstructEntries()),
_ => null
};
for (var i = 0; i < bod?.Entries.Length; ++i)
{
bod.Entries[i].Owner = bod;
}
return bod;
}
private LargeBulkEntry[] ReconstructEntries()
{
var entries = new LargeBulkEntry[Entries.Length];
for (var i = 0; i < Entries.Length; ++i)
{
entries[i] = new LargeBulkEntry(
null,
new SmallBulkEntry(Entries[i].ItemType, Entries[i].Number, Entries[i].Graphic)
)
{ Amount = Entries[i].AmountCur };
}
return entries;
}
public void Serialize(IGenericWriter writer)
{
writer.WriteEncodedInt(0); // version
writer.Write(RequireExceptional);
writer.WriteEncodedInt((int)DeedType);
writer.WriteEncodedInt((int)Material);
writer.WriteEncodedInt(AmountMax);
writer.WriteEncodedInt(Price);
writer.WriteEncodedInt(Entries.Length);
for (var i = 0; i < Entries.Length; ++i)
{
Entries[i].Serialize(writer);
}
_entries[i] = new BOBLargeSubEntry();
_entries[i].Deserialize(reader);
}
}
}

View file

@ -1,58 +1,35 @@
using System;
using ModernUO.Serialization;
namespace Server.Engines.BulkOrders
namespace Server.Engines.BulkOrders;
[SerializationGenerator(0)]
public partial class BOBLargeSubEntry
{
public class BOBLargeSubEntry
[SerializableField(0, setter: "private")]
private Type _itemType;
[EncodedInt]
[SerializableField(1, setter: "private")]
private int _amountCur;
[EncodedInt]
[SerializableField(2, setter: "private")]
private int _number;
[EncodedInt]
[SerializableField(3, setter: "private")]
private int _graphic;
public BOBLargeSubEntry()
{
public BOBLargeSubEntry(LargeBulkEntry lbe)
{
ItemType = lbe.Details.Type;
AmountCur = lbe.Amount;
Number = lbe.Details.Number;
Graphic = lbe.Details.Graphic;
}
}
public BOBLargeSubEntry(IGenericReader reader)
{
var version = reader.ReadEncodedInt();
switch (version)
{
case 0:
{
var type = reader.ReadString();
if (type != null)
{
ItemType = AssemblyHandler.FindTypeByFullName(type);
}
AmountCur = reader.ReadEncodedInt();
Number = reader.ReadEncodedInt();
Graphic = reader.ReadEncodedInt();
break;
}
}
}
public Type ItemType { get; }
public int AmountCur { get; }
public int Number { get; }
public int Graphic { get; }
public void Serialize(IGenericWriter writer)
{
writer.WriteEncodedInt(0); // version
writer.Write(ItemType?.FullName);
writer.WriteEncodedInt(AmountCur);
writer.WriteEncodedInt(Number);
writer.WriteEncodedInt(Graphic);
}
public BOBLargeSubEntry(LargeBulkEntry lbe)
{
_itemType = lbe.Details.Type;
_amountCur = lbe.Amount;
_number = lbe.Details.Number;
_graphic = lbe.Details.Graphic;
}
}

View file

@ -1,110 +1,76 @@
using System;
using ModernUO.Serialization;
namespace Server.Engines.BulkOrders
namespace Server.Engines.BulkOrders;
[SerializationGenerator(1)]
public partial class BOBSmallEntry : BaseBOBEntry
{
public class BOBSmallEntry : IBOBEntry
[SerializableField(0, setter: "private")]
private Type _itemType;
[EncodedInt]
[SerializableField(1, setter: "private")]
private int _amountCur;
[EncodedInt]
[SerializableField(2, setter: "private")]
private int _number;
[EncodedInt]
[SerializableField(3, setter: "private")]
private int _graphic;
public BOBSmallEntry(SmallBOD bod)
{
public BOBSmallEntry(SmallBOD bod)
_itemType = bod.Type;
RequireExceptional = bod.RequireExceptional;
if (bod is SmallTailorBOD)
{
ItemType = bod.Type;
RequireExceptional = bod.RequireExceptional;
if (bod is SmallTailorBOD)
{
DeedType = BODType.Tailor;
}
else if (bod is SmallSmithBOD)
{
DeedType = BODType.Smith;
}
Material = bod.Material;
AmountCur = bod.AmountCur;
AmountMax = bod.AmountMax;
Number = bod.Number;
Graphic = bod.Graphic;
DeedType = BODType.Tailor;
}
else if (bod is SmallSmithBOD)
{
DeedType = BODType.Smith;
}
public BOBSmallEntry(IGenericReader reader)
Material = bod.Material;
_amountCur = bod.AmountCur;
AmountMax = bod.AmountMax;
_number = bod.Number;
_graphic = bod.Graphic;
}
public override Item Reconstruct()
{
SmallBOD bod = null;
if (DeedType == BODType.Smith)
{
var version = reader.ReadEncodedInt();
switch (version)
{
case 0:
{
var type = reader.ReadString();
if (type != null)
{
ItemType = AssemblyHandler.FindTypeByFullName(type);
}
RequireExceptional = reader.ReadBool();
DeedType = (BODType)reader.ReadEncodedInt();
Material = (BulkMaterialType)reader.ReadEncodedInt();
AmountCur = reader.ReadEncodedInt();
AmountMax = reader.ReadEncodedInt();
Number = reader.ReadEncodedInt();
Graphic = reader.ReadEncodedInt();
Price = reader.ReadEncodedInt();
break;
}
}
bod = new SmallSmithBOD(AmountCur, AmountMax, ItemType, Number, Graphic, RequireExceptional, Material);
}
else if (DeedType == BODType.Tailor)
{
bod = new SmallTailorBOD(AmountCur, AmountMax, ItemType, Number, Graphic, RequireExceptional, Material);
}
public Type ItemType { get; }
return bod;
}
public int AmountCur { get; }
private void Deserialize(IGenericReader reader, int version)
{
_itemType = reader.ReadType();
public int Number { get; }
RequireExceptional = reader.ReadBool();
public int Graphic { get; }
DeedType = (BODType)reader.ReadEncodedInt();
public bool RequireExceptional { get; }
public BODType DeedType { get; }
public BulkMaterialType Material { get; }
public int AmountMax { get; }
public int Price { get; set; }
public Item Reconstruct()
{
SmallBOD bod = null;
if (DeedType == BODType.Smith)
{
bod = new SmallSmithBOD(AmountCur, AmountMax, ItemType, Number, Graphic, RequireExceptional, Material);
}
else if (DeedType == BODType.Tailor)
{
bod = new SmallTailorBOD(AmountCur, AmountMax, ItemType, Number, Graphic, RequireExceptional, Material);
}
return bod;
}
public void Serialize(IGenericWriter writer)
{
writer.WriteEncodedInt(0); // version
writer.Write(ItemType?.FullName);
writer.Write(RequireExceptional);
writer.WriteEncodedInt((int)DeedType);
writer.WriteEncodedInt((int)Material);
writer.WriteEncodedInt(AmountCur);
writer.WriteEncodedInt(AmountMax);
writer.WriteEncodedInt(Number);
writer.WriteEncodedInt(Graphic);
writer.WriteEncodedInt(Price);
}
Material = (BulkMaterialType)reader.ReadEncodedInt();
AmountCur = reader.ReadEncodedInt();
AmountMax = reader.ReadEncodedInt();
Number = reader.ReadEncodedInt();
Graphic = reader.ReadEncodedInt();
Price = reader.ReadEncodedInt();
}
}

View file

@ -0,0 +1,60 @@
using System;
using System.IO;
using ModernUO.Serialization;
namespace Server.Engines.BulkOrders;
[SerializationGenerator(1)]
public abstract partial class BaseBOBEntry : IBOBEntry
{
[SerializableField(0, setter: "protected")]
private bool _requireExceptional;
[SerializableField(1, setter: "protected")]
private BODType _deedType;
[SerializableField(2, setter: "protected")]
private BulkMaterialType _material;
[SerializableField(3, setter: "protected")]
private int _amountMax;
[SerializableField(4)]
private int _price;
public DateTime Created { get; set; } = Core.Now;
public DateTime LastSerialized { get; set; } = Core.Now;
public Serial Serial { get; }
public bool Deleted { get; private set; }
public BaseBOBEntry()
{
Serial = BOBEntries.NewEntity;
BOBEntries.AddEntity(this);
}
public virtual void Delete()
{
Deleted = true;
BOBEntries.RemoveEntity(this);
}
public abstract Item Reconstruct();
private void Deserialize(IGenericReader reader, int version)
{
if (version == 0)
{
// version 0 - This class didn't exist, so we are going to skip deserializing
// Seek back 1 byte because encoded int of 0 is 1 byte
reader.Seek(-1, SeekOrigin.Current);
}
else
{
throw new Exception("Unknown deserialization error in presource generated BOB Entries");
}
}
}

View file

@ -244,11 +244,20 @@ namespace Server.Engines.BulkOrders
switch (v)
{
case 0:
Entries.Add(new BOBLargeEntry(reader));
break;
{
var largeEntry = new BOBLargeEntry(BOBEntries.NewEntity);
largeEntry.Deserialize(reader);
Entries.Add(largeEntry);
break;
}
case 1:
Entries.Add(new BOBSmallEntry(reader));
break;
{
var smallEntry = new BOBSmallEntry(BOBEntries.NewEntity);
smallEntry.Deserialize(reader);
Entries.Add(smallEntry);
break;
}
}
}

View file

@ -1,6 +1,6 @@
namespace Server.Engines.BulkOrders
{
public interface IBOBEntry
public interface IBOBEntry : ISerializable
{
bool RequireExceptional { get; }
BODType DeedType { get; }

View file

@ -0,0 +1,16 @@
{
"version": 1,
"type": "Server.Engines.BulkOrders.BOBLargeEntry",
"properties": [
{
"name": "Entries",
"type": "Server.Engines.BulkOrders.BOBLargeSubEntry[]",
"rule": "ArrayMigrationRule",
"ruleArguments": [
"Server.Engines.BulkOrders.BOBLargeSubEntry",
"RawSerializableMigrationRule",
""
]
}
]
}

View file

@ -0,0 +1,35 @@
{
"version": 0,
"type": "Server.Engines.BulkOrders.BOBLargeSubEntry",
"properties": [
{
"name": "ItemType",
"type": "System.Type",
"rule": "PrimitiveTypeMigrationRule"
},
{
"name": "AmountCur",
"type": "int",
"rule": "PrimitiveTypeMigrationRule",
"ruleArguments": [
"EncodedInt"
]
},
{
"name": "Number",
"type": "int",
"rule": "PrimitiveTypeMigrationRule",
"ruleArguments": [
"EncodedInt"
]
},
{
"name": "Graphic",
"type": "int",
"rule": "PrimitiveTypeMigrationRule",
"ruleArguments": [
"EncodedInt"
]
}
]
}

View file

@ -0,0 +1,35 @@
{
"version": 1,
"type": "Server.Engines.BulkOrders.BOBSmallEntry",
"properties": [
{
"name": "ItemType",
"type": "System.Type",
"rule": "PrimitiveTypeMigrationRule"
},
{
"name": "AmountCur",
"type": "int",
"rule": "PrimitiveTypeMigrationRule",
"ruleArguments": [
"EncodedInt"
]
},
{
"name": "Number",
"type": "int",
"rule": "PrimitiveTypeMigrationRule",
"ruleArguments": [
"EncodedInt"
]
},
{
"name": "Graphic",
"type": "int",
"rule": "PrimitiveTypeMigrationRule",
"ruleArguments": [
"EncodedInt"
]
}
]
}

View file

@ -0,0 +1,40 @@
{
"version": 1,
"type": "Server.Engines.BulkOrders.BaseBOBEntry",
"properties": [
{
"name": "RequireExceptional",
"type": "bool",
"rule": "PrimitiveTypeMigrationRule",
"ruleArguments": [
""
]
},
{
"name": "DeedType",
"type": "Server.Engines.BulkOrders.BODType",
"rule": "EnumMigrationRule"
},
{
"name": "Material",
"type": "Server.Engines.BulkOrders.BulkMaterialType",
"rule": "EnumMigrationRule"
},
{
"name": "AmountMax",
"type": "int",
"rule": "PrimitiveTypeMigrationRule",
"ruleArguments": [
""
]
},
{
"name": "Price",
"type": "int",
"rule": "PrimitiveTypeMigrationRule",
"ruleArguments": [
""
]
}
]
}

View file

@ -136,7 +136,7 @@ public abstract partial class BaseHealer : BaseVendor
private void Deserialize(IGenericReader reader, int version)
{
// NOTE: This is to fix a previous RunUO serialiation issue with this class:
// NOTE: This is to fix a previous RunUO serialization issue with this class:
// This would be a breaking change if there is a derived class that is version 2 or higher
// If that is the case, change the SerializationGenerator to a version higher than that before merging this change
reader.Seek(-4, SeekOrigin.Current);