diff --git a/Docs/VS_Scratch_Mapping.md b/Docs/VS_Scratch_Mapping.md index 55c419d..f73c0d4 100644 --- a/Docs/VS_Scratch_Mapping.md +++ b/Docs/VS_Scratch_Mapping.md @@ -12,7 +12,7 @@ Scratch ブロックと FUnity 独自 Visual Scripting Unit の対応関係で - Scratch 系のコルーチン Unit は Visual Scripting 標準の `flow.StartCoroutine` を用い、開始後に `ScratchUnitUtil.RegisterScratchFlow` で Flow を登録して停止ブロックと連動させる。 - Scratch のイベント Unit(緑の旗/キー押下/メッセージ受信/クローン開始など)は EventBus 登録時に Flow を新規作成し、`flow.StartCoroutine(trigger)` で起動してから `ScratchUnitUtil.RegisterScratchFlow(flow)` で ActorId/ThreadId を Flow.variables に保存する。Unity の Coroutine へは依存しない。 - `ScratchUnitUtil.RegisterScratchFlow` は Flow.variables に `FUNITY_SCRATCH_ACTOR_ID` / `FUNITY_SCRATCH_THREAD_ID` を格納し、`FUnityScriptThreadManager` の `(actorId, threadId)` テーブルへ登録する。停止系ユニットは Flow から逆引きした ActorId/ThreadId を使って停止対象を精密に選択する。 -- Scratch のイベントリスナー状態は GraphReference 単位で static Dictionary に保持し、EventBus.Register/Unregister ではジェネリック型引数を明示する。`GraphStack.SetElementData` や EventUnit.Data 拡張に依存しない。 +- Scratch のイベントリスナー状態は GraphReference と Unit(RuntimeHelpers.GetHashCode を使用)単位で static Dictionary に保持し、同一グラフ内に同種のイベントノードが複数あっても全て並行発火させる。EventBus.Register/Unregister ではジェネリック型引数を明示する。`GraphStack.SetElementData` や EventUnit.Data 拡張に依存しない。 - コルーチン専用ポート(例: Forever の `enter`)を叩く際は、Flow 上で `flow.StartCoroutine(trigger)` を使って実行し、コルーチンとしてのみ許可されているポートを正しく起動する。 - Presenter 取得は `ScratchUnitUtil.TryGetActorPresenter` を経由し、内部で `ResolveAdapter` と `ResolveActorPresenter` に委譲する共通ロジックを利用する。 diff --git a/Runtime/Integrations/VisualScripting/Units/ScratchUnits/CloneUnits.cs b/Runtime/Integrations/VisualScripting/Units/ScratchUnits/CloneUnits.cs index 5fc5ed2..dd5a92b 100644 --- a/Runtime/Integrations/VisualScripting/Units/ScratchUnits/CloneUnits.cs +++ b/Runtime/Integrations/VisualScripting/Units/ScratchUnits/CloneUnits.cs @@ -2,6 +2,7 @@ using System.Collections; using System; using System.Collections.Generic; +using System.Runtime.CompilerServices; using UnityEngine; using Unity.VisualScripting; using FUnity.Runtime.Integrations.VisualScripting; @@ -128,9 +129,12 @@ private IEnumerator Run(Flow flow) [TypeIcon(typeof(FUnityScratchUnitIcon))] public sealed class WhenIStartAsCloneUnit : EventUnit { - /// GraphReference ごとに登録したクローン開始イベントのハンドラ管理。 - private static readonly Dictionary> s_Handlers - = new Dictionary>(); + /// + /// GraphReference と Unit ごとに登録したクローン開始イベントのハンドラ管理。 + /// Unit 単位で登録することで、同一グラフ内に複数存在しても全て並行発火させます。 + /// + private static readonly Dictionary<(GraphReference reference, int unitId), Action> s_Handlers + = new Dictionary<(GraphReference reference, int unitId), Action>(); /// EventBus に登録するかどうか。 protected override bool register => true; @@ -179,8 +183,10 @@ public override void StartListening(GraphStack stack) } var reference = stack.ToReference(); + var unitId = RuntimeHelpers.GetHashCode(this); + var key = (reference, unitId); - if (s_Handlers.ContainsKey(reference)) + if (s_Handlers.ContainsKey(key)) { return; } @@ -191,7 +197,7 @@ public override void StartListening(GraphStack stack) if (hook.name != null && handler != null) { EventBus.Register(hook, handler); - s_Handlers[reference] = handler; + s_Handlers[key] = handler; } } @@ -207,8 +213,10 @@ public override void StopListening(GraphStack stack) } var reference = stack.ToReference(); + var unitId = RuntimeHelpers.GetHashCode(this); + var key = (reference, unitId); - if (!s_Handlers.TryGetValue(reference, out var handler) || handler == null) + if (!s_Handlers.TryGetValue(key, out var handler) || handler == null) { return; } @@ -219,7 +227,7 @@ public override void StopListening(GraphStack stack) EventBus.Unregister(hook, handler); } - s_Handlers.Remove(reference); + s_Handlers.Remove(key); } /// diff --git a/Runtime/Integrations/VisualScripting/Units/ScratchUnits/GreenFlagUnits.cs b/Runtime/Integrations/VisualScripting/Units/ScratchUnits/GreenFlagUnits.cs index 744772f..8d9f3e1 100644 --- a/Runtime/Integrations/VisualScripting/Units/ScratchUnits/GreenFlagUnits.cs +++ b/Runtime/Integrations/VisualScripting/Units/ScratchUnits/GreenFlagUnits.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Runtime.CompilerServices; using Unity.VisualScripting; using FUnity.Runtime.Core; using FUnity.Runtime.Integrations.VisualScripting; @@ -17,9 +18,12 @@ namespace FUnity.Runtime.Integrations.VisualScripting.Units.ScratchUnits [TypeIcon(typeof(FUnityScratchUnitIcon))] public sealed class WhenGreenFlagClickedUnit : EventUnit { - /// GraphReference ごとに EventBus へ登録したハンドラを保持します。 - private static readonly Dictionary> s_Handlers - = new Dictionary>(); + /// + /// GraphReference と Unit ごとに EventBus へ登録したハンドラを保持します。 + /// Unit 単位で管理することで、同一グラフ内に複数のイベントノードがあっても全て並行発火させます。 + /// + private static readonly Dictionary<(GraphReference reference, int unitId), Action> s_Handlers + = new Dictionary<(GraphReference reference, int unitId), Action>(); /// Visual Scripting 側でイベント登録を行うかどうかを制御します。 protected override bool register => true; @@ -81,8 +85,10 @@ public override void StartListening(GraphStack stack) } var reference = stack.ToReference(); + var unitId = RuntimeHelpers.GetHashCode(this); + var key = (reference, unitId); - if (s_Handlers.ContainsKey(reference)) + if (s_Handlers.ContainsKey(key)) { return; } @@ -93,7 +99,7 @@ public override void StartListening(GraphStack stack) if (hook.name != null && handler != null) { EventBus.Register(hook, handler); - s_Handlers[reference] = handler; + s_Handlers[key] = handler; } } @@ -109,8 +115,10 @@ public override void StopListening(GraphStack stack) } var reference = stack.ToReference(); + var unitId = RuntimeHelpers.GetHashCode(this); + var key = (reference, unitId); - if (!s_Handlers.TryGetValue(reference, out var handler) || handler == null) + if (!s_Handlers.TryGetValue(key, out var handler) || handler == null) { return; } @@ -121,7 +129,7 @@ public override void StopListening(GraphStack stack) EventBus.Unregister(hook, handler); } - s_Handlers.Remove(reference); + s_Handlers.Remove(key); } /// diff --git a/Runtime/Integrations/VisualScripting/Units/ScratchUnits/InputEventUnits.cs b/Runtime/Integrations/VisualScripting/Units/ScratchUnits/InputEventUnits.cs index 2148a22..3a18b6d 100644 --- a/Runtime/Integrations/VisualScripting/Units/ScratchUnits/InputEventUnits.cs +++ b/Runtime/Integrations/VisualScripting/Units/ScratchUnits/InputEventUnits.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Runtime.CompilerServices; using Unity.VisualScripting; using UnityEngine; using FUnity.Runtime.Integrations.VisualScripting; @@ -18,9 +19,12 @@ namespace FUnity.Runtime.Integrations.VisualScripting.Units.ScratchUnits [TypeIcon(typeof(FUnityScratchUnitIcon))] public sealed class OnKeyPressedUnit : EventUnit { - /// GraphReference 単位のキー入力リスナーを保持します。 - private static readonly Dictionary> s_Handlers - = new Dictionary>(); + /// + /// GraphReference と Unit ごとにキー入力リスナーを保持します。 + /// 同一グラフ内で複数のキーイベントがあっても並列に処理できるよう unitId を含めて管理します。 + /// + private static readonly Dictionary<(GraphReference reference, int unitId), Action> s_Handlers + = new Dictionary<(GraphReference reference, int unitId), Action>(); /// 現在ひとつでもキー入力リスナーが登録されているかを返します。 internal static bool HasAnyListeners => s_Handlers.Count > 0; @@ -121,15 +125,17 @@ public override void StartListening(GraphStack stack) } var reference = stack.ToReference(); + var unitId = RuntimeHelpers.GetHashCode(this); + var key = (reference, unitId); - if (s_Handlers.ContainsKey(reference)) + if (s_Handlers.ContainsKey(key)) { return; } Action handler = args => TriggerWithThreadRegistration(reference, args); - s_Handlers.Add(reference, handler); + s_Handlers.Add(key, handler); } /// @@ -145,7 +151,10 @@ public override void StopListening(GraphStack stack) var reference = stack.ToReference(); - s_Handlers.Remove(reference); + var unitId = RuntimeHelpers.GetHashCode(this); + var key = (reference, unitId); + + s_Handlers.Remove(key); } /// diff --git a/Runtime/Integrations/VisualScripting/Units/ScratchUnits/MessagingUnits.cs b/Runtime/Integrations/VisualScripting/Units/ScratchUnits/MessagingUnits.cs index d1adb41..925c81e 100644 --- a/Runtime/Integrations/VisualScripting/Units/ScratchUnits/MessagingUnits.cs +++ b/Runtime/Integrations/VisualScripting/Units/ScratchUnits/MessagingUnits.cs @@ -3,6 +3,7 @@ using System; using System.Collections; using System.Collections.Generic; +using System.Runtime.CompilerServices; using Unity.VisualScripting; using FUnity.Runtime.Integrations.VisualScripting; @@ -139,9 +140,12 @@ private IEnumerator OnEnterCoroutine(Flow flow) [TypeIcon(typeof(FUnityScratchUnitIcon))] public sealed class WhenIReceiveMessageUnit : EventUnit { - /// GraphReference ごとに登録済みのメッセージリスナーを保存します。 - private static readonly Dictionary> s_Handlers - = new Dictionary>(); + /// + /// GraphReference と Unit ごとに登録済みのメッセージリスナーを保存します。 + /// 同一グラフ内に複数の「メッセージを受け取ったとき」が存在しても全て発火させるため、unitId を含めて管理します。 + /// + private static readonly Dictionary<(GraphReference reference, int unitId), Action> s_Handlers + = new Dictionary<(GraphReference reference, int unitId), Action>(); /// EventUnit の自動登録を有効にします。 protected override bool register => true; @@ -219,8 +223,10 @@ public override void StartListening(GraphStack stack) } var reference = stack.ToReference(); + var unitId = RuntimeHelpers.GetHashCode(this); + var key = (reference, unitId); - if (s_Handlers.ContainsKey(reference)) + if (s_Handlers.ContainsKey(key)) { return; } @@ -231,7 +237,7 @@ public override void StartListening(GraphStack stack) if (hook.name != null && handler != null) { EventBus.Register(hook, handler); - s_Handlers[reference] = handler; + s_Handlers[key] = handler; } } @@ -247,8 +253,10 @@ public override void StopListening(GraphStack stack) } var reference = stack.ToReference(); + var unitId = RuntimeHelpers.GetHashCode(this); + var key = (reference, unitId); - if (!s_Handlers.TryGetValue(reference, out var handler) || handler == null) + if (!s_Handlers.TryGetValue(key, out var handler) || handler == null) { return; } @@ -259,7 +267,7 @@ public override void StopListening(GraphStack stack) EventBus.Unregister(hook, handler); } - s_Handlers.Remove(reference); + s_Handlers.Remove(key); } /// diff --git a/Runtime/Integrations/VisualScripting/Units/ScratchUnits/WhenThisSpriteClickedUnit.cs b/Runtime/Integrations/VisualScripting/Units/ScratchUnits/WhenThisSpriteClickedUnit.cs index e7e826f..670a712 100644 --- a/Runtime/Integrations/VisualScripting/Units/ScratchUnits/WhenThisSpriteClickedUnit.cs +++ b/Runtime/Integrations/VisualScripting/Units/ScratchUnits/WhenThisSpriteClickedUnit.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Runtime.CompilerServices; using Unity.VisualScripting; using FUnity.Runtime.Core; using FUnity.Runtime.Integrations.VisualScripting; @@ -22,13 +23,13 @@ namespace FUnity.Runtime.Integrations.VisualScripting.Units.ScratchUnits public sealed class WhenThisSpriteClickedUnit : EventUnit { /// - /// GraphReference ごとに EventBus へ登録したハンドラを保持します。 + /// GraphReference と Unit ごとに EventBus へ登録したハンドラを保持します。 /// - /// ・キー: GraphReference + /// ・キー: (GraphReference, unitId) /// ・値: EventBus から呼び出されるコールバック /// - private static readonly Dictionary> s_Handlers - = new Dictionary>(); + private static readonly Dictionary<(GraphReference reference, int unitId), Action> s_Handlers + = new Dictionary<(GraphReference reference, int unitId), Action>(); /// /// EventUnit による EventBus への自動登録を有効にします。 @@ -104,8 +105,10 @@ public override void StartListening(GraphStack stack) } var reference = stack.ToReference(); + var unitId = RuntimeHelpers.GetHashCode(this); + var key = (reference, unitId); - if (s_Handlers.ContainsKey(reference)) + if (s_Handlers.ContainsKey(key)) { return; } @@ -116,7 +119,7 @@ public override void StartListening(GraphStack stack) if (hook.name != null && handler != null) { EventBus.Register(hook, handler); - s_Handlers[reference] = handler; + s_Handlers[key] = handler; } } @@ -132,8 +135,10 @@ public override void StopListening(GraphStack stack) } var reference = stack.ToReference(); + var unitId = RuntimeHelpers.GetHashCode(this); + var key = (reference, unitId); - if (!s_Handlers.TryGetValue(reference, out var handler) || handler == null) + if (!s_Handlers.TryGetValue(key, out var handler) || handler == null) { return; } @@ -144,7 +149,7 @@ public override void StopListening(GraphStack stack) EventBus.Unregister(hook, handler); } - s_Handlers.Remove(reference); + s_Handlers.Remove(key); } ///