feat(eventbus): add platform runtimes and benchmarks
Add the Entities NativeQueue adapter, standalone .NET runtime and source generator, reproducible smoke coverage, and Unity benchmark assets for EventBus 2.0.
This commit is contained in:
@@ -0,0 +1,14 @@
|
||||
# ShrinkEventBus Entities
|
||||
|
||||
`com.cneicy.shrink-eventbus-entities` 是可选 ECS/Burst 适配包。它不创建第二套事件总线,而是让 Burst Job 把 `unmanaged IShrinkEvent` 写入 `NativeQueue<T>`,随后由主线程或 ECS playback system 发布到指定的 `IShrinkEventBus`。
|
||||
|
||||
```csharp
|
||||
using var queue = new ShrinkEcsEventQueue<MyEcsEvent>();
|
||||
var writer = queue.Writer;
|
||||
|
||||
// Burst Job 中:writer.Post(in eventData);
|
||||
// Playback 阶段:
|
||||
queue.Playback(worldBus);
|
||||
```
|
||||
|
||||
限制:Burst 端只负责事实事件生产,不能直接执行托管 handler、UniTask、取消或结果裁决。
|
||||
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 02173172caac46a6bb3e586a95c6f8e1
|
||||
TextScriptImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3c58d5bbaaf44a3dba31fe63ab32fd22
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,53 @@
|
||||
#nullable enable
|
||||
|
||||
using System;
|
||||
using ShrinkEventBus;
|
||||
using Unity.Collections;
|
||||
|
||||
namespace ShrinkEventBus.Entities
|
||||
{
|
||||
/// <summary>Burst-safe producer queue; playback enters the regular Bus instance.</summary>
|
||||
public sealed class ShrinkEcsEventQueue<TEvent> : IDisposable where TEvent : unmanaged, IShrinkEvent
|
||||
{
|
||||
private NativeQueue<TEvent> _queue;
|
||||
|
||||
public ShrinkEcsEventQueue(Allocator allocator = Allocator.Persistent)
|
||||
{
|
||||
_queue = new NativeQueue<TEvent>(allocator);
|
||||
Writer = new ShrinkEcsEventWriter<TEvent>(_queue.AsParallelWriter());
|
||||
}
|
||||
|
||||
public ShrinkEcsEventWriter<TEvent> Writer { get; }
|
||||
|
||||
public int Playback(IShrinkEventBus bus)
|
||||
{
|
||||
if (bus == null)
|
||||
throw new ArgumentNullException(nameof(bus));
|
||||
var count = 0;
|
||||
while (_queue.TryDequeue(out var eventData))
|
||||
{
|
||||
bus.Post(in eventData);
|
||||
count++;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (_queue.IsCreated)
|
||||
_queue.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
public readonly struct ShrinkEcsEventWriter<TEvent> where TEvent : unmanaged, IShrinkEvent
|
||||
{
|
||||
private readonly NativeQueue<TEvent>.ParallelWriter _writer;
|
||||
|
||||
internal ShrinkEcsEventWriter(NativeQueue<TEvent>.ParallelWriter writer)
|
||||
{
|
||||
_writer = writer;
|
||||
}
|
||||
|
||||
public void Post(in TEvent eventData) => _writer.Enqueue(eventData);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 05a2db7ffefb4841bdcd63d8fd3ac6fe
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"name": "ShrinkEventBus.Entities.Runtime",
|
||||
"rootNamespace": "ShrinkEventBus.Entities",
|
||||
"references": [
|
||||
"ShrinkEventBus.Runtime",
|
||||
"Unity.Collections",
|
||||
"Unity.Entities"
|
||||
],
|
||||
"includePlatforms": [],
|
||||
"excludePlatforms": [],
|
||||
"allowUnsafeCode": true,
|
||||
"autoReferenced": false
|
||||
}
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9e31f017584a4a04992bb6fa7538cb2f
|
||||
AssemblyDefinitionImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 28ac62d48f4f4ba296c67b9b5985d39c
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,76 @@
|
||||
#nullable enable
|
||||
|
||||
using System;
|
||||
using NUnit.Framework;
|
||||
using Unity.Burst;
|
||||
using Unity.Collections;
|
||||
using Unity.Jobs;
|
||||
|
||||
namespace ShrinkEventBus.Entities.Tests
|
||||
{
|
||||
internal struct EcsPingEvent : IShrinkEvent
|
||||
{
|
||||
public int Value;
|
||||
}
|
||||
|
||||
internal sealed class EcsPingSubscriber : IShrinkGeneratedSubscriber
|
||||
{
|
||||
public int Sum { get; private set; }
|
||||
|
||||
public IDisposable AttachGenerated(IShrinkBusResolver resolver, ShrinkBusKey? defaultBus = null)
|
||||
{
|
||||
return ShrinkGeneratedBinding.Subscribe<EcsPingEvent>(resolver, defaultBus,
|
||||
string.Empty, this, OnPing, ShrinkEventPriority.Normal, 0, false);
|
||||
}
|
||||
|
||||
private void OnPing(EcsPingEvent value) => Sum += value.Value;
|
||||
}
|
||||
|
||||
[BurstCompile]
|
||||
internal struct PostPingJob : IJob
|
||||
{
|
||||
public ShrinkEcsEventWriter<EcsPingEvent> Writer;
|
||||
|
||||
public void Execute()
|
||||
{
|
||||
Writer.Post(new EcsPingEvent { Value = 11 });
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class ShrinkEcsEventQueueTests
|
||||
{
|
||||
[Test]
|
||||
public void NativeWriterPlaybackUsesSameBusChannel()
|
||||
{
|
||||
using var host = new ShrinkEventBusHost();
|
||||
var bus = host.CreateBus(ShrinkBusKey.World("tests"), ShrinkBusOptions.Inline());
|
||||
var subscriber = new EcsPingSubscriber();
|
||||
using var binding = host.Attach(subscriber, ShrinkBusKey.World("tests"));
|
||||
using var queue = new ShrinkEcsEventQueue<EcsPingEvent>(Allocator.TempJob);
|
||||
|
||||
queue.Writer.Post(new EcsPingEvent { Value = 2 });
|
||||
queue.Writer.Post(new EcsPingEvent { Value = 5 });
|
||||
var played = queue.Playback(bus);
|
||||
|
||||
Assert.AreEqual(2, played);
|
||||
Assert.AreEqual(7, subscriber.Sum);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void BurstJobWritesThenPlaybackUsesManagedBus()
|
||||
{
|
||||
using var host = new ShrinkEventBusHost();
|
||||
var bus = host.CreateBus(ShrinkBusKey.World("burst-tests"), ShrinkBusOptions.Inline());
|
||||
var subscriber = new EcsPingSubscriber();
|
||||
using var binding = host.Attach(subscriber, ShrinkBusKey.World("burst-tests"));
|
||||
using var queue = new ShrinkEcsEventQueue<EcsPingEvent>(Allocator.TempJob);
|
||||
var job = new PostPingJob { Writer = queue.Writer };
|
||||
|
||||
job.Schedule().Complete();
|
||||
var played = queue.Playback(bus);
|
||||
|
||||
Assert.AreEqual(1, played);
|
||||
Assert.AreEqual(11, subscriber.Sum);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d3be15e44ff9405e947ecaaac7905527
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,20 @@
|
||||
{
|
||||
"name": "ShrinkEventBus.Entities.Tests",
|
||||
"rootNamespace": "ShrinkEventBus.Entities.Tests",
|
||||
"references": [
|
||||
"ShrinkEventBus.Entities.Runtime",
|
||||
"ShrinkEventBus.Runtime",
|
||||
"Unity.Burst",
|
||||
"Unity.Collections",
|
||||
"Unity.Jobs",
|
||||
"UniTask",
|
||||
"UnityEngine.TestRunner",
|
||||
"UnityEditor.TestRunner"
|
||||
],
|
||||
"includePlatforms": ["Editor"],
|
||||
"excludePlatforms": [],
|
||||
"allowUnsafeCode": false,
|
||||
"overrideReferences": false,
|
||||
"autoReferenced": false,
|
||||
"defineConstraints": ["UNITY_INCLUDE_TESTS"]
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9ef47a51870047fda3659747535d685a
|
||||
AssemblyDefinitionImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"name": "com.cneicy.shrink-eventbus-entities",
|
||||
"version": "0.1.0",
|
||||
"displayName": "ShrinkEventBus Entities",
|
||||
"description": "Burst-safe NativeQueue writer and playback adapter for ShrinkEventBus.",
|
||||
"unity": "2022.3",
|
||||
"dependencies": {
|
||||
"com.cneicy.shrink-eventbus": "2.0.0",
|
||||
"com.unity.entities": "1.0.11"
|
||||
},
|
||||
"keywords": ["eventbus", "entities", "burst", "ecs"],
|
||||
"author": {
|
||||
"name": "cneicy",
|
||||
"url": "https://github.com/cneicy"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 908d154d9ac34f55817ba92f073b3aa8
|
||||
TextScriptImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Reference in New Issue
Block a user