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:
parent
666b83a3dd
commit
e0225c6e59
22 changed files with 666 additions and 311 deletions
|
|
@ -48,7 +48,7 @@ public static class EntityPersistence
|
|||
using var idx = new BinaryFileWriter(idxPath, false, types);
|
||||
using var bin = new BinaryFileWriter(binPath, true, types);
|
||||
|
||||
idx.Write(2); // Version
|
||||
idx.Write(3); // Version
|
||||
idx.Write(entities.Count);
|
||||
foreach (var e in entities.Values)
|
||||
{
|
||||
|
|
@ -58,7 +58,6 @@ public static class EntityPersistence
|
|||
idx.Write(t);
|
||||
idx.Write(e.Serial);
|
||||
idx.Write(e.Created.Ticks);
|
||||
idx.Write(e.LastSerialized.Ticks);
|
||||
idx.Write(start);
|
||||
|
||||
e.SerializeTo(bin);
|
||||
|
|
@ -152,7 +151,10 @@ public static class EntityPersistence
|
|||
|
||||
var serial = idxReader.ReadUInt32();
|
||||
var created = version == 0 ? now : new DateTime(idxReader.ReadInt64(), DateTimeKind.Utc);
|
||||
var lastSerialized = version == 0 ? DateTime.MinValue : new DateTime(idxReader.ReadInt64(), DateTimeKind.Utc);
|
||||
if (version is > 0 and < 3)
|
||||
{
|
||||
idxReader.ReadInt64(); // LastSerialized
|
||||
}
|
||||
var pos = idxReader.ReadInt64();
|
||||
var length = idxReader.ReadInt32();
|
||||
|
||||
|
|
@ -168,7 +170,6 @@ public static class EntityPersistence
|
|||
if (ctor.Invoke(ctorArgs) is T entity)
|
||||
{
|
||||
entity.Created = created;
|
||||
entity.LastSerialized = lastSerialized;
|
||||
entities.Add(new EntitySpan<T>(entity, pos, length));
|
||||
map[indexer] = entity;
|
||||
}
|
||||
|
|
@ -223,7 +224,7 @@ public static class EntityPersistence
|
|||
var buffer = GC.AllocateUninitializedArray<byte>(entry.Length);
|
||||
if (br == null)
|
||||
{
|
||||
br = new BufferReader(buffer, t.LastSerialized, serializedTypes);
|
||||
br = new BufferReader(buffer, serializedTypes);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ using System.Diagnostics;
|
|||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Threading;
|
||||
using Server.Guilds;
|
||||
using Server.Logging;
|
||||
|
|
@ -592,9 +593,10 @@ public static class World
|
|||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static IEntity FindEntity(Serial serial, bool returnDeleted = false) => FindEntity<IEntity>(serial, returnDeleted);
|
||||
public static IEntity FindEntity(Serial serial, bool returnDeleted = false, bool returnPending = true) =>
|
||||
FindEntity<IEntity>(serial, returnDeleted, returnPending);
|
||||
|
||||
public static T FindEntity<T>(Serial serial, bool returnDeleted = false) where T : class, IEntity
|
||||
public static T FindEntity<T>(Serial serial, bool returnDeleted = false, bool returnPending = true) where T : class, IEntity
|
||||
{
|
||||
switch (WorldState)
|
||||
{
|
||||
|
|
@ -603,43 +605,41 @@ public static class World
|
|||
case WorldState.Saving:
|
||||
case WorldState.WritingSave:
|
||||
{
|
||||
if (returnDeleted && _pendingDelete.TryGetValue(serial, out var entity))
|
||||
if (returnDeleted && returnPending && _pendingDelete.TryGetValue(serial, out var entity))
|
||||
{
|
||||
return entity as T;
|
||||
}
|
||||
|
||||
if (!_pendingAdd.TryGetValue(serial, out entity))
|
||||
if (!returnPending || !_pendingAdd.TryGetValue(serial, out entity))
|
||||
{
|
||||
if (serial.IsItem)
|
||||
{
|
||||
if (Items.TryGetValue(serial, out var item))
|
||||
{
|
||||
entity = item;
|
||||
return item as T;
|
||||
}
|
||||
}
|
||||
else // if (serial.IsMobile)
|
||||
{
|
||||
if (Mobiles.TryGetValue(serial, out var mob))
|
||||
{
|
||||
entity = mob;
|
||||
return mob as T;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return entity?.Deleted == false || returnDeleted ? entity as T : null;
|
||||
return null;
|
||||
}
|
||||
case WorldState.Running:
|
||||
{
|
||||
if (serial.IsItem)
|
||||
{
|
||||
Items.TryGetValue(serial, out var item);
|
||||
return item as T;
|
||||
return Items.TryGetValue(serial, out var item) ? item as T : null;
|
||||
}
|
||||
|
||||
if (serial.IsMobile)
|
||||
{
|
||||
Mobiles.TryGetValue(serial, out var mob);
|
||||
return mob as T;
|
||||
return Mobiles.TryGetValue(serial, out var mob) ? mob as T : null;
|
||||
}
|
||||
|
||||
return default;
|
||||
|
|
@ -684,11 +684,10 @@ public static class World
|
|||
{
|
||||
if (entity.Serial.IsItem)
|
||||
{
|
||||
if (!Items.TryAdd(entity.Serial, entity as Item))
|
||||
ref var item = ref CollectionsMarshal.GetValueRefOrAddDefault(Items, entity.Serial, out bool exists);
|
||||
if (exists)
|
||||
{
|
||||
var existing = Items[entity.Serial];
|
||||
|
||||
if (existing == entity)
|
||||
if (item == entity)
|
||||
{
|
||||
logger.Error(
|
||||
$"Attempted to add '{{Entity}}' ({{Serial}}) to World.Items but it already exists in the collection.{Environment.NewLine}{{StackTrace}}",
|
||||
|
|
@ -703,21 +702,24 @@ public static class World
|
|||
$"Attempted to add '{{Entity}}' ({{Serial}}) to World.Items but found '{{ExistingEntity}}' ({{ExistingSerial}}).{Environment.NewLine}{{StackTrace}}",
|
||||
entity.GetType().FullName,
|
||||
entity.Serial,
|
||||
existing.GetType().FullName,
|
||||
existing.Serial,
|
||||
item.GetType().FullName,
|
||||
item.Serial,
|
||||
new StackTrace()
|
||||
);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
item = entity as Item;
|
||||
}
|
||||
}
|
||||
|
||||
if (entity.Serial.IsMobile)
|
||||
{
|
||||
if (!Mobiles.TryAdd(entity.Serial, entity as Mobile))
|
||||
ref var mob = ref CollectionsMarshal.GetValueRefOrAddDefault(Mobiles, entity.Serial, out bool exists);
|
||||
if (exists)
|
||||
{
|
||||
var existing = Mobiles[entity.Serial];
|
||||
|
||||
if (existing == entity)
|
||||
if (mob == entity)
|
||||
{
|
||||
logger.Error(
|
||||
$"Attempted to add '{{Entity}}' ({{Serial}}) to World.Mobiles but it already exists in the collection.{Environment.NewLine}{{StackTrace}}",
|
||||
|
|
@ -732,30 +734,33 @@ public static class World
|
|||
$"Attempted to add '{{Entity}}' ({{Serial}}) to World.Mobiles but found '{{ExistingEntity}}' ({{ExistingSerial}}).{Environment.NewLine}{{StackTrace}}",
|
||||
entity.GetType().FullName,
|
||||
entity.Serial,
|
||||
existing.GetType().FullName,
|
||||
existing.Serial,
|
||||
mob.GetType().FullName,
|
||||
mob.Serial,
|
||||
new StackTrace()
|
||||
);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
mob = entity as Mobile;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void AddGuild(BaseGuild guild)
|
||||
public static void AddGuild(BaseGuild entity)
|
||||
{
|
||||
if (!Guilds.TryAdd(guild.Serial, guild))
|
||||
ref var guild = ref CollectionsMarshal.GetValueRefOrAddDefault(Guilds, entity.Serial, out bool exists);
|
||||
if (exists)
|
||||
{
|
||||
var existing = Guilds[guild.Serial];
|
||||
|
||||
if (existing == guild)
|
||||
if (guild == entity)
|
||||
{
|
||||
logger.Error(
|
||||
$"Attempted to add '{{Entity}}' ({{Serial}}) to World.Guilds but it already exists in the collection.{Environment.NewLine}{{StackTrace}}",
|
||||
guild.GetType().FullName,
|
||||
guild.Serial,
|
||||
entity.GetType().FullName,
|
||||
entity.Serial,
|
||||
new StackTrace()
|
||||
);
|
||||
}
|
||||
|
|
@ -763,14 +768,18 @@ public static class World
|
|||
{
|
||||
logger.Error(
|
||||
$"Attempted to add '{{Entity}}' ({{Serial}}) to World.Guilds but found '{{ExistingEntity}}' ({{ExistingSerial}}).{Environment.NewLine}{{StackTrace}}",
|
||||
entity.GetType().FullName,
|
||||
entity.Serial,
|
||||
guild.GetType().FullName,
|
||||
guild.Serial,
|
||||
existing.GetType().FullName,
|
||||
existing.Serial,
|
||||
new StackTrace()
|
||||
);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
guild = entity;
|
||||
}
|
||||
}
|
||||
|
||||
public static void RemoveEntity<T>(T entity) where T : class, IEntity
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue