diff --git a/Sia.Examples/Example13_Addon.cs b/Sia.Examples/Example13_Addon.cs new file mode 100644 index 0000000..2bc4382 --- /dev/null +++ b/Sia.Examples/Example13_Addon.cs @@ -0,0 +1,22 @@ +namespace Sia_Examples; + +using Sia; + +public static partial class Example13_Addon +{ + public interface ITestAddon : IAddon {} + public class Addon1 : ITestAddon {} + public class Addon2 : ITestAddon {} + + public static void Run(World world) + { + var a1 = world.AcquireAddon(); + var a2 = world.GetAddon(); + world.AddAddon(); + Console.WriteLine("Found addon by interface: " + (a1 == a2)); + + foreach (var addon in world.GetAddons()) { + Console.WriteLine(addon.GetType()); + } + } +} \ No newline at end of file diff --git a/Sia.Examples/Program.cs b/Sia.Examples/Program.cs index f10737d..669997a 100644 --- a/Sia.Examples/Program.cs +++ b/Sia.Examples/Program.cs @@ -21,4 +21,5 @@ void Invoke(Action action) Invoke(Example8_SIMD.Run); Invoke(Example10_DuplicateSystem.Run); Invoke(Example11_RPG.Run); -Invoke(Example12_DynEntityRef.Run); \ No newline at end of file +Invoke(Example12_DynEntityRef.Run); +Invoke(Example13_Addon.Run); \ No newline at end of file diff --git a/Sia/Systems/AddonSystemBase.cs b/Sia/Systems/AddonSystemBase.cs index b6b85e3..9f0b0d0 100644 --- a/Sia/Systems/AddonSystemBase.cs +++ b/Sia/Systems/AddonSystemBase.cs @@ -16,10 +16,11 @@ public AddonSystemBase( } protected TAddon AddAddon(World world) - where TAddon : IAddon, new() + where TAddon : class, IAddon, new() { - _addonRemovers.TryAdd(typeof(TAddon), static world => world.RemoveAddon()); - return world.AcquireAddon(); + _addonRemovers.TryAdd(typeof(TAddon), + static world => world.RemoveAddon()); + return world.AddAddon(); } public override void Uninitialize(World world, Scheduler scheduler) diff --git a/Sia/Worlds/World.cs b/Sia/Worlds/World.cs index 2889f59..99e8216 100644 --- a/Sia/Worlds/World.cs +++ b/Sia/Worlds/World.cs @@ -165,8 +165,17 @@ private readonly record struct SimpleIterationData( public IReadOnlyDictionary Queries => _queries; public IEnumerable EntityHosts => _hosts.Values; - public IEnumerable Addons => - _addons[.._addonCount].Where(addon => addon != null)!; + public IEnumerable Addons { + get { + for (int i = 0; i < _addonCount;) { + var addon = _addons[i]; + if (addon != null) { + i++; + yield return addon; + } + } + } + } private readonly Dictionary _queries = []; private readonly SparseSet _hosts = new(256, 256); @@ -470,24 +479,14 @@ public void Modify( public WorldCommandBuffer CreateCommandBuffer() => new(this); - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private TAddon CreateAddon() - where TAddon : IAddon, new() - { - var addon = new TAddon(); - addon.OnInitialize(this); - _addonCount++; - return addon; - } [MethodImpl(MethodImplOptions.AggressiveInlining)] public TAddon AcquireAddon() - where TAddon : IAddon, new() + where TAddon : class, IAddon, new() { ref var addon = ref _addons[WorldAddonIndexer.Index]; if (addon != null) { - return (TAddon)addon!; + return Unsafe.As(addon); } var newAddon = CreateAddon(); addon = newAddon; @@ -496,7 +495,7 @@ public TAddon AcquireAddon() [MethodImpl(MethodImplOptions.AggressiveInlining)] public TAddon AddAddon() - where TAddon : IAddon, new() + where TAddon : class, IAddon, new() { ref var addon = ref _addons[WorldAddonIndexer.Index]; if (addon != null) { @@ -507,45 +506,94 @@ public TAddon AddAddon() return newAddon; } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private TAddon CreateAddon() + where TAddon : class, IAddon, new() + { + var addon = new TAddon(); + addon.OnInitialize(this); + _addonCount++; + return addon; + } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool RemoveAddon() - where TAddon : IAddon + where TAddon : class, IAddon { ref var addon = ref _addons[WorldAddonIndexer.Index]; - if (addon != null) { - addon.OnUninitialize(this); - addon = null; - _addonCount--; - return true; + if (addon == null) { + return false; } - return false; + addon.OnUninitialize(this); + addon = null; + _addonCount--; + return true; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public TAddon GetAddon() - where TAddon : IAddon + where TAddon : class, IAddon { - ref var addon = ref _addons[WorldAddonIndexer.Index]; - if (addon == null) { - throw new KeyNotFoundException("Addon not found: " + typeof(TAddon)); + var addon = _addons[WorldAddonIndexer.Index]; + if (addon != null) { + return Unsafe.As(addon); } - return (TAddon)addon!; + + for (int i = 0, found = 0; found < _addonCount; ++i) { + addon = _addons[i]; + if (addon != null) { + if (addon is TAddon converted) { + return converted; + } + found++; + } + } + + throw new KeyNotFoundException("Addon not found: " + typeof(TAddon)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool ContainsAddon() - where TAddon : IAddon - => _addons[WorldAddonIndexer.Index] != null; + public IEnumerable GetAddons() + where TAddon : class, IAddon + { + var addon = _addons[WorldAddonIndexer.Index]; + if (addon != null) { + yield return Unsafe.As(addon); + } + + for (int i = 0, found = 0; found < _addonCount; ++i) { + addon = _addons[i]; + if (addon != null) { + if (addon is TAddon converted) { + yield return converted; + } + found++; + } + } + } [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool TryGetAddon([MaybeNullWhen(false)] out TAddon addon) - where TAddon : IAddon + where TAddon : class, IAddon { - ref var rawAddon = ref _addons[WorldAddonIndexer.Index]; + var rawAddon = _addons[WorldAddonIndexer.Index]; + if (rawAddon != null) { - addon = (TAddon)rawAddon; + addon = Unsafe.As(rawAddon); return true; } + + for (int i = 0, found = 0; found < _addonCount; ++i) { + rawAddon = _addons[i]; + if (rawAddon != null) { + if (rawAddon is TAddon converted) { + addon = converted; + return true; + } + found++; + } + } + addon = default; return false; }