commit 50da51bd7f1553ff78f16471e2d486083f96834d Author: cneicy Date: Wed Aug 26 02:50:25 2026 +0800 chore: initialize standalone UPM package diff --git a/.gitea/workflows/publish.yml b/.gitea/workflows/publish.yml new file mode 100644 index 0000000..032a6be --- /dev/null +++ b/.gitea/workflows/publish.yml @@ -0,0 +1,49 @@ +name: Publish UPM package + +on: + push: + tags: + - 'v*' + workflow_dispatch: + +jobs: + publish: + runs-on: ubuntu-latest + permissions: + contents: read + packages: write + env: + NODE_AUTH_TOKEN: ${{ secrets.SHRINKSDK_PACKAGE_TOKEN }} + steps: + - name: Fetch tagged revision + shell: bash + run: | + set -eu + ref="${{ gitea.sha }}" + test -n "$ref" + git init . + git remote add origin "https://git.crash.work/ShrinkSDK/ShrinkEventBus.Entities.git" + git fetch --depth=1 origin "$ref" + git checkout --detach FETCH_HEAD + + - name: Validate immutable release version + shell: bash + run: | + set -eu + tag="$(git describe --exact-match --tags HEAD)" + version="$(node -p "require('./package.json').version")" + test "$tag" = "v$version" + npm pack --dry-run + + - name: Publish to ShrinkSDK registry + shell: bash + run: | + set -eu + : "${NODE_AUTH_TOKEN:?SHRINKSDK_PACKAGE_TOKEN is required}" + npmrc="$HOME/.npmrc" + cleanup() { rm -f "$npmrc"; } + trap cleanup EXIT + printf '%s\n' \ + 'registry=https://git.crash.work/api/packages/ShrinkSDK/npm/' \ + '//git.crash.work/api/packages/ShrinkSDK/npm/:_authToken=${NODE_AUTH_TOKEN}' > "$npmrc" + npm publish --registry=https://git.crash.work/api/packages/ShrinkSDK/npm/ \ No newline at end of file diff --git a/.gitea/workflows/unity-verify.yml b/.gitea/workflows/unity-verify.yml new file mode 100644 index 0000000..c3293ff --- /dev/null +++ b/.gitea/workflows/unity-verify.yml @@ -0,0 +1,39 @@ +name: Verify standalone Unity package + +on: + workflow_dispatch: + +jobs: + editmode: + runs-on: unity-2022.3.62f3 + container: + image: docker.1panel.live/unityci/editor:ubuntu-2022.3.62f3-windows-mono-3 + volumes: + - /www/dk_project/bt-recovery/gitea/runner/seedskey-unity-license:/root/.local/share/unity3d/Unity + - /www/dk_project/bt-recovery/gitea/runner/seedskey-unity-entitlements:/root/.config/unity3d/Unity/licenses + steps: + - name: Fetch selected revision + shell: bash + run: | + set -eu + ref="${{ gitea.sha }}" + git init . + git remote add origin "https://git.crash.work/ShrinkSDK/ShrinkEventBus.Entities.git" + git fetch --depth=1 origin "$ref" + git checkout --detach FETCH_HEAD + + - name: Run package EditMode tests + shell: bash + run: | + set -eu + unity_bin="$(command -v unity-editor || command -v unity || command -v Unity || true)" + test -n "$unity_bin" + "$unity_bin" \ + -batchmode \ + -nographics \ + -quit \ + -projectPath "$PWD/Development~/UnityProject" \ + -runTests \ + -testPlatform EditMode \ + -testResults "$PWD/TestResults/editmode.xml" \ + -logFile "$PWD/TestResults/unity.log" \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..246935d --- /dev/null +++ b/.gitignore @@ -0,0 +1,10 @@ +/Development~/UnityProject/[Ll]ibrary/ +/Development~/UnityProject/[Tt]emp/ +/Development~/UnityProject/[Oo]bj/ +/Development~/UnityProject/[Ll]ogs/ +/Development~/UnityProject/[Uu]ser[Ss]ettings/ +/Development~/UnityProject/TestResults/ +/Tools~/**/[Bb]in/ +/Tools~/**/[Oo]bj/ +*.user +*.DotSettings.user diff --git a/.npmignore b/.npmignore new file mode 100644 index 0000000..700f03d --- /dev/null +++ b/.npmignore @@ -0,0 +1,8 @@ +.git/ +.gitea/ +Development~/ +Tools~/ +*.csproj +*.sln +*.user +*.DotSettings.user diff --git a/Development~/UnityProject/.gitignore b/Development~/UnityProject/.gitignore new file mode 100644 index 0000000..aa2eb00 --- /dev/null +++ b/Development~/UnityProject/.gitignore @@ -0,0 +1,6 @@ +[Ll]ibrary/ +[Tt]emp/ +[Oo]bj/ +[Ll]ogs/ +[Uu]ser[Ss]ettings/ +TestResults/ \ No newline at end of file diff --git a/Development~/UnityProject/Assets/.gitkeep b/Development~/UnityProject/Assets/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/Development~/UnityProject/Packages/manifest.json b/Development~/UnityProject/Packages/manifest.json new file mode 100644 index 0000000..7d7fff8 --- /dev/null +++ b/Development~/UnityProject/Packages/manifest.json @@ -0,0 +1,15 @@ +{ + "scopedRegistries": [ + { + "name": "ShrinkSDK", + "url": "https://git.crash.work/api/packages/ShrinkSDK/npm/", + "scopes": [ + "com.cneicy" + ] + } + ], + "dependencies": { + "com.unity.test-framework": "1.1.33", + "com.cneicy.shrink-eventbus-entities": "file:../../.." + } +} diff --git a/Development~/UnityProject/ProjectSettings/ProjectVersion.txt b/Development~/UnityProject/ProjectSettings/ProjectVersion.txt new file mode 100644 index 0000000..587f809 --- /dev/null +++ b/Development~/UnityProject/ProjectSettings/ProjectVersion.txt @@ -0,0 +1,2 @@ +m_EditorVersion: 2022.3.62f3 +m_EditorVersionWithRevision: 2022.3.62f3 (96770f904ca7) diff --git a/README.md b/README.md new file mode 100644 index 0000000..f652cd7 --- /dev/null +++ b/README.md @@ -0,0 +1,14 @@ +# ShrinkEventBus Entities + +`com.cneicy.shrink-eventbus-entities` 是可选 ECS/Burst 适配包。它不创建第二套事件总线,而是让 Burst Job 把 `unmanaged IShrinkEvent` 写入 `NativeQueue`,随后由主线程或 ECS playback system 发布到指定的 `IShrinkEventBus`。 + +```csharp +using var queue = new ShrinkEcsEventQueue(); +var writer = queue.Writer; + +// Burst Job 中:writer.Post(in eventData); +// Playback 阶段: +queue.Playback(worldBus); +``` + +限制:Burst 端只负责事实事件生产,不能直接执行托管 handler、UniTask、取消或结果裁决。 diff --git a/README.md.meta b/README.md.meta new file mode 100644 index 0000000..534a178 --- /dev/null +++ b/README.md.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 02173172caac46a6bb3e586a95c6f8e1 +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime.meta b/Runtime.meta new file mode 100644 index 0000000..ac1547d --- /dev/null +++ b/Runtime.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 3c58d5bbaaf44a3dba31fe63ab32fd22 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/ShrinkEcsEventQueue.cs b/Runtime/ShrinkEcsEventQueue.cs new file mode 100644 index 0000000..f565932 --- /dev/null +++ b/Runtime/ShrinkEcsEventQueue.cs @@ -0,0 +1,53 @@ +#nullable enable + +using System; +using ShrinkEventBus; +using Unity.Collections; + +namespace ShrinkEventBus.Entities +{ + /// Burst-safe producer queue; playback enters the regular Bus instance. + public sealed class ShrinkEcsEventQueue : IDisposable where TEvent : unmanaged, IShrinkEvent + { + private NativeQueue _queue; + + public ShrinkEcsEventQueue(Allocator allocator = Allocator.Persistent) + { + _queue = new NativeQueue(allocator); + Writer = new ShrinkEcsEventWriter(_queue.AsParallelWriter()); + } + + public ShrinkEcsEventWriter 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 where TEvent : unmanaged, IShrinkEvent + { + private readonly NativeQueue.ParallelWriter _writer; + + internal ShrinkEcsEventWriter(NativeQueue.ParallelWriter writer) + { + _writer = writer; + } + + public void Post(in TEvent eventData) => _writer.Enqueue(eventData); + } +} diff --git a/Runtime/ShrinkEcsEventQueue.cs.meta b/Runtime/ShrinkEcsEventQueue.cs.meta new file mode 100644 index 0000000..c9b1378 --- /dev/null +++ b/Runtime/ShrinkEcsEventQueue.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 05a2db7ffefb4841bdcd63d8fd3ac6fe +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/ShrinkEventBus.Entities.Runtime.asmdef b/Runtime/ShrinkEventBus.Entities.Runtime.asmdef new file mode 100644 index 0000000..803d21d --- /dev/null +++ b/Runtime/ShrinkEventBus.Entities.Runtime.asmdef @@ -0,0 +1,13 @@ +{ + "name": "ShrinkEventBus.Entities.Runtime", + "rootNamespace": "ShrinkEventBus.Entities", + "references": [ + "ShrinkEventBus.Runtime", + "Unity.Collections", + "Unity.Entities" + ], + "includePlatforms": [], + "excludePlatforms": [], + "allowUnsafeCode": true, + "autoReferenced": false +} diff --git a/Runtime/ShrinkEventBus.Entities.Runtime.asmdef.meta b/Runtime/ShrinkEventBus.Entities.Runtime.asmdef.meta new file mode 100644 index 0000000..4b345dd --- /dev/null +++ b/Runtime/ShrinkEventBus.Entities.Runtime.asmdef.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 9e31f017584a4a04992bb6fa7538cb2f +AssemblyDefinitionImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Tests.meta b/Tests.meta new file mode 100644 index 0000000..32d1019 --- /dev/null +++ b/Tests.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 28ac62d48f4f4ba296c67b9b5985d39c +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Tests/ShrinkEcsEventQueueTests.cs b/Tests/ShrinkEcsEventQueueTests.cs new file mode 100644 index 0000000..170f9f9 --- /dev/null +++ b/Tests/ShrinkEcsEventQueueTests.cs @@ -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(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 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(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(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); + } + } +} diff --git a/Tests/ShrinkEcsEventQueueTests.cs.meta b/Tests/ShrinkEcsEventQueueTests.cs.meta new file mode 100644 index 0000000..8db7711 --- /dev/null +++ b/Tests/ShrinkEcsEventQueueTests.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: d3be15e44ff9405e947ecaaac7905527 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Tests/ShrinkEventBus.Entities.Tests.asmdef b/Tests/ShrinkEventBus.Entities.Tests.asmdef new file mode 100644 index 0000000..98a9b4b --- /dev/null +++ b/Tests/ShrinkEventBus.Entities.Tests.asmdef @@ -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"] +} diff --git a/Tests/ShrinkEventBus.Entities.Tests.asmdef.meta b/Tests/ShrinkEventBus.Entities.Tests.asmdef.meta new file mode 100644 index 0000000..655caca --- /dev/null +++ b/Tests/ShrinkEventBus.Entities.Tests.asmdef.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 9ef47a51870047fda3659747535d685a +AssemblyDefinitionImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/package.json b/package.json new file mode 100644 index 0000000..a838775 --- /dev/null +++ b/package.json @@ -0,0 +1,22 @@ +{ + "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://git.crash.work/ShrinkSDK" + }, + "documentationUrl": "https://git.crash.work/ShrinkSDK/ShrinkEventBus.Entities" +} diff --git a/package.json.meta b/package.json.meta new file mode 100644 index 0000000..d52a2a4 --- /dev/null +++ b/package.json.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 908d154d9ac34f55817ba92f073b3aa8 +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: