From 0544a12822dcfae01d78b345692693666b593df0 Mon Sep 17 00:00:00 2001 From: Peng Xiao Date: Sat, 5 Sep 2026 13:53:34 +0800 Subject: [PATCH] fix(overlays): avoid version-specific scene handle access --- .../Game/OverlayPanels/OverlayPanelHost.cs | 10 +++--- .../Scenes/ActiveSceneNameCache.cs | 6 ++-- .../SceneRuntimeCompatibilityTests.cs | 34 +++++++++++++++++++ 3 files changed, 42 insertions(+), 8 deletions(-) create mode 100644 tests/RuntimeIntegration.Tests/SceneRuntimeCompatibilityTests.cs diff --git a/src/BazaarPlusPlus/Game/OverlayPanels/OverlayPanelHost.cs b/src/BazaarPlusPlus/Game/OverlayPanels/OverlayPanelHost.cs index fd23b690..48884bb0 100644 --- a/src/BazaarPlusPlus/Game/OverlayPanels/OverlayPanelHost.cs +++ b/src/BazaarPlusPlus/Game/OverlayPanels/OverlayPanelHost.cs @@ -15,7 +15,7 @@ internal sealed class OverlayPanelHost : MonoBehaviour private readonly OverlayLifecycleCore _core = new(); private readonly OverlayPanelHostLogState _logState = new(); private readonly List _registrations = new(); - private int _sceneTokenHandle; + private Scene _sceneTokenScene; private bool _sceneTokenLoaded; private string _sceneToken = string.Empty; @@ -128,18 +128,18 @@ private void Unregister(string panelId) private bool ReadIsInCombat() => _logState.ReadIsInCombat(static () => TheBazaar.Data.IsInCombat); - // name/path/buildIndex are fixed for a given scene handle, so the token string is rebuilt - // only when the active scene (or its loaded flag) actually changes. + // Compare Scene values, not Scene.handle: Unity 6 changed that getter's return type + // from int to SceneHandle. The equality operator's ABI is stable across both versions. private string GetSceneToken(Scene scene) { if ( _sceneToken.Length != 0 - && _sceneTokenHandle == scene.handle + && _sceneTokenScene == scene && _sceneTokenLoaded == scene.isLoaded ) return _sceneToken; - _sceneTokenHandle = scene.handle; + _sceneTokenScene = scene; _sceneTokenLoaded = scene.isLoaded; _sceneToken = $"{scene.name}|{scene.path}|{scene.buildIndex}|{scene.isLoaded}"; return _sceneToken; diff --git a/src/BazaarPlusPlus/GameInterop/Scenes/ActiveSceneNameCache.cs b/src/BazaarPlusPlus/GameInterop/Scenes/ActiveSceneNameCache.cs index 6b44a3f7..0643d15f 100644 --- a/src/BazaarPlusPlus/GameInterop/Scenes/ActiveSceneNameCache.cs +++ b/src/BazaarPlusPlus/GameInterop/Scenes/ActiveSceneNameCache.cs @@ -10,7 +10,7 @@ namespace BazaarPlusPlus.GameInterop.Scenes; /// internal static class ActiveSceneNameCache { - private static int _handle; + private static Scene _scene; private static bool _loaded; private static bool _hasName; private static string _name = string.Empty; @@ -20,10 +20,10 @@ internal static string Current get { var scene = SceneManager.GetActiveScene(); - if (_hasName && _handle == scene.handle && _loaded == scene.isLoaded) + if (_hasName && _scene == scene && _loaded == scene.isLoaded) return _name; - _handle = scene.handle; + _scene = scene; _loaded = scene.isLoaded; _name = scene.name; _hasName = true; diff --git a/tests/RuntimeIntegration.Tests/SceneRuntimeCompatibilityTests.cs b/tests/RuntimeIntegration.Tests/SceneRuntimeCompatibilityTests.cs new file mode 100644 index 00000000..16005fd5 --- /dev/null +++ b/tests/RuntimeIntegration.Tests/SceneRuntimeCompatibilityTests.cs @@ -0,0 +1,34 @@ +using System.Reflection.Metadata; +using System.Reflection.PortableExecutable; +using Xunit; + +namespace RuntimeIntegration.Tests; + +public sealed class SceneRuntimeCompatibilityTests +{ + [Fact] + public void Compiled_mod_does_not_bind_to_the_version_specific_scene_handle_getter() + { + using var stream = File.OpenRead( + Path.Combine(AppContext.BaseDirectory, "BazaarPlusPlus.dll") + ); + using var pe = new PEReader(stream); + var metadata = pe.GetMetadataReader(); + var sceneMembers = new List(); + foreach (var handle in metadata.MemberReferences) + { + var member = metadata.GetMemberReference(handle); + if (member.Parent.Kind != HandleKind.TypeReference) + continue; + var type = metadata.GetTypeReference((TypeReferenceHandle)member.Parent); + if ( + metadata.GetString(type.Namespace) == "UnityEngine.SceneManagement" + && metadata.GetString(type.Name) == "Scene" + ) + sceneMembers.Add(metadata.GetString(member.Name)); + } + + Assert.DoesNotContain("get_handle", sceneMembers); + Assert.Contains("op_Equality", sceneMembers); + } +}