refactor: replace boxed component addition with typed delegate
This commit is contained in:
parent
96ba037432
commit
1da0ca30d3
|
|
@ -211,7 +211,8 @@ public class ComponentDiscoveryGenerator : IIncrementalGenerator
|
|||
sb.AppendLine($" typeName: \"{aqn}\",");
|
||||
sb.AppendLine($" type: typeof({fqn}),");
|
||||
sb.AppendLine($" serialize: obj => MessagePackSerializer.Serialize(({fqn})obj),");
|
||||
sb.AppendLine($" deserialize: data => MessagePackSerializer.Deserialize<{fqn}>(data)");
|
||||
sb.AppendLine($" deserializeAndAdd: (world, entity, data) =>");
|
||||
sb.AppendLine($" world.AddComponent(entity, MessagePackSerializer.Deserialize<{fqn}>(data))");
|
||||
sb.Append(" )");
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -23,19 +23,20 @@ public sealed class ComponentDescriptor
|
|||
public Func<object, byte[]> Serialize { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Deserializes a MessagePack byte array into a boxed component instance.
|
||||
/// Deserializes a MessagePack byte array and adds the component to the entity
|
||||
/// via the typed <see cref="World.AddComponent{T}"/> method. No reflection.
|
||||
/// </summary>
|
||||
public Func<byte[], object> Deserialize { get; }
|
||||
public Action<World, Entity, byte[]> DeserializeAndAdd { get; }
|
||||
|
||||
public ComponentDescriptor(
|
||||
string typeName,
|
||||
Type type,
|
||||
Func<object, byte[]> serialize,
|
||||
Func<byte[], object> deserialize)
|
||||
Action<World, Entity, byte[]> deserializeAndAdd)
|
||||
{
|
||||
TypeName = typeName;
|
||||
Type = type;
|
||||
Serialize = serialize;
|
||||
Deserialize = deserialize;
|
||||
DeserializeAndAdd = deserializeAndAdd;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,5 +1,4 @@
|
|||
using System.Diagnostics;
|
||||
using System.Reflection;
|
||||
using R3;
|
||||
|
||||
namespace OECS;
|
||||
|
|
@ -665,27 +664,6 @@ public class World : IDisposable
|
|||
/// </summary>
|
||||
internal ComponentStore Components => _components;
|
||||
|
||||
/// <summary>
|
||||
/// Adds a boxed component to an entity by its runtime type.
|
||||
/// Used by <see cref="WorldSerializer"/> during deserialization to
|
||||
/// invoke the typed <see cref="AddComponent{T}"/> without reflection.
|
||||
/// </summary>
|
||||
internal void AddComponentBoxed(Type componentType, Entity entity, object component)
|
||||
{
|
||||
// Use a cached delegate per type to avoid reflection on every call.
|
||||
if (!_addComponentDelegates.TryGetValue(componentType, out var del))
|
||||
{
|
||||
var method = typeof(World).GetMethod(nameof(AddComponent))!
|
||||
.MakeGenericMethod(componentType);
|
||||
del = (Action<World, Entity, object>)Delegate.CreateDelegate(
|
||||
typeof(Action<World, Entity, object>), method);
|
||||
_addComponentDelegates[componentType] = del;
|
||||
}
|
||||
del(this, entity, component);
|
||||
}
|
||||
|
||||
private readonly Dictionary<Type, Action<World, Entity, object>> _addComponentDelegates = new();
|
||||
|
||||
// ── Helpers ───────────────────────────────────────────────────────
|
||||
|
||||
private void ThrowIfNotAlive(Entity entity)
|
||||
|
|
|
|||
|
|
@ -93,12 +93,8 @@ public static class WorldSerializer
|
|||
$"Ensure the component type is used with the World " +
|
||||
$"API so the source generator can discover it.");
|
||||
|
||||
var component = desc.Deserialize(ce.Data)
|
||||
?? throw new InvalidOperationException(
|
||||
$"Failed to deserialize component of type '{ce.TypeName}'.");
|
||||
|
||||
// Use the generated typed delegate to add the component.
|
||||
world.AddComponentBoxed(desc.Type, entity, component);
|
||||
// Deserialize and add in one typed operation — no reflection.
|
||||
desc.DeserializeAndAdd(world, entity, ce.Data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue