From b306907ea2fca018646e912c16578bbadb531c5b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=A2=81=E9=93=96?= <> Date: Tue, 20 Jan 2026 17:45:41 +0800 Subject: [PATCH 01/33] =?UTF-8?q?=E7=A7=BB=E9=99=A4=20multi-pass=20?= =?UTF-8?q?=E5=88=86=E5=8F=91=E5=B9=B6=E6=8E=A5=E5=85=A5=20Unity=20?= =?UTF-8?q?=E6=80=A7=E8=83=BD=E6=B5=8B=E8=AF=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 12 +- AGENTS.md | 55 + CMakeLists.txt | 12 + Core/README.md | 9 + Core/Tools/BridgeGen/BridgeGen.csproj | 10 + Core/Tools/BridgeGen/Program.cs | 730 + Core/cpp/CMakeLists.txt | 22 + Core/cpp/include/bridge/bridge.h | 199 + Core/cpp/include/bridge/runtime/core_app.h | 20 + .../cpp/include/bridge/runtime/core_context.h | 34 + Core/cpp/include/bridge/runtime/game_entry.h | 13 + Core/cpp/src/api/bridge_api.cpp | 59 + Core/cpp/src/core/command_stream.cpp | 40 + Core/cpp/src/core/command_stream.h | 71 + Core/cpp/src/core/core_instance.cpp | 191 + Core/cpp/src/core/core_instance.h | 38 + Core/csharp/Bridge.Core/Bridge.Core.csproj | 9 + Core/csharp/Bridge.Core/BridgeCore.cs | 78 + Core/csharp/Bridge.Core/CommandStream.cs | 23 + .../Bridge.Core/Interop/BridgeNative.cs | 35 + Core/csharp/Bridge.Core/Interop/Structs.cs | 120 + Core/docs/BRIDGE_DESIGN.md | 121 + Core/docs/BUILD.md | 88 + Core/docs/UNITY_WIN_NATIVE_LOADING.md | 66 + README.md | 263 +- Tests/README.md | 10 + Tests/assets/Main/Prefabs/Bot.bytes | 2 + Tests/cpp/CMakeLists.txt | 2 + .../generated/demo_asset_bindings.generated.h | 46 + .../demo_entity_bindings.generated.h | 70 + Tests/cpp/demo_game/CMakeLists.txt | 45 + Tests/cpp/demo_game/src/demo_asset_app.cpp | 90 + Tests/cpp/demo_game/src/demo_asset_app.h | 10 + Tests/cpp/demo_game/src/game_entry.cpp | 12 + .../generated/demo_log_bindings.generated.h | 36 + Tests/cpp/robot_runner/CMakeLists.txt | 28 + Tests/cpp/robot_runner/main.cpp | 161 + Tests/csharp/RobotHost/Bind/Args.cs | 12 + .../RobotHost/Bind/FileAssetProvider.cs | 68 + Tests/csharp/RobotHost/Bind/IRobotHostApi.cs | 8 + .../csharp/RobotHost/Bind/IRobotHostStats.cs | 10 + .../RobotHost/Bind/NativeBridgeResolver.cs | 35 + Tests/csharp/RobotHost/Bind/Paths.cs | 46 + Tests/csharp/RobotHost/Bind/RobotHostApi.cs | 64 + .../csharp/RobotHost/Bind/RobotNullHostApi.cs | 68 + Tests/csharp/RobotHost/Bind/WorldState.cs | 49 + .../Bridge.AllCommandDispatcher.g.cs | 99 + .../Generated/DemoAsset.CoreCalls.g.cs | 23 + .../RobotHost/Generated/DemoAsset.Ids.g.cs | 16 + .../Generated/DemoAsset.Structs.g.cs | 26 + .../Generated/DemoEntity.CoreCalls.g.cs | 12 + .../RobotHost/Generated/DemoEntity.Ids.g.cs | 17 + .../Generated/DemoEntity.Structs.g.cs | 33 + .../Generated/DemoLog.CoreCalls.g.cs | 12 + .../RobotHost/Generated/DemoLog.Ids.g.cs | 15 + .../RobotHost/Generated/DemoLog.Structs.g.cs | 17 + .../Generated/IDemoAssetHostApi.g.cs | 13 + .../Generated/IDemoEntityHostApi.g.cs | 15 + .../RobotHost/Generated/IDemoLogHostApi.g.cs | 13 + Tests/csharp/RobotHost/Program.cs | 241 + Tests/csharp/RobotHost/RobotHost.csproj | 14 + Tests/defs/demo_asset_api.def | 6 + Tests/defs/demo_entity_api.def | 6 + Tests/defs/demo_log_api.def | 8 + {Unity => Tests/unity}/.gitignore | 0 .../unity/Assets/BridgeCore.meta | 5 +- .../unity/Assets/BridgeCore/Editor.meta | 5 +- .../Editor/BridgeCoreWinHotReload.cs | 208 + .../Editor/BridgeCoreWinHotReload.cs.meta | 5 +- .../BridgeCore/Editor/BridgeCoreWinSync.cs | 114 + .../Editor/BridgeCoreWinSync.cs.meta | 5 +- .../unity/Assets/BridgeCore/Managed.meta | 5 +- .../BridgeCore/Managed/Bridge.Core.meta | 5 +- .../Managed/Bridge.Core/Bridge.Core.asmdef | 7 + .../Bridge.Core/Bridge.Core.asmdef.meta | 7 + .../Managed/Bridge.Core/BridgeCore.cs | 78 + .../Managed/Bridge.Core/BridgeCore.cs.meta | 6 +- .../Managed/Bridge.Core/CommandStream.cs | 24 + .../Managed/Bridge.Core/CommandStream.cs.meta | 6 +- .../Managed/Bridge.Core/Interop.meta | 9 + .../Bridge.Core/Interop/BridgeNative.cs | 135 + .../Bridge.Core/Interop/BridgeNative.cs.meta | 12 + .../Managed/Bridge.Core/Interop/Structs.cs | 120 + .../Bridge.Core/Interop/Structs.cs.meta | 12 + Tests/unity/Assets/BridgeCore/README.md | 13 + .../unity/Assets/BridgeCore/README.md.meta | 5 +- Tests/unity/Assets/BridgeCore/Runtime.meta | 9 + .../Runtime/Bridge.Core.Unity.asmdef | 3 + .../Runtime/Bridge.Core.Unity.asmdef.meta | 7 + .../BridgeCore/Runtime/BridgeCoreWinLoader.cs | 214 + .../Runtime/BridgeCoreWinLoader.cs.meta | 12 + Tests/unity/Assets/BridgeDemoGame.meta | 9 + Tests/unity/Assets/BridgeDemoGame/Editor.meta | 8 + .../BridgeDemoGame/Editor/Performance.meta | 8 + .../BridgeDemoGame.PerformanceTests.asmdef | 15 + ...ridgeDemoGame.PerformanceTests.asmdef.meta | 7 + .../BridgeDispatchPerformanceTests.cs | 105 + .../BridgeDispatchPerformanceTests.cs.meta | 11 + .../Assets/BridgeDemoGame/Generated.meta | 9 + .../Bridge.AllCommandDispatcher.g.cs | 99 + .../Bridge.AllCommandDispatcher.g.cs.meta | 12 + .../Generated/BridgeDemoGame.Generated.asmdef | 7 + .../BridgeDemoGame.Generated.asmdef.meta | 7 + .../Generated/DemoAsset.CoreCalls.g.cs | 23 + .../Generated/DemoAsset.CoreCalls.g.cs.meta | 12 + .../Generated/DemoAsset.Ids.g.cs | 16 + .../Generated/DemoAsset.Ids.g.cs.meta | 12 + .../Generated/DemoAsset.Structs.g.cs | 26 + .../Generated/DemoAsset.Structs.g.cs.meta | 12 + .../Generated/DemoEntity.CoreCalls.g.cs | 12 + .../Generated/DemoEntity.CoreCalls.g.cs.meta | 12 + .../Generated/DemoEntity.Ids.g.cs | 17 + .../Generated/DemoEntity.Ids.g.cs.meta | 12 + .../Generated/DemoEntity.Structs.g.cs | 33 + .../Generated/DemoEntity.Structs.g.cs.meta | 12 + .../Generated/DemoLog.CoreCalls.g.cs | 12 + .../Generated/DemoLog.CoreCalls.g.cs.meta | 12 + .../BridgeDemoGame/Generated/DemoLog.Ids.g.cs | 15 + .../Generated/DemoLog.Ids.g.cs.meta | 12 + .../Generated/DemoLog.Structs.g.cs | 17 + .../Generated/DemoLog.Structs.g.cs.meta | 12 + .../Generated/IDemoAssetHostApi.g.cs | 13 + .../Generated/IDemoAssetHostApi.g.cs.meta | 12 + .../Generated/IDemoEntityHostApi.g.cs | 15 + .../Generated/IDemoEntityHostApi.g.cs.meta | 12 + .../Generated/IDemoLogHostApi.g.cs | 13 + .../Generated/IDemoLogHostApi.g.cs.meta | 12 + Tests/unity/Assets/BridgeDemoGame/README.md | 62 + .../Assets/BridgeDemoGame/README.md.meta | 6 +- .../Assets/BridgeDemoGame/Resources.meta | 9 + .../Assets/BridgeDemoGame/Resources/Main.meta | 9 + .../Resources/Main/Prefabs.meta | 9 + .../Resources/Main/Prefabs/Bot.bytes | 2 + .../Resources/Main/Prefabs/Bot.bytes.meta | 6 +- .../unity/Assets/BridgeDemoGame/Runtime.meta | 9 + .../Runtime/DemoGameUnityAssetService.cs | 133 + .../Runtime/DemoGameUnityAssetService.cs.meta | 12 + .../Runtime/DemoGameUnityHostApi.Asset.cs | 16 + .../DemoGameUnityHostApi.Asset.cs.meta | 12 + .../Runtime/DemoGameUnityHostApi.Entity.cs | 60 + .../DemoGameUnityHostApi.Entity.cs.meta | 12 + .../Runtime/DemoGameUnityHostApi.Log.cs | 32 + .../Runtime/DemoGameUnityHostApi.Log.cs.meta | 12 + .../Runtime/DemoGameUnityHostApi.cs | 44 + .../Runtime/DemoGameUnityHostApi.cs.meta | 12 + .../Runtime/DemoGameUnityRunner.cs | 67 + .../Runtime/DemoGameUnityRunner.cs.meta | 12 + Tests/unity/Assets/BridgeDemoGame/Test.unity | 378 + .../Assets/BridgeDemoGame/Test.unity.meta | 4 +- Tests/unity/Assets/Resources.meta | 8 + Tests/unity/Assets/Resources/BillingMode.json | 1 + .../Assets/Resources/BillingMode.json.meta | 7 + {Unity => Tests/unity}/Packages/manifest.json | 29 +- Tests/unity/Packages/packages-lock.json | 437 + .../unity}/ProjectSettings/AudioManager.asset | 0 .../ProjectSettings/ClusterInputManager.asset | 0 .../ProjectSettings/DynamicsManager.asset | 0 .../ProjectSettings/EditorBuildSettings.asset | 0 .../ProjectSettings/EditorSettings.asset | 0 .../ProjectSettings/GraphicsSettings.asset | 0 .../unity}/ProjectSettings/InputManager.asset | 0 .../ProjectSettings/MemorySettings.asset | 35 + .../ProjectSettings/MultiplayerManager.asset | 7 + .../unity}/ProjectSettings/NavMeshAreas.asset | 0 .../ProjectSettings/NavMeshLayers.asset | Bin .../ProjectSettings/NetworkManager.asset | 0 .../PackageManagerSettings.asset | 37 + .../com.unity.services.core/Settings.json | 0 .../ProjectSettings/Physics2DSettings.asset | 0 .../ProjectSettings/PresetManager.asset | 0 .../ProjectSettings/ProjectSettings.asset | 402 +- .../unity/ProjectSettings/ProjectVersion.txt | 2 + .../ProjectSettings/QualitySettings.asset | 0 .../SceneTemplateSettings.json | 121 + .../unity}/ProjectSettings/TagManager.asset | 0 .../unity}/ProjectSettings/TimeManager.asset | 0 .../UnityConnectSettings.asset | 0 .../unity}/ProjectSettings/VFXManager.asset | 0 .../VersionControlSettings.asset | 7 + .../unity}/ProjectSettings/XRSettings.asset | 0 Unity/Assets/CppSource/CMakeLists.txt | 87 - Unity/Assets/CppSource/Game/Game.cpp | 85 - Unity/Assets/CppSource/Game/Game.cpp.meta | 26 - Unity/Assets/CppSource/Game/Game.h | 23 - Unity/Assets/CppSource/Game/Game.h.meta | 26 - .../CppSource/NativeScript/Bindings.cpp | 6349 ------- .../CppSource/NativeScript/Bindings.cpp.meta | 26 - .../Assets/CppSource/NativeScript/Bindings.h | 1669 -- .../CppSource/NativeScript/Bindings.h.meta | 26 - Unity/Assets/CppSource/iOS.cmake | 208 - Unity/Assets/Game/AbstractBaseBallScript.cs | 19 - Unity/Assets/NativeScript.meta | 9 - Unity/Assets/NativeScript/Bindings.cs | 2157 --- Unity/Assets/NativeScript/BootScene.unity | 239 - .../Assets/NativeScript/BootScene.unity.meta | 8 - Unity/Assets/NativeScript/BootScript.cs | 95 - Unity/Assets/NativeScript/BootScript.cs.meta | 8 - Unity/Assets/NativeScript/Editor.meta | 9 - .../Assets/NativeScript/Editor/EditorMenus.cs | 30 - .../NativeScript/Editor/GenerateBindings.cs | 13654 ---------------- Unity/Assets/NativeScript/VERSION.txt | 1 - Unity/Assets/NativeScriptConstants.cs | 17 - Unity/Assets/NativeScriptConstants.cs.meta | 12 - Unity/Assets/NativeScriptTypes.json | 344 - Unity/Assets/Plugins.meta | 9 - Unity/ProjectSettings/ProjectVersion.txt | 2 - 206 files changed, 7112 insertions(+), 25497 deletions(-) create mode 100644 AGENTS.md create mode 100644 CMakeLists.txt create mode 100644 Core/README.md create mode 100644 Core/Tools/BridgeGen/BridgeGen.csproj create mode 100644 Core/Tools/BridgeGen/Program.cs create mode 100644 Core/cpp/CMakeLists.txt create mode 100644 Core/cpp/include/bridge/bridge.h create mode 100644 Core/cpp/include/bridge/runtime/core_app.h create mode 100644 Core/cpp/include/bridge/runtime/core_context.h create mode 100644 Core/cpp/include/bridge/runtime/game_entry.h create mode 100644 Core/cpp/src/api/bridge_api.cpp create mode 100644 Core/cpp/src/core/command_stream.cpp create mode 100644 Core/cpp/src/core/command_stream.h create mode 100644 Core/cpp/src/core/core_instance.cpp create mode 100644 Core/cpp/src/core/core_instance.h create mode 100644 Core/csharp/Bridge.Core/Bridge.Core.csproj create mode 100644 Core/csharp/Bridge.Core/BridgeCore.cs create mode 100644 Core/csharp/Bridge.Core/CommandStream.cs create mode 100644 Core/csharp/Bridge.Core/Interop/BridgeNative.cs create mode 100644 Core/csharp/Bridge.Core/Interop/Structs.cs create mode 100644 Core/docs/BRIDGE_DESIGN.md create mode 100644 Core/docs/BUILD.md create mode 100644 Core/docs/UNITY_WIN_NATIVE_LOADING.md create mode 100644 Tests/README.md create mode 100644 Tests/assets/Main/Prefabs/Bot.bytes create mode 100644 Tests/cpp/CMakeLists.txt create mode 100644 Tests/cpp/demo_asset/generated/demo_asset_bindings.generated.h create mode 100644 Tests/cpp/demo_entity/generated/demo_entity_bindings.generated.h create mode 100644 Tests/cpp/demo_game/CMakeLists.txt create mode 100644 Tests/cpp/demo_game/src/demo_asset_app.cpp create mode 100644 Tests/cpp/demo_game/src/demo_asset_app.h create mode 100644 Tests/cpp/demo_game/src/game_entry.cpp create mode 100644 Tests/cpp/demo_log/generated/demo_log_bindings.generated.h create mode 100644 Tests/cpp/robot_runner/CMakeLists.txt create mode 100644 Tests/cpp/robot_runner/main.cpp create mode 100644 Tests/csharp/RobotHost/Bind/Args.cs create mode 100644 Tests/csharp/RobotHost/Bind/FileAssetProvider.cs create mode 100644 Tests/csharp/RobotHost/Bind/IRobotHostApi.cs create mode 100644 Tests/csharp/RobotHost/Bind/IRobotHostStats.cs create mode 100644 Tests/csharp/RobotHost/Bind/NativeBridgeResolver.cs create mode 100644 Tests/csharp/RobotHost/Bind/Paths.cs create mode 100644 Tests/csharp/RobotHost/Bind/RobotHostApi.cs create mode 100644 Tests/csharp/RobotHost/Bind/RobotNullHostApi.cs create mode 100644 Tests/csharp/RobotHost/Bind/WorldState.cs create mode 100644 Tests/csharp/RobotHost/Generated/Bridge.AllCommandDispatcher.g.cs create mode 100644 Tests/csharp/RobotHost/Generated/DemoAsset.CoreCalls.g.cs create mode 100644 Tests/csharp/RobotHost/Generated/DemoAsset.Ids.g.cs create mode 100644 Tests/csharp/RobotHost/Generated/DemoAsset.Structs.g.cs create mode 100644 Tests/csharp/RobotHost/Generated/DemoEntity.CoreCalls.g.cs create mode 100644 Tests/csharp/RobotHost/Generated/DemoEntity.Ids.g.cs create mode 100644 Tests/csharp/RobotHost/Generated/DemoEntity.Structs.g.cs create mode 100644 Tests/csharp/RobotHost/Generated/DemoLog.CoreCalls.g.cs create mode 100644 Tests/csharp/RobotHost/Generated/DemoLog.Ids.g.cs create mode 100644 Tests/csharp/RobotHost/Generated/DemoLog.Structs.g.cs create mode 100644 Tests/csharp/RobotHost/Generated/IDemoAssetHostApi.g.cs create mode 100644 Tests/csharp/RobotHost/Generated/IDemoEntityHostApi.g.cs create mode 100644 Tests/csharp/RobotHost/Generated/IDemoLogHostApi.g.cs create mode 100644 Tests/csharp/RobotHost/Program.cs create mode 100644 Tests/csharp/RobotHost/RobotHost.csproj create mode 100644 Tests/defs/demo_asset_api.def create mode 100644 Tests/defs/demo_entity_api.def create mode 100644 Tests/defs/demo_log_api.def rename {Unity => Tests/unity}/.gitignore (100%) rename Unity/Assets/CppSource.meta => Tests/unity/Assets/BridgeCore.meta (62%) rename Unity/Assets/CppSource/NativeScript.meta => Tests/unity/Assets/BridgeCore/Editor.meta (62%) create mode 100644 Tests/unity/Assets/BridgeCore/Editor/BridgeCoreWinHotReload.cs rename Unity/Assets/Game/AbstractBaseBallScript.cs.meta => Tests/unity/Assets/BridgeCore/Editor/BridgeCoreWinHotReload.cs.meta (71%) create mode 100644 Tests/unity/Assets/BridgeCore/Editor/BridgeCoreWinSync.cs rename Unity/Assets/NativeScript/Editor/EditorMenus.cs.meta => Tests/unity/Assets/BridgeCore/Editor/BridgeCoreWinSync.cs.meta (71%) rename Unity/Assets/Game.meta => Tests/unity/Assets/BridgeCore/Managed.meta (62%) rename Unity/Assets/CppSource/Game.meta => Tests/unity/Assets/BridgeCore/Managed/Bridge.Core.meta (62%) create mode 100644 Tests/unity/Assets/BridgeCore/Managed/Bridge.Core/Bridge.Core.asmdef create mode 100644 Tests/unity/Assets/BridgeCore/Managed/Bridge.Core/Bridge.Core.asmdef.meta create mode 100644 Tests/unity/Assets/BridgeCore/Managed/Bridge.Core/BridgeCore.cs rename Unity/Assets/NativeScript/Bindings.cs.meta => Tests/unity/Assets/BridgeCore/Managed/Bridge.Core/BridgeCore.cs.meta (69%) create mode 100644 Tests/unity/Assets/BridgeCore/Managed/Bridge.Core/CommandStream.cs rename Unity/Assets/NativeScript/Editor/GenerateBindings.cs.meta => Tests/unity/Assets/BridgeCore/Managed/Bridge.Core/CommandStream.cs.meta (69%) create mode 100644 Tests/unity/Assets/BridgeCore/Managed/Bridge.Core/Interop.meta create mode 100644 Tests/unity/Assets/BridgeCore/Managed/Bridge.Core/Interop/BridgeNative.cs create mode 100644 Tests/unity/Assets/BridgeCore/Managed/Bridge.Core/Interop/BridgeNative.cs.meta create mode 100644 Tests/unity/Assets/BridgeCore/Managed/Bridge.Core/Interop/Structs.cs create mode 100644 Tests/unity/Assets/BridgeCore/Managed/Bridge.Core/Interop/Structs.cs.meta create mode 100644 Tests/unity/Assets/BridgeCore/README.md rename Unity/Assets/CppSource/CMakeLists.txt.meta => Tests/unity/Assets/BridgeCore/README.md.meta (59%) create mode 100644 Tests/unity/Assets/BridgeCore/Runtime.meta create mode 100644 Tests/unity/Assets/BridgeCore/Runtime/Bridge.Core.Unity.asmdef create mode 100644 Tests/unity/Assets/BridgeCore/Runtime/Bridge.Core.Unity.asmdef.meta create mode 100644 Tests/unity/Assets/BridgeCore/Runtime/BridgeCoreWinLoader.cs create mode 100644 Tests/unity/Assets/BridgeCore/Runtime/BridgeCoreWinLoader.cs.meta create mode 100644 Tests/unity/Assets/BridgeDemoGame.meta create mode 100644 Tests/unity/Assets/BridgeDemoGame/Editor.meta create mode 100644 Tests/unity/Assets/BridgeDemoGame/Editor/Performance.meta create mode 100644 Tests/unity/Assets/BridgeDemoGame/Editor/Performance/BridgeDemoGame.PerformanceTests.asmdef create mode 100644 Tests/unity/Assets/BridgeDemoGame/Editor/Performance/BridgeDemoGame.PerformanceTests.asmdef.meta create mode 100644 Tests/unity/Assets/BridgeDemoGame/Editor/Performance/BridgeDispatchPerformanceTests.cs create mode 100644 Tests/unity/Assets/BridgeDemoGame/Editor/Performance/BridgeDispatchPerformanceTests.cs.meta create mode 100644 Tests/unity/Assets/BridgeDemoGame/Generated.meta create mode 100644 Tests/unity/Assets/BridgeDemoGame/Generated/Bridge.AllCommandDispatcher.g.cs create mode 100644 Tests/unity/Assets/BridgeDemoGame/Generated/Bridge.AllCommandDispatcher.g.cs.meta create mode 100644 Tests/unity/Assets/BridgeDemoGame/Generated/BridgeDemoGame.Generated.asmdef create mode 100644 Tests/unity/Assets/BridgeDemoGame/Generated/BridgeDemoGame.Generated.asmdef.meta create mode 100644 Tests/unity/Assets/BridgeDemoGame/Generated/DemoAsset.CoreCalls.g.cs create mode 100644 Tests/unity/Assets/BridgeDemoGame/Generated/DemoAsset.CoreCalls.g.cs.meta create mode 100644 Tests/unity/Assets/BridgeDemoGame/Generated/DemoAsset.Ids.g.cs create mode 100644 Tests/unity/Assets/BridgeDemoGame/Generated/DemoAsset.Ids.g.cs.meta create mode 100644 Tests/unity/Assets/BridgeDemoGame/Generated/DemoAsset.Structs.g.cs create mode 100644 Tests/unity/Assets/BridgeDemoGame/Generated/DemoAsset.Structs.g.cs.meta create mode 100644 Tests/unity/Assets/BridgeDemoGame/Generated/DemoEntity.CoreCalls.g.cs create mode 100644 Tests/unity/Assets/BridgeDemoGame/Generated/DemoEntity.CoreCalls.g.cs.meta create mode 100644 Tests/unity/Assets/BridgeDemoGame/Generated/DemoEntity.Ids.g.cs create mode 100644 Tests/unity/Assets/BridgeDemoGame/Generated/DemoEntity.Ids.g.cs.meta create mode 100644 Tests/unity/Assets/BridgeDemoGame/Generated/DemoEntity.Structs.g.cs create mode 100644 Tests/unity/Assets/BridgeDemoGame/Generated/DemoEntity.Structs.g.cs.meta create mode 100644 Tests/unity/Assets/BridgeDemoGame/Generated/DemoLog.CoreCalls.g.cs create mode 100644 Tests/unity/Assets/BridgeDemoGame/Generated/DemoLog.CoreCalls.g.cs.meta create mode 100644 Tests/unity/Assets/BridgeDemoGame/Generated/DemoLog.Ids.g.cs create mode 100644 Tests/unity/Assets/BridgeDemoGame/Generated/DemoLog.Ids.g.cs.meta create mode 100644 Tests/unity/Assets/BridgeDemoGame/Generated/DemoLog.Structs.g.cs create mode 100644 Tests/unity/Assets/BridgeDemoGame/Generated/DemoLog.Structs.g.cs.meta create mode 100644 Tests/unity/Assets/BridgeDemoGame/Generated/IDemoAssetHostApi.g.cs create mode 100644 Tests/unity/Assets/BridgeDemoGame/Generated/IDemoAssetHostApi.g.cs.meta create mode 100644 Tests/unity/Assets/BridgeDemoGame/Generated/IDemoEntityHostApi.g.cs create mode 100644 Tests/unity/Assets/BridgeDemoGame/Generated/IDemoEntityHostApi.g.cs.meta create mode 100644 Tests/unity/Assets/BridgeDemoGame/Generated/IDemoLogHostApi.g.cs create mode 100644 Tests/unity/Assets/BridgeDemoGame/Generated/IDemoLogHostApi.g.cs.meta create mode 100644 Tests/unity/Assets/BridgeDemoGame/README.md rename Unity/Assets/NativeScript/VERSION.txt.meta => Tests/unity/Assets/BridgeDemoGame/README.md.meta (54%) create mode 100644 Tests/unity/Assets/BridgeDemoGame/Resources.meta create mode 100644 Tests/unity/Assets/BridgeDemoGame/Resources/Main.meta create mode 100644 Tests/unity/Assets/BridgeDemoGame/Resources/Main/Prefabs.meta create mode 100644 Tests/unity/Assets/BridgeDemoGame/Resources/Main/Prefabs/Bot.bytes rename Unity/Assets/NativeScriptTypes.json.meta => Tests/unity/Assets/BridgeDemoGame/Resources/Main/Prefabs/Bot.bytes.meta (54%) create mode 100644 Tests/unity/Assets/BridgeDemoGame/Runtime.meta create mode 100644 Tests/unity/Assets/BridgeDemoGame/Runtime/DemoGameUnityAssetService.cs create mode 100644 Tests/unity/Assets/BridgeDemoGame/Runtime/DemoGameUnityAssetService.cs.meta create mode 100644 Tests/unity/Assets/BridgeDemoGame/Runtime/DemoGameUnityHostApi.Asset.cs create mode 100644 Tests/unity/Assets/BridgeDemoGame/Runtime/DemoGameUnityHostApi.Asset.cs.meta create mode 100644 Tests/unity/Assets/BridgeDemoGame/Runtime/DemoGameUnityHostApi.Entity.cs create mode 100644 Tests/unity/Assets/BridgeDemoGame/Runtime/DemoGameUnityHostApi.Entity.cs.meta create mode 100644 Tests/unity/Assets/BridgeDemoGame/Runtime/DemoGameUnityHostApi.Log.cs create mode 100644 Tests/unity/Assets/BridgeDemoGame/Runtime/DemoGameUnityHostApi.Log.cs.meta create mode 100644 Tests/unity/Assets/BridgeDemoGame/Runtime/DemoGameUnityHostApi.cs create mode 100644 Tests/unity/Assets/BridgeDemoGame/Runtime/DemoGameUnityHostApi.cs.meta create mode 100644 Tests/unity/Assets/BridgeDemoGame/Runtime/DemoGameUnityRunner.cs create mode 100644 Tests/unity/Assets/BridgeDemoGame/Runtime/DemoGameUnityRunner.cs.meta create mode 100644 Tests/unity/Assets/BridgeDemoGame/Test.unity rename Unity/Assets/CppSource/iOS.cmake.meta => Tests/unity/Assets/BridgeDemoGame/Test.unity.meta (58%) create mode 100644 Tests/unity/Assets/Resources.meta create mode 100644 Tests/unity/Assets/Resources/BillingMode.json create mode 100644 Tests/unity/Assets/Resources/BillingMode.json.meta rename {Unity => Tests/unity}/Packages/manifest.json (71%) create mode 100644 Tests/unity/Packages/packages-lock.json rename {Unity => Tests/unity}/ProjectSettings/AudioManager.asset (100%) rename {Unity => Tests/unity}/ProjectSettings/ClusterInputManager.asset (100%) rename {Unity => Tests/unity}/ProjectSettings/DynamicsManager.asset (100%) rename {Unity => Tests/unity}/ProjectSettings/EditorBuildSettings.asset (100%) rename {Unity => Tests/unity}/ProjectSettings/EditorSettings.asset (100%) rename {Unity => Tests/unity}/ProjectSettings/GraphicsSettings.asset (100%) rename {Unity => Tests/unity}/ProjectSettings/InputManager.asset (100%) create mode 100644 Tests/unity/ProjectSettings/MemorySettings.asset create mode 100644 Tests/unity/ProjectSettings/MultiplayerManager.asset rename {Unity => Tests/unity}/ProjectSettings/NavMeshAreas.asset (100%) rename {Unity => Tests/unity}/ProjectSettings/NavMeshLayers.asset (100%) rename {Unity => Tests/unity}/ProjectSettings/NetworkManager.asset (100%) create mode 100644 Tests/unity/ProjectSettings/PackageManagerSettings.asset create mode 100644 Tests/unity/ProjectSettings/Packages/com.unity.services.core/Settings.json rename {Unity => Tests/unity}/ProjectSettings/Physics2DSettings.asset (100%) rename {Unity => Tests/unity}/ProjectSettings/PresetManager.asset (100%) rename {Unity => Tests/unity}/ProjectSettings/ProjectSettings.asset (67%) create mode 100644 Tests/unity/ProjectSettings/ProjectVersion.txt rename {Unity => Tests/unity}/ProjectSettings/QualitySettings.asset (100%) create mode 100644 Tests/unity/ProjectSettings/SceneTemplateSettings.json rename {Unity => Tests/unity}/ProjectSettings/TagManager.asset (100%) rename {Unity => Tests/unity}/ProjectSettings/TimeManager.asset (100%) rename {Unity => Tests/unity}/ProjectSettings/UnityConnectSettings.asset (100%) rename {Unity => Tests/unity}/ProjectSettings/VFXManager.asset (100%) create mode 100644 Tests/unity/ProjectSettings/VersionControlSettings.asset rename {Unity => Tests/unity}/ProjectSettings/XRSettings.asset (100%) delete mode 100644 Unity/Assets/CppSource/CMakeLists.txt delete mode 100644 Unity/Assets/CppSource/Game/Game.cpp delete mode 100644 Unity/Assets/CppSource/Game/Game.cpp.meta delete mode 100644 Unity/Assets/CppSource/Game/Game.h delete mode 100644 Unity/Assets/CppSource/Game/Game.h.meta delete mode 100644 Unity/Assets/CppSource/NativeScript/Bindings.cpp delete mode 100644 Unity/Assets/CppSource/NativeScript/Bindings.cpp.meta delete mode 100644 Unity/Assets/CppSource/NativeScript/Bindings.h delete mode 100644 Unity/Assets/CppSource/NativeScript/Bindings.h.meta delete mode 100644 Unity/Assets/CppSource/iOS.cmake delete mode 100644 Unity/Assets/Game/AbstractBaseBallScript.cs delete mode 100644 Unity/Assets/NativeScript.meta delete mode 100644 Unity/Assets/NativeScript/Bindings.cs delete mode 100644 Unity/Assets/NativeScript/BootScene.unity delete mode 100644 Unity/Assets/NativeScript/BootScene.unity.meta delete mode 100644 Unity/Assets/NativeScript/BootScript.cs delete mode 100644 Unity/Assets/NativeScript/BootScript.cs.meta delete mode 100644 Unity/Assets/NativeScript/Editor.meta delete mode 100644 Unity/Assets/NativeScript/Editor/EditorMenus.cs delete mode 100644 Unity/Assets/NativeScript/Editor/GenerateBindings.cs delete mode 100644 Unity/Assets/NativeScript/VERSION.txt delete mode 100644 Unity/Assets/NativeScriptConstants.cs delete mode 100644 Unity/Assets/NativeScriptConstants.cs.meta delete mode 100644 Unity/Assets/NativeScriptTypes.json delete mode 100644 Unity/Assets/Plugins.meta delete mode 100644 Unity/ProjectSettings/ProjectVersion.txt diff --git a/.gitignore b/.gitignore index eaec275..08b61b2 100644 --- a/.gitignore +++ b/.gitignore @@ -2,4 +2,14 @@ .idea # Unity upgrade logs -Unity/Logs \ No newline at end of file +Tests/unity/Logs + +# Build outputs +build/ +Core/**/bin/ +Core/**/obj/ +Core/**/build/ +Tests/**/bin/ +Tests/**/obj/ +Tests/**/build/ +Tests/unity/UserSettings diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..b1f4f89 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,55 @@ +# UnityNativeScripting(工作区)协作说明 + +当前仓库包含: + +- `Core/`:全新 Core-first 运行时(C++20 + C# `netstandard2.1`)。 +- `Core/Tools/`:代码生成等工具。 +- `Tests/`:机器人/压测/示例业务 + 标准 Host(C++ + C#)。 +- `Tests/unity/`:Unity Host 范例工程(Windows Editor 下 Copy-Then-Load)。 + +## 新系统目标 + +核心思想:把业务/数据/规则尽可能下沉到 C++ Core;引擎(Unity/自研)只做渲染壳与必须能力提供者(Host)。 + +关键约束:Unity/IL2CPP 友好,避免 native→managed 回调(AOT/裁剪复杂),改为轮询式数据流: + +- Core → Host:每帧输出一段 command stream(字节流)。 +- Host → Core:通过 C ABI 推送事件(例如资源加载完成)。 + +## 目录约定 + +- `Core/cpp/`:C++20 核心(导出稳定 C ABI) +- `Core/csharp/`:C# 封装(Unity 兼容) +- `Core/docs/`:设计/构建说明(中文) +- `Tests/cpp/demo_game/`:示例业务(引用 `bridge_runtime`,并产出最终 `bridge_core.dll` 供 Host 加载) +- `Tests/cpp/`:C++ 机器人 runner(用于压测/快速验证) +- `Tests/csharp/`:标准 .NET Host(读文件模拟资源模块),并包含绑定实现 +- `Tests/unity/`:Unity Host 范例工程 +- `Tests/assets/`:测试资源(示例文件) + +## 构建 + +### C++(C++20) + +```powershell +cmake -S . -B build -DCMAKE_BUILD_TYPE=Release +cmake --build build --config Release +``` + +### C#(`netstandard2.1`) + +```powershell +dotnet build Core/csharp/Bridge.Core/Bridge.Core.csproj -c Release +dotnet build Tests/csharp/RobotHost/RobotHost.csproj -c Release +``` + +## 重要约束(ABI/绑定) + +- 公共 C ABI 入口定义在 `Core/cpp/include/bridge/bridge.h`。 +- C ABI 结构体变更必须同步更新:`Core/csharp/Bridge.Core/Interop/Structs.cs`。 +- 业务侧接口通过宏文件定义并生成: + - 定义:`Tests/defs/*.def`(建议一个 `.def` 对应一个业务模块/子系统) + - 生成(C++):`Tests/cpp//generated/_bindings.generated.h` + - 生成(C# Host):`Tests/csharp/RobotHost/Generated/.*.g.cs` + - 生成(Unity Host):`Tests/unity/Assets/BridgeDemoGame/Generated/.*.g.cs` +- 跨边界只传:blittable struct、ID/handle(`uint64`)、UTF-8 字符串视图(`ptr+len`,仅在当帧有效)。 diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..c130c0f --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,12 @@ +cmake_minimum_required(VERSION 3.20) + +project(NativeBridge LANGUAGES C CXX) + +option(BRIDGE_BUILD_TESTS "Build tests (robot runner, etc.)" ON) + +add_subdirectory(Core/cpp) + +if (BRIDGE_BUILD_TESTS) + enable_testing() + add_subdirectory(Tests/cpp) +endif() diff --git a/Core/README.md b/Core/README.md new file mode 100644 index 0000000..d136898 --- /dev/null +++ b/Core/README.md @@ -0,0 +1,9 @@ +# Core(Core-first Runtime) + +这里是全新设计的、引擎无关的 Core/Host 桥接运行时: + +- `cpp/`:C++20 Core 运行时 + 稳定 C ABI +- `csharp/`:C# `netstandard2.1` 封装(Unity 兼容) +- `docs/`:架构与构建文档 + +设计说明见:`Core/docs/BRIDGE_DESIGN.md`。 diff --git a/Core/Tools/BridgeGen/BridgeGen.csproj b/Core/Tools/BridgeGen/BridgeGen.csproj new file mode 100644 index 0000000..8300eb9 --- /dev/null +++ b/Core/Tools/BridgeGen/BridgeGen.csproj @@ -0,0 +1,10 @@ + + + Exe + net8.0 + latest + enable + enable + + + diff --git a/Core/Tools/BridgeGen/Program.cs b/Core/Tools/BridgeGen/Program.cs new file mode 100644 index 0000000..30c3ae5 --- /dev/null +++ b/Core/Tools/BridgeGen/Program.cs @@ -0,0 +1,730 @@ +using System.Text; +using System.Text.RegularExpressions; + +static class Program +{ + private sealed record CsModule(string Module, string CsNamespace, ApiModel Model); + + private static int Main(string[] args) + { + string repoRoot = FindRepoRoot(); + var apiFiles = GetArgs(args, "--api"); + if (apiFiles.Count == 0) + { + string defsDir = Path.Combine(repoRoot, "Tests", "defs"); + if (Directory.Exists(defsDir)) + { + apiFiles.AddRange(Directory.GetFiles(defsDir, "*.def", SearchOption.TopDirectoryOnly)); + apiFiles.Sort(StringComparer.OrdinalIgnoreCase); + } + if (apiFiles.Count == 0) + throw new InvalidOperationException($"未找到任何 .def 文件:{defsDir}。请创建 Tests/defs/*.def 或使用 --api 指定输入。"); + } + + // outCpp 约定为 Tests 目录(默认:/Tests),每个模块输出到 Tests/cpp//generated + string outCpp = GetArg(args, "--out-cpp") ?? Path.Combine(repoRoot, "Tests"); + string outCs = GetArg(args, "--out-cs") ?? Path.Combine(repoRoot, "Tests", "csharp", "RobotHost", "Generated"); + + string? singleModuleOverride = GetArg(args, "--module"); + string? singleNamespaceOverride = GetArg(args, "--cs-namespace"); + bool clean = !string.Equals(GetArg(args, "--clean"), "false", StringComparison.OrdinalIgnoreCase); + + Directory.CreateDirectory(outCpp); + Directory.CreateDirectory(outCs); + + var usedHostIds = new Dictionary(); + var usedCoreIds = new Dictionary(); + var csModules = new List(); + + foreach (string apiFile in apiFiles) + { + string fullApiFile = Path.IsPathRooted(apiFile) ? apiFile : Path.Combine(repoRoot, apiFile); + var model = ApiModel.Parse(File.ReadAllText(fullApiFile)); + + string module = singleModuleOverride ?? ModuleNameFromApiPath(fullApiFile); + string cppNs = CppNamespaceFromModule(module); + string csNs = singleNamespaceOverride ?? $"{module}.Bindings"; + + foreach (var fn in model.HostFns) + RegisterIdOrThrow(usedHostIds, ComputeHostFuncId(module, fn.Name), $"H:{module}.{fn.Name}"); + + foreach (var fn in model.CoreFns) + RegisterIdOrThrow(usedCoreIds, ComputeCoreFuncId(module, fn.Name), $"C:{module}.{fn.Name}"); + + string outCppDir = ResolveOutCppDir(repoRoot, outCpp, module); + Directory.CreateDirectory(outCppDir); + + if (clean) + CleanupGeneratedCs(outCs, module); + + string cppFileName = $"{cppNs}_bindings.generated.h"; + File.WriteAllText(Path.Combine(outCppDir, cppFileName), CppEmitter.Emit(model, module, cppNs), new UTF8Encoding(encoderShouldEmitUTF8Identifier: false)); + + foreach (var file in CsEmitter.EmitFiles(model, module, csNs)) + { + File.WriteAllText(Path.Combine(outCs, file.FileName), file.Contents, new UTF8Encoding(encoderShouldEmitUTF8Identifier: false)); + } + + Console.WriteLine($"OK: {fullApiFile}"); + Console.WriteLine($" C++: {outCppDir}"); + Console.WriteLine($" C#: {outCs}"); + + csModules.Add(new CsModule(module, csNs, model)); + } + + foreach (var file in CsEmitter.EmitAggregateFiles(csModules)) + { + File.WriteAllText(Path.Combine(outCs, file.FileName), file.Contents, new UTF8Encoding(encoderShouldEmitUTF8Identifier: false)); + } + return 0; + } + + private static void RegisterIdOrThrow(Dictionary map, uint id, string name) + { + if (map.TryGetValue(id, out string? existing) && !string.Equals(existing, name, StringComparison.Ordinal)) + { + throw new InvalidOperationException($"FuncId 冲突:0x{id:X8} 同时用于 `{existing}` 与 `{name}`。请重命名或拆分模块。"); + } + map[id] = name; + } + + private static uint ComputeHostFuncId(string module, string fnName) + { + return Fnv1a32("H:" + module + "." + fnName); + } + + private static uint ComputeCoreFuncId(string module, string fnName) + { + return Fnv1a32("C:" + module + "." + fnName); + } + + private static uint Fnv1a32(string s) + { + const uint offset = 2166136261u; + const uint prime = 16777619u; + + uint hash = offset; + byte[] bytes = Encoding.UTF8.GetBytes(s); + for (int i = 0; i < bytes.Length; i++) + { + hash ^= bytes[i]; + hash *= prime; + } + return hash; + } + + private static string? GetArg(string[] args, string name) + { + for (int i = 0; i < args.Length - 1; i++) + { + if (string.Equals(args[i], name, StringComparison.Ordinal)) + return args[i + 1]; + } + return null; + } + + private static List GetArgs(string[] args, string name) + { + var list = new List(); + for (int i = 0; i < args.Length - 1; i++) + { + if (string.Equals(args[i], name, StringComparison.Ordinal)) + list.Add(args[i + 1]); + } + return list; + } + + private static string FindRepoRoot() + { + string dir = AppContext.BaseDirectory; + for (int i = 0; i < 12; i++) + { + if (File.Exists(Path.Combine(dir, "CMakeLists.txt"))) + return dir; + + string? parent = Directory.GetParent(dir)?.FullName; + if (string.IsNullOrWhiteSpace(parent)) + break; + dir = parent; + } + return Directory.GetCurrentDirectory(); + } + + private static void CleanupGeneratedCs(string outCsDir, string module) + { + if (!Directory.Exists(outCsDir)) + return; + + // 仅清理本模块生成的文件,避免误删其他模块 + string prefix = module + "."; + string hostApiFile = "I" + module + "HostApi.g.cs"; + foreach (string file in Directory.GetFiles(outCsDir, "*.g.cs", SearchOption.TopDirectoryOnly)) + { + string name = Path.GetFileName(file); + if (name.StartsWith(prefix, StringComparison.Ordinal) || + string.Equals(name, hostApiFile, StringComparison.Ordinal) || + string.Equals(name, module + "Bindings.g.cs", StringComparison.Ordinal)) + { + File.Delete(file); + } + } + } + + private static string ModuleNameFromApiPath(string apiPath) + { + string name = Path.GetFileNameWithoutExtension(apiPath); + if (name.EndsWith("_api", StringComparison.OrdinalIgnoreCase)) + name = name.Substring(0, name.Length - 4); + + var parts = name.Split(new[] { '_', '-', '.' }, StringSplitOptions.RemoveEmptyEntries); + var sb = new StringBuilder(); + foreach (string p in parts) + { + if (p.Length == 0) continue; + sb.Append(char.ToUpperInvariant(p[0])); + if (p.Length > 1) sb.Append(p.Substring(1)); + } + return sb.Length == 0 ? "DemoGame" : sb.ToString(); + } + + private static string CppNamespaceFromModule(string module) + { + // DemoGame -> demo_game + var sb = new StringBuilder(); + for (int i = 0; i < module.Length; i++) + { + char c = module[i]; + if (char.IsUpper(c) && i > 0) + sb.Append('_'); + sb.Append(char.ToLowerInvariant(c)); + } + return sb.ToString(); + } + + private static string ResolveOutCppDir(string repoRoot, string outCppArg, string module) + { + // 默认 outCpp 为 Tests/cpp 根目录;每个模块输出到 Tests/cpp//generated + string outCppRoot = Path.IsPathRooted(outCppArg) ? outCppArg : Path.Combine(repoRoot, outCppArg); + string cppNs = CppNamespaceFromModule(module); + return Path.Combine(outCppRoot, "cpp", cppNs, "generated"); + } + + private sealed record ApiModel(List HostFns, List CoreFns) + { + public static ApiModel Parse(string text) + { + var hostFns = new List(); + var coreFns = new List(); + + foreach (string rawLine in text.Split('\n')) + { + string line = rawLine.Trim(); + if (line.Length == 0 || line.StartsWith("//", StringComparison.Ordinal)) + continue; + + if (TryParseMacro(line, "BRIDGE_HOST_API", out ApiFn hostFn)) + { + hostFns.Add(hostFn); + continue; + } + + if (TryParseMacro(line, "BRIDGE_CORE_API", out ApiFn coreFn)) + { + coreFns.Add(coreFn); + continue; + } + } + + return new ApiModel(hostFns, coreFns); + } + + private static bool TryParseMacro(string line, string macroName, out ApiFn fn) + { + fn = new ApiFn(string.Empty, new List()); + + var match = Regex.Match(line, $"^{Regex.Escape(macroName)}\\((.*)\\)\\s*$"); + if (!match.Success) + return false; + + string inside = match.Groups[1].Value.Trim(); + var parts = SplitTopLevel(inside); + if (parts.Count < 1) + throw new InvalidOperationException($"无效定义:{line}"); + + string name = parts[0].Trim(); + var args = new List(); + for (int i = 1; i < parts.Count; i++) + { + string arg = parts[i].Trim(); + if (arg.Length == 0) + continue; + + int lastSpace = arg.LastIndexOf(' '); + if (lastSpace <= 0 || lastSpace == arg.Length - 1) + throw new InvalidOperationException($"参数格式必须为 `Type name`:{line}"); + + string type = arg.Substring(0, lastSpace).Trim(); + string argName = arg.Substring(lastSpace + 1).Trim(); + args.Add(new ApiArg(type, argName)); + } + + fn = new ApiFn(name, args); + return true; + } + + private static List SplitTopLevel(string s) + { + var list = new List(); + var cur = new StringBuilder(); + int depth = 0; + foreach (char c in s) + { + if (c == '(') depth++; + if (c == ')') depth--; + + if (c == ',' && depth == 0) + { + list.Add(cur.ToString()); + cur.Clear(); + continue; + } + + cur.Append(c); + } + if (cur.Length > 0) + list.Add(cur.ToString()); + return list; + } + } + + private sealed record ApiFn(string Name, List Args); + private sealed record ApiArg(string CppType, string Name); + + private static class CppEmitter + { + public static string Emit(ApiModel model, string module, string cppNamespace) + { + var sb = new StringBuilder(); + sb.AppendLine("#pragma once"); + sb.AppendLine(); + sb.AppendLine("#include "); + sb.AppendLine("#include "); + sb.AppendLine(); + sb.AppendLine("#include "); + sb.AppendLine("#include "); + sb.AppendLine("#include "); + sb.AppendLine(); + sb.AppendLine($"namespace {cppNamespace}"); + sb.AppendLine("{"); + sb.AppendLine("\tenum class HostFuncId : uint32_t"); + sb.AppendLine("\t{"); + for (int i = 0; i < model.HostFns.Count; i++) + { + uint id = ComputeHostFuncId(module, model.HostFns[i].Name); + sb.AppendLine($"\t\t{model.HostFns[i].Name} = 0x{id:X8}u,"); + } + sb.AppendLine("\t};"); + sb.AppendLine(); + sb.AppendLine("\tenum class CoreFuncId : uint32_t"); + sb.AppendLine("\t{"); + for (int i = 0; i < model.CoreFns.Count; i++) + { + uint id = ComputeCoreFuncId(module, model.CoreFns[i].Name); + sb.AppendLine($"\t\t{model.CoreFns[i].Name} = 0x{id:X8}u,"); + } + sb.AppendLine("\t};"); + sb.AppendLine(); + + foreach (var fn in model.HostFns) + { + sb.AppendLine($"\tstruct HostArgs_{fn.Name}"); + sb.AppendLine("\t{"); + foreach (var arg in fn.Args) + sb.AppendLine($"\t\t{arg.CppType} {ToSnake(arg.Name)};"); + sb.AppendLine("\t};"); + sb.AppendLine(); + } + + foreach (var fn in model.CoreFns) + { + sb.AppendLine($"\tstruct CoreArgs_{fn.Name}"); + sb.AppendLine("\t{"); + foreach (var arg in fn.Args) + sb.AppendLine($"\t\t{arg.CppType} {ToSnake(arg.Name)};"); + sb.AppendLine("\t};"); + sb.AppendLine(); + } + + sb.AppendLine("\t// Core -> Host 调用(写入 command stream)"); + foreach (var fn in model.HostFns) + { + sb.Append($"\tinline void {fn.Name}(bridge::CoreContext& ctx"); + foreach (var arg in fn.Args) + { + sb.Append(", "); + sb.Append(MapCppCallArgType(arg.CppType)); + sb.Append(' '); + sb.Append(arg.Name); + } + sb.AppendLine(")"); + sb.AppendLine("\t{"); + sb.AppendLine($"\t\tHostArgs_{fn.Name} a{{}};"); + foreach (var arg in fn.Args) + { + if (arg.CppType == "BridgeStringView") + { + sb.AppendLine($"\t\ta.{ToSnake(arg.Name)} = ctx.StoreUtf8(std::string({arg.Name}));"); + } + else + { + sb.AppendLine($"\t\ta.{ToSnake(arg.Name)} = {arg.Name};"); + } + } + sb.AppendLine($"\t\tctx.CallHost(static_cast(HostFuncId::{fn.Name}), &a, static_cast(sizeof(a)));"); + sb.AppendLine("\t}"); + sb.AppendLine(); + } + + sb.AppendLine($"}} // namespace {cppNamespace}"); + return sb.ToString(); + } + + private static string ToSnake(string name) + { + if (string.IsNullOrEmpty(name)) + return name; + return char.ToLowerInvariant(name[0]) + name.Substring(1); + } + + private static string MapCppCallArgType(string cppType) + { + return cppType == "BridgeStringView" ? "std::string_view" : cppType; + } + } + + private static class CsEmitter + { + public sealed record CsFile(string FileName, string Contents); + + public static List EmitFiles(ApiModel model, string module, string csNamespace) + { + var files = new List(); + files.Add(new CsFile($"{module}.Ids.g.cs", EmitIds(model, module, csNamespace))); + files.Add(new CsFile($"{module}.Structs.g.cs", EmitStructs(model, csNamespace))); + files.Add(new CsFile($"I{module}HostApi.g.cs", EmitHostApi(model, module, csNamespace))); + files.Add(new CsFile($"{module}.CoreCalls.g.cs", EmitCoreCalls(model, module, csNamespace))); + return files; + } + + public static List EmitAggregateFiles(IReadOnlyList modules) + { + var files = new List(); + files.Add(new CsFile("Bridge.AllCommandDispatcher.g.cs", EmitAllDispatcher(modules))); + return files; + } + + private static string AutoHeader() + { + return string.Join( + "\n", + "// ", + "// 由 Core/Tools/BridgeGen 生成,请勿手改。", + "// ", + "" + ); + } + + private static string EmitIds(ApiModel model, string module, string csNamespace) + { + var sb = new StringBuilder(); + sb.AppendLine(AutoHeader()); + sb.AppendLine("namespace " + csNamespace); + sb.AppendLine("{"); + sb.AppendLine(" public enum HostFuncId : uint"); + sb.AppendLine(" {"); + for (int i = 0; i < model.HostFns.Count; i++) + { + uint id = ComputeHostFuncId(module, model.HostFns[i].Name); + sb.AppendLine($" {model.HostFns[i].Name} = 0x{id:X8}u,"); + } + sb.AppendLine(" }"); + sb.AppendLine(); + sb.AppendLine(" public enum CoreFuncId : uint"); + sb.AppendLine(" {"); + for (int i = 0; i < model.CoreFns.Count; i++) + { + uint id = ComputeCoreFuncId(module, model.CoreFns[i].Name); + sb.AppendLine($" {model.CoreFns[i].Name} = 0x{id:X8}u,"); + } + sb.AppendLine(" }"); + sb.AppendLine("}"); + return sb.ToString(); + } + + private static string EmitAllDispatcher(IReadOnlyList modules) + { + var sb = new StringBuilder(); + sb.AppendLine(AutoHeader()); + sb.AppendLine("using Bridge.Core;"); + sb.AppendLine(); + sb.AppendLine("namespace Bridge.Bindings"); + sb.AppendLine("{"); + sb.AppendLine(" /// "); + sb.AppendLine(" /// 单次扫描 command stream,并按 func_id 分发到各模块 Host API。"); + sb.AppendLine(" /// "); + sb.AppendLine(" public static class BridgeAllCommandDispatcher"); + sb.AppendLine(" {"); + sb.AppendLine(" public static unsafe void Dispatch(CommandStream stream, THost host)"); + sb.Append(" where THost : class"); + + foreach (var m in modules) + { + if (m.Model.HostFns.Count == 0) + continue; + sb.Append(", "); + sb.Append(m.CsNamespace); + sb.Append(".I"); + sb.Append(m.Module); + sb.Append("HostApi"); + } + sb.AppendLine(); + sb.AppendLine(" {"); + sb.AppendLine(" if (stream.IsEmpty || host == null)"); + sb.AppendLine(" return;"); + sb.AppendLine(); + sb.AppendLine(" byte* cursor = (byte*)stream.Ptr;"); + sb.AppendLine(" byte* end = cursor + (int)stream.Length;"); + sb.AppendLine(); + sb.AppendLine(" while (cursor < end)"); + sb.AppendLine(" {"); + sb.AppendLine(" long remaining = end - cursor;"); + sb.AppendLine(" if (remaining < sizeof(BridgeCommandHeader))"); + sb.AppendLine(" break;"); + sb.AppendLine(); + sb.AppendLine(" var header = (BridgeCommandHeader*)cursor;"); + sb.AppendLine(" int size = header->Size;"); + sb.AppendLine(" if (size <= 0)"); + sb.AppendLine(" break;"); + sb.AppendLine(" if (size < sizeof(BridgeCommandHeader) || size > remaining)"); + sb.AppendLine(" break;"); + sb.AppendLine(); + sb.AppendLine(" if (header->Type == (ushort)BridgeCommandType.CallHost && size >= sizeof(BridgeCmdCallHost))"); + sb.AppendLine(" {"); + sb.AppendLine(" var cmd = (BridgeCmdCallHost*)cursor;"); + sb.AppendLine(" uint payloadSize = cmd->PayloadSize;"); + sb.AppendLine(" if (payloadSize <= (uint)(size - sizeof(BridgeCmdCallHost)))"); + sb.AppendLine(" {"); + sb.AppendLine(" byte* payloadPtr = cursor + sizeof(BridgeCmdCallHost);"); + sb.AppendLine(); + sb.AppendLine(" switch (cmd->FuncId)"); + sb.AppendLine(" {"); + + foreach (var m in modules) + { + if (m.Model.HostFns.Count == 0) + continue; + + foreach (var fn in m.Model.HostFns) + { + uint id = ComputeHostFuncId(m.Module, fn.Name); + sb.AppendLine($" case 0x{id:X8}u:"); + sb.AppendLine(" {"); + sb.Append(" if (payloadSize == (uint)sizeof("); + sb.Append(m.CsNamespace); + sb.Append(".HostArgs_"); + sb.Append(fn.Name); + sb.AppendLine("))"); + sb.AppendLine(" {"); + sb.Append(" var a = *(("); + sb.Append(m.CsNamespace); + sb.Append(".HostArgs_"); + sb.Append(fn.Name); + sb.AppendLine("*)payloadPtr);"); + sb.Append(" host."); + sb.Append(fn.Name); + sb.Append('('); + for (int i = 0; i < fn.Args.Count; i++) + { + if (i > 0) sb.Append(", "); + var arg = fn.Args[i]; + string field = $"a.{ToPascal(arg.Name)}"; + sb.Append(MapCsHostArgExpr(arg.CppType, field)); + } + sb.AppendLine(");"); + sb.AppendLine(" }"); + sb.AppendLine(" break;"); + sb.AppendLine(" }"); + } + } + + sb.AppendLine(" }"); + sb.AppendLine(" }"); + sb.AppendLine(" }"); + sb.AppendLine(); + sb.AppendLine(" cursor += size;"); + sb.AppendLine(" }"); + sb.AppendLine(" }"); + sb.AppendLine(" }"); + sb.AppendLine("}"); + return sb.ToString(); + } + + private static string EmitStructs(ApiModel model, string csNamespace) + { + var sb = new StringBuilder(); + sb.AppendLine(AutoHeader()); + sb.AppendLine("using System.Runtime.InteropServices;"); + sb.AppendLine("using Bridge.Core;"); + sb.AppendLine(); + sb.AppendLine("namespace " + csNamespace); + sb.AppendLine("{"); + + foreach (var fn in model.HostFns) + { + sb.AppendLine(" [StructLayout(LayoutKind.Sequential)]"); + sb.AppendLine($" public struct HostArgs_{fn.Name}"); + sb.AppendLine(" {"); + foreach (var arg in fn.Args) + sb.AppendLine($" public {MapCsInteropType(arg.CppType)} {ToPascal(arg.Name)};"); + sb.AppendLine(" }"); + sb.AppendLine(); + } + + foreach (var fn in model.CoreFns) + { + sb.AppendLine(" [StructLayout(LayoutKind.Sequential)]"); + sb.AppendLine($" public struct CoreArgs_{fn.Name}"); + sb.AppendLine(" {"); + foreach (var arg in fn.Args) + sb.AppendLine($" public {MapCsInteropType(arg.CppType)} {ToPascal(arg.Name)};"); + sb.AppendLine(" }"); + sb.AppendLine(); + } + + sb.AppendLine("}"); + return sb.ToString(); + } + + private static string EmitHostApi(ApiModel model, string module, string csNamespace) + { + var sb = new StringBuilder(); + sb.AppendLine(AutoHeader()); + sb.AppendLine("using Bridge.Core;"); + sb.AppendLine(); + sb.AppendLine("namespace " + csNamespace); + sb.AppendLine("{"); + sb.AppendLine($" public interface I{module}HostApi"); + sb.AppendLine(" {"); + foreach (var fn in model.HostFns) + { + sb.Append($" void {fn.Name}("); + for (int i = 0; i < fn.Args.Count; i++) + { + if (i > 0) sb.Append(", "); + var arg = fn.Args[i]; + sb.Append(MapCsHostArgType(arg.CppType)); + sb.Append(' '); + sb.Append(ToCamel(arg.Name)); + } + sb.AppendLine(");"); + } + sb.AppendLine(" }"); + sb.AppendLine("}"); + return sb.ToString(); + } + + private static string EmitCoreCalls(ApiModel model, string module, string csNamespace) + { + var sb = new StringBuilder(); + sb.AppendLine(AutoHeader()); + sb.AppendLine("using Bridge.Core;"); + sb.AppendLine(); + sb.AppendLine("namespace " + csNamespace); + sb.AppendLine("{"); + sb.AppendLine($" public static class {module}CoreCalls"); + sb.AppendLine(" {"); + foreach (var fn in model.CoreFns) + { + sb.Append($" public static void {fn.Name}(this BridgeCore core"); + foreach (var arg in fn.Args) + { + sb.Append(", "); + sb.Append(MapCsCoreCallArgType(arg.CppType)); + sb.Append(' '); + sb.Append(ToCamel(arg.Name)); + } + sb.AppendLine(")"); + sb.AppendLine(" {"); + sb.AppendLine($" var a = new CoreArgs_{fn.Name}"); + sb.AppendLine(" {"); + foreach (var arg in fn.Args) + sb.AppendLine($" {ToPascal(arg.Name)} = {ToCamel(arg.Name)},"); + sb.AppendLine(" };"); + sb.AppendLine($" core.PushCallCore((uint)CoreFuncId.{fn.Name}, a);"); + sb.AppendLine(" }"); + sb.AppendLine(); + } + sb.AppendLine(" }"); + sb.AppendLine("}"); + return sb.ToString(); + } + + private static string ToPascal(string name) + { + if (string.IsNullOrEmpty(name)) + return name; + return char.ToUpperInvariant(name[0]) + name.Substring(1); + } + + private static string ToCamel(string name) + { + if (string.IsNullOrEmpty(name)) + return name; + return char.ToLowerInvariant(name[0]) + name.Substring(1); + } + + private static string MapCsInteropType(string cppType) + { + return cppType switch + { + "uint64_t" => "ulong", + "uint32_t" => "uint", + "BridgeLogLevel" => "BridgeLogLevel", + "BridgeAssetType" => "BridgeAssetType", + "BridgeAssetStatus" => "BridgeAssetStatus", + "BridgeTransform" => "BridgeTransform", + "BridgeStringView" => "BridgeStringView", + _ => throw new InvalidOperationException($"未支持的 C++ 类型:{cppType}") + }; + } + + private static string MapCsHostArgType(string cppType) + { + return cppType switch + { + "BridgeStringView" => "string", + "BridgeLogLevel" => "BridgeLogLevel", + "BridgeAssetType" => "BridgeAssetType", + "BridgeAssetStatus" => "BridgeAssetStatus", + "BridgeTransform" => "BridgeTransform", + "uint64_t" => "ulong", + "uint32_t" => "uint", + _ => MapCsInteropType(cppType), + }; + } + + private static string MapCsCoreCallArgType(string cppType) + { + return MapCsHostArgType(cppType); + } + + private static string MapCsHostArgExpr(string cppType, string fieldExpr) + { + return cppType switch + { + "BridgeStringView" => $"{fieldExpr}.ToManagedString()", + _ => fieldExpr + }; + } + } +} diff --git a/Core/cpp/CMakeLists.txt b/Core/cpp/CMakeLists.txt new file mode 100644 index 0000000..27cd250 --- /dev/null +++ b/Core/cpp/CMakeLists.txt @@ -0,0 +1,22 @@ +cmake_minimum_required(VERSION 3.20) + +project(bridge_runtime LANGUAGES C CXX) + +add_library(bridge_runtime STATIC + src/core/command_stream.cpp + src/core/core_instance.cpp +) + +target_include_directories(bridge_runtime + PUBLIC + ${CMAKE_CURRENT_SOURCE_DIR}/include +) + +target_compile_features(bridge_runtime PUBLIC cxx_std_20) + +if (MSVC) + target_compile_options(bridge_runtime PRIVATE /W4 /permissive- /utf-8) +else() + target_compile_options(bridge_runtime PRIVATE -Wall -Wextra -Wpedantic) +endif() + diff --git a/Core/cpp/include/bridge/bridge.h b/Core/cpp/include/bridge/bridge.h new file mode 100644 index 0000000..b25ab4f --- /dev/null +++ b/Core/cpp/include/bridge/bridge.h @@ -0,0 +1,199 @@ +#pragma once + +#include +#include + +#if defined(_WIN32) + #define BRIDGE_CALL __cdecl + #if defined(BRIDGE_BUILD_DLL) + #define BRIDGE_API __declspec(dllexport) + #else + #define BRIDGE_API __declspec(dllimport) + #endif +#else + #define BRIDGE_CALL + #define BRIDGE_API __attribute__((visibility("default"))) +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +//------------------------------------------------------------------------------ +// 概览 +//------------------------------------------------------------------------------ +// +// 本文件定义 Core(C++)与 Host(C# / Unity 等)之间的“稳定 C ABI”。 +// +// 目标: +// - Core 尽可能只包含业务/数据/规则 +// - Host(引擎壳)提供渲染/资源/输入等能力 +// +// 关键约束: +// - Unity/IL2CPP 友好:避免 native->managed 回调 +// - 轮询式数据流: +// - Core -> Host:每帧产出 command stream(字节流) +// - Host -> Core:通过 BridgeCore_PushCallCore 推送“调用 Core API”的事件 +// +//------------------------------------------------------------------------------ +// Version +//------------------------------------------------------------------------------ + +#define BRIDGE_VERSION_MAJOR 0 +#define BRIDGE_VERSION_MINOR 2 +#define BRIDGE_VERSION_PATCH 0 + +typedef struct BridgeVersion +{ + uint32_t major; + uint32_t minor; + uint32_t patch; +} BridgeVersion; + +BRIDGE_API BridgeVersion BRIDGE_CALL Bridge_GetVersion(void); + +//------------------------------------------------------------------------------ +// Core types +//------------------------------------------------------------------------------ + +typedef struct BridgeCore BridgeCore; + +typedef enum BridgeResult +{ + BRIDGE_OK = 0, + BRIDGE_ERROR = 1, + BRIDGE_INVALID_ARGUMENT = 2 +} BridgeResult; + +typedef enum BridgeMode : uint32_t +{ + BRIDGE_MODE_GAME = 0, + BRIDGE_MODE_ROBOT = 1 +} BridgeMode; + +typedef struct BridgeCoreConfig +{ + uint64_t seed; + uint32_t mode; // BridgeMode + // 预留字段(用于未来 ABI 扩展),必须为 0。 + uint32_t reserved0; +} BridgeCoreConfig; + +BRIDGE_API BridgeCore* BRIDGE_CALL BridgeCore_Create(BridgeCoreConfig config); +BRIDGE_API void BRIDGE_CALL BridgeCore_Destroy(BridgeCore* core); + +//------------------------------------------------------------------------------ +// Common blittable structs +//------------------------------------------------------------------------------ + +typedef struct BridgeStringView +{ + // 指针值(UTF-8 字节),非 0 结尾。 + uint64_t ptr; + // 字节长度。 + uint32_t len; + // 预留字段(用于未来 ABI 扩展),必须为 0。 + uint32_t reserved0; +} BridgeStringView; + +typedef struct BridgeVec3 +{ + float x; + float y; + float z; + float reserved0; +} BridgeVec3; + +typedef struct BridgeQuat +{ + float x; + float y; + float z; + float w; +} BridgeQuat; + +typedef struct BridgeTransform +{ + BridgeVec3 position; + BridgeQuat rotation; + BridgeVec3 scale; +} BridgeTransform; + +//------------------------------------------------------------------------------ +// Common enums(可按需扩展/替换) +//------------------------------------------------------------------------------ + +typedef enum BridgeLogLevel : uint32_t +{ + BRIDGE_LOG_DEBUG = 0, + BRIDGE_LOG_INFO = 1, + BRIDGE_LOG_WARN = 2, + BRIDGE_LOG_ERROR = 3 +} BridgeLogLevel; + +typedef enum BridgeAssetType : uint32_t +{ + BRIDGE_ASSET_UNKNOWN = 0, + BRIDGE_ASSET_PREFAB = 1 +} BridgeAssetType; + +typedef enum BridgeAssetStatus : uint32_t +{ + BRIDGE_ASSET_STATUS_OK = 0, + BRIDGE_ASSET_STATUS_NOT_FOUND = 1, + BRIDGE_ASSET_STATUS_ERROR = 2 +} BridgeAssetStatus; + +//------------------------------------------------------------------------------ +// Commands (Core -> Host) +//------------------------------------------------------------------------------ + +typedef enum BridgeCommandType : uint16_t +{ + BRIDGE_CMD_NONE = 0, + // 通用 Host 调用:func_id + payload(由代码生成决定 payload 结构) + BRIDGE_CMD_CALL_HOST = 1 +} BridgeCommandType; + +typedef struct BridgeCommandHeader +{ + uint16_t type; // BridgeCommandType + // 命令总大小(包含 header+后续数据),必须 8 字节对齐 + uint16_t size; + uint32_t reserved0; +} BridgeCommandHeader; + +// 通用 Host 调用命令头: +// - payload 紧跟其后(payload_size 字节),并按 8 字节补齐到 header.size +typedef struct BridgeCmdCallHost +{ + BridgeCommandHeader header; + uint32_t func_id; + uint32_t payload_size; +} BridgeCmdCallHost; + +BRIDGE_API void BRIDGE_CALL BridgeCore_Tick(BridgeCore* core, float dt); + +// 返回最近一次 BridgeCore_Tick 生成的 command stream(连续字节流)指针。 +// 返回的内存由 Core 持有,只保证在下一次 BridgeCore_Tick(或 BridgeCore_Destroy)前有效。 +BRIDGE_API BridgeResult BRIDGE_CALL BridgeCore_GetCommandStream( + const BridgeCore* core, + const void** out_ptr, + uint32_t* out_len); + +//------------------------------------------------------------------------------ +// Calls (Host -> Core) +//------------------------------------------------------------------------------ + +// Host 调用 Core API(由代码生成决定 func_id 与 payload 结构)。 +// - payload 指向 blittable 数据(可为 null,当 payload_size==0) +BRIDGE_API BridgeResult BRIDGE_CALL BridgeCore_PushCallCore( + BridgeCore* core, + uint32_t func_id, + const void* payload, + uint32_t payload_size); + +#ifdef __cplusplus +} // extern "C" +#endif + diff --git a/Core/cpp/include/bridge/runtime/core_app.h b/Core/cpp/include/bridge/runtime/core_app.h new file mode 100644 index 0000000..a315644 --- /dev/null +++ b/Core/cpp/include/bridge/runtime/core_app.h @@ -0,0 +1,20 @@ +#pragma once + +#include + +namespace bridge +{ + class CoreContext; + + // 可插拔的业务/玩法层(由业务库实现)。 + // + // 说明: + // - Runtime 只负责:稳定 ABI、命令流缓冲、事件接收与分发时序 + // - ICoreApp 决定每帧输出哪些“Host 命令”(例如请求资源、创建实体等) + struct ICoreApp + { + virtual ~ICoreApp() = default; + virtual void Tick(CoreContext& ctx, float dt) = 0; + virtual void OnCallCore(CoreContext& ctx, uint32_t funcId, const void* payload, uint32_t payloadSize) = 0; + }; +} diff --git a/Core/cpp/include/bridge/runtime/core_context.h b/Core/cpp/include/bridge/runtime/core_context.h new file mode 100644 index 0000000..749ee26 --- /dev/null +++ b/Core/cpp/include/bridge/runtime/core_context.h @@ -0,0 +1,34 @@ +#pragma once + +#include + +#include +#include + +struct BridgeCore; + +namespace bridge +{ + // 业务层在 Tick/事件回调中使用的上下文对象(由 Runtime 创建并传入)。 + // + // 该类型属于 C++ 侧“业务/Runtime 接口”,不属于对外 C ABI(bridge.h)。 + class CoreContext + { + public: + explicit CoreContext(BridgeCore& core); + + const BridgeCoreConfig& Config() const; + uint64_t AllocRequestId(); + + BridgeStringView StoreUtf8(std::string utf8); + + // 向 Host 发起一次“函数调用”(具体 func_id 与 payload 结构由代码生成定义)。 + // payload 会被复制进 command stream,且 header.size 按 8 字节补齐。 + void CallHost(uint32_t funcId, const void* payload, uint32_t payloadSize); + + static BridgeTransform IdentityTransform(); + + private: + BridgeCore& core_; + }; +} diff --git a/Core/cpp/include/bridge/runtime/game_entry.h b/Core/cpp/include/bridge/runtime/game_entry.h new file mode 100644 index 0000000..516f266 --- /dev/null +++ b/Core/cpp/include/bridge/runtime/game_entry.h @@ -0,0 +1,13 @@ +#pragma once + +#include + +#include + +namespace bridge +{ + // 业务层入口:由最终链接产物(业务库/插件)提供实现。 + // Runtime 在 BridgeCore_Create 时调用该函数创建 ICoreApp。 + std::unique_ptr CreateGameApp(); +} + diff --git a/Core/cpp/src/api/bridge_api.cpp b/Core/cpp/src/api/bridge_api.cpp new file mode 100644 index 0000000..310ee19 --- /dev/null +++ b/Core/cpp/src/api/bridge_api.cpp @@ -0,0 +1,59 @@ +#include + +#include "../core/core_instance.h" + +//------------------------------------------------------------------------------ +// C ABI 实现(绑定层) +// +// 这个文件要尽量保持“朴素”:只做参数校验 + 转发到内部 C++ Runtime。 +// 业务/玩法逻辑应放在业务层或测试工程(例如 Tests/cpp/demo_game)。 +//------------------------------------------------------------------------------ + +BridgeVersion BRIDGE_CALL Bridge_GetVersion(void) +{ + return bridge::GetVersion(); +} + +BridgeCore* BRIDGE_CALL BridgeCore_Create(BridgeCoreConfig config) +{ + return bridge::CreateCore(config); +} + +void BRIDGE_CALL BridgeCore_Destroy(BridgeCore* core) +{ + bridge::DestroyCore(core); +} + +void BRIDGE_CALL BridgeCore_Tick(BridgeCore* core, float dt) +{ + if (!core) + { + return; + } + bridge::Tick(*core, dt); +} + +BridgeResult BRIDGE_CALL BridgeCore_GetCommandStream( + const BridgeCore* core, + const void** out_ptr, + uint32_t* out_len) +{ + if (!core) + { + return BRIDGE_INVALID_ARGUMENT; + } + return bridge::GetCommandStream(*core, out_ptr, out_len); +} + +BridgeResult BRIDGE_CALL BridgeCore_PushCallCore( + BridgeCore* core, + uint32_t func_id, + const void* payload, + uint32_t payload_size) +{ + if (!core) + { + return BRIDGE_INVALID_ARGUMENT; + } + return bridge::PushCallCore(*core, func_id, payload, payload_size); +} diff --git a/Core/cpp/src/core/command_stream.cpp b/Core/cpp/src/core/command_stream.cpp new file mode 100644 index 0000000..55d1e19 --- /dev/null +++ b/Core/cpp/src/core/command_stream.cpp @@ -0,0 +1,40 @@ +#include "command_stream.h" + +namespace bridge +{ + void CommandStream::Reserve(size_t commandBytesCapacity, size_t stringCountCapacity) + { + bytes_.reserve(commandBytesCapacity); + strings_.reserve(stringCountCapacity); + } + + void CommandStream::Clear() + { + bytes_.clear(); + strings_.clear(); + } + + BridgeStringView CommandStream::StoreUtf8(std::string utf8) + { + auto stored = std::make_unique(std::move(utf8)); + const char* p = stored->data(); + const uint32_t len = static_cast(stored->size()); + strings_.emplace_back(std::move(stored)); + + BridgeStringView view{}; + view.ptr = static_cast(reinterpret_cast(p)); + view.len = len; + return view; + } + + const uint8_t* CommandStream::Data() const + { + return bytes_.empty() ? nullptr : bytes_.data(); + } + + uint32_t CommandStream::Size() const + { + return static_cast(bytes_.size()); + } +} + diff --git a/Core/cpp/src/core/command_stream.h b/Core/cpp/src/core/command_stream.h new file mode 100644 index 0000000..7016c51 --- /dev/null +++ b/Core/cpp/src/core/command_stream.h @@ -0,0 +1,71 @@ +#pragma once + +#include + +#include +#include +#include +#include +#include +#include + +namespace bridge +{ + // Owns the per-frame command byte stream and any referenced string storage. + // The stream is exposed to the Host as a raw pointer + length. + // + // Lifetime: + // - Returned pointers are valid until the next Core tick clears the stream + // (or the core is destroyed). + class CommandStream + { + public: + void Reserve(size_t commandBytesCapacity, size_t stringCountCapacity); + void Clear(); + + // Store UTF-8 bytes and return a view that remains valid until Clear(). + BridgeStringView StoreUtf8(std::string utf8); + + void PushBytes(const void* data, size_t size) + { + if (!data || size == 0) + { + return; + } + const size_t oldSize = bytes_.size(); + bytes_.resize(oldSize + size); + std::memcpy(bytes_.data() + oldSize, data, size); + } + + void PushZeroBytes(size_t size) + { + if (size == 0) + { + return; + } + const size_t oldSize = bytes_.size(); + bytes_.resize(oldSize + size); + std::memset(bytes_.data() + oldSize, 0, size); + } + + template + void Push(const T& command) + { + static_assert(std::is_trivially_copyable::value, "Command must be trivially copyable"); + static_assert(std::is_standard_layout::value, "Command must be standard layout"); + static_assert(sizeof(T) % 8 == 0, "Command size must be 8-byte aligned"); + static_assert(sizeof(T) <= UINT16_MAX, "Command struct too large for header.size"); + + const size_t oldSize = bytes_.size(); + bytes_.resize(oldSize + sizeof(T)); + std::memcpy(bytes_.data() + oldSize, &command, sizeof(T)); + } + + const uint8_t* Data() const; + uint32_t Size() const; + + private: + std::vector bytes_; + std::vector> strings_; + }; +} diff --git a/Core/cpp/src/core/core_instance.cpp b/Core/cpp/src/core/core_instance.cpp new file mode 100644 index 0000000..44bbef9 --- /dev/null +++ b/Core/cpp/src/core/core_instance.cpp @@ -0,0 +1,191 @@ +#include "core_instance.h" + +#include +#include + +#include +#include +#include +#include + +namespace +{ + struct PendingCallHeader + { + uint32_t func_id = 0; + uint32_t payload_size = 0; + }; + + static uint32_t Align8(uint32_t x) + { + return (x + 7u) & ~7u; + } +} + +namespace bridge +{ + CoreContext::CoreContext(BridgeCore& core) + : core_(core) + { + } + + const BridgeCoreConfig& CoreContext::Config() const + { + return core_.config; + } + + uint64_t CoreContext::AllocRequestId() + { + return core_.next_request_id++; + } + + BridgeStringView CoreContext::StoreUtf8(std::string utf8) + { + return core_.commands.StoreUtf8(std::move(utf8)); + } + + void CoreContext::CallHost(uint32_t funcId, const void* payload, uint32_t payloadSize) + { + if (payloadSize > 0 && !payload) + { + return; + } + + const uint32_t totalSize = static_cast(sizeof(BridgeCmdCallHost)) + payloadSize; + const uint32_t alignedTotal = Align8(totalSize); + if (alignedTotal > UINT16_MAX) + { + return; + } + + BridgeCmdCallHost cmd{}; + cmd.header.type = BRIDGE_CMD_CALL_HOST; + cmd.header.size = static_cast(alignedTotal); + cmd.func_id = funcId; + cmd.payload_size = payloadSize; + + core_.commands.PushBytes(&cmd, sizeof(cmd)); + core_.commands.PushBytes(payload, payloadSize); + core_.commands.PushZeroBytes(alignedTotal - static_cast(sizeof(cmd)) - payloadSize); + } + + BridgeTransform CoreContext::IdentityTransform() + { + BridgeTransform tr{}; + tr.position = BridgeVec3{0, 0, 0, 0}; + tr.rotation = BridgeQuat{0, 0, 0, 1}; + tr.scale = BridgeVec3{1, 1, 1, 0}; + return tr; + } + + BridgeVersion GetVersion() + { + return BridgeVersion{ + BRIDGE_VERSION_MAJOR, + BRIDGE_VERSION_MINOR, + BRIDGE_VERSION_PATCH}; + } + + BridgeCore* CreateCore(BridgeCoreConfig config) + { + auto* core = new BridgeCore(); + core->config = config; + core->commands.Reserve(/*commandBytesCapacity*/ 1024, /*stringCountCapacity*/ 32); + core->pending_call_bytes.reserve(256); + core->app = CreateGameApp(); + if (!core->app) + { + delete core; + return nullptr; + } + return core; + } + + void DestroyCore(BridgeCore* core) + { + delete core; + } + + void Tick(BridgeCore& core, float dt) + { + // Per-frame command buffer. Data pointers become invalid after Clear(). + core.commands.Clear(); + + CoreContext ctx(core); + + // 先分发 Host->Core 调用,再跑本帧逻辑。 + const uint8_t* cur = core.pending_call_bytes.data(); + size_t remaining = core.pending_call_bytes.size(); + while (cur && remaining >= sizeof(PendingCallHeader)) + { + PendingCallHeader hdr{}; + std::memcpy(&hdr, cur, sizeof(hdr)); + cur += sizeof(hdr); + remaining -= sizeof(hdr); + + if (hdr.payload_size > remaining) + { + break; + } + + const void* payload = cur; + cur += hdr.payload_size; + remaining -= hdr.payload_size; + + const uint32_t pad = Align8(hdr.payload_size) - hdr.payload_size; + if (pad > remaining) + { + break; + } + cur += pad; + remaining -= pad; + + core.app->OnCallCore(ctx, hdr.func_id, payload, hdr.payload_size); + } + core.pending_call_bytes.clear(); + + core.app->Tick(ctx, std::max(0.0f, dt)); + } + + BridgeResult GetCommandStream( + const BridgeCore& core, + const void** out_ptr, + uint32_t* out_len) + { + if (!out_ptr || !out_len) + { + return BRIDGE_INVALID_ARGUMENT; + } + + *out_ptr = core.commands.Data(); + *out_len = core.commands.Size(); + return BRIDGE_OK; + } + + BridgeResult PushCallCore(BridgeCore& core, uint32_t funcId, const void* payload, uint32_t payloadSize) + { + if (payloadSize > 0 && !payload) + { + return BRIDGE_INVALID_ARGUMENT; + } + + PendingCallHeader hdr{}; + hdr.func_id = funcId; + hdr.payload_size = payloadSize; + + const size_t oldSize = core.pending_call_bytes.size(); + const uint32_t alignedPayload = Align8(payloadSize); + core.pending_call_bytes.resize(oldSize + sizeof(hdr) + alignedPayload); + + std::memcpy(core.pending_call_bytes.data() + oldSize, &hdr, sizeof(hdr)); + if (payloadSize > 0) + { + std::memcpy(core.pending_call_bytes.data() + oldSize + sizeof(hdr), payload, payloadSize); + } + if (alignedPayload > payloadSize) + { + std::memset(core.pending_call_bytes.data() + oldSize + sizeof(hdr) + payloadSize, 0, alignedPayload - payloadSize); + } + return BRIDGE_OK; + } +} diff --git a/Core/cpp/src/core/core_instance.h b/Core/cpp/src/core/core_instance.h new file mode 100644 index 0000000..e2f62a3 --- /dev/null +++ b/Core/cpp/src/core/core_instance.h @@ -0,0 +1,38 @@ +#pragma once + +#include +#include + +#include "command_stream.h" + +#include +#include +#include + +struct BridgeCore +{ + BridgeCoreConfig config{}; + uint64_t next_request_id = 1; + + bridge::CommandStream commands; + std::vector pending_call_bytes; + + std::unique_ptr app; +}; + +namespace bridge +{ + BridgeVersion GetVersion(); + + BridgeCore* CreateCore(BridgeCoreConfig config); + void DestroyCore(BridgeCore* core); + + void Tick(BridgeCore& core, float dt); + + BridgeResult GetCommandStream( + const BridgeCore& core, + const void** out_ptr, + uint32_t* out_len); + + BridgeResult PushCallCore(BridgeCore& core, uint32_t funcId, const void* payload, uint32_t payloadSize); +} diff --git a/Core/csharp/Bridge.Core/Bridge.Core.csproj b/Core/csharp/Bridge.Core/Bridge.Core.csproj new file mode 100644 index 0000000..6d2bfc3 --- /dev/null +++ b/Core/csharp/Bridge.Core/Bridge.Core.csproj @@ -0,0 +1,9 @@ + + + netstandard2.1 + latest + enable + true + Bridge.Core + + diff --git a/Core/csharp/Bridge.Core/BridgeCore.cs b/Core/csharp/Bridge.Core/BridgeCore.cs new file mode 100644 index 0000000..540fe45 --- /dev/null +++ b/Core/csharp/Bridge.Core/BridgeCore.cs @@ -0,0 +1,78 @@ +using System; + +namespace Bridge.Core +{ + /// + /// 原生 BridgeCore 的托管封装(Host 侧入口)。 + /// + public sealed class BridgeCore : IDisposable + { + private IntPtr _handle; + + public BridgeCore(ulong seed = 1, bool robotMode = false) + { + var cfg = new BridgeCoreConfig + { + Seed = seed, + Mode = (uint)(robotMode ? BridgeMode.Robot : BridgeMode.Game) + }; + + _handle = BridgeNative.BridgeCore_Create(cfg); + if (_handle == IntPtr.Zero) + throw new InvalidOperationException("BridgeCore_Create returned null"); + } + + /// + /// 推进 Core 一帧(或一个逻辑 tick)。 + /// + public void Tick(float dt) + { + ThrowIfDisposed(); + BridgeNative.BridgeCore_Tick(_handle, dt); + } + + /// + /// 获取最近一次 生成的命令字节流(command stream)。 + /// + /// + /// 返回指针由原生侧持有,只保证在下一次 (或 )前有效。 + /// + public CommandStream GetCommandStream() + { + ThrowIfDisposed(); + var result = BridgeNative.BridgeCore_GetCommandStream(_handle, out var ptr, out var len); + if (result != BridgeResult.Ok || ptr == IntPtr.Zero || len == 0) + return CommandStream.Empty; + + return new CommandStream(ptr, len); + } + + public void PushCallCore(uint funcId) + { + ThrowIfDisposed(); + BridgeNative.BridgeCore_PushCallCore(_handle, funcId, IntPtr.Zero, 0); + } + + public unsafe void PushCallCore(uint funcId, T payload) where T : unmanaged + { + ThrowIfDisposed(); + BridgeNative.BridgeCore_PushCallCore(_handle, funcId, (IntPtr)(&payload), (uint)sizeof(T)); + } + + public void Dispose() + { + if (_handle != IntPtr.Zero) + { + BridgeNative.BridgeCore_Destroy(_handle); + _handle = IntPtr.Zero; + } + GC.SuppressFinalize(this); + } + + private void ThrowIfDisposed() + { + if (_handle == IntPtr.Zero) + throw new ObjectDisposedException(nameof(BridgeCore)); + } + } +} diff --git a/Core/csharp/Bridge.Core/CommandStream.cs b/Core/csharp/Bridge.Core/CommandStream.cs new file mode 100644 index 0000000..cc6cdfe --- /dev/null +++ b/Core/csharp/Bridge.Core/CommandStream.cs @@ -0,0 +1,23 @@ +using System; + +namespace Bridge.Core +{ + /// + /// 原生侧返回的 command stream(指针 + 长度)。 + /// + public readonly struct CommandStream + { + public readonly IntPtr Ptr; + public readonly uint Length; + + public bool IsEmpty => Ptr == IntPtr.Zero || Length == 0; + + public static CommandStream Empty => new CommandStream(IntPtr.Zero, 0); + + internal CommandStream(IntPtr ptr, uint length) + { + Ptr = ptr; + Length = length; + } + } +} diff --git a/Core/csharp/Bridge.Core/Interop/BridgeNative.cs b/Core/csharp/Bridge.Core/Interop/BridgeNative.cs new file mode 100644 index 0000000..1d65fce --- /dev/null +++ b/Core/csharp/Bridge.Core/Interop/BridgeNative.cs @@ -0,0 +1,35 @@ +using System; +using System.Runtime.InteropServices; + +namespace Bridge.Core +{ + internal static class BridgeNative + { + private const string LibraryName = "bridge_core"; + + [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern BridgeVersion Bridge_GetVersion(); + + [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern IntPtr BridgeCore_Create(BridgeCoreConfig config); + + [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern void BridgeCore_Destroy(IntPtr core); + + [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern void BridgeCore_Tick(IntPtr core, float dt); + + [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern BridgeResult BridgeCore_GetCommandStream( + IntPtr core, + out IntPtr ptr, + out uint len); + + [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern BridgeResult BridgeCore_PushCallCore( + IntPtr core, + uint funcId, + IntPtr payload, + uint payloadSize); + } +} diff --git a/Core/csharp/Bridge.Core/Interop/Structs.cs b/Core/csharp/Bridge.Core/Interop/Structs.cs new file mode 100644 index 0000000..be9b104 --- /dev/null +++ b/Core/csharp/Bridge.Core/Interop/Structs.cs @@ -0,0 +1,120 @@ +using System; +using System.Runtime.InteropServices; + +namespace Bridge.Core +{ + public enum BridgeResult : int + { + Ok = 0, + Error = 1, + InvalidArgument = 2 + } + + public enum BridgeMode : uint + { + Game = 0, + Robot = 1 + } + + [StructLayout(LayoutKind.Sequential)] + public readonly struct BridgeVersion + { + public readonly uint Major; + public readonly uint Minor; + public readonly uint Patch; + } + + [StructLayout(LayoutKind.Sequential)] + public struct BridgeCoreConfig + { + public ulong Seed; + public uint Mode; + public uint Reserved0; + } + + [StructLayout(LayoutKind.Sequential)] + public readonly struct BridgeStringView + { + public readonly ulong Ptr; + public readonly uint Len; + public readonly uint Reserved0; + + public string ToManagedString() + { + if (Ptr == 0 || Len == 0) + return string.Empty; + + // netstandard2.1+ 支持按长度读取 UTF-8,避免额外分配 byte[]。 + return Marshal.PtrToStringUTF8(new IntPtr(unchecked((long)Ptr)), (int)Len) ?? string.Empty; + } + } + + public enum BridgeLogLevel : uint + { + Debug = 0, + Info = 1, + Warn = 2, + Error = 3 + } + + public enum BridgeAssetType : uint + { + Unknown = 0, + Prefab = 1 + } + + public enum BridgeAssetStatus : uint + { + Ok = 0, + NotFound = 1, + Error = 2 + } + + [StructLayout(LayoutKind.Sequential)] + public struct BridgeVec3 + { + public float X; + public float Y; + public float Z; + public float Reserved0; + } + + [StructLayout(LayoutKind.Sequential)] + public struct BridgeQuat + { + public float X; + public float Y; + public float Z; + public float W; + } + + [StructLayout(LayoutKind.Sequential)] + public struct BridgeTransform + { + public BridgeVec3 Position; + public BridgeQuat Rotation; + public BridgeVec3 Scale; + } + + [StructLayout(LayoutKind.Sequential)] + public struct BridgeCommandHeader + { + public ushort Type; + public ushort Size; + public uint Reserved0; + } + + public enum BridgeCommandType : ushort + { + None = 0, + CallHost = 1 + } + + [StructLayout(LayoutKind.Sequential)] + public struct BridgeCmdCallHost + { + public BridgeCommandHeader Header; + public uint FuncId; + public uint PayloadSize; + } +} diff --git a/Core/docs/BRIDGE_DESIGN.md b/Core/docs/BRIDGE_DESIGN.md new file mode 100644 index 0000000..cfd403c --- /dev/null +++ b/Core/docs/BRIDGE_DESIGN.md @@ -0,0 +1,121 @@ +# Core/Host Bridge 设计(v0.2) + +## 目标 + +将“业务/数据/规则”尽可能下沉到 C++ Core;引擎只作为渲染壳与必要能力提供者(Host)。 + +首期先跑通 **标准 .NET Host**,随后替换为 Unity Host(不改变 Core 架构)。 + +## 核心原则 + +1) **Core 不依赖引擎**:不包含 UnityEngine,不使用反射,不假设资源系统细节。 +2) **Host 来适配 Core**:现有模块按需要包一层实现 Host;Core API 固定且最小。 +3) **IL2CPP 友好**:避免 native→managed 回调(AOT/裁剪复杂),改用轮询 command stream。 +4) **接口可生成**:跨语言接口用 C++ 宏定义(标记“谁实现”),由生成器产出两侧代码。 +5) **机器人模式优先**:Core 可在 Headless Host 下运行,支持一进程成千上百实例压测。 + +## 数据边界 + +跨边界只允许: + +- blittable struct(固定布局,可内存拷贝) +- 句柄/ID(`uint64`) +- 字符串:UTF-8 `ptr+len`(只在 command stream 有效期内可读) + +禁止跨边界传递 Unity 对象、托管对象、List/Dictionary 等。 + +## 数据流 + +### Core → Host(命令) + +Core 每帧生成一个 **command stream**(字节序列),Host 拉取并执行。 + +v0.2 中 Core→Host 的命令统一为: + +- `BridgeCmdCallHost { func_id, payload_size, payload... }` + +具体有哪些“Host API”(例如 `LoadAsset` / `SpawnEntity` / `SetTransform` / `Log`)由业务层通过宏文件定义并生成代码。 + +### Host → Core(事件) + +Host 处理命令后以“调用 Core API”的方式回推(无需事件结构体一条条手写): + +- `BridgeCore_PushCallCore(core, func_id, payload, payload_size)` +- (后续)InputFrame / NetPacket / Lifecycle / UIEvent … 都是同一种机制 + +这样新增跨语言接口只需要改宏定义并重新生成,不需要改 Core 的稳定 ABI。 + +## 资源加载(以 Unity AB 为例) + +1) Core 通过生成的 Host API 发起 `LoadAsset(assetKey, requestId, type)`(写入 command stream) +2) Unity Host 收到后通过 AB 系统异步加载 +3) 加载完成后 Host 调用 Core API:`AssetLoaded(requestId, handle, status)`(内部用 `BridgeCore_PushCallCore` 实现) +4) Core 收到回调后继续输出后续 Host API(例如 `SpawnEntity(prefabHandle=handle)`) + +Core 只关心 `assetKey` 与 `handle`,不关心 AB 细节。 + +## 机器人模式 + +两种运行方式: + +1) **Headless Host + 多实例 Core**(推荐压测方式) + - Host 不执行渲染命令(Spawn/Transform 直接丢弃或只做统计) + - 资源加载可立即回执(或模拟延迟) + - 一进程 N 个 CoreInstance,单线程 tick(或分线程分区) + +2) Unity 内机器人 + - Unity Host 执行命令,适合功能验证,不适合千人压测 + +## 版本与兼容 + +- Native:C++20,CMake 构建,导出 C ABI(`cdecl`) +- Managed:C# `netstandard2.1`(Unity 兼容) + +稳定 ABI(`Core/cpp/include/bridge/bridge.h`)必须保持 layout 稳定。 + +业务接口(func_id 与 payload 结构)通过宏文件定义并由生成器产出: + +- 定义:`Tests/defs/*.def`(建议一个 `.def` 对应一个模块/子系统) +- 生成(C++):`Tests/cpp//generated/_bindings.generated.h` +- 生成(C# Host):`Tests/csharp/RobotHost/Generated/.*.g.cs` +- 生成(Unity Host):`Tests/unity/Assets/BridgeDemoGame/Generated/.*.g.cs` + +另外:生成器使用“模块名 + 函数名”计算稳定的 `func_id`(哈希),并在生成期检测冲突,避免模块拆分后 ID 因顺序变化而漂移。 + +## 分发策略与性能 + +Host 侧拿到 Core 输出的 `CommandStream` 后,需要把 `CallHost(func_id, payload...)` 分发到各模块的 Host API 实现。 + +为性能与 Unity/IL2CPP 友好,本仓库只保留一种分发策略(不依赖 native→managed 回调): + +- **单次扫描聚合分发(all)** + - 生成 `Bridge.Bindings.BridgeAllCommandDispatcher.Dispatch(stream, host)` + - 单 pass 扫描,并按 `func_id` 分发到各模块 Host API + - 模块化的边界仍然体现在:`IHostApi` / `*.Structs.g.cs` / `*.CoreCalls.g.cs` + +为降低 C# / Unity 开销: + +- 分发器使用 `unsafe` + `sizeof(T)` + 指针解引用读取 payload,避免 `Marshal.PtrToStructure` 的反射与分配。 +- Host→Core 的 `PushCallCore(payload)` 使用 `unmanaged` 泛型直接传栈上数据指针,避免 `AllocHGlobal`。 + +### 基准结果(示例) + +环境:Windows,Release,bots=1000,frames=300,dt=1/60。 + +- C#(`--host null`) + - `all`:约 14.95M cmd/s,分配 ~208KB +- C#(`--host full`) + - `all`:约 8.64M cmd/s,分配 ~488KB +- C++ 解析 baseline(仅解析 command stream):约 40.49M cmd/s +- Unity(EditMode / Performance Test Framework) + - `TickAndDispatch_OneFrame(1)`:Avg ~0.01 ms + - `TickAndDispatch_OneFrame(1000)`:Avg ~0.27 ms + +对应命令: + +```powershell +dotnet run --project Tests/csharp/RobotHost/RobotHost.csproj -c Release -- 1000 300 0.0166667 --host null +dotnet run --project Tests/csharp/RobotHost/RobotHost.csproj -c Release -- 1000 300 0.0166667 --host full +.\build\bin\Release\bridge_robot_runner.exe 1000 300 0.0166667 +& "C:\\Program Files\\Unity\\Hub\\Editor\\6000.0.40f1\\Editor\\Unity.exe" -runTests -batchmode -nographics -projectPath "D:\\UGit\\UnityNativeScripting\\Tests\\unity" -testPlatform EditMode -testResults "D:\\UGit\\UnityNativeScripting\\build\\unity-editmode-test-results.xml" -perfTestResults "D:\\UGit\\UnityNativeScripting\\build\\unity-editmode-perf-results.json" -logFile "D:\\UGit\\UnityNativeScripting\\build\\unity-editmode-test.log" +``` diff --git a/Core/docs/BUILD.md b/Core/docs/BUILD.md new file mode 100644 index 0000000..4b7b125 --- /dev/null +++ b/Core/docs/BUILD.md @@ -0,0 +1,88 @@ +# 构建与运行 + +## C++(C++20) + +在仓库根目录执行: + +```powershell +cmake -S . -B build -DCMAKE_BUILD_TYPE=Release +cmake --build build --config Release +``` + +(Windows / VS 多配置)默认输出到: + +- `build/bin/Release/bridge_core.dll` +- `build/bin/Release/bridge_robot_runner.exe` + +### 运行 C++ 机器人(Windows) + +```powershell +cd build/bin/Release +.\bridge_robot_runner.exe 1000 300 0.0166667 +``` + +### 运行 CTest(可选) + +```powershell +cd build +ctest -C Release +``` + +## C#(`netstandard2.1`,Unity 兼容) + +构建托管封装(Core 侧): + +```powershell +dotnet build Core/csharp/Bridge.Core/Bridge.Core.csproj -c Release +``` + +构建示例 Host(包含生成的绑定代码与绑定实现): + +```powershell +dotnet build Tests/csharp/RobotHost/RobotHost.csproj -c Release +``` + +### 运行 C# 机器人 Host(读文件模拟资源模块) + +默认资源根目录为:`Tests/assets`。 + +```powershell +# 先确保已编译出 build/bin/Release/bridge_core.dll +dotnet run --project Tests/csharp/RobotHost/RobotHost.csproj -c Release -- 1000 300 0.0166667 +``` + +如需用“空 Host”降低业务逻辑干扰(更接近桥接开销): + +```powershell +dotnet run --project Tests/csharp/RobotHost/RobotHost.csproj -c Release -- 1000 300 0.0166667 --host null +``` + +如需手动指定原生库目录(包含 `bridge_core.dll`): + +```powershell +$env:BRIDGE_NATIVE_DIR="D:\\UGit\\UnityNativeScripting\\build\\bin\\Release" +dotnet run --project Tests/csharp/RobotHost/RobotHost.csproj -c Release -- 1000 300 0.0166667 +``` + +## Unity(Windows Editor) + +Unity Host 示例工程位于:`Tests/unity`。 + +- 原生 DLL 加载采用 “Copy-Then-Load”(避免锁定构建产物),见:`Core/docs/UNITY_WIN_NATIVE_LOADING.md` +- DemoGame 范例使用说明见:`Tests/unity/Assets/BridgeDemoGame/README.md` + +## 代码生成(绑定) + +示例业务接口定义在:`Tests/defs/*.def`(示例拆为多个模块,例如 `demo_asset_api.def` / `demo_entity_api.def` / `demo_log_api.def`)。 + +运行生成器(会覆盖生成文件): + +```powershell +dotnet run --project Core/Tools/BridgeGen/BridgeGen.csproj -c Release -- +``` + +如需把 C# 绑定输出到 Unity 工程(示例): + +```powershell +dotnet run --project Core/Tools/BridgeGen/BridgeGen.csproj -c Release -- --out-cs Tests/unity/Assets/BridgeDemoGame/Generated +``` diff --git a/Core/docs/UNITY_WIN_NATIVE_LOADING.md b/Core/docs/UNITY_WIN_NATIVE_LOADING.md new file mode 100644 index 0000000..1a3ce10 --- /dev/null +++ b/Core/docs/UNITY_WIN_NATIVE_LOADING.md @@ -0,0 +1,66 @@ +# Unity(Windows)原生 DLL 加载方案(Editor 优先) + +目标:在 Unity Editor(Windows)中使用 `bridge_core.dll` 跑起来,同时支持“重编译后覆盖 DLL”而不被 Windows 文件锁卡死;出包阶段再切换到更标准的插件/源码编译方案。 + +## 背景:为什么会被锁 + +Windows 下一个 DLL 被进程加载后,其文件会被锁定(不能覆盖/删除)。Unity Editor 在域重载、脚本重编译、迭代调试时经常需要替换原生 DLL,如果直接加载固定路径(例如 `Assets/Plugins/.../bridge_core.dll`),就会出现: + +- C++ 重新编译输出无法覆盖(“正在被占用”) +- Unity 需要重启才能更新原生 DLL + +## 设计原则 + +1) **Editor 与 Player 分开处理**:Editor 追求可热替换;Player 追求稳定部署。 +2) **Editor 不直接锁定固定源文件**:实际加载前先复制到临时目录,再加载临时副本。 +3) **保持 `DllImport("bridge_core")` 名称稳定**:避免每次生成不同的 import 名称导致 C# 代码变更。 +4) **依赖 DLL 一起复制**:避免加载时从错误位置解析依赖。 + +## Editor(Windows)推荐方案:Copy-Then-Load + +### 目录约定 + +- 作为“源 DLL”的路径(可被覆盖):例如仓库构建产物 `../build/bin/Release/bridge_core.dll` +- 作为“实际加载”的临时目录(会被锁,但可换目录):`/Library/BridgeNative//` + +其中 `` 可以用 `LastWriteTimeUtc + FileSize` 或 hash 组合,保证每次编译变化都会得到新目录,从而绕过锁定。 + +### 加载步骤(Editor 启动/脚本域重载时) + +1) 从源目录拷贝: + - `bridge_core.dll` + - 同目录所有依赖 `.dll`(如果有) +2) 设置 DLL 搜索路径到临时目录: + - Windows API:`SetDllDirectoryW(tempDir)` +3) 主动加载临时 DLL: + - Windows API:`LoadLibraryW(tempDir\\bridge_core.dll)` + +这样: + +- 被锁的是 `Library/BridgeNative//bridge_core.dll` +- 源 DLL 仍可被 C++ 构建覆盖 + +### 与 Unity 插件导入的关系 + +为了避免 Unity Editor 自动加载并锁定 `Assets/Plugins` 下的 DLL,建议: + +- 通过 `PluginImporter` 把 `bridge_core.dll` 标记为 **不兼容 Editor**(仅用于 Player 平台) +- Editor 只通过上述 Copy-Then-Load 路径加载 + +## Player(Windows)建议方案 + +两种选择: + +1) **标准原生插件**:把 `bridge_core.dll` 放到 `Assets/Plugins/x86_64/`(或正确的平台目录),让 Unity 在 Player 中加载。 +2) **源码编译进 Player**:如果你的构建系统支持把 C++ 直接编译链接进 Unity Player(例如自定义构建管线),则 Player 不需要单独的 DLL 文件。 + +Player 通常不需要“复制到临时目录”来绕开锁问题,因为运行时不会频繁替换 DLL。 + +## 与本仓库的落地 + +本仓库提供一组 Unity 脚本(Windows)用于: + +- Editor:从“源 DLL”复制到 `Library/BridgeNative//` 并加载 +- Editor:可选的“同步 DLL 到 Assets/Plugins(仅用于出包)”工具 + +对应实现位于 `Tests/unity/Assets/BridgeCore/`(不提交二进制 DLL)。 diff --git a/README.md b/README.md index 8b108f6..28e6e2c 100644 --- a/README.md +++ b/README.md @@ -1,239 +1,62 @@ -# Unity Native Scripting +# UnityNativeScripting(Core-first 重构) -A library to allow writing Unity scripts in native code: C, C++, assembly. +本仓库用于验证与迭代一套 **Core-first** 架构: -## Purpose +- 业务/数据/规则尽可能下沉到 **C++ Core** +- 引擎(Unity/自研)只作为渲染壳与必须能力提供者(Host) +- 为了 IL2CPP/AOT 友好,避免 native→managed 回调,改用 **轮询式数据流** + - Core → Host:每帧输出 command stream(字节流) + - Host → Core:通过稳定 C ABI 推送事件(`PushCallCore`) -This project aims to give you a viable alternative to C#. Scripting in C++ isn't right for all parts of every project, but now it's an option. +## 目录 -## Goals +- `Core/`:运行时核心(C++20 + C# `netstandard2.1`) +- `Core/Tools/`:代码生成工具(绑定生成) +- `Tests/`:示例业务、机器人压测、标准 .NET Host +- `Tests/unity/`:Unity Host 范例工程(Windows Editor 下 Copy-Then-Load) -* Make scripting in C++ as easy as C# -* Low performance overhead -* Easy integration with any Unity project -* Fast compile, build, and code generation times -* Don't lose support from Unity Technologies +## 快速开始 -# Reasons to Prefer C++ Over C# # +### 1) 构建 C++(产出 `bridge_core.dll`) -## Fast Device Build Times +```powershell +cmake -S . -B build -DCMAKE_BUILD_TYPE=Release +cmake --build build --config Release +``` -Changing one line of C# code requires you to make a new build of the game. Typical Android build times tend to be at least 10 minutes because IL2CPP has to run and then a huge amount of C++ must be compiled. +### 2) 运行 C++ 机器人(可选) -By using C++, we can compile the game as a C++ plugin in about 1 second, swap the plugin into the APK, and then immediately install and run the game. That's a huge productivity boost! +```powershell +cd build/bin/Release +.\bridge_robot_runner.exe 1000 300 0.0166667 +``` -## Fast Compile Times +### 3) 运行标准 C# Host(RobotHost) -C++ [compiles much more quickly](https://github.com/jacksondunstan/cscppcompiletimes) than C#. Incremental builds when just one file changes-- the most common builds-- can be 15x faster than with C#. Faster compilation adds up over time to productivity gains. Quicker iteration times make it easier to stay in the "flow" of programming. +```powershell +dotnet run --project Tests/csharp/RobotHost/RobotHost.csproj -c Release -- 1000 300 0.0166667 +``` -## No Garbage Collector +如需用“空 Host”降低业务逻辑干扰(更接近桥接开销): -Unity's garbage collector is mandatory and has a lot of problems. It's slow, runs on the main thread, collects all garbage at once, fragments the heap, and never shrinks the heap. So your game will experience "frame hitches" and eventually you'll run out of memory and crash. +```powershell +dotnet run --project Tests/csharp/RobotHost/RobotHost.csproj -c Release -- 1000 300 0.0166667 --host null +``` -A significant amount of effort is required to work around the GC and the resulting code is difficult to maintain and slow. This includes techniques like [object pools](https://jacksondunstan.com/articles/3829), which essentially make memory management manual. You've also got to avoid boxing value types like `int` to to managed types like `object`, not use `foreach` loops in some situations, and various other [gotchas](https://jacksondunstan.com/articles/3850). +### 4) 生成绑定(扫描 `Tests/defs/*.def`) -C++ has no required garbage collector and features optional automatic memory management via "smart pointer" types like [shared_ptr](http://en.cppreference.com/w/cpp/memory/shared_ptr). It offers excellent alternatives to Unity's primitive garbage collector. +```powershell +dotnet run --project Core/Tools/BridgeGen/BridgeGen.csproj -c Release -- +``` -While using some .NET APIs will still involve garbage creation, the problem is contained to only those APIs rather than being a pervasive issue for all your code. +如需把 C# 绑定输出到 Unity 工程(示例): -## Total Control +```powershell +dotnet run --project Core/Tools/BridgeGen/BridgeGen.csproj -c Release -- --out-cs Tests/unity/Assets/BridgeDemoGame/Generated +``` -By using C++ directly, you gain complete control over the code the CPU will execute. It's much easier to generate optimal code with a C++ compiler than with a C# compiler, IL2CPP, and finally a C++ compiler. Cut out the middle-man and you can take advantage of compiler intrinsics or assembly to directly write machine code using powerful CPU features like [SIMD](https://jacksondunstan.com/articles/3890) and hardware AES encryption for massive performance gains. +## 文档 -## More Features - -C++ is a much larger language than C# and some developers will prefer having more tools at their disposal. Here are a few differences: - -* Its template system is much more powerful than C# generics -* There are macros for extreme flexibility by generating code -* Cheap function pointers instead of heavyweight delegates -* No-overhead [algorithms](http://en.cppreference.com/w/cpp/algorithm) instead of LINQ -* Bit fields for easy memory savings -* Pointers and never-null references instead of just managed references -* Much more. C++ is huge. - -## No IL2CPP Surprises - -While IL2CPP transforms C# into C++ already, it generates a lot of overhead. There are many [surprises](https://jacksondunstan.com/articles/3916) if you read through the generated C++. For example, there's overhead for any function using a static variable and an extra two pointers are stored at the beginning of every class. The same goes for all sorts of features such as `sizeof()`, mandatory null checks, and so forth. Instead, you could write C++ directly and not need to work around IL2CPP. - -## Industry Standard Language - -C++ is the standard language for video games as well as many other fields. By programming in C++ you can more easily transfer your skills and code to and from non-Unity projects. For example, you can avoid lock-in by using the same language (C++) that you'd use in the [Unreal](https://www.unrealengine.com) or [Lumberyard](https://aws.amazon.com/lumberyard/) engines. - -# UnityNativeScripting Features - -* Code generator exposes any C# API to C++ -* Supports Windows, macOS, Linux, iOS, and Android (editor and standalone) -* Works with Unity 2017.x and 5.x -* Plays nice with other C# scripts- no need to use 100% C++ -* Object-oriented API just like in C# - -> - GameObject go; - Transform transform = go.GetTransform(); - Vector3 position(1.0f, 2.0f, 3.0f); - transform.SetPosition(position); - -* Hot reloading: change C++ without restarting the game -* Handle `MonoBehaviour` messages in C++ - -> - void MyScript::Start() - { - String message("MyScript has started"); - Debug::Log(message); - } - -* Platform-dependent compilation (e.g. `#if TARGET_OS_ANDROID`) -* [CMake](https://cmake.org/) build system sets up any IDE project or command-line build - -# Code Generator - -The core of this project is a code generator. It generates C# and C++ code called "bindings" that make C# APIs available to C++ game code. It supports a wide range of language features: - -* Types - * `class` - * `struct` - * `enum` - * Arrays (single- and multi-dimensional) - * Delegates (e.g. `Action`) - * `decimal` -* Type Contents - * Constructors - * Methods - * Fields - * Properties (`get` and `set` like `obj.x`) - * Indexers (`get` and `set` like `obj[x]`) - * Events (`add` and `remove` delegates) - * Overloaded operators - * Boxing and unboxing (e.g. casting `int` to `object` and visa versa) -* Function Features - * `out` and `ref` parameters - * Generic types and methods - * Default parameters -* Cross-Language Features - * Exceptions (C# to C++ and C++ to C#) - * Implementing C# interfaces with C++ classes - * Deriving from C# classes with C++ classes - -Note that the code generator does not yet support: - -* `Array`, `string`, and `object` methods (e.g. `GetHashCode`) -* Non-null string default parameters and null non-string default parameters -* Implicit `params` parameter (a.k.a. "var args") passing -* C# pointers -* Nested types -* Down-casting - -To configure the code generator, open `Unity/Assets/NativeScriptTypes.json` and notice the existing examples. Add on to this file to expose more C# APIs from Unity, .NET, or custom DLLs to your C++ code. - -To run the code generator, choose `NativeScript > Generate Bindings` from the Unity editor. - -# Performance - -Almost all projects will see a net performance win by reducing garbage collection, eliminating IL2CPP overhead, and access to compiler intrinsics and assembly. Calls from C++ into C# incur only a minor performance penalty. In the rare case that almost all of your code is calls to .NET APIs then you may experience a net performance loss. - -[Testing and benchmarks article](https://jacksondunstan.com/articles/3952) - -[Optimizations article](https://jacksondunstan.com/articles/4311) - -# Project Structure - -When scripting in C++, C# is used only as a "binding" layer so Unity can call C++ functions and C++ functions can call the Unity API. A code generator is used to generate most of these bindings according to the needs of your project. - -All of your code, plus a few bindings, will exist in a single "native" C++ plugin. When you change your C++ code, you'll build this plugin and then play the game in the editor or in a deployed build (e.g. to an Android device). There won't be any C# code for Unity to compile unless you run the code generator, which is infrequent. - -The standard C# workflow looks like this: - -1. Edit C# code in a C# IDE like MonoDevelop -2. Switch to the Unity editor window -3. Wait for the compile to finish (slow, "real" games take 5+ seconds) -4. Run the game - -With C++, the workflow looks like this: - -1. Edit C++ code in a C++ IDE like Xcode or Visual Studio -2. Build the C++ plugin (extremely fast, often under 1 second) -3. Switch to the Unity editor window. Nothing to compile. -4. Run the game - -# Getting Started - -1. Download or clone this repo -2. Copy everything in `Unity/Assets` directory to your Unity project's `Assets` directory -3. Edit `NativeScriptTypes.json` and specify what parts of the Unity, .NET, and custom DLL APIs you want access to from C++. -4. Edit `Unity/Assets/CppSource/Game/Game.cpp` and `Unity/Assets/CppSource/Game/Game.h` to create your game. Some example code is provided, but feel free to delete it. You can add more C++ source (`.cpp`) and header (`.h`) files here as your game grows. - -# Building the C++ Plugin - -## iOS - -1. Install [CMake](https://cmake.org/) version 3.6 or greater -2. Create a directory for build files. Anywhere is fine. -3. Open the Terminal app in `/Applications/Utilities` -4. Execute `cd /path/to/your/build/directory` -5. Execute `cmake -G MyGenerator -DCMAKE_TOOLCHAIN_FILE=/path/to/your/project/CppSource/iOS.cmake /path/to/your/project/CppSource`. Replace `MyGenerator` with the generator of your choice. To see the options, execute `cmake --help` and look at the list at the bottom. Common choices include "Unix Makefiles" to build from command line or "Xcode" to use Apple's IDE. -6. The build scripts or IDE project files are now generated in your build directory -7. Build as appropriate for your generator. For example, execute `make` if you chose `Unix Makefiles` as your generator or open `NativeScript.xcodeproj` and click `Product > Build` if you chose Xcode. - -## macOS (Editor and Standalone) - -1. Install [CMake](https://cmake.org/) version 3.6 or greater -2. Create a directory for build files. Anywhere is fine. -3. Open the Terminal app in `/Applications/Utilities` -4. Execute `cd /path/to/your/build/directory` -5. Execute `cmake -G "MyGenerator" -DEDITOR=TRUE /path/to/your/project/CppSource`. Replace `MyGenerator` with the generator of your choice. To see the options, execute `cmake --help` and look at the list at the bottom. Common choices include "Unix Makefiles" to build from command line or "Xcode" to use Apple's IDE. Remove `-DEDITOR=TRUE` for standalone builds. -6. The build scripts or IDE project files are now generated in your build directory -7. Build as appropriate for your generator. For example, execute `make` if you chose `Unix Makefiles` as your generator or open `NativeScript.xcodeproj` and click `Product > Build` if you chose Xcode. - -## Windows (Editor and Standalone) - -1. Install [CMake](https://cmake.org/) version 3.6 or greater -2. Create a directory for build files. Anywhere is fine. -3. Open a Command Prompt by clicking the Start button, typing "Command Prompt", then clicking the app -4. Execute `cd /path/to/your/build/directory` -5. Execute `cmake -G "Visual Studio VERSION YEAR Win64" -DEDITOR=TRUE /path/to/your/project/CppSource`. Replace `VERSION` and `YEAR` with the version of Visual Studio you want to use. To see the options, execute `cmake --help` and look at the list at the bottom. For example, use `"Visual Studio 15 2017 Win64"` for Visual Studio 2017. Any version, including Community, works just fine. Remove `-DEDITOR=TRUE` for standalone builds. If you are using Visual Studio 2019, execute `cmake -G "Visual Studio 16" -A "x64" -DEDITOR=TRUE /path/to/your/project/CppSource` instead. -6. The project files are now generated in your build directory -7. Open `NativeScript.sln` and click `Build > Build Solution`. - -## Linux (Editor and Standalone) - -1. Install [CMake](https://cmake.org/) version 3.6 or greater -2. Create a directory for build files. Anywhere is fine. -3. Open a terminal as appropriate for your Linux distribution -4. Execute `cd /path/to/your/build/directory` -5. Execute `cmake -G "MyGenerator" -DEDITOR=TRUE /path/to/your/project/CppSource`. Replace `MyGenerator` with the generator of your choice. To see the options, execute `cmake --help` and look at the list at the bottom. The most common choice is "Unix Makefiles" to build from command line, but there are IDE options too. Remove `-DEDITOR=TRUE` for standalone builds. -6. The build scripts or IDE project files are now generated in your build directory -7. Build as appropriate for your generator. For example, execute `make` if you chose `Unix Makefiles` as your generator. - -## Android - -1. Install [CMake](https://cmake.org/) version 3.6 or greater -2. Create a directory for build files. Anywhere is fine. -3. Open a terminal (macOS, Linux) or Command Prompt (Windows) -4. Execute `cd /path/to/your/build/directory` -5. Execute `cmake -G MyGenerator -DANDROID_NDK=/path/to/android/ndk /path/to/your/project/CppSource`. Replace `MyGenerator` with the generator of your choice. To see the options, execute `cmake --help` and look at the list at the bottom. To make a build for any platform other than Android, omit the `-DANDROID_NDK=/path/to/android/ndk` part. -6. The build scripts or IDE project files are now generated in your build directory -7. Build as appropriate for your generator. For example, execute `make` if you chose `Unix Makefiles` as your generator. - -# Updating To A New Version - -To update to a new version of this project, overwrite your Unity project's `Assets/NativeScript` directory with this project's `Unity/Assets/NativeScript` directory and re-run the code generator. - -# Reference - -[Articles](https://jacksondunstan.com/articles/3938) by the author describing the development of this project. - -# Author - -[Jackson Dunstan](https://jacksondunstan.com) - -# Contributing - -Please feel free to fork and send [pull requests](https://github.com/jacksondunstan/UnityNativeScripting/pulls) or simply submit an [issue](https://github.com/jacksondunstan/UnityNativeScripting/issues) for features or bug fixes. - -# License - -All code is licensed [MIT](https://opensource.org/licenses/MIT), which means it can usually be easily used in commercial and non-commercial applications. - -All writing is licensed [CC BY 4.0](https://creativecommons.org/licenses/by/4.0/), which means it can be used as long as attribution is given. \ No newline at end of file +- 架构设计:`Core/docs/BRIDGE_DESIGN.md` +- 构建与运行:`Core/docs/BUILD.md` +- Unity Windows 原生库加载:`Core/docs/UNITY_WIN_NATIVE_LOADING.md` diff --git a/Tests/README.md b/Tests/README.md new file mode 100644 index 0000000..6e5f2c3 --- /dev/null +++ b/Tests/README.md @@ -0,0 +1,10 @@ +# Tests(机器人/验证) + +本目录用于验证 “Core(C++)⇄ Host(C#)” 的最小闭环,以及后续压测(机器人模式)。 + +- `Tests/cpp/robot_runner`:C++ 机器人 runner(快速压测/跑通 ABI)。 +- `Tests/csharp/RobotHost`:标准 .NET Host(读 `Tests/assets` 模拟资源模块,并通过 `PushCallCore` 回推 `AssetLoaded`)。 +- `Tests/unity`:Unity Host 范例工程(Windows Editor 下演示 Copy-Then-Load,并用 Unity `Resources` API 实现 `LoadAsset`)。 +- `Tests/assets`:测试资源(示例文件)。 + +运行方式见:`Core/docs/BUILD.md`。 diff --git a/Tests/assets/Main/Prefabs/Bot.bytes b/Tests/assets/Main/Prefabs/Bot.bytes new file mode 100644 index 0000000..d35bbad --- /dev/null +++ b/Tests/assets/Main/Prefabs/Bot.bytes @@ -0,0 +1,2 @@ +DemoPrefab: Bot + diff --git a/Tests/cpp/CMakeLists.txt b/Tests/cpp/CMakeLists.txt new file mode 100644 index 0000000..dbe9a28 --- /dev/null +++ b/Tests/cpp/CMakeLists.txt @@ -0,0 +1,2 @@ +add_subdirectory(demo_game) +add_subdirectory(robot_runner) diff --git a/Tests/cpp/demo_asset/generated/demo_asset_bindings.generated.h b/Tests/cpp/demo_asset/generated/demo_asset_bindings.generated.h new file mode 100644 index 0000000..8e50fa5 --- /dev/null +++ b/Tests/cpp/demo_asset/generated/demo_asset_bindings.generated.h @@ -0,0 +1,46 @@ +#pragma once + +#include +#include + +#include +#include +#include + +namespace demo_asset +{ + enum class HostFuncId : uint32_t + { + LoadAsset = 0x82A5E93Au, + }; + + enum class CoreFuncId : uint32_t + { + AssetLoaded = 0x2442BC8Au, + }; + + struct HostArgs_LoadAsset + { + uint64_t requestId; + BridgeAssetType assetType; + BridgeStringView assetKey; + }; + + struct CoreArgs_AssetLoaded + { + uint64_t requestId; + uint64_t handle; + BridgeAssetStatus status; + }; + + // Core -> Host 调用(写入 command stream) + inline void LoadAsset(bridge::CoreContext& ctx, uint64_t requestId, BridgeAssetType assetType, std::string_view assetKey) + { + HostArgs_LoadAsset a{}; + a.requestId = requestId; + a.assetType = assetType; + a.assetKey = ctx.StoreUtf8(std::string(assetKey)); + ctx.CallHost(static_cast(HostFuncId::LoadAsset), &a, static_cast(sizeof(a))); + } + +} // namespace demo_asset diff --git a/Tests/cpp/demo_entity/generated/demo_entity_bindings.generated.h b/Tests/cpp/demo_entity/generated/demo_entity_bindings.generated.h new file mode 100644 index 0000000..8509a1a --- /dev/null +++ b/Tests/cpp/demo_entity/generated/demo_entity_bindings.generated.h @@ -0,0 +1,70 @@ +#pragma once + +#include +#include + +#include +#include +#include + +namespace demo_entity +{ + enum class HostFuncId : uint32_t + { + SpawnEntity = 0xBCAA331Du, + SetTransform = 0x20DA0B6Fu, + DestroyEntity = 0xC7C1C59Cu, + }; + + enum class CoreFuncId : uint32_t + { + }; + + struct HostArgs_SpawnEntity + { + uint64_t entityId; + uint64_t prefabHandle; + BridgeTransform transform; + uint32_t flags; + }; + + struct HostArgs_SetTransform + { + uint64_t entityId; + uint32_t mask; + BridgeTransform transform; + }; + + struct HostArgs_DestroyEntity + { + uint64_t entityId; + }; + + // Core -> Host 调用(写入 command stream) + inline void SpawnEntity(bridge::CoreContext& ctx, uint64_t entityId, uint64_t prefabHandle, BridgeTransform transform, uint32_t flags) + { + HostArgs_SpawnEntity a{}; + a.entityId = entityId; + a.prefabHandle = prefabHandle; + a.transform = transform; + a.flags = flags; + ctx.CallHost(static_cast(HostFuncId::SpawnEntity), &a, static_cast(sizeof(a))); + } + + inline void SetTransform(bridge::CoreContext& ctx, uint64_t entityId, uint32_t mask, BridgeTransform transform) + { + HostArgs_SetTransform a{}; + a.entityId = entityId; + a.mask = mask; + a.transform = transform; + ctx.CallHost(static_cast(HostFuncId::SetTransform), &a, static_cast(sizeof(a))); + } + + inline void DestroyEntity(bridge::CoreContext& ctx, uint64_t entityId) + { + HostArgs_DestroyEntity a{}; + a.entityId = entityId; + ctx.CallHost(static_cast(HostFuncId::DestroyEntity), &a, static_cast(sizeof(a))); + } + +} // namespace demo_entity diff --git a/Tests/cpp/demo_game/CMakeLists.txt b/Tests/cpp/demo_game/CMakeLists.txt new file mode 100644 index 0000000..3f36183 --- /dev/null +++ b/Tests/cpp/demo_game/CMakeLists.txt @@ -0,0 +1,45 @@ +cmake_minimum_required(VERSION 3.20) + +project(bridge_demo_game LANGUAGES C CXX) + +add_library(bridge_demo_game STATIC + src/demo_asset_app.cpp + src/game_entry.cpp +) + +target_link_libraries(bridge_demo_game PUBLIC bridge_runtime) +target_compile_features(bridge_demo_game PUBLIC cxx_std_20) + +target_include_directories(bridge_demo_game PRIVATE + ${CMAKE_SOURCE_DIR}/Tests/cpp/demo_asset/generated + ${CMAKE_SOURCE_DIR}/Tests/cpp/demo_entity/generated + ${CMAKE_SOURCE_DIR}/Tests/cpp/demo_log/generated +) + +if (MSVC) + target_compile_options(bridge_demo_game PRIVATE /W4 /permissive- /utf-8) +else() + target_compile_options(bridge_demo_game PRIVATE -Wall -Wextra -Wpedantic) +endif() + +add_library(bridge_core SHARED + ${CMAKE_SOURCE_DIR}/Core/cpp/src/api/bridge_api.cpp +) + +target_link_libraries(bridge_core PRIVATE bridge_demo_game PUBLIC bridge_runtime) +target_compile_features(bridge_core PUBLIC cxx_std_20) + +if (MSVC) + target_compile_options(bridge_core PRIVATE /W4 /permissive- /utf-8) +else() + target_compile_options(bridge_core PRIVATE -Wall -Wextra -Wpedantic) +endif() + +target_compile_definitions(bridge_core PRIVATE BRIDGE_BUILD_DLL=1) + +set_target_properties(bridge_core PROPERTIES + OUTPUT_NAME "bridge_core" + RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin/$" + LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin/$" + ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib/$" +) diff --git a/Tests/cpp/demo_game/src/demo_asset_app.cpp b/Tests/cpp/demo_game/src/demo_asset_app.cpp new file mode 100644 index 0000000..0e5665c --- /dev/null +++ b/Tests/cpp/demo_game/src/demo_asset_app.cpp @@ -0,0 +1,90 @@ +#include "demo_asset_app.h" + +#include + +#include +#include +#include + +#include + +namespace bridge +{ + namespace + { + // 最小示例 App(用于验证数据流): + // - 请求一个 Prefab 资源 + // - 资源加载完成后 Spawn 一个实体 + // - 每帧更新 Transform + class DemoAssetApp final : public ICoreApp + { + public: + void Tick(CoreContext& ctx, float dt) override + { + if (!startup_asset_requested_) + { + startup_asset_requested_ = true; + startup_request_id_ = ctx.AllocRequestId(); + demo_log::Log(ctx, BRIDGE_LOG_INFO, "Requesting startup prefab asset"); + demo_asset::LoadAsset(ctx, startup_request_id_, BRIDGE_ASSET_PREFAB, "Main/Prefabs/Bot"); + } + + if (startup_asset_ready_ && !entity_spawned_) + { + entity_spawned_ = true; + demo_entity::SpawnEntity(ctx, entity_id_, startup_asset_handle_, CoreContext::IdentityTransform(), /*flags*/ 0); + } + + if (entity_spawned_) + { + t_ += dt; + BridgeTransform tr = CoreContext::IdentityTransform(); + tr.position.x = t_; + demo_entity::SetTransform(ctx, entity_id_, /*mask*/ 1u, tr); + } + } + + void OnCallCore(CoreContext& ctx, uint32_t funcId, const void* payload, uint32_t payloadSize) override + { + if (funcId != static_cast(demo_asset::CoreFuncId::AssetLoaded) || + payloadSize != sizeof(demo_asset::CoreArgs_AssetLoaded) || + !payload) + { + return; + } + + const auto& evt = *reinterpret_cast(payload); + + if (evt.requestId != startup_request_id_) + { + return; + } + if (evt.status != BRIDGE_ASSET_STATUS_OK) + { + demo_log::Log(ctx, BRIDGE_LOG_ERROR, "Startup asset failed to load"); + return; + } + + startup_asset_ready_ = true; + startup_asset_handle_ = evt.handle; + demo_log::Log(ctx, BRIDGE_LOG_INFO, "Startup asset loaded"); + } + + private: + uint64_t startup_request_id_ = 0; + bool startup_asset_requested_ = false; + bool startup_asset_ready_ = false; + uint64_t startup_asset_handle_ = 0; + + bool entity_spawned_ = false; + uint64_t entity_id_ = 1; + + float t_ = 0.0f; + }; + } + + std::unique_ptr CreateDemoAssetApp() + { + return std::make_unique(); + } +} diff --git a/Tests/cpp/demo_game/src/demo_asset_app.h b/Tests/cpp/demo_game/src/demo_asset_app.h new file mode 100644 index 0000000..8ca8f89 --- /dev/null +++ b/Tests/cpp/demo_game/src/demo_asset_app.h @@ -0,0 +1,10 @@ +#pragma once + +#include + +#include + +namespace bridge +{ + std::unique_ptr CreateDemoAssetApp(); +} diff --git a/Tests/cpp/demo_game/src/game_entry.cpp b/Tests/cpp/demo_game/src/game_entry.cpp new file mode 100644 index 0000000..745094b --- /dev/null +++ b/Tests/cpp/demo_game/src/game_entry.cpp @@ -0,0 +1,12 @@ +#include + +#include "demo_asset_app.h" + +namespace bridge +{ + std::unique_ptr CreateGameApp() + { + return CreateDemoAssetApp(); + } +} + diff --git a/Tests/cpp/demo_log/generated/demo_log_bindings.generated.h b/Tests/cpp/demo_log/generated/demo_log_bindings.generated.h new file mode 100644 index 0000000..94a8ad9 --- /dev/null +++ b/Tests/cpp/demo_log/generated/demo_log_bindings.generated.h @@ -0,0 +1,36 @@ +#pragma once + +#include +#include + +#include +#include +#include + +namespace demo_log +{ + enum class HostFuncId : uint32_t + { + Log = 0xDA3184A2u, + }; + + enum class CoreFuncId : uint32_t + { + }; + + struct HostArgs_Log + { + BridgeLogLevel level; + BridgeStringView message; + }; + + // Core -> Host 调用(写入 command stream) + inline void Log(bridge::CoreContext& ctx, BridgeLogLevel level, std::string_view message) + { + HostArgs_Log a{}; + a.level = level; + a.message = ctx.StoreUtf8(std::string(message)); + ctx.CallHost(static_cast(HostFuncId::Log), &a, static_cast(sizeof(a))); + } + +} // namespace demo_log diff --git a/Tests/cpp/robot_runner/CMakeLists.txt b/Tests/cpp/robot_runner/CMakeLists.txt new file mode 100644 index 0000000..c35ffbc --- /dev/null +++ b/Tests/cpp/robot_runner/CMakeLists.txt @@ -0,0 +1,28 @@ +add_executable(bridge_robot_runner + main.cpp +) + +target_link_libraries(bridge_robot_runner PRIVATE bridge_core) +target_compile_features(bridge_robot_runner PRIVATE cxx_std_20) + +target_include_directories(bridge_robot_runner PRIVATE + ${CMAKE_SOURCE_DIR}/Tests/cpp/demo_asset/generated +) + +if (MSVC) + target_compile_options(bridge_robot_runner PRIVATE /W4 /permissive- /utf-8) +else() + target_compile_options(bridge_robot_runner PRIVATE -Wall -Wextra -Wpedantic) +endif() + +set_target_properties(bridge_robot_runner PROPERTIES + RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin/$" +) + +add_test( + NAME bridge_robot_runner_smoke + COMMAND $ 10 5 0.0166667 +) +set_tests_properties(bridge_robot_runner_smoke PROPERTIES + WORKING_DIRECTORY $ +) diff --git a/Tests/cpp/robot_runner/main.cpp b/Tests/cpp/robot_runner/main.cpp new file mode 100644 index 0000000..f51b2ae --- /dev/null +++ b/Tests/cpp/robot_runner/main.cpp @@ -0,0 +1,161 @@ +#include + +#include + +#include +#include +#include +#include +#include +#include +#include + +namespace +{ + struct CommandCursor + { + const uint8_t* p = nullptr; + const uint8_t* end = nullptr; + }; + + static bool Next(CommandCursor& cur, const BridgeCommandHeader*& outHeader) + { + if (!cur.p || cur.p >= cur.end) + { + return false; + } + if (static_cast(cur.end - cur.p) < sizeof(BridgeCommandHeader)) + { + return false; + } + const auto* header = reinterpret_cast(cur.p); + if (header->size < sizeof(BridgeCommandHeader) || + static_cast(cur.end - cur.p) < header->size) + { + return false; + } + outHeader = header; + cur.p += header->size; + return true; + } + + static std::string ReadUtf8(BridgeStringView view) + { + const char* p = reinterpret_cast(static_cast(view.ptr)); + if (!p || view.len == 0) + { + return std::string(); + } + return std::string(p, p + view.len); + } + + static uint64_t FakeHandleFromKey(const std::string& key) + { + // Simple FNV-1a 64-bit + uint64_t hash = 1469598103934665603ull; + for (unsigned char c : key) + { + hash ^= static_cast(c); + hash *= 1099511628211ull; + } + return hash ? hash : 1ull; + } +} + +int main(int argc, char** argv) +{ + int bots = 1000; + int frames = 300; + float dt = 1.0f / 60.0f; + + if (argc >= 2) bots = std::atoi(argv[1]); + if (argc >= 3) frames = std::atoi(argv[2]); + if (argc >= 4) dt = static_cast(std::atof(argv[3])); + + std::printf("robot_runner: bots=%d frames=%d dt=%f\n", bots, frames, dt); + + std::vector cores; + cores.reserve(static_cast(bots)); + + for (int i = 0; i < bots; ++i) + { + BridgeCoreConfig cfg{}; + cfg.seed = static_cast(i + 1); + cfg.mode = BRIDGE_MODE_ROBOT; + cores.push_back(BridgeCore_Create(cfg)); + } + + const auto start = std::chrono::high_resolution_clock::now(); + + uint64_t totalCommands = 0; + uint64_t totalAssetRequests = 0; + + for (int frame = 0; frame < frames; ++frame) + { + for (BridgeCore* core : cores) + { + BridgeCore_Tick(core, dt); + + const void* bytes = nullptr; + uint32_t len = 0; + BridgeCore_GetCommandStream(core, &bytes, &len); + + CommandCursor cur{}; + cur.p = reinterpret_cast(bytes); + cur.end = cur.p ? (cur.p + len) : nullptr; + + uint64_t commandsThisCore = 0; + + const BridgeCommandHeader* header = nullptr; + while (Next(cur, header)) + { + ++commandsThisCore; + if (header->type == BRIDGE_CMD_CALL_HOST && + header->size >= sizeof(BridgeCmdCallHost)) + { + const auto* cmd = reinterpret_cast(header); + if (cmd->func_id == static_cast(demo_asset::HostFuncId::LoadAsset) && + cmd->payload_size == sizeof(demo_asset::HostArgs_LoadAsset)) + { + ++totalAssetRequests; + const uint8_t* payload = reinterpret_cast(cmd) + sizeof(BridgeCmdCallHost); + const auto* args = reinterpret_cast(payload); + + std::string key = ReadUtf8(args->assetKey); + uint64_t handle = FakeHandleFromKey(key); + + demo_asset::CoreArgs_AssetLoaded evt{}; + evt.requestId = args->requestId; + evt.handle = handle; + evt.status = BRIDGE_ASSET_STATUS_OK; + + BridgeCore_PushCallCore(core, + static_cast(demo_asset::CoreFuncId::AssetLoaded), + &evt, + static_cast(sizeof(evt))); + } + } + } + + totalCommands += commandsThisCore; + } + } + + const auto end = std::chrono::high_resolution_clock::now(); + const std::chrono::duration elapsed = end - start; + + std::printf("elapsed: %.3f s\n", elapsed.count()); + std::printf("total commands parsed: %llu\n", static_cast(totalCommands)); + if (elapsed.count() > 0.0) + std::printf("commands/sec: %.0f\n", static_cast(totalCommands) / elapsed.count()); + std::printf("total asset requests: %llu\n", static_cast(totalAssetRequests)); + std::printf("ticks: %llu\n", + static_cast(static_cast(bots) * static_cast(frames))); + + for (BridgeCore* core : cores) + { + BridgeCore_Destroy(core); + } + + return 0; +} diff --git a/Tests/csharp/RobotHost/Bind/Args.cs b/Tests/csharp/RobotHost/Bind/Args.cs new file mode 100644 index 0000000..cd395e3 --- /dev/null +++ b/Tests/csharp/RobotHost/Bind/Args.cs @@ -0,0 +1,12 @@ +static class Args +{ + public static int ReadInt(string[] args, int index, int fallback) + => (index < args.Length && int.TryParse(args[index], out int value)) ? value : fallback; + + public static float ReadFloat(string[] args, int index, float fallback) + => (index < args.Length && float.TryParse(args[index], out float value)) ? value : fallback; + + public static string ReadString(string[] args, int index, string fallback) + => (index < args.Length && !string.IsNullOrWhiteSpace(args[index])) ? args[index] : fallback; +} + diff --git a/Tests/csharp/RobotHost/Bind/FileAssetProvider.cs b/Tests/csharp/RobotHost/Bind/FileAssetProvider.cs new file mode 100644 index 0000000..5099084 --- /dev/null +++ b/Tests/csharp/RobotHost/Bind/FileAssetProvider.cs @@ -0,0 +1,68 @@ +using System.Collections.Generic; + +sealed class FileAssetProvider +{ + private readonly string _root; + private readonly Dictionary _handleCache = new(StringComparer.Ordinal); + + public FileAssetProvider(string root) + { + _root = root; + } + + public bool TryGetHandle(string assetKey, out ulong handle) + { + if (_handleCache.TryGetValue(assetKey, out handle)) + return true; + + string? path = ResolvePath(assetKey); + if (string.IsNullOrWhiteSpace(path) || !File.Exists(path)) + { + handle = 0; + return false; + } + + byte[] bytes = File.ReadAllBytes(path); + handle = Fnv1a64(bytes); + if (handle == 0) + handle = 1; + + _handleCache[assetKey] = handle; + return true; + } + + private string? ResolvePath(string assetKey) + { + if (string.IsNullOrWhiteSpace(assetKey)) + return null; + + string rel = assetKey.Replace('\\', '/').TrimStart('/'); + string direct = Path.Combine(_root, rel); + if (File.Exists(direct)) + return direct; + + foreach (string ext in new[] { ".bytes", ".bin", ".txt" }) + { + string candidate = direct + ext; + if (File.Exists(candidate)) + return candidate; + } + + return null; + } + + private static ulong Fnv1a64(byte[] bytes) + { + const ulong offset = 1469598103934665603ul; + const ulong prime = 1099511628211ul; + + ulong hash = offset; + foreach (byte b in bytes) + { + hash ^= b; + hash *= prime; + } + return hash; + } +} + diff --git a/Tests/csharp/RobotHost/Bind/IRobotHostApi.cs b/Tests/csharp/RobotHost/Bind/IRobotHostApi.cs new file mode 100644 index 0000000..bb2adbd --- /dev/null +++ b/Tests/csharp/RobotHost/Bind/IRobotHostApi.cs @@ -0,0 +1,8 @@ +using DemoAsset.Bindings; +using DemoEntity.Bindings; +using DemoLog.Bindings; + +interface IRobotHostApi : IDemoLogHostApi, IDemoAssetHostApi, IDemoEntityHostApi, IRobotHostStats +{ +} + diff --git a/Tests/csharp/RobotHost/Bind/IRobotHostStats.cs b/Tests/csharp/RobotHost/Bind/IRobotHostStats.cs new file mode 100644 index 0000000..50e8a05 --- /dev/null +++ b/Tests/csharp/RobotHost/Bind/IRobotHostStats.cs @@ -0,0 +1,10 @@ +interface IRobotHostStats +{ + ulong Commands { get; } + ulong AssetRequests { get; } + ulong Logs { get; } + ulong Spawns { get; } + ulong Transforms { get; } + ulong Destroys { get; } +} + diff --git a/Tests/csharp/RobotHost/Bind/NativeBridgeResolver.cs b/Tests/csharp/RobotHost/Bind/NativeBridgeResolver.cs new file mode 100644 index 0000000..78ea7e7 --- /dev/null +++ b/Tests/csharp/RobotHost/Bind/NativeBridgeResolver.cs @@ -0,0 +1,35 @@ +using System.Runtime.InteropServices; +using Bridge.Core; + +static class NativeBridgeResolver +{ + public static void TryRegisterFromEnvOrDefault() + { + string? nativeDir = Environment.GetEnvironmentVariable("BRIDGE_NATIVE_DIR"); + nativeDir = string.IsNullOrWhiteSpace(nativeDir) ? Paths.FindDefaultNativeDir() : nativeDir; + if (string.IsNullOrWhiteSpace(nativeDir)) + return; + + string libraryPath = Path.Combine(nativeDir, GetPlatformLibraryFileName("bridge_core")); + if (!File.Exists(libraryPath)) + return; + + NativeLibrary.SetDllImportResolver(typeof(BridgeCore).Assembly, (name, _, _) => + { + if (!string.Equals(name, "bridge_core", StringComparison.Ordinal)) + return IntPtr.Zero; + + return NativeLibrary.Load(libraryPath); + }); + } + + private static string GetPlatformLibraryFileName(string baseName) + { + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + return baseName + ".dll"; + if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) + return "lib" + baseName + ".dylib"; + return "lib" + baseName + ".so"; + } +} + diff --git a/Tests/csharp/RobotHost/Bind/Paths.cs b/Tests/csharp/RobotHost/Bind/Paths.cs new file mode 100644 index 0000000..5d44930 --- /dev/null +++ b/Tests/csharp/RobotHost/Bind/Paths.cs @@ -0,0 +1,46 @@ +static class Paths +{ + public static string FindDefaultAssetsRoot() + { + string repoRoot = FindRepoRoot(); + return Path.Combine(repoRoot, "Tests", "assets"); + } + + public static string FindDefaultNativeDir() + { + string repoRoot = FindRepoRoot(); + var candidates = new[] + { + Path.Combine(repoRoot, "build", "bin", "Release"), + Path.Combine(repoRoot, "build", "bin", "Debug"), + Path.Combine(repoRoot, "build", "bin"), + }; + + foreach (string candidate in candidates) + { + if (Directory.Exists(candidate)) + return candidate; + } + + return string.Empty; + } + + private static string FindRepoRoot() + { + string dir = AppContext.BaseDirectory; + for (int i = 0; i < 12; i++) + { + if (File.Exists(Path.Combine(dir, "CMakeLists.txt")) && + Directory.Exists(Path.Combine(dir, "Core"))) + return dir; + + string? parent = Directory.GetParent(dir)?.FullName; + if (string.IsNullOrWhiteSpace(parent)) + break; + dir = parent; + } + + return Directory.GetCurrentDirectory(); + } +} + diff --git a/Tests/csharp/RobotHost/Bind/RobotHostApi.cs b/Tests/csharp/RobotHost/Bind/RobotHostApi.cs new file mode 100644 index 0000000..3c8f964 --- /dev/null +++ b/Tests/csharp/RobotHost/Bind/RobotHostApi.cs @@ -0,0 +1,64 @@ +using Bridge.Core; +using DemoAsset.Bindings; + +sealed class RobotHostApi : IRobotHostApi +{ + private readonly BridgeCore _core; + private readonly WorldState _world; + private readonly FileAssetProvider _assets; + + public ulong Commands { get; private set; } + public ulong AssetRequests { get; private set; } + public ulong Logs { get; private set; } + public ulong Spawns { get; private set; } + public ulong Transforms { get; private set; } + public ulong Destroys { get; private set; } + + public RobotHostApi(BridgeCore core, WorldState world, FileAssetProvider assets) + { + _core = core; + _world = world; + _assets = assets; + } + + public void Log(BridgeLogLevel level, string message) + { + Commands++; + Logs++; + _world.OnLog(level, message); + } + + public void LoadAsset(ulong requestId, BridgeAssetType assetType, string assetKey) + { + _ = assetType; + + Commands++; + AssetRequests++; + + if (_assets.TryGetHandle(assetKey, out ulong handle)) + _core.AssetLoaded(requestId, handle, BridgeAssetStatus.Ok); + else + _core.AssetLoaded(requestId, 0, BridgeAssetStatus.NotFound); + } + + public void SpawnEntity(ulong entityId, ulong prefabHandle, BridgeTransform transform, uint flags) + { + Commands++; + Spawns++; + _world.OnSpawn(entityId, prefabHandle, transform, flags); + } + + public void SetTransform(ulong entityId, uint mask, BridgeTransform transform) + { + Commands++; + Transforms++; + _world.OnSetTransform(entityId, mask, transform); + } + + public void DestroyEntity(ulong entityId) + { + Commands++; + Destroys++; + _world.OnDestroy(entityId); + } +} diff --git a/Tests/csharp/RobotHost/Bind/RobotNullHostApi.cs b/Tests/csharp/RobotHost/Bind/RobotNullHostApi.cs new file mode 100644 index 0000000..d3d29c8 --- /dev/null +++ b/Tests/csharp/RobotHost/Bind/RobotNullHostApi.cs @@ -0,0 +1,68 @@ +using Bridge.Core; +using DemoAsset.Bindings; + +sealed class RobotNullHostApi : IRobotHostApi +{ + private readonly BridgeCore _core; + private readonly FileAssetProvider _assets; + + public ulong Commands { get; private set; } + public ulong AssetRequests { get; private set; } + public ulong Logs { get; private set; } + public ulong Spawns { get; private set; } + public ulong Transforms { get; private set; } + public ulong Destroys { get; private set; } + + public RobotNullHostApi(BridgeCore core, FileAssetProvider assets) + { + _core = core; + _assets = assets; + } + + public void Log(BridgeLogLevel level, string message) + { + _ = level; + _ = message; + Commands++; + Logs++; + } + + public void LoadAsset(ulong requestId, BridgeAssetType assetType, string assetKey) + { + _ = assetType; + + Commands++; + AssetRequests++; + + if (_assets.TryGetHandle(assetKey, out ulong handle)) + _core.AssetLoaded(requestId, handle, BridgeAssetStatus.Ok); + else + _core.AssetLoaded(requestId, 0, BridgeAssetStatus.NotFound); + } + + public void SpawnEntity(ulong entityId, ulong prefabHandle, BridgeTransform transform, uint flags) + { + _ = entityId; + _ = prefabHandle; + _ = transform; + _ = flags; + Commands++; + Spawns++; + } + + public void SetTransform(ulong entityId, uint mask, BridgeTransform transform) + { + _ = entityId; + _ = mask; + _ = transform; + Commands++; + Transforms++; + } + + public void DestroyEntity(ulong entityId) + { + _ = entityId; + Commands++; + Destroys++; + } +} diff --git a/Tests/csharp/RobotHost/Bind/WorldState.cs b/Tests/csharp/RobotHost/Bind/WorldState.cs new file mode 100644 index 0000000..5ad33d4 --- /dev/null +++ b/Tests/csharp/RobotHost/Bind/WorldState.cs @@ -0,0 +1,49 @@ +using System.Collections.Generic; +using Bridge.Core; + +sealed class WorldState +{ + private readonly Dictionary _entities = new(); + + public void OnLog(BridgeLogLevel level, string message) + { + _ = level; + _ = message; + } + + public void OnSpawn(ulong entityId, ulong prefabHandle, BridgeTransform transform, uint flags) + { + _ = flags; + _entities[entityId] = new Entity(prefabHandle, transform); + } + + public void OnSetTransform(ulong entityId, uint mask, BridgeTransform transform) + { + if (_entities.TryGetValue(entityId, out var entity)) + { + var tr = entity.Transform; + if ((mask & 1u) != 0) tr.Position = transform.Position; + if ((mask & 2u) != 0) tr.Rotation = transform.Rotation; + if ((mask & 4u) != 0) tr.Scale = transform.Scale; + _entities[entityId] = new Entity(entity.PrefabHandle, tr); + } + } + + public void OnDestroy(ulong entityId) + { + _entities.Remove(entityId); + } + + private readonly struct Entity + { + public readonly ulong PrefabHandle; + public readonly BridgeTransform Transform; + + public Entity(ulong prefabHandle, BridgeTransform transform) + { + PrefabHandle = prefabHandle; + Transform = transform; + } + } +} + diff --git a/Tests/csharp/RobotHost/Generated/Bridge.AllCommandDispatcher.g.cs b/Tests/csharp/RobotHost/Generated/Bridge.AllCommandDispatcher.g.cs new file mode 100644 index 0000000..1052c03 --- /dev/null +++ b/Tests/csharp/RobotHost/Generated/Bridge.AllCommandDispatcher.g.cs @@ -0,0 +1,99 @@ +// +// 由 Core/Tools/BridgeGen 生成,请勿手改。 +// + +using Bridge.Core; + +namespace Bridge.Bindings +{ + /// + /// 单次扫描 command stream,并按 func_id 分发到各模块 Host API。 + /// + public static class BridgeAllCommandDispatcher + { + public static unsafe void Dispatch(CommandStream stream, THost host) + where THost : class, DemoAsset.Bindings.IDemoAssetHostApi, DemoEntity.Bindings.IDemoEntityHostApi, DemoLog.Bindings.IDemoLogHostApi + { + if (stream.IsEmpty || host == null) + return; + + byte* cursor = (byte*)stream.Ptr; + byte* end = cursor + (int)stream.Length; + + while (cursor < end) + { + long remaining = end - cursor; + if (remaining < sizeof(BridgeCommandHeader)) + break; + + var header = (BridgeCommandHeader*)cursor; + int size = header->Size; + if (size <= 0) + break; + if (size < sizeof(BridgeCommandHeader) || size > remaining) + break; + + if (header->Type == (ushort)BridgeCommandType.CallHost && size >= sizeof(BridgeCmdCallHost)) + { + var cmd = (BridgeCmdCallHost*)cursor; + uint payloadSize = cmd->PayloadSize; + if (payloadSize <= (uint)(size - sizeof(BridgeCmdCallHost))) + { + byte* payloadPtr = cursor + sizeof(BridgeCmdCallHost); + + switch (cmd->FuncId) + { + case 0x82A5E93Au: + { + if (payloadSize == (uint)sizeof(DemoAsset.Bindings.HostArgs_LoadAsset)) + { + var a = *((DemoAsset.Bindings.HostArgs_LoadAsset*)payloadPtr); + host.LoadAsset(a.RequestId, a.AssetType, a.AssetKey.ToManagedString()); + } + break; + } + case 0xBCAA331Du: + { + if (payloadSize == (uint)sizeof(DemoEntity.Bindings.HostArgs_SpawnEntity)) + { + var a = *((DemoEntity.Bindings.HostArgs_SpawnEntity*)payloadPtr); + host.SpawnEntity(a.EntityId, a.PrefabHandle, a.Transform, a.Flags); + } + break; + } + case 0x20DA0B6Fu: + { + if (payloadSize == (uint)sizeof(DemoEntity.Bindings.HostArgs_SetTransform)) + { + var a = *((DemoEntity.Bindings.HostArgs_SetTransform*)payloadPtr); + host.SetTransform(a.EntityId, a.Mask, a.Transform); + } + break; + } + case 0xC7C1C59Cu: + { + if (payloadSize == (uint)sizeof(DemoEntity.Bindings.HostArgs_DestroyEntity)) + { + var a = *((DemoEntity.Bindings.HostArgs_DestroyEntity*)payloadPtr); + host.DestroyEntity(a.EntityId); + } + break; + } + case 0xDA3184A2u: + { + if (payloadSize == (uint)sizeof(DemoLog.Bindings.HostArgs_Log)) + { + var a = *((DemoLog.Bindings.HostArgs_Log*)payloadPtr); + host.Log(a.Level, a.Message.ToManagedString()); + } + break; + } + } + } + } + + cursor += size; + } + } + } +} diff --git a/Tests/csharp/RobotHost/Generated/DemoAsset.CoreCalls.g.cs b/Tests/csharp/RobotHost/Generated/DemoAsset.CoreCalls.g.cs new file mode 100644 index 0000000..3a7406c --- /dev/null +++ b/Tests/csharp/RobotHost/Generated/DemoAsset.CoreCalls.g.cs @@ -0,0 +1,23 @@ +// +// 由 Core/Tools/BridgeGen 生成,请勿手改。 +// + +using Bridge.Core; + +namespace DemoAsset.Bindings +{ + public static class DemoAssetCoreCalls + { + public static void AssetLoaded(this BridgeCore core, ulong requestId, ulong handle, BridgeAssetStatus status) + { + var a = new CoreArgs_AssetLoaded + { + RequestId = requestId, + Handle = handle, + Status = status, + }; + core.PushCallCore((uint)CoreFuncId.AssetLoaded, a); + } + + } +} diff --git a/Tests/csharp/RobotHost/Generated/DemoAsset.Ids.g.cs b/Tests/csharp/RobotHost/Generated/DemoAsset.Ids.g.cs new file mode 100644 index 0000000..dcbfa24 --- /dev/null +++ b/Tests/csharp/RobotHost/Generated/DemoAsset.Ids.g.cs @@ -0,0 +1,16 @@ +// +// 由 Core/Tools/BridgeGen 生成,请勿手改。 +// + +namespace DemoAsset.Bindings +{ + public enum HostFuncId : uint + { + LoadAsset = 0x82A5E93Au, + } + + public enum CoreFuncId : uint + { + AssetLoaded = 0x2442BC8Au, + } +} diff --git a/Tests/csharp/RobotHost/Generated/DemoAsset.Structs.g.cs b/Tests/csharp/RobotHost/Generated/DemoAsset.Structs.g.cs new file mode 100644 index 0000000..eb6a5de --- /dev/null +++ b/Tests/csharp/RobotHost/Generated/DemoAsset.Structs.g.cs @@ -0,0 +1,26 @@ +// +// 由 Core/Tools/BridgeGen 生成,请勿手改。 +// + +using System.Runtime.InteropServices; +using Bridge.Core; + +namespace DemoAsset.Bindings +{ + [StructLayout(LayoutKind.Sequential)] + public struct HostArgs_LoadAsset + { + public ulong RequestId; + public BridgeAssetType AssetType; + public BridgeStringView AssetKey; + } + + [StructLayout(LayoutKind.Sequential)] + public struct CoreArgs_AssetLoaded + { + public ulong RequestId; + public ulong Handle; + public BridgeAssetStatus Status; + } + +} diff --git a/Tests/csharp/RobotHost/Generated/DemoEntity.CoreCalls.g.cs b/Tests/csharp/RobotHost/Generated/DemoEntity.CoreCalls.g.cs new file mode 100644 index 0000000..d20621e --- /dev/null +++ b/Tests/csharp/RobotHost/Generated/DemoEntity.CoreCalls.g.cs @@ -0,0 +1,12 @@ +// +// 由 Core/Tools/BridgeGen 生成,请勿手改。 +// + +using Bridge.Core; + +namespace DemoEntity.Bindings +{ + public static class DemoEntityCoreCalls + { + } +} diff --git a/Tests/csharp/RobotHost/Generated/DemoEntity.Ids.g.cs b/Tests/csharp/RobotHost/Generated/DemoEntity.Ids.g.cs new file mode 100644 index 0000000..139525c --- /dev/null +++ b/Tests/csharp/RobotHost/Generated/DemoEntity.Ids.g.cs @@ -0,0 +1,17 @@ +// +// 由 Core/Tools/BridgeGen 生成,请勿手改。 +// + +namespace DemoEntity.Bindings +{ + public enum HostFuncId : uint + { + SpawnEntity = 0xBCAA331Du, + SetTransform = 0x20DA0B6Fu, + DestroyEntity = 0xC7C1C59Cu, + } + + public enum CoreFuncId : uint + { + } +} diff --git a/Tests/csharp/RobotHost/Generated/DemoEntity.Structs.g.cs b/Tests/csharp/RobotHost/Generated/DemoEntity.Structs.g.cs new file mode 100644 index 0000000..48c0308 --- /dev/null +++ b/Tests/csharp/RobotHost/Generated/DemoEntity.Structs.g.cs @@ -0,0 +1,33 @@ +// +// 由 Core/Tools/BridgeGen 生成,请勿手改。 +// + +using System.Runtime.InteropServices; +using Bridge.Core; + +namespace DemoEntity.Bindings +{ + [StructLayout(LayoutKind.Sequential)] + public struct HostArgs_SpawnEntity + { + public ulong EntityId; + public ulong PrefabHandle; + public BridgeTransform Transform; + public uint Flags; + } + + [StructLayout(LayoutKind.Sequential)] + public struct HostArgs_SetTransform + { + public ulong EntityId; + public uint Mask; + public BridgeTransform Transform; + } + + [StructLayout(LayoutKind.Sequential)] + public struct HostArgs_DestroyEntity + { + public ulong EntityId; + } + +} diff --git a/Tests/csharp/RobotHost/Generated/DemoLog.CoreCalls.g.cs b/Tests/csharp/RobotHost/Generated/DemoLog.CoreCalls.g.cs new file mode 100644 index 0000000..c00b537 --- /dev/null +++ b/Tests/csharp/RobotHost/Generated/DemoLog.CoreCalls.g.cs @@ -0,0 +1,12 @@ +// +// 由 Core/Tools/BridgeGen 生成,请勿手改。 +// + +using Bridge.Core; + +namespace DemoLog.Bindings +{ + public static class DemoLogCoreCalls + { + } +} diff --git a/Tests/csharp/RobotHost/Generated/DemoLog.Ids.g.cs b/Tests/csharp/RobotHost/Generated/DemoLog.Ids.g.cs new file mode 100644 index 0000000..790cb61 --- /dev/null +++ b/Tests/csharp/RobotHost/Generated/DemoLog.Ids.g.cs @@ -0,0 +1,15 @@ +// +// 由 Core/Tools/BridgeGen 生成,请勿手改。 +// + +namespace DemoLog.Bindings +{ + public enum HostFuncId : uint + { + Log = 0xDA3184A2u, + } + + public enum CoreFuncId : uint + { + } +} diff --git a/Tests/csharp/RobotHost/Generated/DemoLog.Structs.g.cs b/Tests/csharp/RobotHost/Generated/DemoLog.Structs.g.cs new file mode 100644 index 0000000..0836d7d --- /dev/null +++ b/Tests/csharp/RobotHost/Generated/DemoLog.Structs.g.cs @@ -0,0 +1,17 @@ +// +// 由 Core/Tools/BridgeGen 生成,请勿手改。 +// + +using System.Runtime.InteropServices; +using Bridge.Core; + +namespace DemoLog.Bindings +{ + [StructLayout(LayoutKind.Sequential)] + public struct HostArgs_Log + { + public BridgeLogLevel Level; + public BridgeStringView Message; + } + +} diff --git a/Tests/csharp/RobotHost/Generated/IDemoAssetHostApi.g.cs b/Tests/csharp/RobotHost/Generated/IDemoAssetHostApi.g.cs new file mode 100644 index 0000000..c5fa10d --- /dev/null +++ b/Tests/csharp/RobotHost/Generated/IDemoAssetHostApi.g.cs @@ -0,0 +1,13 @@ +// +// 由 Core/Tools/BridgeGen 生成,请勿手改。 +// + +using Bridge.Core; + +namespace DemoAsset.Bindings +{ + public interface IDemoAssetHostApi + { + void LoadAsset(ulong requestId, BridgeAssetType assetType, string assetKey); + } +} diff --git a/Tests/csharp/RobotHost/Generated/IDemoEntityHostApi.g.cs b/Tests/csharp/RobotHost/Generated/IDemoEntityHostApi.g.cs new file mode 100644 index 0000000..449e796 --- /dev/null +++ b/Tests/csharp/RobotHost/Generated/IDemoEntityHostApi.g.cs @@ -0,0 +1,15 @@ +// +// 由 Core/Tools/BridgeGen 生成,请勿手改。 +// + +using Bridge.Core; + +namespace DemoEntity.Bindings +{ + public interface IDemoEntityHostApi + { + void SpawnEntity(ulong entityId, ulong prefabHandle, BridgeTransform transform, uint flags); + void SetTransform(ulong entityId, uint mask, BridgeTransform transform); + void DestroyEntity(ulong entityId); + } +} diff --git a/Tests/csharp/RobotHost/Generated/IDemoLogHostApi.g.cs b/Tests/csharp/RobotHost/Generated/IDemoLogHostApi.g.cs new file mode 100644 index 0000000..41676fb --- /dev/null +++ b/Tests/csharp/RobotHost/Generated/IDemoLogHostApi.g.cs @@ -0,0 +1,13 @@ +// +// 由 Core/Tools/BridgeGen 生成,请勿手改。 +// + +using Bridge.Core; + +namespace DemoLog.Bindings +{ + public interface IDemoLogHostApi + { + void Log(BridgeLogLevel level, string message); + } +} diff --git a/Tests/csharp/RobotHost/Program.cs b/Tests/csharp/RobotHost/Program.cs new file mode 100644 index 0000000..ed7d429 --- /dev/null +++ b/Tests/csharp/RobotHost/Program.cs @@ -0,0 +1,241 @@ +using System.Diagnostics; +using Bridge.Bindings; +using Bridge.Core; + +static class Program +{ + private readonly struct RunResult + { + public readonly double ElapsedSeconds; + public readonly long AllocatedBytes; + + public readonly ulong TotalCommands; + public readonly ulong TotalAssetRequests; + public readonly ulong TotalLogs; + public readonly ulong TotalSpawns; + public readonly ulong TotalTransforms; + public readonly ulong TotalDestroys; + + public RunResult( + double elapsedSeconds, + long allocatedBytes, + ulong totalCommands, + ulong totalAssetRequests, + ulong totalLogs, + ulong totalSpawns, + ulong totalTransforms, + ulong totalDestroys) + { + ElapsedSeconds = elapsedSeconds; + AllocatedBytes = allocatedBytes; + TotalCommands = totalCommands; + TotalAssetRequests = totalAssetRequests; + TotalLogs = totalLogs; + TotalSpawns = totalSpawns; + TotalTransforms = totalTransforms; + TotalDestroys = totalDestroys; + } + } + + private static int Main(string[] args) + { + int bots = Args.ReadInt(args, 0, 1000); + int frames = Args.ReadInt(args, 1, 300); + float dt = Args.ReadFloat(args, 2, 1.0f / 60.0f); + + string assetsRoot = Paths.FindDefaultAssetsRoot(); + string hostMode = "full"; + + int idx = 3; + if (args.Length > idx && !args[idx].StartsWith("--", StringComparison.Ordinal)) + { + assetsRoot = Args.ReadString(args, idx, assetsRoot); + idx++; + } + + if (args.Length > idx && !args[idx].StartsWith("--", StringComparison.Ordinal)) + { + hostMode = Args.ReadString(args, idx, hostMode); + idx++; + } + + assetsRoot = FindOption(args, "--assets") ?? + FindOption(args, "--assetsRoot") ?? + assetsRoot; + + hostMode = FindOption(args, "--host") ?? hostMode; + + NativeBridgeResolver.TryRegisterFromEnvOrDefault(); + + bool nullHost = string.Equals(hostMode, "null", StringComparison.OrdinalIgnoreCase); + + Console.WriteLine($"RobotHost: bots={bots} frames={frames} dt={dt}"); + Console.WriteLine($"assetsRoot: {assetsRoot}"); + Console.WriteLine($"hostMode: {(nullHost ? "null" : "full")}"); + + var r = Run(bots, frames, dt, assetsRoot, nullHost: nullHost); + PrintRun("all", r); + + return 0; + } + + private static string? FindOption(string[] args, string name) + { + for (int i = 0; i < args.Length - 1; i++) + { + if (string.Equals(args[i], name, StringComparison.OrdinalIgnoreCase)) + return args[i + 1]; + } + return null; + } + + private static RunResult Run(int bots, int frames, float dt, string assetsRoot, bool nullHost) + { + var assetProvider = new FileAssetProvider(assetsRoot); + _ = assetProvider.TryGetHandle("Main/Prefabs/Bot", out _); + + var cores = new BridgeCore[bots]; + + if (nullHost) + { + var hosts = new RobotNullHostApi[bots]; + for (int i = 0; i < bots; i++) + { + var core = new BridgeCore(seed: (ulong)(i + 1), robotMode: true); + cores[i] = core; + hosts[i] = new RobotNullHostApi(core, assetProvider); + } + + long allocBefore = GC.GetAllocatedBytesForCurrentThread(); + var sw = Stopwatch.StartNew(); + + try + { + for (int frame = 0; frame < frames; frame++) + { + for (int i = 0; i < cores.Length; i++) + { + var core = cores[i]; + core.Tick(dt); + + var stream = core.GetCommandStream(); + BridgeAllCommandDispatcher.Dispatch(stream, hosts[i]); + } + } + } + finally + { + sw.Stop(); + for (int i = 0; i < cores.Length; i++) + cores[i].Dispose(); + } + + long allocAfter = GC.GetAllocatedBytesForCurrentThread(); + + ulong totalCommands = 0; + ulong totalAssetRequests = 0; + ulong totalLogs = 0; + ulong totalSpawns = 0; + ulong totalTransforms = 0; + ulong totalDestroys = 0; + + for (int i = 0; i < hosts.Length; i++) + { + totalCommands += hosts[i].Commands; + totalAssetRequests += hosts[i].AssetRequests; + totalLogs += hosts[i].Logs; + totalSpawns += hosts[i].Spawns; + totalTransforms += hosts[i].Transforms; + totalDestroys += hosts[i].Destroys; + } + + return new RunResult( + elapsedSeconds: sw.Elapsed.TotalSeconds, + allocatedBytes: allocAfter - allocBefore, + totalCommands: totalCommands, + totalAssetRequests: totalAssetRequests, + totalLogs: totalLogs, + totalSpawns: totalSpawns, + totalTransforms: totalTransforms, + totalDestroys: totalDestroys); + } + else + { + var hosts = new RobotHostApi[bots]; + for (int i = 0; i < bots; i++) + { + var core = new BridgeCore(seed: (ulong)(i + 1), robotMode: true); + cores[i] = core; + + var world = new WorldState(); + hosts[i] = new RobotHostApi(core, world, assetProvider); + } + + long allocBefore = GC.GetAllocatedBytesForCurrentThread(); + var sw = Stopwatch.StartNew(); + + try + { + for (int frame = 0; frame < frames; frame++) + { + for (int i = 0; i < cores.Length; i++) + { + var core = cores[i]; + core.Tick(dt); + + var stream = core.GetCommandStream(); + BridgeAllCommandDispatcher.Dispatch(stream, hosts[i]); + } + } + } + finally + { + sw.Stop(); + for (int i = 0; i < cores.Length; i++) + cores[i].Dispose(); + } + + long allocAfter = GC.GetAllocatedBytesForCurrentThread(); + + ulong totalCommands = 0; + ulong totalAssetRequests = 0; + ulong totalLogs = 0; + ulong totalSpawns = 0; + ulong totalTransforms = 0; + ulong totalDestroys = 0; + + for (int i = 0; i < hosts.Length; i++) + { + totalCommands += hosts[i].Commands; + totalAssetRequests += hosts[i].AssetRequests; + totalLogs += hosts[i].Logs; + totalSpawns += hosts[i].Spawns; + totalTransforms += hosts[i].Transforms; + totalDestroys += hosts[i].Destroys; + } + + return new RunResult( + elapsedSeconds: sw.Elapsed.TotalSeconds, + allocatedBytes: allocAfter - allocBefore, + totalCommands: totalCommands, + totalAssetRequests: totalAssetRequests, + totalLogs: totalLogs, + totalSpawns: totalSpawns, + totalTransforms: totalTransforms, + totalDestroys: totalDestroys); + } + } + + private static void PrintRun(string label, RunResult r) + { + Console.WriteLine($"[{label}] elapsed: {r.ElapsedSeconds:F3} s"); + Console.WriteLine($"[{label}] allocated (thread): {r.AllocatedBytes} bytes"); + Console.WriteLine($"[{label}] total commands handled: {r.TotalCommands}"); + Console.WriteLine($"[{label}] commands/sec: {r.TotalCommands / Math.Max(1e-9, r.ElapsedSeconds):F0}"); + Console.WriteLine($"[{label}] total asset requests: {r.TotalAssetRequests}"); + Console.WriteLine($"[{label}] total logs: {r.TotalLogs}"); + Console.WriteLine($"[{label}] total spawns: {r.TotalSpawns}"); + Console.WriteLine($"[{label}] total transforms: {r.TotalTransforms}"); + Console.WriteLine($"[{label}] total destroys: {r.TotalDestroys}"); + } +} diff --git a/Tests/csharp/RobotHost/RobotHost.csproj b/Tests/csharp/RobotHost/RobotHost.csproj new file mode 100644 index 0000000..333f218 --- /dev/null +++ b/Tests/csharp/RobotHost/RobotHost.csproj @@ -0,0 +1,14 @@ + + + Exe + net8.0 + latest + enable + enable + true + + + + + + diff --git a/Tests/defs/demo_asset_api.def b/Tests/defs/demo_asset_api.def new file mode 100644 index 0000000..517b4b0 --- /dev/null +++ b/Tests/defs/demo_asset_api.def @@ -0,0 +1,6 @@ +// DemoAsset 模块:资源加载(Core 发起,Host 用引擎/文件系统实现) + +BRIDGE_HOST_API(LoadAsset, uint64_t requestId, BridgeAssetType assetType, BridgeStringView assetKey) + +BRIDGE_CORE_API(AssetLoaded, uint64_t requestId, uint64_t handle, BridgeAssetStatus status) + diff --git a/Tests/defs/demo_entity_api.def b/Tests/defs/demo_entity_api.def new file mode 100644 index 0000000..d0710f4 --- /dev/null +++ b/Tests/defs/demo_entity_api.def @@ -0,0 +1,6 @@ +// DemoEntity 模块:实体/渲染驱动(Core -> Host) + +BRIDGE_HOST_API(SpawnEntity, uint64_t entityId, uint64_t prefabHandle, BridgeTransform transform, uint32_t flags) +BRIDGE_HOST_API(SetTransform, uint64_t entityId, uint32_t mask, BridgeTransform transform) +BRIDGE_HOST_API(DestroyEntity, uint64_t entityId) + diff --git a/Tests/defs/demo_log_api.def b/Tests/defs/demo_log_api.def new file mode 100644 index 0000000..9e744ad --- /dev/null +++ b/Tests/defs/demo_log_api.def @@ -0,0 +1,8 @@ +// DemoLog 模块:日志输出(Core -> Host) +// +// 约定: +// - BRIDGE_HOST_API:由 Host(C# / Unity)实现,Core 通过 command stream 调用 +// - BRIDGE_CORE_API:由 Core(C++)实现,Host 通过 PushCallCore 调用 + +BRIDGE_HOST_API(Log, BridgeLogLevel level, BridgeStringView message) + diff --git a/Unity/.gitignore b/Tests/unity/.gitignore similarity index 100% rename from Unity/.gitignore rename to Tests/unity/.gitignore diff --git a/Unity/Assets/CppSource.meta b/Tests/unity/Assets/BridgeCore.meta similarity index 62% rename from Unity/Assets/CppSource.meta rename to Tests/unity/Assets/BridgeCore.meta index a8346ff..97fe715 100644 --- a/Unity/Assets/CppSource.meta +++ b/Tests/unity/Assets/BridgeCore.meta @@ -1,10 +1,9 @@ fileFormatVersion: 2 -guid: ec1b3d1da421646d781f3ccc6960a558 +guid: 9a3d65f0cde84a1fb2f5b7c9a1e4c2d1 folderAsset: yes -timeCreated: 1525538114 -licenseType: Free DefaultImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: + diff --git a/Unity/Assets/CppSource/NativeScript.meta b/Tests/unity/Assets/BridgeCore/Editor.meta similarity index 62% rename from Unity/Assets/CppSource/NativeScript.meta rename to Tests/unity/Assets/BridgeCore/Editor.meta index a82c5d8..7288872 100644 --- a/Unity/Assets/CppSource/NativeScript.meta +++ b/Tests/unity/Assets/BridgeCore/Editor.meta @@ -1,10 +1,9 @@ fileFormatVersion: 2 -guid: c48669dd52f8e49b890586dd9a417de5 +guid: 1a7a8f63a0b64f47b8c815b6b7bb70c9 folderAsset: yes -timeCreated: 1525538114 -licenseType: Free DefaultImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: + diff --git a/Tests/unity/Assets/BridgeCore/Editor/BridgeCoreWinHotReload.cs b/Tests/unity/Assets/BridgeCore/Editor/BridgeCoreWinHotReload.cs new file mode 100644 index 0000000..921c999 --- /dev/null +++ b/Tests/unity/Assets/BridgeCore/Editor/BridgeCoreWinHotReload.cs @@ -0,0 +1,208 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using UnityEditor; +using UnityEngine; +using Debug = UnityEngine.Debug; + +namespace Bridge.Core.Unity.Editor +{ + public static class BridgeCoreWinHotReload + { + private enum PendingAction + { + None = 0, + BuildReleaseAndReload = 1, + } + + private static PendingAction s_pending; + + [MenuItem("BridgeCore/Windows/Build bridge_core.dll (Release)")] + public static void BuildRelease() + { + if (!EnsureWindows()) + return; + + string repoRoot = FindRepoRoot(); + if (string.IsNullOrEmpty(repoRoot)) + return; + + RunBuildRelease(repoRoot, reloadAfterBuild: false); + } + + [MenuItem("BridgeCore/Windows/Build + Hot Reload (Release)")] + public static void BuildReleaseAndReload() + { + if (!EnsureWindows()) + return; + + if (EditorApplication.isPlaying) + { + bool ok = EditorUtility.DisplayDialog( + "BridgeCore", + "热更需要先退出 PlayMode(确保没有存活的 BridgeCore 实例)。\n\n是否退出 PlayMode 后继续 Build + Reload?", + "退出并继续", + "取消"); + if (!ok) + return; + + s_pending = PendingAction.BuildReleaseAndReload; + EditorApplication.playModeStateChanged -= OnPlayModeStateChanged; + EditorApplication.playModeStateChanged += OnPlayModeStateChanged; + EditorApplication.isPlaying = false; + return; + } + + string repoRoot = FindRepoRoot(); + if (string.IsNullOrEmpty(repoRoot)) + return; + + RunBuildRelease(repoRoot, reloadAfterBuild: true); + } + + [MenuItem("BridgeCore/Windows/Reload bridge_core.dll (from build output)")] + public static void ReloadOnly() + { + if (!EnsureWindows()) + return; + + if (EditorApplication.isPlaying) + { + EditorUtility.DisplayDialog( + "BridgeCore", + "请先退出 PlayMode 再 Reload(避免旧 DLL 创建的对象被新 DLL 销毁导致崩溃)。", + "OK"); + return; + } + + BridgeCoreWinLoader.TryReloadLatest(); + Debug.Log("BridgeCore: reloaded from " + BridgeCoreWinLoader.GetLoadedDllPath()); + } + + private static void OnPlayModeStateChanged(PlayModeStateChange state) + { + if (state != PlayModeStateChange.EnteredEditMode) + return; + + EditorApplication.playModeStateChanged -= OnPlayModeStateChanged; + + var action = s_pending; + s_pending = PendingAction.None; + + if (action == PendingAction.BuildReleaseAndReload) + { + string repoRoot = FindRepoRoot(); + if (!string.IsNullOrEmpty(repoRoot)) + RunBuildRelease(repoRoot, reloadAfterBuild: true); + } + } + + private static bool EnsureWindows() + { +#if !UNITY_EDITOR_WIN + EditorUtility.DisplayDialog("BridgeCore", "此菜单仅用于 Windows Editor。", "OK"); + return false; +#else + return true; +#endif + } + + private static void RunBuildRelease(string repoRoot, bool reloadAfterBuild) + { + try + { + EditorUtility.DisplayProgressBar("BridgeCore", "Configuring (cmake)...", 0.1f); + if (!RunProcess("cmake", $"-S \"{repoRoot}\" -B \"{Path.Combine(repoRoot, "build")}\" -DCMAKE_BUILD_TYPE=Release", repoRoot)) + { + EditorUtility.DisplayDialog("BridgeCore", "cmake configure 失败。请查看 Console 输出。", "OK"); + return; + } + + EditorUtility.DisplayProgressBar("BridgeCore", "Building (cmake --build)...", 0.6f); + if (!RunProcess("cmake", $"--build \"{Path.Combine(repoRoot, "build")}\" --config Release", repoRoot)) + { + EditorUtility.DisplayDialog("BridgeCore", "cmake build 失败。请查看 Console 输出。", "OK"); + return; + } + + if (reloadAfterBuild) + { + EditorUtility.DisplayProgressBar("BridgeCore", "Reloading bridge_core.dll...", 0.9f); + BridgeCoreWinLoader.TryReloadLatest(); + Debug.Log("BridgeCore: reloaded from " + BridgeCoreWinLoader.GetLoadedDllPath()); + } + + EditorUtility.DisplayDialog("BridgeCore", reloadAfterBuild ? "Build + Reload 完成。" : "Build 完成。", "OK"); + } + finally + { + EditorUtility.ClearProgressBar(); + } + } + + private static bool RunProcess(string fileName, string arguments, string workingDirectory) + { + try + { + var psi = new ProcessStartInfo + { + FileName = fileName, + Arguments = arguments, + WorkingDirectory = workingDirectory, + UseShellExecute = false, + CreateNoWindow = true, + RedirectStandardOutput = true, + RedirectStandardError = true, + }; + + using (var p = new Process { StartInfo = psi }) + { + var lines = new List(256); + p.OutputDataReceived += (_, e) => { if (!string.IsNullOrEmpty(e.Data)) lines.Add(e.Data); }; + p.ErrorDataReceived += (_, e) => { if (!string.IsNullOrEmpty(e.Data)) lines.Add(e.Data); }; + + p.Start(); + p.BeginOutputReadLine(); + p.BeginErrorReadLine(); + p.WaitForExit(); + + for (int i = 0; i < lines.Count; i++) + Debug.Log(lines[i]); + + return p.ExitCode == 0; + } + } + catch (Exception e) + { + Debug.LogError("BridgeCore: failed to run process: " + fileName + " " + arguments + "\n" + e); + return false; + } + } + + private static string FindRepoRoot() + { + string projectRoot = Directory.GetParent(Application.dataPath).FullName; + string dir = projectRoot; + for (int i = 0; i < 10; i++) + { + if (File.Exists(Path.Combine(dir, "CMakeLists.txt")) && + Directory.Exists(Path.Combine(dir, "Core"))) + { + return dir; + } + + var parent = Directory.GetParent(dir); + if (parent == null) + break; + dir = parent.FullName; + } + + EditorUtility.DisplayDialog( + "BridgeCore", + "无法定位仓库根目录(未找到 CMakeLists.txt 与 Core/)。\n当前工程目录:" + projectRoot, + "OK"); + return string.Empty; + } + } +} diff --git a/Unity/Assets/Game/AbstractBaseBallScript.cs.meta b/Tests/unity/Assets/BridgeCore/Editor/BridgeCoreWinHotReload.cs.meta similarity index 71% rename from Unity/Assets/Game/AbstractBaseBallScript.cs.meta rename to Tests/unity/Assets/BridgeCore/Editor/BridgeCoreWinHotReload.cs.meta index 0757588..dd899c4 100644 --- a/Unity/Assets/Game/AbstractBaseBallScript.cs.meta +++ b/Tests/unity/Assets/BridgeCore/Editor/BridgeCoreWinHotReload.cs.meta @@ -1,7 +1,5 @@ fileFormatVersion: 2 -guid: 7c6c722578a90428dbeacfd4a5aaa3ae -timeCreated: 1520705999 -licenseType: Free +guid: 3a3b4c5d6e7f4a8b9c0d1e2f3a4b5c6d MonoImporter: externalObjects: {} serializedVersion: 2 @@ -11,3 +9,4 @@ MonoImporter: userData: assetBundleName: assetBundleVariant: + diff --git a/Tests/unity/Assets/BridgeCore/Editor/BridgeCoreWinSync.cs b/Tests/unity/Assets/BridgeCore/Editor/BridgeCoreWinSync.cs new file mode 100644 index 0000000..0b33f76 --- /dev/null +++ b/Tests/unity/Assets/BridgeCore/Editor/BridgeCoreWinSync.cs @@ -0,0 +1,114 @@ +using System; +using System.IO; +using UnityEditor; +using UnityEngine; + +namespace Bridge.Core.Unity.Editor +{ + /// + /// Windows 下辅助同步/配置 bridge_core.dll: + /// - 可把构建产物同步到 Assets/Plugins(用于 Player 出包) + /// - 并确保插件不在 Editor 自动加载,避免锁定 + /// + public static class BridgeCoreWinSync + { + private const string PluginRelativePath = "Assets/Plugins/BridgeCore/Win64/bridge_core.dll"; + + [MenuItem("BridgeCore/Windows/Sync bridge_core.dll (for Player)")] + public static void SyncForPlayer() + { + string sourceDll = FindSourceBridgeCoreDll(); + if (string.IsNullOrEmpty(sourceDll) || !File.Exists(sourceDll)) + { + EditorUtility.DisplayDialog( + "BridgeCore", + "未找到源 bridge_core.dll。\n\n可选:设置环境变量 BRIDGE_CORE_DLL 指向 DLL 路径。\n或先在仓库根目录构建 CMake:build/bin/Release/bridge_core.dll", + "OK"); + return; + } + + EnsureDir(Path.GetDirectoryName(PluginRelativePath)); + File.Copy(sourceDll, PluginRelativePath, true); + AssetDatabase.ImportAsset(PluginRelativePath, ImportAssetOptions.ForceUpdate); + + ConfigurePluginImporter(); + + Debug.Log("BridgeCore: synced " + sourceDll + " -> " + PluginRelativePath); + } + + [MenuItem("BridgeCore/Windows/Configure Plugin Importer")] + public static void ConfigurePluginImporter() + { + var importer = AssetImporter.GetAtPath(PluginRelativePath) as PluginImporter; + if (importer == null) + { + EditorUtility.DisplayDialog( + "BridgeCore", + "未找到插件资源:" + PluginRelativePath + "\n先执行 Sync bridge_core.dll。", + "OK"); + return; + } + + // 避免 Editor 自动加载并锁定文件,Editor 运行时由 BridgeCoreWinLoader 负责从 Library 加载 + importer.SetCompatibleWithAnyPlatform(false); + importer.SetCompatibleWithEditor(false); + importer.SetCompatibleWithPlatform(BuildTarget.StandaloneWindows64, true); + +#if UNITY_2019_2_OR_NEWER + importer.SetPlatformData(BuildTarget.StandaloneWindows64, "CPU", "x86_64"); +#endif + + EditorUtility.SetDirty(importer); + importer.SaveAndReimport(); + } + + private static string FindSourceBridgeCoreDll() + { + string env = Environment.GetEnvironmentVariable("BRIDGE_CORE_DLL"); + if (!string.IsNullOrEmpty(env) && File.Exists(env)) + return env; + + string projectRoot = Directory.GetParent(Application.dataPath).FullName; + string repoRoot = FindRepoRoot(projectRoot); + string[] candidates = new[] + { + Path.Combine(repoRoot, "build", "bin", "Release", "bridge_core.dll"), + Path.Combine(repoRoot, "build", "bin", "Debug", "bridge_core.dll"), + }; + for (int i = 0; i < candidates.Length; i++) + { + if (File.Exists(candidates[i])) + return candidates[i]; + } + return string.Empty; + } + + private static string FindRepoRoot(string startDir) + { + string dir = startDir; + for (int i = 0; i < 10; i++) + { + if (File.Exists(Path.Combine(dir, "CMakeLists.txt")) && + Directory.Exists(Path.Combine(dir, "Core"))) + { + return dir; + } + + var parent = Directory.GetParent(dir); + if (parent == null) + break; + dir = parent.FullName; + } + return startDir; + } + + private static void EnsureDir(string dir) + { + if (string.IsNullOrEmpty(dir)) + return; + if (Directory.Exists(dir)) + return; + Directory.CreateDirectory(dir); + } + } +} diff --git a/Unity/Assets/NativeScript/Editor/EditorMenus.cs.meta b/Tests/unity/Assets/BridgeCore/Editor/BridgeCoreWinSync.cs.meta similarity index 71% rename from Unity/Assets/NativeScript/Editor/EditorMenus.cs.meta rename to Tests/unity/Assets/BridgeCore/Editor/BridgeCoreWinSync.cs.meta index ae3469a..6122c68 100644 --- a/Unity/Assets/NativeScript/Editor/EditorMenus.cs.meta +++ b/Tests/unity/Assets/BridgeCore/Editor/BridgeCoreWinSync.cs.meta @@ -1,7 +1,5 @@ fileFormatVersion: 2 -guid: 5aad51de55c544325a293e98c996a550 -timeCreated: 1515806821 -licenseType: Free +guid: 6e8c2f4f4d7b4fe6b28e812b71b8dc55 MonoImporter: externalObjects: {} serializedVersion: 2 @@ -11,3 +9,4 @@ MonoImporter: userData: assetBundleName: assetBundleVariant: + diff --git a/Unity/Assets/Game.meta b/Tests/unity/Assets/BridgeCore/Managed.meta similarity index 62% rename from Unity/Assets/Game.meta rename to Tests/unity/Assets/BridgeCore/Managed.meta index 42f3c6b..3cac82b 100644 --- a/Unity/Assets/Game.meta +++ b/Tests/unity/Assets/BridgeCore/Managed.meta @@ -1,10 +1,9 @@ fileFormatVersion: 2 -guid: bb19f2d6c4c0e41c18cdd5ead2b97cec +guid: 2d1d2a6c1a6a4b5fb9b6c7c3cdbd6e17 folderAsset: yes -timeCreated: 1519492407 -licenseType: Free DefaultImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: + diff --git a/Unity/Assets/CppSource/Game.meta b/Tests/unity/Assets/BridgeCore/Managed/Bridge.Core.meta similarity index 62% rename from Unity/Assets/CppSource/Game.meta rename to Tests/unity/Assets/BridgeCore/Managed/Bridge.Core.meta index 7121431..9ad2a1d 100644 --- a/Unity/Assets/CppSource/Game.meta +++ b/Tests/unity/Assets/BridgeCore/Managed/Bridge.Core.meta @@ -1,10 +1,9 @@ fileFormatVersion: 2 -guid: 5097e8d235bbf426abeae3e4fc76859f +guid: 0a1b9c0b1a3c4d5e9f1a2b3c4d5e6f70 folderAsset: yes -timeCreated: 1525538114 -licenseType: Free DefaultImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: + diff --git a/Tests/unity/Assets/BridgeCore/Managed/Bridge.Core/Bridge.Core.asmdef b/Tests/unity/Assets/BridgeCore/Managed/Bridge.Core/Bridge.Core.asmdef new file mode 100644 index 0000000..87f1980 --- /dev/null +++ b/Tests/unity/Assets/BridgeCore/Managed/Bridge.Core/Bridge.Core.asmdef @@ -0,0 +1,7 @@ +{ + "name": "Bridge.Core", + "references": [ + "Bridge.Core.Unity" + ], + "allowUnsafeCode": true +} diff --git a/Tests/unity/Assets/BridgeCore/Managed/Bridge.Core/Bridge.Core.asmdef.meta b/Tests/unity/Assets/BridgeCore/Managed/Bridge.Core/Bridge.Core.asmdef.meta new file mode 100644 index 0000000..1fb662e --- /dev/null +++ b/Tests/unity/Assets/BridgeCore/Managed/Bridge.Core/Bridge.Core.asmdef.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: b28e6674eef7407eb799362680615767 +AssemblyDefinitionImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Tests/unity/Assets/BridgeCore/Managed/Bridge.Core/BridgeCore.cs b/Tests/unity/Assets/BridgeCore/Managed/Bridge.Core/BridgeCore.cs new file mode 100644 index 0000000..540fe45 --- /dev/null +++ b/Tests/unity/Assets/BridgeCore/Managed/Bridge.Core/BridgeCore.cs @@ -0,0 +1,78 @@ +using System; + +namespace Bridge.Core +{ + /// + /// 原生 BridgeCore 的托管封装(Host 侧入口)。 + /// + public sealed class BridgeCore : IDisposable + { + private IntPtr _handle; + + public BridgeCore(ulong seed = 1, bool robotMode = false) + { + var cfg = new BridgeCoreConfig + { + Seed = seed, + Mode = (uint)(robotMode ? BridgeMode.Robot : BridgeMode.Game) + }; + + _handle = BridgeNative.BridgeCore_Create(cfg); + if (_handle == IntPtr.Zero) + throw new InvalidOperationException("BridgeCore_Create returned null"); + } + + /// + /// 推进 Core 一帧(或一个逻辑 tick)。 + /// + public void Tick(float dt) + { + ThrowIfDisposed(); + BridgeNative.BridgeCore_Tick(_handle, dt); + } + + /// + /// 获取最近一次 生成的命令字节流(command stream)。 + /// + /// + /// 返回指针由原生侧持有,只保证在下一次 (或 )前有效。 + /// + public CommandStream GetCommandStream() + { + ThrowIfDisposed(); + var result = BridgeNative.BridgeCore_GetCommandStream(_handle, out var ptr, out var len); + if (result != BridgeResult.Ok || ptr == IntPtr.Zero || len == 0) + return CommandStream.Empty; + + return new CommandStream(ptr, len); + } + + public void PushCallCore(uint funcId) + { + ThrowIfDisposed(); + BridgeNative.BridgeCore_PushCallCore(_handle, funcId, IntPtr.Zero, 0); + } + + public unsafe void PushCallCore(uint funcId, T payload) where T : unmanaged + { + ThrowIfDisposed(); + BridgeNative.BridgeCore_PushCallCore(_handle, funcId, (IntPtr)(&payload), (uint)sizeof(T)); + } + + public void Dispose() + { + if (_handle != IntPtr.Zero) + { + BridgeNative.BridgeCore_Destroy(_handle); + _handle = IntPtr.Zero; + } + GC.SuppressFinalize(this); + } + + private void ThrowIfDisposed() + { + if (_handle == IntPtr.Zero) + throw new ObjectDisposedException(nameof(BridgeCore)); + } + } +} diff --git a/Unity/Assets/NativeScript/Bindings.cs.meta b/Tests/unity/Assets/BridgeCore/Managed/Bridge.Core/BridgeCore.cs.meta similarity index 69% rename from Unity/Assets/NativeScript/Bindings.cs.meta rename to Tests/unity/Assets/BridgeCore/Managed/Bridge.Core/BridgeCore.cs.meta index b03a09a..e41f58d 100644 --- a/Unity/Assets/NativeScript/Bindings.cs.meta +++ b/Tests/unity/Assets/BridgeCore/Managed/Bridge.Core/BridgeCore.cs.meta @@ -1,8 +1,7 @@ fileFormatVersion: 2 -guid: 665d6bf4c0af74229be9793f99cca81a -timeCreated: 1501905896 -licenseType: Free +guid: 9ed7f0d8c49b4b95a2b8c2e3b7d1a90c MonoImporter: + externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 @@ -10,3 +9,4 @@ MonoImporter: userData: assetBundleName: assetBundleVariant: + diff --git a/Tests/unity/Assets/BridgeCore/Managed/Bridge.Core/CommandStream.cs b/Tests/unity/Assets/BridgeCore/Managed/Bridge.Core/CommandStream.cs new file mode 100644 index 0000000..7608889 --- /dev/null +++ b/Tests/unity/Assets/BridgeCore/Managed/Bridge.Core/CommandStream.cs @@ -0,0 +1,24 @@ +using System; + +namespace Bridge.Core +{ + /// + /// 原生侧返回的 command stream(指针 + 长度)。 + /// + public readonly struct CommandStream + { + public readonly IntPtr Ptr; + public readonly uint Length; + + public bool IsEmpty => Ptr == IntPtr.Zero || Length == 0; + + public static CommandStream Empty => new CommandStream(IntPtr.Zero, 0); + + internal CommandStream(IntPtr ptr, uint length) + { + Ptr = ptr; + Length = length; + } + } +} + diff --git a/Unity/Assets/NativeScript/Editor/GenerateBindings.cs.meta b/Tests/unity/Assets/BridgeCore/Managed/Bridge.Core/CommandStream.cs.meta similarity index 69% rename from Unity/Assets/NativeScript/Editor/GenerateBindings.cs.meta rename to Tests/unity/Assets/BridgeCore/Managed/Bridge.Core/CommandStream.cs.meta index 7170af5..261847b 100644 --- a/Unity/Assets/NativeScript/Editor/GenerateBindings.cs.meta +++ b/Tests/unity/Assets/BridgeCore/Managed/Bridge.Core/CommandStream.cs.meta @@ -1,8 +1,7 @@ fileFormatVersion: 2 -guid: 28b8219f9650f4601a77f7ba1f5a37b5 -timeCreated: 1500836910 -licenseType: Free +guid: 3fbd5849f0f54e1d8bd5a466f1f4e1bd MonoImporter: + externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 @@ -10,3 +9,4 @@ MonoImporter: userData: assetBundleName: assetBundleVariant: + diff --git a/Tests/unity/Assets/BridgeCore/Managed/Bridge.Core/Interop.meta b/Tests/unity/Assets/BridgeCore/Managed/Bridge.Core/Interop.meta new file mode 100644 index 0000000..938a6ff --- /dev/null +++ b/Tests/unity/Assets/BridgeCore/Managed/Bridge.Core/Interop.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 4b6f3c1a2d4e4f5a8b9c0d1e2f3a4b5c +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: + diff --git a/Tests/unity/Assets/BridgeCore/Managed/Bridge.Core/Interop/BridgeNative.cs b/Tests/unity/Assets/BridgeCore/Managed/Bridge.Core/Interop/BridgeNative.cs new file mode 100644 index 0000000..4840b9a --- /dev/null +++ b/Tests/unity/Assets/BridgeCore/Managed/Bridge.Core/Interop/BridgeNative.cs @@ -0,0 +1,135 @@ +using System; +using System.Runtime.InteropServices; + +#if UNITY_EDITOR_WIN +using Bridge.Core.Unity; +#endif + +namespace Bridge.Core +{ + internal static class BridgeNative + { +#if UNITY_EDITOR_WIN + [DllImport("kernel32.dll", CharSet = CharSet.Ansi, ExactSpelling = true, SetLastError = true)] + private static extern IntPtr GetProcAddress(IntPtr libraryHandle, string symbolName); + + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + private delegate BridgeVersion Bridge_GetVersionDelegate(); + + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + private delegate IntPtr BridgeCore_CreateDelegate(BridgeCoreConfig config); + + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + private delegate void BridgeCore_DestroyDelegate(IntPtr core); + + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + private delegate void BridgeCore_TickDelegate(IntPtr core, float dt); + + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + private delegate BridgeResult BridgeCore_GetCommandStreamDelegate(IntPtr core, out IntPtr ptr, out uint len); + + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + private delegate BridgeResult BridgeCore_PushCallCoreDelegate(IntPtr core, uint funcId, IntPtr payload, uint payloadSize); + + private static IntPtr s_boundModule; + private static Bridge_GetVersionDelegate s_getVersion; + private static BridgeCore_CreateDelegate s_create; + private static BridgeCore_DestroyDelegate s_destroy; + private static BridgeCore_TickDelegate s_tick; + private static BridgeCore_GetCommandStreamDelegate s_getCommandStream; + private static BridgeCore_PushCallCoreDelegate s_pushCallCore; + + private static void EnsureBound() + { + BridgeCoreWinLoader.TryEnsureLoaded(); + + IntPtr module = BridgeCoreWinLoader.GetLoadedModuleHandle(); + if (module == IntPtr.Zero) + throw new DllNotFoundException("bridge_core.dll 未加载(请先编译 build/bin/Release/bridge_core.dll)"); + + if (module == s_boundModule) + return; + + s_getVersion = GetDelegate(module, "Bridge_GetVersion"); + s_create = GetDelegate(module, "BridgeCore_Create"); + s_destroy = GetDelegate(module, "BridgeCore_Destroy"); + s_tick = GetDelegate(module, "BridgeCore_Tick"); + s_getCommandStream = GetDelegate(module, "BridgeCore_GetCommandStream"); + s_pushCallCore = GetDelegate(module, "BridgeCore_PushCallCore"); + s_boundModule = module; + } + + private static T GetDelegate(IntPtr libraryHandle, string functionName) where T : class + { + IntPtr symbol = GetProcAddress(libraryHandle, functionName); + if (symbol == IntPtr.Zero) + throw new MissingMethodException("bridge_core.dll", functionName); + + return Marshal.GetDelegateForFunctionPointer(symbol, typeof(T)) as T; + } + + internal static BridgeVersion Bridge_GetVersion() + { + EnsureBound(); + return s_getVersion(); + } + + internal static IntPtr BridgeCore_Create(BridgeCoreConfig config) + { + EnsureBound(); + return s_create(config); + } + + internal static void BridgeCore_Destroy(IntPtr core) + { + EnsureBound(); + s_destroy(core); + } + + internal static void BridgeCore_Tick(IntPtr core, float dt) + { + EnsureBound(); + s_tick(core, dt); + } + + internal static BridgeResult BridgeCore_GetCommandStream(IntPtr core, out IntPtr ptr, out uint len) + { + EnsureBound(); + return s_getCommandStream(core, out ptr, out len); + } + + internal static BridgeResult BridgeCore_PushCallCore(IntPtr core, uint funcId, IntPtr payload, uint payloadSize) + { + EnsureBound(); + return s_pushCallCore(core, funcId, payload, payloadSize); + } +#else + private const string LibraryName = "bridge_core"; + + [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern BridgeVersion Bridge_GetVersion(); + + [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern IntPtr BridgeCore_Create(BridgeCoreConfig config); + + [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern void BridgeCore_Destroy(IntPtr core); + + [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern void BridgeCore_Tick(IntPtr core, float dt); + + [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern BridgeResult BridgeCore_GetCommandStream( + IntPtr core, + out IntPtr ptr, + out uint len); + + [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern BridgeResult BridgeCore_PushCallCore( + IntPtr core, + uint funcId, + IntPtr payload, + uint payloadSize); +#endif + } +} diff --git a/Tests/unity/Assets/BridgeCore/Managed/Bridge.Core/Interop/BridgeNative.cs.meta b/Tests/unity/Assets/BridgeCore/Managed/Bridge.Core/Interop/BridgeNative.cs.meta new file mode 100644 index 0000000..13e928f --- /dev/null +++ b/Tests/unity/Assets/BridgeCore/Managed/Bridge.Core/Interop/BridgeNative.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 5c1d1f2f9c4d4b5a9a4f2c1d3e4b5a6c +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: + diff --git a/Tests/unity/Assets/BridgeCore/Managed/Bridge.Core/Interop/Structs.cs b/Tests/unity/Assets/BridgeCore/Managed/Bridge.Core/Interop/Structs.cs new file mode 100644 index 0000000..be9b104 --- /dev/null +++ b/Tests/unity/Assets/BridgeCore/Managed/Bridge.Core/Interop/Structs.cs @@ -0,0 +1,120 @@ +using System; +using System.Runtime.InteropServices; + +namespace Bridge.Core +{ + public enum BridgeResult : int + { + Ok = 0, + Error = 1, + InvalidArgument = 2 + } + + public enum BridgeMode : uint + { + Game = 0, + Robot = 1 + } + + [StructLayout(LayoutKind.Sequential)] + public readonly struct BridgeVersion + { + public readonly uint Major; + public readonly uint Minor; + public readonly uint Patch; + } + + [StructLayout(LayoutKind.Sequential)] + public struct BridgeCoreConfig + { + public ulong Seed; + public uint Mode; + public uint Reserved0; + } + + [StructLayout(LayoutKind.Sequential)] + public readonly struct BridgeStringView + { + public readonly ulong Ptr; + public readonly uint Len; + public readonly uint Reserved0; + + public string ToManagedString() + { + if (Ptr == 0 || Len == 0) + return string.Empty; + + // netstandard2.1+ 支持按长度读取 UTF-8,避免额外分配 byte[]。 + return Marshal.PtrToStringUTF8(new IntPtr(unchecked((long)Ptr)), (int)Len) ?? string.Empty; + } + } + + public enum BridgeLogLevel : uint + { + Debug = 0, + Info = 1, + Warn = 2, + Error = 3 + } + + public enum BridgeAssetType : uint + { + Unknown = 0, + Prefab = 1 + } + + public enum BridgeAssetStatus : uint + { + Ok = 0, + NotFound = 1, + Error = 2 + } + + [StructLayout(LayoutKind.Sequential)] + public struct BridgeVec3 + { + public float X; + public float Y; + public float Z; + public float Reserved0; + } + + [StructLayout(LayoutKind.Sequential)] + public struct BridgeQuat + { + public float X; + public float Y; + public float Z; + public float W; + } + + [StructLayout(LayoutKind.Sequential)] + public struct BridgeTransform + { + public BridgeVec3 Position; + public BridgeQuat Rotation; + public BridgeVec3 Scale; + } + + [StructLayout(LayoutKind.Sequential)] + public struct BridgeCommandHeader + { + public ushort Type; + public ushort Size; + public uint Reserved0; + } + + public enum BridgeCommandType : ushort + { + None = 0, + CallHost = 1 + } + + [StructLayout(LayoutKind.Sequential)] + public struct BridgeCmdCallHost + { + public BridgeCommandHeader Header; + public uint FuncId; + public uint PayloadSize; + } +} diff --git a/Tests/unity/Assets/BridgeCore/Managed/Bridge.Core/Interop/Structs.cs.meta b/Tests/unity/Assets/BridgeCore/Managed/Bridge.Core/Interop/Structs.cs.meta new file mode 100644 index 0000000..3248d78 --- /dev/null +++ b/Tests/unity/Assets/BridgeCore/Managed/Bridge.Core/Interop/Structs.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 1dfc2e3b4a5b4c6d8e9f0a1b2c3d4e5f +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: + diff --git a/Tests/unity/Assets/BridgeCore/README.md b/Tests/unity/Assets/BridgeCore/README.md new file mode 100644 index 0000000..72e5efe --- /dev/null +++ b/Tests/unity/Assets/BridgeCore/README.md @@ -0,0 +1,13 @@ +# BridgeCore(Unity 侧) + +此目录仅提供 **Windows Editor** 下的原生 DLL 加载支持: + +- 运行时从 `Library/BridgeNative//bridge_core.dll` 加载,避免锁定固定源文件 +- 源 DLL 默认从仓库构建输出 `build/bin/Release/bridge_core.dll` 查找(会自动向上寻找仓库根目录) +- 也可通过环境变量 `BRIDGE_CORE_DLL` 指定源 DLL 的绝对路径 + +Unity 菜单: + +- `BridgeCore/Windows/Build + Hot Reload (Release)`:触发 CMake 编译并重新加载 + +更多说明见:`Core/docs/UNITY_WIN_NATIVE_LOADING.md`。 diff --git a/Unity/Assets/CppSource/CMakeLists.txt.meta b/Tests/unity/Assets/BridgeCore/README.md.meta similarity index 59% rename from Unity/Assets/CppSource/CMakeLists.txt.meta rename to Tests/unity/Assets/BridgeCore/README.md.meta index 3ecd08d..4adbc07 100644 --- a/Unity/Assets/CppSource/CMakeLists.txt.meta +++ b/Tests/unity/Assets/BridgeCore/README.md.meta @@ -1,9 +1,8 @@ fileFormatVersion: 2 -guid: ff824f6dad1204438ac5993f133fa551 -timeCreated: 1525538114 -licenseType: Free +guid: 61f46c01363c4cb7b4e7d2da8a19a4ff TextScriptImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: + diff --git a/Tests/unity/Assets/BridgeCore/Runtime.meta b/Tests/unity/Assets/BridgeCore/Runtime.meta new file mode 100644 index 0000000..faa4a3e --- /dev/null +++ b/Tests/unity/Assets/BridgeCore/Runtime.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 68c0e37d26ce4c98bdc3a62bbd7984e0 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: + diff --git a/Tests/unity/Assets/BridgeCore/Runtime/Bridge.Core.Unity.asmdef b/Tests/unity/Assets/BridgeCore/Runtime/Bridge.Core.Unity.asmdef new file mode 100644 index 0000000..afa15db --- /dev/null +++ b/Tests/unity/Assets/BridgeCore/Runtime/Bridge.Core.Unity.asmdef @@ -0,0 +1,3 @@ +{ + "name": "Bridge.Core.Unity" +} diff --git a/Tests/unity/Assets/BridgeCore/Runtime/Bridge.Core.Unity.asmdef.meta b/Tests/unity/Assets/BridgeCore/Runtime/Bridge.Core.Unity.asmdef.meta new file mode 100644 index 0000000..de7794d --- /dev/null +++ b/Tests/unity/Assets/BridgeCore/Runtime/Bridge.Core.Unity.asmdef.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 86c54d11920f4eeaa93fe1bc6d7db5fe +AssemblyDefinitionImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Tests/unity/Assets/BridgeCore/Runtime/BridgeCoreWinLoader.cs b/Tests/unity/Assets/BridgeCore/Runtime/BridgeCoreWinLoader.cs new file mode 100644 index 0000000..29539e5 --- /dev/null +++ b/Tests/unity/Assets/BridgeCore/Runtime/BridgeCoreWinLoader.cs @@ -0,0 +1,214 @@ +using System; +using System.IO; +using System.Runtime.InteropServices; +using UnityEngine; + +namespace Bridge.Core.Unity +{ + /// + /// Windows 下 Unity Editor 的原生 DLL “先拷贝再加载”: + /// - 避免锁定固定源文件(便于热替换/重编译覆盖) + /// - 运行时从 Library 临时目录加载 + /// + public static class BridgeCoreWinLoader + { +#if UNITY_EDITOR_WIN || UNITY_STANDALONE_WIN + [DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)] + private static extern bool SetDllDirectory(string lpPathName); + + [DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)] + private static extern IntPtr LoadLibrary(string lpFileName); +#endif + + private static bool s_loaded; + private static string s_loadedDir; + private static string s_loadedDllPath; + private static IntPtr s_moduleHandle; + +#if UNITY_EDITOR_WIN + [UnityEditor.InitializeOnLoadMethod] + private static void EditorInit() + { + // 只做一次尝试:避免不停弹错误;真正需要时也可手动调用 EnsureLoaded() + TryEnsureLoaded(); + } +#endif + + [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)] + private static void RuntimeInit() + { + TryEnsureLoaded(); + } + + public static void TryEnsureLoaded() + { +#if UNITY_EDITOR_WIN || UNITY_STANDALONE_WIN + TryLoadLatest(force: false); +#endif + } + + public static void TryReloadLatest() + { +#if UNITY_EDITOR_WIN || UNITY_STANDALONE_WIN + TryLoadLatest(force: true); +#endif + } + + public static IntPtr GetLoadedModuleHandle() + { + return s_moduleHandle; + } + + public static string GetLoadedDllPath() + { + return s_loadedDllPath ?? string.Empty; + } + + private static void TryLoadLatest(bool force) + { + if (s_loaded) + { + if (!force) + return; + } + +#if !(UNITY_EDITOR_WIN || UNITY_STANDALONE_WIN) + return; +#else + string sourceDll = FindSourceBridgeCoreDll(); + if (string.IsNullOrEmpty(sourceDll) || !File.Exists(sourceDll)) + return; + + string destDir = PrepareTempDir(sourceDll); + if (string.IsNullOrEmpty(destDir)) + return; + + if (!force && + s_loaded && + !string.IsNullOrEmpty(s_loadedDir) && + string.Equals(s_loadedDir, destDir, StringComparison.OrdinalIgnoreCase) && + s_moduleHandle != IntPtr.Zero) + { + return; + } + + CopyAllDlls(Path.GetDirectoryName(sourceDll), destDir); + + // 让后续 DllImport("bridge_core") 能在此目录找到 dll + SetDllDirectory(destDir); + + string destDll = Path.Combine(destDir, "bridge_core.dll"); + IntPtr h = LoadLibrary(destDll); + if (h == IntPtr.Zero) + { + // 加载失败时不要抛异常,避免卡住编辑器;需要时可在 Console 看到错误 + int err = Marshal.GetLastWin32Error(); + Debug.LogWarning("BridgeCoreWinLoader: LoadLibrary failed. path=" + destDll + " err=" + err); + return; + } + + s_loaded = true; + s_loadedDir = destDir; + s_loadedDllPath = destDll; + s_moduleHandle = h; +#endif + } + + public static string GetLoadedDirectory() + { + return s_loadedDir ?? string.Empty; + } + +#if UNITY_EDITOR_WIN || UNITY_STANDALONE_WIN + private static string FindSourceBridgeCoreDll() + { + // 优先读环境变量,方便 CI/本机自定义 + string env = Environment.GetEnvironmentVariable("BRIDGE_CORE_DLL"); + if (!string.IsNullOrEmpty(env) && File.Exists(env)) + return env; + + string projectRoot = Directory.GetParent(Application.dataPath).FullName; + string repoRoot = FindRepoRoot(projectRoot); + + string[] candidates = new[] + { + Path.Combine(repoRoot, "build", "bin", "Release", "bridge_core.dll"), + Path.Combine(repoRoot, "build", "bin", "Debug", "bridge_core.dll"), + Path.Combine(repoRoot, "build", "bin", "bridge_core.dll"), + }; + + for (int i = 0; i < candidates.Length; i++) + { + if (File.Exists(candidates[i])) + return candidates[i]; + } + + return string.Empty; + } + + private static string FindRepoRoot(string startDir) + { + string dir = startDir; + for (int i = 0; i < 10; i++) + { + if (File.Exists(Path.Combine(dir, "CMakeLists.txt")) && + Directory.Exists(Path.Combine(dir, "Core"))) + { + return dir; + } + + var parent = Directory.GetParent(dir); + if (parent == null) + break; + dir = parent.FullName; + } + return startDir; + } + + private static string PrepareTempDir(string sourceDll) + { + try + { + string projectRoot = Directory.GetParent(Application.dataPath).FullName; + string libRoot = Path.Combine(projectRoot, "Library", "BridgeNative"); + + var fi = new FileInfo(sourceDll); + string buildId = fi.LastWriteTimeUtc.Ticks.ToString() + "_" + fi.Length.ToString(); + string dir = Path.Combine(libRoot, buildId); + Directory.CreateDirectory(dir); + return dir; + } + catch (Exception e) + { + Debug.LogWarning("BridgeCoreWinLoader: PrepareTempDir failed: " + e); + return string.Empty; + } + } + + private static void CopyAllDlls(string sourceDir, string destDir) + { + if (string.IsNullOrEmpty(sourceDir) || !Directory.Exists(sourceDir)) + return; + + try + { + string[] dlls = Directory.GetFiles(sourceDir, "*.dll", SearchOption.TopDirectoryOnly); + for (int i = 0; i < dlls.Length; i++) + { + string src = dlls[i]; + string name = Path.GetFileName(src); + string dst = Path.Combine(destDir, name); + + // 只在目标不存在或源更新时拷贝 + if (!File.Exists(dst) || File.GetLastWriteTimeUtc(src) != File.GetLastWriteTimeUtc(dst)) + File.Copy(src, dst, true); + } + } + catch (Exception e) + { + Debug.LogWarning("BridgeCoreWinLoader: CopyAllDlls failed: " + e); + } + } +#endif + } +} diff --git a/Tests/unity/Assets/BridgeCore/Runtime/BridgeCoreWinLoader.cs.meta b/Tests/unity/Assets/BridgeCore/Runtime/BridgeCoreWinLoader.cs.meta new file mode 100644 index 0000000..3cb8cd7 --- /dev/null +++ b/Tests/unity/Assets/BridgeCore/Runtime/BridgeCoreWinLoader.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 8cfa0e38b36f4e7bba9d2d6a0c36a81b +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: -32000 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: + diff --git a/Tests/unity/Assets/BridgeDemoGame.meta b/Tests/unity/Assets/BridgeDemoGame.meta new file mode 100644 index 0000000..7cb2e39 --- /dev/null +++ b/Tests/unity/Assets/BridgeDemoGame.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 8a6f2f2d7b4a4d7f9a2d3b4c5d6e7f80 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: + diff --git a/Tests/unity/Assets/BridgeDemoGame/Editor.meta b/Tests/unity/Assets/BridgeDemoGame/Editor.meta new file mode 100644 index 0000000..5ab417b --- /dev/null +++ b/Tests/unity/Assets/BridgeDemoGame/Editor.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: d465aea5e2db45b3a635e5f6616a68a1 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Tests/unity/Assets/BridgeDemoGame/Editor/Performance.meta b/Tests/unity/Assets/BridgeDemoGame/Editor/Performance.meta new file mode 100644 index 0000000..20207ff --- /dev/null +++ b/Tests/unity/Assets/BridgeDemoGame/Editor/Performance.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 12552cc7318d408f9236af6fb696a0c1 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Tests/unity/Assets/BridgeDemoGame/Editor/Performance/BridgeDemoGame.PerformanceTests.asmdef b/Tests/unity/Assets/BridgeDemoGame/Editor/Performance/BridgeDemoGame.PerformanceTests.asmdef new file mode 100644 index 0000000..5065378 --- /dev/null +++ b/Tests/unity/Assets/BridgeDemoGame/Editor/Performance/BridgeDemoGame.PerformanceTests.asmdef @@ -0,0 +1,15 @@ +{ + "name": "BridgeDemoGame.PerformanceTests", + "references": [ + "Bridge.Core", + "Bridge.Core.Unity", + "BridgeDemoGame.Generated", + "Unity.PerformanceTesting" + ], + "includePlatforms": [ + "Editor" + ], + "optionalUnityReferences": [ + "TestAssemblies" + ] +} diff --git a/Tests/unity/Assets/BridgeDemoGame/Editor/Performance/BridgeDemoGame.PerformanceTests.asmdef.meta b/Tests/unity/Assets/BridgeDemoGame/Editor/Performance/BridgeDemoGame.PerformanceTests.asmdef.meta new file mode 100644 index 0000000..78cc5c3 --- /dev/null +++ b/Tests/unity/Assets/BridgeDemoGame/Editor/Performance/BridgeDemoGame.PerformanceTests.asmdef.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 1207cb5e4118441e834ae4ecae3c0272 +AssemblyDefinitionImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Tests/unity/Assets/BridgeDemoGame/Editor/Performance/BridgeDispatchPerformanceTests.cs b/Tests/unity/Assets/BridgeDemoGame/Editor/Performance/BridgeDispatchPerformanceTests.cs new file mode 100644 index 0000000..4d91eed --- /dev/null +++ b/Tests/unity/Assets/BridgeDemoGame/Editor/Performance/BridgeDispatchPerformanceTests.cs @@ -0,0 +1,105 @@ +using Bridge.Bindings; +using Bridge.Core; +using Bridge.Core.Unity; +using DemoAsset.Bindings; +using DemoEntity.Bindings; +using DemoLog.Bindings; +using NUnit.Framework; +using Unity.PerformanceTesting; + +namespace BridgeDemoGame.Tests +{ + public sealed class BridgeDispatchPerformanceTests + { + private sealed class NullHostApi : IDemoAssetHostApi, IDemoEntityHostApi, IDemoLogHostApi + { + private readonly BridgeCore _core; + + public NullHostApi(BridgeCore core) + { + _core = core; + } + + public void LoadAsset(ulong requestId, BridgeAssetType assetType, string assetKey) + { + _ = assetType; + _ = assetKey; + _core.AssetLoaded(requestId, handle: 1, BridgeAssetStatus.Ok); + } + + public void SpawnEntity(ulong entityId, ulong prefabHandle, BridgeTransform transform, uint flags) + { + _ = entityId; + _ = prefabHandle; + _ = transform; + _ = flags; + } + + public void SetTransform(ulong entityId, uint mask, BridgeTransform transform) + { + _ = entityId; + _ = mask; + _ = transform; + } + + public void DestroyEntity(ulong entityId) + { + _ = entityId; + } + + public void Log(BridgeLogLevel level, string message) + { + _ = level; + _ = message; + } + } + + [Test, Performance] + [TestCase(1)] + [TestCase(1000)] + public void TickAndDispatch_OneFrame(int bots) + { +#if !UNITY_EDITOR_WIN + Assert.Ignore("当前性能测试仅支持 Windows Editor(依赖 bridge_core.dll 的 Win 加载路径)。"); +#else + BridgeCoreWinLoader.TryEnsureLoaded(); + + var cores = new BridgeCore[bots]; + var hosts = new NullHostApi[bots]; + + for (int i = 0; i < bots; i++) + { + var core = new BridgeCore(seed: (ulong)(i + 1), robotMode: true); + cores[i] = core; + hosts[i] = new NullHostApi(core); + } + + const float dt = 1.0f / 60.0f; + + try + { + Measure.Method(() => + { + for (int i = 0; i < bots; i++) + { + var core = cores[i]; + core.Tick(dt); + var stream = core.GetCommandStream(); + BridgeAllCommandDispatcher.Dispatch(stream, hosts[i]); + } + }) + .WarmupCount(5) + .MeasurementCount(30) + .IterationsPerMeasurement(1) + .GC() + .Run(); + } + finally + { + for (int i = 0; i < bots; i++) + cores[i].Dispose(); + } +#endif + } + } +} diff --git a/Tests/unity/Assets/BridgeDemoGame/Editor/Performance/BridgeDispatchPerformanceTests.cs.meta b/Tests/unity/Assets/BridgeDemoGame/Editor/Performance/BridgeDispatchPerformanceTests.cs.meta new file mode 100644 index 0000000..1e00925 --- /dev/null +++ b/Tests/unity/Assets/BridgeDemoGame/Editor/Performance/BridgeDispatchPerformanceTests.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 84d18033a51641ab99a0c81215393f0b +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Tests/unity/Assets/BridgeDemoGame/Generated.meta b/Tests/unity/Assets/BridgeDemoGame/Generated.meta new file mode 100644 index 0000000..67b3ffb --- /dev/null +++ b/Tests/unity/Assets/BridgeDemoGame/Generated.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 0b7c8d9e1f2a3b4c5d6e7f8091a2b3c4 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: + diff --git a/Tests/unity/Assets/BridgeDemoGame/Generated/Bridge.AllCommandDispatcher.g.cs b/Tests/unity/Assets/BridgeDemoGame/Generated/Bridge.AllCommandDispatcher.g.cs new file mode 100644 index 0000000..1052c03 --- /dev/null +++ b/Tests/unity/Assets/BridgeDemoGame/Generated/Bridge.AllCommandDispatcher.g.cs @@ -0,0 +1,99 @@ +// +// 由 Core/Tools/BridgeGen 生成,请勿手改。 +// + +using Bridge.Core; + +namespace Bridge.Bindings +{ + /// + /// 单次扫描 command stream,并按 func_id 分发到各模块 Host API。 + /// + public static class BridgeAllCommandDispatcher + { + public static unsafe void Dispatch(CommandStream stream, THost host) + where THost : class, DemoAsset.Bindings.IDemoAssetHostApi, DemoEntity.Bindings.IDemoEntityHostApi, DemoLog.Bindings.IDemoLogHostApi + { + if (stream.IsEmpty || host == null) + return; + + byte* cursor = (byte*)stream.Ptr; + byte* end = cursor + (int)stream.Length; + + while (cursor < end) + { + long remaining = end - cursor; + if (remaining < sizeof(BridgeCommandHeader)) + break; + + var header = (BridgeCommandHeader*)cursor; + int size = header->Size; + if (size <= 0) + break; + if (size < sizeof(BridgeCommandHeader) || size > remaining) + break; + + if (header->Type == (ushort)BridgeCommandType.CallHost && size >= sizeof(BridgeCmdCallHost)) + { + var cmd = (BridgeCmdCallHost*)cursor; + uint payloadSize = cmd->PayloadSize; + if (payloadSize <= (uint)(size - sizeof(BridgeCmdCallHost))) + { + byte* payloadPtr = cursor + sizeof(BridgeCmdCallHost); + + switch (cmd->FuncId) + { + case 0x82A5E93Au: + { + if (payloadSize == (uint)sizeof(DemoAsset.Bindings.HostArgs_LoadAsset)) + { + var a = *((DemoAsset.Bindings.HostArgs_LoadAsset*)payloadPtr); + host.LoadAsset(a.RequestId, a.AssetType, a.AssetKey.ToManagedString()); + } + break; + } + case 0xBCAA331Du: + { + if (payloadSize == (uint)sizeof(DemoEntity.Bindings.HostArgs_SpawnEntity)) + { + var a = *((DemoEntity.Bindings.HostArgs_SpawnEntity*)payloadPtr); + host.SpawnEntity(a.EntityId, a.PrefabHandle, a.Transform, a.Flags); + } + break; + } + case 0x20DA0B6Fu: + { + if (payloadSize == (uint)sizeof(DemoEntity.Bindings.HostArgs_SetTransform)) + { + var a = *((DemoEntity.Bindings.HostArgs_SetTransform*)payloadPtr); + host.SetTransform(a.EntityId, a.Mask, a.Transform); + } + break; + } + case 0xC7C1C59Cu: + { + if (payloadSize == (uint)sizeof(DemoEntity.Bindings.HostArgs_DestroyEntity)) + { + var a = *((DemoEntity.Bindings.HostArgs_DestroyEntity*)payloadPtr); + host.DestroyEntity(a.EntityId); + } + break; + } + case 0xDA3184A2u: + { + if (payloadSize == (uint)sizeof(DemoLog.Bindings.HostArgs_Log)) + { + var a = *((DemoLog.Bindings.HostArgs_Log*)payloadPtr); + host.Log(a.Level, a.Message.ToManagedString()); + } + break; + } + } + } + } + + cursor += size; + } + } + } +} diff --git a/Tests/unity/Assets/BridgeDemoGame/Generated/Bridge.AllCommandDispatcher.g.cs.meta b/Tests/unity/Assets/BridgeDemoGame/Generated/Bridge.AllCommandDispatcher.g.cs.meta new file mode 100644 index 0000000..5ccc737 --- /dev/null +++ b/Tests/unity/Assets/BridgeDemoGame/Generated/Bridge.AllCommandDispatcher.g.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: fc514b3fd3ad4185bc24349f56cfa115 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: + diff --git a/Tests/unity/Assets/BridgeDemoGame/Generated/BridgeDemoGame.Generated.asmdef b/Tests/unity/Assets/BridgeDemoGame/Generated/BridgeDemoGame.Generated.asmdef new file mode 100644 index 0000000..09e7a1e --- /dev/null +++ b/Tests/unity/Assets/BridgeDemoGame/Generated/BridgeDemoGame.Generated.asmdef @@ -0,0 +1,7 @@ +{ + "name": "BridgeDemoGame.Generated", + "references": [ + "Bridge.Core" + ], + "allowUnsafeCode": true +} diff --git a/Tests/unity/Assets/BridgeDemoGame/Generated/BridgeDemoGame.Generated.asmdef.meta b/Tests/unity/Assets/BridgeDemoGame/Generated/BridgeDemoGame.Generated.asmdef.meta new file mode 100644 index 0000000..ad0afb3 --- /dev/null +++ b/Tests/unity/Assets/BridgeDemoGame/Generated/BridgeDemoGame.Generated.asmdef.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 0808661f311746ffa0ea89fbfd6bbae6 +AssemblyDefinitionImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Tests/unity/Assets/BridgeDemoGame/Generated/DemoAsset.CoreCalls.g.cs b/Tests/unity/Assets/BridgeDemoGame/Generated/DemoAsset.CoreCalls.g.cs new file mode 100644 index 0000000..3a7406c --- /dev/null +++ b/Tests/unity/Assets/BridgeDemoGame/Generated/DemoAsset.CoreCalls.g.cs @@ -0,0 +1,23 @@ +// +// 由 Core/Tools/BridgeGen 生成,请勿手改。 +// + +using Bridge.Core; + +namespace DemoAsset.Bindings +{ + public static class DemoAssetCoreCalls + { + public static void AssetLoaded(this BridgeCore core, ulong requestId, ulong handle, BridgeAssetStatus status) + { + var a = new CoreArgs_AssetLoaded + { + RequestId = requestId, + Handle = handle, + Status = status, + }; + core.PushCallCore((uint)CoreFuncId.AssetLoaded, a); + } + + } +} diff --git a/Tests/unity/Assets/BridgeDemoGame/Generated/DemoAsset.CoreCalls.g.cs.meta b/Tests/unity/Assets/BridgeDemoGame/Generated/DemoAsset.CoreCalls.g.cs.meta new file mode 100644 index 0000000..4294a05 --- /dev/null +++ b/Tests/unity/Assets/BridgeDemoGame/Generated/DemoAsset.CoreCalls.g.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 7002f58cf498473d83422c8c2695f80f +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: + diff --git a/Tests/unity/Assets/BridgeDemoGame/Generated/DemoAsset.Ids.g.cs b/Tests/unity/Assets/BridgeDemoGame/Generated/DemoAsset.Ids.g.cs new file mode 100644 index 0000000..dcbfa24 --- /dev/null +++ b/Tests/unity/Assets/BridgeDemoGame/Generated/DemoAsset.Ids.g.cs @@ -0,0 +1,16 @@ +// +// 由 Core/Tools/BridgeGen 生成,请勿手改。 +// + +namespace DemoAsset.Bindings +{ + public enum HostFuncId : uint + { + LoadAsset = 0x82A5E93Au, + } + + public enum CoreFuncId : uint + { + AssetLoaded = 0x2442BC8Au, + } +} diff --git a/Tests/unity/Assets/BridgeDemoGame/Generated/DemoAsset.Ids.g.cs.meta b/Tests/unity/Assets/BridgeDemoGame/Generated/DemoAsset.Ids.g.cs.meta new file mode 100644 index 0000000..216dbb2 --- /dev/null +++ b/Tests/unity/Assets/BridgeDemoGame/Generated/DemoAsset.Ids.g.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 3ab6a096fbd04985972e4ee886cd165f +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: + diff --git a/Tests/unity/Assets/BridgeDemoGame/Generated/DemoAsset.Structs.g.cs b/Tests/unity/Assets/BridgeDemoGame/Generated/DemoAsset.Structs.g.cs new file mode 100644 index 0000000..eb6a5de --- /dev/null +++ b/Tests/unity/Assets/BridgeDemoGame/Generated/DemoAsset.Structs.g.cs @@ -0,0 +1,26 @@ +// +// 由 Core/Tools/BridgeGen 生成,请勿手改。 +// + +using System.Runtime.InteropServices; +using Bridge.Core; + +namespace DemoAsset.Bindings +{ + [StructLayout(LayoutKind.Sequential)] + public struct HostArgs_LoadAsset + { + public ulong RequestId; + public BridgeAssetType AssetType; + public BridgeStringView AssetKey; + } + + [StructLayout(LayoutKind.Sequential)] + public struct CoreArgs_AssetLoaded + { + public ulong RequestId; + public ulong Handle; + public BridgeAssetStatus Status; + } + +} diff --git a/Tests/unity/Assets/BridgeDemoGame/Generated/DemoAsset.Structs.g.cs.meta b/Tests/unity/Assets/BridgeDemoGame/Generated/DemoAsset.Structs.g.cs.meta new file mode 100644 index 0000000..c5fbcd9 --- /dev/null +++ b/Tests/unity/Assets/BridgeDemoGame/Generated/DemoAsset.Structs.g.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: d163877d165040f6bf94d7343d2cf822 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: + diff --git a/Tests/unity/Assets/BridgeDemoGame/Generated/DemoEntity.CoreCalls.g.cs b/Tests/unity/Assets/BridgeDemoGame/Generated/DemoEntity.CoreCalls.g.cs new file mode 100644 index 0000000..d20621e --- /dev/null +++ b/Tests/unity/Assets/BridgeDemoGame/Generated/DemoEntity.CoreCalls.g.cs @@ -0,0 +1,12 @@ +// +// 由 Core/Tools/BridgeGen 生成,请勿手改。 +// + +using Bridge.Core; + +namespace DemoEntity.Bindings +{ + public static class DemoEntityCoreCalls + { + } +} diff --git a/Tests/unity/Assets/BridgeDemoGame/Generated/DemoEntity.CoreCalls.g.cs.meta b/Tests/unity/Assets/BridgeDemoGame/Generated/DemoEntity.CoreCalls.g.cs.meta new file mode 100644 index 0000000..70d4869 --- /dev/null +++ b/Tests/unity/Assets/BridgeDemoGame/Generated/DemoEntity.CoreCalls.g.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: a0e77fe4bd3548f28a561d244fe12c88 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: + diff --git a/Tests/unity/Assets/BridgeDemoGame/Generated/DemoEntity.Ids.g.cs b/Tests/unity/Assets/BridgeDemoGame/Generated/DemoEntity.Ids.g.cs new file mode 100644 index 0000000..139525c --- /dev/null +++ b/Tests/unity/Assets/BridgeDemoGame/Generated/DemoEntity.Ids.g.cs @@ -0,0 +1,17 @@ +// +// 由 Core/Tools/BridgeGen 生成,请勿手改。 +// + +namespace DemoEntity.Bindings +{ + public enum HostFuncId : uint + { + SpawnEntity = 0xBCAA331Du, + SetTransform = 0x20DA0B6Fu, + DestroyEntity = 0xC7C1C59Cu, + } + + public enum CoreFuncId : uint + { + } +} diff --git a/Tests/unity/Assets/BridgeDemoGame/Generated/DemoEntity.Ids.g.cs.meta b/Tests/unity/Assets/BridgeDemoGame/Generated/DemoEntity.Ids.g.cs.meta new file mode 100644 index 0000000..f88eb4a --- /dev/null +++ b/Tests/unity/Assets/BridgeDemoGame/Generated/DemoEntity.Ids.g.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 87ea94031c65443fa4680a4634c2b2a9 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: + diff --git a/Tests/unity/Assets/BridgeDemoGame/Generated/DemoEntity.Structs.g.cs b/Tests/unity/Assets/BridgeDemoGame/Generated/DemoEntity.Structs.g.cs new file mode 100644 index 0000000..48c0308 --- /dev/null +++ b/Tests/unity/Assets/BridgeDemoGame/Generated/DemoEntity.Structs.g.cs @@ -0,0 +1,33 @@ +// +// 由 Core/Tools/BridgeGen 生成,请勿手改。 +// + +using System.Runtime.InteropServices; +using Bridge.Core; + +namespace DemoEntity.Bindings +{ + [StructLayout(LayoutKind.Sequential)] + public struct HostArgs_SpawnEntity + { + public ulong EntityId; + public ulong PrefabHandle; + public BridgeTransform Transform; + public uint Flags; + } + + [StructLayout(LayoutKind.Sequential)] + public struct HostArgs_SetTransform + { + public ulong EntityId; + public uint Mask; + public BridgeTransform Transform; + } + + [StructLayout(LayoutKind.Sequential)] + public struct HostArgs_DestroyEntity + { + public ulong EntityId; + } + +} diff --git a/Tests/unity/Assets/BridgeDemoGame/Generated/DemoEntity.Structs.g.cs.meta b/Tests/unity/Assets/BridgeDemoGame/Generated/DemoEntity.Structs.g.cs.meta new file mode 100644 index 0000000..00f5d20 --- /dev/null +++ b/Tests/unity/Assets/BridgeDemoGame/Generated/DemoEntity.Structs.g.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 854a63392d2849a08ec691d9ba02280b +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: + diff --git a/Tests/unity/Assets/BridgeDemoGame/Generated/DemoLog.CoreCalls.g.cs b/Tests/unity/Assets/BridgeDemoGame/Generated/DemoLog.CoreCalls.g.cs new file mode 100644 index 0000000..c00b537 --- /dev/null +++ b/Tests/unity/Assets/BridgeDemoGame/Generated/DemoLog.CoreCalls.g.cs @@ -0,0 +1,12 @@ +// +// 由 Core/Tools/BridgeGen 生成,请勿手改。 +// + +using Bridge.Core; + +namespace DemoLog.Bindings +{ + public static class DemoLogCoreCalls + { + } +} diff --git a/Tests/unity/Assets/BridgeDemoGame/Generated/DemoLog.CoreCalls.g.cs.meta b/Tests/unity/Assets/BridgeDemoGame/Generated/DemoLog.CoreCalls.g.cs.meta new file mode 100644 index 0000000..113323f --- /dev/null +++ b/Tests/unity/Assets/BridgeDemoGame/Generated/DemoLog.CoreCalls.g.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 7e402fe3ecf74180ba7932fff8db4360 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: + diff --git a/Tests/unity/Assets/BridgeDemoGame/Generated/DemoLog.Ids.g.cs b/Tests/unity/Assets/BridgeDemoGame/Generated/DemoLog.Ids.g.cs new file mode 100644 index 0000000..790cb61 --- /dev/null +++ b/Tests/unity/Assets/BridgeDemoGame/Generated/DemoLog.Ids.g.cs @@ -0,0 +1,15 @@ +// +// 由 Core/Tools/BridgeGen 生成,请勿手改。 +// + +namespace DemoLog.Bindings +{ + public enum HostFuncId : uint + { + Log = 0xDA3184A2u, + } + + public enum CoreFuncId : uint + { + } +} diff --git a/Tests/unity/Assets/BridgeDemoGame/Generated/DemoLog.Ids.g.cs.meta b/Tests/unity/Assets/BridgeDemoGame/Generated/DemoLog.Ids.g.cs.meta new file mode 100644 index 0000000..74fca32 --- /dev/null +++ b/Tests/unity/Assets/BridgeDemoGame/Generated/DemoLog.Ids.g.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 8c705420db0a452ba0e13d4c64b156cd +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: + diff --git a/Tests/unity/Assets/BridgeDemoGame/Generated/DemoLog.Structs.g.cs b/Tests/unity/Assets/BridgeDemoGame/Generated/DemoLog.Structs.g.cs new file mode 100644 index 0000000..0836d7d --- /dev/null +++ b/Tests/unity/Assets/BridgeDemoGame/Generated/DemoLog.Structs.g.cs @@ -0,0 +1,17 @@ +// +// 由 Core/Tools/BridgeGen 生成,请勿手改。 +// + +using System.Runtime.InteropServices; +using Bridge.Core; + +namespace DemoLog.Bindings +{ + [StructLayout(LayoutKind.Sequential)] + public struct HostArgs_Log + { + public BridgeLogLevel Level; + public BridgeStringView Message; + } + +} diff --git a/Tests/unity/Assets/BridgeDemoGame/Generated/DemoLog.Structs.g.cs.meta b/Tests/unity/Assets/BridgeDemoGame/Generated/DemoLog.Structs.g.cs.meta new file mode 100644 index 0000000..1e5012d --- /dev/null +++ b/Tests/unity/Assets/BridgeDemoGame/Generated/DemoLog.Structs.g.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 83f37968760a4bec8281720546ad8b92 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: + diff --git a/Tests/unity/Assets/BridgeDemoGame/Generated/IDemoAssetHostApi.g.cs b/Tests/unity/Assets/BridgeDemoGame/Generated/IDemoAssetHostApi.g.cs new file mode 100644 index 0000000..c5fa10d --- /dev/null +++ b/Tests/unity/Assets/BridgeDemoGame/Generated/IDemoAssetHostApi.g.cs @@ -0,0 +1,13 @@ +// +// 由 Core/Tools/BridgeGen 生成,请勿手改。 +// + +using Bridge.Core; + +namespace DemoAsset.Bindings +{ + public interface IDemoAssetHostApi + { + void LoadAsset(ulong requestId, BridgeAssetType assetType, string assetKey); + } +} diff --git a/Tests/unity/Assets/BridgeDemoGame/Generated/IDemoAssetHostApi.g.cs.meta b/Tests/unity/Assets/BridgeDemoGame/Generated/IDemoAssetHostApi.g.cs.meta new file mode 100644 index 0000000..15aa960 --- /dev/null +++ b/Tests/unity/Assets/BridgeDemoGame/Generated/IDemoAssetHostApi.g.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: c5ca6178c9b24818bc057984e516d4a8 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: + diff --git a/Tests/unity/Assets/BridgeDemoGame/Generated/IDemoEntityHostApi.g.cs b/Tests/unity/Assets/BridgeDemoGame/Generated/IDemoEntityHostApi.g.cs new file mode 100644 index 0000000..449e796 --- /dev/null +++ b/Tests/unity/Assets/BridgeDemoGame/Generated/IDemoEntityHostApi.g.cs @@ -0,0 +1,15 @@ +// +// 由 Core/Tools/BridgeGen 生成,请勿手改。 +// + +using Bridge.Core; + +namespace DemoEntity.Bindings +{ + public interface IDemoEntityHostApi + { + void SpawnEntity(ulong entityId, ulong prefabHandle, BridgeTransform transform, uint flags); + void SetTransform(ulong entityId, uint mask, BridgeTransform transform); + void DestroyEntity(ulong entityId); + } +} diff --git a/Tests/unity/Assets/BridgeDemoGame/Generated/IDemoEntityHostApi.g.cs.meta b/Tests/unity/Assets/BridgeDemoGame/Generated/IDemoEntityHostApi.g.cs.meta new file mode 100644 index 0000000..67e1a0d --- /dev/null +++ b/Tests/unity/Assets/BridgeDemoGame/Generated/IDemoEntityHostApi.g.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 0eb2716d4aa54a65acc1fa189864351f +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: + diff --git a/Tests/unity/Assets/BridgeDemoGame/Generated/IDemoLogHostApi.g.cs b/Tests/unity/Assets/BridgeDemoGame/Generated/IDemoLogHostApi.g.cs new file mode 100644 index 0000000..41676fb --- /dev/null +++ b/Tests/unity/Assets/BridgeDemoGame/Generated/IDemoLogHostApi.g.cs @@ -0,0 +1,13 @@ +// +// 由 Core/Tools/BridgeGen 生成,请勿手改。 +// + +using Bridge.Core; + +namespace DemoLog.Bindings +{ + public interface IDemoLogHostApi + { + void Log(BridgeLogLevel level, string message); + } +} diff --git a/Tests/unity/Assets/BridgeDemoGame/Generated/IDemoLogHostApi.g.cs.meta b/Tests/unity/Assets/BridgeDemoGame/Generated/IDemoLogHostApi.g.cs.meta new file mode 100644 index 0000000..05acf38 --- /dev/null +++ b/Tests/unity/Assets/BridgeDemoGame/Generated/IDemoLogHostApi.g.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 256ab2f970044295927f6bde21e2cd2c +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: + diff --git a/Tests/unity/Assets/BridgeDemoGame/README.md b/Tests/unity/Assets/BridgeDemoGame/README.md new file mode 100644 index 0000000..0a2469a --- /dev/null +++ b/Tests/unity/Assets/BridgeDemoGame/README.md @@ -0,0 +1,62 @@ +# DemoGame(Unity Host 范例) + +目标:在 Unity 中复用与 `Tests/csharp/RobotHost` 相同的协议与 Core,但把资源读取改为 Unity API(`Resources.LoadAsync`)。 + +## 运行步骤(Windows Editor) + +1) 在仓库根目录构建原生库: + +```powershell +cmake -S . -B build -DCMAKE_BUILD_TYPE=Release +cmake --build build --config Release +``` + +确保存在:`build/bin/Release/bridge_core.dll` + +也可以直接在 Unity 菜单执行: + +- `BridgeCore/Windows/Build + Hot Reload (Release)` + +2) 用 Unity 打开工程:`Tests/unity` + +3) 新建一个空场景,创建空 GameObject,挂载组件: + +- `BridgeDemoGame.DemoGameUnityRunner` + +保持默认参数即可(`Bots=1`)。 + +4) 点击 Play + +预期效果: + +- Core 会请求 `Main/Prefabs/Bot`(对应 `Assets/BridgeDemoGame/Resources/Main/Prefabs/Bot.bytes`) +- Host 收到 `LoadAsset` 后通过 `Resources.LoadAsync` 读取并回推 `AssetLoaded` +- Core 随后输出 `SpawnEntity` / `SetTransform`,Unity 侧会生成一个 Capsule 并沿 X 轴移动 + +## 常用配置 + +- 环境变量 `BRIDGE_CORE_DLL`:可指定源 `bridge_core.dll` 的绝对路径(优先级最高) +- `DemoGameUnityRunner.Bots`:多实例(超过 `MaxBotsWithRendering` 会自动关闭渲染命令) + +## 性能测试(Unity Performance Test Framework) + +已在工程内加入 `com.unity.test-framework.performance`,并提供 EditMode 性能用例: + +- `BridgeDemoGame.Tests.BridgeDispatchPerformanceTests.TickAndDispatch_OneFrame` + +命令行运行(Windows / PowerShell): + +```powershell +& "C:\\Program Files\\Unity\\Hub\\Editor\\6000.0.40f1\\Editor\\Unity.exe" ` + -batchmode -nographics -quit ` + -projectPath "D:\\UGit\\UnityNativeScripting\\Tests\\unity" ` + -runTests -testPlatform EditMode ` + -testResults "D:\\UGit\\UnityNativeScripting\\build\\unity-editmode-test-results.xml" ` + -perfTestResults "D:\\UGit\\UnityNativeScripting\\build\\unity-editmode-perf-results.json" ` + -logFile "D:\\UGit\\UnityNativeScripting\\build\\unity-editmode-test.log" +``` + +注意: + +- `-testPlatform` 在 Unity 6 下建议使用 `EditMode` / `PlayMode`(大小写匹配)。 +- 如果 `Tests/unity` 工程已在 Unity Editor 中打开,命令行跑测试会被锁定;请先关闭该工程的 Editor 实例。 diff --git a/Unity/Assets/NativeScript/VERSION.txt.meta b/Tests/unity/Assets/BridgeDemoGame/README.md.meta similarity index 54% rename from Unity/Assets/NativeScript/VERSION.txt.meta rename to Tests/unity/Assets/BridgeDemoGame/README.md.meta index 059b3f5..6161a9a 100644 --- a/Unity/Assets/NativeScript/VERSION.txt.meta +++ b/Tests/unity/Assets/BridgeDemoGame/README.md.meta @@ -1,8 +1,8 @@ fileFormatVersion: 2 -guid: b5930bc09a4784968b77045e37b77968 -timeCreated: 1503122108 -licenseType: Free +guid: 6e2a5b7c8d9e4f0a1b2c3d4e5f607182 TextScriptImporter: + externalObjects: {} userData: assetBundleName: assetBundleVariant: + diff --git a/Tests/unity/Assets/BridgeDemoGame/Resources.meta b/Tests/unity/Assets/BridgeDemoGame/Resources.meta new file mode 100644 index 0000000..6a7b9e8 --- /dev/null +++ b/Tests/unity/Assets/BridgeDemoGame/Resources.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 2a8c1d3e4f5b4c6d9e0f1a2b3c4d5e6f +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: + diff --git a/Tests/unity/Assets/BridgeDemoGame/Resources/Main.meta b/Tests/unity/Assets/BridgeDemoGame/Resources/Main.meta new file mode 100644 index 0000000..cb6c969 --- /dev/null +++ b/Tests/unity/Assets/BridgeDemoGame/Resources/Main.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 3b9d2e4f5a6c4d7e8f0a1b2c3d4e5f60 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: + diff --git a/Tests/unity/Assets/BridgeDemoGame/Resources/Main/Prefabs.meta b/Tests/unity/Assets/BridgeDemoGame/Resources/Main/Prefabs.meta new file mode 100644 index 0000000..2093793 --- /dev/null +++ b/Tests/unity/Assets/BridgeDemoGame/Resources/Main/Prefabs.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 4c0e3f5a6b7d4e8f9a0b1c2d3e4f5061 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: + diff --git a/Tests/unity/Assets/BridgeDemoGame/Resources/Main/Prefabs/Bot.bytes b/Tests/unity/Assets/BridgeDemoGame/Resources/Main/Prefabs/Bot.bytes new file mode 100644 index 0000000..d35bbad --- /dev/null +++ b/Tests/unity/Assets/BridgeDemoGame/Resources/Main/Prefabs/Bot.bytes @@ -0,0 +1,2 @@ +DemoPrefab: Bot + diff --git a/Unity/Assets/NativeScriptTypes.json.meta b/Tests/unity/Assets/BridgeDemoGame/Resources/Main/Prefabs/Bot.bytes.meta similarity index 54% rename from Unity/Assets/NativeScriptTypes.json.meta rename to Tests/unity/Assets/BridgeDemoGame/Resources/Main/Prefabs/Bot.bytes.meta index f3143ad..63a0fab 100644 --- a/Unity/Assets/NativeScriptTypes.json.meta +++ b/Tests/unity/Assets/BridgeDemoGame/Resources/Main/Prefabs/Bot.bytes.meta @@ -1,8 +1,8 @@ fileFormatVersion: 2 -guid: b6fdf41c47dd54c009e401c6b8f50f98 -timeCreated: 1501974609 -licenseType: Free +guid: 5d1f4a6b7c8e4f9a0b1c2d3e4f506172 TextScriptImporter: + externalObjects: {} userData: assetBundleName: assetBundleVariant: + diff --git a/Tests/unity/Assets/BridgeDemoGame/Runtime.meta b/Tests/unity/Assets/BridgeDemoGame/Runtime.meta new file mode 100644 index 0000000..b63421c --- /dev/null +++ b/Tests/unity/Assets/BridgeDemoGame/Runtime.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 9c8d7e6f5a4b3c2d1e0f9a8b7c6d5e4f +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: + diff --git a/Tests/unity/Assets/BridgeDemoGame/Runtime/DemoGameUnityAssetService.cs b/Tests/unity/Assets/BridgeDemoGame/Runtime/DemoGameUnityAssetService.cs new file mode 100644 index 0000000..9e9bbd2 --- /dev/null +++ b/Tests/unity/Assets/BridgeDemoGame/Runtime/DemoGameUnityAssetService.cs @@ -0,0 +1,133 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using Bridge.Core; +using DemoAsset.Bindings; +using UnityEngine; + +namespace BridgeDemoGame +{ + public sealed class DemoGameUnityAssetService : MonoBehaviour + { + private readonly Dictionary _pending = new Dictionary(StringComparer.Ordinal); + private readonly Dictionary _assetKeyToHandle = new Dictionary(StringComparer.Ordinal); + private readonly Dictionary _handleToAsset = new Dictionary(); + + public bool TryGetTextAsset(ulong handle, out TextAsset asset) + { + return _handleToAsset.TryGetValue(handle, out asset); + } + + public void RequestLoad(BridgeCore core, ulong requestId, BridgeAssetType assetType, string assetKey) + { + if (core == null) + return; + + if (assetType != BridgeAssetType.Prefab) + { + core.AssetLoaded(requestId, 0, BridgeAssetStatus.Error); + return; + } + + if (string.IsNullOrEmpty(assetKey)) + { + core.AssetLoaded(requestId, 0, BridgeAssetStatus.NotFound); + return; + } + + if (_assetKeyToHandle.TryGetValue(assetKey, out ulong cachedHandle) && cachedHandle != 0) + { + core.AssetLoaded(requestId, cachedHandle, BridgeAssetStatus.Ok); + return; + } + + if (_pending.TryGetValue(assetKey, out PendingAssetLoad pending)) + { + pending.Waiters.Add(new PendingRequest(core, requestId)); + return; + } + + pending = new PendingAssetLoad(assetKey); + pending.Waiters.Add(new PendingRequest(core, requestId)); + _pending.Add(assetKey, pending); + StartCoroutine(LoadCoroutine(pending)); + } + + private IEnumerator LoadCoroutine(PendingAssetLoad pending) + { + ResourceRequest req = Resources.LoadAsync(pending.AssetKey); + yield return req; + + TextAsset textAsset = req.asset as TextAsset; + if (textAsset == null) + { + Complete(pending, handle: 0, BridgeAssetStatus.NotFound); + yield break; + } + + ulong handle = Fnv1a64(textAsset.bytes); + if (handle == 0) + handle = 1; + + _assetKeyToHandle[pending.AssetKey] = handle; + _handleToAsset[handle] = textAsset; + + Complete(pending, handle, BridgeAssetStatus.Ok); + } + + private void Complete(PendingAssetLoad pending, ulong handle, BridgeAssetStatus status) + { + _pending.Remove(pending.AssetKey); + + for (int i = 0; i < pending.Waiters.Count; i++) + { + PendingRequest r = pending.Waiters[i]; + try + { + r.Core.AssetLoaded(r.RequestId, handle, status); + } + catch + { + // Core 已销毁或异常时忽略(示例工程不做强保证)。 + } + } + } + + private static ulong Fnv1a64(byte[] bytes) + { + const ulong offset = 1469598103934665603ul; + const ulong prime = 1099511628211ul; + + ulong hash = offset; + for (int i = 0; i < bytes.Length; i++) + { + hash ^= bytes[i]; + hash *= prime; + } + return hash; + } + + private sealed class PendingAssetLoad + { + public readonly string AssetKey; + public readonly List Waiters = new List(); + + public PendingAssetLoad(string assetKey) + { + AssetKey = assetKey; + } + } + + private readonly struct PendingRequest + { + public readonly BridgeCore Core; + public readonly ulong RequestId; + + public PendingRequest(BridgeCore core, ulong requestId) + { + Core = core; + RequestId = requestId; + } + } + } +} diff --git a/Tests/unity/Assets/BridgeDemoGame/Runtime/DemoGameUnityAssetService.cs.meta b/Tests/unity/Assets/BridgeDemoGame/Runtime/DemoGameUnityAssetService.cs.meta new file mode 100644 index 0000000..f4548fa --- /dev/null +++ b/Tests/unity/Assets/BridgeDemoGame/Runtime/DemoGameUnityAssetService.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 0d6c7b8a9f1e2d3c4b5a69788796a5b4 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: + diff --git a/Tests/unity/Assets/BridgeDemoGame/Runtime/DemoGameUnityHostApi.Asset.cs b/Tests/unity/Assets/BridgeDemoGame/Runtime/DemoGameUnityHostApi.Asset.cs new file mode 100644 index 0000000..b27941f --- /dev/null +++ b/Tests/unity/Assets/BridgeDemoGame/Runtime/DemoGameUnityHostApi.Asset.cs @@ -0,0 +1,16 @@ +using Bridge.Core; +using DemoAsset.Bindings; + +namespace BridgeDemoGame +{ + public sealed partial class DemoGameUnityHostApi : IDemoAssetHostApi + { + public void LoadAsset(ulong requestId, BridgeAssetType assetType, string assetKey) + { + Commands++; + AssetRequests++; + + _assets.RequestLoad(_core, requestId, assetType, assetKey); + } + } +} \ No newline at end of file diff --git a/Tests/unity/Assets/BridgeDemoGame/Runtime/DemoGameUnityHostApi.Asset.cs.meta b/Tests/unity/Assets/BridgeDemoGame/Runtime/DemoGameUnityHostApi.Asset.cs.meta new file mode 100644 index 0000000..077c05d --- /dev/null +++ b/Tests/unity/Assets/BridgeDemoGame/Runtime/DemoGameUnityHostApi.Asset.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 0438030728f94c89907f2d08ff1f694f +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: + diff --git a/Tests/unity/Assets/BridgeDemoGame/Runtime/DemoGameUnityHostApi.Entity.cs b/Tests/unity/Assets/BridgeDemoGame/Runtime/DemoGameUnityHostApi.Entity.cs new file mode 100644 index 0000000..eaf1e6d --- /dev/null +++ b/Tests/unity/Assets/BridgeDemoGame/Runtime/DemoGameUnityHostApi.Entity.cs @@ -0,0 +1,60 @@ +using Bridge.Core; +using DemoEntity.Bindings; +using UnityEngine; + +namespace BridgeDemoGame +{ + public sealed partial class DemoGameUnityHostApi : IDemoEntityHostApi + { + public void SpawnEntity(ulong entityId, ulong prefabHandle, BridgeTransform transform, uint flags) + { + _ = prefabHandle; + _ = flags; + + Commands++; + Spawns++; + + if (!_enableRendering) + return; + + if (_entities.TryGetValue(entityId, out GameObject existing) && existing != null) + { + Object.Destroy(existing); + _entities.Remove(entityId); + } + + GameObject go = GameObject.CreatePrimitive(PrimitiveType.Capsule); + go.name = "Entity_" + entityId; + ApplyTransform(go.transform, transform, mask: 0x7u); + _entities[entityId] = go; + } + + public void SetTransform(ulong entityId, uint mask, BridgeTransform transform) + { + Commands++; + Transforms++; + + if (!_enableRendering) + return; + + if (_entities.TryGetValue(entityId, out GameObject go) && go != null) + ApplyTransform(go.transform, transform, mask); + } + + public void DestroyEntity(ulong entityId) + { + Commands++; + Destroys++; + + if (!_enableRendering) + return; + + if (_entities.TryGetValue(entityId, out GameObject go)) + { + if (go != null) + Object.Destroy(go); + _entities.Remove(entityId); + } + } + } +} \ No newline at end of file diff --git a/Tests/unity/Assets/BridgeDemoGame/Runtime/DemoGameUnityHostApi.Entity.cs.meta b/Tests/unity/Assets/BridgeDemoGame/Runtime/DemoGameUnityHostApi.Entity.cs.meta new file mode 100644 index 0000000..22d674a --- /dev/null +++ b/Tests/unity/Assets/BridgeDemoGame/Runtime/DemoGameUnityHostApi.Entity.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 39073b2522ae46f2ba20e5e0cf4a9c2c +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: + diff --git a/Tests/unity/Assets/BridgeDemoGame/Runtime/DemoGameUnityHostApi.Log.cs b/Tests/unity/Assets/BridgeDemoGame/Runtime/DemoGameUnityHostApi.Log.cs new file mode 100644 index 0000000..11e228f --- /dev/null +++ b/Tests/unity/Assets/BridgeDemoGame/Runtime/DemoGameUnityHostApi.Log.cs @@ -0,0 +1,32 @@ +using Bridge.Core; +using DemoLog.Bindings; +using UnityEngine; + +namespace BridgeDemoGame +{ + public sealed partial class DemoGameUnityHostApi: IDemoLogHostApi + { + public void Log(BridgeLogLevel level, string message) + { + Commands++; + Logs++; + + switch (level) + { + case BridgeLogLevel.Debug: + Debug.Log(message); + break; + case BridgeLogLevel.Info: + Debug.Log(message); + break; + case BridgeLogLevel.Warn: + Debug.LogWarning(message); + break; + default: + Debug.LogError(message); + break; + } + } + } +} + diff --git a/Tests/unity/Assets/BridgeDemoGame/Runtime/DemoGameUnityHostApi.Log.cs.meta b/Tests/unity/Assets/BridgeDemoGame/Runtime/DemoGameUnityHostApi.Log.cs.meta new file mode 100644 index 0000000..5d0b71e --- /dev/null +++ b/Tests/unity/Assets/BridgeDemoGame/Runtime/DemoGameUnityHostApi.Log.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 708d0fdac7c645e7901a441b15f102a0 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: + diff --git a/Tests/unity/Assets/BridgeDemoGame/Runtime/DemoGameUnityHostApi.cs b/Tests/unity/Assets/BridgeDemoGame/Runtime/DemoGameUnityHostApi.cs new file mode 100644 index 0000000..8b496dc --- /dev/null +++ b/Tests/unity/Assets/BridgeDemoGame/Runtime/DemoGameUnityHostApi.cs @@ -0,0 +1,44 @@ +using System.Collections.Generic; +using Bridge.Core; +using DemoAsset.Bindings; +using DemoEntity.Bindings; +using DemoLog.Bindings; +using UnityEngine; + +namespace BridgeDemoGame +{ + public sealed partial class DemoGameUnityHostApi + { + private readonly BridgeCore _core; + private readonly DemoGameUnityAssetService _assets; + private readonly bool _enableRendering; + + private readonly Dictionary _entities = new Dictionary(); + + public ulong Commands { get; private set; } + public ulong AssetRequests { get; private set; } + public ulong Logs { get; private set; } + public ulong Spawns { get; private set; } + public ulong Transforms { get; private set; } + public ulong Destroys { get; private set; } + + public DemoGameUnityHostApi(BridgeCore core, DemoGameUnityAssetService assets, bool enableRendering) + { + _core = core; + _assets = assets; + _enableRendering = enableRendering; + } + + private static void ApplyTransform(Transform t, BridgeTransform transform, uint mask) + { + if ((mask & 1u) != 0) + t.position = new Vector3(transform.Position.X, transform.Position.Y, transform.Position.Z); + + if ((mask & 2u) != 0) + t.rotation = new Quaternion(transform.Rotation.X, transform.Rotation.Y, transform.Rotation.Z, transform.Rotation.W); + + if ((mask & 4u) != 0) + t.localScale = new Vector3(transform.Scale.X, transform.Scale.Y, transform.Scale.Z); + } + } +} diff --git a/Tests/unity/Assets/BridgeDemoGame/Runtime/DemoGameUnityHostApi.cs.meta b/Tests/unity/Assets/BridgeDemoGame/Runtime/DemoGameUnityHostApi.cs.meta new file mode 100644 index 0000000..37fa085 --- /dev/null +++ b/Tests/unity/Assets/BridgeDemoGame/Runtime/DemoGameUnityHostApi.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 4adab9f0c1d24a1e9d62f3b4a5c6d7e8 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: + diff --git a/Tests/unity/Assets/BridgeDemoGame/Runtime/DemoGameUnityRunner.cs b/Tests/unity/Assets/BridgeDemoGame/Runtime/DemoGameUnityRunner.cs new file mode 100644 index 0000000..b13e493 --- /dev/null +++ b/Tests/unity/Assets/BridgeDemoGame/Runtime/DemoGameUnityRunner.cs @@ -0,0 +1,67 @@ +using System; +using Bridge.Bindings; +using Bridge.Core; +using UnityEngine; + +namespace BridgeDemoGame +{ + public sealed class DemoGameUnityRunner : MonoBehaviour + { + [Header("Core")] + public int Bots = 1; + public bool RobotMode = false; + + [Header("Host")] + public bool EnableRendering = true; + public int MaxBotsWithRendering = 32; + + private BridgeCore[] _cores = Array.Empty(); + private DemoGameUnityHostApi[] _hosts = Array.Empty(); + private DemoGameUnityAssetService _assets; + + private void Awake() + { + _assets = GetComponent(); + if (_assets == null) + _assets = gameObject.AddComponent(); + } + + private void Start() + { + int bots = Mathf.Max(1, Bots); + _cores = new BridgeCore[bots]; + _hosts = new DemoGameUnityHostApi[bots]; + + bool render = EnableRendering && bots <= MaxBotsWithRendering; + for (int i = 0; i < bots; i++) + { + var core = new BridgeCore(seed: (ulong)(i + 1), robotMode: RobotMode); + _cores[i] = core; + _hosts[i] = new DemoGameUnityHostApi(core, _assets, render); + } + } + + private void Update() + { + float dt = Time.deltaTime; + for (int i = 0; i < _cores.Length; i++) + { + BridgeCore core = _cores[i]; + core.Tick(dt); + + CommandStream stream = core.GetCommandStream(); + BridgeAllCommandDispatcher.Dispatch(stream, _hosts[i]); + } + } + + private void OnDestroy() + { + for (int i = 0; i < _cores.Length; i++) + { + try { _cores[i].Dispose(); } catch { } + } + _cores = Array.Empty(); + _hosts = Array.Empty(); + } + } +} diff --git a/Tests/unity/Assets/BridgeDemoGame/Runtime/DemoGameUnityRunner.cs.meta b/Tests/unity/Assets/BridgeDemoGame/Runtime/DemoGameUnityRunner.cs.meta new file mode 100644 index 0000000..4d65dff --- /dev/null +++ b/Tests/unity/Assets/BridgeDemoGame/Runtime/DemoGameUnityRunner.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 7b9c3d2e1f4a5b6c7d8e9f0a1b2c3d4e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: + diff --git a/Tests/unity/Assets/BridgeDemoGame/Test.unity b/Tests/unity/Assets/BridgeDemoGame/Test.unity new file mode 100644 index 0000000..99b36b0 --- /dev/null +++ b/Tests/unity/Assets/BridgeDemoGame/Test.unity @@ -0,0 +1,378 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!29 &1 +OcclusionCullingSettings: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_OcclusionBakeSettings: + smallestOccluder: 5 + smallestHole: 0.25 + backfaceThreshold: 100 + m_SceneGUID: 00000000000000000000000000000000 + m_OcclusionCullingData: {fileID: 0} +--- !u!104 &2 +RenderSettings: + m_ObjectHideFlags: 0 + serializedVersion: 10 + m_Fog: 0 + m_FogColor: {r: 0.5, g: 0.5, b: 0.5, a: 1} + m_FogMode: 3 + m_FogDensity: 0.01 + m_LinearFogStart: 0 + m_LinearFogEnd: 300 + m_AmbientSkyColor: {r: 0.212, g: 0.227, b: 0.259, a: 1} + m_AmbientEquatorColor: {r: 0.114, g: 0.125, b: 0.133, a: 1} + m_AmbientGroundColor: {r: 0.047, g: 0.043, b: 0.035, a: 1} + m_AmbientIntensity: 1 + m_AmbientMode: 0 + m_SubtractiveShadowColor: {r: 0.42, g: 0.478, b: 0.627, a: 1} + m_SkyboxMaterial: {fileID: 10304, guid: 0000000000000000f000000000000000, type: 0} + m_HaloStrength: 0.5 + m_FlareStrength: 1 + m_FlareFadeSpeed: 3 + m_HaloTexture: {fileID: 0} + m_SpotCookie: {fileID: 10001, guid: 0000000000000000e000000000000000, type: 0} + m_DefaultReflectionMode: 0 + m_DefaultReflectionResolution: 128 + m_ReflectionBounces: 1 + m_ReflectionIntensity: 1 + m_CustomReflection: {fileID: 0} + m_Sun: {fileID: 0} + m_UseRadianceAmbientProbe: 0 +--- !u!157 &3 +LightmapSettings: + m_ObjectHideFlags: 0 + serializedVersion: 13 + m_BakeOnSceneLoad: 0 + m_GISettings: + serializedVersion: 2 + m_BounceScale: 1 + m_IndirectOutputScale: 1 + m_AlbedoBoost: 1 + m_EnvironmentLightingMode: 0 + m_EnableBakedLightmaps: 1 + m_EnableRealtimeLightmaps: 0 + m_LightmapEditorSettings: + serializedVersion: 12 + m_Resolution: 2 + m_BakeResolution: 40 + m_AtlasSize: 1024 + m_AO: 0 + m_AOMaxDistance: 1 + m_CompAOExponent: 1 + m_CompAOExponentDirect: 0 + m_ExtractAmbientOcclusion: 0 + m_Padding: 2 + m_LightmapParameters: {fileID: 0} + m_LightmapsBakeMode: 1 + m_TextureCompression: 1 + m_ReflectionCompression: 2 + m_MixedBakeMode: 2 + m_BakeBackend: 1 + m_PVRSampling: 1 + m_PVRDirectSampleCount: 32 + m_PVRSampleCount: 512 + m_PVRBounces: 2 + m_PVREnvironmentSampleCount: 256 + m_PVREnvironmentReferencePointCount: 2048 + m_PVRFilteringMode: 1 + m_PVRDenoiserTypeDirect: 1 + m_PVRDenoiserTypeIndirect: 1 + m_PVRDenoiserTypeAO: 1 + m_PVRFilterTypeDirect: 0 + m_PVRFilterTypeIndirect: 0 + m_PVRFilterTypeAO: 0 + m_PVREnvironmentMIS: 1 + m_PVRCulling: 1 + m_PVRFilteringGaussRadiusDirect: 1 + m_PVRFilteringGaussRadiusIndirect: 1 + m_PVRFilteringGaussRadiusAO: 1 + m_PVRFilteringAtrousPositionSigmaDirect: 0.5 + m_PVRFilteringAtrousPositionSigmaIndirect: 2 + m_PVRFilteringAtrousPositionSigmaAO: 1 + m_ExportTrainingData: 0 + m_TrainingDataDestination: TrainingData + m_LightProbeSampleCountMultiplier: 4 + m_LightingDataAsset: {fileID: 20201, guid: 0000000000000000f000000000000000, type: 0} + m_LightingSettings: {fileID: 0} +--- !u!196 &4 +NavMeshSettings: + serializedVersion: 2 + m_ObjectHideFlags: 0 + m_BuildSettings: + serializedVersion: 3 + agentTypeID: 0 + agentRadius: 0.5 + agentHeight: 2 + agentSlope: 45 + agentClimb: 0.4 + ledgeDropHeight: 0 + maxJumpAcrossDistance: 0 + minRegionArea: 2 + manualCellSize: 0 + cellSize: 0.16666667 + manualTileSize: 0 + tileSize: 256 + buildHeightMesh: 0 + maxJobWorkers: 0 + preserveTilesOutsideBounds: 0 + debug: + m_Flags: 0 + m_NavMeshData: {fileID: 0} +--- !u!1 &282273562 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 282273565} + - component: {fileID: 282273564} + - component: {fileID: 282273563} + m_Layer: 0 + m_Name: Test + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &282273563 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 282273562} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 0d6c7b8a9f1e2d3c4b5a69788796a5b4, type: 3} + m_Name: + m_EditorClassIdentifier: +--- !u!114 &282273564 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 282273562} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 7b9c3d2e1f4a5b6c7d8e9f0a1b2c3d4e, type: 3} + m_Name: + m_EditorClassIdentifier: + Bots: 1 + RobotMode: 0 + EnableRendering: 1 + MaxBotsWithRendering: 32 +--- !u!4 &282273565 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 282273562} + serializedVersion: 2 + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 0} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &1026717029 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1026717031} + - component: {fileID: 1026717030} + m_Layer: 0 + m_Name: Directional Light + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!108 &1026717030 +Light: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1026717029} + m_Enabled: 1 + serializedVersion: 11 + m_Type: 1 + m_Color: {r: 1, g: 0.95686275, b: 0.8392157, a: 1} + m_Intensity: 1 + m_Range: 10 + m_SpotAngle: 30 + m_InnerSpotAngle: 21.80208 + m_CookieSize: 10 + m_Shadows: + m_Type: 2 + m_Resolution: -1 + m_CustomResolution: -1 + m_Strength: 1 + m_Bias: 0.05 + m_NormalBias: 0.4 + m_NearPlane: 0.2 + m_CullingMatrixOverride: + e00: 1 + e01: 0 + e02: 0 + e03: 0 + e10: 0 + e11: 1 + e12: 0 + e13: 0 + e20: 0 + e21: 0 + e22: 1 + e23: 0 + e30: 0 + e31: 0 + e32: 0 + e33: 1 + m_UseCullingMatrixOverride: 0 + m_Cookie: {fileID: 0} + m_DrawHalo: 0 + m_Flare: {fileID: 0} + m_RenderMode: 0 + m_CullingMask: + serializedVersion: 2 + m_Bits: 4294967295 + m_RenderingLayerMask: 1 + m_Lightmapping: 4 + m_LightShadowCasterMode: 0 + m_AreaSize: {x: 1, y: 1} + m_BounceIntensity: 1 + m_ColorTemperature: 6570 + m_UseColorTemperature: 0 + m_BoundingSphereOverride: {x: 0, y: 0, z: 0, w: 0} + m_UseBoundingSphereOverride: 0 + m_UseViewFrustumForShadowCasterCull: 1 + m_ForceVisible: 0 + m_ShadowRadius: 0 + m_ShadowAngle: 0 + m_LightUnit: 1 + m_LuxAtDistance: 1 + m_EnableSpotReflector: 1 +--- !u!4 &1026717031 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1026717029} + serializedVersion: 2 + m_LocalRotation: {x: 0.40821788, y: -0.23456968, z: 0.10938163, w: 0.8754261} + m_LocalPosition: {x: 0, y: 3, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 0} + m_LocalEulerAnglesHint: {x: 50, y: -30, z: 0} +--- !u!1 &1463934154 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1463934157} + - component: {fileID: 1463934156} + - component: {fileID: 1463934155} + m_Layer: 0 + m_Name: Main Camera + m_TagString: MainCamera + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!81 &1463934155 +AudioListener: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1463934154} + m_Enabled: 1 +--- !u!20 &1463934156 +Camera: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1463934154} + m_Enabled: 1 + serializedVersion: 2 + m_ClearFlags: 1 + m_BackGroundColor: {r: 0.19215687, g: 0.3019608, b: 0.4745098, a: 0} + m_projectionMatrixMode: 1 + m_GateFitMode: 2 + m_FOVAxisMode: 0 + m_Iso: 200 + m_ShutterSpeed: 0.005 + m_Aperture: 16 + m_FocusDistance: 10 + m_FocalLength: 50 + m_BladeCount: 5 + m_Curvature: {x: 2, y: 11} + m_BarrelClipping: 0.25 + m_Anamorphism: 0 + m_SensorSize: {x: 36, y: 24} + m_LensShift: {x: 0, y: 0} + m_NormalizedViewPortRect: + serializedVersion: 2 + x: 0 + y: 0 + width: 1 + height: 1 + near clip plane: 0.3 + far clip plane: 1000 + field of view: 60 + orthographic: 0 + orthographic size: 5 + m_Depth: -1 + m_CullingMask: + serializedVersion: 2 + m_Bits: 4294967295 + m_RenderingPath: -1 + m_TargetTexture: {fileID: 0} + m_TargetDisplay: 0 + m_TargetEye: 3 + m_HDR: 1 + m_AllowMSAA: 1 + m_AllowDynamicResolution: 0 + m_ForceIntoRT: 0 + m_OcclusionCulling: 1 + m_StereoConvergence: 10 + m_StereoSeparation: 0.022 +--- !u!4 &1463934157 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1463934154} + serializedVersion: 2 + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 1, z: -10} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 0} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1660057539 &9223372036854775807 +SceneRoots: + m_ObjectHideFlags: 0 + m_Roots: + - {fileID: 1463934157} + - {fileID: 1026717031} + - {fileID: 282273565} diff --git a/Unity/Assets/CppSource/iOS.cmake.meta b/Tests/unity/Assets/BridgeDemoGame/Test.unity.meta similarity index 58% rename from Unity/Assets/CppSource/iOS.cmake.meta rename to Tests/unity/Assets/BridgeDemoGame/Test.unity.meta index f706a0b..d1b7f2f 100644 --- a/Unity/Assets/CppSource/iOS.cmake.meta +++ b/Tests/unity/Assets/BridgeDemoGame/Test.unity.meta @@ -1,7 +1,5 @@ fileFormatVersion: 2 -guid: 4d9a55f92979e442396f99d94a5e9ec5 -timeCreated: 1525538114 -licenseType: Free +guid: ba598a3968732bf4ab4ee76686d92636 DefaultImporter: externalObjects: {} userData: diff --git a/Tests/unity/Assets/Resources.meta b/Tests/unity/Assets/Resources.meta new file mode 100644 index 0000000..75ee0a5 --- /dev/null +++ b/Tests/unity/Assets/Resources.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 8acd4dff368f3ca419b1d6fc6d1eb188 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Tests/unity/Assets/Resources/BillingMode.json b/Tests/unity/Assets/Resources/BillingMode.json new file mode 100644 index 0000000..6f4bfb7 --- /dev/null +++ b/Tests/unity/Assets/Resources/BillingMode.json @@ -0,0 +1 @@ +{"androidStore":"GooglePlay"} \ No newline at end of file diff --git a/Tests/unity/Assets/Resources/BillingMode.json.meta b/Tests/unity/Assets/Resources/BillingMode.json.meta new file mode 100644 index 0000000..408a60c --- /dev/null +++ b/Tests/unity/Assets/Resources/BillingMode.json.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: c0a2595c79530ad4a9342b3e68361047 +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Unity/Packages/manifest.json b/Tests/unity/Packages/manifest.json similarity index 71% rename from Unity/Packages/manifest.json rename to Tests/unity/Packages/manifest.json index bc19e66..501ef4b 100644 --- a/Unity/Packages/manifest.json +++ b/Tests/unity/Packages/manifest.json @@ -2,20 +2,21 @@ "dependencies": { "com.unity.2d.sprite": "1.0.0", "com.unity.2d.tilemap": "1.0.0", - "com.unity.ads": "2.0.8", - "com.unity.analytics": "3.3.2", - "com.unity.collab-proxy": "1.2.16", - "com.unity.ext.nunit": "1.0.0", - "com.unity.ide.rider": "1.0.8", - "com.unity.ide.vscode": "1.0.7", - "com.unity.multiplayer-hlapi": "1.0.2", - "com.unity.package-manager-ui": "2.2.0", - "com.unity.purchasing": "2.0.6", - "com.unity.test-framework": "1.0.13", - "com.unity.textmeshpro": "2.0.1", - "com.unity.timeline": "1.1.0", - "com.unity.ugui": "1.0.0", - "com.unity.xr.legacyinputhelpers": "2.0.2", + "com.unity.ads": "4.4.2", + "com.unity.ai.navigation": "2.0.6", + "com.unity.analytics": "3.8.1", + "com.unity.collab-proxy": "2.7.1", + "com.unity.ext.nunit": "2.0.5", + "com.unity.ide.rider": "3.0.31", + "com.unity.ide.visualstudio": "2.0.22", + "com.unity.multiplayer.center": "1.0.0", + "com.unity.purchasing": "4.12.2", + "com.unity.test-framework": "1.4.6", + "com.unity.test-framework.performance": "3.2.0", + "com.unity.timeline": "1.8.7", + "com.unity.ugui": "2.0.0", + "com.unity.xr.legacyinputhelpers": "2.1.12", + "com.unity.modules.accessibility": "1.0.0", "com.unity.modules.ai": "1.0.0", "com.unity.modules.androidjni": "1.0.0", "com.unity.modules.animation": "1.0.0", diff --git a/Tests/unity/Packages/packages-lock.json b/Tests/unity/Packages/packages-lock.json new file mode 100644 index 0000000..b870019 --- /dev/null +++ b/Tests/unity/Packages/packages-lock.json @@ -0,0 +1,437 @@ +{ + "dependencies": { + "com.unity.2d.sprite": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": {} + }, + "com.unity.2d.tilemap": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": { + "com.unity.modules.tilemap": "1.0.0", + "com.unity.modules.uielements": "1.0.0" + } + }, + "com.unity.ads": { + "version": "4.4.2", + "depth": 0, + "source": "registry", + "dependencies": { + "com.unity.ugui": "1.0.0" + }, + "url": "https://packages.unity.com" + }, + "com.unity.ai.navigation": { + "version": "2.0.6", + "depth": 0, + "source": "registry", + "dependencies": { + "com.unity.modules.ai": "1.0.0" + }, + "url": "https://packages.unity.com" + }, + "com.unity.analytics": { + "version": "3.8.1", + "depth": 0, + "source": "registry", + "dependencies": { + "com.unity.ugui": "1.0.0", + "com.unity.services.analytics": "1.0.4" + }, + "url": "https://packages.unity.com" + }, + "com.unity.collab-proxy": { + "version": "2.7.1", + "depth": 0, + "source": "registry", + "dependencies": {}, + "url": "https://packages.unity.com" + }, + "com.unity.ext.nunit": { + "version": "2.0.5", + "depth": 0, + "source": "registry", + "dependencies": {}, + "url": "https://packages.unity.com" + }, + "com.unity.ide.rider": { + "version": "3.0.31", + "depth": 0, + "source": "registry", + "dependencies": { + "com.unity.ext.nunit": "1.0.6" + }, + "url": "https://packages.unity.com" + }, + "com.unity.ide.visualstudio": { + "version": "2.0.22", + "depth": 0, + "source": "registry", + "dependencies": { + "com.unity.test-framework": "1.1.9" + }, + "url": "https://packages.unity.com" + }, + "com.unity.multiplayer.center": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": { + "com.unity.modules.uielements": "1.0.0" + } + }, + "com.unity.nuget.newtonsoft-json": { + "version": "3.2.1", + "depth": 2, + "source": "registry", + "dependencies": {}, + "url": "https://packages.unity.com" + }, + "com.unity.purchasing": { + "version": "4.12.2", + "depth": 0, + "source": "registry", + "dependencies": { + "com.unity.ugui": "1.0.0", + "com.unity.services.core": "1.12.5", + "com.unity.modules.androidjni": "1.0.0", + "com.unity.modules.jsonserialize": "1.0.0", + "com.unity.modules.unitywebrequest": "1.0.0" + }, + "url": "https://packages.unity.com" + }, + "com.unity.services.analytics": { + "version": "6.0.1", + "depth": 1, + "source": "registry", + "dependencies": { + "com.unity.ugui": "1.0.0", + "com.unity.services.core": "1.12.4", + "com.unity.modules.jsonserialize": "1.0.0" + }, + "url": "https://packages.unity.com" + }, + "com.unity.services.core": { + "version": "1.14.0", + "depth": 1, + "source": "registry", + "dependencies": { + "com.unity.modules.androidjni": "1.0.0", + "com.unity.nuget.newtonsoft-json": "3.2.1", + "com.unity.modules.unitywebrequest": "1.0.0" + }, + "url": "https://packages.unity.com" + }, + "com.unity.test-framework": { + "version": "1.4.6", + "depth": 0, + "source": "registry", + "dependencies": { + "com.unity.ext.nunit": "2.0.3", + "com.unity.modules.imgui": "1.0.0", + "com.unity.modules.jsonserialize": "1.0.0" + }, + "url": "https://packages.unity.com" + }, + "com.unity.test-framework.performance": { + "version": "3.2.0", + "depth": 0, + "source": "registry", + "dependencies": { + "com.unity.test-framework": "1.1.33", + "com.unity.modules.jsonserialize": "1.0.0" + }, + "url": "https://packages.unity.com" + }, + "com.unity.timeline": { + "version": "1.8.7", + "depth": 0, + "source": "registry", + "dependencies": { + "com.unity.modules.audio": "1.0.0", + "com.unity.modules.director": "1.0.0", + "com.unity.modules.animation": "1.0.0", + "com.unity.modules.particlesystem": "1.0.0" + }, + "url": "https://packages.unity.com" + }, + "com.unity.ugui": { + "version": "2.0.0", + "depth": 0, + "source": "builtin", + "dependencies": { + "com.unity.modules.ui": "1.0.0", + "com.unity.modules.imgui": "1.0.0" + } + }, + "com.unity.xr.legacyinputhelpers": { + "version": "2.1.12", + "depth": 0, + "source": "registry", + "dependencies": { + "com.unity.modules.vr": "1.0.0", + "com.unity.modules.xr": "1.0.0" + }, + "url": "https://packages.unity.com" + }, + "com.unity.modules.accessibility": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": {} + }, + "com.unity.modules.ai": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": {} + }, + "com.unity.modules.androidjni": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": {} + }, + "com.unity.modules.animation": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": {} + }, + "com.unity.modules.assetbundle": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": {} + }, + "com.unity.modules.audio": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": {} + }, + "com.unity.modules.cloth": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": { + "com.unity.modules.physics": "1.0.0" + } + }, + "com.unity.modules.director": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": { + "com.unity.modules.audio": "1.0.0", + "com.unity.modules.animation": "1.0.0" + } + }, + "com.unity.modules.hierarchycore": { + "version": "1.0.0", + "depth": 1, + "source": "builtin", + "dependencies": {} + }, + "com.unity.modules.imageconversion": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": {} + }, + "com.unity.modules.imgui": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": {} + }, + "com.unity.modules.jsonserialize": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": {} + }, + "com.unity.modules.particlesystem": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": {} + }, + "com.unity.modules.physics": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": {} + }, + "com.unity.modules.physics2d": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": {} + }, + "com.unity.modules.screencapture": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": { + "com.unity.modules.imageconversion": "1.0.0" + } + }, + "com.unity.modules.subsystems": { + "version": "1.0.0", + "depth": 1, + "source": "builtin", + "dependencies": { + "com.unity.modules.jsonserialize": "1.0.0" + } + }, + "com.unity.modules.terrain": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": {} + }, + "com.unity.modules.terrainphysics": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": { + "com.unity.modules.physics": "1.0.0", + "com.unity.modules.terrain": "1.0.0" + } + }, + "com.unity.modules.tilemap": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": { + "com.unity.modules.physics2d": "1.0.0" + } + }, + "com.unity.modules.ui": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": {} + }, + "com.unity.modules.uielements": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": { + "com.unity.modules.ui": "1.0.0", + "com.unity.modules.imgui": "1.0.0", + "com.unity.modules.jsonserialize": "1.0.0", + "com.unity.modules.hierarchycore": "1.0.0" + } + }, + "com.unity.modules.umbra": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": {} + }, + "com.unity.modules.unityanalytics": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": { + "com.unity.modules.unitywebrequest": "1.0.0", + "com.unity.modules.jsonserialize": "1.0.0" + } + }, + "com.unity.modules.unitywebrequest": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": {} + }, + "com.unity.modules.unitywebrequestassetbundle": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": { + "com.unity.modules.assetbundle": "1.0.0", + "com.unity.modules.unitywebrequest": "1.0.0" + } + }, + "com.unity.modules.unitywebrequestaudio": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": { + "com.unity.modules.unitywebrequest": "1.0.0", + "com.unity.modules.audio": "1.0.0" + } + }, + "com.unity.modules.unitywebrequesttexture": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": { + "com.unity.modules.unitywebrequest": "1.0.0", + "com.unity.modules.imageconversion": "1.0.0" + } + }, + "com.unity.modules.unitywebrequestwww": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": { + "com.unity.modules.unitywebrequest": "1.0.0", + "com.unity.modules.unitywebrequestassetbundle": "1.0.0", + "com.unity.modules.unitywebrequestaudio": "1.0.0", + "com.unity.modules.audio": "1.0.0", + "com.unity.modules.assetbundle": "1.0.0", + "com.unity.modules.imageconversion": "1.0.0" + } + }, + "com.unity.modules.vehicles": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": { + "com.unity.modules.physics": "1.0.0" + } + }, + "com.unity.modules.video": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": { + "com.unity.modules.audio": "1.0.0", + "com.unity.modules.ui": "1.0.0", + "com.unity.modules.unitywebrequest": "1.0.0" + } + }, + "com.unity.modules.vr": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": { + "com.unity.modules.jsonserialize": "1.0.0", + "com.unity.modules.physics": "1.0.0", + "com.unity.modules.xr": "1.0.0" + } + }, + "com.unity.modules.wind": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": {} + }, + "com.unity.modules.xr": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": { + "com.unity.modules.physics": "1.0.0", + "com.unity.modules.jsonserialize": "1.0.0", + "com.unity.modules.subsystems": "1.0.0" + } + } + } +} diff --git a/Unity/ProjectSettings/AudioManager.asset b/Tests/unity/ProjectSettings/AudioManager.asset similarity index 100% rename from Unity/ProjectSettings/AudioManager.asset rename to Tests/unity/ProjectSettings/AudioManager.asset diff --git a/Unity/ProjectSettings/ClusterInputManager.asset b/Tests/unity/ProjectSettings/ClusterInputManager.asset similarity index 100% rename from Unity/ProjectSettings/ClusterInputManager.asset rename to Tests/unity/ProjectSettings/ClusterInputManager.asset diff --git a/Unity/ProjectSettings/DynamicsManager.asset b/Tests/unity/ProjectSettings/DynamicsManager.asset similarity index 100% rename from Unity/ProjectSettings/DynamicsManager.asset rename to Tests/unity/ProjectSettings/DynamicsManager.asset diff --git a/Unity/ProjectSettings/EditorBuildSettings.asset b/Tests/unity/ProjectSettings/EditorBuildSettings.asset similarity index 100% rename from Unity/ProjectSettings/EditorBuildSettings.asset rename to Tests/unity/ProjectSettings/EditorBuildSettings.asset diff --git a/Unity/ProjectSettings/EditorSettings.asset b/Tests/unity/ProjectSettings/EditorSettings.asset similarity index 100% rename from Unity/ProjectSettings/EditorSettings.asset rename to Tests/unity/ProjectSettings/EditorSettings.asset diff --git a/Unity/ProjectSettings/GraphicsSettings.asset b/Tests/unity/ProjectSettings/GraphicsSettings.asset similarity index 100% rename from Unity/ProjectSettings/GraphicsSettings.asset rename to Tests/unity/ProjectSettings/GraphicsSettings.asset diff --git a/Unity/ProjectSettings/InputManager.asset b/Tests/unity/ProjectSettings/InputManager.asset similarity index 100% rename from Unity/ProjectSettings/InputManager.asset rename to Tests/unity/ProjectSettings/InputManager.asset diff --git a/Tests/unity/ProjectSettings/MemorySettings.asset b/Tests/unity/ProjectSettings/MemorySettings.asset new file mode 100644 index 0000000..5b5face --- /dev/null +++ b/Tests/unity/ProjectSettings/MemorySettings.asset @@ -0,0 +1,35 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!387306366 &1 +MemorySettings: + m_ObjectHideFlags: 0 + m_EditorMemorySettings: + m_MainAllocatorBlockSize: -1 + m_ThreadAllocatorBlockSize: -1 + m_MainGfxBlockSize: -1 + m_ThreadGfxBlockSize: -1 + m_CacheBlockSize: -1 + m_TypetreeBlockSize: -1 + m_ProfilerBlockSize: -1 + m_ProfilerEditorBlockSize: -1 + m_BucketAllocatorGranularity: -1 + m_BucketAllocatorBucketsCount: -1 + m_BucketAllocatorBlockSize: -1 + m_BucketAllocatorBlockCount: -1 + m_ProfilerBucketAllocatorGranularity: -1 + m_ProfilerBucketAllocatorBucketsCount: -1 + m_ProfilerBucketAllocatorBlockSize: -1 + m_ProfilerBucketAllocatorBlockCount: -1 + m_TempAllocatorSizeMain: -1 + m_JobTempAllocatorBlockSize: -1 + m_BackgroundJobTempAllocatorBlockSize: -1 + m_JobTempAllocatorReducedBlockSize: -1 + m_TempAllocatorSizeGIBakingWorker: -1 + m_TempAllocatorSizeNavMeshWorker: -1 + m_TempAllocatorSizeAudioWorker: -1 + m_TempAllocatorSizeCloudWorker: -1 + m_TempAllocatorSizeGfx: -1 + m_TempAllocatorSizeJobWorker: -1 + m_TempAllocatorSizeBackgroundWorker: -1 + m_TempAllocatorSizePreloadManager: -1 + m_PlatformMemorySettings: {} diff --git a/Tests/unity/ProjectSettings/MultiplayerManager.asset b/Tests/unity/ProjectSettings/MultiplayerManager.asset new file mode 100644 index 0000000..2a93664 --- /dev/null +++ b/Tests/unity/ProjectSettings/MultiplayerManager.asset @@ -0,0 +1,7 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!655991488 &1 +MultiplayerManager: + m_ObjectHideFlags: 0 + m_EnableMultiplayerRoles: 0 + m_StrippingTypes: {} diff --git a/Unity/ProjectSettings/NavMeshAreas.asset b/Tests/unity/ProjectSettings/NavMeshAreas.asset similarity index 100% rename from Unity/ProjectSettings/NavMeshAreas.asset rename to Tests/unity/ProjectSettings/NavMeshAreas.asset diff --git a/Unity/ProjectSettings/NavMeshLayers.asset b/Tests/unity/ProjectSettings/NavMeshLayers.asset similarity index 100% rename from Unity/ProjectSettings/NavMeshLayers.asset rename to Tests/unity/ProjectSettings/NavMeshLayers.asset diff --git a/Unity/ProjectSettings/NetworkManager.asset b/Tests/unity/ProjectSettings/NetworkManager.asset similarity index 100% rename from Unity/ProjectSettings/NetworkManager.asset rename to Tests/unity/ProjectSettings/NetworkManager.asset diff --git a/Tests/unity/ProjectSettings/PackageManagerSettings.asset b/Tests/unity/ProjectSettings/PackageManagerSettings.asset new file mode 100644 index 0000000..c7f7c42 --- /dev/null +++ b/Tests/unity/ProjectSettings/PackageManagerSettings.asset @@ -0,0 +1,37 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &1 +MonoBehaviour: + m_ObjectHideFlags: 53 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 13964, guid: 0000000000000000e000000000000000, type: 0} + m_Name: + m_EditorClassIdentifier: + m_EnablePreReleasePackages: 0 + m_AdvancedSettingsExpanded: 1 + m_ScopedRegistriesSettingsExpanded: 1 + m_SeeAllPackageVersions: 0 + m_DismissPreviewPackagesInUse: 0 + oneTimeWarningShown: 0 + oneTimeDeprecatedPopUpShown: 0 + m_Registries: + - m_Id: main + m_Name: + m_Url: https://packages.unity.com + m_Scopes: [] + m_IsDefault: 1 + m_Capabilities: 7 + m_ConfigSource: 0 + m_UserSelectedRegistryName: + m_UserAddingNewScopedRegistry: 0 + m_RegistryInfoDraft: + m_Modified: 0 + m_ErrorMessage: + m_UserModificationsInstanceId: -898 + m_OriginalInstanceId: -900 + m_LoadAssets: 0 diff --git a/Tests/unity/ProjectSettings/Packages/com.unity.services.core/Settings.json b/Tests/unity/ProjectSettings/Packages/com.unity.services.core/Settings.json new file mode 100644 index 0000000..e69de29 diff --git a/Unity/ProjectSettings/Physics2DSettings.asset b/Tests/unity/ProjectSettings/Physics2DSettings.asset similarity index 100% rename from Unity/ProjectSettings/Physics2DSettings.asset rename to Tests/unity/ProjectSettings/Physics2DSettings.asset diff --git a/Unity/ProjectSettings/PresetManager.asset b/Tests/unity/ProjectSettings/PresetManager.asset similarity index 100% rename from Unity/ProjectSettings/PresetManager.asset rename to Tests/unity/ProjectSettings/PresetManager.asset diff --git a/Unity/ProjectSettings/ProjectSettings.asset b/Tests/unity/ProjectSettings/ProjectSettings.asset similarity index 67% rename from Unity/ProjectSettings/ProjectSettings.asset rename to Tests/unity/ProjectSettings/ProjectSettings.asset index 8602e2b..783db7c 100644 --- a/Unity/ProjectSettings/ProjectSettings.asset +++ b/Tests/unity/ProjectSettings/ProjectSettings.asset @@ -3,7 +3,7 @@ --- !u!129 &1 PlayerSettings: m_ObjectHideFlags: 0 - serializedVersion: 18 + serializedVersion: 28 productGUID: 435980e4cf9ff4aa8b71e496e8163063 AndroidProfiler: 0 AndroidFilterTouchesWhenObscured: 0 @@ -48,13 +48,17 @@ PlayerSettings: defaultScreenHeightWeb: 600 m_StereoRenderingPath: 0 m_ActiveColorSpace: 0 + unsupportedMSAAFallback: 0 + m_SpriteBatchMaxVertexCount: 65535 + m_SpriteBatchVertexThreshold: 300 m_MTRendering: 1 + mipStripping: 0 + numberOfMipsStripped: 0 + numberOfMipsStrippedPerMipmapLimitGroup: {} m_StackTraceTypes: 010000000100000001000000010000000100000001000000 iosShowActivityIndicatorOnLoading: -1 androidShowActivityIndicatorOnLoading: -1 - displayResolutionDialog: 1 iosUseCustomAppBackgroundBehavior: 0 - iosAllowHTTPDownload: 1 allowedAutorotateToPortrait: 1 allowedAutorotateToPortraitUpsideDown: 1 allowedAutorotateToLandscapeRight: 1 @@ -67,10 +71,18 @@ PlayerSettings: androidRenderOutsideSafeArea: 1 androidUseSwappy: 0 androidBlitType: 0 + androidResizeableActivity: 1 + androidDefaultWindowWidth: 1920 + androidDefaultWindowHeight: 1080 + androidMinimumWindowWidth: 400 + androidMinimumWindowHeight: 300 + androidFullscreenMode: 1 + androidAutoRotationBehavior: 1 + androidPredictiveBackSupport: 0 + androidApplicationEntry: 1 defaultIsNativeResolution: 1 macRetinaSupport: 1 runInBackground: 0 - captureSingleScreen: 0 muteOtherAudioSources: 0 Prepare IOS For Recording: 0 Force IOS Speakers When Recording: 0 @@ -78,6 +90,7 @@ PlayerSettings: hideHomeButton: 0 submitAnalytics: 1 usePlayerLog: 1 + dedicatedServerOptimizations: 1 bakeCollisionMeshes: 0 forceSingleInstance: 0 useFlipModelSwapchain: 1 @@ -85,7 +98,7 @@ PlayerSettings: useMacAppStoreValidation: 0 macAppStoreCategory: public.app-category.games gpuSkinning: 0 - graphicsJobs: 0 + meshDeformation: 0 xboxPIXTextureCapture: 0 xboxEnableAvatar: 0 xboxEnableKinect: 0 @@ -93,7 +106,6 @@ PlayerSettings: xboxEnableFitness: 0 visibleInBackground: 0 allowFullscreenSwitch: 1 - graphicsJobMode: 0 fullscreenMode: 1 xboxSpeechDB: 0 xboxEnableHeadOrientation: 0 @@ -106,6 +118,7 @@ PlayerSettings: xboxOneMonoLoggingLevel: 0 xboxOneLoggingLevel: 1 xboxOneDisableEsram: 0 + xboxOneEnableTypeOptimization: 0 xboxOnePresentImmediateThreshold: 0 switchQueueCommandMemory: 1048576 switchQueueControlMemory: 16384 @@ -113,13 +126,20 @@ PlayerSettings: switchNVNShaderPoolsGranularity: 33554432 switchNVNDefaultPoolsGranularity: 16777216 switchNVNOtherPoolsGranularity: 16777216 + switchGpuScratchPoolGranularity: 2097152 + switchAllowGpuScratchShrinking: 0 + switchNVNMaxPublicTextureIDCount: 0 + switchNVNMaxPublicSamplerIDCount: 0 + switchMaxWorkerMultiple: 8 + switchNVNGraphicsFirmwareMemory: 32 + vulkanNumSwapchainBuffers: 3 vulkanEnableSetSRGBWrite: 0 - m_SupportedAspectRatios: - 4:3: 1 - 5:4: 1 - 16:10: 1 - 16:9: 1 - Others: 1 + vulkanEnablePreTransform: 0 + vulkanEnableLateAcquireNextImage: 0 + vulkanEnableCommandBufferRecycling: 1 + loadStoreDebugModeEnabled: 0 + visionOSBundleVersion: 1.0 + tvOSBundleVersion: 1.0 bundleVersion: 1.0 preloadedAssets: [] metroInputSource: 0 @@ -128,39 +148,20 @@ PlayerSettings: xboxOneDisableKinectGpuReservation: 0 xboxOneEnable7thCore: 0 vrSettings: - cardboard: - depthFormat: 0 - enableTransitionView: 0 - daydream: - depthFormat: 0 - useSustainedPerformanceMode: 0 - enableVideoLayer: 0 - useProtectedVideoMemory: 0 - minimumSupportedHeadTracking: 0 - maximumSupportedHeadTracking: 1 - hololens: - depthFormat: 1 - depthBufferSharingEnabled: 0 - lumin: - depthFormat: 0 - frameTiming: 2 - enableGLCache: 0 - glCacheMaxBlobSize: 524288 - glCacheMaxFileSize: 8388608 - oculus: - sharedDepthBuffer: 0 - dashSupport: 0 - lowOverheadMode: 0 enable360StereoCapture: 0 isWsaHolographicRemotingEnabled: 0 - protectGraphicsMemory: 0 enableFrameTimingStats: 0 + enableOpenGLProfilerGPURecorders: 1 + allowHDRDisplaySupport: 0 useHDRDisplay: 0 + hdrBitDepth: 0 m_ColorGamuts: 00000000 targetPixelDensity: 30 resolutionScalingMode: 0 + resetResolutionOnWindowResize: 0 androidSupportedAspectRatio: 1 androidMaxAspectRatio: 2.1 + androidMinAspectRatio: 1 applicationIdentifier: Android: com.jacksondunstan.unityplayground Standalone: unity.DefaultCompany.UnityPlayground @@ -168,9 +169,13 @@ PlayerSettings: iPhone: com.jacksondunstan.unityplayground tvOS: com.jacksondunstan.unityplayground buildNumber: + Standalone: 0 + VisionOS: 0 iPhone: 0 + tvOS: 0 + overrideDefaultApplicationIdentifier: 1 AndroidBundleVersionCode: 1 - AndroidMinSdkVersion: 16 + AndroidMinSdkVersion: 23 AndroidTargetSdkVersion: 0 AndroidPreferredInstallLocation: 1 aotOptions: @@ -180,37 +185,26 @@ PlayerSettings: ForceInternetPermission: 0 ForceSDCardPermission: 0 CreateWallpaper: 0 - APKExpansionFiles: 0 + androidSplitApplicationBinary: 0 keepLoadedShadersAlive: 0 StripUnusedMeshComponents: 0 + strictShaderVariantMatching: 0 VertexChannelCompressionMask: 214 iPhoneSdkVersion: 988 - iOSTargetOSVersionString: 9.0 + iOSSimulatorArchitecture: 0 + iOSTargetOSVersionString: 13.0 tvOSSdkVersion: 0 + tvOSSimulatorArchitecture: 0 tvOSRequireExtendedGameController: 0 - tvOSTargetOSVersionString: 9.0 + tvOSTargetOSVersionString: 13.0 + VisionOSSdkVersion: 0 + VisionOSTargetOSVersionString: 1.0 uIPrerenderedIcon: 0 uIRequiresPersistentWiFi: 0 uIRequiresFullScreen: 1 uIStatusBarHidden: 1 uIExitOnSuspend: 0 uIStatusBarStyle: 0 - iPhoneSplashScreen: {fileID: 0} - iPhoneHighResSplashScreen: {fileID: 0} - iPhoneTallHighResSplashScreen: {fileID: 0} - iPhone47inSplashScreen: {fileID: 0} - iPhone55inPortraitSplashScreen: {fileID: 0} - iPhone55inLandscapeSplashScreen: {fileID: 0} - iPhone58inPortraitSplashScreen: {fileID: 0} - iPhone58inLandscapeSplashScreen: {fileID: 0} - iPadPortraitSplashScreen: {fileID: 0} - iPadHighResPortraitSplashScreen: {fileID: 0} - iPadLandscapeSplashScreen: {fileID: 0} - iPadHighResLandscapeSplashScreen: {fileID: 0} - iPhone65inPortraitSplashScreen: {fileID: 0} - iPhone65inLandscapeSplashScreen: {fileID: 0} - iPhone61inPortraitSplashScreen: {fileID: 0} - iPhone61inLandscapeSplashScreen: {fileID: 0} appleTVSplashScreen: {fileID: 0} appleTVSplashScreen2x: {fileID: 0} tvOSSmallIconLayers: [] @@ -229,7 +223,6 @@ PlayerSettings: rgba: 0 iOSLaunchScreenFillPct: 1 iOSLaunchScreenSize: 100 - iOSLaunchScreenCustomXibPath: iOSLaunchScreeniPadType: 0 iOSLaunchScreeniPadImage: {fileID: 0} iOSLaunchScreeniPadBackgroundColor: @@ -237,33 +230,48 @@ PlayerSettings: rgba: 0 iOSLaunchScreeniPadFillPct: 100 iOSLaunchScreeniPadSize: 100 - iOSLaunchScreeniPadCustomXibPath: - iOSUseLaunchScreenStoryboard: 0 iOSLaunchScreenCustomStoryboardPath: + iOSLaunchScreeniPadCustomStoryboardPath: iOSDeviceRequirements: [] iOSURLSchemes: [] + macOSURLSchemes: [] iOSBackgroundModes: 0 iOSMetalForceHardShadows: 0 metalEditorSupport: 0 metalAPIValidation: 1 + metalCompileShaderBinary: 0 iOSRenderExtraFrameOnPause: 1 + iosCopyPluginsCodeInsteadOfSymlink: 0 appleDeveloperTeamID: iOSManualSigningProvisioningProfileID: tvOSManualSigningProvisioningProfileID: + VisionOSManualSigningProvisioningProfileID: iOSManualSigningProvisioningProfileType: 0 tvOSManualSigningProvisioningProfileType: 0 + VisionOSManualSigningProvisioningProfileType: 0 appleEnableAutomaticSigning: 0 iOSRequireARKit: 0 iOSAutomaticallyDetectAndAddCapabilities: 1 appleEnableProMotion: 0 + shaderPrecisionModel: 0 clonedFromGUID: 00000000000000000000000000000000 templatePackageId: templateDefaultScene: + useCustomMainManifest: 0 + useCustomLauncherManifest: 0 + useCustomMainGradleTemplate: 0 + useCustomLauncherGradleManifest: 0 + useCustomBaseGradleTemplate: 0 + useCustomGradlePropertiesTemplate: 0 + useCustomGradleSettingsTemplate: 0 + useCustomProguardFile: 0 AndroidTargetArchitectures: 1 AndroidSplashScreenScale: 0 androidSplashScreen: {fileID: 0} AndroidKeystoreName: '{inproject}: ' AndroidKeyaliasName: + AndroidEnableArmv9SecurityFeatures: 0 + AndroidEnableArm64MTE: 0 AndroidBuildApkPerCpuArchitecture: 0 AndroidTVCompatibility: 1 AndroidIsGame: 1 @@ -276,9 +284,12 @@ PlayerSettings: height: 180 banner: {fileID: 0} androidGamepadSupportLevel: 0 + AndroidMinifyRelease: 0 + AndroidMinifyDebug: 0 AndroidValidateAppBundleSize: 1 AndroidAppBundleSizeToValidate: 150 - resolutionDialogBanner: {fileID: 0} + AndroidReportGooglePlayAppDependencies: 1 + androidSymbolsSizeThreshold: 800 m_BuildTargetIcons: - m_BuildTarget: m_Icons: @@ -287,12 +298,152 @@ PlayerSettings: m_Width: 128 m_Height: 128 m_Kind: 0 - m_BuildTargetPlatformIcons: [] + m_BuildTargetPlatformIcons: + - m_BuildTarget: Android + m_Icons: + - m_Textures: [] + m_Width: 432 + m_Height: 432 + m_Kind: 2 + m_SubKind: + - m_Textures: [] + m_Width: 324 + m_Height: 324 + m_Kind: 2 + m_SubKind: + - m_Textures: [] + m_Width: 216 + m_Height: 216 + m_Kind: 2 + m_SubKind: + - m_Textures: [] + m_Width: 162 + m_Height: 162 + m_Kind: 2 + m_SubKind: + - m_Textures: [] + m_Width: 108 + m_Height: 108 + m_Kind: 2 + m_SubKind: + - m_Textures: [] + m_Width: 81 + m_Height: 81 + m_Kind: 2 + m_SubKind: + - m_Textures: [] + m_Width: 192 + m_Height: 192 + m_Kind: 1 + m_SubKind: + - m_Textures: [] + m_Width: 144 + m_Height: 144 + m_Kind: 1 + m_SubKind: + - m_Textures: [] + m_Width: 96 + m_Height: 96 + m_Kind: 1 + m_SubKind: + - m_Textures: [] + m_Width: 72 + m_Height: 72 + m_Kind: 1 + m_SubKind: + - m_Textures: [] + m_Width: 48 + m_Height: 48 + m_Kind: 1 + m_SubKind: + - m_Textures: [] + m_Width: 36 + m_Height: 36 + m_Kind: 1 + m_SubKind: + - m_Textures: [] + m_Width: 192 + m_Height: 192 + m_Kind: 0 + m_SubKind: + - m_Textures: [] + m_Width: 144 + m_Height: 144 + m_Kind: 0 + m_SubKind: + - m_Textures: [] + m_Width: 96 + m_Height: 96 + m_Kind: 0 + m_SubKind: + - m_Textures: [] + m_Width: 72 + m_Height: 72 + m_Kind: 0 + m_SubKind: + - m_Textures: [] + m_Width: 48 + m_Height: 48 + m_Kind: 0 + m_SubKind: + - m_Textures: [] + m_Width: 36 + m_Height: 36 + m_Kind: 0 + m_SubKind: m_BuildTargetBatching: [] + m_BuildTargetShaderSettings: [] + m_BuildTargetGraphicsJobs: + - m_BuildTarget: WindowsStandaloneSupport + m_GraphicsJobs: 0 + - m_BuildTarget: MacStandaloneSupport + m_GraphicsJobs: 0 + - m_BuildTarget: LinuxStandaloneSupport + m_GraphicsJobs: 0 + - m_BuildTarget: AndroidPlayer + m_GraphicsJobs: 0 + - m_BuildTarget: iOSSupport + m_GraphicsJobs: 0 + - m_BuildTarget: PS4Player + m_GraphicsJobs: 0 + - m_BuildTarget: PS5Player + m_GraphicsJobs: 0 + - m_BuildTarget: XboxOnePlayer + m_GraphicsJobs: 0 + - m_BuildTarget: GameCoreXboxOneSupport + m_GraphicsJobs: 0 + - m_BuildTarget: GameCoreScarlettSupport + m_GraphicsJobs: 0 + - m_BuildTarget: Switch + m_GraphicsJobs: 0 + - m_BuildTarget: WebGLSupport + m_GraphicsJobs: 0 + - m_BuildTarget: MetroSupport + m_GraphicsJobs: 0 + - m_BuildTarget: AppleTVSupport + m_GraphicsJobs: 0 + - m_BuildTarget: VisionOSPlayer + m_GraphicsJobs: 0 + - m_BuildTarget: CloudRendering + m_GraphicsJobs: 0 + - m_BuildTarget: EmbeddedLinux + m_GraphicsJobs: 0 + - m_BuildTarget: QNX + m_GraphicsJobs: 0 + - m_BuildTarget: ReservedCFE + m_GraphicsJobs: 0 + m_BuildTargetGraphicsJobMode: + - m_BuildTarget: PS4Player + m_GraphicsJobMode: 0 + - m_BuildTarget: XboxOnePlayer + m_GraphicsJobMode: 0 m_BuildTargetGraphicsAPIs: - m_BuildTarget: AndroidPlayer - m_APIs: 08000000 - m_Automatic: 0 + m_APIs: 150000000b000000 + m_Automatic: 1 + - m_BuildTarget: iOSSupport + m_APIs: 10000000 + m_Automatic: 1 m_BuildTargetVRSettings: - m_BuildTarget: Android m_Enabled: 0 @@ -348,40 +499,54 @@ PlayerSettings: - m_BuildTarget: tvOS m_Enabled: 0 m_Devices: [] + m_DefaultShaderChunkSizeInMB: 16 + m_DefaultShaderChunkCount: 0 openGLRequireES31: 0 openGLRequireES31AEP: 0 openGLRequireES32: 0 - vuforiaEnabled: 0 m_TemplateCustomTags: {} mobileMTRendering: Android: 1 iPhone: 1 tvOS: 1 m_BuildTargetGroupLightmapEncodingQuality: - - m_BuildTarget: Standalone + - serializedVersion: 2 + m_BuildTarget: Standalone m_EncodingQuality: 1 - - m_BuildTarget: XboxOne + - serializedVersion: 2 + m_BuildTarget: XboxOne m_EncodingQuality: 1 - - m_BuildTarget: PS4 + - serializedVersion: 2 + m_BuildTarget: PS4 m_EncodingQuality: 1 m_BuildTargetGroupLightmapSettings: [] + m_BuildTargetGroupLoadStoreDebugModeSettings: [] + m_BuildTargetNormalMapEncoding: [] + m_BuildTargetDefaultTextureCompressionFormat: [] playModeTestRunnerEnabled: 0 runPlayModeTestAsEditModeTest: 0 actionOnDotNetUnhandledException: 1 + editorGfxJobOverride: 1 enableInternalProfiler: 0 logObjCUncaughtExceptions: 1 enableCrashReportAPI: 0 cameraUsageDescription: locationUsageDescription: microphoneUsageDescription: + bluetoothUsageDescription: + macOSTargetOSVersion: 11.0 + switchNMETAOverride: switchNetLibKey: switchSocketMemoryPoolSize: 6144 switchSocketAllocatorPoolSize: 128 switchSocketConcurrencyLimit: 14 switchScreenResolutionBehavior: 2 switchUseCPUProfiler: 0 + switchEnableFileSystemTrace: 0 + switchLTOSetting: 0 switchApplicationID: 0x0005000C10000001 switchNSODependencies: + switchCompilerFlags: switchTitleNames_0: switchTitleNames_1: switchTitleNames_2: @@ -397,6 +562,7 @@ PlayerSettings: switchTitleNames_12: switchTitleNames_13: switchTitleNames_14: + switchTitleNames_15: switchPublisherNames_0: switchPublisherNames_1: switchPublisherNames_2: @@ -412,6 +578,7 @@ PlayerSettings: switchPublisherNames_12: switchPublisherNames_13: switchPublisherNames_14: + switchPublisherNames_15: switchIcons_0: {fileID: 0} switchIcons_1: {fileID: 0} switchIcons_2: {fileID: 0} @@ -427,6 +594,7 @@ PlayerSettings: switchIcons_12: {fileID: 0} switchIcons_13: {fileID: 0} switchIcons_14: {fileID: 0} + switchIcons_15: {fileID: 0} switchSmallIcons_0: {fileID: 0} switchSmallIcons_1: {fileID: 0} switchSmallIcons_2: {fileID: 0} @@ -442,6 +610,7 @@ PlayerSettings: switchSmallIcons_12: {fileID: 0} switchSmallIcons_13: {fileID: 0} switchSmallIcons_14: {fileID: 0} + switchSmallIcons_15: {fileID: 0} switchManualHTML: switchAccessibleURLs: switchLegalInformation: @@ -451,7 +620,6 @@ PlayerSettings: switchReleaseVersion: 0 switchDisplayVersion: 1.0.0 switchStartupUserAccount: 0 - switchTouchScreenUsage: 0 switchSupportedLanguagesMask: 0 switchLogoType: 0 switchApplicationErrorCodeCategory: @@ -473,6 +641,7 @@ PlayerSettings: switchRatingsInt_9: 0 switchRatingsInt_10: 0 switchRatingsInt_11: 0 + switchRatingsInt_12: 0 switchLocalCommunicationIds_0: 0x0005000C10000001 switchLocalCommunicationIds_1: switchLocalCommunicationIds_2: @@ -492,6 +661,7 @@ PlayerSettings: switchNativeFsCacheSize: 32 switchIsHoldTypeHorizontal: 0 switchSupportedNpadCount: 8 + switchEnableTouchScreen: 1 switchSocketConfigEnabled: 0 switchTcpInitialSendBufferSize: 32 switchTcpInitialReceiveBufferSize: 64 @@ -502,7 +672,14 @@ PlayerSettings: switchSocketBufferEfficiency: 4 switchSocketInitializeEnabled: 1 switchNetworkInterfaceManagerInitializeEnabled: 1 - switchPlayerConnectionEnabled: 1 + switchDisableHTCSPlayerConnection: 0 + switchUseNewStyleFilepaths: 1 + switchUseLegacyFmodPriorities: 0 + switchUseMicroSleepForYield: 1 + switchEnableRamDiskSupport: 0 + switchMicroSleepForYieldTime: 25 + switchRamDiskSpaceSize: 12 + switchUpgradedPlayerSettingsToNMETA: 0 ps4NPAgeRating: 12 ps4NPTitleSecret: ps4NPTrophyPackPath: @@ -529,6 +706,7 @@ PlayerSettings: ps4ShareFilePath: ps4ShareOverlayImagePath: ps4PrivacyGuardImagePath: + ps4ExtraSceSysFile: ps4NPtitleDatPath: ps4RemotePlayKeyAssignment: -1 ps4RemotePlayKeyMappingDir: @@ -554,6 +732,7 @@ PlayerSettings: ps4UseResolutionFallback: 0 ps4ReprojectionSupport: 0 ps4UseAudio3dBackend: 0 + ps4UseLowGarlicFragmentationMode: 1 ps4SocialScreenEnabled: 0 ps4ScriptOptimizationLevel: 3 ps4Audio3dVirtualSpeakerCount: 14 @@ -570,8 +749,12 @@ PlayerSettings: ps4disableAutoHideSplash: 0 ps4videoRecordingFeaturesUsed: 0 ps4contentSearchFeaturesUsed: 0 + ps4CompatibilityPS5: 0 + ps4AllowPS5Detection: 0 + ps4GPU800MHz: 1 ps4attribEyeToEyeDistanceSettingVR: 0 ps4IncludedModules: [] + ps4attribVROutputEnabled: 0 monoEnv: splashScreenBackgroundSourceLandscape: {fileID: 0} splashScreenBackgroundSourcePortrait: {fileID: 0} @@ -580,6 +763,7 @@ PlayerSettings: webGLMemorySize: 256 webGLExceptionSupport: 0 webGLNameFilesAsHashes: 0 + webGLShowDiagnostics: 0 webGLDataCaching: 0 webGLDebugSymbols: 0 webGLEmscriptenArgs: @@ -588,28 +772,63 @@ PlayerSettings: webGLAnalyzeBuildSize: 0 webGLUseEmbeddedResources: 0 webGLCompressionFormat: 1 + webGLWasmArithmeticExceptions: 0 webGLLinkerTarget: 1 webGLThreadsSupport: 0 - webGLWasmStreaming: 0 + webGLDecompressionFallback: 0 + webGLInitialMemorySize: 32 + webGLMaximumMemorySize: 2048 + webGLMemoryGrowthMode: 2 + webGLMemoryLinearGrowthStep: 16 + webGLMemoryGeometricGrowthStep: 0.2 + webGLMemoryGeometricGrowthCap: 96 + webGLEnableWebGPU: 0 + webGLPowerPreference: 2 + webGLWebAssemblyTable: 0 + webGLWebAssemblyBigInt: 0 + webGLCloseOnQuit: 0 + webWasm2023: 0 scriptingDefineSymbols: - 1: + Standalone: + additionalCompilerArguments: {} platformArchitecture: - iPhone: 0 + iPhone: 1 scriptingBackend: Android: 1 Standalone: 1 WebGL: 1 iPhone: 1 il2cppCompilerConfiguration: {} - managedStrippingLevel: {} + il2cppCodeGeneration: {} + il2cppStacktraceInformation: {} + managedStrippingLevel: + Android: 1 + EmbeddedLinux: 1 + GameCoreScarlett: 1 + GameCoreXboxOne: 1 + Nintendo Switch: 1 + PS4: 1 + PS5: 1 + QNX: 1 + ReservedCFE: 1 + Standalone: 1 + VisionOS: 1 + WebGL: 1 + Windows Store Apps: 1 + XboxOne: 1 + iPhone: 1 + tvOS: 1 incrementalIl2cppBuild: iPhone: 0 - allowUnsafeCode: 0 + suppressCommonWarnings: 1 + allowUnsafeCode: 1 + useDeterministicCompilation: 1 additionalIl2CppArgs: scriptingRuntimeVersion: 1 gcIncremental: 0 gcWBarrierValidation: 0 apiCompatibilityLevelPerPlatform: {} + editorAssembliesCompatibilityLevel: 1 m_RenderingPath: 1 m_MobileRenderingPath: 1 metroPackageName: UnityPlayground @@ -633,11 +852,13 @@ PlayerSettings: metroTileBackgroundColor: {r: 0, g: 0, b: 0, a: 1} metroSplashScreenBackgroundColor: {r: 0, g: 0, b: 0, a: 1} metroSplashScreenUseBackgroundColor: 0 + syncCapabilities: 0 platformCapabilities: {} metroTargetDeviceFamilies: {} metroFTAName: metroFTAFileTypes: [] metroProtocolName: + vcxProjDefaultLanguage: XboxOneProductId: XboxOneUpdateKey: XboxOneSandboxId: @@ -656,18 +877,16 @@ PlayerSettings: XboxOneCapability: [] XboxOneGameRating: {} XboxOneIsContentPackage: 0 + XboxOneEnhancedXboxCompatibilityMode: 0 XboxOneEnableGPUVariability: 0 XboxOneSockets: {} XboxOneSplashScreen: {fileID: 0} XboxOneAllowedProductIds: [] XboxOnePersistentLocalStorageSize: 0 XboxOneXTitleMemory: 8 - xboxOneScriptCompiler: 1 XboxOneOverrideIdentityName: - vrEditorSettings: - daydream: - daydreamIconForeground: {fileID: 0} - daydreamIconBackground: {fileID: 0} + XboxOneOverrideIdentityPublisher: + vrEditorSettings: {} cloudServicesEnabled: Analytics: 0 Build: 0 @@ -689,19 +908,26 @@ PlayerSettings: luminVersion: m_VersionCode: 1 m_VersionName: - facebookSdkVersion: 7.9.1 - facebookAppId: - facebookCookies: 1 - facebookLogging: 1 - facebookStatus: 1 - facebookXfbml: 0 - facebookFrictionlessRequests: 1 + hmiPlayerDataPath: + hmiForceSRGBBlit: 0 + embeddedLinuxEnableGamepadInput: 0 + hmiCpuConfiguration: + hmiLogStartupTiming: 0 + qnxGraphicConfPath: apiCompatibilityLevel: 6 + captureStartupLogs: {} + activeInputHandler: 0 + windowsGamepadBackendHint: 0 cloudProjectId: framebufferDepthMemorylessMode: 0 + qualitySettingsNames: [] projectName: organizationId: cloudEnabled: 0 - enableNativePlatformBackendsForNewInputSystem: 0 - disableOldInputManagerSupport: 0 legacyClampBlendShapeWeights: 1 + hmiLoadingImage: {fileID: 0} + platformRequiresReadableAssets: 0 + virtualTexturingSupportEnabled: 0 + insecureHttpOption: 0 + androidVulkanDenyFilterList: [] + androidVulkanAllowFilterList: [] diff --git a/Tests/unity/ProjectSettings/ProjectVersion.txt b/Tests/unity/ProjectSettings/ProjectVersion.txt new file mode 100644 index 0000000..a1aff48 --- /dev/null +++ b/Tests/unity/ProjectSettings/ProjectVersion.txt @@ -0,0 +1,2 @@ +m_EditorVersion: 6000.0.40f1 +m_EditorVersionWithRevision: 6000.0.40f1 (157d81624ddf) diff --git a/Unity/ProjectSettings/QualitySettings.asset b/Tests/unity/ProjectSettings/QualitySettings.asset similarity index 100% rename from Unity/ProjectSettings/QualitySettings.asset rename to Tests/unity/ProjectSettings/QualitySettings.asset diff --git a/Tests/unity/ProjectSettings/SceneTemplateSettings.json b/Tests/unity/ProjectSettings/SceneTemplateSettings.json new file mode 100644 index 0000000..ede5887 --- /dev/null +++ b/Tests/unity/ProjectSettings/SceneTemplateSettings.json @@ -0,0 +1,121 @@ +{ + "templatePinStates": [], + "dependencyTypeInfos": [ + { + "userAdded": false, + "type": "UnityEngine.AnimationClip", + "defaultInstantiationMode": 0 + }, + { + "userAdded": false, + "type": "UnityEditor.Animations.AnimatorController", + "defaultInstantiationMode": 0 + }, + { + "userAdded": false, + "type": "UnityEngine.AnimatorOverrideController", + "defaultInstantiationMode": 0 + }, + { + "userAdded": false, + "type": "UnityEditor.Audio.AudioMixerController", + "defaultInstantiationMode": 0 + }, + { + "userAdded": false, + "type": "UnityEngine.ComputeShader", + "defaultInstantiationMode": 1 + }, + { + "userAdded": false, + "type": "UnityEngine.Cubemap", + "defaultInstantiationMode": 0 + }, + { + "userAdded": false, + "type": "UnityEngine.GameObject", + "defaultInstantiationMode": 0 + }, + { + "userAdded": false, + "type": "UnityEditor.LightingDataAsset", + "defaultInstantiationMode": 0 + }, + { + "userAdded": false, + "type": "UnityEngine.LightingSettings", + "defaultInstantiationMode": 0 + }, + { + "userAdded": false, + "type": "UnityEngine.Material", + "defaultInstantiationMode": 0 + }, + { + "userAdded": false, + "type": "UnityEditor.MonoScript", + "defaultInstantiationMode": 1 + }, + { + "userAdded": false, + "type": "UnityEngine.PhysicsMaterial", + "defaultInstantiationMode": 0 + }, + { + "userAdded": false, + "type": "UnityEngine.PhysicsMaterial2D", + "defaultInstantiationMode": 0 + }, + { + "userAdded": false, + "type": "UnityEngine.Rendering.PostProcessing.PostProcessProfile", + "defaultInstantiationMode": 0 + }, + { + "userAdded": false, + "type": "UnityEngine.Rendering.PostProcessing.PostProcessResources", + "defaultInstantiationMode": 0 + }, + { + "userAdded": false, + "type": "UnityEngine.Rendering.VolumeProfile", + "defaultInstantiationMode": 0 + }, + { + "userAdded": false, + "type": "UnityEditor.SceneAsset", + "defaultInstantiationMode": 1 + }, + { + "userAdded": false, + "type": "UnityEngine.Shader", + "defaultInstantiationMode": 1 + }, + { + "userAdded": false, + "type": "UnityEngine.ShaderVariantCollection", + "defaultInstantiationMode": 1 + }, + { + "userAdded": false, + "type": "UnityEngine.Texture", + "defaultInstantiationMode": 0 + }, + { + "userAdded": false, + "type": "UnityEngine.Texture2D", + "defaultInstantiationMode": 0 + }, + { + "userAdded": false, + "type": "UnityEngine.Timeline.TimelineAsset", + "defaultInstantiationMode": 0 + } + ], + "defaultDependencyTypeInfo": { + "userAdded": false, + "type": "", + "defaultInstantiationMode": 1 + }, + "newSceneOverride": 0 +} \ No newline at end of file diff --git a/Unity/ProjectSettings/TagManager.asset b/Tests/unity/ProjectSettings/TagManager.asset similarity index 100% rename from Unity/ProjectSettings/TagManager.asset rename to Tests/unity/ProjectSettings/TagManager.asset diff --git a/Unity/ProjectSettings/TimeManager.asset b/Tests/unity/ProjectSettings/TimeManager.asset similarity index 100% rename from Unity/ProjectSettings/TimeManager.asset rename to Tests/unity/ProjectSettings/TimeManager.asset diff --git a/Unity/ProjectSettings/UnityConnectSettings.asset b/Tests/unity/ProjectSettings/UnityConnectSettings.asset similarity index 100% rename from Unity/ProjectSettings/UnityConnectSettings.asset rename to Tests/unity/ProjectSettings/UnityConnectSettings.asset diff --git a/Unity/ProjectSettings/VFXManager.asset b/Tests/unity/ProjectSettings/VFXManager.asset similarity index 100% rename from Unity/ProjectSettings/VFXManager.asset rename to Tests/unity/ProjectSettings/VFXManager.asset diff --git a/Tests/unity/ProjectSettings/VersionControlSettings.asset b/Tests/unity/ProjectSettings/VersionControlSettings.asset new file mode 100644 index 0000000..979fd8e --- /dev/null +++ b/Tests/unity/ProjectSettings/VersionControlSettings.asset @@ -0,0 +1,7 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!890905787 &1 +VersionControlSettings: + m_ObjectHideFlags: 0 + m_Mode: Visible Meta Files + m_TrackPackagesOutsideProject: 0 diff --git a/Unity/ProjectSettings/XRSettings.asset b/Tests/unity/ProjectSettings/XRSettings.asset similarity index 100% rename from Unity/ProjectSettings/XRSettings.asset rename to Tests/unity/ProjectSettings/XRSettings.asset diff --git a/Unity/Assets/CppSource/CMakeLists.txt b/Unity/Assets/CppSource/CMakeLists.txt deleted file mode 100644 index 2baa025..0000000 --- a/Unity/Assets/CppSource/CMakeLists.txt +++ /dev/null @@ -1,87 +0,0 @@ -cmake_minimum_required(VERSION 3.6.0 FATAL_ERROR) -project(NativeScript CXX) - -# Set platform-dependent compilation defines matching C# -if (EDITOR) - add_definitions(-DTARGET_OS_EDITOR) - if (WIN32) - add_definitions(-DTARGET_OS_EDITOR_WIN) - elseif (${CMAKE_SYSTEM_NAME} MATCHES "Darwin") - add_definitions(-DTARGET_OS_EDITOR_OSX) - elseif (${CMAKE_SYSTEM_NAME} MATCHES "Linux") - add_definitions(-DTARGET_OS_EDITOR_LINUX) - endif() -else() - add_definitions(-DTARGET_OS_STANDALONE) - if (WIN32) - add_definitions(-DTARGET_OS_WIN) - elseif (${CMAKE_SYSTEM_NAME} MATCHES "Darwin") - add_definitions(-DTARGET_OS_OSX) - elseif (${CMAKE_SYSTEM_NAME} MATCHES "Linux") - add_definitions(-DTARGET_OS_LINUX) - endif() -endif() -if (IOS) - add_definitions(-DTARGET_OS_IPHONE) -endif() -if (ANDROID_NDK) - add_definitions(-DTARGET_OS_ANDROID) -endif() - -# Use NDK on Android -if (ANDROID_NDK) - set(ANDROID_ABI armeabi-v7a) - set(CMAKE_TOOLCHAIN_FILE ${ANDROID_NDK}/build/cmake/android.toolchain.cmake) -endif() - -# Set output path -if (ANDROID_NDK) - set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/../Plugins/Android) - set(CMAKE_LIBRARY_OUTPUT_DIRECTORY_DEBUG ${CMAKE_SOURCE_DIR}/../Plugins/Android) - set(CMAKE_LIBRARY_OUTPUT_DIRECTORY_RELEASE ${CMAKE_SOURCE_DIR}/../Plugins/Android) -elseif (IOS) - set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/../Plugins/.iOS) - set(CMAKE_LIBRARY_OUTPUT_DIRECTORY_DEBUG ${CMAKE_SOURCE_DIR}/../Plugins/.iOS) - set(CMAKE_LIBRARY_OUTPUT_DIRECTORY_RELEASE ${CMAKE_SOURCE_DIR}/../Plugins/.iOS) -elseif (WIN32 OR (${CMAKE_SYSTEM_NAME} MATCHES "Darwin") OR (${CMAKE_SYSTEM_NAME} MATCHES "Linux")) - if (EDITOR) - set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/../Plugins/Editor) - set(CMAKE_LIBRARY_OUTPUT_DIRECTORY_DEBUG ${CMAKE_SOURCE_DIR}/../Plugins/Editor) - set(CMAKE_LIBRARY_OUTPUT_DIRECTORY_RELEASE ${CMAKE_SOURCE_DIR}/../Plugins/Editor) - else() - set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/../Plugins) - set(CMAKE_LIBRARY_OUTPUT_DIRECTORY_DEBUG ${CMAKE_SOURCE_DIR}/../Plugins) - set(CMAKE_LIBRARY_OUTPUT_DIRECTORY_RELEASE ${CMAKE_SOURCE_DIR}/../Plugins) - endif() -endif() - -# Set the directories for NativeScript and game C++ as include directories -include_directories( - ${CMAKE_SOURCE_DIR}/NativeScript - ${CMAKE_SOURCE_DIR}/Game) - -# Set all .cpp files for NativeScript and the game as sources -file(GLOB GAMESOURCEFILES ${CMAKE_SOURCE_DIR}/Game/*.cpp) -file(GLOB GAMEHEADERFILES ${CMAKE_SOURCE_DIR}/Game/*.h) -file(GLOB NATIVESCRIPTSOURCEFILES ${CMAKE_SOURCE_DIR}/NativeScript/*.cpp) -file(GLOB NATIVESCRIPTHEADERFILES ${CMAKE_SOURCE_DIR}/NativeScript/*.h) -set( - SOURCES - ${GAMESOURCEFILES} - ${GAMEHEADERFILES} - ${NATIVESCRIPTSOURCEFILES} - ${NATIVESCRIPTHEADERFILES}) - -# Build a library. If on an Apple platform, build it in a bundle. -add_library(${PROJECT_NAME} MODULE ${SOURCES}) -set_target_properties(${PROJECT_NAME} PROPERTIES BUNDLE TRUE) -if (IOS) - set_xcode_property(${PROJECT_NAME} ENABLE_BITCODE "NO") -endif() - -if(WIN32 AND MINGW) - set_property(TARGET ${PROJECT_NAME} PROPERTY PREFIX "") -endif() - -# Enable C++11 -set_property(TARGET ${PROJECT_NAME} PROPERTY CXX_STANDARD 11) \ No newline at end of file diff --git a/Unity/Assets/CppSource/Game/Game.cpp b/Unity/Assets/CppSource/Game/Game.cpp deleted file mode 100644 index a8baeff..0000000 --- a/Unity/Assets/CppSource/Game/Game.cpp +++ /dev/null @@ -1,85 +0,0 @@ -/// -/// Game-specific code for the native plugin -/// -/// -/// Jackson Dunstan, 2017, http://JacksonDunstan.com -/// -/// -/// MIT -/// - -#include "Bindings.h" -#include "Game.h" - -using namespace System; -using namespace UnityEngine; - -namespace -{ - struct GameState - { - float BallDir; - }; - - GameState* gameState; -} - -namespace MyGame -{ - void BallScript::Update() - { - Transform transform = GetTransform(); - Vector3 pos = transform.GetPosition(); - const float speed = 1.2f; - const float min = -1.5f; - const float max = 1.5f; - float distance = Time::GetDeltaTime() * speed * gameState->BallDir; - Vector3 offset(distance, 0, 0); - Vector3 newPos = pos + offset; - if (newPos.x > max) - { - gameState->BallDir *= -1.0f; - newPos.x = max - (newPos.x - max); - if (newPos.x < min) - { - newPos.x = min; - } - } - else if (newPos.x < min) - { - gameState->BallDir *= -1.0f; - newPos.x = min + (min - newPos.x); - if (newPos.x > max) - { - newPos.x = max; - } - } - transform.SetPosition(newPos); - } -} - -// Called when the plugin is initialized -// This is mostly full of test code. Feel free to remove it all. -void PluginMain( - void* memory, - int32_t memorySize, - bool isFirstBoot) -{ - gameState = (GameState*)memory; - if (isFirstBoot) - { - String message("Game booted up"); - Debug::Log(message); - - // The ball initially goes right - gameState->BallDir = 1.0f; - - // Create the ball game object out of a sphere primitive - GameObject go = GameObject::CreatePrimitive(PrimitiveType::Sphere); - String name("GameObject with a BallScript"); - go.SetName(name); - - // Attach the ball script to make it bounce back and forth - go.AddComponent(); - } -} diff --git a/Unity/Assets/CppSource/Game/Game.cpp.meta b/Unity/Assets/CppSource/Game/Game.cpp.meta deleted file mode 100644 index 6bcf89c..0000000 --- a/Unity/Assets/CppSource/Game/Game.cpp.meta +++ /dev/null @@ -1,26 +0,0 @@ -fileFormatVersion: 2 -guid: cd5ee8d1b4f5748ed98f1f7cd17c386d -timeCreated: 1525538114 -licenseType: Free -PluginImporter: - externalObjects: {} - serializedVersion: 2 - iconMap: {} - executionOrder: {} - isPreloaded: 0 - isOverridable: 0 - platformData: - - first: - Any: - second: - enabled: 1 - settings: {} - - first: - Editor: Editor - second: - enabled: 0 - settings: - DefaultValueInitialized: true - userData: - assetBundleName: - assetBundleVariant: diff --git a/Unity/Assets/CppSource/Game/Game.h b/Unity/Assets/CppSource/Game/Game.h deleted file mode 100644 index 79d31ad..0000000 --- a/Unity/Assets/CppSource/Game/Game.h +++ /dev/null @@ -1,23 +0,0 @@ -/// -/// Declaration of the game types the bindings layer needs to know about -/// -/// -/// Jackson Dunstan, 2018, http://JacksonDunstan.com -/// -/// -/// MIT -/// - -#pragma once - -#include "Bindings.h" - -namespace MyGame -{ - struct BallScript : MyGame::BaseBallScript - { - MY_GAME_BALL_SCRIPT_DEFAULT_CONTENTS - MY_GAME_BALL_SCRIPT_DEFAULT_CONSTRUCTOR - void Update() override; - }; -} diff --git a/Unity/Assets/CppSource/Game/Game.h.meta b/Unity/Assets/CppSource/Game/Game.h.meta deleted file mode 100644 index c81ed01..0000000 --- a/Unity/Assets/CppSource/Game/Game.h.meta +++ /dev/null @@ -1,26 +0,0 @@ -fileFormatVersion: 2 -guid: 568849c22711c4c4aaaf09df05a1d812 -timeCreated: 1525538114 -licenseType: Free -PluginImporter: - externalObjects: {} - serializedVersion: 2 - iconMap: {} - executionOrder: {} - isPreloaded: 0 - isOverridable: 0 - platformData: - - first: - Any: - second: - enabled: 1 - settings: {} - - first: - Editor: Editor - second: - enabled: 0 - settings: - DefaultValueInitialized: true - userData: - assetBundleName: - assetBundleVariant: diff --git a/Unity/Assets/CppSource/NativeScript/Bindings.cpp b/Unity/Assets/CppSource/NativeScript/Bindings.cpp deleted file mode 100644 index 8cb2e2e..0000000 --- a/Unity/Assets/CppSource/NativeScript/Bindings.cpp +++ /dev/null @@ -1,6349 +0,0 @@ -/// -/// Internals of the bindings between native and .NET code. -/// Game code shouldn't go here. -/// -/// -/// Jackson Dunstan, 2017, http://JacksonDunstan.com -/// -/// -/// MIT -/// - -// Game type definitions -#include "Game.h" - -// Type definitions -#include "Bindings.h" - -// For assert() -#include - -// For memset(), etc. -#include - -// Macro to put before functions that need to be exposed to C# -#ifdef _WIN32 - #define DLLEXPORT extern "C" __declspec(dllexport) -#else - #define DLLEXPORT extern "C" -#endif - -//////////////////////////////////////////////////////////////// -// C# functions for C++ to call -//////////////////////////////////////////////////////////////// - -namespace Plugin -{ - void (*ReleaseObject)(int32_t handle); - int32_t (*StringNew)(const char* chars); - void (*SetException)(int32_t handle); - int32_t (*ArrayGetLength)(int32_t handle); - int32_t (*EnumerableGetEnumerator)(int32_t handle); - - /*BEGIN FUNCTION POINTERS*/ - void (*ReleaseSystemDecimal)(int32_t handle); - int32_t (*SystemDecimalConstructorSystemDouble)(double value); - int32_t (*SystemDecimalConstructorSystemUInt64)(uint64_t value); - int32_t (*BoxDecimal)(int32_t valHandle); - int32_t (*UnboxDecimal)(int32_t valHandle); - UnityEngine::Vector3 (*UnityEngineVector3ConstructorSystemSingle_SystemSingle_SystemSingle)(float x, float y, float z); - UnityEngine::Vector3 (*UnityEngineVector3Methodop_AdditionUnityEngineVector3_UnityEngineVector3)(UnityEngine::Vector3& a, UnityEngine::Vector3& b); - int32_t (*BoxVector3)(UnityEngine::Vector3& val); - UnityEngine::Vector3 (*UnboxVector3)(int32_t valHandle); - int32_t (*UnityEngineObjectPropertyGetName)(int32_t thisHandle); - void (*UnityEngineObjectPropertySetName)(int32_t thisHandle, int32_t valueHandle); - int32_t (*UnityEngineComponentPropertyGetTransform)(int32_t thisHandle); - UnityEngine::Vector3 (*UnityEngineTransformPropertyGetPosition)(int32_t thisHandle); - void (*UnityEngineTransformPropertySetPosition)(int32_t thisHandle, UnityEngine::Vector3& value); - int32_t (*SystemCollectionsIEnumeratorPropertyGetCurrent)(int32_t thisHandle); - int32_t (*SystemCollectionsIEnumeratorMethodMoveNext)(int32_t thisHandle); - int32_t (*UnityEngineGameObjectMethodAddComponentMyGameBaseBallScript)(int32_t thisHandle); - int32_t (*UnityEngineGameObjectMethodCreatePrimitiveUnityEnginePrimitiveType)(UnityEngine::PrimitiveType type); - void (*UnityEngineDebugMethodLogSystemObject)(int32_t messageHandle); - int32_t (*UnityEngineMonoBehaviourPropertyGetTransform)(int32_t thisHandle); - int32_t (*SystemExceptionConstructorSystemString)(int32_t messageHandle); - int32_t (*BoxPrimitiveType)(UnityEngine::PrimitiveType val); - UnityEngine::PrimitiveType (*UnboxPrimitiveType)(int32_t valHandle); - float (*UnityEngineTimePropertyGetDeltaTime)(); - void (*ReleaseBaseBallScript)(int32_t handle); - void (*BaseBallScriptConstructor)(int32_t cppHandle, int32_t* handle); - int32_t (*BoxBoolean)(uint32_t val); - int32_t (*UnboxBoolean)(int32_t valHandle); - int32_t (*BoxSByte)(int8_t val); - int8_t (*UnboxSByte)(int32_t valHandle); - int32_t (*BoxByte)(uint8_t val); - uint8_t (*UnboxByte)(int32_t valHandle); - int32_t (*BoxInt16)(int16_t val); - int16_t (*UnboxInt16)(int32_t valHandle); - int32_t (*BoxUInt16)(uint16_t val); - uint16_t (*UnboxUInt16)(int32_t valHandle); - int32_t (*BoxInt32)(int32_t val); - int32_t (*UnboxInt32)(int32_t valHandle); - int32_t (*BoxUInt32)(uint32_t val); - uint32_t (*UnboxUInt32)(int32_t valHandle); - int32_t (*BoxInt64)(int64_t val); - int64_t (*UnboxInt64)(int32_t valHandle); - int32_t (*BoxUInt64)(uint64_t val); - uint64_t (*UnboxUInt64)(int32_t valHandle); - int32_t (*BoxChar)(uint16_t val); - int16_t (*UnboxChar)(int32_t valHandle); - int32_t (*BoxSingle)(float val); - float (*UnboxSingle)(int32_t valHandle); - int32_t (*BoxDouble)(double val); - double (*UnboxDouble)(int32_t valHandle); - /*END FUNCTION POINTERS*/ -} - -//////////////////////////////////////////////////////////////// -// Global variables -//////////////////////////////////////////////////////////////// - -namespace Plugin -{ - System::String NullString(nullptr); -} - -//////////////////////////////////////////////////////////////// -// Plugin Types -//////////////////////////////////////////////////////////////// - -namespace Plugin -{ - ManagedType::ManagedType() - : Handle(0) - { - } - - ManagedType::ManagedType(decltype(nullptr)) - : Handle(0) - { - } - - ManagedType::ManagedType(Plugin::InternalUse iu, int32_t handle) - : Handle(handle) - { - } -} - -//////////////////////////////////////////////////////////////// -// C# Primitive Types -//////////////////////////////////////////////////////////////// - -namespace System -{ - Boolean::Boolean() - : Value(0) - { - } - - Boolean::Boolean(bool value) - : Value((int32_t)value) - { - } - - Boolean::Boolean(int32_t value) - : Value(value) - { - } - - Boolean::Boolean(uint32_t value) - : Value(value) - { - } - - Boolean::operator bool() const - { - return (bool)Value; - } - - Boolean::operator int32_t() const - { - return Value; - } - - Boolean::operator uint32_t() const - { - return Value; - } - - Boolean::operator Object() const - { - return Object(Plugin::InternalUse::Only, Plugin::BoxBoolean(Value)); - } - - Boolean::operator ValueType() const - { - return ValueType(Plugin::InternalUse::Only, Plugin::BoxBoolean(Value)); - } - - Boolean::operator IComparable() const - { - return IComparable(Plugin::InternalUse::Only, Plugin::BoxBoolean(Value)); - } - - Boolean::operator IFormattable() const - { - return IFormattable(Plugin::InternalUse::Only, Plugin::BoxBoolean(Value)); - } - - Boolean::operator IConvertible() const - { - return IConvertible(Plugin::InternalUse::Only, Plugin::BoxBoolean(Value)); - } - - Boolean::operator IComparable_1() const - { - return IComparable_1(Plugin::InternalUse::Only, Plugin::BoxBoolean(Value)); - } - - Boolean::operator IEquatable_1() const - { - return IEquatable_1(Plugin::InternalUse::Only, Plugin::BoxBoolean(Value)); - } - - Char::Char() - : Value(0) - { - } - - Char::Char(char value) - : Value(value) - { - } - - Char::Char(int16_t value) - : Value(value) - { - } - - Char::operator int16_t() const - { - return Value; - } - - Char::operator Object() const - { - return Object(Plugin::InternalUse::Only, Plugin::BoxChar(Value)); - } - - Char::operator ValueType() const - { - return ValueType(Plugin::InternalUse::Only, Plugin::BoxChar(Value)); - } - - Char::operator IComparable() const - { - return IComparable(Plugin::InternalUse::Only, Plugin::BoxChar(Value)); - } - - Char::operator IFormattable() const - { - return IFormattable(Plugin::InternalUse::Only, Plugin::BoxChar(Value)); - } - - Char::operator IConvertible() const - { - return IConvertible(Plugin::InternalUse::Only, Plugin::BoxChar(Value)); - } - - Char::operator IComparable_1() const - { - return IComparable_1(Plugin::InternalUse::Only, Plugin::BoxChar(Value)); - } - - Char::operator IEquatable_1() const - { - return IEquatable_1(Plugin::InternalUse::Only, Plugin::BoxChar(Value)); - } - - SByte::SByte() - : Value(0) - { - } - - SByte::SByte(int8_t val) - : Value(val) - { - } - - SByte::operator int8_t() const - { - return Value; - } - - SByte::operator Object() const - { - return Object(Plugin::InternalUse::Only, Plugin::BoxSByte(Value)); - } - - SByte::operator ValueType() const - { - return ValueType(Plugin::InternalUse::Only, Plugin::BoxSByte(Value)); - } - - SByte::operator IComparable() const - { - return IComparable(Plugin::InternalUse::Only, Plugin::BoxSByte(Value)); - } - - SByte::operator IFormattable() const - { - return IFormattable(Plugin::InternalUse::Only, Plugin::BoxSByte(Value)); - } - - SByte::operator IConvertible() const - { - return IConvertible(Plugin::InternalUse::Only, Plugin::BoxSByte(Value)); - } - - SByte::operator IComparable_1() const - { - return IComparable_1(Plugin::InternalUse::Only, Plugin::BoxSByte(Value)); - } - - SByte::operator IEquatable_1() const - { - return IEquatable_1(Plugin::InternalUse::Only, Plugin::BoxSByte(Value)); - } - - Byte::Byte() - : Value(0) - { - } - - Byte::Byte(uint8_t value) - : Value(value) - { - } - - Byte::operator uint8_t() const - { - return Value; - } - - Byte::operator Object() const - { - return Object(Plugin::InternalUse::Only, Plugin::BoxByte(Value)); - } - - Byte::operator ValueType() const - { - return ValueType(Plugin::InternalUse::Only, Plugin::BoxByte(Value)); - } - - Byte::operator IComparable() const - { - return IComparable(Plugin::InternalUse::Only, Plugin::BoxByte(Value)); - } - - Byte::operator IFormattable() const - { - return IFormattable(Plugin::InternalUse::Only, Plugin::BoxByte(Value)); - } - - Byte::operator IConvertible() const - { - return IConvertible(Plugin::InternalUse::Only, Plugin::BoxByte(Value)); - } - - Byte::operator IComparable_1() const - { - return IComparable_1(Plugin::InternalUse::Only, Plugin::BoxByte(Value)); - } - - Byte::operator IEquatable_1() const - { - return IEquatable_1(Plugin::InternalUse::Only, Plugin::BoxByte(Value)); - } - - Int16::Int16() - : Value(0) - { - } - - Int16::Int16(int16_t value) - : Value(value) - { - } - - Int16::operator int16_t() const - { - return Value; - } - - Int16::operator Object() const - { - return Object(Plugin::InternalUse::Only, Plugin::BoxInt16(Value)); - } - - Int16::operator ValueType() const - { - return ValueType(Plugin::InternalUse::Only, Plugin::BoxInt16(Value)); - } - - Int16::operator IComparable() const - { - return IComparable(Plugin::InternalUse::Only, Plugin::BoxInt16(Value)); - } - - Int16::operator IFormattable() const - { - return IFormattable(Plugin::InternalUse::Only, Plugin::BoxInt16(Value)); - } - - Int16::operator IConvertible() const - { - return IConvertible(Plugin::InternalUse::Only, Plugin::BoxInt16(Value)); - } - - Int16::operator IComparable_1() const - { - return IComparable_1(Plugin::InternalUse::Only, Plugin::BoxInt16(Value)); - } - - Int16::operator IEquatable_1() const - { - return IEquatable_1(Plugin::InternalUse::Only, Plugin::BoxInt16(Value)); - } - - UInt16::UInt16() - : Value(0) - { - } - - UInt16::UInt16(uint16_t value) - : Value(value) - { - } - - UInt16::operator uint16_t() const - { - return Value; - } - - UInt16::operator Object() const - { - return Object(Plugin::InternalUse::Only, Plugin::BoxUInt16(Value)); - } - - UInt16::operator ValueType() const - { - return ValueType(Plugin::InternalUse::Only, Plugin::BoxUInt16(Value)); - } - - UInt16::operator IComparable() const - { - return IComparable(Plugin::InternalUse::Only, Plugin::BoxUInt16(Value)); - } - - UInt16::operator IFormattable() const - { - return IFormattable(Plugin::InternalUse::Only, Plugin::BoxUInt16(Value)); - } - - UInt16::operator IConvertible() const - { - return IConvertible(Plugin::InternalUse::Only, Plugin::BoxUInt16(Value)); - } - - UInt16::operator IComparable_1() const - { - return IComparable_1(Plugin::InternalUse::Only, Plugin::BoxUInt16(Value)); - } - - UInt16::operator IEquatable_1() const - { - return IEquatable_1(Plugin::InternalUse::Only, Plugin::BoxUInt16(Value)); - } - - Int32::Int32() - : Value(0) - { - } - - Int32::Int32(int32_t value) - : Value(value) - { - } - - Int32::operator int32_t() const - { - return Value; - } - - Int32::operator Object() const - { - return Object(Plugin::InternalUse::Only, Plugin::BoxInt32(Value)); - } - - Int32::operator ValueType() const - { - return ValueType(Plugin::InternalUse::Only, Plugin::BoxInt32(Value)); - } - - Int32::operator IComparable() const - { - return IComparable(Plugin::InternalUse::Only, Plugin::BoxInt32(Value)); - } - - Int32::operator IFormattable() const - { - return IFormattable(Plugin::InternalUse::Only, Plugin::BoxInt32(Value)); - } - - Int32::operator IConvertible() const - { - return IConvertible(Plugin::InternalUse::Only, Plugin::BoxInt32(Value)); - } - - Int32::operator IComparable_1() const - { - return IComparable_1(Plugin::InternalUse::Only, Plugin::BoxInt32(Value)); - } - - Int32::operator IEquatable_1() const - { - return IEquatable_1(Plugin::InternalUse::Only, Plugin::BoxInt32(Value)); - } - - UInt32::UInt32() - : Value(0) - { - } - - UInt32::UInt32(uint32_t value) - : Value(value) - { - } - - UInt32::operator uint32_t() const - { - return Value; - } - - UInt32::operator Object() const - { - return Object(Plugin::InternalUse::Only, Plugin::BoxUInt32(Value)); - } - - UInt32::operator ValueType() const - { - return ValueType(Plugin::InternalUse::Only, Plugin::BoxUInt32(Value)); - } - - UInt32::operator IComparable() const - { - return IComparable(Plugin::InternalUse::Only, Plugin::BoxUInt32(Value)); - } - - UInt32::operator IFormattable() const - { - return IFormattable(Plugin::InternalUse::Only, Plugin::BoxUInt32(Value)); - } - - UInt32::operator IConvertible() const - { - return IConvertible(Plugin::InternalUse::Only, Plugin::BoxUInt32(Value)); - } - - UInt32::operator IComparable_1() const - { - return IComparable_1(Plugin::InternalUse::Only, Plugin::BoxUInt32(Value)); - } - - UInt32::operator IEquatable_1() const - { - return IEquatable_1(Plugin::InternalUse::Only, Plugin::BoxUInt32(Value)); - } - - Int64::Int64() - : Value(0) - { - } - - Int64::Int64(int64_t value) - : Value(value) - { - } - - Int64::operator int64_t() const - { - return Value; - } - - Int64::operator Object() const - { - return Object(Plugin::InternalUse::Only, Plugin::BoxInt64(Value)); - } - - Int64::operator ValueType() const - { - return ValueType(Plugin::InternalUse::Only, Plugin::BoxInt64(Value)); - } - - Int64::operator IComparable() const - { - return IComparable(Plugin::InternalUse::Only, Plugin::BoxInt64(Value)); - } - - Int64::operator IFormattable() const - { - return IFormattable(Plugin::InternalUse::Only, Plugin::BoxInt64(Value)); - } - - Int64::operator IConvertible() const - { - return IConvertible(Plugin::InternalUse::Only, Plugin::BoxInt64(Value)); - } - - Int64::operator IComparable_1() const - { - return IComparable_1(Plugin::InternalUse::Only, Plugin::BoxInt64(Value)); - } - - Int64::operator IEquatable_1() const - { - return IEquatable_1(Plugin::InternalUse::Only, Plugin::BoxInt64(Value)); - } - - UInt64::UInt64() - : Value(0) - { - } - - UInt64::UInt64(uint64_t value) - : Value(value) - { - } - - UInt64::operator uint64_t() const - { - return Value; - } - - UInt64::operator Object() const - { - return Object(Plugin::InternalUse::Only, Plugin::BoxUInt64(Value)); - } - - UInt64::operator ValueType() const - { - return ValueType(Plugin::InternalUse::Only, Plugin::BoxUInt64(Value)); - } - - UInt64::operator IComparable() const - { - return IComparable(Plugin::InternalUse::Only, Plugin::BoxUInt64(Value)); - } - - UInt64::operator IFormattable() const - { - return IFormattable(Plugin::InternalUse::Only, Plugin::BoxUInt64(Value)); - } - - UInt64::operator IConvertible() const - { - return IConvertible(Plugin::InternalUse::Only, Plugin::BoxUInt64(Value)); - } - - UInt64::operator IComparable_1() const - { - return IComparable_1(Plugin::InternalUse::Only, Plugin::BoxUInt64(Value)); - } - - UInt64::operator IEquatable_1() const - { - return IEquatable_1(Plugin::InternalUse::Only, Plugin::BoxUInt64(Value)); - } - - Single::Single() - : Value(0.0f) - { - } - - Single::Single(float value) - : Value(value) - { - } - - Single::operator float() const - { - return Value; - } - - Single::operator Object() const - { - return Object(Plugin::InternalUse::Only, Plugin::BoxSingle(Value)); - } - - Single::operator ValueType() const - { - return ValueType(Plugin::InternalUse::Only, Plugin::BoxSingle(Value)); - } - - Single::operator IComparable() const - { - return IComparable(Plugin::InternalUse::Only, Plugin::BoxSingle(Value)); - } - - Single::operator IFormattable() const - { - return IFormattable(Plugin::InternalUse::Only, Plugin::BoxSingle(Value)); - } - - Single::operator IConvertible() const - { - return IConvertible(Plugin::InternalUse::Only, Plugin::BoxSingle(Value)); - } - - Single::operator IComparable_1() const - { - return IComparable_1(Plugin::InternalUse::Only, Plugin::BoxSingle(Value)); - } - - Single::operator IEquatable_1() const - { - return IEquatable_1(Plugin::InternalUse::Only, Plugin::BoxSingle(Value)); - } - - Double::Double() - : Value(0.0) - { - } - - Double::Double(double value) - : Value(value) - { - } - - Double::operator double() const - { - return Value; - } - - Double::operator Object() const - { - return Object(Plugin::InternalUse::Only, Plugin::BoxDouble(Value)); - } - - Double::operator ValueType() const - { - return ValueType(Plugin::InternalUse::Only, Plugin::BoxDouble(Value)); - } - - Double::operator IComparable() const - { - return IComparable(Plugin::InternalUse::Only, Plugin::BoxDouble(Value)); - } - - Double::operator IFormattable() const - { - return IFormattable(Plugin::InternalUse::Only, Plugin::BoxDouble(Value)); - } - - Double::operator IConvertible() const - { - return IConvertible(Plugin::InternalUse::Only, Plugin::BoxDouble(Value)); - } - - Double::operator IComparable_1() const - { - return IComparable_1(Plugin::InternalUse::Only, Plugin::BoxDouble(Value)); - } - - Double::operator IEquatable_1() const - { - return IEquatable_1(Plugin::InternalUse::Only, Plugin::BoxDouble(Value)); - } -} - -//////////////////////////////////////////////////////////////// -// Support for using IEnumerable with range for loops -//////////////////////////////////////////////////////////////// - -namespace Plugin -{ - // End iterators are dummies full of null - EnumerableIterator::EnumerableIterator(decltype(nullptr)) - : enumerator(nullptr) - , hasMore(false) - { - } - - // Begin iterators keep track of an IEnumerator - EnumerableIterator::EnumerableIterator( - System::Collections::IEnumerable& enumerable) - : enumerator(enumerable.GetEnumerator()) - { - hasMore = enumerator.MoveNext(); - } - - EnumerableIterator& EnumerableIterator::operator++() - { - hasMore = enumerator.MoveNext(); - return *this; - } - - bool EnumerableIterator::operator!=(const EnumerableIterator& other) - { - return hasMore; - } - - System::Object EnumerableIterator::operator*() - { - return enumerator.GetCurrent(); - } -} - -//////////////////////////////////////////////////////////////// -// User-defined literals for creating decimals (System.Decimal) -//////////////////////////////////////////////////////////////// - -System::Decimal operator"" _m(long double x) -{ - return System::Decimal((System::Double)x); -} - -System::Decimal operator"" _m(unsigned long long x) -{ - return System::Decimal((System::UInt64)x); -} - -//////////////////////////////////////////////////////////////// -// Reference counting of managed objects -//////////////////////////////////////////////////////////////// - -namespace Plugin -{ - int32_t RefCountsLenClass; - int32_t* RefCountsClass; - - void ReferenceManagedClass(int32_t handle) - { - assert(handle >= 0 && handle < RefCountsLenClass); - if (handle != 0) - { - RefCountsClass[handle]++; - } - } - - void DereferenceManagedClass(int32_t handle) - { - assert(handle >= 0 && handle < RefCountsLenClass); - if (handle != 0) - { - int32_t numRemain = --RefCountsClass[handle]; - if (numRemain == 0) - { - ReleaseObject(handle); - } - } - } - - bool DereferenceManagedClassNoRelease(int32_t handle) - { - assert(handle >= 0 && handle < RefCountsLenClass); - if (handle != 0) - { - int32_t numRemain = --RefCountsClass[handle]; - if (numRemain == 0) - { - return true; - } - } - return false; - } - - /*BEGIN GLOBAL STATE AND FUNCTIONS*/ - int32_t RefCountsLenSystemDecimal; - int32_t* RefCountsSystemDecimal; - - void ReferenceManagedSystemDecimal(int32_t handle) - { - assert(handle >= 0 && handle < RefCountsLenSystemDecimal); - if (handle != 0) - { - RefCountsSystemDecimal[handle]++; - } - } - - void DereferenceManagedSystemDecimal(int32_t handle) - { - assert(handle >= 0 && handle < RefCountsLenSystemDecimal); - if (handle != 0) - { - int32_t numRemain = --RefCountsSystemDecimal[handle]; - if (numRemain == 0) - { - ReleaseSystemDecimal(handle); - } - } - } - - // Free list for MyGame::BaseBallScript pointers - - int32_t BaseBallScriptFreeListSize; - MyGame::BaseBallScript** BaseBallScriptFreeList; - MyGame::BaseBallScript** NextFreeBaseBallScript; - - int32_t StoreBaseBallScript(MyGame::BaseBallScript* del) - { - assert(NextFreeBaseBallScript != nullptr); - MyGame::BaseBallScript** pNext = NextFreeBaseBallScript; - NextFreeBaseBallScript = (MyGame::BaseBallScript**)*pNext; - *pNext = del; - return (int32_t)(pNext - BaseBallScriptFreeList); - } - - MyGame::BaseBallScript* GetBaseBallScript(int32_t handle) - { - assert(handle >= 0 && handle < BaseBallScriptFreeListSize); - return BaseBallScriptFreeList[handle]; - } - - void RemoveBaseBallScript(int32_t handle) - { - MyGame::BaseBallScript** pRelease = BaseBallScriptFreeList + handle; - *pRelease = (MyGame::BaseBallScript*)NextFreeBaseBallScript; - NextFreeBaseBallScript = pRelease; - } - - // Free list for whole MyGame::BaseBallScript objects - - union BaseBallScriptFreeWholeListEntry - { - BaseBallScriptFreeWholeListEntry* Next; - MyGame::BaseBallScript Value; - }; - int32_t BaseBallScriptFreeWholeListSize; - BaseBallScriptFreeWholeListEntry* BaseBallScriptFreeWholeList; - BaseBallScriptFreeWholeListEntry* NextFreeWholeBaseBallScript; - - MyGame::BaseBallScript* StoreWholeBaseBallScript() - { - assert(NextFreeWholeBaseBallScript != nullptr); - BaseBallScriptFreeWholeListEntry* pNext = NextFreeWholeBaseBallScript; - NextFreeWholeBaseBallScript = pNext->Next; - return &pNext->Value; - } - - void RemoveWholeBaseBallScript(MyGame::BaseBallScript* instance) - { - BaseBallScriptFreeWholeListEntry* pRelease = (BaseBallScriptFreeWholeListEntry*)instance; - if (pRelease >= BaseBallScriptFreeWholeList && pRelease < BaseBallScriptFreeWholeList + (BaseBallScriptFreeWholeListSize - 1)) - { - pRelease->Next = NextFreeWholeBaseBallScript; - NextFreeWholeBaseBallScript = pRelease->Next; - } - } - /*END GLOBAL STATE AND FUNCTIONS*/ -} - -namespace Plugin -{ - // An unhandled exception caused by C++ calling into C# - System::Exception* unhandledCsharpException = nullptr; -} - -//////////////////////////////////////////////////////////////// -// Mirrors of C# types. These wrap the C# functions to present -// a similiar API as in C#. -//////////////////////////////////////////////////////////////// - -namespace System -{ - Object::Object() - : Plugin::ManagedType(nullptr) - { - } - - Object::Object(Plugin::InternalUse iu, int32_t handle) - : ManagedType(Plugin::InternalUse::Only, handle) - { - } - - Object::Object(decltype(nullptr)) - : ManagedType(nullptr) - { - } - - Object::~Object() - { - } - - bool Object::operator==(decltype(nullptr)) const - { - return Handle == 0; - } - - bool Object::operator!=(decltype(nullptr)) const - { - return Handle != 0; - } - - void Object::ThrowReferenceToThis() - { - throw *this; - } - - ValueType::ValueType(Plugin::InternalUse iu, int32_t handle) - : Object(iu, handle) - { - } - - ValueType::ValueType(decltype(nullptr)) - : Object(nullptr) - { - } - - Enum::Enum(Plugin::InternalUse iu, int32_t handle) - : ValueType(iu, handle) - { - } - - Enum::Enum(decltype(nullptr)) - : ValueType(nullptr) - { - } - - String::String(decltype(nullptr)) - : Object(Plugin::InternalUse::Only, 0) - { - } - - String::String(Plugin::InternalUse iu, int32_t handle) - : Object(iu, handle) - { - if (handle) - { - Plugin::ReferenceManagedClass(handle); - } - } - - String::String(const String& other) - : Object(Plugin::InternalUse::Only, other.Handle) - { - if (Handle) - { - Plugin::ReferenceManagedClass(Handle); - } - } - - String::String(String&& other) - : Object(Plugin::InternalUse::Only, other.Handle) - { - other.Handle = 0; - } - - String::~String() - { - if (Handle) - { - Plugin::DereferenceManagedClass(Handle); - Handle = 0; - } - } - - String& String::operator=(const String& other) - { - if (Handle != other.Handle) - { - if (Handle) - { - Plugin::DereferenceManagedClass(Handle); - } - Handle = other.Handle; - if (Handle) - { - Plugin::ReferenceManagedClass(Handle); - } - } - return *this; - } - - String& String::operator=(decltype(nullptr)) - { - if (Handle) - { - Plugin::DereferenceManagedClass(Handle); - Handle = 0; - } - return *this; - } - - String& String::operator=(String&& other) - { - if (Handle) - { - Plugin::DereferenceManagedClass(Handle); - } - Handle = other.Handle; - other.Handle = 0; - return *this; - } - - String::String(const char* chars) - : Object(Plugin::InternalUse::Only, Plugin::StringNew(chars)) - { - Plugin::ReferenceManagedClass(Handle); - } - - ICloneable::ICloneable(Plugin::InternalUse iu, int32_t handle) - : Object(iu, handle) - { - } - - ICloneable::ICloneable(decltype(nullptr)) - : Object(nullptr) - { - } - - namespace Collections - { - IEnumerable::IEnumerable(Plugin::InternalUse iu, int32_t handle) - : Object(iu, handle) - { - } - - IEnumerable::IEnumerable(decltype(nullptr)) - : Object(nullptr) - { - } - - IEnumerator IEnumerable::GetEnumerator() - { - return IEnumerator( - Plugin::InternalUse::Only, - Plugin::EnumerableGetEnumerator(Handle)); - } - - Plugin::EnumerableIterator begin( - System::Collections::IEnumerable& enumerable) - { - return Plugin::EnumerableIterator(enumerable); - } - - Plugin::EnumerableIterator end( - System::Collections::IEnumerable& enumerable) - { - return Plugin::EnumerableIterator(nullptr); - } - - ICollection::ICollection(Plugin::InternalUse iu, int32_t handle) - : Object(iu, handle) - , IEnumerable(nullptr) - { - } - - ICollection::ICollection(decltype(nullptr)) - : Object(nullptr) - , IEnumerable(nullptr) - { - } - - IList::IList(Plugin::InternalUse iu, int32_t handle) - : Object(iu, handle) - , IEnumerable(nullptr) - , ICollection(nullptr) - { - } - - IList::IList(decltype(nullptr)) - : Object(nullptr) - , IEnumerable(nullptr) - , ICollection(nullptr) - { - } - } - - Array::Array(Plugin::InternalUse iu, int32_t handle) - : Object(iu, handle) - , ICloneable(nullptr) - , Collections::IEnumerable(nullptr) - , Collections::ICollection(nullptr) - , Collections::IList(nullptr) - { - } - - Array::Array(decltype(nullptr)) - : Object(nullptr) - , ICloneable(nullptr) - , Collections::IEnumerable(nullptr) - , Collections::ICollection(nullptr) - , Collections::IList(nullptr) - { - } - - int32_t Array::GetLength() - { - return Plugin::ArrayGetLength(Handle); - } - - int32_t Array::GetRank() - { - return 0; - } -} - -/*BEGIN METHOD DEFINITIONS*/ -namespace System -{ - IFormattable::IFormattable(decltype(nullptr)) - { - } - - IFormattable::IFormattable(Plugin::InternalUse, int32_t handle) - { - Handle = handle; - if (handle) - { - Plugin::ReferenceManagedClass(handle); - } - } - - IFormattable::IFormattable(const IFormattable& other) - : IFormattable(Plugin::InternalUse::Only, other.Handle) - { - } - - IFormattable::IFormattable(IFormattable&& other) - : IFormattable(Plugin::InternalUse::Only, other.Handle) - { - other.Handle = 0; - } - - IFormattable::~IFormattable() - { - if (Handle) - { - Plugin::DereferenceManagedClass(Handle); - Handle = 0; - } - } - - IFormattable& IFormattable::operator=(const IFormattable& other) - { - if (this->Handle) - { - Plugin::DereferenceManagedClass(this->Handle); - } - this->Handle = other.Handle; - if (this->Handle) - { - Plugin::ReferenceManagedClass(this->Handle); - } - return *this; - } - - IFormattable& IFormattable::operator=(decltype(nullptr)) - { - if (Handle) - { - Plugin::DereferenceManagedClass(Handle); - Handle = 0; - } - return *this; - } - - IFormattable& IFormattable::operator=(IFormattable&& other) - { - if (Handle) - { - Plugin::DereferenceManagedClass(Handle); - } - Handle = other.Handle; - other.Handle = 0; - return *this; - } - - bool IFormattable::operator==(const IFormattable& other) const - { - return Handle == other.Handle; - } - - bool IFormattable::operator!=(const IFormattable& other) const - { - return Handle != other.Handle; - } -} - -namespace System -{ - IConvertible::IConvertible(decltype(nullptr)) - { - } - - IConvertible::IConvertible(Plugin::InternalUse, int32_t handle) - { - Handle = handle; - if (handle) - { - Plugin::ReferenceManagedClass(handle); - } - } - - IConvertible::IConvertible(const IConvertible& other) - : IConvertible(Plugin::InternalUse::Only, other.Handle) - { - } - - IConvertible::IConvertible(IConvertible&& other) - : IConvertible(Plugin::InternalUse::Only, other.Handle) - { - other.Handle = 0; - } - - IConvertible::~IConvertible() - { - if (Handle) - { - Plugin::DereferenceManagedClass(Handle); - Handle = 0; - } - } - - IConvertible& IConvertible::operator=(const IConvertible& other) - { - if (this->Handle) - { - Plugin::DereferenceManagedClass(this->Handle); - } - this->Handle = other.Handle; - if (this->Handle) - { - Plugin::ReferenceManagedClass(this->Handle); - } - return *this; - } - - IConvertible& IConvertible::operator=(decltype(nullptr)) - { - if (Handle) - { - Plugin::DereferenceManagedClass(Handle); - Handle = 0; - } - return *this; - } - - IConvertible& IConvertible::operator=(IConvertible&& other) - { - if (Handle) - { - Plugin::DereferenceManagedClass(Handle); - } - Handle = other.Handle; - other.Handle = 0; - return *this; - } - - bool IConvertible::operator==(const IConvertible& other) const - { - return Handle == other.Handle; - } - - bool IConvertible::operator!=(const IConvertible& other) const - { - return Handle != other.Handle; - } -} - -namespace System -{ - IComparable::IComparable(decltype(nullptr)) - { - } - - IComparable::IComparable(Plugin::InternalUse, int32_t handle) - { - Handle = handle; - if (handle) - { - Plugin::ReferenceManagedClass(handle); - } - } - - IComparable::IComparable(const IComparable& other) - : IComparable(Plugin::InternalUse::Only, other.Handle) - { - } - - IComparable::IComparable(IComparable&& other) - : IComparable(Plugin::InternalUse::Only, other.Handle) - { - other.Handle = 0; - } - - IComparable::~IComparable() - { - if (Handle) - { - Plugin::DereferenceManagedClass(Handle); - Handle = 0; - } - } - - IComparable& IComparable::operator=(const IComparable& other) - { - if (this->Handle) - { - Plugin::DereferenceManagedClass(this->Handle); - } - this->Handle = other.Handle; - if (this->Handle) - { - Plugin::ReferenceManagedClass(this->Handle); - } - return *this; - } - - IComparable& IComparable::operator=(decltype(nullptr)) - { - if (Handle) - { - Plugin::DereferenceManagedClass(Handle); - Handle = 0; - } - return *this; - } - - IComparable& IComparable::operator=(IComparable&& other) - { - if (Handle) - { - Plugin::DereferenceManagedClass(Handle); - } - Handle = other.Handle; - other.Handle = 0; - return *this; - } - - bool IComparable::operator==(const IComparable& other) const - { - return Handle == other.Handle; - } - - bool IComparable::operator!=(const IComparable& other) const - { - return Handle != other.Handle; - } -} - -namespace System -{ - IEquatable_1::IEquatable_1(decltype(nullptr)) - { - } - - IEquatable_1::IEquatable_1(Plugin::InternalUse, int32_t handle) - { - Handle = handle; - if (handle) - { - Plugin::ReferenceManagedClass(handle); - } - } - - IEquatable_1::IEquatable_1(const IEquatable_1& other) - : IEquatable_1(Plugin::InternalUse::Only, other.Handle) - { - } - - IEquatable_1::IEquatable_1(IEquatable_1&& other) - : IEquatable_1(Plugin::InternalUse::Only, other.Handle) - { - other.Handle = 0; - } - - IEquatable_1::~IEquatable_1() - { - if (Handle) - { - Plugin::DereferenceManagedClass(Handle); - Handle = 0; - } - } - - IEquatable_1& IEquatable_1::operator=(const IEquatable_1& other) - { - if (this->Handle) - { - Plugin::DereferenceManagedClass(this->Handle); - } - this->Handle = other.Handle; - if (this->Handle) - { - Plugin::ReferenceManagedClass(this->Handle); - } - return *this; - } - - IEquatable_1& IEquatable_1::operator=(decltype(nullptr)) - { - if (Handle) - { - Plugin::DereferenceManagedClass(Handle); - Handle = 0; - } - return *this; - } - - IEquatable_1& IEquatable_1::operator=(IEquatable_1&& other) - { - if (Handle) - { - Plugin::DereferenceManagedClass(Handle); - } - Handle = other.Handle; - other.Handle = 0; - return *this; - } - - bool IEquatable_1::operator==(const IEquatable_1& other) const - { - return Handle == other.Handle; - } - - bool IEquatable_1::operator!=(const IEquatable_1& other) const - { - return Handle != other.Handle; - } -} - -namespace System -{ - IEquatable_1::IEquatable_1(decltype(nullptr)) - { - } - - IEquatable_1::IEquatable_1(Plugin::InternalUse, int32_t handle) - { - Handle = handle; - if (handle) - { - Plugin::ReferenceManagedClass(handle); - } - } - - IEquatable_1::IEquatable_1(const IEquatable_1& other) - : IEquatable_1(Plugin::InternalUse::Only, other.Handle) - { - } - - IEquatable_1::IEquatable_1(IEquatable_1&& other) - : IEquatable_1(Plugin::InternalUse::Only, other.Handle) - { - other.Handle = 0; - } - - IEquatable_1::~IEquatable_1() - { - if (Handle) - { - Plugin::DereferenceManagedClass(Handle); - Handle = 0; - } - } - - IEquatable_1& IEquatable_1::operator=(const IEquatable_1& other) - { - if (this->Handle) - { - Plugin::DereferenceManagedClass(this->Handle); - } - this->Handle = other.Handle; - if (this->Handle) - { - Plugin::ReferenceManagedClass(this->Handle); - } - return *this; - } - - IEquatable_1& IEquatable_1::operator=(decltype(nullptr)) - { - if (Handle) - { - Plugin::DereferenceManagedClass(Handle); - Handle = 0; - } - return *this; - } - - IEquatable_1& IEquatable_1::operator=(IEquatable_1&& other) - { - if (Handle) - { - Plugin::DereferenceManagedClass(Handle); - } - Handle = other.Handle; - other.Handle = 0; - return *this; - } - - bool IEquatable_1::operator==(const IEquatable_1& other) const - { - return Handle == other.Handle; - } - - bool IEquatable_1::operator!=(const IEquatable_1& other) const - { - return Handle != other.Handle; - } -} - -namespace System -{ - IEquatable_1::IEquatable_1(decltype(nullptr)) - { - } - - IEquatable_1::IEquatable_1(Plugin::InternalUse, int32_t handle) - { - Handle = handle; - if (handle) - { - Plugin::ReferenceManagedClass(handle); - } - } - - IEquatable_1::IEquatable_1(const IEquatable_1& other) - : IEquatable_1(Plugin::InternalUse::Only, other.Handle) - { - } - - IEquatable_1::IEquatable_1(IEquatable_1&& other) - : IEquatable_1(Plugin::InternalUse::Only, other.Handle) - { - other.Handle = 0; - } - - IEquatable_1::~IEquatable_1() - { - if (Handle) - { - Plugin::DereferenceManagedClass(Handle); - Handle = 0; - } - } - - IEquatable_1& IEquatable_1::operator=(const IEquatable_1& other) - { - if (this->Handle) - { - Plugin::DereferenceManagedClass(this->Handle); - } - this->Handle = other.Handle; - if (this->Handle) - { - Plugin::ReferenceManagedClass(this->Handle); - } - return *this; - } - - IEquatable_1& IEquatable_1::operator=(decltype(nullptr)) - { - if (Handle) - { - Plugin::DereferenceManagedClass(Handle); - Handle = 0; - } - return *this; - } - - IEquatable_1& IEquatable_1::operator=(IEquatable_1&& other) - { - if (Handle) - { - Plugin::DereferenceManagedClass(Handle); - } - Handle = other.Handle; - other.Handle = 0; - return *this; - } - - bool IEquatable_1::operator==(const IEquatable_1& other) const - { - return Handle == other.Handle; - } - - bool IEquatable_1::operator!=(const IEquatable_1& other) const - { - return Handle != other.Handle; - } -} - -namespace System -{ - IEquatable_1::IEquatable_1(decltype(nullptr)) - { - } - - IEquatable_1::IEquatable_1(Plugin::InternalUse, int32_t handle) - { - Handle = handle; - if (handle) - { - Plugin::ReferenceManagedClass(handle); - } - } - - IEquatable_1::IEquatable_1(const IEquatable_1& other) - : IEquatable_1(Plugin::InternalUse::Only, other.Handle) - { - } - - IEquatable_1::IEquatable_1(IEquatable_1&& other) - : IEquatable_1(Plugin::InternalUse::Only, other.Handle) - { - other.Handle = 0; - } - - IEquatable_1::~IEquatable_1() - { - if (Handle) - { - Plugin::DereferenceManagedClass(Handle); - Handle = 0; - } - } - - IEquatable_1& IEquatable_1::operator=(const IEquatable_1& other) - { - if (this->Handle) - { - Plugin::DereferenceManagedClass(this->Handle); - } - this->Handle = other.Handle; - if (this->Handle) - { - Plugin::ReferenceManagedClass(this->Handle); - } - return *this; - } - - IEquatable_1& IEquatable_1::operator=(decltype(nullptr)) - { - if (Handle) - { - Plugin::DereferenceManagedClass(Handle); - Handle = 0; - } - return *this; - } - - IEquatable_1& IEquatable_1::operator=(IEquatable_1&& other) - { - if (Handle) - { - Plugin::DereferenceManagedClass(Handle); - } - Handle = other.Handle; - other.Handle = 0; - return *this; - } - - bool IEquatable_1::operator==(const IEquatable_1& other) const - { - return Handle == other.Handle; - } - - bool IEquatable_1::operator!=(const IEquatable_1& other) const - { - return Handle != other.Handle; - } -} - -namespace System -{ - IEquatable_1::IEquatable_1(decltype(nullptr)) - { - } - - IEquatable_1::IEquatable_1(Plugin::InternalUse, int32_t handle) - { - Handle = handle; - if (handle) - { - Plugin::ReferenceManagedClass(handle); - } - } - - IEquatable_1::IEquatable_1(const IEquatable_1& other) - : IEquatable_1(Plugin::InternalUse::Only, other.Handle) - { - } - - IEquatable_1::IEquatable_1(IEquatable_1&& other) - : IEquatable_1(Plugin::InternalUse::Only, other.Handle) - { - other.Handle = 0; - } - - IEquatable_1::~IEquatable_1() - { - if (Handle) - { - Plugin::DereferenceManagedClass(Handle); - Handle = 0; - } - } - - IEquatable_1& IEquatable_1::operator=(const IEquatable_1& other) - { - if (this->Handle) - { - Plugin::DereferenceManagedClass(this->Handle); - } - this->Handle = other.Handle; - if (this->Handle) - { - Plugin::ReferenceManagedClass(this->Handle); - } - return *this; - } - - IEquatable_1& IEquatable_1::operator=(decltype(nullptr)) - { - if (Handle) - { - Plugin::DereferenceManagedClass(Handle); - Handle = 0; - } - return *this; - } - - IEquatable_1& IEquatable_1::operator=(IEquatable_1&& other) - { - if (Handle) - { - Plugin::DereferenceManagedClass(Handle); - } - Handle = other.Handle; - other.Handle = 0; - return *this; - } - - bool IEquatable_1::operator==(const IEquatable_1& other) const - { - return Handle == other.Handle; - } - - bool IEquatable_1::operator!=(const IEquatable_1& other) const - { - return Handle != other.Handle; - } -} - -namespace System -{ - IEquatable_1::IEquatable_1(decltype(nullptr)) - { - } - - IEquatable_1::IEquatable_1(Plugin::InternalUse, int32_t handle) - { - Handle = handle; - if (handle) - { - Plugin::ReferenceManagedClass(handle); - } - } - - IEquatable_1::IEquatable_1(const IEquatable_1& other) - : IEquatable_1(Plugin::InternalUse::Only, other.Handle) - { - } - - IEquatable_1::IEquatable_1(IEquatable_1&& other) - : IEquatable_1(Plugin::InternalUse::Only, other.Handle) - { - other.Handle = 0; - } - - IEquatable_1::~IEquatable_1() - { - if (Handle) - { - Plugin::DereferenceManagedClass(Handle); - Handle = 0; - } - } - - IEquatable_1& IEquatable_1::operator=(const IEquatable_1& other) - { - if (this->Handle) - { - Plugin::DereferenceManagedClass(this->Handle); - } - this->Handle = other.Handle; - if (this->Handle) - { - Plugin::ReferenceManagedClass(this->Handle); - } - return *this; - } - - IEquatable_1& IEquatable_1::operator=(decltype(nullptr)) - { - if (Handle) - { - Plugin::DereferenceManagedClass(Handle); - Handle = 0; - } - return *this; - } - - IEquatable_1& IEquatable_1::operator=(IEquatable_1&& other) - { - if (Handle) - { - Plugin::DereferenceManagedClass(Handle); - } - Handle = other.Handle; - other.Handle = 0; - return *this; - } - - bool IEquatable_1::operator==(const IEquatable_1& other) const - { - return Handle == other.Handle; - } - - bool IEquatable_1::operator!=(const IEquatable_1& other) const - { - return Handle != other.Handle; - } -} - -namespace System -{ - IEquatable_1::IEquatable_1(decltype(nullptr)) - { - } - - IEquatable_1::IEquatable_1(Plugin::InternalUse, int32_t handle) - { - Handle = handle; - if (handle) - { - Plugin::ReferenceManagedClass(handle); - } - } - - IEquatable_1::IEquatable_1(const IEquatable_1& other) - : IEquatable_1(Plugin::InternalUse::Only, other.Handle) - { - } - - IEquatable_1::IEquatable_1(IEquatable_1&& other) - : IEquatable_1(Plugin::InternalUse::Only, other.Handle) - { - other.Handle = 0; - } - - IEquatable_1::~IEquatable_1() - { - if (Handle) - { - Plugin::DereferenceManagedClass(Handle); - Handle = 0; - } - } - - IEquatable_1& IEquatable_1::operator=(const IEquatable_1& other) - { - if (this->Handle) - { - Plugin::DereferenceManagedClass(this->Handle); - } - this->Handle = other.Handle; - if (this->Handle) - { - Plugin::ReferenceManagedClass(this->Handle); - } - return *this; - } - - IEquatable_1& IEquatable_1::operator=(decltype(nullptr)) - { - if (Handle) - { - Plugin::DereferenceManagedClass(Handle); - Handle = 0; - } - return *this; - } - - IEquatable_1& IEquatable_1::operator=(IEquatable_1&& other) - { - if (Handle) - { - Plugin::DereferenceManagedClass(Handle); - } - Handle = other.Handle; - other.Handle = 0; - return *this; - } - - bool IEquatable_1::operator==(const IEquatable_1& other) const - { - return Handle == other.Handle; - } - - bool IEquatable_1::operator!=(const IEquatable_1& other) const - { - return Handle != other.Handle; - } -} - -namespace System -{ - IEquatable_1::IEquatable_1(decltype(nullptr)) - { - } - - IEquatable_1::IEquatable_1(Plugin::InternalUse, int32_t handle) - { - Handle = handle; - if (handle) - { - Plugin::ReferenceManagedClass(handle); - } - } - - IEquatable_1::IEquatable_1(const IEquatable_1& other) - : IEquatable_1(Plugin::InternalUse::Only, other.Handle) - { - } - - IEquatable_1::IEquatable_1(IEquatable_1&& other) - : IEquatable_1(Plugin::InternalUse::Only, other.Handle) - { - other.Handle = 0; - } - - IEquatable_1::~IEquatable_1() - { - if (Handle) - { - Plugin::DereferenceManagedClass(Handle); - Handle = 0; - } - } - - IEquatable_1& IEquatable_1::operator=(const IEquatable_1& other) - { - if (this->Handle) - { - Plugin::DereferenceManagedClass(this->Handle); - } - this->Handle = other.Handle; - if (this->Handle) - { - Plugin::ReferenceManagedClass(this->Handle); - } - return *this; - } - - IEquatable_1& IEquatable_1::operator=(decltype(nullptr)) - { - if (Handle) - { - Plugin::DereferenceManagedClass(Handle); - Handle = 0; - } - return *this; - } - - IEquatable_1& IEquatable_1::operator=(IEquatable_1&& other) - { - if (Handle) - { - Plugin::DereferenceManagedClass(Handle); - } - Handle = other.Handle; - other.Handle = 0; - return *this; - } - - bool IEquatable_1::operator==(const IEquatable_1& other) const - { - return Handle == other.Handle; - } - - bool IEquatable_1::operator!=(const IEquatable_1& other) const - { - return Handle != other.Handle; - } -} - -namespace System -{ - IEquatable_1::IEquatable_1(decltype(nullptr)) - { - } - - IEquatable_1::IEquatable_1(Plugin::InternalUse, int32_t handle) - { - Handle = handle; - if (handle) - { - Plugin::ReferenceManagedClass(handle); - } - } - - IEquatable_1::IEquatable_1(const IEquatable_1& other) - : IEquatable_1(Plugin::InternalUse::Only, other.Handle) - { - } - - IEquatable_1::IEquatable_1(IEquatable_1&& other) - : IEquatable_1(Plugin::InternalUse::Only, other.Handle) - { - other.Handle = 0; - } - - IEquatable_1::~IEquatable_1() - { - if (Handle) - { - Plugin::DereferenceManagedClass(Handle); - Handle = 0; - } - } - - IEquatable_1& IEquatable_1::operator=(const IEquatable_1& other) - { - if (this->Handle) - { - Plugin::DereferenceManagedClass(this->Handle); - } - this->Handle = other.Handle; - if (this->Handle) - { - Plugin::ReferenceManagedClass(this->Handle); - } - return *this; - } - - IEquatable_1& IEquatable_1::operator=(decltype(nullptr)) - { - if (Handle) - { - Plugin::DereferenceManagedClass(Handle); - Handle = 0; - } - return *this; - } - - IEquatable_1& IEquatable_1::operator=(IEquatable_1&& other) - { - if (Handle) - { - Plugin::DereferenceManagedClass(Handle); - } - Handle = other.Handle; - other.Handle = 0; - return *this; - } - - bool IEquatable_1::operator==(const IEquatable_1& other) const - { - return Handle == other.Handle; - } - - bool IEquatable_1::operator!=(const IEquatable_1& other) const - { - return Handle != other.Handle; - } -} - -namespace System -{ - IEquatable_1::IEquatable_1(decltype(nullptr)) - { - } - - IEquatable_1::IEquatable_1(Plugin::InternalUse, int32_t handle) - { - Handle = handle; - if (handle) - { - Plugin::ReferenceManagedClass(handle); - } - } - - IEquatable_1::IEquatable_1(const IEquatable_1& other) - : IEquatable_1(Plugin::InternalUse::Only, other.Handle) - { - } - - IEquatable_1::IEquatable_1(IEquatable_1&& other) - : IEquatable_1(Plugin::InternalUse::Only, other.Handle) - { - other.Handle = 0; - } - - IEquatable_1::~IEquatable_1() - { - if (Handle) - { - Plugin::DereferenceManagedClass(Handle); - Handle = 0; - } - } - - IEquatable_1& IEquatable_1::operator=(const IEquatable_1& other) - { - if (this->Handle) - { - Plugin::DereferenceManagedClass(this->Handle); - } - this->Handle = other.Handle; - if (this->Handle) - { - Plugin::ReferenceManagedClass(this->Handle); - } - return *this; - } - - IEquatable_1& IEquatable_1::operator=(decltype(nullptr)) - { - if (Handle) - { - Plugin::DereferenceManagedClass(Handle); - Handle = 0; - } - return *this; - } - - IEquatable_1& IEquatable_1::operator=(IEquatable_1&& other) - { - if (Handle) - { - Plugin::DereferenceManagedClass(Handle); - } - Handle = other.Handle; - other.Handle = 0; - return *this; - } - - bool IEquatable_1::operator==(const IEquatable_1& other) const - { - return Handle == other.Handle; - } - - bool IEquatable_1::operator!=(const IEquatable_1& other) const - { - return Handle != other.Handle; - } -} - -namespace System -{ - IEquatable_1::IEquatable_1(decltype(nullptr)) - { - } - - IEquatable_1::IEquatable_1(Plugin::InternalUse, int32_t handle) - { - Handle = handle; - if (handle) - { - Plugin::ReferenceManagedClass(handle); - } - } - - IEquatable_1::IEquatable_1(const IEquatable_1& other) - : IEquatable_1(Plugin::InternalUse::Only, other.Handle) - { - } - - IEquatable_1::IEquatable_1(IEquatable_1&& other) - : IEquatable_1(Plugin::InternalUse::Only, other.Handle) - { - other.Handle = 0; - } - - IEquatable_1::~IEquatable_1() - { - if (Handle) - { - Plugin::DereferenceManagedClass(Handle); - Handle = 0; - } - } - - IEquatable_1& IEquatable_1::operator=(const IEquatable_1& other) - { - if (this->Handle) - { - Plugin::DereferenceManagedClass(this->Handle); - } - this->Handle = other.Handle; - if (this->Handle) - { - Plugin::ReferenceManagedClass(this->Handle); - } - return *this; - } - - IEquatable_1& IEquatable_1::operator=(decltype(nullptr)) - { - if (Handle) - { - Plugin::DereferenceManagedClass(Handle); - Handle = 0; - } - return *this; - } - - IEquatable_1& IEquatable_1::operator=(IEquatable_1&& other) - { - if (Handle) - { - Plugin::DereferenceManagedClass(Handle); - } - Handle = other.Handle; - other.Handle = 0; - return *this; - } - - bool IEquatable_1::operator==(const IEquatable_1& other) const - { - return Handle == other.Handle; - } - - bool IEquatable_1::operator!=(const IEquatable_1& other) const - { - return Handle != other.Handle; - } -} - -namespace System -{ - IEquatable_1::IEquatable_1(decltype(nullptr)) - { - } - - IEquatable_1::IEquatable_1(Plugin::InternalUse, int32_t handle) - { - Handle = handle; - if (handle) - { - Plugin::ReferenceManagedClass(handle); - } - } - - IEquatable_1::IEquatable_1(const IEquatable_1& other) - : IEquatable_1(Plugin::InternalUse::Only, other.Handle) - { - } - - IEquatable_1::IEquatable_1(IEquatable_1&& other) - : IEquatable_1(Plugin::InternalUse::Only, other.Handle) - { - other.Handle = 0; - } - - IEquatable_1::~IEquatable_1() - { - if (Handle) - { - Plugin::DereferenceManagedClass(Handle); - Handle = 0; - } - } - - IEquatable_1& IEquatable_1::operator=(const IEquatable_1& other) - { - if (this->Handle) - { - Plugin::DereferenceManagedClass(this->Handle); - } - this->Handle = other.Handle; - if (this->Handle) - { - Plugin::ReferenceManagedClass(this->Handle); - } - return *this; - } - - IEquatable_1& IEquatable_1::operator=(decltype(nullptr)) - { - if (Handle) - { - Plugin::DereferenceManagedClass(Handle); - Handle = 0; - } - return *this; - } - - IEquatable_1& IEquatable_1::operator=(IEquatable_1&& other) - { - if (Handle) - { - Plugin::DereferenceManagedClass(Handle); - } - Handle = other.Handle; - other.Handle = 0; - return *this; - } - - bool IEquatable_1::operator==(const IEquatable_1& other) const - { - return Handle == other.Handle; - } - - bool IEquatable_1::operator!=(const IEquatable_1& other) const - { - return Handle != other.Handle; - } -} - -namespace System -{ - IEquatable_1::IEquatable_1(decltype(nullptr)) - { - } - - IEquatable_1::IEquatable_1(Plugin::InternalUse, int32_t handle) - { - Handle = handle; - if (handle) - { - Plugin::ReferenceManagedClass(handle); - } - } - - IEquatable_1::IEquatable_1(const IEquatable_1& other) - : IEquatable_1(Plugin::InternalUse::Only, other.Handle) - { - } - - IEquatable_1::IEquatable_1(IEquatable_1&& other) - : IEquatable_1(Plugin::InternalUse::Only, other.Handle) - { - other.Handle = 0; - } - - IEquatable_1::~IEquatable_1() - { - if (Handle) - { - Plugin::DereferenceManagedClass(Handle); - Handle = 0; - } - } - - IEquatable_1& IEquatable_1::operator=(const IEquatable_1& other) - { - if (this->Handle) - { - Plugin::DereferenceManagedClass(this->Handle); - } - this->Handle = other.Handle; - if (this->Handle) - { - Plugin::ReferenceManagedClass(this->Handle); - } - return *this; - } - - IEquatable_1& IEquatable_1::operator=(decltype(nullptr)) - { - if (Handle) - { - Plugin::DereferenceManagedClass(Handle); - Handle = 0; - } - return *this; - } - - IEquatable_1& IEquatable_1::operator=(IEquatable_1&& other) - { - if (Handle) - { - Plugin::DereferenceManagedClass(Handle); - } - Handle = other.Handle; - other.Handle = 0; - return *this; - } - - bool IEquatable_1::operator==(const IEquatable_1& other) const - { - return Handle == other.Handle; - } - - bool IEquatable_1::operator!=(const IEquatable_1& other) const - { - return Handle != other.Handle; - } -} - -namespace System -{ - IEquatable_1::IEquatable_1(decltype(nullptr)) - { - } - - IEquatable_1::IEquatable_1(Plugin::InternalUse, int32_t handle) - { - Handle = handle; - if (handle) - { - Plugin::ReferenceManagedClass(handle); - } - } - - IEquatable_1::IEquatable_1(const IEquatable_1& other) - : IEquatable_1(Plugin::InternalUse::Only, other.Handle) - { - } - - IEquatable_1::IEquatable_1(IEquatable_1&& other) - : IEquatable_1(Plugin::InternalUse::Only, other.Handle) - { - other.Handle = 0; - } - - IEquatable_1::~IEquatable_1() - { - if (Handle) - { - Plugin::DereferenceManagedClass(Handle); - Handle = 0; - } - } - - IEquatable_1& IEquatable_1::operator=(const IEquatable_1& other) - { - if (this->Handle) - { - Plugin::DereferenceManagedClass(this->Handle); - } - this->Handle = other.Handle; - if (this->Handle) - { - Plugin::ReferenceManagedClass(this->Handle); - } - return *this; - } - - IEquatable_1& IEquatable_1::operator=(decltype(nullptr)) - { - if (Handle) - { - Plugin::DereferenceManagedClass(Handle); - Handle = 0; - } - return *this; - } - - IEquatable_1& IEquatable_1::operator=(IEquatable_1&& other) - { - if (Handle) - { - Plugin::DereferenceManagedClass(Handle); - } - Handle = other.Handle; - other.Handle = 0; - return *this; - } - - bool IEquatable_1::operator==(const IEquatable_1& other) const - { - return Handle == other.Handle; - } - - bool IEquatable_1::operator!=(const IEquatable_1& other) const - { - return Handle != other.Handle; - } -} - -namespace System -{ - IComparable_1::IComparable_1(decltype(nullptr)) - { - } - - IComparable_1::IComparable_1(Plugin::InternalUse, int32_t handle) - { - Handle = handle; - if (handle) - { - Plugin::ReferenceManagedClass(handle); - } - } - - IComparable_1::IComparable_1(const IComparable_1& other) - : IComparable_1(Plugin::InternalUse::Only, other.Handle) - { - } - - IComparable_1::IComparable_1(IComparable_1&& other) - : IComparable_1(Plugin::InternalUse::Only, other.Handle) - { - other.Handle = 0; - } - - IComparable_1::~IComparable_1() - { - if (Handle) - { - Plugin::DereferenceManagedClass(Handle); - Handle = 0; - } - } - - IComparable_1& IComparable_1::operator=(const IComparable_1& other) - { - if (this->Handle) - { - Plugin::DereferenceManagedClass(this->Handle); - } - this->Handle = other.Handle; - if (this->Handle) - { - Plugin::ReferenceManagedClass(this->Handle); - } - return *this; - } - - IComparable_1& IComparable_1::operator=(decltype(nullptr)) - { - if (Handle) - { - Plugin::DereferenceManagedClass(Handle); - Handle = 0; - } - return *this; - } - - IComparable_1& IComparable_1::operator=(IComparable_1&& other) - { - if (Handle) - { - Plugin::DereferenceManagedClass(Handle); - } - Handle = other.Handle; - other.Handle = 0; - return *this; - } - - bool IComparable_1::operator==(const IComparable_1& other) const - { - return Handle == other.Handle; - } - - bool IComparable_1::operator!=(const IComparable_1& other) const - { - return Handle != other.Handle; - } -} - -namespace System -{ - IComparable_1::IComparable_1(decltype(nullptr)) - { - } - - IComparable_1::IComparable_1(Plugin::InternalUse, int32_t handle) - { - Handle = handle; - if (handle) - { - Plugin::ReferenceManagedClass(handle); - } - } - - IComparable_1::IComparable_1(const IComparable_1& other) - : IComparable_1(Plugin::InternalUse::Only, other.Handle) - { - } - - IComparable_1::IComparable_1(IComparable_1&& other) - : IComparable_1(Plugin::InternalUse::Only, other.Handle) - { - other.Handle = 0; - } - - IComparable_1::~IComparable_1() - { - if (Handle) - { - Plugin::DereferenceManagedClass(Handle); - Handle = 0; - } - } - - IComparable_1& IComparable_1::operator=(const IComparable_1& other) - { - if (this->Handle) - { - Plugin::DereferenceManagedClass(this->Handle); - } - this->Handle = other.Handle; - if (this->Handle) - { - Plugin::ReferenceManagedClass(this->Handle); - } - return *this; - } - - IComparable_1& IComparable_1::operator=(decltype(nullptr)) - { - if (Handle) - { - Plugin::DereferenceManagedClass(Handle); - Handle = 0; - } - return *this; - } - - IComparable_1& IComparable_1::operator=(IComparable_1&& other) - { - if (Handle) - { - Plugin::DereferenceManagedClass(Handle); - } - Handle = other.Handle; - other.Handle = 0; - return *this; - } - - bool IComparable_1::operator==(const IComparable_1& other) const - { - return Handle == other.Handle; - } - - bool IComparable_1::operator!=(const IComparable_1& other) const - { - return Handle != other.Handle; - } -} - -namespace System -{ - IComparable_1::IComparable_1(decltype(nullptr)) - { - } - - IComparable_1::IComparable_1(Plugin::InternalUse, int32_t handle) - { - Handle = handle; - if (handle) - { - Plugin::ReferenceManagedClass(handle); - } - } - - IComparable_1::IComparable_1(const IComparable_1& other) - : IComparable_1(Plugin::InternalUse::Only, other.Handle) - { - } - - IComparable_1::IComparable_1(IComparable_1&& other) - : IComparable_1(Plugin::InternalUse::Only, other.Handle) - { - other.Handle = 0; - } - - IComparable_1::~IComparable_1() - { - if (Handle) - { - Plugin::DereferenceManagedClass(Handle); - Handle = 0; - } - } - - IComparable_1& IComparable_1::operator=(const IComparable_1& other) - { - if (this->Handle) - { - Plugin::DereferenceManagedClass(this->Handle); - } - this->Handle = other.Handle; - if (this->Handle) - { - Plugin::ReferenceManagedClass(this->Handle); - } - return *this; - } - - IComparable_1& IComparable_1::operator=(decltype(nullptr)) - { - if (Handle) - { - Plugin::DereferenceManagedClass(Handle); - Handle = 0; - } - return *this; - } - - IComparable_1& IComparable_1::operator=(IComparable_1&& other) - { - if (Handle) - { - Plugin::DereferenceManagedClass(Handle); - } - Handle = other.Handle; - other.Handle = 0; - return *this; - } - - bool IComparable_1::operator==(const IComparable_1& other) const - { - return Handle == other.Handle; - } - - bool IComparable_1::operator!=(const IComparable_1& other) const - { - return Handle != other.Handle; - } -} - -namespace System -{ - IComparable_1::IComparable_1(decltype(nullptr)) - { - } - - IComparable_1::IComparable_1(Plugin::InternalUse, int32_t handle) - { - Handle = handle; - if (handle) - { - Plugin::ReferenceManagedClass(handle); - } - } - - IComparable_1::IComparable_1(const IComparable_1& other) - : IComparable_1(Plugin::InternalUse::Only, other.Handle) - { - } - - IComparable_1::IComparable_1(IComparable_1&& other) - : IComparable_1(Plugin::InternalUse::Only, other.Handle) - { - other.Handle = 0; - } - - IComparable_1::~IComparable_1() - { - if (Handle) - { - Plugin::DereferenceManagedClass(Handle); - Handle = 0; - } - } - - IComparable_1& IComparable_1::operator=(const IComparable_1& other) - { - if (this->Handle) - { - Plugin::DereferenceManagedClass(this->Handle); - } - this->Handle = other.Handle; - if (this->Handle) - { - Plugin::ReferenceManagedClass(this->Handle); - } - return *this; - } - - IComparable_1& IComparable_1::operator=(decltype(nullptr)) - { - if (Handle) - { - Plugin::DereferenceManagedClass(Handle); - Handle = 0; - } - return *this; - } - - IComparable_1& IComparable_1::operator=(IComparable_1&& other) - { - if (Handle) - { - Plugin::DereferenceManagedClass(Handle); - } - Handle = other.Handle; - other.Handle = 0; - return *this; - } - - bool IComparable_1::operator==(const IComparable_1& other) const - { - return Handle == other.Handle; - } - - bool IComparable_1::operator!=(const IComparable_1& other) const - { - return Handle != other.Handle; - } -} - -namespace System -{ - IComparable_1::IComparable_1(decltype(nullptr)) - { - } - - IComparable_1::IComparable_1(Plugin::InternalUse, int32_t handle) - { - Handle = handle; - if (handle) - { - Plugin::ReferenceManagedClass(handle); - } - } - - IComparable_1::IComparable_1(const IComparable_1& other) - : IComparable_1(Plugin::InternalUse::Only, other.Handle) - { - } - - IComparable_1::IComparable_1(IComparable_1&& other) - : IComparable_1(Plugin::InternalUse::Only, other.Handle) - { - other.Handle = 0; - } - - IComparable_1::~IComparable_1() - { - if (Handle) - { - Plugin::DereferenceManagedClass(Handle); - Handle = 0; - } - } - - IComparable_1& IComparable_1::operator=(const IComparable_1& other) - { - if (this->Handle) - { - Plugin::DereferenceManagedClass(this->Handle); - } - this->Handle = other.Handle; - if (this->Handle) - { - Plugin::ReferenceManagedClass(this->Handle); - } - return *this; - } - - IComparable_1& IComparable_1::operator=(decltype(nullptr)) - { - if (Handle) - { - Plugin::DereferenceManagedClass(Handle); - Handle = 0; - } - return *this; - } - - IComparable_1& IComparable_1::operator=(IComparable_1&& other) - { - if (Handle) - { - Plugin::DereferenceManagedClass(Handle); - } - Handle = other.Handle; - other.Handle = 0; - return *this; - } - - bool IComparable_1::operator==(const IComparable_1& other) const - { - return Handle == other.Handle; - } - - bool IComparable_1::operator!=(const IComparable_1& other) const - { - return Handle != other.Handle; - } -} - -namespace System -{ - IComparable_1::IComparable_1(decltype(nullptr)) - { - } - - IComparable_1::IComparable_1(Plugin::InternalUse, int32_t handle) - { - Handle = handle; - if (handle) - { - Plugin::ReferenceManagedClass(handle); - } - } - - IComparable_1::IComparable_1(const IComparable_1& other) - : IComparable_1(Plugin::InternalUse::Only, other.Handle) - { - } - - IComparable_1::IComparable_1(IComparable_1&& other) - : IComparable_1(Plugin::InternalUse::Only, other.Handle) - { - other.Handle = 0; - } - - IComparable_1::~IComparable_1() - { - if (Handle) - { - Plugin::DereferenceManagedClass(Handle); - Handle = 0; - } - } - - IComparable_1& IComparable_1::operator=(const IComparable_1& other) - { - if (this->Handle) - { - Plugin::DereferenceManagedClass(this->Handle); - } - this->Handle = other.Handle; - if (this->Handle) - { - Plugin::ReferenceManagedClass(this->Handle); - } - return *this; - } - - IComparable_1& IComparable_1::operator=(decltype(nullptr)) - { - if (Handle) - { - Plugin::DereferenceManagedClass(Handle); - Handle = 0; - } - return *this; - } - - IComparable_1& IComparable_1::operator=(IComparable_1&& other) - { - if (Handle) - { - Plugin::DereferenceManagedClass(Handle); - } - Handle = other.Handle; - other.Handle = 0; - return *this; - } - - bool IComparable_1::operator==(const IComparable_1& other) const - { - return Handle == other.Handle; - } - - bool IComparable_1::operator!=(const IComparable_1& other) const - { - return Handle != other.Handle; - } -} - -namespace System -{ - IComparable_1::IComparable_1(decltype(nullptr)) - { - } - - IComparable_1::IComparable_1(Plugin::InternalUse, int32_t handle) - { - Handle = handle; - if (handle) - { - Plugin::ReferenceManagedClass(handle); - } - } - - IComparable_1::IComparable_1(const IComparable_1& other) - : IComparable_1(Plugin::InternalUse::Only, other.Handle) - { - } - - IComparable_1::IComparable_1(IComparable_1&& other) - : IComparable_1(Plugin::InternalUse::Only, other.Handle) - { - other.Handle = 0; - } - - IComparable_1::~IComparable_1() - { - if (Handle) - { - Plugin::DereferenceManagedClass(Handle); - Handle = 0; - } - } - - IComparable_1& IComparable_1::operator=(const IComparable_1& other) - { - if (this->Handle) - { - Plugin::DereferenceManagedClass(this->Handle); - } - this->Handle = other.Handle; - if (this->Handle) - { - Plugin::ReferenceManagedClass(this->Handle); - } - return *this; - } - - IComparable_1& IComparable_1::operator=(decltype(nullptr)) - { - if (Handle) - { - Plugin::DereferenceManagedClass(Handle); - Handle = 0; - } - return *this; - } - - IComparable_1& IComparable_1::operator=(IComparable_1&& other) - { - if (Handle) - { - Plugin::DereferenceManagedClass(Handle); - } - Handle = other.Handle; - other.Handle = 0; - return *this; - } - - bool IComparable_1::operator==(const IComparable_1& other) const - { - return Handle == other.Handle; - } - - bool IComparable_1::operator!=(const IComparable_1& other) const - { - return Handle != other.Handle; - } -} - -namespace System -{ - IComparable_1::IComparable_1(decltype(nullptr)) - { - } - - IComparable_1::IComparable_1(Plugin::InternalUse, int32_t handle) - { - Handle = handle; - if (handle) - { - Plugin::ReferenceManagedClass(handle); - } - } - - IComparable_1::IComparable_1(const IComparable_1& other) - : IComparable_1(Plugin::InternalUse::Only, other.Handle) - { - } - - IComparable_1::IComparable_1(IComparable_1&& other) - : IComparable_1(Plugin::InternalUse::Only, other.Handle) - { - other.Handle = 0; - } - - IComparable_1::~IComparable_1() - { - if (Handle) - { - Plugin::DereferenceManagedClass(Handle); - Handle = 0; - } - } - - IComparable_1& IComparable_1::operator=(const IComparable_1& other) - { - if (this->Handle) - { - Plugin::DereferenceManagedClass(this->Handle); - } - this->Handle = other.Handle; - if (this->Handle) - { - Plugin::ReferenceManagedClass(this->Handle); - } - return *this; - } - - IComparable_1& IComparable_1::operator=(decltype(nullptr)) - { - if (Handle) - { - Plugin::DereferenceManagedClass(Handle); - Handle = 0; - } - return *this; - } - - IComparable_1& IComparable_1::operator=(IComparable_1&& other) - { - if (Handle) - { - Plugin::DereferenceManagedClass(Handle); - } - Handle = other.Handle; - other.Handle = 0; - return *this; - } - - bool IComparable_1::operator==(const IComparable_1& other) const - { - return Handle == other.Handle; - } - - bool IComparable_1::operator!=(const IComparable_1& other) const - { - return Handle != other.Handle; - } -} - -namespace System -{ - IComparable_1::IComparable_1(decltype(nullptr)) - { - } - - IComparable_1::IComparable_1(Plugin::InternalUse, int32_t handle) - { - Handle = handle; - if (handle) - { - Plugin::ReferenceManagedClass(handle); - } - } - - IComparable_1::IComparable_1(const IComparable_1& other) - : IComparable_1(Plugin::InternalUse::Only, other.Handle) - { - } - - IComparable_1::IComparable_1(IComparable_1&& other) - : IComparable_1(Plugin::InternalUse::Only, other.Handle) - { - other.Handle = 0; - } - - IComparable_1::~IComparable_1() - { - if (Handle) - { - Plugin::DereferenceManagedClass(Handle); - Handle = 0; - } - } - - IComparable_1& IComparable_1::operator=(const IComparable_1& other) - { - if (this->Handle) - { - Plugin::DereferenceManagedClass(this->Handle); - } - this->Handle = other.Handle; - if (this->Handle) - { - Plugin::ReferenceManagedClass(this->Handle); - } - return *this; - } - - IComparable_1& IComparable_1::operator=(decltype(nullptr)) - { - if (Handle) - { - Plugin::DereferenceManagedClass(Handle); - Handle = 0; - } - return *this; - } - - IComparable_1& IComparable_1::operator=(IComparable_1&& other) - { - if (Handle) - { - Plugin::DereferenceManagedClass(Handle); - } - Handle = other.Handle; - other.Handle = 0; - return *this; - } - - bool IComparable_1::operator==(const IComparable_1& other) const - { - return Handle == other.Handle; - } - - bool IComparable_1::operator!=(const IComparable_1& other) const - { - return Handle != other.Handle; - } -} - -namespace System -{ - IComparable_1::IComparable_1(decltype(nullptr)) - { - } - - IComparable_1::IComparable_1(Plugin::InternalUse, int32_t handle) - { - Handle = handle; - if (handle) - { - Plugin::ReferenceManagedClass(handle); - } - } - - IComparable_1::IComparable_1(const IComparable_1& other) - : IComparable_1(Plugin::InternalUse::Only, other.Handle) - { - } - - IComparable_1::IComparable_1(IComparable_1&& other) - : IComparable_1(Plugin::InternalUse::Only, other.Handle) - { - other.Handle = 0; - } - - IComparable_1::~IComparable_1() - { - if (Handle) - { - Plugin::DereferenceManagedClass(Handle); - Handle = 0; - } - } - - IComparable_1& IComparable_1::operator=(const IComparable_1& other) - { - if (this->Handle) - { - Plugin::DereferenceManagedClass(this->Handle); - } - this->Handle = other.Handle; - if (this->Handle) - { - Plugin::ReferenceManagedClass(this->Handle); - } - return *this; - } - - IComparable_1& IComparable_1::operator=(decltype(nullptr)) - { - if (Handle) - { - Plugin::DereferenceManagedClass(Handle); - Handle = 0; - } - return *this; - } - - IComparable_1& IComparable_1::operator=(IComparable_1&& other) - { - if (Handle) - { - Plugin::DereferenceManagedClass(Handle); - } - Handle = other.Handle; - other.Handle = 0; - return *this; - } - - bool IComparable_1::operator==(const IComparable_1& other) const - { - return Handle == other.Handle; - } - - bool IComparable_1::operator!=(const IComparable_1& other) const - { - return Handle != other.Handle; - } -} - -namespace System -{ - IComparable_1::IComparable_1(decltype(nullptr)) - { - } - - IComparable_1::IComparable_1(Plugin::InternalUse, int32_t handle) - { - Handle = handle; - if (handle) - { - Plugin::ReferenceManagedClass(handle); - } - } - - IComparable_1::IComparable_1(const IComparable_1& other) - : IComparable_1(Plugin::InternalUse::Only, other.Handle) - { - } - - IComparable_1::IComparable_1(IComparable_1&& other) - : IComparable_1(Plugin::InternalUse::Only, other.Handle) - { - other.Handle = 0; - } - - IComparable_1::~IComparable_1() - { - if (Handle) - { - Plugin::DereferenceManagedClass(Handle); - Handle = 0; - } - } - - IComparable_1& IComparable_1::operator=(const IComparable_1& other) - { - if (this->Handle) - { - Plugin::DereferenceManagedClass(this->Handle); - } - this->Handle = other.Handle; - if (this->Handle) - { - Plugin::ReferenceManagedClass(this->Handle); - } - return *this; - } - - IComparable_1& IComparable_1::operator=(decltype(nullptr)) - { - if (Handle) - { - Plugin::DereferenceManagedClass(Handle); - Handle = 0; - } - return *this; - } - - IComparable_1& IComparable_1::operator=(IComparable_1&& other) - { - if (Handle) - { - Plugin::DereferenceManagedClass(Handle); - } - Handle = other.Handle; - other.Handle = 0; - return *this; - } - - bool IComparable_1::operator==(const IComparable_1& other) const - { - return Handle == other.Handle; - } - - bool IComparable_1::operator!=(const IComparable_1& other) const - { - return Handle != other.Handle; - } -} - -namespace System -{ - IComparable_1::IComparable_1(decltype(nullptr)) - { - } - - IComparable_1::IComparable_1(Plugin::InternalUse, int32_t handle) - { - Handle = handle; - if (handle) - { - Plugin::ReferenceManagedClass(handle); - } - } - - IComparable_1::IComparable_1(const IComparable_1& other) - : IComparable_1(Plugin::InternalUse::Only, other.Handle) - { - } - - IComparable_1::IComparable_1(IComparable_1&& other) - : IComparable_1(Plugin::InternalUse::Only, other.Handle) - { - other.Handle = 0; - } - - IComparable_1::~IComparable_1() - { - if (Handle) - { - Plugin::DereferenceManagedClass(Handle); - Handle = 0; - } - } - - IComparable_1& IComparable_1::operator=(const IComparable_1& other) - { - if (this->Handle) - { - Plugin::DereferenceManagedClass(this->Handle); - } - this->Handle = other.Handle; - if (this->Handle) - { - Plugin::ReferenceManagedClass(this->Handle); - } - return *this; - } - - IComparable_1& IComparable_1::operator=(decltype(nullptr)) - { - if (Handle) - { - Plugin::DereferenceManagedClass(Handle); - Handle = 0; - } - return *this; - } - - IComparable_1& IComparable_1::operator=(IComparable_1&& other) - { - if (Handle) - { - Plugin::DereferenceManagedClass(Handle); - } - Handle = other.Handle; - other.Handle = 0; - return *this; - } - - bool IComparable_1::operator==(const IComparable_1& other) const - { - return Handle == other.Handle; - } - - bool IComparable_1::operator!=(const IComparable_1& other) const - { - return Handle != other.Handle; - } -} - -namespace System -{ - IComparable_1::IComparable_1(decltype(nullptr)) - { - } - - IComparable_1::IComparable_1(Plugin::InternalUse, int32_t handle) - { - Handle = handle; - if (handle) - { - Plugin::ReferenceManagedClass(handle); - } - } - - IComparable_1::IComparable_1(const IComparable_1& other) - : IComparable_1(Plugin::InternalUse::Only, other.Handle) - { - } - - IComparable_1::IComparable_1(IComparable_1&& other) - : IComparable_1(Plugin::InternalUse::Only, other.Handle) - { - other.Handle = 0; - } - - IComparable_1::~IComparable_1() - { - if (Handle) - { - Plugin::DereferenceManagedClass(Handle); - Handle = 0; - } - } - - IComparable_1& IComparable_1::operator=(const IComparable_1& other) - { - if (this->Handle) - { - Plugin::DereferenceManagedClass(this->Handle); - } - this->Handle = other.Handle; - if (this->Handle) - { - Plugin::ReferenceManagedClass(this->Handle); - } - return *this; - } - - IComparable_1& IComparable_1::operator=(decltype(nullptr)) - { - if (Handle) - { - Plugin::DereferenceManagedClass(Handle); - Handle = 0; - } - return *this; - } - - IComparable_1& IComparable_1::operator=(IComparable_1&& other) - { - if (Handle) - { - Plugin::DereferenceManagedClass(Handle); - } - Handle = other.Handle; - other.Handle = 0; - return *this; - } - - bool IComparable_1::operator==(const IComparable_1& other) const - { - return Handle == other.Handle; - } - - bool IComparable_1::operator!=(const IComparable_1& other) const - { - return Handle != other.Handle; - } -} - -namespace System -{ - namespace Runtime - { - namespace Serialization - { - IDeserializationCallback::IDeserializationCallback(decltype(nullptr)) - { - } - - IDeserializationCallback::IDeserializationCallback(Plugin::InternalUse, int32_t handle) - { - Handle = handle; - if (handle) - { - Plugin::ReferenceManagedClass(handle); - } - } - - IDeserializationCallback::IDeserializationCallback(const IDeserializationCallback& other) - : IDeserializationCallback(Plugin::InternalUse::Only, other.Handle) - { - } - - IDeserializationCallback::IDeserializationCallback(IDeserializationCallback&& other) - : IDeserializationCallback(Plugin::InternalUse::Only, other.Handle) - { - other.Handle = 0; - } - - IDeserializationCallback::~IDeserializationCallback() - { - if (Handle) - { - Plugin::DereferenceManagedClass(Handle); - Handle = 0; - } - } - - IDeserializationCallback& IDeserializationCallback::operator=(const IDeserializationCallback& other) - { - if (this->Handle) - { - Plugin::DereferenceManagedClass(this->Handle); - } - this->Handle = other.Handle; - if (this->Handle) - { - Plugin::ReferenceManagedClass(this->Handle); - } - return *this; - } - - IDeserializationCallback& IDeserializationCallback::operator=(decltype(nullptr)) - { - if (Handle) - { - Plugin::DereferenceManagedClass(Handle); - Handle = 0; - } - return *this; - } - - IDeserializationCallback& IDeserializationCallback::operator=(IDeserializationCallback&& other) - { - if (Handle) - { - Plugin::DereferenceManagedClass(Handle); - } - Handle = other.Handle; - other.Handle = 0; - return *this; - } - - bool IDeserializationCallback::operator==(const IDeserializationCallback& other) const - { - return Handle == other.Handle; - } - - bool IDeserializationCallback::operator!=(const IDeserializationCallback& other) const - { - return Handle != other.Handle; - } - } - } -} - -namespace System -{ - Decimal::Decimal(decltype(nullptr)) - { - } - - Decimal::Decimal(Plugin::InternalUse, int32_t handle) - { - Handle = handle; - if (handle) - { - Plugin::ReferenceManagedSystemDecimal(Handle); - } - } - - Decimal::Decimal(const Decimal& other) - : Decimal(Plugin::InternalUse::Only, other.Handle) - { - } - - Decimal::Decimal(Decimal&& other) - : Decimal(Plugin::InternalUse::Only, other.Handle) - { - other.Handle = 0; - } - - Decimal::~Decimal() - { - if (Handle) - { - Plugin::DereferenceManagedSystemDecimal(Handle); - Handle = 0; - } - } - - Decimal& Decimal::operator=(const Decimal& other) - { - if (this->Handle) - { - Plugin::DereferenceManagedSystemDecimal(Handle); - } - this->Handle = other.Handle; - if (this->Handle) - { - Plugin::ReferenceManagedSystemDecimal(Handle); - } - return *this; - } - - Decimal& Decimal::operator=(decltype(nullptr)) - { - if (Handle) - { - Plugin::DereferenceManagedSystemDecimal(Handle); - Handle = 0; - } - return *this; - } - - Decimal& Decimal::operator=(Decimal&& other) - { - if (Handle) - { - Plugin::DereferenceManagedSystemDecimal(Handle); - } - Handle = other.Handle; - other.Handle = 0; - return *this; - } - - bool Decimal::operator==(const Decimal& other) const - { - return Handle == other.Handle; - } - - bool Decimal::operator!=(const Decimal& other) const - { - return Handle != other.Handle; - } - - System::Decimal::Decimal(System::Double value) - { - auto returnValue = Plugin::SystemDecimalConstructorSystemDouble(value); - if (Plugin::unhandledCsharpException) - { - System::Exception* ex = Plugin::unhandledCsharpException; - Plugin::unhandledCsharpException = nullptr; - ex->ThrowReferenceToThis(); - delete ex; - } - Handle = returnValue; - if (returnValue) - { - Plugin::ReferenceManagedSystemDecimal(Handle); - } - } - - System::Decimal::Decimal(System::UInt64 value) - { - auto returnValue = Plugin::SystemDecimalConstructorSystemUInt64(value); - if (Plugin::unhandledCsharpException) - { - System::Exception* ex = Plugin::unhandledCsharpException; - Plugin::unhandledCsharpException = nullptr; - ex->ThrowReferenceToThis(); - delete ex; - } - Handle = returnValue; - if (returnValue) - { - Plugin::ReferenceManagedSystemDecimal(Handle); - } - } - - System::Decimal::operator System::ValueType() - { - int32_t handle = Plugin::BoxDecimal(Handle); - if (Plugin::unhandledCsharpException) - { - System::Exception* ex = Plugin::unhandledCsharpException; - Plugin::unhandledCsharpException = nullptr; - ex->ThrowReferenceToThis(); - delete ex; - } - if (handle) - { - Plugin::ReferenceManagedClass(handle); - return System::ValueType(Plugin::InternalUse::Only, handle); - } - return nullptr; - } - - System::Decimal::operator System::Object() - { - int32_t handle = Plugin::BoxDecimal(Handle); - if (Plugin::unhandledCsharpException) - { - System::Exception* ex = Plugin::unhandledCsharpException; - Plugin::unhandledCsharpException = nullptr; - ex->ThrowReferenceToThis(); - delete ex; - } - if (handle) - { - Plugin::ReferenceManagedClass(handle); - return System::Object(Plugin::InternalUse::Only, handle); - } - return nullptr; - } - - System::Decimal::operator System::IComparable() - { - int32_t handle = Plugin::BoxDecimal(Handle); - if (Plugin::unhandledCsharpException) - { - System::Exception* ex = Plugin::unhandledCsharpException; - Plugin::unhandledCsharpException = nullptr; - ex->ThrowReferenceToThis(); - delete ex; - } - if (handle) - { - Plugin::ReferenceManagedClass(handle); - return System::IComparable(Plugin::InternalUse::Only, handle); - } - return nullptr; - } - - System::Decimal::operator System::IComparable_1() - { - int32_t handle = Plugin::BoxDecimal(Handle); - if (Plugin::unhandledCsharpException) - { - System::Exception* ex = Plugin::unhandledCsharpException; - Plugin::unhandledCsharpException = nullptr; - ex->ThrowReferenceToThis(); - delete ex; - } - if (handle) - { - Plugin::ReferenceManagedClass(handle); - return System::IComparable_1(Plugin::InternalUse::Only, handle); - } - return nullptr; - } - - System::Decimal::operator System::IConvertible() - { - int32_t handle = Plugin::BoxDecimal(Handle); - if (Plugin::unhandledCsharpException) - { - System::Exception* ex = Plugin::unhandledCsharpException; - Plugin::unhandledCsharpException = nullptr; - ex->ThrowReferenceToThis(); - delete ex; - } - if (handle) - { - Plugin::ReferenceManagedClass(handle); - return System::IConvertible(Plugin::InternalUse::Only, handle); - } - return nullptr; - } - - System::Decimal::operator System::IEquatable_1() - { - int32_t handle = Plugin::BoxDecimal(Handle); - if (Plugin::unhandledCsharpException) - { - System::Exception* ex = Plugin::unhandledCsharpException; - Plugin::unhandledCsharpException = nullptr; - ex->ThrowReferenceToThis(); - delete ex; - } - if (handle) - { - Plugin::ReferenceManagedClass(handle); - return System::IEquatable_1(Plugin::InternalUse::Only, handle); - } - return nullptr; - } - - System::Decimal::operator System::Runtime::Serialization::IDeserializationCallback() - { - int32_t handle = Plugin::BoxDecimal(Handle); - if (Plugin::unhandledCsharpException) - { - System::Exception* ex = Plugin::unhandledCsharpException; - Plugin::unhandledCsharpException = nullptr; - ex->ThrowReferenceToThis(); - delete ex; - } - if (handle) - { - Plugin::ReferenceManagedClass(handle); - return System::Runtime::Serialization::IDeserializationCallback(Plugin::InternalUse::Only, handle); - } - return nullptr; - } - - System::Decimal::operator System::IFormattable() - { - int32_t handle = Plugin::BoxDecimal(Handle); - if (Plugin::unhandledCsharpException) - { - System::Exception* ex = Plugin::unhandledCsharpException; - Plugin::unhandledCsharpException = nullptr; - ex->ThrowReferenceToThis(); - delete ex; - } - if (handle) - { - Plugin::ReferenceManagedClass(handle); - return System::IFormattable(Plugin::InternalUse::Only, handle); - } - return nullptr; - } -} - -namespace System -{ - System::Object::operator System::Decimal() - { - System::Decimal returnVal(Plugin::InternalUse::Only, Plugin::UnboxDecimal(Handle)); - if (Plugin::unhandledCsharpException) - { - System::Exception* ex = Plugin::unhandledCsharpException; - Plugin::unhandledCsharpException = nullptr; - ex->ThrowReferenceToThis(); - delete ex; - } - return returnVal; - } -} - -namespace UnityEngine -{ - Vector3::Vector3() - { - } - - UnityEngine::Vector3::Vector3(System::Single x, System::Single y, System::Single z) - { - auto returnValue = Plugin::UnityEngineVector3ConstructorSystemSingle_SystemSingle_SystemSingle(x, y, z); - if (Plugin::unhandledCsharpException) - { - System::Exception* ex = Plugin::unhandledCsharpException; - Plugin::unhandledCsharpException = nullptr; - ex->ThrowReferenceToThis(); - delete ex; - } - *this = returnValue; - } - - UnityEngine::Vector3 UnityEngine::Vector3::operator+(UnityEngine::Vector3& a) - { - auto returnValue = Plugin::UnityEngineVector3Methodop_AdditionUnityEngineVector3_UnityEngineVector3(*this, a); - if (Plugin::unhandledCsharpException) - { - System::Exception* ex = Plugin::unhandledCsharpException; - Plugin::unhandledCsharpException = nullptr; - ex->ThrowReferenceToThis(); - delete ex; - } - return returnValue; - } - - UnityEngine::Vector3::operator System::ValueType() - { - int32_t handle = Plugin::BoxVector3(*this); - if (Plugin::unhandledCsharpException) - { - System::Exception* ex = Plugin::unhandledCsharpException; - Plugin::unhandledCsharpException = nullptr; - ex->ThrowReferenceToThis(); - delete ex; - } - if (handle) - { - Plugin::ReferenceManagedClass(handle); - return System::ValueType(Plugin::InternalUse::Only, handle); - } - return nullptr; - } - - UnityEngine::Vector3::operator System::Object() - { - int32_t handle = Plugin::BoxVector3(*this); - if (Plugin::unhandledCsharpException) - { - System::Exception* ex = Plugin::unhandledCsharpException; - Plugin::unhandledCsharpException = nullptr; - ex->ThrowReferenceToThis(); - delete ex; - } - if (handle) - { - Plugin::ReferenceManagedClass(handle); - return System::Object(Plugin::InternalUse::Only, handle); - } - return nullptr; - } - - UnityEngine::Vector3::operator System::IEquatable_1() - { - int32_t handle = Plugin::BoxVector3(*this); - if (Plugin::unhandledCsharpException) - { - System::Exception* ex = Plugin::unhandledCsharpException; - Plugin::unhandledCsharpException = nullptr; - ex->ThrowReferenceToThis(); - delete ex; - } - if (handle) - { - Plugin::ReferenceManagedClass(handle); - return System::IEquatable_1(Plugin::InternalUse::Only, handle); - } - return nullptr; - } -} - -namespace System -{ - System::Object::operator UnityEngine::Vector3() - { - UnityEngine::Vector3 returnVal(Plugin::UnboxVector3(Handle)); - if (Plugin::unhandledCsharpException) - { - System::Exception* ex = Plugin::unhandledCsharpException; - Plugin::unhandledCsharpException = nullptr; - ex->ThrowReferenceToThis(); - delete ex; - } - return returnVal; - } -} - -namespace UnityEngine -{ - Object::Object(decltype(nullptr)) - { - } - - Object::Object(Plugin::InternalUse, int32_t handle) - { - Handle = handle; - if (handle) - { - Plugin::ReferenceManagedClass(handle); - } - } - - Object::Object(const Object& other) - : Object(Plugin::InternalUse::Only, other.Handle) - { - } - - Object::Object(Object&& other) - : Object(Plugin::InternalUse::Only, other.Handle) - { - other.Handle = 0; - } - - Object::~Object() - { - if (Handle) - { - Plugin::DereferenceManagedClass(Handle); - Handle = 0; - } - } - - Object& Object::operator=(const Object& other) - { - if (this->Handle) - { - Plugin::DereferenceManagedClass(this->Handle); - } - this->Handle = other.Handle; - if (this->Handle) - { - Plugin::ReferenceManagedClass(this->Handle); - } - return *this; - } - - Object& Object::operator=(decltype(nullptr)) - { - if (Handle) - { - Plugin::DereferenceManagedClass(Handle); - Handle = 0; - } - return *this; - } - - Object& Object::operator=(Object&& other) - { - if (Handle) - { - Plugin::DereferenceManagedClass(Handle); - } - Handle = other.Handle; - other.Handle = 0; - return *this; - } - - bool Object::operator==(const Object& other) const - { - return Handle == other.Handle; - } - - bool Object::operator!=(const Object& other) const - { - return Handle != other.Handle; - } - - System::String UnityEngine::Object::GetName() - { - auto returnValue = Plugin::UnityEngineObjectPropertyGetName(Handle); - if (Plugin::unhandledCsharpException) - { - System::Exception* ex = Plugin::unhandledCsharpException; - Plugin::unhandledCsharpException = nullptr; - ex->ThrowReferenceToThis(); - delete ex; - } - return System::String(Plugin::InternalUse::Only, returnValue); - } - - void UnityEngine::Object::SetName(System::String& value) - { - Plugin::UnityEngineObjectPropertySetName(Handle, value.Handle); - if (Plugin::unhandledCsharpException) - { - System::Exception* ex = Plugin::unhandledCsharpException; - Plugin::unhandledCsharpException = nullptr; - ex->ThrowReferenceToThis(); - delete ex; - } - } -} - -namespace UnityEngine -{ - Component::Component(decltype(nullptr)) - : UnityEngine::Object(nullptr) - { - } - - Component::Component(Plugin::InternalUse, int32_t handle) - : UnityEngine::Object(nullptr) - { - Handle = handle; - if (handle) - { - Plugin::ReferenceManagedClass(handle); - } - } - - Component::Component(const Component& other) - : Component(Plugin::InternalUse::Only, other.Handle) - { - } - - Component::Component(Component&& other) - : Component(Plugin::InternalUse::Only, other.Handle) - { - other.Handle = 0; - } - - Component::~Component() - { - if (Handle) - { - Plugin::DereferenceManagedClass(Handle); - Handle = 0; - } - } - - Component& Component::operator=(const Component& other) - { - if (this->Handle) - { - Plugin::DereferenceManagedClass(this->Handle); - } - this->Handle = other.Handle; - if (this->Handle) - { - Plugin::ReferenceManagedClass(this->Handle); - } - return *this; - } - - Component& Component::operator=(decltype(nullptr)) - { - if (Handle) - { - Plugin::DereferenceManagedClass(Handle); - Handle = 0; - } - return *this; - } - - Component& Component::operator=(Component&& other) - { - if (Handle) - { - Plugin::DereferenceManagedClass(Handle); - } - Handle = other.Handle; - other.Handle = 0; - return *this; - } - - bool Component::operator==(const Component& other) const - { - return Handle == other.Handle; - } - - bool Component::operator!=(const Component& other) const - { - return Handle != other.Handle; - } - - UnityEngine::Transform UnityEngine::Component::GetTransform() - { - auto returnValue = Plugin::UnityEngineComponentPropertyGetTransform(Handle); - if (Plugin::unhandledCsharpException) - { - System::Exception* ex = Plugin::unhandledCsharpException; - Plugin::unhandledCsharpException = nullptr; - ex->ThrowReferenceToThis(); - delete ex; - } - return UnityEngine::Transform(Plugin::InternalUse::Only, returnValue); - } -} - -namespace UnityEngine -{ - Transform::Transform(decltype(nullptr)) - : UnityEngine::Object(nullptr) - , UnityEngine::Component(nullptr) - , System::Collections::IEnumerable(nullptr) - { - } - - Transform::Transform(Plugin::InternalUse, int32_t handle) - : UnityEngine::Object(nullptr) - , UnityEngine::Component(nullptr) - , System::Collections::IEnumerable(nullptr) - { - Handle = handle; - if (handle) - { - Plugin::ReferenceManagedClass(handle); - } - } - - Transform::Transform(const Transform& other) - : Transform(Plugin::InternalUse::Only, other.Handle) - { - } - - Transform::Transform(Transform&& other) - : Transform(Plugin::InternalUse::Only, other.Handle) - { - other.Handle = 0; - } - - Transform::~Transform() - { - if (Handle) - { - Plugin::DereferenceManagedClass(Handle); - Handle = 0; - } - } - - Transform& Transform::operator=(const Transform& other) - { - if (this->Handle) - { - Plugin::DereferenceManagedClass(this->Handle); - } - this->Handle = other.Handle; - if (this->Handle) - { - Plugin::ReferenceManagedClass(this->Handle); - } - return *this; - } - - Transform& Transform::operator=(decltype(nullptr)) - { - if (Handle) - { - Plugin::DereferenceManagedClass(Handle); - Handle = 0; - } - return *this; - } - - Transform& Transform::operator=(Transform&& other) - { - if (Handle) - { - Plugin::DereferenceManagedClass(Handle); - } - Handle = other.Handle; - other.Handle = 0; - return *this; - } - - bool Transform::operator==(const Transform& other) const - { - return Handle == other.Handle; - } - - bool Transform::operator!=(const Transform& other) const - { - return Handle != other.Handle; - } - - UnityEngine::Vector3 UnityEngine::Transform::GetPosition() - { - auto returnValue = Plugin::UnityEngineTransformPropertyGetPosition(Handle); - if (Plugin::unhandledCsharpException) - { - System::Exception* ex = Plugin::unhandledCsharpException; - Plugin::unhandledCsharpException = nullptr; - ex->ThrowReferenceToThis(); - delete ex; - } - return returnValue; - } - - void UnityEngine::Transform::SetPosition(UnityEngine::Vector3& value) - { - Plugin::UnityEngineTransformPropertySetPosition(Handle, value); - if (Plugin::unhandledCsharpException) - { - System::Exception* ex = Plugin::unhandledCsharpException; - Plugin::unhandledCsharpException = nullptr; - ex->ThrowReferenceToThis(); - delete ex; - } - } -} - -namespace System -{ - namespace Collections - { - IEnumerator::IEnumerator(decltype(nullptr)) - { - } - - IEnumerator::IEnumerator(Plugin::InternalUse, int32_t handle) - { - Handle = handle; - if (handle) - { - Plugin::ReferenceManagedClass(handle); - } - } - - IEnumerator::IEnumerator(const IEnumerator& other) - : IEnumerator(Plugin::InternalUse::Only, other.Handle) - { - } - - IEnumerator::IEnumerator(IEnumerator&& other) - : IEnumerator(Plugin::InternalUse::Only, other.Handle) - { - other.Handle = 0; - } - - IEnumerator::~IEnumerator() - { - if (Handle) - { - Plugin::DereferenceManagedClass(Handle); - Handle = 0; - } - } - - IEnumerator& IEnumerator::operator=(const IEnumerator& other) - { - if (this->Handle) - { - Plugin::DereferenceManagedClass(this->Handle); - } - this->Handle = other.Handle; - if (this->Handle) - { - Plugin::ReferenceManagedClass(this->Handle); - } - return *this; - } - - IEnumerator& IEnumerator::operator=(decltype(nullptr)) - { - if (Handle) - { - Plugin::DereferenceManagedClass(Handle); - Handle = 0; - } - return *this; - } - - IEnumerator& IEnumerator::operator=(IEnumerator&& other) - { - if (Handle) - { - Plugin::DereferenceManagedClass(Handle); - } - Handle = other.Handle; - other.Handle = 0; - return *this; - } - - bool IEnumerator::operator==(const IEnumerator& other) const - { - return Handle == other.Handle; - } - - bool IEnumerator::operator!=(const IEnumerator& other) const - { - return Handle != other.Handle; - } - - System::Object System::Collections::IEnumerator::GetCurrent() - { - auto returnValue = Plugin::SystemCollectionsIEnumeratorPropertyGetCurrent(Handle); - if (Plugin::unhandledCsharpException) - { - System::Exception* ex = Plugin::unhandledCsharpException; - Plugin::unhandledCsharpException = nullptr; - ex->ThrowReferenceToThis(); - delete ex; - } - return System::Object(Plugin::InternalUse::Only, returnValue); - } - - System::Boolean System::Collections::IEnumerator::MoveNext() - { - auto returnValue = Plugin::SystemCollectionsIEnumeratorMethodMoveNext(Handle); - if (Plugin::unhandledCsharpException) - { - System::Exception* ex = Plugin::unhandledCsharpException; - Plugin::unhandledCsharpException = nullptr; - ex->ThrowReferenceToThis(); - delete ex; - } - return returnValue; - } - } -} - -namespace System -{ - namespace Runtime - { - namespace Serialization - { - ISerializable::ISerializable(decltype(nullptr)) - { - } - - ISerializable::ISerializable(Plugin::InternalUse, int32_t handle) - { - Handle = handle; - if (handle) - { - Plugin::ReferenceManagedClass(handle); - } - } - - ISerializable::ISerializable(const ISerializable& other) - : ISerializable(Plugin::InternalUse::Only, other.Handle) - { - } - - ISerializable::ISerializable(ISerializable&& other) - : ISerializable(Plugin::InternalUse::Only, other.Handle) - { - other.Handle = 0; - } - - ISerializable::~ISerializable() - { - if (Handle) - { - Plugin::DereferenceManagedClass(Handle); - Handle = 0; - } - } - - ISerializable& ISerializable::operator=(const ISerializable& other) - { - if (this->Handle) - { - Plugin::DereferenceManagedClass(this->Handle); - } - this->Handle = other.Handle; - if (this->Handle) - { - Plugin::ReferenceManagedClass(this->Handle); - } - return *this; - } - - ISerializable& ISerializable::operator=(decltype(nullptr)) - { - if (Handle) - { - Plugin::DereferenceManagedClass(Handle); - Handle = 0; - } - return *this; - } - - ISerializable& ISerializable::operator=(ISerializable&& other) - { - if (Handle) - { - Plugin::DereferenceManagedClass(Handle); - } - Handle = other.Handle; - other.Handle = 0; - return *this; - } - - bool ISerializable::operator==(const ISerializable& other) const - { - return Handle == other.Handle; - } - - bool ISerializable::operator!=(const ISerializable& other) const - { - return Handle != other.Handle; - } - } - } -} - -namespace System -{ - namespace Runtime - { - namespace InteropServices - { - _Exception::_Exception(decltype(nullptr)) - { - } - - _Exception::_Exception(Plugin::InternalUse, int32_t handle) - { - Handle = handle; - if (handle) - { - Plugin::ReferenceManagedClass(handle); - } - } - - _Exception::_Exception(const _Exception& other) - : _Exception(Plugin::InternalUse::Only, other.Handle) - { - } - - _Exception::_Exception(_Exception&& other) - : _Exception(Plugin::InternalUse::Only, other.Handle) - { - other.Handle = 0; - } - - _Exception::~_Exception() - { - if (Handle) - { - Plugin::DereferenceManagedClass(Handle); - Handle = 0; - } - } - - _Exception& _Exception::operator=(const _Exception& other) - { - if (this->Handle) - { - Plugin::DereferenceManagedClass(this->Handle); - } - this->Handle = other.Handle; - if (this->Handle) - { - Plugin::ReferenceManagedClass(this->Handle); - } - return *this; - } - - _Exception& _Exception::operator=(decltype(nullptr)) - { - if (Handle) - { - Plugin::DereferenceManagedClass(Handle); - Handle = 0; - } - return *this; - } - - _Exception& _Exception::operator=(_Exception&& other) - { - if (Handle) - { - Plugin::DereferenceManagedClass(Handle); - } - Handle = other.Handle; - other.Handle = 0; - return *this; - } - - bool _Exception::operator==(const _Exception& other) const - { - return Handle == other.Handle; - } - - bool _Exception::operator!=(const _Exception& other) const - { - return Handle != other.Handle; - } - } - } -} - -namespace UnityEngine -{ - GameObject::GameObject(decltype(nullptr)) - : UnityEngine::Object(nullptr) - { - } - - GameObject::GameObject(Plugin::InternalUse, int32_t handle) - : UnityEngine::Object(nullptr) - { - Handle = handle; - if (handle) - { - Plugin::ReferenceManagedClass(handle); - } - } - - GameObject::GameObject(const GameObject& other) - : GameObject(Plugin::InternalUse::Only, other.Handle) - { - } - - GameObject::GameObject(GameObject&& other) - : GameObject(Plugin::InternalUse::Only, other.Handle) - { - other.Handle = 0; - } - - GameObject::~GameObject() - { - if (Handle) - { - Plugin::DereferenceManagedClass(Handle); - Handle = 0; - } - } - - GameObject& GameObject::operator=(const GameObject& other) - { - if (this->Handle) - { - Plugin::DereferenceManagedClass(this->Handle); - } - this->Handle = other.Handle; - if (this->Handle) - { - Plugin::ReferenceManagedClass(this->Handle); - } - return *this; - } - - GameObject& GameObject::operator=(decltype(nullptr)) - { - if (Handle) - { - Plugin::DereferenceManagedClass(Handle); - Handle = 0; - } - return *this; - } - - GameObject& GameObject::operator=(GameObject&& other) - { - if (Handle) - { - Plugin::DereferenceManagedClass(Handle); - } - Handle = other.Handle; - other.Handle = 0; - return *this; - } - - bool GameObject::operator==(const GameObject& other) const - { - return Handle == other.Handle; - } - - bool GameObject::operator!=(const GameObject& other) const - { - return Handle != other.Handle; - } - - template<> MyGame::BaseBallScript UnityEngine::GameObject::AddComponent() - { - auto returnValue = Plugin::UnityEngineGameObjectMethodAddComponentMyGameBaseBallScript(Handle); - if (Plugin::unhandledCsharpException) - { - System::Exception* ex = Plugin::unhandledCsharpException; - Plugin::unhandledCsharpException = nullptr; - ex->ThrowReferenceToThis(); - delete ex; - } - return MyGame::BaseBallScript(Plugin::InternalUse::Only, returnValue); - } - - UnityEngine::GameObject UnityEngine::GameObject::CreatePrimitive(UnityEngine::PrimitiveType type) - { - auto returnValue = Plugin::UnityEngineGameObjectMethodCreatePrimitiveUnityEnginePrimitiveType(type); - if (Plugin::unhandledCsharpException) - { - System::Exception* ex = Plugin::unhandledCsharpException; - Plugin::unhandledCsharpException = nullptr; - ex->ThrowReferenceToThis(); - delete ex; - } - return UnityEngine::GameObject(Plugin::InternalUse::Only, returnValue); - } -} - -namespace UnityEngine -{ - Debug::Debug(decltype(nullptr)) - { - } - - Debug::Debug(Plugin::InternalUse, int32_t handle) - { - Handle = handle; - if (handle) - { - Plugin::ReferenceManagedClass(handle); - } - } - - Debug::Debug(const Debug& other) - : Debug(Plugin::InternalUse::Only, other.Handle) - { - } - - Debug::Debug(Debug&& other) - : Debug(Plugin::InternalUse::Only, other.Handle) - { - other.Handle = 0; - } - - Debug::~Debug() - { - if (Handle) - { - Plugin::DereferenceManagedClass(Handle); - Handle = 0; - } - } - - Debug& Debug::operator=(const Debug& other) - { - if (this->Handle) - { - Plugin::DereferenceManagedClass(this->Handle); - } - this->Handle = other.Handle; - if (this->Handle) - { - Plugin::ReferenceManagedClass(this->Handle); - } - return *this; - } - - Debug& Debug::operator=(decltype(nullptr)) - { - if (Handle) - { - Plugin::DereferenceManagedClass(Handle); - Handle = 0; - } - return *this; - } - - Debug& Debug::operator=(Debug&& other) - { - if (Handle) - { - Plugin::DereferenceManagedClass(Handle); - } - Handle = other.Handle; - other.Handle = 0; - return *this; - } - - bool Debug::operator==(const Debug& other) const - { - return Handle == other.Handle; - } - - bool Debug::operator!=(const Debug& other) const - { - return Handle != other.Handle; - } - - void UnityEngine::Debug::Log(System::Object& message) - { - Plugin::UnityEngineDebugMethodLogSystemObject(message.Handle); - if (Plugin::unhandledCsharpException) - { - System::Exception* ex = Plugin::unhandledCsharpException; - Plugin::unhandledCsharpException = nullptr; - ex->ThrowReferenceToThis(); - delete ex; - } - } -} - -namespace UnityEngine -{ - Behaviour::Behaviour(decltype(nullptr)) - : UnityEngine::Object(nullptr) - , UnityEngine::Component(nullptr) - { - } - - Behaviour::Behaviour(Plugin::InternalUse, int32_t handle) - : UnityEngine::Object(nullptr) - , UnityEngine::Component(nullptr) - { - Handle = handle; - if (handle) - { - Plugin::ReferenceManagedClass(handle); - } - } - - Behaviour::Behaviour(const Behaviour& other) - : Behaviour(Plugin::InternalUse::Only, other.Handle) - { - } - - Behaviour::Behaviour(Behaviour&& other) - : Behaviour(Plugin::InternalUse::Only, other.Handle) - { - other.Handle = 0; - } - - Behaviour::~Behaviour() - { - if (Handle) - { - Plugin::DereferenceManagedClass(Handle); - Handle = 0; - } - } - - Behaviour& Behaviour::operator=(const Behaviour& other) - { - if (this->Handle) - { - Plugin::DereferenceManagedClass(this->Handle); - } - this->Handle = other.Handle; - if (this->Handle) - { - Plugin::ReferenceManagedClass(this->Handle); - } - return *this; - } - - Behaviour& Behaviour::operator=(decltype(nullptr)) - { - if (Handle) - { - Plugin::DereferenceManagedClass(Handle); - Handle = 0; - } - return *this; - } - - Behaviour& Behaviour::operator=(Behaviour&& other) - { - if (Handle) - { - Plugin::DereferenceManagedClass(Handle); - } - Handle = other.Handle; - other.Handle = 0; - return *this; - } - - bool Behaviour::operator==(const Behaviour& other) const - { - return Handle == other.Handle; - } - - bool Behaviour::operator!=(const Behaviour& other) const - { - return Handle != other.Handle; - } -} - -namespace UnityEngine -{ - MonoBehaviour::MonoBehaviour(decltype(nullptr)) - : UnityEngine::Object(nullptr) - , UnityEngine::Component(nullptr) - , UnityEngine::Behaviour(nullptr) - { - } - - MonoBehaviour::MonoBehaviour(Plugin::InternalUse, int32_t handle) - : UnityEngine::Object(nullptr) - , UnityEngine::Component(nullptr) - , UnityEngine::Behaviour(nullptr) - { - Handle = handle; - if (handle) - { - Plugin::ReferenceManagedClass(handle); - } - } - - MonoBehaviour::MonoBehaviour(const MonoBehaviour& other) - : MonoBehaviour(Plugin::InternalUse::Only, other.Handle) - { - } - - MonoBehaviour::MonoBehaviour(MonoBehaviour&& other) - : MonoBehaviour(Plugin::InternalUse::Only, other.Handle) - { - other.Handle = 0; - } - - MonoBehaviour::~MonoBehaviour() - { - if (Handle) - { - Plugin::DereferenceManagedClass(Handle); - Handle = 0; - } - } - - MonoBehaviour& MonoBehaviour::operator=(const MonoBehaviour& other) - { - if (this->Handle) - { - Plugin::DereferenceManagedClass(this->Handle); - } - this->Handle = other.Handle; - if (this->Handle) - { - Plugin::ReferenceManagedClass(this->Handle); - } - return *this; - } - - MonoBehaviour& MonoBehaviour::operator=(decltype(nullptr)) - { - if (Handle) - { - Plugin::DereferenceManagedClass(Handle); - Handle = 0; - } - return *this; - } - - MonoBehaviour& MonoBehaviour::operator=(MonoBehaviour&& other) - { - if (Handle) - { - Plugin::DereferenceManagedClass(Handle); - } - Handle = other.Handle; - other.Handle = 0; - return *this; - } - - bool MonoBehaviour::operator==(const MonoBehaviour& other) const - { - return Handle == other.Handle; - } - - bool MonoBehaviour::operator!=(const MonoBehaviour& other) const - { - return Handle != other.Handle; - } - - UnityEngine::Transform UnityEngine::MonoBehaviour::GetTransform() - { - auto returnValue = Plugin::UnityEngineMonoBehaviourPropertyGetTransform(Handle); - if (Plugin::unhandledCsharpException) - { - System::Exception* ex = Plugin::unhandledCsharpException; - Plugin::unhandledCsharpException = nullptr; - ex->ThrowReferenceToThis(); - delete ex; - } - return UnityEngine::Transform(Plugin::InternalUse::Only, returnValue); - } -} - -namespace System -{ - Exception::Exception(decltype(nullptr)) - : System::Runtime::InteropServices::_Exception(nullptr) - , System::Runtime::Serialization::ISerializable(nullptr) - { - } - - Exception::Exception(Plugin::InternalUse, int32_t handle) - : System::Runtime::InteropServices::_Exception(nullptr) - , System::Runtime::Serialization::ISerializable(nullptr) - { - Handle = handle; - if (handle) - { - Plugin::ReferenceManagedClass(handle); - } - } - - Exception::Exception(const Exception& other) - : Exception(Plugin::InternalUse::Only, other.Handle) - { - } - - Exception::Exception(Exception&& other) - : Exception(Plugin::InternalUse::Only, other.Handle) - { - other.Handle = 0; - } - - Exception::~Exception() - { - if (Handle) - { - Plugin::DereferenceManagedClass(Handle); - Handle = 0; - } - } - - Exception& Exception::operator=(const Exception& other) - { - if (this->Handle) - { - Plugin::DereferenceManagedClass(this->Handle); - } - this->Handle = other.Handle; - if (this->Handle) - { - Plugin::ReferenceManagedClass(this->Handle); - } - return *this; - } - - Exception& Exception::operator=(decltype(nullptr)) - { - if (Handle) - { - Plugin::DereferenceManagedClass(Handle); - Handle = 0; - } - return *this; - } - - Exception& Exception::operator=(Exception&& other) - { - if (Handle) - { - Plugin::DereferenceManagedClass(Handle); - } - Handle = other.Handle; - other.Handle = 0; - return *this; - } - - bool Exception::operator==(const Exception& other) const - { - return Handle == other.Handle; - } - - bool Exception::operator!=(const Exception& other) const - { - return Handle != other.Handle; - } - - System::Exception::Exception(System::String& message) - : System::Runtime::InteropServices::_Exception(nullptr) - , System::Runtime::Serialization::ISerializable(nullptr) - { - auto returnValue = Plugin::SystemExceptionConstructorSystemString(message.Handle); - if (Plugin::unhandledCsharpException) - { - System::Exception* ex = Plugin::unhandledCsharpException; - Plugin::unhandledCsharpException = nullptr; - ex->ThrowReferenceToThis(); - delete ex; - } - Handle = returnValue; - if (returnValue) - { - Plugin::ReferenceManagedClass(returnValue); - } - } -} - -namespace System -{ - SystemException::SystemException(decltype(nullptr)) - : System::Runtime::InteropServices::_Exception(nullptr) - , System::Runtime::Serialization::ISerializable(nullptr) - , System::Exception(nullptr) - { - } - - SystemException::SystemException(Plugin::InternalUse, int32_t handle) - : System::Runtime::InteropServices::_Exception(nullptr) - , System::Runtime::Serialization::ISerializable(nullptr) - , System::Exception(nullptr) - { - Handle = handle; - if (handle) - { - Plugin::ReferenceManagedClass(handle); - } - } - - SystemException::SystemException(const SystemException& other) - : SystemException(Plugin::InternalUse::Only, other.Handle) - { - } - - SystemException::SystemException(SystemException&& other) - : SystemException(Plugin::InternalUse::Only, other.Handle) - { - other.Handle = 0; - } - - SystemException::~SystemException() - { - if (Handle) - { - Plugin::DereferenceManagedClass(Handle); - Handle = 0; - } - } - - SystemException& SystemException::operator=(const SystemException& other) - { - if (this->Handle) - { - Plugin::DereferenceManagedClass(this->Handle); - } - this->Handle = other.Handle; - if (this->Handle) - { - Plugin::ReferenceManagedClass(this->Handle); - } - return *this; - } - - SystemException& SystemException::operator=(decltype(nullptr)) - { - if (Handle) - { - Plugin::DereferenceManagedClass(Handle); - Handle = 0; - } - return *this; - } - - SystemException& SystemException::operator=(SystemException&& other) - { - if (Handle) - { - Plugin::DereferenceManagedClass(Handle); - } - Handle = other.Handle; - other.Handle = 0; - return *this; - } - - bool SystemException::operator==(const SystemException& other) const - { - return Handle == other.Handle; - } - - bool SystemException::operator!=(const SystemException& other) const - { - return Handle != other.Handle; - } -} - -namespace System -{ - NullReferenceException::NullReferenceException(decltype(nullptr)) - : System::Runtime::InteropServices::_Exception(nullptr) - , System::Runtime::Serialization::ISerializable(nullptr) - , System::Exception(nullptr) - , System::SystemException(nullptr) - { - } - - NullReferenceException::NullReferenceException(Plugin::InternalUse, int32_t handle) - : System::Runtime::InteropServices::_Exception(nullptr) - , System::Runtime::Serialization::ISerializable(nullptr) - , System::Exception(nullptr) - , System::SystemException(nullptr) - { - Handle = handle; - if (handle) - { - Plugin::ReferenceManagedClass(handle); - } - } - - NullReferenceException::NullReferenceException(const NullReferenceException& other) - : NullReferenceException(Plugin::InternalUse::Only, other.Handle) - { - } - - NullReferenceException::NullReferenceException(NullReferenceException&& other) - : NullReferenceException(Plugin::InternalUse::Only, other.Handle) - { - other.Handle = 0; - } - - NullReferenceException::~NullReferenceException() - { - if (Handle) - { - Plugin::DereferenceManagedClass(Handle); - Handle = 0; - } - } - - NullReferenceException& NullReferenceException::operator=(const NullReferenceException& other) - { - if (this->Handle) - { - Plugin::DereferenceManagedClass(this->Handle); - } - this->Handle = other.Handle; - if (this->Handle) - { - Plugin::ReferenceManagedClass(this->Handle); - } - return *this; - } - - NullReferenceException& NullReferenceException::operator=(decltype(nullptr)) - { - if (Handle) - { - Plugin::DereferenceManagedClass(Handle); - Handle = 0; - } - return *this; - } - - NullReferenceException& NullReferenceException::operator=(NullReferenceException&& other) - { - if (Handle) - { - Plugin::DereferenceManagedClass(Handle); - } - Handle = other.Handle; - other.Handle = 0; - return *this; - } - - bool NullReferenceException::operator==(const NullReferenceException& other) const - { - return Handle == other.Handle; - } - - bool NullReferenceException::operator!=(const NullReferenceException& other) const - { - return Handle != other.Handle; - } -} - -namespace UnityEngine -{ - PrimitiveType::PrimitiveType(int32_t value) - : Value(value) - { - } - - UnityEngine::PrimitiveType::operator int32_t() const - { - return Value; - } - - bool UnityEngine::PrimitiveType::operator==(PrimitiveType other) - { - return Value == other.Value; - } - - bool UnityEngine::PrimitiveType::operator!=(PrimitiveType other) - { - return Value != other.Value; - } - - UnityEngine::PrimitiveType::operator System::Enum() - { - int32_t handle = Plugin::BoxPrimitiveType(*this); - if (Plugin::unhandledCsharpException) - { - System::Exception* ex = Plugin::unhandledCsharpException; - Plugin::unhandledCsharpException = nullptr; - ex->ThrowReferenceToThis(); - delete ex; - } - if (handle) - { - Plugin::ReferenceManagedClass(handle); - return System::Enum(Plugin::InternalUse::Only, handle); - } - return nullptr; - } - - UnityEngine::PrimitiveType::operator System::ValueType() - { - int32_t handle = Plugin::BoxPrimitiveType(*this); - if (Plugin::unhandledCsharpException) - { - System::Exception* ex = Plugin::unhandledCsharpException; - Plugin::unhandledCsharpException = nullptr; - ex->ThrowReferenceToThis(); - delete ex; - } - if (handle) - { - Plugin::ReferenceManagedClass(handle); - return System::ValueType(Plugin::InternalUse::Only, handle); - } - return nullptr; - } - - UnityEngine::PrimitiveType::operator System::Object() - { - int32_t handle = Plugin::BoxPrimitiveType(*this); - if (Plugin::unhandledCsharpException) - { - System::Exception* ex = Plugin::unhandledCsharpException; - Plugin::unhandledCsharpException = nullptr; - ex->ThrowReferenceToThis(); - delete ex; - } - if (handle) - { - Plugin::ReferenceManagedClass(handle); - return System::Object(Plugin::InternalUse::Only, handle); - } - return nullptr; - } - - UnityEngine::PrimitiveType::operator System::IComparable() - { - int32_t handle = Plugin::BoxPrimitiveType(*this); - if (Plugin::unhandledCsharpException) - { - System::Exception* ex = Plugin::unhandledCsharpException; - Plugin::unhandledCsharpException = nullptr; - ex->ThrowReferenceToThis(); - delete ex; - } - if (handle) - { - Plugin::ReferenceManagedClass(handle); - return System::IComparable(Plugin::InternalUse::Only, handle); - } - return nullptr; - } - - UnityEngine::PrimitiveType::operator System::IConvertible() - { - int32_t handle = Plugin::BoxPrimitiveType(*this); - if (Plugin::unhandledCsharpException) - { - System::Exception* ex = Plugin::unhandledCsharpException; - Plugin::unhandledCsharpException = nullptr; - ex->ThrowReferenceToThis(); - delete ex; - } - if (handle) - { - Plugin::ReferenceManagedClass(handle); - return System::IConvertible(Plugin::InternalUse::Only, handle); - } - return nullptr; - } - - UnityEngine::PrimitiveType::operator System::IFormattable() - { - int32_t handle = Plugin::BoxPrimitiveType(*this); - if (Plugin::unhandledCsharpException) - { - System::Exception* ex = Plugin::unhandledCsharpException; - Plugin::unhandledCsharpException = nullptr; - ex->ThrowReferenceToThis(); - delete ex; - } - if (handle) - { - Plugin::ReferenceManagedClass(handle); - return System::IFormattable(Plugin::InternalUse::Only, handle); - } - return nullptr; - } - -} -const UnityEngine::PrimitiveType UnityEngine::PrimitiveType::Sphere(0); -const UnityEngine::PrimitiveType UnityEngine::PrimitiveType::Capsule(1); -const UnityEngine::PrimitiveType UnityEngine::PrimitiveType::Cylinder(2); -const UnityEngine::PrimitiveType UnityEngine::PrimitiveType::Cube(3); -const UnityEngine::PrimitiveType UnityEngine::PrimitiveType::Plane(4); -const UnityEngine::PrimitiveType UnityEngine::PrimitiveType::Quad(5); - -namespace System -{ - System::Object::operator UnityEngine::PrimitiveType() - { - UnityEngine::PrimitiveType returnVal(Plugin::UnboxPrimitiveType(Handle)); - if (Plugin::unhandledCsharpException) - { - System::Exception* ex = Plugin::unhandledCsharpException; - Plugin::unhandledCsharpException = nullptr; - ex->ThrowReferenceToThis(); - delete ex; - } - return returnVal; - } -} - -namespace UnityEngine -{ - Time::Time(decltype(nullptr)) - { - } - - Time::Time(Plugin::InternalUse, int32_t handle) - { - Handle = handle; - if (handle) - { - Plugin::ReferenceManagedClass(handle); - } - } - - Time::Time(const Time& other) - : Time(Plugin::InternalUse::Only, other.Handle) - { - } - - Time::Time(Time&& other) - : Time(Plugin::InternalUse::Only, other.Handle) - { - other.Handle = 0; - } - - Time::~Time() - { - if (Handle) - { - Plugin::DereferenceManagedClass(Handle); - Handle = 0; - } - } - - Time& Time::operator=(const Time& other) - { - if (this->Handle) - { - Plugin::DereferenceManagedClass(this->Handle); - } - this->Handle = other.Handle; - if (this->Handle) - { - Plugin::ReferenceManagedClass(this->Handle); - } - return *this; - } - - Time& Time::operator=(decltype(nullptr)) - { - if (Handle) - { - Plugin::DereferenceManagedClass(Handle); - Handle = 0; - } - return *this; - } - - Time& Time::operator=(Time&& other) - { - if (Handle) - { - Plugin::DereferenceManagedClass(Handle); - } - Handle = other.Handle; - other.Handle = 0; - return *this; - } - - bool Time::operator==(const Time& other) const - { - return Handle == other.Handle; - } - - bool Time::operator!=(const Time& other) const - { - return Handle != other.Handle; - } - - System::Single UnityEngine::Time::GetDeltaTime() - { - auto returnValue = Plugin::UnityEngineTimePropertyGetDeltaTime(); - if (Plugin::unhandledCsharpException) - { - System::Exception* ex = Plugin::unhandledCsharpException; - Plugin::unhandledCsharpException = nullptr; - ex->ThrowReferenceToThis(); - delete ex; - } - return returnValue; - } -} - -namespace MyGame -{ - AbstractBaseBallScript::AbstractBaseBallScript(decltype(nullptr)) - : UnityEngine::Object(nullptr) - , UnityEngine::Component(nullptr) - , UnityEngine::Behaviour(nullptr) - , UnityEngine::MonoBehaviour(nullptr) - { - } - - AbstractBaseBallScript::AbstractBaseBallScript(Plugin::InternalUse, int32_t handle) - : UnityEngine::Object(nullptr) - , UnityEngine::Component(nullptr) - , UnityEngine::Behaviour(nullptr) - , UnityEngine::MonoBehaviour(nullptr) - { - Handle = handle; - if (handle) - { - Plugin::ReferenceManagedClass(handle); - } - } - - AbstractBaseBallScript::AbstractBaseBallScript(const AbstractBaseBallScript& other) - : AbstractBaseBallScript(Plugin::InternalUse::Only, other.Handle) - { - } - - AbstractBaseBallScript::AbstractBaseBallScript(AbstractBaseBallScript&& other) - : AbstractBaseBallScript(Plugin::InternalUse::Only, other.Handle) - { - other.Handle = 0; - } - - AbstractBaseBallScript::~AbstractBaseBallScript() - { - if (Handle) - { - Plugin::DereferenceManagedClass(Handle); - Handle = 0; - } - } - - AbstractBaseBallScript& AbstractBaseBallScript::operator=(const AbstractBaseBallScript& other) - { - if (this->Handle) - { - Plugin::DereferenceManagedClass(this->Handle); - } - this->Handle = other.Handle; - if (this->Handle) - { - Plugin::ReferenceManagedClass(this->Handle); - } - return *this; - } - - AbstractBaseBallScript& AbstractBaseBallScript::operator=(decltype(nullptr)) - { - if (Handle) - { - Plugin::DereferenceManagedClass(Handle); - Handle = 0; - } - return *this; - } - - AbstractBaseBallScript& AbstractBaseBallScript::operator=(AbstractBaseBallScript&& other) - { - if (Handle) - { - Plugin::DereferenceManagedClass(Handle); - } - Handle = other.Handle; - other.Handle = 0; - return *this; - } - - bool AbstractBaseBallScript::operator==(const AbstractBaseBallScript& other) const - { - return Handle == other.Handle; - } - - bool AbstractBaseBallScript::operator!=(const AbstractBaseBallScript& other) const - { - return Handle != other.Handle; - } -} - -namespace MyGame -{ - MyGame::BaseBallScript::BaseBallScript() - : UnityEngine::Object(nullptr) - , UnityEngine::Component(nullptr) - , UnityEngine::Behaviour(nullptr) - , UnityEngine::MonoBehaviour(nullptr) - , MyGame::AbstractBaseBallScript(nullptr) - { - CppHandle = Plugin::StoreBaseBallScript(this); - System::Int32* handle = (System::Int32*)&Handle; - int32_t cppHandle = CppHandle; - Plugin::BaseBallScriptConstructor(cppHandle, &handle->Value); - if (Plugin::unhandledCsharpException) - { - System::Exception* ex = Plugin::unhandledCsharpException; - Plugin::unhandledCsharpException = nullptr; - ex->ThrowReferenceToThis(); - delete ex; - } - if (Handle) - { - Plugin::ReferenceManagedClass(Handle); - } - else - { - Plugin::RemoveBaseBallScript(CppHandle); - CppHandle = 0; - } - if (Plugin::unhandledCsharpException) - { - System::Exception* ex = Plugin::unhandledCsharpException; - Plugin::unhandledCsharpException = nullptr; - ex->ThrowReferenceToThis(); - delete ex; - } - } - - BaseBallScript::BaseBallScript(decltype(nullptr)) - : UnityEngine::Object(nullptr) - , UnityEngine::Component(nullptr) - , UnityEngine::Behaviour(nullptr) - , UnityEngine::MonoBehaviour(nullptr) - , MyGame::AbstractBaseBallScript(nullptr) - { - CppHandle = Plugin::StoreBaseBallScript(this); - } - - MyGame::BaseBallScript::BaseBallScript(const MyGame::BaseBallScript& other) - : UnityEngine::Object(nullptr) - , UnityEngine::Component(nullptr) - , UnityEngine::Behaviour(nullptr) - , UnityEngine::MonoBehaviour(nullptr) - , MyGame::AbstractBaseBallScript(nullptr) - { - Handle = other.Handle; - CppHandle = Plugin::StoreBaseBallScript(this); - if (Handle) - { - Plugin::ReferenceManagedClass(Handle); - } - } - - MyGame::BaseBallScript::BaseBallScript(MyGame::BaseBallScript&& other) - : UnityEngine::Object(nullptr) - , UnityEngine::Component(nullptr) - , UnityEngine::Behaviour(nullptr) - , UnityEngine::MonoBehaviour(nullptr) - , MyGame::AbstractBaseBallScript(nullptr) - { - Handle = other.Handle; - CppHandle = other.CppHandle; - other.Handle = 0; - other.CppHandle = 0; - } - - MyGame::BaseBallScript::BaseBallScript(Plugin::InternalUse, int32_t handle) - : UnityEngine::Object(nullptr) - , UnityEngine::Component(nullptr) - , UnityEngine::Behaviour(nullptr) - , UnityEngine::MonoBehaviour(nullptr) - , MyGame::AbstractBaseBallScript(nullptr) - { - Handle = handle; - CppHandle = Plugin::StoreBaseBallScript(this); - if (Handle) - { - Plugin::ReferenceManagedClass(Handle); - } - } - - MyGame::BaseBallScript::~BaseBallScript() - { - Plugin::RemoveWholeBaseBallScript(this); - Plugin::RemoveBaseBallScript(CppHandle); - CppHandle = 0; - if (Handle) - { - int32_t handle = Handle; - Handle = 0; - if (Plugin::DereferenceManagedClassNoRelease(handle)) - { - Plugin::ReleaseBaseBallScript(handle); - if (Plugin::unhandledCsharpException) - { - System::Exception* ex = Plugin::unhandledCsharpException; - Plugin::unhandledCsharpException = nullptr; - ex->ThrowReferenceToThis(); - delete ex; - } - } - } - } - - MyGame::BaseBallScript& MyGame::BaseBallScript::operator=(const MyGame::BaseBallScript& other) - { - if (this->Handle) - { - Plugin::DereferenceManagedClass(this->Handle); - } - this->Handle = other.Handle; - if (this->Handle) - { - Plugin::ReferenceManagedClass(this->Handle); - } - return *this; - } - - MyGame::BaseBallScript& MyGame::BaseBallScript::operator=(decltype(nullptr)) - { - if (Handle) - { - int32_t handle = Handle; - Handle = 0; - if (Plugin::DereferenceManagedClassNoRelease(handle)) - { - Plugin::ReleaseBaseBallScript(handle); - if (Plugin::unhandledCsharpException) - { - System::Exception* ex = Plugin::unhandledCsharpException; - Plugin::unhandledCsharpException = nullptr; - ex->ThrowReferenceToThis(); - delete ex; - } - } - } - Handle = 0; - return *this; - } - - MyGame::BaseBallScript& MyGame::BaseBallScript::operator=(MyGame::BaseBallScript&& other) - { - Plugin::RemoveBaseBallScript(CppHandle); - CppHandle = 0; - if (Handle) - { - int32_t handle = Handle; - Handle = 0; - if (Plugin::DereferenceManagedClassNoRelease(handle)) - { - Plugin::ReleaseBaseBallScript(handle); - if (Plugin::unhandledCsharpException) - { - System::Exception* ex = Plugin::unhandledCsharpException; - Plugin::unhandledCsharpException = nullptr; - ex->ThrowReferenceToThis(); - delete ex; - } - } - } - Handle = other.Handle; - other.Handle = 0; - return *this; - } - - bool MyGame::BaseBallScript::operator==(const MyGame::BaseBallScript& other) const - { - return Handle == other.Handle; - } - - bool MyGame::BaseBallScript::operator!=(const MyGame::BaseBallScript& other) const - { - return Handle != other.Handle; - } - - DLLEXPORT int32_t NewBaseBallScript(int32_t handle) - { - MyGame::BaseBallScript* memory = Plugin::StoreWholeBaseBallScript(); - MyGame::BallScript* thiz = new (memory) MyGame::BallScript(Plugin::InternalUse::Only, handle); - return thiz->CppHandle; - } - - DLLEXPORT void DestroyBaseBallScript(int32_t cppHandle) - { - MyGame::BaseBallScript* instance = Plugin::GetBaseBallScript(cppHandle); - instance->~BaseBallScript(); - } - - void MyGame::BaseBallScript::Update() - { - } - - DLLEXPORT void MyGameAbstractBaseBallScriptUpdate(int32_t cppHandle) - { - try - { - Plugin::GetBaseBallScript(cppHandle)->Update(); - } - catch (System::Exception ex) - { - Plugin::SetException(ex.Handle); - } - catch (...) - { - System::String msg = "Unhandled exception invoking MyGame::AbstractBaseBallScript"; - System::Exception ex(msg); - Plugin::SetException(ex.Handle); - } - } -} - -namespace System -{ - System::Object::operator System::Boolean() - { - System::Boolean returnVal(Plugin::UnboxBoolean(Handle)); - if (Plugin::unhandledCsharpException) - { - System::Exception* ex = Plugin::unhandledCsharpException; - Plugin::unhandledCsharpException = nullptr; - ex->ThrowReferenceToThis(); - delete ex; - } - return returnVal; - } -} - -namespace System -{ - System::Object::operator System::SByte() - { - System::SByte returnVal(Plugin::UnboxSByte(Handle)); - if (Plugin::unhandledCsharpException) - { - System::Exception* ex = Plugin::unhandledCsharpException; - Plugin::unhandledCsharpException = nullptr; - ex->ThrowReferenceToThis(); - delete ex; - } - return returnVal; - } -} - -namespace System -{ - System::Object::operator System::Byte() - { - System::Byte returnVal(Plugin::UnboxByte(Handle)); - if (Plugin::unhandledCsharpException) - { - System::Exception* ex = Plugin::unhandledCsharpException; - Plugin::unhandledCsharpException = nullptr; - ex->ThrowReferenceToThis(); - delete ex; - } - return returnVal; - } -} - -namespace System -{ - System::Object::operator System::Int16() - { - System::Int16 returnVal(Plugin::UnboxInt16(Handle)); - if (Plugin::unhandledCsharpException) - { - System::Exception* ex = Plugin::unhandledCsharpException; - Plugin::unhandledCsharpException = nullptr; - ex->ThrowReferenceToThis(); - delete ex; - } - return returnVal; - } -} - -namespace System -{ - System::Object::operator System::UInt16() - { - System::UInt16 returnVal(Plugin::UnboxUInt16(Handle)); - if (Plugin::unhandledCsharpException) - { - System::Exception* ex = Plugin::unhandledCsharpException; - Plugin::unhandledCsharpException = nullptr; - ex->ThrowReferenceToThis(); - delete ex; - } - return returnVal; - } -} - -namespace System -{ - System::Object::operator System::Int32() - { - System::Int32 returnVal(Plugin::UnboxInt32(Handle)); - if (Plugin::unhandledCsharpException) - { - System::Exception* ex = Plugin::unhandledCsharpException; - Plugin::unhandledCsharpException = nullptr; - ex->ThrowReferenceToThis(); - delete ex; - } - return returnVal; - } -} - -namespace System -{ - System::Object::operator System::UInt32() - { - System::UInt32 returnVal(Plugin::UnboxUInt32(Handle)); - if (Plugin::unhandledCsharpException) - { - System::Exception* ex = Plugin::unhandledCsharpException; - Plugin::unhandledCsharpException = nullptr; - ex->ThrowReferenceToThis(); - delete ex; - } - return returnVal; - } -} - -namespace System -{ - System::Object::operator System::Int64() - { - System::Int64 returnVal(Plugin::UnboxInt64(Handle)); - if (Plugin::unhandledCsharpException) - { - System::Exception* ex = Plugin::unhandledCsharpException; - Plugin::unhandledCsharpException = nullptr; - ex->ThrowReferenceToThis(); - delete ex; - } - return returnVal; - } -} - -namespace System -{ - System::Object::operator System::UInt64() - { - System::UInt64 returnVal(Plugin::UnboxUInt64(Handle)); - if (Plugin::unhandledCsharpException) - { - System::Exception* ex = Plugin::unhandledCsharpException; - Plugin::unhandledCsharpException = nullptr; - ex->ThrowReferenceToThis(); - delete ex; - } - return returnVal; - } -} - -namespace System -{ - System::Object::operator System::Char() - { - System::Char returnVal(Plugin::UnboxChar(Handle)); - if (Plugin::unhandledCsharpException) - { - System::Exception* ex = Plugin::unhandledCsharpException; - Plugin::unhandledCsharpException = nullptr; - ex->ThrowReferenceToThis(); - delete ex; - } - return returnVal; - } -} - -namespace System -{ - System::Object::operator System::Single() - { - System::Single returnVal(Plugin::UnboxSingle(Handle)); - if (Plugin::unhandledCsharpException) - { - System::Exception* ex = Plugin::unhandledCsharpException; - Plugin::unhandledCsharpException = nullptr; - ex->ThrowReferenceToThis(); - delete ex; - } - return returnVal; - } -} - -namespace System -{ - System::Object::operator System::Double() - { - System::Double returnVal(Plugin::UnboxDouble(Handle)); - if (Plugin::unhandledCsharpException) - { - System::Exception* ex = Plugin::unhandledCsharpException; - Plugin::unhandledCsharpException = nullptr; - ex->ThrowReferenceToThis(); - delete ex; - } - return returnVal; - } -} - -namespace System -{ - struct NullReferenceExceptionThrower : System::NullReferenceException - { - NullReferenceExceptionThrower(int32_t handle) - : System::Runtime::InteropServices::_Exception(nullptr) - , System::Runtime::Serialization::ISerializable(nullptr) - , System::Exception(nullptr) - , System::SystemException(nullptr) - , System::NullReferenceException(Plugin::InternalUse::Only, handle) - { - } - - virtual void ThrowReferenceToThis() - { - throw *this; - } - }; -} - -DLLEXPORT void SetCsharpExceptionSystemNullReferenceException(int32_t handle) -{ - delete Plugin::unhandledCsharpException; - Plugin::unhandledCsharpException = new System::NullReferenceExceptionThrower(handle); -} -/*END METHOD DEFINITIONS*/ - -//////////////////////////////////////////////////////////////// -// App-specific functions for this file to call -//////////////////////////////////////////////////////////////// - -// Called when the plugin is initialized -extern void PluginMain( - void* memory, - int32_t memorySize, - bool isFirstBoot); - -//////////////////////////////////////////////////////////////// -// C++ functions for C# to call -//////////////////////////////////////////////////////////////// - -enum class InitMode : uint8_t -{ - FirstBoot, - Reload -}; - -// Init the plugin -DLLEXPORT void Init( - uint8_t* memory, - int32_t memorySize, - InitMode initMode) -{ - uint8_t* curMemory = memory; - - // Read fixed parameters - Plugin::ReleaseObject = *(void (**)(int32_t handle))curMemory; - curMemory += sizeof(Plugin::ReleaseObject); - Plugin::StringNew = *(int32_t (**)(const char*))curMemory; - curMemory += sizeof(Plugin::StringNew); - Plugin::SetException = *(void (**)(int32_t))curMemory; - curMemory += sizeof(Plugin::SetException); - Plugin::ArrayGetLength = *(int32_t (**)(int32_t))curMemory; - curMemory += sizeof(Plugin::ArrayGetLength); - Plugin::EnumerableGetEnumerator = *(int32_t (**)(int32_t))curMemory; - curMemory += sizeof(Plugin::EnumerableGetEnumerator); - - // Read generated parameters - int32_t maxManagedObjects = *(int32_t*)curMemory; - curMemory += sizeof(int32_t); - /*BEGIN INIT BODY PARAMETER READS*/ - Plugin::ReleaseSystemDecimal = *(void (**)(int32_t handle))curMemory; - curMemory += sizeof(Plugin::ReleaseSystemDecimal); - Plugin::SystemDecimalConstructorSystemDouble = *(int32_t (**)(double value))curMemory; - curMemory += sizeof(Plugin::SystemDecimalConstructorSystemDouble); - Plugin::SystemDecimalConstructorSystemUInt64 = *(int32_t (**)(uint64_t value))curMemory; - curMemory += sizeof(Plugin::SystemDecimalConstructorSystemUInt64); - Plugin::BoxDecimal = *(int32_t (**)(int32_t valHandle))curMemory; - curMemory += sizeof(Plugin::BoxDecimal); - Plugin::UnboxDecimal = *(int32_t (**)(int32_t valHandle))curMemory; - curMemory += sizeof(Plugin::UnboxDecimal); - Plugin::UnityEngineVector3ConstructorSystemSingle_SystemSingle_SystemSingle = *(UnityEngine::Vector3 (**)(float x, float y, float z))curMemory; - curMemory += sizeof(Plugin::UnityEngineVector3ConstructorSystemSingle_SystemSingle_SystemSingle); - Plugin::UnityEngineVector3Methodop_AdditionUnityEngineVector3_UnityEngineVector3 = *(UnityEngine::Vector3 (**)(UnityEngine::Vector3& a, UnityEngine::Vector3& b))curMemory; - curMemory += sizeof(Plugin::UnityEngineVector3Methodop_AdditionUnityEngineVector3_UnityEngineVector3); - Plugin::BoxVector3 = *(int32_t (**)(UnityEngine::Vector3& val))curMemory; - curMemory += sizeof(Plugin::BoxVector3); - Plugin::UnboxVector3 = *(UnityEngine::Vector3 (**)(int32_t valHandle))curMemory; - curMemory += sizeof(Plugin::UnboxVector3); - Plugin::UnityEngineObjectPropertyGetName = *(int32_t (**)(int32_t thisHandle))curMemory; - curMemory += sizeof(Plugin::UnityEngineObjectPropertyGetName); - Plugin::UnityEngineObjectPropertySetName = *(void (**)(int32_t thisHandle, int32_t valueHandle))curMemory; - curMemory += sizeof(Plugin::UnityEngineObjectPropertySetName); - Plugin::UnityEngineComponentPropertyGetTransform = *(int32_t (**)(int32_t thisHandle))curMemory; - curMemory += sizeof(Plugin::UnityEngineComponentPropertyGetTransform); - Plugin::UnityEngineTransformPropertyGetPosition = *(UnityEngine::Vector3 (**)(int32_t thisHandle))curMemory; - curMemory += sizeof(Plugin::UnityEngineTransformPropertyGetPosition); - Plugin::UnityEngineTransformPropertySetPosition = *(void (**)(int32_t thisHandle, UnityEngine::Vector3& value))curMemory; - curMemory += sizeof(Plugin::UnityEngineTransformPropertySetPosition); - Plugin::SystemCollectionsIEnumeratorPropertyGetCurrent = *(int32_t (**)(int32_t thisHandle))curMemory; - curMemory += sizeof(Plugin::SystemCollectionsIEnumeratorPropertyGetCurrent); - Plugin::SystemCollectionsIEnumeratorMethodMoveNext = *(int32_t (**)(int32_t thisHandle))curMemory; - curMemory += sizeof(Plugin::SystemCollectionsIEnumeratorMethodMoveNext); - Plugin::UnityEngineGameObjectMethodAddComponentMyGameBaseBallScript = *(int32_t (**)(int32_t thisHandle))curMemory; - curMemory += sizeof(Plugin::UnityEngineGameObjectMethodAddComponentMyGameBaseBallScript); - Plugin::UnityEngineGameObjectMethodCreatePrimitiveUnityEnginePrimitiveType = *(int32_t (**)(UnityEngine::PrimitiveType type))curMemory; - curMemory += sizeof(Plugin::UnityEngineGameObjectMethodCreatePrimitiveUnityEnginePrimitiveType); - Plugin::UnityEngineDebugMethodLogSystemObject = *(void (**)(int32_t messageHandle))curMemory; - curMemory += sizeof(Plugin::UnityEngineDebugMethodLogSystemObject); - Plugin::UnityEngineMonoBehaviourPropertyGetTransform = *(int32_t (**)(int32_t thisHandle))curMemory; - curMemory += sizeof(Plugin::UnityEngineMonoBehaviourPropertyGetTransform); - Plugin::SystemExceptionConstructorSystemString = *(int32_t (**)(int32_t messageHandle))curMemory; - curMemory += sizeof(Plugin::SystemExceptionConstructorSystemString); - Plugin::BoxPrimitiveType = *(int32_t (**)(UnityEngine::PrimitiveType val))curMemory; - curMemory += sizeof(Plugin::BoxPrimitiveType); - Plugin::UnboxPrimitiveType = *(UnityEngine::PrimitiveType (**)(int32_t valHandle))curMemory; - curMemory += sizeof(Plugin::UnboxPrimitiveType); - Plugin::UnityEngineTimePropertyGetDeltaTime = *(float (**)())curMemory; - curMemory += sizeof(Plugin::UnityEngineTimePropertyGetDeltaTime); - Plugin::ReleaseBaseBallScript = *(void (**)(int32_t handle))curMemory; - curMemory += sizeof(Plugin::ReleaseBaseBallScript); - Plugin::BaseBallScriptConstructor = *(void (**)(int32_t cppHandle, int32_t* handle))curMemory; - curMemory += sizeof(Plugin::BaseBallScriptConstructor); - Plugin::BoxBoolean = *(int32_t (**)(uint32_t val))curMemory; - curMemory += sizeof(Plugin::BoxBoolean); - Plugin::UnboxBoolean = *(int32_t (**)(int32_t valHandle))curMemory; - curMemory += sizeof(Plugin::UnboxBoolean); - Plugin::BoxSByte = *(int32_t (**)(int8_t val))curMemory; - curMemory += sizeof(Plugin::BoxSByte); - Plugin::UnboxSByte = *(int8_t (**)(int32_t valHandle))curMemory; - curMemory += sizeof(Plugin::UnboxSByte); - Plugin::BoxByte = *(int32_t (**)(uint8_t val))curMemory; - curMemory += sizeof(Plugin::BoxByte); - Plugin::UnboxByte = *(uint8_t (**)(int32_t valHandle))curMemory; - curMemory += sizeof(Plugin::UnboxByte); - Plugin::BoxInt16 = *(int32_t (**)(int16_t val))curMemory; - curMemory += sizeof(Plugin::BoxInt16); - Plugin::UnboxInt16 = *(int16_t (**)(int32_t valHandle))curMemory; - curMemory += sizeof(Plugin::UnboxInt16); - Plugin::BoxUInt16 = *(int32_t (**)(uint16_t val))curMemory; - curMemory += sizeof(Plugin::BoxUInt16); - Plugin::UnboxUInt16 = *(uint16_t (**)(int32_t valHandle))curMemory; - curMemory += sizeof(Plugin::UnboxUInt16); - Plugin::BoxInt32 = *(int32_t (**)(int32_t val))curMemory; - curMemory += sizeof(Plugin::BoxInt32); - Plugin::UnboxInt32 = *(int32_t (**)(int32_t valHandle))curMemory; - curMemory += sizeof(Plugin::UnboxInt32); - Plugin::BoxUInt32 = *(int32_t (**)(uint32_t val))curMemory; - curMemory += sizeof(Plugin::BoxUInt32); - Plugin::UnboxUInt32 = *(uint32_t (**)(int32_t valHandle))curMemory; - curMemory += sizeof(Plugin::UnboxUInt32); - Plugin::BoxInt64 = *(int32_t (**)(int64_t val))curMemory; - curMemory += sizeof(Plugin::BoxInt64); - Plugin::UnboxInt64 = *(int64_t (**)(int32_t valHandle))curMemory; - curMemory += sizeof(Plugin::UnboxInt64); - Plugin::BoxUInt64 = *(int32_t (**)(uint64_t val))curMemory; - curMemory += sizeof(Plugin::BoxUInt64); - Plugin::UnboxUInt64 = *(uint64_t (**)(int32_t valHandle))curMemory; - curMemory += sizeof(Plugin::UnboxUInt64); - Plugin::BoxChar = *(int32_t (**)(uint16_t val))curMemory; - curMemory += sizeof(Plugin::BoxChar); - Plugin::UnboxChar = *(int16_t (**)(int32_t valHandle))curMemory; - curMemory += sizeof(Plugin::UnboxChar); - Plugin::BoxSingle = *(int32_t (**)(float val))curMemory; - curMemory += sizeof(Plugin::BoxSingle); - Plugin::UnboxSingle = *(float (**)(int32_t valHandle))curMemory; - curMemory += sizeof(Plugin::UnboxSingle); - Plugin::BoxDouble = *(int32_t (**)(double val))curMemory; - curMemory += sizeof(Plugin::BoxDouble); - Plugin::UnboxDouble = *(double (**)(int32_t valHandle))curMemory; - curMemory += sizeof(Plugin::UnboxDouble); - /*END INIT BODY PARAMETER READS*/ - - // Init managed object ref counting - Plugin::RefCountsLenClass = maxManagedObjects; - Plugin::RefCountsClass = (int32_t*)curMemory; - curMemory += maxManagedObjects * sizeof(int32_t); - - /*BEGIN INIT BODY ARRAYS*/ - Plugin::RefCountsSystemDecimal = (int32_t*)curMemory; - curMemory += 1000 * sizeof(int32_t); - Plugin::RefCountsLenSystemDecimal = 1000; - - Plugin::BaseBallScriptFreeListSize = 1000; - Plugin::BaseBallScriptFreeList = (MyGame::BaseBallScript**)curMemory; - curMemory += 1000 * sizeof(MyGame::BaseBallScript*); - - Plugin::BaseBallScriptFreeWholeListSize = 1000; - Plugin::BaseBallScriptFreeWholeList = (Plugin::BaseBallScriptFreeWholeListEntry*)curMemory; - curMemory += 1000 * sizeof(Plugin::BaseBallScriptFreeWholeListEntry); - /*END INIT BODY ARRAYS*/ - - // Make sure there was enough memory - int32_t usedMemory = (int32_t)(curMemory - (uint8_t*)memory); - if (usedMemory > memorySize) - { - System::String msg = "Plugin memory size is too low"; - System::Exception ex(msg); - Plugin::SetException(ex.Handle); - return; - } - - if (initMode == InitMode::FirstBoot) - { - // Clear memory - memset(memory, 0, memorySize); - - /*BEGIN INIT BODY FIRST BOOT*/ - for (int32_t i = 0, end = Plugin::BaseBallScriptFreeListSize - 1; i < end; ++i) - { - Plugin::BaseBallScriptFreeList[i] = (MyGame::BaseBallScript*)(Plugin::BaseBallScriptFreeList + i + 1); - } - Plugin::BaseBallScriptFreeList[Plugin::BaseBallScriptFreeListSize - 1] = nullptr; - Plugin::NextFreeBaseBallScript = Plugin::BaseBallScriptFreeList + 1; - - for (int32_t i = 0, end = Plugin::BaseBallScriptFreeWholeListSize - 1; i < end; ++i) - { - Plugin::BaseBallScriptFreeWholeList[i].Next = Plugin::BaseBallScriptFreeWholeList + i + 1; - } - Plugin::BaseBallScriptFreeWholeList[Plugin::BaseBallScriptFreeWholeListSize - 1].Next = nullptr; - Plugin::NextFreeWholeBaseBallScript = Plugin::BaseBallScriptFreeWholeList + 1; - /*END INIT BODY FIRST BOOT*/ - } - - try - { - PluginMain( - curMemory, - (int32_t)(memorySize - usedMemory), - initMode == InitMode::FirstBoot); - } - catch (System::Exception ex) - { - Plugin::SetException(ex.Handle); - } - catch (...) - { - System::String msg = "Unhandled exception in PluginMain"; - System::Exception ex(msg); - Plugin::SetException(ex.Handle); - } -} - -// Receive an unhandled exception from C# -DLLEXPORT void SetCsharpException(int32_t handle) -{ - Plugin::unhandledCsharpException = new System::Exception( - Plugin::InternalUse::Only, - handle); -} - diff --git a/Unity/Assets/CppSource/NativeScript/Bindings.cpp.meta b/Unity/Assets/CppSource/NativeScript/Bindings.cpp.meta deleted file mode 100644 index 1b1a472..0000000 --- a/Unity/Assets/CppSource/NativeScript/Bindings.cpp.meta +++ /dev/null @@ -1,26 +0,0 @@ -fileFormatVersion: 2 -guid: 6b6c5fe253c434b7db04a6d5165c1001 -timeCreated: 1525538114 -licenseType: Free -PluginImporter: - externalObjects: {} - serializedVersion: 2 - iconMap: {} - executionOrder: {} - isPreloaded: 0 - isOverridable: 0 - platformData: - - first: - Any: - second: - enabled: 1 - settings: {} - - first: - Editor: Editor - second: - enabled: 0 - settings: - DefaultValueInitialized: true - userData: - assetBundleName: - assetBundleVariant: diff --git a/Unity/Assets/CppSource/NativeScript/Bindings.h b/Unity/Assets/CppSource/NativeScript/Bindings.h deleted file mode 100644 index 4da12a4..0000000 --- a/Unity/Assets/CppSource/NativeScript/Bindings.h +++ /dev/null @@ -1,1669 +0,0 @@ -/// -/// Declaration of the various .NET types exposed to C++ -/// -/// -/// Jackson Dunstan, 2017, http://JacksonDunstan.com -/// -/// -/// MIT -/// - -#pragma once - -// For int32_t, etc. -#include - -// For size_t to support placement new and delete -#include - -//////////////////////////////////////////////////////////////// -// Plugin internals. Do not name these in game code as they may -// change without warning. For example: -// // Good. Uses behavior, not names. -// int x = myArray[5]; -// // Bad. Directly uses names. -// ArrayElementProxy1_1 proxy = myArray[5]; -// int x = proxy; -//////////////////////////////////////////////////////////////// - -namespace Plugin -{ - enum struct InternalUse - { - Only - }; - - struct ManagedType - { - int32_t Handle; - - ManagedType(); - ManagedType(decltype(nullptr)); - ManagedType(InternalUse, int32_t handle); - }; - - template struct ArrayElementProxy1_1; - - template struct ArrayElementProxy1_2; - template struct ArrayElementProxy2_2; - - template struct ArrayElementProxy1_3; - template struct ArrayElementProxy2_3; - template struct ArrayElementProxy3_3; - - template struct ArrayElementProxy1_4; - template struct ArrayElementProxy2_4; - template struct ArrayElementProxy3_4; - template struct ArrayElementProxy4_4; - - template struct ArrayElementProxy1_5; - template struct ArrayElementProxy2_5; - template struct ArrayElementProxy3_5; - template struct ArrayElementProxy4_5; - template struct ArrayElementProxy5_5; -} - -//////////////////////////////////////////////////////////////// -// C# basic types -//////////////////////////////////////////////////////////////// - -namespace System -{ - struct Object; - struct ValueType; - struct Enum; - struct String; - struct Array; - template struct Array1; - template struct Array2; - template struct Array3; - template struct Array4; - template struct Array5; - struct IComparable; - template struct IComparable_1; - template struct IEquatable_1; - struct IFormattable; - struct IConvertible; - - // .NET booleans are four bytes long - // This struct makes them feel like C++'s bool, int32_t, and uint32_t types - struct Boolean - { - int32_t Value; - - Boolean(); - Boolean(bool value); - Boolean(int32_t value); - Boolean(uint32_t value); - operator bool() const; - operator int32_t() const; - operator uint32_t() const; - explicit operator Object() const; - explicit operator ValueType() const; - explicit operator IComparable() const; - explicit operator IFormattable() const; - explicit operator IConvertible() const; - explicit operator IComparable_1() const; - explicit operator IEquatable_1() const; - }; - - // .NET chars are two bytes long - // This struct helps them interoperate with C++'s char and int16_t types - struct Char - { - int16_t Value; - - Char(); - Char(char value); - Char(int16_t value); - operator int16_t() const; - explicit operator Object() const; - explicit operator ValueType() const; - explicit operator IComparable() const; - explicit operator IFormattable() const; - explicit operator IConvertible() const; - explicit operator IComparable_1() const; - explicit operator IEquatable_1() const; - }; - - struct SByte - { - int8_t Value; - - SByte(); - SByte(int8_t value); - operator int8_t() const; - explicit operator Object() const; - explicit operator ValueType() const; - explicit operator IComparable() const; - explicit operator IFormattable() const; - explicit operator IConvertible() const; - explicit operator IComparable_1() const; - explicit operator IEquatable_1() const; - }; - - struct Byte - { - uint8_t Value; - - Byte(); - Byte(uint8_t value); - operator uint8_t() const; - explicit operator Object() const; - explicit operator ValueType() const; - explicit operator IComparable() const; - explicit operator IFormattable() const; - explicit operator IConvertible() const; - explicit operator IComparable_1() const; - explicit operator IEquatable_1() const; - }; - - struct Int16 - { - int16_t Value; - - Int16(); - Int16(int16_t value); - operator int16_t() const; - explicit operator Object() const; - explicit operator ValueType() const; - explicit operator IComparable() const; - explicit operator IFormattable() const; - explicit operator IConvertible() const; - explicit operator IComparable_1() const; - explicit operator IEquatable_1() const; - }; - - struct UInt16 - { - uint16_t Value; - - UInt16(); - UInt16(uint16_t value); - operator uint16_t() const; - explicit operator Object() const; - explicit operator ValueType() const; - explicit operator IComparable() const; - explicit operator IFormattable() const; - explicit operator IConvertible() const; - explicit operator IComparable_1() const; - explicit operator IEquatable_1() const; - }; - - struct Int32 - { - int32_t Value; - - Int32(); - Int32(int32_t value); - operator int32_t() const; - explicit operator Object() const; - explicit operator ValueType() const; - explicit operator IComparable() const; - explicit operator IFormattable() const; - explicit operator IConvertible() const; - explicit operator IComparable_1() const; - explicit operator IEquatable_1() const; - }; - - struct UInt32 - { - uint32_t Value; - - UInt32(); - UInt32(uint32_t value); - operator uint32_t() const; - explicit operator Object() const; - explicit operator ValueType() const; - explicit operator IComparable() const; - explicit operator IFormattable() const; - explicit operator IConvertible() const; - explicit operator IComparable_1() const; - explicit operator IEquatable_1() const; - }; - - struct Int64 - { - int64_t Value; - - Int64(); - Int64(int64_t value); - operator int64_t() const; - explicit operator Object() const; - explicit operator ValueType() const; - explicit operator IComparable() const; - explicit operator IFormattable() const; - explicit operator IConvertible() const; - explicit operator IComparable_1() const; - explicit operator IEquatable_1() const; - }; - - struct UInt64 - { - uint64_t Value; - - UInt64(); - UInt64(uint64_t value); - operator uint64_t() const; - explicit operator Object() const; - explicit operator ValueType() const; - explicit operator IComparable() const; - explicit operator IFormattable() const; - explicit operator IConvertible() const; - explicit operator IComparable_1() const; - explicit operator IEquatable_1() const; - }; - - struct Single - { - float Value; - - Single(); - Single(float value); - operator float() const; - explicit operator Object() const; - explicit operator ValueType() const; - explicit operator IComparable() const; - explicit operator IFormattable() const; - explicit operator IConvertible() const; - explicit operator IComparable_1() const; - explicit operator IEquatable_1() const; - }; - - struct Double - { - double Value; - - Double(); - Double(double value); - operator double() const; - explicit operator Object() const; - explicit operator ValueType() const; - explicit operator IComparable() const; - explicit operator IFormattable() const; - explicit operator IConvertible() const; - explicit operator IComparable_1() const; - explicit operator IEquatable_1() const; - }; -} - -/*BEGIN TEMPLATE DECLARATIONS*/ -namespace System -{ - template struct IEquatable_1; -} - -namespace System -{ - template struct IComparable_1; -} -/*END TEMPLATE DECLARATIONS*/ - -/*BEGIN TYPE DECLARATIONS*/ -namespace System -{ - struct IFormattable; -} - -namespace System -{ - struct IConvertible; -} - -namespace System -{ - struct IComparable; -} - -namespace System -{ - namespace Runtime - { - namespace Serialization - { - struct IDeserializationCallback; - } - } -} - -namespace System -{ - struct Decimal; -} - -namespace UnityEngine -{ - struct Vector3; -} - -namespace UnityEngine -{ - struct Object; -} - -namespace UnityEngine -{ - struct Component; -} - -namespace UnityEngine -{ - struct Transform; -} - -namespace System -{ - namespace Collections - { - struct IEnumerator; - } -} - -namespace System -{ - namespace Runtime - { - namespace Serialization - { - struct ISerializable; - } - } -} - -namespace System -{ - namespace Runtime - { - namespace InteropServices - { - struct _Exception; - } - } -} - -namespace UnityEngine -{ - struct GameObject; -} - -namespace UnityEngine -{ - struct Debug; -} - -namespace UnityEngine -{ - struct Behaviour; -} - -namespace UnityEngine -{ - struct MonoBehaviour; -} - -namespace System -{ - struct Exception; -} - -namespace System -{ - struct SystemException; -} - -namespace System -{ - struct NullReferenceException; -} - -namespace UnityEngine -{ - struct PrimitiveType; -} - -namespace UnityEngine -{ - struct Time; -} - -namespace MyGame -{ - struct AbstractBaseBallScript; -} - -namespace MyGame -{ - struct BaseBallScript; -} -/*END TYPE DECLARATIONS*/ - -/*BEGIN TEMPLATE SPECIALIZATION DECLARATIONS*/ -namespace System -{ - template<> struct IEquatable_1; -} - -namespace System -{ - template<> struct IEquatable_1; -} - -namespace System -{ - template<> struct IEquatable_1; -} - -namespace System -{ - template<> struct IEquatable_1; -} - -namespace System -{ - template<> struct IEquatable_1; -} - -namespace System -{ - template<> struct IEquatable_1; -} - -namespace System -{ - template<> struct IEquatable_1; -} - -namespace System -{ - template<> struct IEquatable_1; -} - -namespace System -{ - template<> struct IEquatable_1; -} - -namespace System -{ - template<> struct IEquatable_1; -} - -namespace System -{ - template<> struct IEquatable_1; -} - -namespace System -{ - template<> struct IEquatable_1; -} - -namespace System -{ - template<> struct IEquatable_1; -} - -namespace System -{ - template<> struct IEquatable_1; -} - -namespace System -{ - template<> struct IComparable_1; -} - -namespace System -{ - template<> struct IComparable_1; -} - -namespace System -{ - template<> struct IComparable_1; -} - -namespace System -{ - template<> struct IComparable_1; -} - -namespace System -{ - template<> struct IComparable_1; -} - -namespace System -{ - template<> struct IComparable_1; -} - -namespace System -{ - template<> struct IComparable_1; -} - -namespace System -{ - template<> struct IComparable_1; -} - -namespace System -{ - template<> struct IComparable_1; -} - -namespace System -{ - template<> struct IComparable_1; -} - -namespace System -{ - template<> struct IComparable_1; -} - -namespace System -{ - template<> struct IComparable_1; -} - -namespace System -{ - template<> struct IComparable_1; -} -/*END TEMPLATE SPECIALIZATION DECLARATIONS*/ - -//////////////////////////////////////////////////////////////// -// C# type definitions -//////////////////////////////////////////////////////////////// - -namespace System -{ - struct Object : Plugin::ManagedType - { - Object(); - Object(Plugin::InternalUse iu, int32_t handle); - Object(decltype(nullptr)); - virtual ~Object(); - bool operator==(decltype(nullptr)) const; - bool operator!=(decltype(nullptr)) const; - virtual void ThrowReferenceToThis(); - - /*BEGIN UNBOXING METHOD DECLARATIONS*/ - explicit operator System::Decimal(); - explicit operator UnityEngine::Vector3(); - explicit operator UnityEngine::PrimitiveType(); - explicit operator System::Boolean(); - explicit operator System::SByte(); - explicit operator System::Byte(); - explicit operator System::Int16(); - explicit operator System::UInt16(); - explicit operator System::Int32(); - explicit operator System::UInt32(); - explicit operator System::Int64(); - explicit operator System::UInt64(); - explicit operator System::Char(); - explicit operator System::Single(); - explicit operator System::Double(); - /*END UNBOXING METHOD DECLARATIONS*/ - }; - - struct ValueType : virtual Object - { - ValueType(Plugin::InternalUse iu, int32_t handle); - ValueType(decltype(nullptr)); - }; - - struct Enum : virtual ValueType - { - Enum(Plugin::InternalUse iu, int32_t handle); - Enum(decltype(nullptr)); - }; - - struct String : virtual Object - { - String(Plugin::InternalUse iu, int32_t handle); - String(decltype(nullptr)); - String(const String& other); - String(String&& other); - virtual ~String(); - String& operator=(const String& other); - String& operator=(decltype(nullptr)); - String& operator=(String&& other); - String(const char* chars); - }; - - struct ICloneable : virtual Object - { - ICloneable(Plugin::InternalUse iu, int32_t handle); - ICloneable(decltype(nullptr)); - }; - - namespace Collections - { - struct IEnumerable : virtual Object - { - IEnumerable(Plugin::InternalUse iu, int32_t handle); - IEnumerable(decltype(nullptr)); - IEnumerator GetEnumerator(); - }; - - struct ICollection : virtual IEnumerable - { - ICollection(Plugin::InternalUse iu, int32_t handle); - ICollection(decltype(nullptr)); - }; - - struct IList : virtual ICollection, virtual IEnumerable - { - IList(Plugin::InternalUse iu, int32_t handle); - IList(decltype(nullptr)); - }; - } - - struct Array : virtual ICloneable, virtual Collections::IList - { - Array(Plugin::InternalUse iu, int32_t handle); - Array(decltype(nullptr)); - int32_t GetLength(); - int32_t GetRank(); - }; -} - -//////////////////////////////////////////////////////////////// -// Global variables -//////////////////////////////////////////////////////////////// - -namespace Plugin -{ - extern System::String NullString; -} - -/*BEGIN TYPE DEFINITIONS*/ -namespace System -{ - struct IFormattable : virtual System::Object - { - IFormattable(decltype(nullptr)); - IFormattable(Plugin::InternalUse, int32_t handle); - IFormattable(const IFormattable& other); - IFormattable(IFormattable&& other); - virtual ~IFormattable(); - IFormattable& operator=(const IFormattable& other); - IFormattable& operator=(decltype(nullptr)); - IFormattable& operator=(IFormattable&& other); - bool operator==(const IFormattable& other) const; - bool operator!=(const IFormattable& other) const; - }; -} - -namespace System -{ - struct IConvertible : virtual System::Object - { - IConvertible(decltype(nullptr)); - IConvertible(Plugin::InternalUse, int32_t handle); - IConvertible(const IConvertible& other); - IConvertible(IConvertible&& other); - virtual ~IConvertible(); - IConvertible& operator=(const IConvertible& other); - IConvertible& operator=(decltype(nullptr)); - IConvertible& operator=(IConvertible&& other); - bool operator==(const IConvertible& other) const; - bool operator!=(const IConvertible& other) const; - }; -} - -namespace System -{ - struct IComparable : virtual System::Object - { - IComparable(decltype(nullptr)); - IComparable(Plugin::InternalUse, int32_t handle); - IComparable(const IComparable& other); - IComparable(IComparable&& other); - virtual ~IComparable(); - IComparable& operator=(const IComparable& other); - IComparable& operator=(decltype(nullptr)); - IComparable& operator=(IComparable&& other); - bool operator==(const IComparable& other) const; - bool operator!=(const IComparable& other) const; - }; -} - -namespace System -{ - template<> struct IEquatable_1 : virtual System::Object - { - IEquatable_1(decltype(nullptr)); - IEquatable_1(Plugin::InternalUse, int32_t handle); - IEquatable_1(const IEquatable_1& other); - IEquatable_1(IEquatable_1&& other); - virtual ~IEquatable_1(); - IEquatable_1& operator=(const IEquatable_1& other); - IEquatable_1& operator=(decltype(nullptr)); - IEquatable_1& operator=(IEquatable_1&& other); - bool operator==(const IEquatable_1& other) const; - bool operator!=(const IEquatable_1& other) const; - }; -} - -namespace System -{ - template<> struct IEquatable_1 : virtual System::Object - { - IEquatable_1(decltype(nullptr)); - IEquatable_1(Plugin::InternalUse, int32_t handle); - IEquatable_1(const IEquatable_1& other); - IEquatable_1(IEquatable_1&& other); - virtual ~IEquatable_1(); - IEquatable_1& operator=(const IEquatable_1& other); - IEquatable_1& operator=(decltype(nullptr)); - IEquatable_1& operator=(IEquatable_1&& other); - bool operator==(const IEquatable_1& other) const; - bool operator!=(const IEquatable_1& other) const; - }; -} - -namespace System -{ - template<> struct IEquatable_1 : virtual System::Object - { - IEquatable_1(decltype(nullptr)); - IEquatable_1(Plugin::InternalUse, int32_t handle); - IEquatable_1(const IEquatable_1& other); - IEquatable_1(IEquatable_1&& other); - virtual ~IEquatable_1(); - IEquatable_1& operator=(const IEquatable_1& other); - IEquatable_1& operator=(decltype(nullptr)); - IEquatable_1& operator=(IEquatable_1&& other); - bool operator==(const IEquatable_1& other) const; - bool operator!=(const IEquatable_1& other) const; - }; -} - -namespace System -{ - template<> struct IEquatable_1 : virtual System::Object - { - IEquatable_1(decltype(nullptr)); - IEquatable_1(Plugin::InternalUse, int32_t handle); - IEquatable_1(const IEquatable_1& other); - IEquatable_1(IEquatable_1&& other); - virtual ~IEquatable_1(); - IEquatable_1& operator=(const IEquatable_1& other); - IEquatable_1& operator=(decltype(nullptr)); - IEquatable_1& operator=(IEquatable_1&& other); - bool operator==(const IEquatable_1& other) const; - bool operator!=(const IEquatable_1& other) const; - }; -} - -namespace System -{ - template<> struct IEquatable_1 : virtual System::Object - { - IEquatable_1(decltype(nullptr)); - IEquatable_1(Plugin::InternalUse, int32_t handle); - IEquatable_1(const IEquatable_1& other); - IEquatable_1(IEquatable_1&& other); - virtual ~IEquatable_1(); - IEquatable_1& operator=(const IEquatable_1& other); - IEquatable_1& operator=(decltype(nullptr)); - IEquatable_1& operator=(IEquatable_1&& other); - bool operator==(const IEquatable_1& other) const; - bool operator!=(const IEquatable_1& other) const; - }; -} - -namespace System -{ - template<> struct IEquatable_1 : virtual System::Object - { - IEquatable_1(decltype(nullptr)); - IEquatable_1(Plugin::InternalUse, int32_t handle); - IEquatable_1(const IEquatable_1& other); - IEquatable_1(IEquatable_1&& other); - virtual ~IEquatable_1(); - IEquatable_1& operator=(const IEquatable_1& other); - IEquatable_1& operator=(decltype(nullptr)); - IEquatable_1& operator=(IEquatable_1&& other); - bool operator==(const IEquatable_1& other) const; - bool operator!=(const IEquatable_1& other) const; - }; -} - -namespace System -{ - template<> struct IEquatable_1 : virtual System::Object - { - IEquatable_1(decltype(nullptr)); - IEquatable_1(Plugin::InternalUse, int32_t handle); - IEquatable_1(const IEquatable_1& other); - IEquatable_1(IEquatable_1&& other); - virtual ~IEquatable_1(); - IEquatable_1& operator=(const IEquatable_1& other); - IEquatable_1& operator=(decltype(nullptr)); - IEquatable_1& operator=(IEquatable_1&& other); - bool operator==(const IEquatable_1& other) const; - bool operator!=(const IEquatable_1& other) const; - }; -} - -namespace System -{ - template<> struct IEquatable_1 : virtual System::Object - { - IEquatable_1(decltype(nullptr)); - IEquatable_1(Plugin::InternalUse, int32_t handle); - IEquatable_1(const IEquatable_1& other); - IEquatable_1(IEquatable_1&& other); - virtual ~IEquatable_1(); - IEquatable_1& operator=(const IEquatable_1& other); - IEquatable_1& operator=(decltype(nullptr)); - IEquatable_1& operator=(IEquatable_1&& other); - bool operator==(const IEquatable_1& other) const; - bool operator!=(const IEquatable_1& other) const; - }; -} - -namespace System -{ - template<> struct IEquatable_1 : virtual System::Object - { - IEquatable_1(decltype(nullptr)); - IEquatable_1(Plugin::InternalUse, int32_t handle); - IEquatable_1(const IEquatable_1& other); - IEquatable_1(IEquatable_1&& other); - virtual ~IEquatable_1(); - IEquatable_1& operator=(const IEquatable_1& other); - IEquatable_1& operator=(decltype(nullptr)); - IEquatable_1& operator=(IEquatable_1&& other); - bool operator==(const IEquatable_1& other) const; - bool operator!=(const IEquatable_1& other) const; - }; -} - -namespace System -{ - template<> struct IEquatable_1 : virtual System::Object - { - IEquatable_1(decltype(nullptr)); - IEquatable_1(Plugin::InternalUse, int32_t handle); - IEquatable_1(const IEquatable_1& other); - IEquatable_1(IEquatable_1&& other); - virtual ~IEquatable_1(); - IEquatable_1& operator=(const IEquatable_1& other); - IEquatable_1& operator=(decltype(nullptr)); - IEquatable_1& operator=(IEquatable_1&& other); - bool operator==(const IEquatable_1& other) const; - bool operator!=(const IEquatable_1& other) const; - }; -} - -namespace System -{ - template<> struct IEquatable_1 : virtual System::Object - { - IEquatable_1(decltype(nullptr)); - IEquatable_1(Plugin::InternalUse, int32_t handle); - IEquatable_1(const IEquatable_1& other); - IEquatable_1(IEquatable_1&& other); - virtual ~IEquatable_1(); - IEquatable_1& operator=(const IEquatable_1& other); - IEquatable_1& operator=(decltype(nullptr)); - IEquatable_1& operator=(IEquatable_1&& other); - bool operator==(const IEquatable_1& other) const; - bool operator!=(const IEquatable_1& other) const; - }; -} - -namespace System -{ - template<> struct IEquatable_1 : virtual System::Object - { - IEquatable_1(decltype(nullptr)); - IEquatable_1(Plugin::InternalUse, int32_t handle); - IEquatable_1(const IEquatable_1& other); - IEquatable_1(IEquatable_1&& other); - virtual ~IEquatable_1(); - IEquatable_1& operator=(const IEquatable_1& other); - IEquatable_1& operator=(decltype(nullptr)); - IEquatable_1& operator=(IEquatable_1&& other); - bool operator==(const IEquatable_1& other) const; - bool operator!=(const IEquatable_1& other) const; - }; -} - -namespace System -{ - template<> struct IEquatable_1 : virtual System::Object - { - IEquatable_1(decltype(nullptr)); - IEquatable_1(Plugin::InternalUse, int32_t handle); - IEquatable_1(const IEquatable_1& other); - IEquatable_1(IEquatable_1&& other); - virtual ~IEquatable_1(); - IEquatable_1& operator=(const IEquatable_1& other); - IEquatable_1& operator=(decltype(nullptr)); - IEquatable_1& operator=(IEquatable_1&& other); - bool operator==(const IEquatable_1& other) const; - bool operator!=(const IEquatable_1& other) const; - }; -} - -namespace System -{ - template<> struct IEquatable_1 : virtual System::Object - { - IEquatable_1(decltype(nullptr)); - IEquatable_1(Plugin::InternalUse, int32_t handle); - IEquatable_1(const IEquatable_1& other); - IEquatable_1(IEquatable_1&& other); - virtual ~IEquatable_1(); - IEquatable_1& operator=(const IEquatable_1& other); - IEquatable_1& operator=(decltype(nullptr)); - IEquatable_1& operator=(IEquatable_1&& other); - bool operator==(const IEquatable_1& other) const; - bool operator!=(const IEquatable_1& other) const; - }; -} - -namespace System -{ - template<> struct IComparable_1 : virtual System::Object - { - IComparable_1(decltype(nullptr)); - IComparable_1(Plugin::InternalUse, int32_t handle); - IComparable_1(const IComparable_1& other); - IComparable_1(IComparable_1&& other); - virtual ~IComparable_1(); - IComparable_1& operator=(const IComparable_1& other); - IComparable_1& operator=(decltype(nullptr)); - IComparable_1& operator=(IComparable_1&& other); - bool operator==(const IComparable_1& other) const; - bool operator!=(const IComparable_1& other) const; - }; -} - -namespace System -{ - template<> struct IComparable_1 : virtual System::Object - { - IComparable_1(decltype(nullptr)); - IComparable_1(Plugin::InternalUse, int32_t handle); - IComparable_1(const IComparable_1& other); - IComparable_1(IComparable_1&& other); - virtual ~IComparable_1(); - IComparable_1& operator=(const IComparable_1& other); - IComparable_1& operator=(decltype(nullptr)); - IComparable_1& operator=(IComparable_1&& other); - bool operator==(const IComparable_1& other) const; - bool operator!=(const IComparable_1& other) const; - }; -} - -namespace System -{ - template<> struct IComparable_1 : virtual System::Object - { - IComparable_1(decltype(nullptr)); - IComparable_1(Plugin::InternalUse, int32_t handle); - IComparable_1(const IComparable_1& other); - IComparable_1(IComparable_1&& other); - virtual ~IComparable_1(); - IComparable_1& operator=(const IComparable_1& other); - IComparable_1& operator=(decltype(nullptr)); - IComparable_1& operator=(IComparable_1&& other); - bool operator==(const IComparable_1& other) const; - bool operator!=(const IComparable_1& other) const; - }; -} - -namespace System -{ - template<> struct IComparable_1 : virtual System::Object - { - IComparable_1(decltype(nullptr)); - IComparable_1(Plugin::InternalUse, int32_t handle); - IComparable_1(const IComparable_1& other); - IComparable_1(IComparable_1&& other); - virtual ~IComparable_1(); - IComparable_1& operator=(const IComparable_1& other); - IComparable_1& operator=(decltype(nullptr)); - IComparable_1& operator=(IComparable_1&& other); - bool operator==(const IComparable_1& other) const; - bool operator!=(const IComparable_1& other) const; - }; -} - -namespace System -{ - template<> struct IComparable_1 : virtual System::Object - { - IComparable_1(decltype(nullptr)); - IComparable_1(Plugin::InternalUse, int32_t handle); - IComparable_1(const IComparable_1& other); - IComparable_1(IComparable_1&& other); - virtual ~IComparable_1(); - IComparable_1& operator=(const IComparable_1& other); - IComparable_1& operator=(decltype(nullptr)); - IComparable_1& operator=(IComparable_1&& other); - bool operator==(const IComparable_1& other) const; - bool operator!=(const IComparable_1& other) const; - }; -} - -namespace System -{ - template<> struct IComparable_1 : virtual System::Object - { - IComparable_1(decltype(nullptr)); - IComparable_1(Plugin::InternalUse, int32_t handle); - IComparable_1(const IComparable_1& other); - IComparable_1(IComparable_1&& other); - virtual ~IComparable_1(); - IComparable_1& operator=(const IComparable_1& other); - IComparable_1& operator=(decltype(nullptr)); - IComparable_1& operator=(IComparable_1&& other); - bool operator==(const IComparable_1& other) const; - bool operator!=(const IComparable_1& other) const; - }; -} - -namespace System -{ - template<> struct IComparable_1 : virtual System::Object - { - IComparable_1(decltype(nullptr)); - IComparable_1(Plugin::InternalUse, int32_t handle); - IComparable_1(const IComparable_1& other); - IComparable_1(IComparable_1&& other); - virtual ~IComparable_1(); - IComparable_1& operator=(const IComparable_1& other); - IComparable_1& operator=(decltype(nullptr)); - IComparable_1& operator=(IComparable_1&& other); - bool operator==(const IComparable_1& other) const; - bool operator!=(const IComparable_1& other) const; - }; -} - -namespace System -{ - template<> struct IComparable_1 : virtual System::Object - { - IComparable_1(decltype(nullptr)); - IComparable_1(Plugin::InternalUse, int32_t handle); - IComparable_1(const IComparable_1& other); - IComparable_1(IComparable_1&& other); - virtual ~IComparable_1(); - IComparable_1& operator=(const IComparable_1& other); - IComparable_1& operator=(decltype(nullptr)); - IComparable_1& operator=(IComparable_1&& other); - bool operator==(const IComparable_1& other) const; - bool operator!=(const IComparable_1& other) const; - }; -} - -namespace System -{ - template<> struct IComparable_1 : virtual System::Object - { - IComparable_1(decltype(nullptr)); - IComparable_1(Plugin::InternalUse, int32_t handle); - IComparable_1(const IComparable_1& other); - IComparable_1(IComparable_1&& other); - virtual ~IComparable_1(); - IComparable_1& operator=(const IComparable_1& other); - IComparable_1& operator=(decltype(nullptr)); - IComparable_1& operator=(IComparable_1&& other); - bool operator==(const IComparable_1& other) const; - bool operator!=(const IComparable_1& other) const; - }; -} - -namespace System -{ - template<> struct IComparable_1 : virtual System::Object - { - IComparable_1(decltype(nullptr)); - IComparable_1(Plugin::InternalUse, int32_t handle); - IComparable_1(const IComparable_1& other); - IComparable_1(IComparable_1&& other); - virtual ~IComparable_1(); - IComparable_1& operator=(const IComparable_1& other); - IComparable_1& operator=(decltype(nullptr)); - IComparable_1& operator=(IComparable_1&& other); - bool operator==(const IComparable_1& other) const; - bool operator!=(const IComparable_1& other) const; - }; -} - -namespace System -{ - template<> struct IComparable_1 : virtual System::Object - { - IComparable_1(decltype(nullptr)); - IComparable_1(Plugin::InternalUse, int32_t handle); - IComparable_1(const IComparable_1& other); - IComparable_1(IComparable_1&& other); - virtual ~IComparable_1(); - IComparable_1& operator=(const IComparable_1& other); - IComparable_1& operator=(decltype(nullptr)); - IComparable_1& operator=(IComparable_1&& other); - bool operator==(const IComparable_1& other) const; - bool operator!=(const IComparable_1& other) const; - }; -} - -namespace System -{ - template<> struct IComparable_1 : virtual System::Object - { - IComparable_1(decltype(nullptr)); - IComparable_1(Plugin::InternalUse, int32_t handle); - IComparable_1(const IComparable_1& other); - IComparable_1(IComparable_1&& other); - virtual ~IComparable_1(); - IComparable_1& operator=(const IComparable_1& other); - IComparable_1& operator=(decltype(nullptr)); - IComparable_1& operator=(IComparable_1&& other); - bool operator==(const IComparable_1& other) const; - bool operator!=(const IComparable_1& other) const; - }; -} - -namespace System -{ - template<> struct IComparable_1 : virtual System::Object - { - IComparable_1(decltype(nullptr)); - IComparable_1(Plugin::InternalUse, int32_t handle); - IComparable_1(const IComparable_1& other); - IComparable_1(IComparable_1&& other); - virtual ~IComparable_1(); - IComparable_1& operator=(const IComparable_1& other); - IComparable_1& operator=(decltype(nullptr)); - IComparable_1& operator=(IComparable_1&& other); - bool operator==(const IComparable_1& other) const; - bool operator!=(const IComparable_1& other) const; - }; -} - -namespace System -{ - namespace Runtime - { - namespace Serialization - { - struct IDeserializationCallback : virtual System::Object - { - IDeserializationCallback(decltype(nullptr)); - IDeserializationCallback(Plugin::InternalUse, int32_t handle); - IDeserializationCallback(const IDeserializationCallback& other); - IDeserializationCallback(IDeserializationCallback&& other); - virtual ~IDeserializationCallback(); - IDeserializationCallback& operator=(const IDeserializationCallback& other); - IDeserializationCallback& operator=(decltype(nullptr)); - IDeserializationCallback& operator=(IDeserializationCallback&& other); - bool operator==(const IDeserializationCallback& other) const; - bool operator!=(const IDeserializationCallback& other) const; - }; - } - } -} - -namespace System -{ - struct Decimal : Plugin::ManagedType - { - Decimal(decltype(nullptr)); - Decimal(Plugin::InternalUse, int32_t handle); - Decimal(const Decimal& other); - Decimal(Decimal&& other); - virtual ~Decimal(); - Decimal& operator=(const Decimal& other); - Decimal& operator=(decltype(nullptr)); - Decimal& operator=(Decimal&& other); - bool operator==(const Decimal& other) const; - bool operator!=(const Decimal& other) const; - Decimal(System::Double value); - Decimal(System::UInt64 value); - explicit operator System::ValueType(); - explicit operator System::Object(); - explicit operator System::IComparable(); - explicit operator System::IComparable_1(); - explicit operator System::IConvertible(); - explicit operator System::IEquatable_1(); - explicit operator System::Runtime::Serialization::IDeserializationCallback(); - explicit operator System::IFormattable(); - }; -} - -namespace UnityEngine -{ - struct Vector3 - { - Vector3(); - Vector3(System::Single x, System::Single y, System::Single z); - System::Single x; - System::Single y; - System::Single z; - UnityEngine::Vector3 operator+(UnityEngine::Vector3& a); - explicit operator System::ValueType(); - explicit operator System::Object(); - explicit operator System::IEquatable_1(); - }; -} - -namespace UnityEngine -{ - struct Object : virtual System::Object - { - Object(decltype(nullptr)); - Object(Plugin::InternalUse, int32_t handle); - Object(const Object& other); - Object(Object&& other); - virtual ~Object(); - Object& operator=(const Object& other); - Object& operator=(decltype(nullptr)); - Object& operator=(Object&& other); - bool operator==(const Object& other) const; - bool operator!=(const Object& other) const; - System::String GetName(); - void SetName(System::String& value); - }; -} - -namespace UnityEngine -{ - struct Component : virtual UnityEngine::Object - { - Component(decltype(nullptr)); - Component(Plugin::InternalUse, int32_t handle); - Component(const Component& other); - Component(Component&& other); - virtual ~Component(); - Component& operator=(const Component& other); - Component& operator=(decltype(nullptr)); - Component& operator=(Component&& other); - bool operator==(const Component& other) const; - bool operator!=(const Component& other) const; - UnityEngine::Transform GetTransform(); - }; -} - -namespace UnityEngine -{ - struct Transform : virtual UnityEngine::Component, virtual System::Collections::IEnumerable - { - Transform(decltype(nullptr)); - Transform(Plugin::InternalUse, int32_t handle); - Transform(const Transform& other); - Transform(Transform&& other); - virtual ~Transform(); - Transform& operator=(const Transform& other); - Transform& operator=(decltype(nullptr)); - Transform& operator=(Transform&& other); - bool operator==(const Transform& other) const; - bool operator!=(const Transform& other) const; - UnityEngine::Vector3 GetPosition(); - void SetPosition(UnityEngine::Vector3& value); - }; -} - -namespace System -{ - namespace Collections - { - struct IEnumerator : virtual System::Object - { - IEnumerator(decltype(nullptr)); - IEnumerator(Plugin::InternalUse, int32_t handle); - IEnumerator(const IEnumerator& other); - IEnumerator(IEnumerator&& other); - virtual ~IEnumerator(); - IEnumerator& operator=(const IEnumerator& other); - IEnumerator& operator=(decltype(nullptr)); - IEnumerator& operator=(IEnumerator&& other); - bool operator==(const IEnumerator& other) const; - bool operator!=(const IEnumerator& other) const; - System::Object GetCurrent(); - System::Boolean MoveNext(); - }; - } -} - -namespace System -{ - namespace Runtime - { - namespace Serialization - { - struct ISerializable : virtual System::Object - { - ISerializable(decltype(nullptr)); - ISerializable(Plugin::InternalUse, int32_t handle); - ISerializable(const ISerializable& other); - ISerializable(ISerializable&& other); - virtual ~ISerializable(); - ISerializable& operator=(const ISerializable& other); - ISerializable& operator=(decltype(nullptr)); - ISerializable& operator=(ISerializable&& other); - bool operator==(const ISerializable& other) const; - bool operator!=(const ISerializable& other) const; - }; - } - } -} - -namespace System -{ - namespace Runtime - { - namespace InteropServices - { - struct _Exception : virtual System::Object - { - _Exception(decltype(nullptr)); - _Exception(Plugin::InternalUse, int32_t handle); - _Exception(const _Exception& other); - _Exception(_Exception&& other); - virtual ~_Exception(); - _Exception& operator=(const _Exception& other); - _Exception& operator=(decltype(nullptr)); - _Exception& operator=(_Exception&& other); - bool operator==(const _Exception& other) const; - bool operator!=(const _Exception& other) const; - }; - } - } -} - -namespace UnityEngine -{ - struct GameObject : virtual UnityEngine::Object - { - GameObject(decltype(nullptr)); - GameObject(Plugin::InternalUse, int32_t handle); - GameObject(const GameObject& other); - GameObject(GameObject&& other); - virtual ~GameObject(); - GameObject& operator=(const GameObject& other); - GameObject& operator=(decltype(nullptr)); - GameObject& operator=(GameObject&& other); - bool operator==(const GameObject& other) const; - bool operator!=(const GameObject& other) const; - template MT0 AddComponent(); - static UnityEngine::GameObject CreatePrimitive(UnityEngine::PrimitiveType type); - }; -} - -namespace UnityEngine -{ - struct Debug : virtual System::Object - { - Debug(decltype(nullptr)); - Debug(Plugin::InternalUse, int32_t handle); - Debug(const Debug& other); - Debug(Debug&& other); - virtual ~Debug(); - Debug& operator=(const Debug& other); - Debug& operator=(decltype(nullptr)); - Debug& operator=(Debug&& other); - bool operator==(const Debug& other) const; - bool operator!=(const Debug& other) const; - static void Log(System::Object& message); - }; -} - -namespace UnityEngine -{ - struct Behaviour : virtual UnityEngine::Component - { - Behaviour(decltype(nullptr)); - Behaviour(Plugin::InternalUse, int32_t handle); - Behaviour(const Behaviour& other); - Behaviour(Behaviour&& other); - virtual ~Behaviour(); - Behaviour& operator=(const Behaviour& other); - Behaviour& operator=(decltype(nullptr)); - Behaviour& operator=(Behaviour&& other); - bool operator==(const Behaviour& other) const; - bool operator!=(const Behaviour& other) const; - }; -} - -namespace UnityEngine -{ - struct MonoBehaviour : virtual UnityEngine::Behaviour - { - MonoBehaviour(decltype(nullptr)); - MonoBehaviour(Plugin::InternalUse, int32_t handle); - MonoBehaviour(const MonoBehaviour& other); - MonoBehaviour(MonoBehaviour&& other); - virtual ~MonoBehaviour(); - MonoBehaviour& operator=(const MonoBehaviour& other); - MonoBehaviour& operator=(decltype(nullptr)); - MonoBehaviour& operator=(MonoBehaviour&& other); - bool operator==(const MonoBehaviour& other) const; - bool operator!=(const MonoBehaviour& other) const; - UnityEngine::Transform GetTransform(); - }; -} - -namespace System -{ - struct Exception : virtual System::Runtime::InteropServices::_Exception, virtual System::Runtime::Serialization::ISerializable - { - Exception(decltype(nullptr)); - Exception(Plugin::InternalUse, int32_t handle); - Exception(const Exception& other); - Exception(Exception&& other); - virtual ~Exception(); - Exception& operator=(const Exception& other); - Exception& operator=(decltype(nullptr)); - Exception& operator=(Exception&& other); - bool operator==(const Exception& other) const; - bool operator!=(const Exception& other) const; - Exception(System::String& message); - }; -} - -namespace System -{ - struct SystemException : virtual System::Exception, virtual System::Runtime::InteropServices::_Exception, virtual System::Runtime::Serialization::ISerializable - { - SystemException(decltype(nullptr)); - SystemException(Plugin::InternalUse, int32_t handle); - SystemException(const SystemException& other); - SystemException(SystemException&& other); - virtual ~SystemException(); - SystemException& operator=(const SystemException& other); - SystemException& operator=(decltype(nullptr)); - SystemException& operator=(SystemException&& other); - bool operator==(const SystemException& other) const; - bool operator!=(const SystemException& other) const; - }; -} - -namespace System -{ - struct NullReferenceException : virtual System::SystemException, virtual System::Runtime::InteropServices::_Exception, virtual System::Runtime::Serialization::ISerializable - { - NullReferenceException(decltype(nullptr)); - NullReferenceException(Plugin::InternalUse, int32_t handle); - NullReferenceException(const NullReferenceException& other); - NullReferenceException(NullReferenceException&& other); - virtual ~NullReferenceException(); - NullReferenceException& operator=(const NullReferenceException& other); - NullReferenceException& operator=(decltype(nullptr)); - NullReferenceException& operator=(NullReferenceException&& other); - bool operator==(const NullReferenceException& other) const; - bool operator!=(const NullReferenceException& other) const; - }; -} - -namespace UnityEngine -{ - struct PrimitiveType - { - int32_t Value; - static const UnityEngine::PrimitiveType Sphere; - static const UnityEngine::PrimitiveType Capsule; - static const UnityEngine::PrimitiveType Cylinder; - static const UnityEngine::PrimitiveType Cube; - static const UnityEngine::PrimitiveType Plane; - static const UnityEngine::PrimitiveType Quad; - explicit PrimitiveType(int32_t value); - explicit operator int32_t() const; - bool operator==(PrimitiveType other); - bool operator!=(PrimitiveType other); - explicit operator System::Enum(); - explicit operator System::ValueType(); - explicit operator System::Object(); - explicit operator System::IComparable(); - explicit operator System::IConvertible(); - explicit operator System::IFormattable(); - }; -} - -namespace UnityEngine -{ - struct Time : virtual System::Object - { - Time(decltype(nullptr)); - Time(Plugin::InternalUse, int32_t handle); - Time(const Time& other); - Time(Time&& other); - virtual ~Time(); - Time& operator=(const Time& other); - Time& operator=(decltype(nullptr)); - Time& operator=(Time&& other); - bool operator==(const Time& other) const; - bool operator!=(const Time& other) const; - static System::Single GetDeltaTime(); - }; -} - -namespace MyGame -{ - struct AbstractBaseBallScript : virtual UnityEngine::MonoBehaviour - { - AbstractBaseBallScript(decltype(nullptr)); - AbstractBaseBallScript(Plugin::InternalUse, int32_t handle); - AbstractBaseBallScript(const AbstractBaseBallScript& other); - AbstractBaseBallScript(AbstractBaseBallScript&& other); - virtual ~AbstractBaseBallScript(); - AbstractBaseBallScript& operator=(const AbstractBaseBallScript& other); - AbstractBaseBallScript& operator=(decltype(nullptr)); - AbstractBaseBallScript& operator=(AbstractBaseBallScript&& other); - bool operator==(const AbstractBaseBallScript& other) const; - bool operator!=(const AbstractBaseBallScript& other) const; - }; -} - -namespace MyGame -{ - struct BaseBallScript : virtual MyGame::AbstractBaseBallScript - { - BaseBallScript(decltype(nullptr)); - BaseBallScript(Plugin::InternalUse, int32_t handle); - BaseBallScript(const BaseBallScript& other); - BaseBallScript(BaseBallScript&& other); - virtual ~BaseBallScript(); - BaseBallScript& operator=(const BaseBallScript& other); - BaseBallScript& operator=(decltype(nullptr)); - BaseBallScript& operator=(BaseBallScript&& other); - bool operator==(const BaseBallScript& other) const; - bool operator!=(const BaseBallScript& other) const; - int32_t CppHandle; - BaseBallScript(); - virtual void Update(); - }; -} -/*END TYPE DEFINITIONS*/ - -/*BEGIN MACROS*/ -#define MY_GAME_BALL_SCRIPT_DEFAULT_CONSTRUCTOR_DECLARATION \ - BallScript(Plugin::InternalUse iu, int32_t handle); - -#define MY_GAME_BALL_SCRIPT_DEFAULT_CONSTRUCTOR_DEFINITION \ - BallScript::BallScript(Plugin::InternalUse iu, int32_t handle) \ - : UnityEngine::Object(nullptr) \ - , UnityEngine::Component(nullptr) \ - , UnityEngine::Behaviour(nullptr) \ - , UnityEngine::MonoBehaviour(nullptr) \ - , MyGame::AbstractBaseBallScript(nullptr) \ - , MyGame::BaseBallScript(iu, handle) \ - { \ - } - -#define MY_GAME_BALL_SCRIPT_DEFAULT_CONSTRUCTOR \ - BallScript(Plugin::InternalUse iu, int32_t handle) \ - : UnityEngine::Object(nullptr) \ - , UnityEngine::Component(nullptr) \ - , UnityEngine::Behaviour(nullptr) \ - , UnityEngine::MonoBehaviour(nullptr) \ - , MyGame::AbstractBaseBallScript(nullptr) \ - , MyGame::BaseBallScript(iu, handle) \ - { \ - } - -#define MY_GAME_BALL_SCRIPT_DEFAULT_CONTENTS_DECLARATION \ - void* operator new(size_t, void* p) noexcept; \ - void operator delete(void*, size_t) noexcept; \ - -#define MY_GAME_BALL_SCRIPT_DEFAULT_CONTENTS_DEFINITION \ - void* BallScript::operator new(size_t, void* p) noexcept\ - { \ - return p; \ - } \ - void BallScript::operator delete(void*, size_t) noexcept \ - { \ - } - -#define MY_GAME_BALL_SCRIPT_DEFAULT_CONTENTS\ - void* operator new(size_t, void* p) noexcept \ - { \ - return p; \ - } \ - void operator delete(void*, size_t) noexcept \ - { \ - } -/*END MACROS*/ - -//////////////////////////////////////////////////////////////// -// Support for using IEnumerable with range for loops -//////////////////////////////////////////////////////////////// - -namespace Plugin -{ - struct EnumerableIterator - { - System::Collections::IEnumerator enumerator; - bool hasMore; - EnumerableIterator(decltype(nullptr)); - EnumerableIterator(System::Collections::IEnumerable& enumerable); - EnumerableIterator& operator++(); - bool operator!=(const EnumerableIterator& other); - System::Object operator*(); - }; -} - -namespace System -{ - namespace Collections - { - Plugin::EnumerableIterator begin(IEnumerable& enumerable); - Plugin::EnumerableIterator end(IEnumerable& enumerable); - } -} - -//////////////////////////////////////////////////////////////// -// User-defined literals for creating decimals (System.Decimal) -//////////////////////////////////////////////////////////////// - -System::Decimal operator"" _m(long double x); -System::Decimal operator"" _m(unsigned long long x); diff --git a/Unity/Assets/CppSource/NativeScript/Bindings.h.meta b/Unity/Assets/CppSource/NativeScript/Bindings.h.meta deleted file mode 100644 index 615fc4b..0000000 --- a/Unity/Assets/CppSource/NativeScript/Bindings.h.meta +++ /dev/null @@ -1,26 +0,0 @@ -fileFormatVersion: 2 -guid: 2fa6cfa70e93c4d59a7f05e21c18d56b -timeCreated: 1525538114 -licenseType: Free -PluginImporter: - externalObjects: {} - serializedVersion: 2 - iconMap: {} - executionOrder: {} - isPreloaded: 0 - isOverridable: 0 - platformData: - - first: - Any: - second: - enabled: 1 - settings: {} - - first: - Editor: Editor - second: - enabled: 0 - settings: - DefaultValueInitialized: true - userData: - assetBundleName: - assetBundleVariant: diff --git a/Unity/Assets/CppSource/iOS.cmake b/Unity/Assets/CppSource/iOS.cmake deleted file mode 100644 index 959bcd6..0000000 --- a/Unity/Assets/CppSource/iOS.cmake +++ /dev/null @@ -1,208 +0,0 @@ -# This file is based off of the Platform/Darwin.cmake and Platform/UnixPaths.cmake -# files which are included with CMake 2.8.4 -# It has been altered for iOS development - -# Options: -# -# IOS_PLATFORM = OS (default) or SIMULATOR or SIMULATOR64 -# This decides if SDKS will be selected from the iPhoneOS.platform or iPhoneSimulator.platform folders -# OS - the default, used to build for iPhone and iPad physical devices, which have an arm arch. -# SIMULATOR - used to build for the Simulator platforms, which have an x86 arch. -# -# CMAKE_IOS_DEVELOPER_ROOT = automatic(default) or /path/to/platform/Developer folder -# By default this location is automatcially chosen based on the IOS_PLATFORM value above. -# If set manually, it will override the default location and force the user of a particular Developer Platform -# -# CMAKE_IOS_SDK_ROOT = automatic(default) or /path/to/platform/Developer/SDKs/SDK folder -# By default this location is automatcially chosen based on the CMAKE_IOS_DEVELOPER_ROOT value. -# In this case it will always be the most up-to-date SDK found in the CMAKE_IOS_DEVELOPER_ROOT path. -# If set manually, this will force the use of a specific SDK version - -# Macros: -# -# set_xcode_property (TARGET XCODE_PROPERTY XCODE_VALUE) -# A convenience macro for setting xcode specific properties on targets -# example: set_xcode_property (myioslib IPHONEOS_DEPLOYMENT_TARGET "3.1") -# -# find_host_package (PROGRAM ARGS) -# A macro used to find executable programs on the host system, not within the iOS environment. -# Thanks to the android-cmake project for providing the command - -# Standard settings -set (CMAKE_SYSTEM_NAME Darwin) -set (CMAKE_SYSTEM_VERSION 1) -set (UNIX True) -set (APPLE True) -set (IOS True) - -# Required as of cmake 2.8.10 -set (CMAKE_OSX_DEPLOYMENT_TARGET "" CACHE STRING "Force unset of the deployment target for iOS" FORCE) - -# Determine the cmake host system version so we know where to find the iOS SDKs -find_program (CMAKE_UNAME uname /bin /usr/bin /usr/local/bin) -if (CMAKE_UNAME) - exec_program(uname ARGS -r OUTPUT_VARIABLE CMAKE_HOST_SYSTEM_VERSION) - string (REGEX REPLACE "^([0-9]+)\\.([0-9]+).*$" "\\1" DARWIN_MAJOR_VERSION "${CMAKE_HOST_SYSTEM_VERSION}") -endif (CMAKE_UNAME) - -# Force the compilers to gcc for iOS -include (CMakeForceCompiler) -set(CMAKE_C_COMPILER (/usr/bin/gcc Apple)) -set(CMAKE_CXX_COMPILER (/usr/bin/g++ Apple)) -set(CMAKE_AR ar CACHE FILEPATH "" FORCE) - -# Skip the platform compiler checks for cross compiling -set (CMAKE_CXX_COMPILER_WORKS TRUE) -set (CMAKE_C_COMPILER_WORKS TRUE) - -# All iOS/Darwin specific settings - some may be redundant -set (CMAKE_SHARED_LIBRARY_PREFIX "lib") -set (CMAKE_SHARED_LIBRARY_SUFFIX ".dylib") -set (CMAKE_SHARED_MODULE_PREFIX "lib") -set (CMAKE_SHARED_MODULE_SUFFIX ".so") -set (CMAKE_MODULE_EXISTS 1) -set (CMAKE_DL_LIBS "") - -set (CMAKE_C_OSX_COMPATIBILITY_VERSION_FLAG "-compatibility_version ") -set (CMAKE_C_OSX_CURRENT_VERSION_FLAG "-current_version ") -set (CMAKE_CXX_OSX_COMPATIBILITY_VERSION_FLAG "${CMAKE_C_OSX_COMPATIBILITY_VERSION_FLAG}") -set (CMAKE_CXX_OSX_CURRENT_VERSION_FLAG "${CMAKE_C_OSX_CURRENT_VERSION_FLAG}") - -# Hidden visibilty is required for cxx on iOS -set (CMAKE_C_FLAGS_INIT "") -set (CMAKE_CXX_FLAGS_INIT "-fvisibility=hidden -fvisibility-inlines-hidden") - -set (CMAKE_C_LINK_FLAGS "-Wl,-search_paths_first ${CMAKE_C_LINK_FLAGS}") -set (CMAKE_CXX_LINK_FLAGS "-Wl,-search_paths_first ${CMAKE_CXX_LINK_FLAGS}") - -set (CMAKE_PLATFORM_HAS_INSTALLNAME 1) -set (CMAKE_SHARED_LIBRARY_CREATE_C_FLAGS "-dynamiclib -headerpad_max_install_names") -set (CMAKE_SHARED_MODULE_CREATE_C_FLAGS "-bundle -headerpad_max_install_names") -set (CMAKE_SHARED_MODULE_LOADER_C_FLAG "-Wl,-bundle_loader,") -set (CMAKE_SHARED_MODULE_LOADER_CXX_FLAG "-Wl,-bundle_loader,") -set (CMAKE_FIND_LIBRARY_SUFFIXES ".dylib" ".so" ".a") - -# hack: if a new cmake (which uses CMAKE_INSTALL_NAME_TOOL) runs on an old build tree -# (where install_name_tool was hardcoded) and where CMAKE_INSTALL_NAME_TOOL isn't in the cache -# and still cmake didn't fail in CMakeFindBinUtils.cmake (because it isn't rerun) -# hardcode CMAKE_INSTALL_NAME_TOOL here to install_name_tool, so it behaves as it did before, Alex -if (NOT DEFINED CMAKE_INSTALL_NAME_TOOL) - find_program(CMAKE_INSTALL_NAME_TOOL install_name_tool) -endif (NOT DEFINED CMAKE_INSTALL_NAME_TOOL) - -# Setup iOS platform unless specified manually with IOS_PLATFORM -if (NOT DEFINED IOS_PLATFORM) - set (IOS_PLATFORM "OS") -endif (NOT DEFINED IOS_PLATFORM) -set (IOS_PLATFORM ${IOS_PLATFORM} CACHE STRING "Type of iOS Platform") - -# Setup building for arm64 or not -if (NOT DEFINED BUILD_ARM64) - set (BUILD_ARM64 true) -endif (NOT DEFINED BUILD_ARM64) -set (BUILD_ARM64 ${BUILD_ARM64} CACHE STRING "Build arm64 arch or not") - -# Check the platform selection and setup for developer root -if (${IOS_PLATFORM} STREQUAL "OS") - set (IOS_PLATFORM_LOCATION "iPhoneOS.platform") - - # This causes the installers to properly locate the output libraries - set (CMAKE_XCODE_EFFECTIVE_PLATFORMS "-iphoneos") -elseif (${IOS_PLATFORM} STREQUAL "SIMULATOR") - set (SIMULATOR true) - set (IOS_PLATFORM_LOCATION "iPhoneSimulator.platform") - - # This causes the installers to properly locate the output libraries - set (CMAKE_XCODE_EFFECTIVE_PLATFORMS "-iphonesimulator") -elseif (${IOS_PLATFORM} STREQUAL "SIMULATOR64") - set (SIMULATOR true) - set (IOS_PLATFORM_LOCATION "iPhoneSimulator.platform") - - # This causes the installers to properly locate the output libraries - set (CMAKE_XCODE_EFFECTIVE_PLATFORMS "-iphonesimulator") -else (${IOS_PLATFORM} STREQUAL "OS") - message (FATAL_ERROR "Unsupported IOS_PLATFORM value selected. Please choose OS or SIMULATOR") -endif (${IOS_PLATFORM} STREQUAL "OS") - -# Setup iOS developer location unless specified manually with CMAKE_IOS_DEVELOPER_ROOT -# Note Xcode 4.3 changed the installation location, choose the most recent one available -exec_program(/usr/bin/xcode-select ARGS -print-path OUTPUT_VARIABLE CMAKE_XCODE_DEVELOPER_DIR) -set (XCODE_POST_43_ROOT "${CMAKE_XCODE_DEVELOPER_DIR}/Platforms/${IOS_PLATFORM_LOCATION}/Developer") -set (XCODE_PRE_43_ROOT "/Developer/Platforms/${IOS_PLATFORM_LOCATION}/Developer") -if (NOT DEFINED CMAKE_IOS_DEVELOPER_ROOT) - if (EXISTS ${XCODE_POST_43_ROOT}) - set (CMAKE_IOS_DEVELOPER_ROOT ${XCODE_POST_43_ROOT}) - elseif(EXISTS ${XCODE_PRE_43_ROOT}) - set (CMAKE_IOS_DEVELOPER_ROOT ${XCODE_PRE_43_ROOT}) - endif (EXISTS ${XCODE_POST_43_ROOT}) -endif (NOT DEFINED CMAKE_IOS_DEVELOPER_ROOT) -set (CMAKE_IOS_DEVELOPER_ROOT ${CMAKE_IOS_DEVELOPER_ROOT} CACHE PATH "Location of iOS Platform") - -# Find and use the most recent iOS sdk unless specified manually with CMAKE_IOS_SDK_ROOT -if (NOT DEFINED CMAKE_IOS_SDK_ROOT) - file (GLOB _CMAKE_IOS_SDKS "${CMAKE_IOS_DEVELOPER_ROOT}/SDKs/*") - if (_CMAKE_IOS_SDKS) - list (SORT _CMAKE_IOS_SDKS) - list (REVERSE _CMAKE_IOS_SDKS) - list (GET _CMAKE_IOS_SDKS 0 CMAKE_IOS_SDK_ROOT) - else (_CMAKE_IOS_SDKS) - message (FATAL_ERROR "No iOS SDK's found in default search path ${CMAKE_IOS_DEVELOPER_ROOT}. Manually set CMAKE_IOS_SDK_ROOT or install the iOS SDK.") - endif (_CMAKE_IOS_SDKS) - message (STATUS "Toolchain using default iOS SDK: ${CMAKE_IOS_SDK_ROOT}") -endif (NOT DEFINED CMAKE_IOS_SDK_ROOT) -set (CMAKE_IOS_SDK_ROOT ${CMAKE_IOS_SDK_ROOT} CACHE PATH "Location of the selected iOS SDK") - -# Set the sysroot default to the most recent SDK -set (CMAKE_OSX_SYSROOT ${CMAKE_IOS_SDK_ROOT} CACHE PATH "Sysroot used for iOS support") - -# set the architecture for iOS -if (${IOS_PLATFORM} STREQUAL "OS") - set (IOS_ARCH armv7 armv7s arm64) -elseif (${IOS_PLATFORM} STREQUAL "SIMULATOR") - set (IOS_ARCH i386) -elseif (${IOS_PLATFORM} STREQUAL "SIMULATOR64") - set (IOS_ARCH x86_64) -endif (${IOS_PLATFORM} STREQUAL "OS") - -set (CMAKE_OSX_ARCHITECTURES ${IOS_ARCH} CACHE string "Build architecture for iOS") - -# Set the find root to the iOS developer roots and to user defined paths -set (CMAKE_FIND_ROOT_PATH ${CMAKE_IOS_DEVELOPER_ROOT} ${CMAKE_IOS_SDK_ROOT} ${CMAKE_PREFIX_PATH} CACHE string "iOS find search path root") - -# default to searching for frameworks first -set (CMAKE_FIND_FRAMEWORK FIRST) - -# set up the default search directories for frameworks -set (CMAKE_SYSTEM_FRAMEWORK_PATH - ${CMAKE_IOS_SDK_ROOT}/System/Library/Frameworks - ${CMAKE_IOS_SDK_ROOT}/System/Library/PrivateFrameworks - ${CMAKE_IOS_SDK_ROOT}/Developer/Library/Frameworks -) - -# only search the iOS sdks, not the remainder of the host filesystem -set (CMAKE_FIND_ROOT_PATH_MODE_PROGRAM ONLY) -set (CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) -set (CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) - - -# This little macro lets you set any XCode specific property -macro (set_xcode_property TARGET XCODE_PROPERTY XCODE_VALUE) - set_property (TARGET ${TARGET} PROPERTY XCODE_ATTRIBUTE_${XCODE_PROPERTY} ${XCODE_VALUE}) -endmacro (set_xcode_property) - - -# This macro lets you find executable programs on the host system -macro (find_host_package) - set (CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) - set (CMAKE_FIND_ROOT_PATH_MODE_LIBRARY NEVER) - set (CMAKE_FIND_ROOT_PATH_MODE_INCLUDE NEVER) - set (IOS FALSE) - - find_package(${ARGN}) - - set (IOS TRUE) - set (CMAKE_FIND_ROOT_PATH_MODE_PROGRAM ONLY) - set (CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) - set (CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) -endmacro (find_host_package) - diff --git a/Unity/Assets/Game/AbstractBaseBallScript.cs b/Unity/Assets/Game/AbstractBaseBallScript.cs deleted file mode 100644 index 8694d19..0000000 --- a/Unity/Assets/Game/AbstractBaseBallScript.cs +++ /dev/null @@ -1,19 +0,0 @@ -using UnityEngine; - -namespace MyGame -{ - /// - /// Base class of a script used in the example code to make a "ball" bounce - /// back and forth on the screen - /// - /// - /// Jackson Dunstan, 2018, http://JacksonDunstan.com - /// - /// - /// MIT - /// - public abstract class AbstractBaseBallScript : MonoBehaviour - { - public abstract void Update(); - } -} diff --git a/Unity/Assets/NativeScript.meta b/Unity/Assets/NativeScript.meta deleted file mode 100644 index 384196e..0000000 --- a/Unity/Assets/NativeScript.meta +++ /dev/null @@ -1,9 +0,0 @@ -fileFormatVersion: 2 -guid: dcdc7fc3d5ef84cfdb237d16ca0546ee -folderAsset: yes -timeCreated: 1501969758 -licenseType: Free -DefaultImporter: - userData: - assetBundleName: - assetBundleVariant: diff --git a/Unity/Assets/NativeScript/Bindings.cs b/Unity/Assets/NativeScript/Bindings.cs deleted file mode 100644 index 3ae570d..0000000 --- a/Unity/Assets/NativeScript/Bindings.cs +++ /dev/null @@ -1,2157 +0,0 @@ -using AOT; - -using System; -using System.Collections; -using System.IO; -using System.Runtime.InteropServices; -using System.Collections.Generic; - -using UnityEngine; - -namespace NativeScript -{ - /// - /// Internals of the bindings between native and .NET code. - /// Game code shouldn't go here. - /// - /// - /// Jackson Dunstan, 2017, http://JacksonDunstan.com - /// - /// - /// MIT - /// - public static class Bindings - { - // Holds objects and provides handles to them in the form of ints - public static class ObjectStore - { - // Lookup handles by object. - static Dictionary objectHandleCache; - - // Stored objects. The first is never used so 0 can be "null". - static object[] objects; - - // Stack of available handles. - static int[] handles; - - // Index of the next available handle - static int nextHandleIndex; - - // The maximum number of objects to store. Must be positive. - static int maxObjects; - - public static void Init(int maxObjects) - { - ObjectStore.maxObjects = maxObjects; - objectHandleCache = new Dictionary(maxObjects); - - // Initialize the objects as all null plus room for the - // first to always be null. - objects = new object[maxObjects + 1]; - - // Initialize the handles stack as 1, 2, 3, ... - handles = new int[maxObjects]; - for ( - int i = 0, handle = maxObjects; - i < maxObjects; - ++i, --handle) - { - handles[i] = handle; - } - nextHandleIndex = maxObjects - 1; - } - - public static int Store(object obj) - { - // Null is always zero - if (object.ReferenceEquals(obj, null)) - { - return 0; - } - - lock (objects) - { - // Pop a handle off the stack - int handle = handles[nextHandleIndex]; - nextHandleIndex--; - - // Store the object - objects[handle] = obj; - objectHandleCache.Add(obj, handle); - - return handle; - } - } - - public static object Get(int handle) - { - return objects[handle]; - } - - public static int GetHandle(object obj) - { - // Null is always zero - if (object.ReferenceEquals(obj, null)) - { - return 0; - } - - lock (objects) - { - int handle; - - // Get handle from object cache - if (objectHandleCache.TryGetValue(obj, out handle)) - { - return handle; - } - } - - // Object not found - return Store(obj); - } - - public static object Remove(int handle) - { - // Null is never stored, so there's nothing to remove - if (handle == 0) - { - return null; - } - - lock (objects) - { - // Forget the object - object obj = objects[handle]; - objects[handle] = null; - - // Push the handle onto the stack - nextHandleIndex++; - handles[nextHandleIndex] = handle; - - // Remove the object from the cache - objectHandleCache.Remove(obj); - - return obj; - } - } - } - - // Holds structs and provides handles to them in the form of ints - public static class StructStore - where T : struct - { - // Stored structs. The first is never used so 0 can be "null". - static T[] structs; - - // Stack of available handles - static int[] handles; - - // Index of the next available handle - static int nextHandleIndex; - - public static void Init(int maxStructs) - { - // Initialize the objects as all default plus room for the - // first to always be unused. - structs = new T[maxStructs + 1]; - - // Initialize the handles stack as 1, 2, 3, ... - handles = new int[maxStructs]; - for ( - int i = 0, handle = maxStructs; - i < maxStructs; - ++i, --handle) - { - handles[i] = handle; - } - nextHandleIndex = maxStructs - 1; - } - - public static int Store(T structToStore) - { - lock (structs) - { - // Pop a handle off the stack - int handle = handles[nextHandleIndex]; - nextHandleIndex--; - - // Store the struct - structs[handle] = structToStore; - - return handle; - } - } - - public static void Replace(int handle, ref T structToStore) - { - structs[handle] = structToStore; - } - - public static T Get(int handle) - { - return structs[handle]; - } - - public static void Remove(int handle) - { - if (handle != 0) - { - lock (structs) - { - // Forget the struct - structs[handle] = default(T); - - // Push the handle onto the stack - nextHandleIndex++; - handles[nextHandleIndex] = handle; - } - } - } - } - - /// - /// A reusable version of UnityEngine.WaitForSecondsRealtime to avoid - /// GC allocs - /// - class ReusableWaitForSecondsRealtime : CustomYieldInstruction - { - private float waitTime; - - public float WaitTime - { - set - { - waitTime = Time.realtimeSinceStartup + value; - } - } - - public override bool keepWaiting - { - get - { - return Time.realtimeSinceStartup < waitTime; - } - } - - public ReusableWaitForSecondsRealtime(float time) - { - WaitTime = time; - } - } - - public enum DestroyFunction - { - /*BEGIN DESTROY FUNCTION ENUMERATORS*/ - BaseBallScript - /*END DESTROY FUNCTION ENUMERATORS*/ - } - - struct DestroyEntry - { - public DestroyFunction Function; - public int CppHandle; - - public DestroyEntry(DestroyFunction function, int cppHandle) - { - Function = function; - CppHandle = cppHandle; - } - } - - // Name of the plugin when using [DllImport] -#if !UNITY_EDITOR && UNITY_IOS - const string PLUGIN_NAME = "__Internal"; -#else - const string PLUGIN_NAME = "NativeScript"; -#endif - - // Path to load the plugin from when running inside the editor -#if UNITY_EDITOR_OSX - const string PLUGIN_PATH = "/Plugins/Editor/NativeScript.bundle/Contents/MacOS/NativeScript"; -#elif UNITY_EDITOR_LINUX - const string PLUGIN_PATH = "/Plugins/Editor/libNativeScript.so"; -#elif UNITY_EDITOR_WIN - const string PLUGIN_PATH = "/Plugins/Editor/NativeScript.dll"; - const string PLUGIN_TEMP_PATH = "/Plugins/Editor/NativeScript_temp.dll"; -#endif - - enum InitMode : byte - { - FirstBoot, - Reload - } - -#if UNITY_EDITOR - // Handle to the C++ DLL - static IntPtr libraryHandle; - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - delegate void InitDelegate( - IntPtr memory, - int memorySize, - InitMode initMode); - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate void SetCsharpExceptionDelegate(int handle); - - /*BEGIN CPP DELEGATES*/ - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate int NewBaseBallScriptDelegateType(int param0); - public static NewBaseBallScriptDelegateType NewBaseBallScript; - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate void DestroyBaseBallScriptDelegateType(int param0); - public static DestroyBaseBallScriptDelegateType DestroyBaseBallScript; - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate void MyGameAbstractBaseBallScriptUpdateDelegateType(int thisHandle); - public static MyGameAbstractBaseBallScriptUpdateDelegateType MyGameAbstractBaseBallScriptUpdate; - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate void SetCsharpExceptionSystemNullReferenceExceptionDelegateType(int param0); - public static SetCsharpExceptionSystemNullReferenceExceptionDelegateType SetCsharpExceptionSystemNullReferenceException; - /*END CPP DELEGATES*/ -#endif - -#if UNITY_EDITOR_OSX || UNITY_EDITOR_LINUX - [DllImport("__Internal", CallingConvention = CallingConvention.Cdecl)] - static extern IntPtr dlopen( - string path, - int flag); - - [DllImport("__Internal", CallingConvention = CallingConvention.Cdecl)] - static extern IntPtr dlsym( - IntPtr handle, - string symbolName); - - [DllImport("__Internal", CallingConvention = CallingConvention.Cdecl)] - static extern int dlclose( - IntPtr handle); - - static IntPtr OpenLibrary( - string path) - { - IntPtr handle = dlopen(path, 1); // 1 = lazy, 2 = now - if (handle == IntPtr.Zero) - { - throw new Exception("Couldn't open native library: " + path); - } - return handle; - } - - static void CloseLibrary( - IntPtr libraryHandle) - { - dlclose(libraryHandle); - } - - static T GetDelegate( - IntPtr libraryHandle, - string functionName) where T : class - { - IntPtr symbol = dlsym(libraryHandle, functionName); - if (symbol == IntPtr.Zero) - { - throw new Exception("Couldn't get function: " + functionName); - } - return Marshal.GetDelegateForFunctionPointer( - symbol, - typeof(T)) as T; - } -#elif UNITY_EDITOR_WIN - [DllImport("kernel32", SetLastError=true, CharSet = CharSet.Ansi)] - static extern IntPtr LoadLibrary( - string path); - - [DllImport("kernel32", CharSet=CharSet.Ansi, ExactSpelling=true, SetLastError=true)] - static extern IntPtr GetProcAddress( - IntPtr libraryHandle, - string symbolName); - - [DllImport("kernel32.dll", SetLastError=true)] - static extern bool FreeLibrary( - IntPtr libraryHandle); - - static IntPtr OpenLibrary(string path) - { - IntPtr handle = LoadLibrary(path); - if (handle == IntPtr.Zero) - { - throw new Exception("Couldn't open native library: " + path); - } - return handle; - } - - static void CloseLibrary(IntPtr libraryHandle) - { - FreeLibrary(libraryHandle); - } - - static T GetDelegate( - IntPtr libraryHandle, - string functionName) where T : class - { - IntPtr symbol = GetProcAddress(libraryHandle, functionName); - if (symbol == IntPtr.Zero) - { - throw new Exception("Couldn't get function: " + functionName); - } - return Marshal.GetDelegateForFunctionPointer( - symbol, - typeof(T)) as T; - } -#else - [DllImport(PLUGIN_NAME, CallingConvention = CallingConvention.Cdecl)] - static extern void Init( - IntPtr memory, - int memorySize, - InitMode initMode); - - [DllImport(PLUGIN_NAME, CallingConvention = CallingConvention.Cdecl)] - static extern void SetCsharpException(int handle); - - /*BEGIN IMPORTS*/ - [DllImport(PLUGIN_NAME, CallingConvention = CallingConvention.Cdecl)] - public static extern int NewBaseBallScript(int thisHandle); - - [DllImport(PLUGIN_NAME, CallingConvention = CallingConvention.Cdecl)] - public static extern void DestroyBaseBallScript(int thisHandle); - - [DllImport(PLUGIN_NAME, CallingConvention = CallingConvention.Cdecl)] - public static extern void MyGameAbstractBaseBallScriptUpdate(int thisHandle); - - [DllImport(PLUGIN_NAME, CallingConvention = CallingConvention.Cdecl)] - public static extern void SetCsharpExceptionSystemNullReferenceException(int thisHandle); - /*END IMPORTS*/ -#endif - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - delegate void ReleaseObjectDelegateType(int handle); - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - delegate int StringNewDelegateType(string chars); - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - delegate void SetExceptionDelegateType(int handle); - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - delegate int ArrayGetLengthDelegateType(int handle); - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - delegate int EnumerableGetEnumeratorDelegateType(int handle); - - /*BEGIN DELEGATE TYPES*/ - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - delegate void ReleaseSystemDecimalDelegateType(int handle); - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - delegate int SystemDecimalConstructorSystemDoubleDelegateType(double value); - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - delegate int SystemDecimalConstructorSystemUInt64DelegateType(ulong value); - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - delegate int BoxDecimalDelegateType(int valHandle); - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - delegate int UnboxDecimalDelegateType(int valHandle); - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - delegate UnityEngine.Vector3 UnityEngineVector3ConstructorSystemSingle_SystemSingle_SystemSingleDelegateType(float x, float y, float z); - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - delegate UnityEngine.Vector3 UnityEngineVector3Methodop_AdditionUnityEngineVector3_UnityEngineVector3DelegateType(ref UnityEngine.Vector3 a, ref UnityEngine.Vector3 b); - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - delegate int BoxVector3DelegateType(ref UnityEngine.Vector3 val); - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - delegate UnityEngine.Vector3 UnboxVector3DelegateType(int valHandle); - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - delegate int UnityEngineObjectPropertyGetNameDelegateType(int thisHandle); - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - delegate void UnityEngineObjectPropertySetNameDelegateType(int thisHandle, int valueHandle); - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - delegate int UnityEngineComponentPropertyGetTransformDelegateType(int thisHandle); - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - delegate UnityEngine.Vector3 UnityEngineTransformPropertyGetPositionDelegateType(int thisHandle); - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - delegate void UnityEngineTransformPropertySetPositionDelegateType(int thisHandle, ref UnityEngine.Vector3 value); - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - delegate int SystemCollectionsIEnumeratorPropertyGetCurrentDelegateType(int thisHandle); - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - delegate bool SystemCollectionsIEnumeratorMethodMoveNextDelegateType(int thisHandle); - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - delegate int UnityEngineGameObjectMethodAddComponentMyGameBaseBallScriptDelegateType(int thisHandle); - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - delegate int UnityEngineGameObjectMethodCreatePrimitiveUnityEnginePrimitiveTypeDelegateType(UnityEngine.PrimitiveType type); - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - delegate void UnityEngineDebugMethodLogSystemObjectDelegateType(int messageHandle); - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - delegate int UnityEngineMonoBehaviourPropertyGetTransformDelegateType(int thisHandle); - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - delegate int SystemExceptionConstructorSystemStringDelegateType(int messageHandle); - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - delegate int BoxPrimitiveTypeDelegateType(UnityEngine.PrimitiveType val); - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - delegate UnityEngine.PrimitiveType UnboxPrimitiveTypeDelegateType(int valHandle); - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - delegate float UnityEngineTimePropertyGetDeltaTimeDelegateType(); - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - delegate void BaseBallScriptConstructorDelegateType(int cppHandle, ref int handle); - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - delegate void ReleaseBaseBallScriptDelegateType(int handle); - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - delegate int BoxBooleanDelegateType(bool val); - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - delegate bool UnboxBooleanDelegateType(int valHandle); - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - delegate int BoxSByteDelegateType(sbyte val); - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - delegate sbyte UnboxSByteDelegateType(int valHandle); - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - delegate int BoxByteDelegateType(byte val); - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - delegate byte UnboxByteDelegateType(int valHandle); - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - delegate int BoxInt16DelegateType(short val); - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - delegate short UnboxInt16DelegateType(int valHandle); - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - delegate int BoxUInt16DelegateType(ushort val); - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - delegate ushort UnboxUInt16DelegateType(int valHandle); - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - delegate int BoxInt32DelegateType(int val); - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - delegate int UnboxInt32DelegateType(int valHandle); - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - delegate int BoxUInt32DelegateType(uint val); - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - delegate uint UnboxUInt32DelegateType(int valHandle); - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - delegate int BoxInt64DelegateType(long val); - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - delegate long UnboxInt64DelegateType(int valHandle); - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - delegate int BoxUInt64DelegateType(ulong val); - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - delegate ulong UnboxUInt64DelegateType(int valHandle); - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - delegate int BoxCharDelegateType(char val); - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - delegate char UnboxCharDelegateType(int valHandle); - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - delegate int BoxSingleDelegateType(float val); - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - delegate float UnboxSingleDelegateType(int valHandle); - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - delegate int BoxDoubleDelegateType(double val); - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - delegate double UnboxDoubleDelegateType(int valHandle); - /*END DELEGATE TYPES*/ - -#if UNITY_EDITOR_WIN - private static readonly string pluginTempPath = Application.dataPath + PLUGIN_TEMP_PATH; -#endif - public static Exception UnhandledCppException; -#if UNITY_EDITOR - private static readonly string pluginPath = Application.dataPath + PLUGIN_PATH; - public static SetCsharpExceptionDelegate SetCsharpException; -#endif - static IntPtr memory; - static int memorySize; - static DestroyEntry[] destroyQueue; - static int destroyQueueCount; - static int destroyQueueCapacity; - static object destroyQueueLockObj; - - // Fixed delegates - static readonly ReleaseObjectDelegateType ReleaseObjectDelegate = new ReleaseObjectDelegateType(ReleaseObject); - static readonly StringNewDelegateType StringNewDelegate = new StringNewDelegateType(StringNew); - static readonly SetExceptionDelegateType SetExceptionDelegate = new SetExceptionDelegateType(SetException); - static readonly ArrayGetLengthDelegateType ArrayGetLengthDelegate = new ArrayGetLengthDelegateType(ArrayGetLength); - static readonly EnumerableGetEnumeratorDelegateType EnumerableGetEnumeratorDelegate = new EnumerableGetEnumeratorDelegateType(EnumerableGetEnumerator); - - // Generated delegates - /*BEGIN CSHARP DELEGATES*/ - static readonly ReleaseSystemDecimalDelegateType ReleaseSystemDecimalDelegate = new ReleaseSystemDecimalDelegateType(ReleaseSystemDecimal); - static readonly SystemDecimalConstructorSystemDoubleDelegateType SystemDecimalConstructorSystemDoubleDelegate = new SystemDecimalConstructorSystemDoubleDelegateType(SystemDecimalConstructorSystemDouble); - static readonly SystemDecimalConstructorSystemUInt64DelegateType SystemDecimalConstructorSystemUInt64Delegate = new SystemDecimalConstructorSystemUInt64DelegateType(SystemDecimalConstructorSystemUInt64); - static readonly BoxDecimalDelegateType BoxDecimalDelegate = new BoxDecimalDelegateType(BoxDecimal); - static readonly UnboxDecimalDelegateType UnboxDecimalDelegate = new UnboxDecimalDelegateType(UnboxDecimal); - static readonly UnityEngineVector3ConstructorSystemSingle_SystemSingle_SystemSingleDelegateType UnityEngineVector3ConstructorSystemSingle_SystemSingle_SystemSingleDelegate = new UnityEngineVector3ConstructorSystemSingle_SystemSingle_SystemSingleDelegateType(UnityEngineVector3ConstructorSystemSingle_SystemSingle_SystemSingle); - static readonly UnityEngineVector3Methodop_AdditionUnityEngineVector3_UnityEngineVector3DelegateType UnityEngineVector3Methodop_AdditionUnityEngineVector3_UnityEngineVector3Delegate = new UnityEngineVector3Methodop_AdditionUnityEngineVector3_UnityEngineVector3DelegateType(UnityEngineVector3Methodop_AdditionUnityEngineVector3_UnityEngineVector3); - static readonly BoxVector3DelegateType BoxVector3Delegate = new BoxVector3DelegateType(BoxVector3); - static readonly UnboxVector3DelegateType UnboxVector3Delegate = new UnboxVector3DelegateType(UnboxVector3); - static readonly UnityEngineObjectPropertyGetNameDelegateType UnityEngineObjectPropertyGetNameDelegate = new UnityEngineObjectPropertyGetNameDelegateType(UnityEngineObjectPropertyGetName); - static readonly UnityEngineObjectPropertySetNameDelegateType UnityEngineObjectPropertySetNameDelegate = new UnityEngineObjectPropertySetNameDelegateType(UnityEngineObjectPropertySetName); - static readonly UnityEngineComponentPropertyGetTransformDelegateType UnityEngineComponentPropertyGetTransformDelegate = new UnityEngineComponentPropertyGetTransformDelegateType(UnityEngineComponentPropertyGetTransform); - static readonly UnityEngineTransformPropertyGetPositionDelegateType UnityEngineTransformPropertyGetPositionDelegate = new UnityEngineTransformPropertyGetPositionDelegateType(UnityEngineTransformPropertyGetPosition); - static readonly UnityEngineTransformPropertySetPositionDelegateType UnityEngineTransformPropertySetPositionDelegate = new UnityEngineTransformPropertySetPositionDelegateType(UnityEngineTransformPropertySetPosition); - static readonly SystemCollectionsIEnumeratorPropertyGetCurrentDelegateType SystemCollectionsIEnumeratorPropertyGetCurrentDelegate = new SystemCollectionsIEnumeratorPropertyGetCurrentDelegateType(SystemCollectionsIEnumeratorPropertyGetCurrent); - static readonly SystemCollectionsIEnumeratorMethodMoveNextDelegateType SystemCollectionsIEnumeratorMethodMoveNextDelegate = new SystemCollectionsIEnumeratorMethodMoveNextDelegateType(SystemCollectionsIEnumeratorMethodMoveNext); - static readonly UnityEngineGameObjectMethodAddComponentMyGameBaseBallScriptDelegateType UnityEngineGameObjectMethodAddComponentMyGameBaseBallScriptDelegate = new UnityEngineGameObjectMethodAddComponentMyGameBaseBallScriptDelegateType(UnityEngineGameObjectMethodAddComponentMyGameBaseBallScript); - static readonly UnityEngineGameObjectMethodCreatePrimitiveUnityEnginePrimitiveTypeDelegateType UnityEngineGameObjectMethodCreatePrimitiveUnityEnginePrimitiveTypeDelegate = new UnityEngineGameObjectMethodCreatePrimitiveUnityEnginePrimitiveTypeDelegateType(UnityEngineGameObjectMethodCreatePrimitiveUnityEnginePrimitiveType); - static readonly UnityEngineDebugMethodLogSystemObjectDelegateType UnityEngineDebugMethodLogSystemObjectDelegate = new UnityEngineDebugMethodLogSystemObjectDelegateType(UnityEngineDebugMethodLogSystemObject); - static readonly UnityEngineMonoBehaviourPropertyGetTransformDelegateType UnityEngineMonoBehaviourPropertyGetTransformDelegate = new UnityEngineMonoBehaviourPropertyGetTransformDelegateType(UnityEngineMonoBehaviourPropertyGetTransform); - static readonly SystemExceptionConstructorSystemStringDelegateType SystemExceptionConstructorSystemStringDelegate = new SystemExceptionConstructorSystemStringDelegateType(SystemExceptionConstructorSystemString); - static readonly BoxPrimitiveTypeDelegateType BoxPrimitiveTypeDelegate = new BoxPrimitiveTypeDelegateType(BoxPrimitiveType); - static readonly UnboxPrimitiveTypeDelegateType UnboxPrimitiveTypeDelegate = new UnboxPrimitiveTypeDelegateType(UnboxPrimitiveType); - static readonly UnityEngineTimePropertyGetDeltaTimeDelegateType UnityEngineTimePropertyGetDeltaTimeDelegate = new UnityEngineTimePropertyGetDeltaTimeDelegateType(UnityEngineTimePropertyGetDeltaTime); - static readonly ReleaseBaseBallScriptDelegateType ReleaseBaseBallScriptDelegate = new ReleaseBaseBallScriptDelegateType(ReleaseBaseBallScript); - static readonly BaseBallScriptConstructorDelegateType BaseBallScriptConstructorDelegate = new BaseBallScriptConstructorDelegateType(BaseBallScriptConstructor); - static readonly BoxBooleanDelegateType BoxBooleanDelegate = new BoxBooleanDelegateType(BoxBoolean); - static readonly UnboxBooleanDelegateType UnboxBooleanDelegate = new UnboxBooleanDelegateType(UnboxBoolean); - static readonly BoxSByteDelegateType BoxSByteDelegate = new BoxSByteDelegateType(BoxSByte); - static readonly UnboxSByteDelegateType UnboxSByteDelegate = new UnboxSByteDelegateType(UnboxSByte); - static readonly BoxByteDelegateType BoxByteDelegate = new BoxByteDelegateType(BoxByte); - static readonly UnboxByteDelegateType UnboxByteDelegate = new UnboxByteDelegateType(UnboxByte); - static readonly BoxInt16DelegateType BoxInt16Delegate = new BoxInt16DelegateType(BoxInt16); - static readonly UnboxInt16DelegateType UnboxInt16Delegate = new UnboxInt16DelegateType(UnboxInt16); - static readonly BoxUInt16DelegateType BoxUInt16Delegate = new BoxUInt16DelegateType(BoxUInt16); - static readonly UnboxUInt16DelegateType UnboxUInt16Delegate = new UnboxUInt16DelegateType(UnboxUInt16); - static readonly BoxInt32DelegateType BoxInt32Delegate = new BoxInt32DelegateType(BoxInt32); - static readonly UnboxInt32DelegateType UnboxInt32Delegate = new UnboxInt32DelegateType(UnboxInt32); - static readonly BoxUInt32DelegateType BoxUInt32Delegate = new BoxUInt32DelegateType(BoxUInt32); - static readonly UnboxUInt32DelegateType UnboxUInt32Delegate = new UnboxUInt32DelegateType(UnboxUInt32); - static readonly BoxInt64DelegateType BoxInt64Delegate = new BoxInt64DelegateType(BoxInt64); - static readonly UnboxInt64DelegateType UnboxInt64Delegate = new UnboxInt64DelegateType(UnboxInt64); - static readonly BoxUInt64DelegateType BoxUInt64Delegate = new BoxUInt64DelegateType(BoxUInt64); - static readonly UnboxUInt64DelegateType UnboxUInt64Delegate = new UnboxUInt64DelegateType(UnboxUInt64); - static readonly BoxCharDelegateType BoxCharDelegate = new BoxCharDelegateType(BoxChar); - static readonly UnboxCharDelegateType UnboxCharDelegate = new UnboxCharDelegateType(UnboxChar); - static readonly BoxSingleDelegateType BoxSingleDelegate = new BoxSingleDelegateType(BoxSingle); - static readonly UnboxSingleDelegateType UnboxSingleDelegate = new UnboxSingleDelegateType(UnboxSingle); - static readonly BoxDoubleDelegateType BoxDoubleDelegate = new BoxDoubleDelegateType(BoxDouble); - static readonly UnboxDoubleDelegateType UnboxDoubleDelegate = new UnboxDoubleDelegateType(UnboxDouble); - /*END CSHARP DELEGATES*/ - - /// - /// Open the C++ plugin and call its PluginMain() - /// - /// - /// - /// Number of bytes of memory to make available to the C++ plugin - /// - public static void Open(int memorySize) - { - /*BEGIN STORE INIT CALLS*/ - NativeScript.Bindings.ObjectStore.Init(1000); - NativeScript.Bindings.StructStore.Init(1000); - /*END STORE INIT CALLS*/ - - // Allocate unmanaged memory - Bindings.memorySize = memorySize; - memory = Marshal.AllocHGlobal(memorySize); - - // Allocate destroy queue - destroyQueueCapacity = 128; - destroyQueue = new DestroyEntry[destroyQueueCapacity]; - destroyQueueLockObj = new object(); - - OpenPlugin(InitMode.FirstBoot); - } - - // Reloading requires dynamic loading of the C++ plugin, which is only - // available in the editor -#if UNITY_EDITOR - /// - /// Reload the C++ plugin. Its memory is intact and false is passed for - /// the isFirstBoot parameter of PluginMain(). - /// - public static void Reload() - { - DestroyAll(); - ClosePlugin(); - OpenPlugin(InitMode.Reload); - } - - /// - /// Poll the plugin for changes and reload if any are found. - /// - /// - /// - /// Number of seconds between polls. - /// - /// - /// - /// Enumerator for this iterator function. Can be passed to - /// MonoBehaviour.StartCoroutine for easy usage. - /// - public static IEnumerator AutoReload(float pollTime) - { - // Get the original time - long lastWriteTime = File.GetLastWriteTime(pluginPath).Ticks; - - ReusableWaitForSecondsRealtime poll - = new ReusableWaitForSecondsRealtime(pollTime); - do - { - // Poll. Reload if the last write time changed. - long cur = File.GetLastWriteTime(pluginPath).Ticks; - if (cur != lastWriteTime) - { - lastWriteTime = cur; - Reload(); - } - - // Wait to poll again - poll.WaitTime = pollTime; - yield return poll; - } - while (true); - } -#endif - - private static void OpenPlugin(InitMode initMode) - { -#if UNITY_EDITOR - string loadPath; -#if UNITY_EDITOR_WIN - // Copy native library to temporary file - File.Copy(pluginPath, pluginTempPath, true); - loadPath = pluginTempPath; -#else - loadPath = pluginPath; -#endif - // Open native library - libraryHandle = OpenLibrary(loadPath); - InitDelegate Init = GetDelegate( - libraryHandle, - "Init"); - SetCsharpException = GetDelegate( - libraryHandle, - "SetCsharpException"); - /*BEGIN GETDELEGATE CALLS*/ - NewBaseBallScript = GetDelegate(libraryHandle, "NewBaseBallScript"); - DestroyBaseBallScript = GetDelegate(libraryHandle, "DestroyBaseBallScript"); - MyGameAbstractBaseBallScriptUpdate = GetDelegate(libraryHandle, "MyGameAbstractBaseBallScriptUpdate"); - SetCsharpExceptionSystemNullReferenceException = GetDelegate(libraryHandle, "SetCsharpExceptionSystemNullReferenceException"); - /*END GETDELEGATE CALLS*/ -#endif - // Pass parameters through 'memory' - int curMemory = 0; - Marshal.WriteIntPtr( - memory, - curMemory, - Marshal.GetFunctionPointerForDelegate(ReleaseObjectDelegate)); - curMemory += IntPtr.Size; - Marshal.WriteIntPtr( - memory, - curMemory, - Marshal.GetFunctionPointerForDelegate(StringNewDelegate)); - curMemory += IntPtr.Size; - Marshal.WriteIntPtr( - memory, - curMemory, - Marshal.GetFunctionPointerForDelegate(SetExceptionDelegate)); - curMemory += IntPtr.Size; - Marshal.WriteIntPtr( - memory, - curMemory, - Marshal.GetFunctionPointerForDelegate(ArrayGetLengthDelegate)); - curMemory += IntPtr.Size; - Marshal.WriteIntPtr( - memory, - curMemory, - Marshal.GetFunctionPointerForDelegate(EnumerableGetEnumeratorDelegate)); - curMemory += IntPtr.Size; - - /*BEGIN INIT CALL*/ - Marshal.WriteInt32(memory, curMemory, 1000); // max managed objects - curMemory += sizeof(int); - Marshal.WriteIntPtr(memory, curMemory, Marshal.GetFunctionPointerForDelegate(ReleaseSystemDecimalDelegate)); - curMemory += IntPtr.Size; - Marshal.WriteIntPtr(memory, curMemory, Marshal.GetFunctionPointerForDelegate(SystemDecimalConstructorSystemDoubleDelegate)); - curMemory += IntPtr.Size; - Marshal.WriteIntPtr(memory, curMemory, Marshal.GetFunctionPointerForDelegate(SystemDecimalConstructorSystemUInt64Delegate)); - curMemory += IntPtr.Size; - Marshal.WriteIntPtr(memory, curMemory, Marshal.GetFunctionPointerForDelegate(BoxDecimalDelegate)); - curMemory += IntPtr.Size; - Marshal.WriteIntPtr(memory, curMemory, Marshal.GetFunctionPointerForDelegate(UnboxDecimalDelegate)); - curMemory += IntPtr.Size; - Marshal.WriteIntPtr(memory, curMemory, Marshal.GetFunctionPointerForDelegate(UnityEngineVector3ConstructorSystemSingle_SystemSingle_SystemSingleDelegate)); - curMemory += IntPtr.Size; - Marshal.WriteIntPtr(memory, curMemory, Marshal.GetFunctionPointerForDelegate(UnityEngineVector3Methodop_AdditionUnityEngineVector3_UnityEngineVector3Delegate)); - curMemory += IntPtr.Size; - Marshal.WriteIntPtr(memory, curMemory, Marshal.GetFunctionPointerForDelegate(BoxVector3Delegate)); - curMemory += IntPtr.Size; - Marshal.WriteIntPtr(memory, curMemory, Marshal.GetFunctionPointerForDelegate(UnboxVector3Delegate)); - curMemory += IntPtr.Size; - Marshal.WriteIntPtr(memory, curMemory, Marshal.GetFunctionPointerForDelegate(UnityEngineObjectPropertyGetNameDelegate)); - curMemory += IntPtr.Size; - Marshal.WriteIntPtr(memory, curMemory, Marshal.GetFunctionPointerForDelegate(UnityEngineObjectPropertySetNameDelegate)); - curMemory += IntPtr.Size; - Marshal.WriteIntPtr(memory, curMemory, Marshal.GetFunctionPointerForDelegate(UnityEngineComponentPropertyGetTransformDelegate)); - curMemory += IntPtr.Size; - Marshal.WriteIntPtr(memory, curMemory, Marshal.GetFunctionPointerForDelegate(UnityEngineTransformPropertyGetPositionDelegate)); - curMemory += IntPtr.Size; - Marshal.WriteIntPtr(memory, curMemory, Marshal.GetFunctionPointerForDelegate(UnityEngineTransformPropertySetPositionDelegate)); - curMemory += IntPtr.Size; - Marshal.WriteIntPtr(memory, curMemory, Marshal.GetFunctionPointerForDelegate(SystemCollectionsIEnumeratorPropertyGetCurrentDelegate)); - curMemory += IntPtr.Size; - Marshal.WriteIntPtr(memory, curMemory, Marshal.GetFunctionPointerForDelegate(SystemCollectionsIEnumeratorMethodMoveNextDelegate)); - curMemory += IntPtr.Size; - Marshal.WriteIntPtr(memory, curMemory, Marshal.GetFunctionPointerForDelegate(UnityEngineGameObjectMethodAddComponentMyGameBaseBallScriptDelegate)); - curMemory += IntPtr.Size; - Marshal.WriteIntPtr(memory, curMemory, Marshal.GetFunctionPointerForDelegate(UnityEngineGameObjectMethodCreatePrimitiveUnityEnginePrimitiveTypeDelegate)); - curMemory += IntPtr.Size; - Marshal.WriteIntPtr(memory, curMemory, Marshal.GetFunctionPointerForDelegate(UnityEngineDebugMethodLogSystemObjectDelegate)); - curMemory += IntPtr.Size; - Marshal.WriteIntPtr(memory, curMemory, Marshal.GetFunctionPointerForDelegate(UnityEngineMonoBehaviourPropertyGetTransformDelegate)); - curMemory += IntPtr.Size; - Marshal.WriteIntPtr(memory, curMemory, Marshal.GetFunctionPointerForDelegate(SystemExceptionConstructorSystemStringDelegate)); - curMemory += IntPtr.Size; - Marshal.WriteIntPtr(memory, curMemory, Marshal.GetFunctionPointerForDelegate(BoxPrimitiveTypeDelegate)); - curMemory += IntPtr.Size; - Marshal.WriteIntPtr(memory, curMemory, Marshal.GetFunctionPointerForDelegate(UnboxPrimitiveTypeDelegate)); - curMemory += IntPtr.Size; - Marshal.WriteIntPtr(memory, curMemory, Marshal.GetFunctionPointerForDelegate(UnityEngineTimePropertyGetDeltaTimeDelegate)); - curMemory += IntPtr.Size; - Marshal.WriteIntPtr(memory, curMemory, Marshal.GetFunctionPointerForDelegate(ReleaseBaseBallScriptDelegate)); - curMemory += IntPtr.Size; - Marshal.WriteIntPtr(memory, curMemory, Marshal.GetFunctionPointerForDelegate(BaseBallScriptConstructorDelegate)); - curMemory += IntPtr.Size; - Marshal.WriteIntPtr(memory, curMemory, Marshal.GetFunctionPointerForDelegate(BoxBooleanDelegate)); - curMemory += IntPtr.Size; - Marshal.WriteIntPtr(memory, curMemory, Marshal.GetFunctionPointerForDelegate(UnboxBooleanDelegate)); - curMemory += IntPtr.Size; - Marshal.WriteIntPtr(memory, curMemory, Marshal.GetFunctionPointerForDelegate(BoxSByteDelegate)); - curMemory += IntPtr.Size; - Marshal.WriteIntPtr(memory, curMemory, Marshal.GetFunctionPointerForDelegate(UnboxSByteDelegate)); - curMemory += IntPtr.Size; - Marshal.WriteIntPtr(memory, curMemory, Marshal.GetFunctionPointerForDelegate(BoxByteDelegate)); - curMemory += IntPtr.Size; - Marshal.WriteIntPtr(memory, curMemory, Marshal.GetFunctionPointerForDelegate(UnboxByteDelegate)); - curMemory += IntPtr.Size; - Marshal.WriteIntPtr(memory, curMemory, Marshal.GetFunctionPointerForDelegate(BoxInt16Delegate)); - curMemory += IntPtr.Size; - Marshal.WriteIntPtr(memory, curMemory, Marshal.GetFunctionPointerForDelegate(UnboxInt16Delegate)); - curMemory += IntPtr.Size; - Marshal.WriteIntPtr(memory, curMemory, Marshal.GetFunctionPointerForDelegate(BoxUInt16Delegate)); - curMemory += IntPtr.Size; - Marshal.WriteIntPtr(memory, curMemory, Marshal.GetFunctionPointerForDelegate(UnboxUInt16Delegate)); - curMemory += IntPtr.Size; - Marshal.WriteIntPtr(memory, curMemory, Marshal.GetFunctionPointerForDelegate(BoxInt32Delegate)); - curMemory += IntPtr.Size; - Marshal.WriteIntPtr(memory, curMemory, Marshal.GetFunctionPointerForDelegate(UnboxInt32Delegate)); - curMemory += IntPtr.Size; - Marshal.WriteIntPtr(memory, curMemory, Marshal.GetFunctionPointerForDelegate(BoxUInt32Delegate)); - curMemory += IntPtr.Size; - Marshal.WriteIntPtr(memory, curMemory, Marshal.GetFunctionPointerForDelegate(UnboxUInt32Delegate)); - curMemory += IntPtr.Size; - Marshal.WriteIntPtr(memory, curMemory, Marshal.GetFunctionPointerForDelegate(BoxInt64Delegate)); - curMemory += IntPtr.Size; - Marshal.WriteIntPtr(memory, curMemory, Marshal.GetFunctionPointerForDelegate(UnboxInt64Delegate)); - curMemory += IntPtr.Size; - Marshal.WriteIntPtr(memory, curMemory, Marshal.GetFunctionPointerForDelegate(BoxUInt64Delegate)); - curMemory += IntPtr.Size; - Marshal.WriteIntPtr(memory, curMemory, Marshal.GetFunctionPointerForDelegate(UnboxUInt64Delegate)); - curMemory += IntPtr.Size; - Marshal.WriteIntPtr(memory, curMemory, Marshal.GetFunctionPointerForDelegate(BoxCharDelegate)); - curMemory += IntPtr.Size; - Marshal.WriteIntPtr(memory, curMemory, Marshal.GetFunctionPointerForDelegate(UnboxCharDelegate)); - curMemory += IntPtr.Size; - Marshal.WriteIntPtr(memory, curMemory, Marshal.GetFunctionPointerForDelegate(BoxSingleDelegate)); - curMemory += IntPtr.Size; - Marshal.WriteIntPtr(memory, curMemory, Marshal.GetFunctionPointerForDelegate(UnboxSingleDelegate)); - curMemory += IntPtr.Size; - Marshal.WriteIntPtr(memory, curMemory, Marshal.GetFunctionPointerForDelegate(BoxDoubleDelegate)); - curMemory += IntPtr.Size; - Marshal.WriteIntPtr(memory, curMemory, Marshal.GetFunctionPointerForDelegate(UnboxDoubleDelegate)); - curMemory += IntPtr.Size; - /*END INIT CALL*/ - - // Init C++ library - Init(memory, memorySize, initMode); - if (UnhandledCppException != null) - { - Exception ex = UnhandledCppException; - UnhandledCppException = null; - throw new Exception("Unhandled C++ exception in Init", ex); - } - } - - /// - /// Close the C++ plugin - /// - public static void Close() - { - ClosePlugin(); - Marshal.FreeHGlobal(memory); - memory = IntPtr.Zero; - } - - /// - /// Perform updates over time - /// - public static void Update() - { - DestroyAll(); - } - - private static void ClosePlugin() - { -#if UNITY_EDITOR - CloseLibrary(libraryHandle); - libraryHandle = IntPtr.Zero; -#endif -#if UNITY_EDITOR_WIN - File.Delete(pluginTempPath); -#endif - } - - public static void QueueDestroy(DestroyFunction function, int cppHandle) - { - lock (destroyQueueLockObj) - { - // Grow capacity if necessary - int count = destroyQueueCount; - int capacity = destroyQueueCapacity; - DestroyEntry[] queue = destroyQueue; - if (count == capacity) - { - int newCapacity = capacity * 2; - DestroyEntry[] newQueue = new DestroyEntry[newCapacity]; - for (int i = 0; i < capacity; ++i) - { - newQueue[i] = queue[i]; - } - destroyQueueCapacity = newCapacity; - destroyQueue = newQueue; - queue = newQueue; - } - - // Add to the end - queue[count] = new DestroyEntry(function, cppHandle); - destroyQueueCount = count + 1; - } - } - - static void DestroyAll() - { - lock (destroyQueueLockObj) - { - int count = destroyQueueCount; - DestroyEntry[] queue = destroyQueue; - for (int i = 0; i < count; ++i) - { - DestroyEntry entry = queue[i]; - switch (entry.Function) - { - /*BEGIN DESTROY QUEUE CASES*/ - case DestroyFunction.BaseBallScript: - DestroyBaseBallScript(entry.CppHandle); - break; - /*END DESTROY QUEUE CASES*/ - } - } - destroyQueueCount = 0; - } - } - - //////////////////////////////////////////////////////////////// - // C# functions for C++ to call - //////////////////////////////////////////////////////////////// - - [MonoPInvokeCallback(typeof(ReleaseObjectDelegateType))] - static void ReleaseObject( - int handle) - { - if (handle != 0) - { - ObjectStore.Remove(handle); - } - } - - [MonoPInvokeCallback(typeof(StringNewDelegateType))] - static int StringNew( - string chars) - { - int handle = ObjectStore.Store(chars); - return handle; - } - - [MonoPInvokeCallback(typeof(SetExceptionDelegateType))] - static void SetException(int handle) - { - UnhandledCppException = ObjectStore.Get(handle) as Exception; - } - - [MonoPInvokeCallback(typeof(ArrayGetLengthDelegateType))] - static int ArrayGetLength(int handle) - { - return ((Array)ObjectStore.Get(handle)).Length; - } - - [MonoPInvokeCallback(typeof(EnumerableGetEnumeratorDelegateType))] - static int EnumerableGetEnumerator(int handle) - { - return ObjectStore.Store(((IEnumerable)ObjectStore.Get(handle)).GetEnumerator()); - } - - /*BEGIN FUNCTIONS*/ - [MonoPInvokeCallback(typeof(ReleaseSystemDecimalDelegateType))] - static void ReleaseSystemDecimal(int handle) - { - try - { - if (handle != 0) - { - NativeScript.Bindings.StructStore.Remove(handle); - } - } - catch (System.NullReferenceException ex) - { - UnityEngine.Debug.LogException(ex); - NativeScript.Bindings.SetCsharpExceptionSystemNullReferenceException(NativeScript.Bindings.ObjectStore.Store(ex)); - } - catch (System.Exception ex) - { - UnityEngine.Debug.LogException(ex); - NativeScript.Bindings.SetCsharpException(NativeScript.Bindings.ObjectStore.Store(ex)); - } - } - - [MonoPInvokeCallback(typeof(SystemDecimalConstructorSystemDoubleDelegateType))] - static int SystemDecimalConstructorSystemDouble(double value) - { - try - { - var returnValue = NativeScript.Bindings.StructStore.Store(new System.Decimal(value)); - return returnValue; - } - catch (System.NullReferenceException ex) - { - UnityEngine.Debug.LogException(ex); - NativeScript.Bindings.SetCsharpExceptionSystemNullReferenceException(NativeScript.Bindings.ObjectStore.Store(ex)); - return default(int); - } - catch (System.Exception ex) - { - UnityEngine.Debug.LogException(ex); - NativeScript.Bindings.SetCsharpException(NativeScript.Bindings.ObjectStore.Store(ex)); - return default(int); - } - } - - [MonoPInvokeCallback(typeof(SystemDecimalConstructorSystemUInt64DelegateType))] - static int SystemDecimalConstructorSystemUInt64(ulong value) - { - try - { - var returnValue = NativeScript.Bindings.StructStore.Store(new System.Decimal(value)); - return returnValue; - } - catch (System.NullReferenceException ex) - { - UnityEngine.Debug.LogException(ex); - NativeScript.Bindings.SetCsharpExceptionSystemNullReferenceException(NativeScript.Bindings.ObjectStore.Store(ex)); - return default(int); - } - catch (System.Exception ex) - { - UnityEngine.Debug.LogException(ex); - NativeScript.Bindings.SetCsharpException(NativeScript.Bindings.ObjectStore.Store(ex)); - return default(int); - } - } - - [MonoPInvokeCallback(typeof(BoxDecimalDelegateType))] - static int BoxDecimal(int valHandle) - { - try - { - var val = (System.Decimal)NativeScript.Bindings.StructStore.Get(valHandle); - var returnValue = NativeScript.Bindings.ObjectStore.Store((object)val); - return returnValue; - } - catch (System.NullReferenceException ex) - { - UnityEngine.Debug.LogException(ex); - NativeScript.Bindings.SetCsharpExceptionSystemNullReferenceException(NativeScript.Bindings.ObjectStore.Store(ex)); - return default(int); - } - catch (System.Exception ex) - { - UnityEngine.Debug.LogException(ex); - NativeScript.Bindings.SetCsharpException(NativeScript.Bindings.ObjectStore.Store(ex)); - return default(int); - } - } - - [MonoPInvokeCallback(typeof(UnboxDecimalDelegateType))] - static int UnboxDecimal(int valHandle) - { - try - { - var val = NativeScript.Bindings.ObjectStore.Get(valHandle); - var returnValue = NativeScript.Bindings.StructStore.Store((System.Decimal)val); - return returnValue; - } - catch (System.NullReferenceException ex) - { - UnityEngine.Debug.LogException(ex); - NativeScript.Bindings.SetCsharpExceptionSystemNullReferenceException(NativeScript.Bindings.ObjectStore.Store(ex)); - return default(int); - } - catch (System.Exception ex) - { - UnityEngine.Debug.LogException(ex); - NativeScript.Bindings.SetCsharpException(NativeScript.Bindings.ObjectStore.Store(ex)); - return default(int); - } - } - - [MonoPInvokeCallback(typeof(UnityEngineVector3ConstructorSystemSingle_SystemSingle_SystemSingleDelegateType))] - static UnityEngine.Vector3 UnityEngineVector3ConstructorSystemSingle_SystemSingle_SystemSingle(float x, float y, float z) - { - try - { - var returnValue = new UnityEngine.Vector3(x, y, z); - return returnValue; - } - catch (System.NullReferenceException ex) - { - UnityEngine.Debug.LogException(ex); - NativeScript.Bindings.SetCsharpExceptionSystemNullReferenceException(NativeScript.Bindings.ObjectStore.Store(ex)); - return default(UnityEngine.Vector3); - } - catch (System.Exception ex) - { - UnityEngine.Debug.LogException(ex); - NativeScript.Bindings.SetCsharpException(NativeScript.Bindings.ObjectStore.Store(ex)); - return default(UnityEngine.Vector3); - } - } - - [MonoPInvokeCallback(typeof(UnityEngineVector3Methodop_AdditionUnityEngineVector3_UnityEngineVector3DelegateType))] - static UnityEngine.Vector3 UnityEngineVector3Methodop_AdditionUnityEngineVector3_UnityEngineVector3(ref UnityEngine.Vector3 a, ref UnityEngine.Vector3 b) - { - try - { - var returnValue = a + b; - return returnValue; - } - catch (System.NullReferenceException ex) - { - UnityEngine.Debug.LogException(ex); - NativeScript.Bindings.SetCsharpExceptionSystemNullReferenceException(NativeScript.Bindings.ObjectStore.Store(ex)); - return default(UnityEngine.Vector3); - } - catch (System.Exception ex) - { - UnityEngine.Debug.LogException(ex); - NativeScript.Bindings.SetCsharpException(NativeScript.Bindings.ObjectStore.Store(ex)); - return default(UnityEngine.Vector3); - } - } - - [MonoPInvokeCallback(typeof(BoxVector3DelegateType))] - static int BoxVector3(ref UnityEngine.Vector3 val) - { - try - { - var returnValue = NativeScript.Bindings.ObjectStore.Store((object)val); - return returnValue; - } - catch (System.NullReferenceException ex) - { - UnityEngine.Debug.LogException(ex); - NativeScript.Bindings.SetCsharpExceptionSystemNullReferenceException(NativeScript.Bindings.ObjectStore.Store(ex)); - return default(int); - } - catch (System.Exception ex) - { - UnityEngine.Debug.LogException(ex); - NativeScript.Bindings.SetCsharpException(NativeScript.Bindings.ObjectStore.Store(ex)); - return default(int); - } - } - - [MonoPInvokeCallback(typeof(UnboxVector3DelegateType))] - static UnityEngine.Vector3 UnboxVector3(int valHandle) - { - try - { - var val = NativeScript.Bindings.ObjectStore.Get(valHandle); - var returnValue = (UnityEngine.Vector3)val; - return returnValue; - } - catch (System.NullReferenceException ex) - { - UnityEngine.Debug.LogException(ex); - NativeScript.Bindings.SetCsharpExceptionSystemNullReferenceException(NativeScript.Bindings.ObjectStore.Store(ex)); - return default(UnityEngine.Vector3); - } - catch (System.Exception ex) - { - UnityEngine.Debug.LogException(ex); - NativeScript.Bindings.SetCsharpException(NativeScript.Bindings.ObjectStore.Store(ex)); - return default(UnityEngine.Vector3); - } - } - - [MonoPInvokeCallback(typeof(UnityEngineObjectPropertyGetNameDelegateType))] - static int UnityEngineObjectPropertyGetName(int thisHandle) - { - try - { - var thiz = (UnityEngine.Object)NativeScript.Bindings.ObjectStore.Get(thisHandle); - var returnValue = thiz.name; - return NativeScript.Bindings.ObjectStore.GetHandle(returnValue); - } - catch (System.NullReferenceException ex) - { - UnityEngine.Debug.LogException(ex); - NativeScript.Bindings.SetCsharpExceptionSystemNullReferenceException(NativeScript.Bindings.ObjectStore.Store(ex)); - return default(int); - } - catch (System.Exception ex) - { - UnityEngine.Debug.LogException(ex); - NativeScript.Bindings.SetCsharpException(NativeScript.Bindings.ObjectStore.Store(ex)); - return default(int); - } - } - - [MonoPInvokeCallback(typeof(UnityEngineObjectPropertySetNameDelegateType))] - static void UnityEngineObjectPropertySetName(int thisHandle, int valueHandle) - { - try - { - var thiz = (UnityEngine.Object)NativeScript.Bindings.ObjectStore.Get(thisHandle); - var value = (string)NativeScript.Bindings.ObjectStore.Get(valueHandle); - thiz.name = value; - } - catch (System.NullReferenceException ex) - { - UnityEngine.Debug.LogException(ex); - NativeScript.Bindings.SetCsharpExceptionSystemNullReferenceException(NativeScript.Bindings.ObjectStore.Store(ex)); - } - catch (System.Exception ex) - { - UnityEngine.Debug.LogException(ex); - NativeScript.Bindings.SetCsharpException(NativeScript.Bindings.ObjectStore.Store(ex)); - } - } - - [MonoPInvokeCallback(typeof(UnityEngineComponentPropertyGetTransformDelegateType))] - static int UnityEngineComponentPropertyGetTransform(int thisHandle) - { - try - { - var thiz = (UnityEngine.Component)NativeScript.Bindings.ObjectStore.Get(thisHandle); - var returnValue = thiz.transform; - return NativeScript.Bindings.ObjectStore.GetHandle(returnValue); - } - catch (System.NullReferenceException ex) - { - UnityEngine.Debug.LogException(ex); - NativeScript.Bindings.SetCsharpExceptionSystemNullReferenceException(NativeScript.Bindings.ObjectStore.Store(ex)); - return default(int); - } - catch (System.Exception ex) - { - UnityEngine.Debug.LogException(ex); - NativeScript.Bindings.SetCsharpException(NativeScript.Bindings.ObjectStore.Store(ex)); - return default(int); - } - } - - [MonoPInvokeCallback(typeof(UnityEngineTransformPropertyGetPositionDelegateType))] - static UnityEngine.Vector3 UnityEngineTransformPropertyGetPosition(int thisHandle) - { - try - { - var thiz = (UnityEngine.Transform)NativeScript.Bindings.ObjectStore.Get(thisHandle); - var returnValue = thiz.position; - return returnValue; - } - catch (System.NullReferenceException ex) - { - UnityEngine.Debug.LogException(ex); - NativeScript.Bindings.SetCsharpExceptionSystemNullReferenceException(NativeScript.Bindings.ObjectStore.Store(ex)); - return default(UnityEngine.Vector3); - } - catch (System.Exception ex) - { - UnityEngine.Debug.LogException(ex); - NativeScript.Bindings.SetCsharpException(NativeScript.Bindings.ObjectStore.Store(ex)); - return default(UnityEngine.Vector3); - } - } - - [MonoPInvokeCallback(typeof(UnityEngineTransformPropertySetPositionDelegateType))] - static void UnityEngineTransformPropertySetPosition(int thisHandle, ref UnityEngine.Vector3 value) - { - try - { - var thiz = (UnityEngine.Transform)NativeScript.Bindings.ObjectStore.Get(thisHandle); - thiz.position = value; - } - catch (System.NullReferenceException ex) - { - UnityEngine.Debug.LogException(ex); - NativeScript.Bindings.SetCsharpExceptionSystemNullReferenceException(NativeScript.Bindings.ObjectStore.Store(ex)); - } - catch (System.Exception ex) - { - UnityEngine.Debug.LogException(ex); - NativeScript.Bindings.SetCsharpException(NativeScript.Bindings.ObjectStore.Store(ex)); - } - } - - [MonoPInvokeCallback(typeof(SystemCollectionsIEnumeratorPropertyGetCurrentDelegateType))] - static int SystemCollectionsIEnumeratorPropertyGetCurrent(int thisHandle) - { - try - { - var thiz = (System.Collections.IEnumerator)NativeScript.Bindings.ObjectStore.Get(thisHandle); - var returnValue = thiz.Current; - return NativeScript.Bindings.ObjectStore.GetHandle(returnValue); - } - catch (System.NullReferenceException ex) - { - UnityEngine.Debug.LogException(ex); - NativeScript.Bindings.SetCsharpExceptionSystemNullReferenceException(NativeScript.Bindings.ObjectStore.Store(ex)); - return default(int); - } - catch (System.Exception ex) - { - UnityEngine.Debug.LogException(ex); - NativeScript.Bindings.SetCsharpException(NativeScript.Bindings.ObjectStore.Store(ex)); - return default(int); - } - } - - [MonoPInvokeCallback(typeof(SystemCollectionsIEnumeratorMethodMoveNextDelegateType))] - static bool SystemCollectionsIEnumeratorMethodMoveNext(int thisHandle) - { - try - { - var thiz = (System.Collections.IEnumerator)NativeScript.Bindings.ObjectStore.Get(thisHandle); - var returnValue = thiz.MoveNext(); - return returnValue; - } - catch (System.NullReferenceException ex) - { - UnityEngine.Debug.LogException(ex); - NativeScript.Bindings.SetCsharpExceptionSystemNullReferenceException(NativeScript.Bindings.ObjectStore.Store(ex)); - return default(bool); - } - catch (System.Exception ex) - { - UnityEngine.Debug.LogException(ex); - NativeScript.Bindings.SetCsharpException(NativeScript.Bindings.ObjectStore.Store(ex)); - return default(bool); - } - } - - [MonoPInvokeCallback(typeof(UnityEngineGameObjectMethodAddComponentMyGameBaseBallScriptDelegateType))] - static int UnityEngineGameObjectMethodAddComponentMyGameBaseBallScript(int thisHandle) - { - try - { - var thiz = (UnityEngine.GameObject)NativeScript.Bindings.ObjectStore.Get(thisHandle); - var returnValue = thiz.AddComponent(); - return NativeScript.Bindings.ObjectStore.GetHandle(returnValue); - } - catch (System.NullReferenceException ex) - { - UnityEngine.Debug.LogException(ex); - NativeScript.Bindings.SetCsharpExceptionSystemNullReferenceException(NativeScript.Bindings.ObjectStore.Store(ex)); - return default(int); - } - catch (System.Exception ex) - { - UnityEngine.Debug.LogException(ex); - NativeScript.Bindings.SetCsharpException(NativeScript.Bindings.ObjectStore.Store(ex)); - return default(int); - } - } - - [MonoPInvokeCallback(typeof(UnityEngineGameObjectMethodCreatePrimitiveUnityEnginePrimitiveTypeDelegateType))] - static int UnityEngineGameObjectMethodCreatePrimitiveUnityEnginePrimitiveType(UnityEngine.PrimitiveType type) - { - try - { - var returnValue = UnityEngine.GameObject.CreatePrimitive(type); - return NativeScript.Bindings.ObjectStore.GetHandle(returnValue); - } - catch (System.NullReferenceException ex) - { - UnityEngine.Debug.LogException(ex); - NativeScript.Bindings.SetCsharpExceptionSystemNullReferenceException(NativeScript.Bindings.ObjectStore.Store(ex)); - return default(int); - } - catch (System.Exception ex) - { - UnityEngine.Debug.LogException(ex); - NativeScript.Bindings.SetCsharpException(NativeScript.Bindings.ObjectStore.Store(ex)); - return default(int); - } - } - - [MonoPInvokeCallback(typeof(UnityEngineDebugMethodLogSystemObjectDelegateType))] - static void UnityEngineDebugMethodLogSystemObject(int messageHandle) - { - try - { - var message = NativeScript.Bindings.ObjectStore.Get(messageHandle); - UnityEngine.Debug.Log(message); - } - catch (System.NullReferenceException ex) - { - UnityEngine.Debug.LogException(ex); - NativeScript.Bindings.SetCsharpExceptionSystemNullReferenceException(NativeScript.Bindings.ObjectStore.Store(ex)); - } - catch (System.Exception ex) - { - UnityEngine.Debug.LogException(ex); - NativeScript.Bindings.SetCsharpException(NativeScript.Bindings.ObjectStore.Store(ex)); - } - } - - [MonoPInvokeCallback(typeof(UnityEngineMonoBehaviourPropertyGetTransformDelegateType))] - static int UnityEngineMonoBehaviourPropertyGetTransform(int thisHandle) - { - try - { - var thiz = (UnityEngine.MonoBehaviour)NativeScript.Bindings.ObjectStore.Get(thisHandle); - var returnValue = thiz.transform; - return NativeScript.Bindings.ObjectStore.GetHandle(returnValue); - } - catch (System.NullReferenceException ex) - { - UnityEngine.Debug.LogException(ex); - NativeScript.Bindings.SetCsharpExceptionSystemNullReferenceException(NativeScript.Bindings.ObjectStore.Store(ex)); - return default(int); - } - catch (System.Exception ex) - { - UnityEngine.Debug.LogException(ex); - NativeScript.Bindings.SetCsharpException(NativeScript.Bindings.ObjectStore.Store(ex)); - return default(int); - } - } - - [MonoPInvokeCallback(typeof(SystemExceptionConstructorSystemStringDelegateType))] - static int SystemExceptionConstructorSystemString(int messageHandle) - { - try - { - var message = (string)NativeScript.Bindings.ObjectStore.Get(messageHandle); - var returnValue = NativeScript.Bindings.ObjectStore.Store(new System.Exception(message)); - return returnValue; - } - catch (System.NullReferenceException ex) - { - UnityEngine.Debug.LogException(ex); - NativeScript.Bindings.SetCsharpExceptionSystemNullReferenceException(NativeScript.Bindings.ObjectStore.Store(ex)); - return default(int); - } - catch (System.Exception ex) - { - UnityEngine.Debug.LogException(ex); - NativeScript.Bindings.SetCsharpException(NativeScript.Bindings.ObjectStore.Store(ex)); - return default(int); - } - } - - [MonoPInvokeCallback(typeof(BoxPrimitiveTypeDelegateType))] - static int BoxPrimitiveType(UnityEngine.PrimitiveType val) - { - try - { - var returnValue = NativeScript.Bindings.ObjectStore.Store((object)val); - return returnValue; - } - catch (System.NullReferenceException ex) - { - UnityEngine.Debug.LogException(ex); - NativeScript.Bindings.SetCsharpExceptionSystemNullReferenceException(NativeScript.Bindings.ObjectStore.Store(ex)); - return default(int); - } - catch (System.Exception ex) - { - UnityEngine.Debug.LogException(ex); - NativeScript.Bindings.SetCsharpException(NativeScript.Bindings.ObjectStore.Store(ex)); - return default(int); - } - } - - [MonoPInvokeCallback(typeof(UnboxPrimitiveTypeDelegateType))] - static UnityEngine.PrimitiveType UnboxPrimitiveType(int valHandle) - { - try - { - var val = NativeScript.Bindings.ObjectStore.Get(valHandle); - var returnValue = (UnityEngine.PrimitiveType)val; - return returnValue; - } - catch (System.NullReferenceException ex) - { - UnityEngine.Debug.LogException(ex); - NativeScript.Bindings.SetCsharpExceptionSystemNullReferenceException(NativeScript.Bindings.ObjectStore.Store(ex)); - return default(UnityEngine.PrimitiveType); - } - catch (System.Exception ex) - { - UnityEngine.Debug.LogException(ex); - NativeScript.Bindings.SetCsharpException(NativeScript.Bindings.ObjectStore.Store(ex)); - return default(UnityEngine.PrimitiveType); - } - } - - [MonoPInvokeCallback(typeof(UnityEngineTimePropertyGetDeltaTimeDelegateType))] - static float UnityEngineTimePropertyGetDeltaTime() - { - try - { - var returnValue = UnityEngine.Time.deltaTime; - return returnValue; - } - catch (System.NullReferenceException ex) - { - UnityEngine.Debug.LogException(ex); - NativeScript.Bindings.SetCsharpExceptionSystemNullReferenceException(NativeScript.Bindings.ObjectStore.Store(ex)); - return default(float); - } - catch (System.Exception ex) - { - UnityEngine.Debug.LogException(ex); - NativeScript.Bindings.SetCsharpException(NativeScript.Bindings.ObjectStore.Store(ex)); - return default(float); - } - } - - [MonoPInvokeCallback(typeof(BaseBallScriptConstructorDelegateType))] - static void BaseBallScriptConstructor(int cppHandle, ref int handle) - { - try - { - var thiz = new MyGame.BaseBallScript(cppHandle); - handle = NativeScript.Bindings.ObjectStore.Store(thiz); - } - catch (System.NullReferenceException ex) - { - UnityEngine.Debug.LogException(ex); - NativeScript.Bindings.SetCsharpExceptionSystemNullReferenceException(NativeScript.Bindings.ObjectStore.Store(ex)); - handle = default(int); - } - catch (System.Exception ex) - { - UnityEngine.Debug.LogException(ex); - NativeScript.Bindings.SetCsharpException(NativeScript.Bindings.ObjectStore.Store(ex)); - handle = default(int); - } - } - - [MonoPInvokeCallback(typeof(ReleaseBaseBallScriptDelegateType))] - static void ReleaseBaseBallScript(int handle) - { - try - { - MyGame.BaseBallScript thiz; - thiz = (MyGame.BaseBallScript)ObjectStore.Get(handle); - int cppHandle = thiz.CppHandle; - thiz.CppHandle = 0; - QueueDestroy(DestroyFunction.BaseBallScript, cppHandle); - ObjectStore.Remove(handle); - } - catch (System.NullReferenceException ex) - { - UnityEngine.Debug.LogException(ex); - NativeScript.Bindings.SetCsharpExceptionSystemNullReferenceException(NativeScript.Bindings.ObjectStore.Store(ex)); - } - catch (System.Exception ex) - { - UnityEngine.Debug.LogException(ex); - NativeScript.Bindings.SetCsharpException(NativeScript.Bindings.ObjectStore.Store(ex)); - } - } - - [MonoPInvokeCallback(typeof(BoxBooleanDelegateType))] - static int BoxBoolean(bool val) - { - try - { - var returnValue = NativeScript.Bindings.ObjectStore.Store((object)val); - return returnValue; - } - catch (System.NullReferenceException ex) - { - UnityEngine.Debug.LogException(ex); - NativeScript.Bindings.SetCsharpExceptionSystemNullReferenceException(NativeScript.Bindings.ObjectStore.Store(ex)); - return default(int); - } - catch (System.Exception ex) - { - UnityEngine.Debug.LogException(ex); - NativeScript.Bindings.SetCsharpException(NativeScript.Bindings.ObjectStore.Store(ex)); - return default(int); - } - } - - [MonoPInvokeCallback(typeof(UnboxBooleanDelegateType))] - static bool UnboxBoolean(int valHandle) - { - try - { - var val = NativeScript.Bindings.ObjectStore.Get(valHandle); - var returnValue = (bool)val; - return returnValue; - } - catch (System.NullReferenceException ex) - { - UnityEngine.Debug.LogException(ex); - NativeScript.Bindings.SetCsharpExceptionSystemNullReferenceException(NativeScript.Bindings.ObjectStore.Store(ex)); - return default(bool); - } - catch (System.Exception ex) - { - UnityEngine.Debug.LogException(ex); - NativeScript.Bindings.SetCsharpException(NativeScript.Bindings.ObjectStore.Store(ex)); - return default(bool); - } - } - - [MonoPInvokeCallback(typeof(BoxSByteDelegateType))] - static int BoxSByte(sbyte val) - { - try - { - var returnValue = NativeScript.Bindings.ObjectStore.Store((object)val); - return returnValue; - } - catch (System.NullReferenceException ex) - { - UnityEngine.Debug.LogException(ex); - NativeScript.Bindings.SetCsharpExceptionSystemNullReferenceException(NativeScript.Bindings.ObjectStore.Store(ex)); - return default(int); - } - catch (System.Exception ex) - { - UnityEngine.Debug.LogException(ex); - NativeScript.Bindings.SetCsharpException(NativeScript.Bindings.ObjectStore.Store(ex)); - return default(int); - } - } - - [MonoPInvokeCallback(typeof(UnboxSByteDelegateType))] - static sbyte UnboxSByte(int valHandle) - { - try - { - var val = NativeScript.Bindings.ObjectStore.Get(valHandle); - var returnValue = (sbyte)val; - return returnValue; - } - catch (System.NullReferenceException ex) - { - UnityEngine.Debug.LogException(ex); - NativeScript.Bindings.SetCsharpExceptionSystemNullReferenceException(NativeScript.Bindings.ObjectStore.Store(ex)); - return default(sbyte); - } - catch (System.Exception ex) - { - UnityEngine.Debug.LogException(ex); - NativeScript.Bindings.SetCsharpException(NativeScript.Bindings.ObjectStore.Store(ex)); - return default(sbyte); - } - } - - [MonoPInvokeCallback(typeof(BoxByteDelegateType))] - static int BoxByte(byte val) - { - try - { - var returnValue = NativeScript.Bindings.ObjectStore.Store((object)val); - return returnValue; - } - catch (System.NullReferenceException ex) - { - UnityEngine.Debug.LogException(ex); - NativeScript.Bindings.SetCsharpExceptionSystemNullReferenceException(NativeScript.Bindings.ObjectStore.Store(ex)); - return default(int); - } - catch (System.Exception ex) - { - UnityEngine.Debug.LogException(ex); - NativeScript.Bindings.SetCsharpException(NativeScript.Bindings.ObjectStore.Store(ex)); - return default(int); - } - } - - [MonoPInvokeCallback(typeof(UnboxByteDelegateType))] - static byte UnboxByte(int valHandle) - { - try - { - var val = NativeScript.Bindings.ObjectStore.Get(valHandle); - var returnValue = (byte)val; - return returnValue; - } - catch (System.NullReferenceException ex) - { - UnityEngine.Debug.LogException(ex); - NativeScript.Bindings.SetCsharpExceptionSystemNullReferenceException(NativeScript.Bindings.ObjectStore.Store(ex)); - return default(byte); - } - catch (System.Exception ex) - { - UnityEngine.Debug.LogException(ex); - NativeScript.Bindings.SetCsharpException(NativeScript.Bindings.ObjectStore.Store(ex)); - return default(byte); - } - } - - [MonoPInvokeCallback(typeof(BoxInt16DelegateType))] - static int BoxInt16(short val) - { - try - { - var returnValue = NativeScript.Bindings.ObjectStore.Store((object)val); - return returnValue; - } - catch (System.NullReferenceException ex) - { - UnityEngine.Debug.LogException(ex); - NativeScript.Bindings.SetCsharpExceptionSystemNullReferenceException(NativeScript.Bindings.ObjectStore.Store(ex)); - return default(int); - } - catch (System.Exception ex) - { - UnityEngine.Debug.LogException(ex); - NativeScript.Bindings.SetCsharpException(NativeScript.Bindings.ObjectStore.Store(ex)); - return default(int); - } - } - - [MonoPInvokeCallback(typeof(UnboxInt16DelegateType))] - static short UnboxInt16(int valHandle) - { - try - { - var val = NativeScript.Bindings.ObjectStore.Get(valHandle); - var returnValue = (short)val; - return returnValue; - } - catch (System.NullReferenceException ex) - { - UnityEngine.Debug.LogException(ex); - NativeScript.Bindings.SetCsharpExceptionSystemNullReferenceException(NativeScript.Bindings.ObjectStore.Store(ex)); - return default(short); - } - catch (System.Exception ex) - { - UnityEngine.Debug.LogException(ex); - NativeScript.Bindings.SetCsharpException(NativeScript.Bindings.ObjectStore.Store(ex)); - return default(short); - } - } - - [MonoPInvokeCallback(typeof(BoxUInt16DelegateType))] - static int BoxUInt16(ushort val) - { - try - { - var returnValue = NativeScript.Bindings.ObjectStore.Store((object)val); - return returnValue; - } - catch (System.NullReferenceException ex) - { - UnityEngine.Debug.LogException(ex); - NativeScript.Bindings.SetCsharpExceptionSystemNullReferenceException(NativeScript.Bindings.ObjectStore.Store(ex)); - return default(int); - } - catch (System.Exception ex) - { - UnityEngine.Debug.LogException(ex); - NativeScript.Bindings.SetCsharpException(NativeScript.Bindings.ObjectStore.Store(ex)); - return default(int); - } - } - - [MonoPInvokeCallback(typeof(UnboxUInt16DelegateType))] - static ushort UnboxUInt16(int valHandle) - { - try - { - var val = NativeScript.Bindings.ObjectStore.Get(valHandle); - var returnValue = (ushort)val; - return returnValue; - } - catch (System.NullReferenceException ex) - { - UnityEngine.Debug.LogException(ex); - NativeScript.Bindings.SetCsharpExceptionSystemNullReferenceException(NativeScript.Bindings.ObjectStore.Store(ex)); - return default(ushort); - } - catch (System.Exception ex) - { - UnityEngine.Debug.LogException(ex); - NativeScript.Bindings.SetCsharpException(NativeScript.Bindings.ObjectStore.Store(ex)); - return default(ushort); - } - } - - [MonoPInvokeCallback(typeof(BoxInt32DelegateType))] - static int BoxInt32(int val) - { - try - { - var returnValue = NativeScript.Bindings.ObjectStore.Store((object)val); - return returnValue; - } - catch (System.NullReferenceException ex) - { - UnityEngine.Debug.LogException(ex); - NativeScript.Bindings.SetCsharpExceptionSystemNullReferenceException(NativeScript.Bindings.ObjectStore.Store(ex)); - return default(int); - } - catch (System.Exception ex) - { - UnityEngine.Debug.LogException(ex); - NativeScript.Bindings.SetCsharpException(NativeScript.Bindings.ObjectStore.Store(ex)); - return default(int); - } - } - - [MonoPInvokeCallback(typeof(UnboxInt32DelegateType))] - static int UnboxInt32(int valHandle) - { - try - { - var val = NativeScript.Bindings.ObjectStore.Get(valHandle); - var returnValue = (int)val; - return returnValue; - } - catch (System.NullReferenceException ex) - { - UnityEngine.Debug.LogException(ex); - NativeScript.Bindings.SetCsharpExceptionSystemNullReferenceException(NativeScript.Bindings.ObjectStore.Store(ex)); - return default(int); - } - catch (System.Exception ex) - { - UnityEngine.Debug.LogException(ex); - NativeScript.Bindings.SetCsharpException(NativeScript.Bindings.ObjectStore.Store(ex)); - return default(int); - } - } - - [MonoPInvokeCallback(typeof(BoxUInt32DelegateType))] - static int BoxUInt32(uint val) - { - try - { - var returnValue = NativeScript.Bindings.ObjectStore.Store((object)val); - return returnValue; - } - catch (System.NullReferenceException ex) - { - UnityEngine.Debug.LogException(ex); - NativeScript.Bindings.SetCsharpExceptionSystemNullReferenceException(NativeScript.Bindings.ObjectStore.Store(ex)); - return default(int); - } - catch (System.Exception ex) - { - UnityEngine.Debug.LogException(ex); - NativeScript.Bindings.SetCsharpException(NativeScript.Bindings.ObjectStore.Store(ex)); - return default(int); - } - } - - [MonoPInvokeCallback(typeof(UnboxUInt32DelegateType))] - static uint UnboxUInt32(int valHandle) - { - try - { - var val = NativeScript.Bindings.ObjectStore.Get(valHandle); - var returnValue = (uint)val; - return returnValue; - } - catch (System.NullReferenceException ex) - { - UnityEngine.Debug.LogException(ex); - NativeScript.Bindings.SetCsharpExceptionSystemNullReferenceException(NativeScript.Bindings.ObjectStore.Store(ex)); - return default(uint); - } - catch (System.Exception ex) - { - UnityEngine.Debug.LogException(ex); - NativeScript.Bindings.SetCsharpException(NativeScript.Bindings.ObjectStore.Store(ex)); - return default(uint); - } - } - - [MonoPInvokeCallback(typeof(BoxInt64DelegateType))] - static int BoxInt64(long val) - { - try - { - var returnValue = NativeScript.Bindings.ObjectStore.Store((object)val); - return returnValue; - } - catch (System.NullReferenceException ex) - { - UnityEngine.Debug.LogException(ex); - NativeScript.Bindings.SetCsharpExceptionSystemNullReferenceException(NativeScript.Bindings.ObjectStore.Store(ex)); - return default(int); - } - catch (System.Exception ex) - { - UnityEngine.Debug.LogException(ex); - NativeScript.Bindings.SetCsharpException(NativeScript.Bindings.ObjectStore.Store(ex)); - return default(int); - } - } - - [MonoPInvokeCallback(typeof(UnboxInt64DelegateType))] - static long UnboxInt64(int valHandle) - { - try - { - var val = NativeScript.Bindings.ObjectStore.Get(valHandle); - var returnValue = (long)val; - return returnValue; - } - catch (System.NullReferenceException ex) - { - UnityEngine.Debug.LogException(ex); - NativeScript.Bindings.SetCsharpExceptionSystemNullReferenceException(NativeScript.Bindings.ObjectStore.Store(ex)); - return default(long); - } - catch (System.Exception ex) - { - UnityEngine.Debug.LogException(ex); - NativeScript.Bindings.SetCsharpException(NativeScript.Bindings.ObjectStore.Store(ex)); - return default(long); - } - } - - [MonoPInvokeCallback(typeof(BoxUInt64DelegateType))] - static int BoxUInt64(ulong val) - { - try - { - var returnValue = NativeScript.Bindings.ObjectStore.Store((object)val); - return returnValue; - } - catch (System.NullReferenceException ex) - { - UnityEngine.Debug.LogException(ex); - NativeScript.Bindings.SetCsharpExceptionSystemNullReferenceException(NativeScript.Bindings.ObjectStore.Store(ex)); - return default(int); - } - catch (System.Exception ex) - { - UnityEngine.Debug.LogException(ex); - NativeScript.Bindings.SetCsharpException(NativeScript.Bindings.ObjectStore.Store(ex)); - return default(int); - } - } - - [MonoPInvokeCallback(typeof(UnboxUInt64DelegateType))] - static ulong UnboxUInt64(int valHandle) - { - try - { - var val = NativeScript.Bindings.ObjectStore.Get(valHandle); - var returnValue = (ulong)val; - return returnValue; - } - catch (System.NullReferenceException ex) - { - UnityEngine.Debug.LogException(ex); - NativeScript.Bindings.SetCsharpExceptionSystemNullReferenceException(NativeScript.Bindings.ObjectStore.Store(ex)); - return default(ulong); - } - catch (System.Exception ex) - { - UnityEngine.Debug.LogException(ex); - NativeScript.Bindings.SetCsharpException(NativeScript.Bindings.ObjectStore.Store(ex)); - return default(ulong); - } - } - - [MonoPInvokeCallback(typeof(BoxCharDelegateType))] - static int BoxChar(char val) - { - try - { - var returnValue = NativeScript.Bindings.ObjectStore.Store((object)val); - return returnValue; - } - catch (System.NullReferenceException ex) - { - UnityEngine.Debug.LogException(ex); - NativeScript.Bindings.SetCsharpExceptionSystemNullReferenceException(NativeScript.Bindings.ObjectStore.Store(ex)); - return default(int); - } - catch (System.Exception ex) - { - UnityEngine.Debug.LogException(ex); - NativeScript.Bindings.SetCsharpException(NativeScript.Bindings.ObjectStore.Store(ex)); - return default(int); - } - } - - [MonoPInvokeCallback(typeof(UnboxCharDelegateType))] - static char UnboxChar(int valHandle) - { - try - { - var val = NativeScript.Bindings.ObjectStore.Get(valHandle); - var returnValue = (char)val; - return returnValue; - } - catch (System.NullReferenceException ex) - { - UnityEngine.Debug.LogException(ex); - NativeScript.Bindings.SetCsharpExceptionSystemNullReferenceException(NativeScript.Bindings.ObjectStore.Store(ex)); - return default(char); - } - catch (System.Exception ex) - { - UnityEngine.Debug.LogException(ex); - NativeScript.Bindings.SetCsharpException(NativeScript.Bindings.ObjectStore.Store(ex)); - return default(char); - } - } - - [MonoPInvokeCallback(typeof(BoxSingleDelegateType))] - static int BoxSingle(float val) - { - try - { - var returnValue = NativeScript.Bindings.ObjectStore.Store((object)val); - return returnValue; - } - catch (System.NullReferenceException ex) - { - UnityEngine.Debug.LogException(ex); - NativeScript.Bindings.SetCsharpExceptionSystemNullReferenceException(NativeScript.Bindings.ObjectStore.Store(ex)); - return default(int); - } - catch (System.Exception ex) - { - UnityEngine.Debug.LogException(ex); - NativeScript.Bindings.SetCsharpException(NativeScript.Bindings.ObjectStore.Store(ex)); - return default(int); - } - } - - [MonoPInvokeCallback(typeof(UnboxSingleDelegateType))] - static float UnboxSingle(int valHandle) - { - try - { - var val = NativeScript.Bindings.ObjectStore.Get(valHandle); - var returnValue = (float)val; - return returnValue; - } - catch (System.NullReferenceException ex) - { - UnityEngine.Debug.LogException(ex); - NativeScript.Bindings.SetCsharpExceptionSystemNullReferenceException(NativeScript.Bindings.ObjectStore.Store(ex)); - return default(float); - } - catch (System.Exception ex) - { - UnityEngine.Debug.LogException(ex); - NativeScript.Bindings.SetCsharpException(NativeScript.Bindings.ObjectStore.Store(ex)); - return default(float); - } - } - - [MonoPInvokeCallback(typeof(BoxDoubleDelegateType))] - static int BoxDouble(double val) - { - try - { - var returnValue = NativeScript.Bindings.ObjectStore.Store((object)val); - return returnValue; - } - catch (System.NullReferenceException ex) - { - UnityEngine.Debug.LogException(ex); - NativeScript.Bindings.SetCsharpExceptionSystemNullReferenceException(NativeScript.Bindings.ObjectStore.Store(ex)); - return default(int); - } - catch (System.Exception ex) - { - UnityEngine.Debug.LogException(ex); - NativeScript.Bindings.SetCsharpException(NativeScript.Bindings.ObjectStore.Store(ex)); - return default(int); - } - } - - [MonoPInvokeCallback(typeof(UnboxDoubleDelegateType))] - static double UnboxDouble(int valHandle) - { - try - { - var val = NativeScript.Bindings.ObjectStore.Get(valHandle); - var returnValue = (double)val; - return returnValue; - } - catch (System.NullReferenceException ex) - { - UnityEngine.Debug.LogException(ex); - NativeScript.Bindings.SetCsharpExceptionSystemNullReferenceException(NativeScript.Bindings.ObjectStore.Store(ex)); - return default(double); - } - catch (System.Exception ex) - { - UnityEngine.Debug.LogException(ex); - NativeScript.Bindings.SetCsharpException(NativeScript.Bindings.ObjectStore.Store(ex)); - return default(double); - } - } - /*END FUNCTIONS*/ - } -} - -/*BEGIN BASE TYPES*/ -namespace MyGame -{ - class BaseBallScript : MyGame.AbstractBaseBallScript - { - public int CppHandle; - - public BaseBallScript() - { - int handle = NativeScript.Bindings.ObjectStore.Store(this); - CppHandle = NativeScript.Bindings.NewBaseBallScript(handle); - } - - ~BaseBallScript() - { - if (CppHandle != 0) - { - NativeScript.Bindings.QueueDestroy(NativeScript.Bindings.DestroyFunction.BaseBallScript, CppHandle); - CppHandle = 0; - } - } - - public BaseBallScript(int cppHandle) - : base() - { - CppHandle = cppHandle; - } - - public override void Update() - { - if (CppHandle != 0) - { - int thisHandle = CppHandle; - NativeScript.Bindings.MyGameAbstractBaseBallScriptUpdate(thisHandle); - if (NativeScript.Bindings.UnhandledCppException != null) - { - Exception ex = NativeScript.Bindings.UnhandledCppException; - NativeScript.Bindings.UnhandledCppException = null; - throw ex; - } - } - } - - } -} -/*END BASE TYPES*/ \ No newline at end of file diff --git a/Unity/Assets/NativeScript/BootScene.unity b/Unity/Assets/NativeScript/BootScene.unity deleted file mode 100644 index 8a205bf..0000000 --- a/Unity/Assets/NativeScript/BootScene.unity +++ /dev/null @@ -1,239 +0,0 @@ -%YAML 1.1 -%TAG !u! tag:unity3d.com,2011: ---- !u!29 &1 -OcclusionCullingSettings: - m_ObjectHideFlags: 0 - serializedVersion: 2 - m_OcclusionBakeSettings: - smallestOccluder: 5 - smallestHole: 0.25 - backfaceThreshold: 100 - m_SceneGUID: 00000000000000000000000000000000 - m_OcclusionCullingData: {fileID: 0} ---- !u!104 &2 -RenderSettings: - m_ObjectHideFlags: 0 - serializedVersion: 9 - m_Fog: 0 - m_FogColor: {r: 0.5, g: 0.5, b: 0.5, a: 1} - m_FogMode: 3 - m_FogDensity: 0.01 - m_LinearFogStart: 0 - m_LinearFogEnd: 300 - m_AmbientSkyColor: {r: 0.212, g: 0.227, b: 0.259, a: 1} - m_AmbientEquatorColor: {r: 0.114, g: 0.125, b: 0.133, a: 1} - m_AmbientGroundColor: {r: 0.047, g: 0.043, b: 0.035, a: 1} - m_AmbientIntensity: 1 - m_AmbientMode: 0 - m_SubtractiveShadowColor: {r: 0.42, g: 0.478, b: 0.627, a: 1} - m_SkyboxMaterial: {fileID: 10304, guid: 0000000000000000f000000000000000, type: 0} - m_HaloStrength: 0.5 - m_FlareStrength: 1 - m_FlareFadeSpeed: 3 - m_HaloTexture: {fileID: 0} - m_SpotCookie: {fileID: 10001, guid: 0000000000000000e000000000000000, type: 0} - m_DefaultReflectionMode: 0 - m_DefaultReflectionResolution: 128 - m_ReflectionBounces: 1 - m_ReflectionIntensity: 1 - m_CustomReflection: {fileID: 0} - m_Sun: {fileID: 0} - m_IndirectSpecularColor: {r: 0.3731316, g: 0.38074902, b: 0.3587254, a: 1} - m_UseRadianceAmbientProbe: 0 ---- !u!157 &3 -LightmapSettings: - m_ObjectHideFlags: 0 - serializedVersion: 11 - m_GIWorkflowMode: 0 - m_GISettings: - serializedVersion: 2 - m_BounceScale: 1 - m_IndirectOutputScale: 1 - m_AlbedoBoost: 1 - m_TemporalCoherenceThreshold: 1 - m_EnvironmentLightingMode: 0 - m_EnableBakedLightmaps: 1 - m_EnableRealtimeLightmaps: 1 - m_LightmapEditorSettings: - serializedVersion: 10 - m_Resolution: 2 - m_BakeResolution: 40 - m_AtlasSize: 1024 - m_AO: 0 - m_AOMaxDistance: 1 - m_CompAOExponent: 1 - m_CompAOExponentDirect: 0 - m_Padding: 2 - m_LightmapParameters: {fileID: 0} - m_LightmapsBakeMode: 1 - m_TextureCompression: 1 - m_FinalGather: 0 - m_FinalGatherFiltering: 1 - m_FinalGatherRayCount: 256 - m_ReflectionCompression: 2 - m_MixedBakeMode: 2 - m_BakeBackend: 0 - m_PVRSampling: 1 - m_PVRDirectSampleCount: 32 - m_PVRSampleCount: 500 - m_PVRBounces: 2 - m_PVRFilterTypeDirect: 0 - m_PVRFilterTypeIndirect: 0 - m_PVRFilterTypeAO: 0 - m_PVRFilteringMode: 1 - m_PVRCulling: 1 - m_PVRFilteringGaussRadiusDirect: 1 - m_PVRFilteringGaussRadiusIndirect: 5 - m_PVRFilteringGaussRadiusAO: 2 - m_PVRFilteringAtrousPositionSigmaDirect: 0.5 - m_PVRFilteringAtrousPositionSigmaIndirect: 2 - m_PVRFilteringAtrousPositionSigmaAO: 1 - m_ShowResolutionOverlay: 1 - m_LightingDataAsset: {fileID: 0} - m_UseShadowmask: 1 ---- !u!196 &4 -NavMeshSettings: - serializedVersion: 2 - m_ObjectHideFlags: 0 - m_BuildSettings: - serializedVersion: 2 - agentTypeID: 0 - agentRadius: 0.5 - agentHeight: 2 - agentSlope: 45 - agentClimb: 0.4 - ledgeDropHeight: 0 - maxJumpAcrossDistance: 0 - minRegionArea: 2 - manualCellSize: 0 - cellSize: 0.16666667 - manualTileSize: 0 - tileSize: 256 - accuratePlacement: 0 - debug: - m_Flags: 0 - m_NavMeshData: {fileID: 0} ---- !u!1 &643357608 -GameObject: - m_ObjectHideFlags: 0 - m_PrefabParentObject: {fileID: 0} - m_PrefabInternal: {fileID: 0} - serializedVersion: 5 - m_Component: - - component: {fileID: 643357610} - - component: {fileID: 643357609} - m_Layer: 0 - m_Name: Boot - m_TagString: Untagged - m_Icon: {fileID: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 1 ---- !u!114 &643357609 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_PrefabParentObject: {fileID: 0} - m_PrefabInternal: {fileID: 0} - m_GameObject: {fileID: 643357608} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 6b5575a60b7c04c7a87ff4e161573c66, type: 3} - m_Name: - m_EditorClassIdentifier: - MemorySize: 1048576 - AutoReload: 1 - AutoReloadPollTime: 1 ---- !u!4 &643357610 -Transform: - m_ObjectHideFlags: 0 - m_PrefabParentObject: {fileID: 0} - m_PrefabInternal: {fileID: 0} - m_GameObject: {fileID: 643357608} - m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} - m_LocalPosition: {x: 0, y: 0, z: 0} - m_LocalScale: {x: 1, y: 1, z: 1} - m_Children: [] - m_Father: {fileID: 0} - m_RootOrder: 0 - m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} ---- !u!1 &1667680821 -GameObject: - m_ObjectHideFlags: 0 - m_PrefabParentObject: {fileID: 0} - m_PrefabInternal: {fileID: 0} - serializedVersion: 5 - m_Component: - - component: {fileID: 1667680825} - - component: {fileID: 1667680824} - - component: {fileID: 1667680823} - - component: {fileID: 1667680822} - m_Layer: 0 - m_Name: Camera - m_TagString: Untagged - m_Icon: {fileID: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 1 ---- !u!81 &1667680822 -AudioListener: - m_ObjectHideFlags: 0 - m_PrefabParentObject: {fileID: 0} - m_PrefabInternal: {fileID: 0} - m_GameObject: {fileID: 1667680821} - m_Enabled: 1 ---- !u!124 &1667680823 -Behaviour: - m_ObjectHideFlags: 0 - m_PrefabParentObject: {fileID: 0} - m_PrefabInternal: {fileID: 0} - m_GameObject: {fileID: 1667680821} - m_Enabled: 1 ---- !u!20 &1667680824 -Camera: - m_ObjectHideFlags: 0 - m_PrefabParentObject: {fileID: 0} - m_PrefabInternal: {fileID: 0} - m_GameObject: {fileID: 1667680821} - m_Enabled: 1 - serializedVersion: 2 - m_ClearFlags: 1 - m_BackGroundColor: {r: 0.19215687, g: 0.3019608, b: 0.4745098, a: 0} - m_NormalizedViewPortRect: - serializedVersion: 2 - x: 0 - y: 0 - width: 1 - height: 1 - near clip plane: 0.3 - far clip plane: 1000 - field of view: 60 - orthographic: 0 - orthographic size: 5 - m_Depth: 0 - m_CullingMask: - serializedVersion: 2 - m_Bits: 4294967295 - m_RenderingPath: -1 - m_TargetTexture: {fileID: 0} - m_TargetDisplay: 0 - m_TargetEye: 3 - m_HDR: 1 - m_AllowMSAA: 1 - m_AllowDynamicResolution: 0 - m_ForceIntoRT: 0 - m_OcclusionCulling: 1 - m_StereoConvergence: 10 - m_StereoSeparation: 0.022 ---- !u!4 &1667680825 -Transform: - m_ObjectHideFlags: 0 - m_PrefabParentObject: {fileID: 0} - m_PrefabInternal: {fileID: 0} - m_GameObject: {fileID: 1667680821} - m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} - m_LocalPosition: {x: 0, y: 0, z: -2} - m_LocalScale: {x: 1, y: 1, z: 1} - m_Children: [] - m_Father: {fileID: 0} - m_RootOrder: 1 - m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} diff --git a/Unity/Assets/NativeScript/BootScene.unity.meta b/Unity/Assets/NativeScript/BootScene.unity.meta deleted file mode 100644 index 225976e..0000000 --- a/Unity/Assets/NativeScript/BootScene.unity.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: e0fcf17822c8c4b4f91d4e8427f62804 -timeCreated: 1501905505 -licenseType: Free -DefaultImporter: - userData: - assetBundleName: - assetBundleVariant: diff --git a/Unity/Assets/NativeScript/BootScript.cs b/Unity/Assets/NativeScript/BootScript.cs deleted file mode 100644 index 74c8268..0000000 --- a/Unity/Assets/NativeScript/BootScript.cs +++ /dev/null @@ -1,95 +0,0 @@ -using System; -using UnityEditor; -using UnityEngine; - -namespace NativeScript -{ - /// - /// Script to run at app startup that initializes and runs the native plugin - /// - /// - /// - /// Jackson Dunstan, 2017, http://JacksonDunstan.com - /// - /// - /// - /// MIT - /// - public class BootScript : MonoBehaviour - { - public int MemorySize = 1024 * 1024 * 16; - - // Reloading requires dynamic loading of the C++ plugin, which is only - // available in the editor -#if UNITY_EDITOR - public bool AutoReload; - - public float AutoReloadPollTime = 1.0f; - private float lastAutoReloadPollTime; - private Coroutine autoReloadCoroutine; - private Action onPlayModeStateChange; -#endif - - void Start() - { -#if UNITY_EDITOR - lastAutoReloadPollTime = AutoReloadPollTime; -#endif - DontDestroyOnLoad(gameObject); - Bindings.Open(MemorySize); -#if UNITY_EDITOR - onPlayModeStateChange = OnEditorStateChanged; - EditorApplication.playModeStateChanged += onPlayModeStateChange; -#endif - } - -#if UNITY_EDITOR - void Update() - { - Bindings.Update(); - - if (AutoReload) - { - if (AutoReloadPollTime > 0) - { - // Not started yet. Start. - if (autoReloadCoroutine == null) - { - lastAutoReloadPollTime = AutoReloadPollTime; - autoReloadCoroutine = StartCoroutine( - Bindings.AutoReload( - AutoReloadPollTime)); - } - // Poll time changed. Restart. - else if (AutoReloadPollTime != lastAutoReloadPollTime) - { - StopCoroutine(autoReloadCoroutine); - lastAutoReloadPollTime = AutoReloadPollTime; - autoReloadCoroutine = StartCoroutine( - Bindings.AutoReload( - AutoReloadPollTime)); - } - } - } - else - { - // Not stopped yet. Stop. - if (autoReloadCoroutine != null) - { - StopCoroutine(autoReloadCoroutine); - autoReloadCoroutine = null; - } - } - } - - private void OnEditorStateChanged(PlayModeStateChange state) - { - if (state == PlayModeStateChange.EnteredEditMode) - { - EditorApplication.playModeStateChanged -= onPlayModeStateChange; - Bindings.Close(); - } - } -#endif - } -} \ No newline at end of file diff --git a/Unity/Assets/NativeScript/BootScript.cs.meta b/Unity/Assets/NativeScript/BootScript.cs.meta deleted file mode 100644 index ec2fae5..0000000 --- a/Unity/Assets/NativeScript/BootScript.cs.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 6b5575a60b7c04c7a87ff4e161573c66 -MonoImporter: - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: diff --git a/Unity/Assets/NativeScript/Editor.meta b/Unity/Assets/NativeScript/Editor.meta deleted file mode 100644 index a8e3655..0000000 --- a/Unity/Assets/NativeScript/Editor.meta +++ /dev/null @@ -1,9 +0,0 @@ -fileFormatVersion: 2 -guid: 30246f3ac733e46d9a5280becbe04ead -folderAsset: yes -timeCreated: 1497929556 -licenseType: Free -DefaultImporter: - userData: - assetBundleName: - assetBundleVariant: diff --git a/Unity/Assets/NativeScript/Editor/EditorMenus.cs b/Unity/Assets/NativeScript/Editor/EditorMenus.cs deleted file mode 100644 index a444732..0000000 --- a/Unity/Assets/NativeScript/Editor/EditorMenus.cs +++ /dev/null @@ -1,30 +0,0 @@ -using UnityEditor; - -namespace NativeScript.Editor -{ - /// - /// Menus for the Unity Editor - /// - /// - /// - /// Jackson Dunstan, 2018, http://JacksonDunstan.com - /// - /// - /// - /// MIT - /// - public static class EditorMenus - { - [MenuItem("NativeScript/Generate Bindings #%g")] - public static void Generate() - { - GenerateBindings.Generate(); - } - - [MenuItem("NativeScript/Reload Plugin #%r")] - public static void Reload() - { - Bindings.Reload(); - } - } -} diff --git a/Unity/Assets/NativeScript/Editor/GenerateBindings.cs b/Unity/Assets/NativeScript/Editor/GenerateBindings.cs deleted file mode 100644 index be815bc..0000000 --- a/Unity/Assets/NativeScript/Editor/GenerateBindings.cs +++ /dev/null @@ -1,13654 +0,0 @@ -using System; -using System.Collections; -using System.Collections.Generic; -using System.IO; -using System.Reflection; -using System.Text; - -using UnityEditor; -using UnityEngine; - -namespace NativeScript.Editor -{ - /// - /// Code generator that reads a JSON file and outputs C# and C++ code - /// bindings so the languages can call each other. - /// - /// - /// Jackson Dunstan, 2017, http://JacksonDunstan.com - /// - /// - /// MIT - /// - public static class GenerateBindings - { - // Disable unused field types. JsonUtility actually uses them, but it - // does so with reflection. - #pragma warning disable 649 - - [Serializable] - class JsonConstructor - { - public string[] ParamTypes; - public string[] Exceptions; - } - - [Serializable] - class JsonGenericParams - { - public string[] Types; - public int MaxSimultaneous; - } - - [Serializable] - class JsonMethod - { - public string Name; - public string[] ParamTypes; - public JsonGenericParams[] GenericParams; - public bool IsReadOnly; - public string[] Exceptions; - } - - [Serializable] - class JsonPropertyGet - { - public bool IsReadOnly = true; - public string[] ParamTypes; - public string[] Exceptions; - } - - [Serializable] - class JsonPropertySet - { - public bool IsReadOnly; - public string[] ParamTypes; - public string[] Exceptions; - } - - [Serializable] - class JsonProperty - { - public string Name; - public JsonPropertyGet Get; - public JsonPropertySet Set; - } - - [Serializable] - class JsonEvent - { - public string Name; - } - - [Serializable] - class JsonType - { - public string Name; - public JsonConstructor[] Constructors; - public JsonMethod[] Methods; - public JsonProperty[] Properties; - public string[] Fields; - public JsonEvent[] Events; - public JsonGenericParams[] GenericParams; - public int MaxSimultaneous; - public JsonBaseType[] BaseTypes; - } - - [Serializable] - class JsonBaseType - { - public string BaseName; - public string DerivedName; - public string[] GenericTypes; - public int MaxSimultaneous; - public JsonConstructor[] Constructors; - public JsonMethod[] OverrideMethods; - public JsonProperty[] OverrideProperties; - public JsonEvent[] OverrideEvents; - } - - [Serializable] - class JsonArray - { - public string Type; - public int[] Ranks; - } - - [Serializable] - class JsonDelegate - { - public string Type; - public JsonGenericParams[] GenericParams; - public int MaxSimultaneous; - } - - [Serializable] - class JsonDocument - { - public int MaxSimultaneousObjects; - public int DefaultMaxSimultaneous; - public string[] Assemblies; - public JsonType[] Types; - public JsonArray[] Arrays; - public JsonDelegate[] Delegates; - } - - const int InitialStringBuilderCapacity = 1024 * 100; - - class StringBuilders - { - public readonly StringBuilder CsharpDelegateTypes = - new StringBuilder(InitialStringBuilderCapacity); - public readonly StringBuilder CsharpStoreInitCalls = - new StringBuilder(InitialStringBuilderCapacity); - public readonly StringBuilder CsharpInitCall = - new StringBuilder(InitialStringBuilderCapacity); - public readonly StringBuilder CsharpBaseTypes = - new StringBuilder(InitialStringBuilderCapacity); - public readonly StringBuilder CsharpFunctions = - new StringBuilder(InitialStringBuilderCapacity); - public readonly StringBuilder CsharpCppDelegates = - new StringBuilder(InitialStringBuilderCapacity); - public readonly StringBuilder CsharpCsharpDelegates = - new StringBuilder(InitialStringBuilderCapacity); - public readonly StringBuilder CsharpImports = - new StringBuilder(InitialStringBuilderCapacity); - public readonly StringBuilder CsharpGetDelegateCalls = - new StringBuilder(InitialStringBuilderCapacity); - public readonly StringBuilder CsharpDestroyFunctionEnumerators = - new StringBuilder(InitialStringBuilderCapacity); - public readonly StringBuilder CsharpDestroyQueueCases = - new StringBuilder(InitialStringBuilderCapacity); - public readonly StringBuilder CppFunctionPointers = - new StringBuilder(InitialStringBuilderCapacity); - public readonly StringBuilder CppTypeDeclarations = - new StringBuilder(InitialStringBuilderCapacity); - public readonly StringBuilder CppTemplateDeclarations = - new StringBuilder(InitialStringBuilderCapacity); - public readonly StringBuilder CppTemplateSpecializationDeclarations = - new StringBuilder(InitialStringBuilderCapacity); - public readonly StringBuilder CppTypeDefinitions = - new StringBuilder(InitialStringBuilderCapacity); - public readonly StringBuilder CppMethodDefinitions = - new StringBuilder(InitialStringBuilderCapacity); - public readonly StringBuilder CppInitBodyParameterReads = - new StringBuilder(InitialStringBuilderCapacity); - public readonly StringBuilder CppInitBodyArrays = - new StringBuilder(InitialStringBuilderCapacity); - public readonly StringBuilder CppInitBodyFirstBoot = - new StringBuilder(InitialStringBuilderCapacity); - public readonly StringBuilder CppGlobalStateAndFunctions = - new StringBuilder(InitialStringBuilderCapacity); - public readonly StringBuilder CppUnboxingMethodDeclarations = - new StringBuilder(InitialStringBuilderCapacity); - public readonly StringBuilder CppStringDefaultParams = - new StringBuilder(InitialStringBuilderCapacity); - public readonly StringBuilder CppMacros = - new StringBuilder(InitialStringBuilderCapacity); - public readonly StringBuilder TempStrBuilder = - new StringBuilder(InitialStringBuilderCapacity); - } - - class ParameterInfo - { - public string Name; - public Type ParameterType; - public Type DereferencedParameterType; - public bool IsOut; - public bool IsRef; - public TypeKind Kind; - public bool IsVirtual; - public bool HasDefault; - public object DefaultValue; - public bool IsVarArg; - } - - enum TypeKind - { - // No type (e.g. a global function) - None, - - // An instance of any class - Class, - - // A struct that must be managed. This includes types like - // RaycastHit which have class fields (Transform) and types with no - // C++ equivalent like decimal. - ManagedStruct, - - // A struct that can be copied between C#/C++. These are types like - // Vector3 with only non-class fields and a C++ equivalent can be - // generated. - FullStruct, - - // Any enum - Enum, - - // Any primitive (e.g. int) except pointers - Primitive, - - // A pointer to any type, either X*, IntPtr, or UIntPtr - Pointer - } - - // Compares by field declaration order - // This uses MetadataToken, which isn't guaranteed to match field - // declaration order. It just happens to on Mono and .NET. - class FieldOrderComparer : IComparer - { - int IComparer.Compare(object x, object y) - { - FieldInfo xField = (FieldInfo)x; - FieldInfo yField = (FieldInfo)y; - return xField == null - ? yField == null - ? 0 - : -1 - : yField == null - ? 1 - : xField.MetadataToken < yField.MetadataToken - ? -1 - : xField.MetadataToken > yField.MetadataToken - ? 1 - : 0; - } - } - - struct TypeName - { - public string Name; - public string Namespace; - public int NumTypeParams; - } - - const int BaseMaxSimultaneous = 1000; - - static readonly Type[] PrimitiveTypes = { - typeof(bool), - typeof(sbyte), - typeof(byte), - typeof(short), - typeof(ushort), - typeof(int), - typeof(uint), - typeof(long), - typeof(ulong), - typeof(char), - typeof(float), - typeof(double) - }; - - const string PostCompileWorkPref = "NativeScriptGenerateBindingsPostCompileWork"; - - static readonly string DotNetDllsDirPath = new FileInfo( - new Uri(typeof(string).Assembly.CodeBase).LocalPath - ).DirectoryName; - static readonly string UnityDllsDirPath = new FileInfo( - new Uri(typeof(GameObject).Assembly.CodeBase).LocalPath - ).DirectoryName; - static readonly string AssetsDirPath = Application.dataPath; - private static readonly DirectoryInfo ProjectDir = - new DirectoryInfo(AssetsDirPath).Parent; - static readonly string ProjectDirPath = ProjectDir.FullName; - static readonly string CppDirPath = - Path.Combine( - Path.Combine( - Path.Combine( - ProjectDirPath, - "Assets"), - "CppSource"), - "NativeScript"); - static readonly string CsharpPath = Path.Combine( - AssetsDirPath, - Path.Combine( - "NativeScript", - "Bindings.cs")); - static readonly string CppHeaderPath = Path.Combine( - CppDirPath, - "Bindings.h"); - static readonly string CppSourcePath = Path.Combine( - CppDirPath, - "Bindings.cpp"); - - static readonly FieldOrderComparer DefaultFieldOrderComparer - = new FieldOrderComparer(); - - // Restore unused field types - #pragma warning restore 649 - - public static void Generate() - { - EditorPrefs.DeleteKey(PostCompileWorkPref); - JsonDocument doc = LoadJson(); - Assembly[] assemblies = GetAssemblies(doc.Assemblies); - - // Determine whether we need to generate stubs - // We can skip this step if we've already generated all the - // required base types - bool needStubs = false; - if (doc.Types != null) - { - foreach (JsonType jsonType in doc.Types) - { - if (jsonType.BaseTypes != null) - { - foreach (JsonBaseType jsonBaseType in jsonType.BaseTypes) - { - // Check if the type is already generated - Type type = TryGetType( - jsonBaseType.BaseName, - assemblies); - if (type == null) - { - needStubs = true; - goto determinedNeedStubs; - } - } - } - } - } - determinedNeedStubs: - - if (needStubs) - { - // We'll need to be able to get these via reflection later - StringBuilders builders = new StringBuilders(); - string timestamp = DateTime.Now.ToLongTimeString(); - AppendStubs( - doc.Types, - assemblies, - timestamp, - builders); - InjectBuilders(builders); - - // Compile and continue after scripts are refreshed - Debug.Log("Waiting for compile..."); - EditorPrefs.SetBool(PostCompileWorkPref, true); - AssetDatabase.Refresh(); - } - else - { - DoPostCompileWork(true); - } - } - - static void AppendStubs( - JsonType[] jsonTypes, - Assembly[] assemblies, - string timestamp, - StringBuilders builders) - { - // Base types - foreach (JsonType jsonType in jsonTypes) - { - if (jsonType.BaseTypes != null) - { - foreach (JsonBaseType jsonBaseType in jsonType.BaseTypes) - { - string typeFullName = jsonType.Name; - TypeName typeName = SplitJsonTypeName(typeFullName); - - string baseTypeFullName = jsonBaseType.BaseName; - TypeName baseTypeName = SplitJsonTypeName(baseTypeFullName); - - Type type = GetType(typeFullName, assemblies); - - Type[] typeParams = GetTypes( - jsonBaseType.GenericTypes, - assemblies); - - AppendStubBaseType( - typeName, - baseTypeName, - typeParams, - type, - timestamp, - builders.CsharpBaseTypes); - } - } - } - } - - static void AppendStubBaseType( - TypeName typeName, - TypeName baseTypeName, - Type[] typeParams, - Type type, - string timestamp, - StringBuilder output) - { - int indent = AppendNamespaceBeginning( - baseTypeName.Namespace, - output); - AppendIndent(indent, output); - if (type.IsClass) - { - output.Append("abstract public class "); - } - else - { - output.Append("public interface "); - } - output.Append(baseTypeName.Name); - output.Append(" : "); - AppendCsharpTypeFullName( - typeName, - output); - AppendCSharpTypeParameters( - typeParams, - output); - output.AppendLine(); - AppendIndent(indent, output); - output.AppendLine("{"); - AppendIndent(indent + 1, output); - output.Append("// Stub version. GenerateBindings is still in progress. "); - output.Append(timestamp); - output.AppendLine(); - if (type.IsClass) - { - output.AppendLine(); - ConstructorInfo[] constructors = type.GetConstructors(); - if (constructors.Length > 0) - { - foreach (ConstructorInfo ctor in constructors) - { - if (ctor.IsPublic - && ctor.GetCustomAttributes(typeof(ObsoleteAttribute), true).Length == 0) - { - ParameterInfo[] ctorParams = ConvertParameters( - ctor.GetParameters()); - output.Append("\t\t"); - output.Append(baseTypeName.Name); - output.Append('('); - AppendCsharpParams( - ctorParams, - output); - output.AppendLine(")"); - output.Append("\t\t\t: base("); - AppendCsharpFunctionCallParameters( - ctorParams, - output); - output.AppendLine(")"); - output.AppendLine("\t\t{"); - output.AppendLine("\t\t}"); - output.AppendLine("\t\t"); - break; - } - } - } - } - AppendIndent(indent, output); - output.AppendLine("}"); - AppendNamespaceEnding(indent, output); - } - - [UnityEditor.Callbacks.DidReloadScripts] - static void OnScriptsReloaded() - { - // Scripts get reloaded for many reasons, not just our work - // Check if this reload is due to us refreshing the asset DB - bool doWork = EditorPrefs.GetBool(PostCompileWorkPref, false); - EditorPrefs.DeleteKey(PostCompileWorkPref); - if (doWork) - { - DoPostCompileWork(false); - } - } - - static void DoPostCompileWork(bool canRefreshAssetDb) - { - DateTime beforeTime = DateTime.Now; - - JsonDocument doc = LoadJson(); - Assembly[] assemblies = GetAssemblies(doc.Assemblies); - StringBuilders builders = new StringBuilders(); - - // Get the default number of maximum simultaneous objects in case - // it's not specified for a specific type - int defaultMaxSimultaneous = doc.DefaultMaxSimultaneous != 0 - ? doc.DefaultMaxSimultaneous - : BaseMaxSimultaneous; - - // Init param for max managed Objects - builders.CsharpInitCall.Append("\t\t\tMarshal.WriteInt32(memory, curMemory, "); - builders.CsharpInitCall.Append(defaultMaxSimultaneous); - builders.CsharpInitCall.AppendLine("); // max managed objects"); - builders.CsharpInitCall.AppendLine("\t\t\tcurMemory += sizeof(int);"); - builders.CsharpInitCall.Append(' '); - - // C# ObjectStore Init call - builders.CsharpStoreInitCalls.Append( - "\t\t\tNativeScript.Bindings.ObjectStore.Init("); - builders.CsharpStoreInitCalls.Append(defaultMaxSimultaneous); - builders.CsharpStoreInitCalls.AppendLine(");"); - - // Generate types - if (doc.Types != null) - { - foreach (JsonType jsonType in doc.Types) - { - Type type = GetType(jsonType.Name, assemblies); - TypeKind typeKind = GetTypeKind(type); - AppendType( - jsonType, - type, - typeKind, - assemblies, - defaultMaxSimultaneous, - builders); - - if (jsonType.BaseTypes != null) - { - Type[] genericArgTypes = type.GetGenericArguments(); - foreach (JsonBaseType jsonBaseType in jsonType.BaseTypes) - { - TypeName baseTypeTypeName = GetBaseTypeBaseNameAndNamespace( - jsonBaseType, - type, - genericArgTypes, - builders.TempStrBuilder); - AppendBaseType( - type, - baseTypeTypeName, - jsonBaseType, - assemblies, - defaultMaxSimultaneous, - builders); - } - } - } - } - - // Generate boxing and unboxing for primitive types - foreach (Type type in PrimitiveTypes) - { - string dummyString; - ParameterInfo[] dummyParams; - AppendBoxingBindings( - type, - TypeKind.Primitive, - null, - builders, - out dummyString, - out dummyParams); - AppendUnboxing( - type, - TypeKind.Primitive, - null, - builders); - } - - // Generate arrays - if (doc.Arrays != null) - { - foreach (JsonArray array in doc.Arrays) - { - AppendArray( - array, - assemblies, - builders); - } - } - - // Generate delegates - if (doc.Delegates != null) - { - foreach (JsonDelegate del in doc.Delegates) - { - AppendDelegate( - del, - assemblies, - defaultMaxSimultaneous, - builders); - } - } - - // Generate exception setters - AppendExceptions( - doc, - assemblies, - builders); - - // Output source files - RemoveTrailingChars(builders); - InjectBuilders(builders); - - // Inform the user of the result - if (canRefreshAssetDb) - { - AssetDatabase.Refresh(); - DateTime afterTime = DateTime.Now; - TimeSpan duration = afterTime - beforeTime; - Debug.LogFormat( - "Done generating bindings in {0} seconds.", - duration.TotalSeconds); - } - else - { - Debug.LogWarning( - "Can't auto-refresh due to a bug in Unity. " + - "Please manually refresh assets with " + - "Assets -> Refresh to finish generating bindings"); - } - } - - static JsonDocument LoadJson() - { - string jsonPath = Path.Combine( - Application.dataPath, - NativeScriptConstants.JSON_CONFIG_PATH); - string json = File.ReadAllText(jsonPath); - return JsonUtility.FromJson(json); - } - - static Assembly[] GetAssemblies(string[] assemblyNames) - { - const int numDefaultAssemblies = -#if UNITY_2017_2_OR_NEWER - 43; -#else - 7; -#endif - - int numAssemblies; - Assembly[] assemblies; - if (assemblyNames == null) - { - numAssemblies = numDefaultAssemblies; - assemblies = new Assembly[numAssemblies]; - } - else - { - numAssemblies = numDefaultAssemblies + assemblyNames.Length; - assemblies = new Assembly[numAssemblies]; - - for (int i = 0; i < assemblyNames.Length; ++i) - { - string path = assemblyNames[i] - .Replace("UNITY_PROJECT", ProjectDirPath) - .Replace("UNITY_ASSETS", AssetsDirPath) - .Replace("DOTNET_DLLS", DotNetDllsDirPath) - .Replace("UNITY_DLLS", UnityDllsDirPath); - Assembly assembly = Assembly.LoadFrom(path); - assemblies[numDefaultAssemblies + i] = assembly; - } - } - assemblies[0] = typeof(string).Assembly; // .NET: mscorlib - assemblies[1] = typeof(Uri).Assembly; // .NET: System - assemblies[2] = typeof(Action).Assembly; // .NET: System.Core - assemblies[3] = typeof(Vector3).Assembly; // UnityEngine (core module for 2017.2+) - assemblies[4] = typeof(Bindings).Assembly; // Runtime scripts - assemblies[5] = typeof(GenerateBindings).Assembly; // Editor scripts - assemblies[6] = typeof(EditorPrefs).Assembly; // UnityEditor -#if UNITY_2017_2_OR_NEWER - assemblies[7] = typeof(UnityEngine.Accessibility.VisionUtility).Assembly; // Unity accessibility module - assemblies[8] = typeof(UnityEngine.AI.NavMesh).Assembly; // Unity AI module - assemblies[9] = typeof(UnityEngine.Animations.AnimationClipPlayable).Assembly; // Unity animation module -#if !UNITY_2020_1_OR_NEWER //This class migrate to package - assemblies[10] = typeof(UnityEngine.XR.ARRenderMode).Assembly; // Unity AR module -#else - assemblies[10] = typeof(UnityEngine.XR.InputDevices).Assembly; // Unity AR module without package -#endif - - assemblies[11] = typeof(AudioSettings).Assembly; // Unity audio module - assemblies[12] = typeof(Cloth).Assembly; // Unity cloth module - assemblies[13] = typeof(ClusterInput).Assembly; // Unity cluster input module - assemblies[14] = typeof(ClusterNetwork).Assembly; // Unity custer renderer module - assemblies[15] = typeof(UnityEngine.CrashReportHandler.CrashReportHandler).Assembly; // Unity crash reporting module - assemblies[16] = typeof(UnityEngine.Playables.PlayableDirector).Assembly; // Unity director module - assemblies[17] = typeof(UnityEngine.SocialPlatforms.IAchievement).Assembly; // Unity game center module - assemblies[18] = typeof(ImageConversion).Assembly; // Unity image conversion module - assemblies[19] = typeof(GUI).Assembly; // Unity IMGUI module - assemblies[20] = typeof(JsonUtility).Assembly; // Unity JSON serialize module - assemblies[21] = typeof(ParticleSystem).Assembly; // Unity particle system module - assemblies[22] = typeof(UnityEngine.Analytics.PerformanceReporting).Assembly; // Unity performance reporting module - assemblies[23] = typeof(Physics2D).Assembly; // Unity physics 2D module - assemblies[24] = typeof(Physics).Assembly; // Unity physics module - assemblies[25] = typeof(ScreenCapture).Assembly; // Unity screen capture module - assemblies[26] = typeof(Terrain).Assembly; // Unity terrain module - assemblies[27] = typeof(TerrainCollider).Assembly; // Unity terrain physics module - assemblies[28] = typeof(Font).Assembly; // Unity text rendering module - assemblies[29] = typeof(UnityEngine.Tilemaps.Tile).Assembly; // Unity tilemap module -#if UNITY_2019_1_OR_NEWER - assemblies[30] = typeof(UnityEngine.UIElements.Button).Assembly; // Unity UI elements module -#else - assemblies[30] = typeof(UnityEngine.Experimental.UIElements.Button).Assembly; // Unity UI elements module -#endif - assemblies[31] = typeof(Canvas).Assembly; // Unity UI module -#if UNITY_2020_1_OR_NEWER - assemblies[32] = typeof(UnityEngine.Networking.Utility).Assembly; // Unity network module -#else - assemblies[32] = typeof(UnityEngine.Networking.NetworkTransport).Assembly; // Unity network module -#endif - assemblies[33] = typeof(UnityEngine.Analytics.Analytics).Assembly; // Unity analytics module - assemblies[34] = typeof(RemoteSettings).Assembly; // Unity Unity connect module - assemblies[35] = typeof(UnityEngine.Networking.DownloadHandlerAudioClip).Assembly; // Unity web request audio module - assemblies[36] = typeof(WWWForm).Assembly; // Unity web request module - assemblies[37] = typeof(UnityEngine.Networking.DownloadHandlerTexture).Assembly; // Unity web request texture module -#if !UNITY_2020_1_OR_NEWER - assemblies[38] = typeof(WWW).Assembly; // Unity web request WWW module -#else - assemblies[38] = typeof(UnityEngine.Networking.UnityWebRequest).Assembly; -#endif - assemblies[39] = typeof(WheelCollider).Assembly; // Unity vehicles module - assemblies[40] = typeof(UnityEngine.Video.VideoClip).Assembly; // Unity video module - assemblies[41] = typeof(UnityEngine.XR.InputTracking).Assembly; // Unity VR module - assemblies[42] = typeof(WindZone).Assembly; // Unity wind module -#endif - return assemblies; - } - - static Type[] GetTypes( - string[] typeNames, - Assembly[] assemblies) - { - if (typeNames == null) - { - return new Type[0]; - } - Type[] types = new Type[typeNames.Length]; - for (int i = 0; i < typeNames.Length; ++i) - { - types[i] = GetType(typeNames[i], assemblies); - } - return types; - } - - static Type GetType( - string typeName, - Assembly[] assemblies) - { - Type type = TryGetType( - typeName, - assemblies); - if (type != null) - { - return type; - } - - // Not finding a type is a fatal error - StringBuilder errorBuilder = new StringBuilder(1024); - errorBuilder.Append("Couldn't find type \""); - errorBuilder.Append(typeName); - errorBuilder.Append('"'); - throw new Exception(errorBuilder.ToString()); - } - - static Type TryGetType( - string typeName, - Assembly[] assemblies) - { - // Search all assemblies for the type - foreach (Assembly assembly in assemblies) - { - Type type = assembly.GetType(typeName); - if (type != null) - { - return type; - } - } - return null; - } - - static TypeKind GetTypeKind(Type type) - { - if (type == typeof(void)) - { - return TypeKind.None; - } - - if (type.IsPointer) - { - return TypeKind.Pointer; - } - - if (type.IsEnum) - { - return TypeKind.Enum; - } - - if (type.IsPrimitive) - { - return TypeKind.Primitive; - } - - if (!type.IsValueType) - { - return TypeKind.Class; - } - - // Decimal (currently) can't be represented on the C++ side, so - // don't count it as a full struct - if (type != typeof(decimal) && IsFullValueType(type)) - { - return TypeKind.FullStruct; - } - - return TypeKind.ManagedStruct; - } - - static ParameterInfo[] GetConstructorParameters( - Type type, - bool allowDefault, - string[] paramTypeNames) - { - foreach (ConstructorInfo ctor in type.GetConstructors()) - { - System.Reflection.ParameterInfo[] reflectionParams - = ctor.GetParameters(); - if (CheckParametersMatch( - paramTypeNames, - reflectionParams)) - { - return ConvertParameters(reflectionParams); - } - } - - if (allowDefault) - { - return new ParameterInfo[0]; - } - - // Throw an exception so the user knows what to fix in the JSON - StringBuilder errorBuilder = new StringBuilder(1024); - errorBuilder.Append("Constructor \""); - AppendCsharpTypeFullName(type, errorBuilder); - errorBuilder.Append('('); - for (int i = 0; i < paramTypeNames.Length; ++i) - { - errorBuilder.Append(paramTypeNames[i]); - if (i != paramTypeNames.Length - 1) - { - errorBuilder.Append(", "); - } - } - errorBuilder.Append(")\" not found"); - throw new Exception(errorBuilder.ToString()); - } - - static MethodInfo GetMethod( - Type type, - MethodInfo[] methods, - string methodName, - string[] paramTypeNames, - string[] genericTypeNames) - { - foreach (MethodInfo method in methods) - { - // Name must match - if (method.Name != methodName) - { - continue; - } - - // All parameters must match - if (!CheckParametersMatch( - paramTypeNames, - method.GetParameters())) - { - continue; - } - - // Generic arg count must match - Type[] methodGenericArgs = method.GetGenericArguments(); - int numGenericTypeNames = genericTypeNames == null ? 0 : genericTypeNames.Length; - if (methodGenericArgs.Length == numGenericTypeNames) - { - return method; - } - } - - // Throw an exception so the user knows what to fix in the JSON - StringBuilder errorBuilder = new StringBuilder(1024); - errorBuilder.Append("Method \""); - AppendCsharpTypeFullName(type, errorBuilder); - errorBuilder.Append('.'); - errorBuilder.Append(methodName); - errorBuilder.Append('('); - for (int i = 0; i < paramTypeNames.Length; ++i) - { - errorBuilder.Append(paramTypeNames[i]); - if (i != paramTypeNames.Length - 1) - { - errorBuilder.Append(", "); - } - } - errorBuilder.Append(")\" not found"); - throw new Exception(errorBuilder.ToString()); - } - - static Type[] GetDirectInterfaces(Type type) - { - Type[] allInterfaces = type.GetInterfaces(); - List minimalInterfaces = new List(); - foreach(Type iType in allInterfaces) - { - bool contains = false; - foreach (Type t in allInterfaces) - { - if (Array.IndexOf(t.GetInterfaces(), iType) >= 0) - { - contains = true; - break; - } - } - if (!contains) - { - minimalInterfaces.Add(iType); - } - } - minimalInterfaces.Sort( - (x, y) => string.Compare( - x.Name, - y.Name, - StringComparison.InvariantCulture)); - return minimalInterfaces.ToArray(); - } - - static void AddCppCtorInitType(Type type, List types) - { - if (type.BaseType != null - && type.BaseType != typeof(object) - && type.BaseType != typeof(ValueType)) - { - AddCppCtorInitType(type.BaseType, types); - } - foreach (Type interfaceType in GetDirectInterfaces(type)) - { - AddCppCtorInitType(interfaceType, types); - } - if (!types.Contains(type)) - { - types.Add(type); - } - } - - static Type[] GetCppCtorInitTypes(Type type, bool includeSelf) - { - List types = new List(); - AddCppCtorInitType(type, types); - if (!includeSelf) - { - types.RemoveAll(t => t == type); - } - return types.ToArray(); - } - - static void AppendCppConstructorInitializerList( - Type[] interfaceTypes, - int indent, - StringBuilder output, - string newline = null) - { - if (string.IsNullOrWhiteSpace(newline)) - { - newline = Environment.NewLine; - } - - string separator = ": "; - foreach (Type interfaceType in interfaceTypes) - { - AppendIndent(indent, output); - output.Append(separator); - AppendCppTypeFullName( interfaceType, output); - output.Append("(nullptr)"); - output.Append(newline); - separator = ", "; - } - } - - static void AppendUppercaseWithUnderscores( - string str, - StringBuilder output) - { - if (string.IsNullOrEmpty(str)) - { - return; - } - char prev = str[0]; - output.Append(char.ToUpper(prev)); - for (int i = 1; i < str.Length; ++i) - { - char cur = str[i]; - if (char.IsUpper(cur) && char.IsLower(prev)) - { - output.Append('_'); - } - output.Append(char.ToUpper(cur)); - prev = cur; - } - } - - static bool CheckParametersMatch( - string[] paramTypeNames, - System.Reflection.ParameterInfo[] reflectionParams) - { - // Length must match - if (reflectionParams.Length != paramTypeNames.Length) - { - return false; - } - - // All params must match - for (int i = 0; i < reflectionParams.Length; ++i) - { - Type type = DereferenceParameterType( - reflectionParams[i]); - string typeName = paramTypeNames[i]; - if (!CheckTypeNameMatches(typeName, type)) - { - return false; - } - } - - return true; - } - - static bool CheckTypeNameMatches( - string typeName, - Type type) - { - // No namespace. Only name must match. - if (string.IsNullOrEmpty(type.Namespace)) - { - if (type.Name != typeName) - { - return false; - } - } - // Must be: Namespace.Name - else - { - // Length must be the same as (namespace + '.' + name) - if ( - typeName.Length != - type.Namespace.Length - + 1 - + type.Name.Length) - { - return false; - } - - // Must start with namespace - if (!typeName.StartsWith(type.Namespace)) - { - return false; - } - - // Namespace must be followed by '.' - if (typeName[type.Namespace.Length] != '.') - { - return false; - } - - // Must end with name - if (!typeName.EndsWith(type.Name)) - { - return false; - } - } - - return true; - } - - static void AppendParameterTypeNames( - ParameterInfo[] parameters, - StringBuilder output) - { - for (int i = 0, len = parameters.Length; i < len; ++i) - { - Type type = parameters[i].DereferencedParameterType; - AppendNamespace(type.Namespace, string.Empty, output); - AppendTypeNameWithoutSuffixes( - type.Name, - output); - if (type.IsArray) - { - output.Append("Array"); - output.Append(type.GetArrayRank()); - } - if (i != len - 1) - { - output.Append('_'); - } - } - } - - static void AppendTypeNames( - Type[] typeNames, - StringBuilder output) - { - if (typeNames != null) - { - for (int i = 0, len = typeNames.Length; i < len; ++i) - { - Type curType = typeNames[i]; - AppendNamespace( - curType.Namespace, - string.Empty, - output); - AppendTypeNameWithoutSuffixes( - curType.Name, - output); - if (i != len - 1) - { - output.Append('_'); - } - } - } - } - - static TypeName GetBaseTypeBaseNameAndNamespace( - JsonBaseType jsonBaseType, - Type type, - Type[] typeParams, - StringBuilder tempStringBuilder) - { - // Get specified (optional) base type name - TypeName baseTypeTypeName = SplitJsonTypeName(jsonBaseType.BaseName); - - // If base type name isn't provided, make one - if (string.IsNullOrEmpty(baseTypeTypeName.Name)) - { - tempStringBuilder.Length = 0; - AppendNamespace( - type.Namespace, - string.Empty, - tempStringBuilder); - tempStringBuilder.Append("Base"); - AppendTypeNameWithoutSuffixes( - type.Name, - tempStringBuilder); - AppendTypeNames( - typeParams, - tempStringBuilder); - baseTypeTypeName.Name = tempStringBuilder.ToString(); - } - - baseTypeTypeName.NumTypeParams = typeParams.Length; - return baseTypeTypeName; - } - - static void AppendNamespace( - string namespaceName, - string separator, - StringBuilder output) - { - int startIndex = 0; - if (!string.IsNullOrEmpty(namespaceName)) - { - do - { - int separatorIndex = namespaceName.IndexOf( - '.', - startIndex); - if (separatorIndex < 0) - { - separatorIndex = namespaceName.IndexOf( - '+', - startIndex); - if (separatorIndex < 0) - { - break; - } - } - output.Append( - namespaceName, - startIndex, - separatorIndex - startIndex); - output.Append(separator); - startIndex = separatorIndex + 1; - } - while (true); - output.Append( - namespaceName, - startIndex, - namespaceName.Length - startIndex); - } - } - - static TypeName SplitJsonTypeName(string fullName) - { - string typeName; - string typeNamespace; - - // No full name - if (string.IsNullOrEmpty(fullName)) - { - typeName = string.Empty; - typeNamespace = string.Empty; - } - else - { - // Has a namespace - int index = fullName.LastIndexOf('.'); - if (index >= 0) - { - typeNamespace = fullName.Substring(0, index); - typeName = fullName.Substring(index + 1); - } - // No namespace. Just name. - else - { - typeName = fullName; - typeNamespace = string.Empty; - } - } - - return GetTypeName(typeName, typeNamespace); - } - - static ParameterInfo[] ConvertParameters( - System.Reflection.ParameterInfo[] reflectionParameters, - int start = 0) - { - int num = reflectionParameters.Length - start; - ParameterInfo[] parameters = new ParameterInfo[num]; - for (int i = start; i < num; ++i) - { - System.Reflection.ParameterInfo reflectionInfo = - reflectionParameters[i]; - ParameterInfo info = new ParameterInfo(); - info.Name = reflectionInfo.Name; - info.ParameterType = reflectionInfo.ParameterType; - info.IsOut = reflectionInfo.IsOut; - info.IsRef = !info.IsOut && info.ParameterType.IsByRef; - info.DereferencedParameterType = DereferenceParameterType( - reflectionInfo); - info.Kind = GetTypeKind( - info.DereferencedParameterType); - info.HasDefault = (reflectionInfo.Attributes & - ParameterAttributes.HasDefault) == - ParameterAttributes.HasDefault; - info.DefaultValue = reflectionInfo.DefaultValue; - info.IsVarArg = reflectionInfo.IsDefined( - typeof(ParamArrayAttribute), - false); - parameters[i - start] = info; - } - return parameters; - } - - static Type DereferenceParameterType( - System.Reflection.ParameterInfo info) - { - Type paramType = info.ParameterType; - return info.IsOut - ? paramType.GetElementType() - : paramType.IsByRef - ? paramType.GetElementType() - : paramType; - } - - static ParameterInfo[] ConvertParameters( - Type[] paramTypes) - { - int num = paramTypes.Length; - ParameterInfo[] parameters = new ParameterInfo[num]; - for (int i = 0; i < num; ++i) - { - Type paramType = paramTypes[i]; - ParameterInfo info = new ParameterInfo(); - info.Name = "param" + i; - info.ParameterType = paramType; - info.IsOut = false; - info.IsRef = false; - info.DereferencedParameterType = paramType; - info.Kind = GetTypeKind( - info.DereferencedParameterType); - parameters[i] = info; - } - return parameters; - } - - static TypeName GetTypeName(Type type) - { - TypeName typeName; - typeName.Name = type.Name; - typeName.Namespace = type.Namespace; - typeName.NumTypeParams = type.GetGenericArguments().Length; - return typeName; - } - - static TypeName GetTypeName( - string name, - string namespaceName) - { - TypeName typeName; - typeName.Name = name; - typeName.Namespace = namespaceName; - typeName.NumTypeParams = 0; - return typeName; - } - - static TypeName GetTypeName( - string name, - string namespaceName, - int numTypeParams) - { - TypeName typeName; - typeName.Name = name; - typeName.Namespace = namespaceName; - typeName.NumTypeParams = numTypeParams; - return typeName; - } - - static bool IsStatic(Type type) - { - return type.IsAbstract && type.IsSealed; - } - - static bool IsDelegate(Type type) - { - return typeof(Delegate).IsAssignableFrom(type); - } - - static bool IsNonDelegateClass(Type type) - { - return type.IsClass && !IsDelegate(type); - } - - static bool IsManagedValueType(Type type) - { - return type.IsValueType && !IsFullValueType(type); - } - - static bool IsFullValueType(Type type) - { - if (!type.IsValueType) - { - return false; - } - if (type.IsPrimitive || type.IsEnum || type == typeof(void)) - { - return true; - } - const BindingFlags bindingFlags = - BindingFlags.Instance - | BindingFlags.NonPublic - | BindingFlags.Public; - foreach (FieldInfo field in type.GetFields(bindingFlags)) - { - if (!field.IsPublic - || (!field.IsStatic - && !IsFullValueType(field.FieldType))) - { - return false; - } - } - return true; - } - - static int ArrayIndexOf(T[] array, T value) - { - return array != null ? - Array.IndexOf(array, value) : - -1; - } - - static void AppendTypeNameWithoutGenericSuffix( - string typeName, - StringBuilder output) - { - // Names are like "List`1" - // Remove the ` and everything after it - int backtickIndex = typeName.IndexOf('`'); - if (backtickIndex < 0) - { - output.Append(typeName); - } - else - { - // Append up to (but not including) the ` - output.Append( - typeName, - 0, - backtickIndex); - - // Find the first non-number after the ` - int endIndex = backtickIndex + 1; - while ( - endIndex < typeName.Length - && char.IsNumber(typeName[endIndex])) - { - endIndex++; - } - - // Append everything after the numbers - if (endIndex < typeName.Length) - { - output.Append( - typeName, - endIndex, - typeName.Length - endIndex); - } - } - } - - static void AppendTypeNameWithoutSuffixes( - string typeName, - StringBuilder output) - { - // Names are like "List`1" or "int[]" or "List`1[]" - // Remove the first of ` or [ and everything after it - int backtickIndex = typeName.IndexOf('`'); - if (backtickIndex < 0) - { - int bracketIndex = typeName.IndexOf('['); - if (bracketIndex < 0) - { - output.Append(typeName); - } - else - { - output.Append(typeName, 0, bracketIndex); - } - } - else - { - output.Append(typeName, 0, backtickIndex); - } - } - - static void AppendType( - JsonType jsonType, - Type type, - TypeKind typeKind, - Assembly[] assemblies, - int defaultMaxSimultaneous, - StringBuilders builders) - { - if (typeKind == TypeKind.Enum) - { - AppendEnum( - type, - builders); - AppendUnboxing( - type, - typeKind, - null, - builders); - } - else - { - Type[] genericArgTypes = type.GetGenericArguments(); - if (jsonType.GenericParams != null) - { - if (!IsStatic(type)) - { - AppendCppTemplateDeclaration( - GetTypeName(type), - builders.CppTemplateDeclarations); - } - - foreach (JsonGenericParams jsonGenericParams - in jsonType.GenericParams) - { - Type[] typeParams = GetTypes( - jsonGenericParams.Types, - assemblies); - Type genericType = type.MakeGenericType(typeParams); - int maxSimultaneous = jsonGenericParams.MaxSimultaneous != 0 - ? jsonGenericParams.MaxSimultaneous - : jsonType.MaxSimultaneous != 0 - ? jsonType.MaxSimultaneous - : defaultMaxSimultaneous; - AppendType( - jsonType, - genericArgTypes, - genericType, - typeKind, - typeParams, - maxSimultaneous, - assemblies, - builders); - if (typeKind != TypeKind.Class) - { - AppendUnboxing( - genericType, - typeKind, - typeParams, - builders); - } - } - } - else - { - int maxSimultaneous = jsonType.MaxSimultaneous != 0 - ? jsonType.MaxSimultaneous - : defaultMaxSimultaneous; - AppendType( - jsonType, - genericArgTypes, - type, - typeKind, - null, - maxSimultaneous, - assemblies, - builders); - if (typeKind != TypeKind.Class) - { - AppendUnboxing( - type, - typeKind, - null, - builders); - } - } - } - } - - static void AppendType( - JsonType jsonType, - Type[] genericArgTypes, - Type type, - TypeKind typeKind, - Type[] typeParams, - int maxSimultaneous, - Assembly[] assemblies, - StringBuilders builders) - { - bool isStatic = IsStatic(type); - if (!isStatic && typeKind == TypeKind.ManagedStruct) - { - // C# StructStore Init call - builders.CsharpStoreInitCalls.Append( - "\t\t\tNativeScript.Bindings.StructStore<"); - AppendCsharpTypeFullName( - type, - builders.CsharpStoreInitCalls); - builders.CsharpStoreInitCalls.Append(">.Init("); - builders.CsharpStoreInitCalls.Append(maxSimultaneous); - builders.CsharpStoreInitCalls.AppendLine(");"); - - // Build function name suffix - builders.TempStrBuilder.Length = 0; - AppendReleaseFunctionNameSuffix( - GetTypeName(type), - typeParams, - builders.TempStrBuilder); - string funcNameSuffix = builders.TempStrBuilder.ToString(); - - // Build function name - builders.TempStrBuilder.Length = 0; - builders.TempStrBuilder.Append("Release"); - AppendReleaseFunctionNameSuffix( - GetTypeName(type), - typeParams, - builders.TempStrBuilder); - string funcName = builders.TempStrBuilder.ToString(); - - // Build ReleaseX parameters - ParameterInfo paramInfo = new ParameterInfo(); - paramInfo.Name = "handle"; - paramInfo.ParameterType = typeof(int); - paramInfo.IsOut = false; - paramInfo.IsRef = false; - paramInfo.DereferencedParameterType = typeof(int); - paramInfo.Kind = TypeKind.Primitive; - ParameterInfo[] parameters = { paramInfo }; - - // ReleaseX C# delegate type - AppendCsharpDelegateType( - funcName, - true, - type, - typeKind, - typeof(void), - parameters, - builders.CsharpDelegateTypes); - - // ReleaseX C# function - AppendCsharpFunctionBeginning( - type, - funcName, - true, - typeKind, - typeof(void), - parameters, - builders.CsharpFunctions); - builders.CsharpFunctions.AppendLine("if (handle != 0)"); - builders.CsharpFunctions.AppendLine("\t\t\t{"); - builders.CsharpFunctions.Append( - "\t\t\t\tNativeScript.Bindings.StructStore<"); - AppendCsharpTypeFullName( - type, - builders.CsharpFunctions); - builders.CsharpFunctions.AppendLine(">.Remove(handle);"); - builders.CsharpFunctions.Append("\t\t\t}"); - AppendCsharpFunctionEnd( - typeof(void), - new Type[0], - parameters, - builders.CsharpFunctions); - - // C++ function pointer definition - AppendCppFunctionPointerDefinition( - funcName, - true, - default(TypeName), - TypeKind.None, - parameters, - typeof(void), - builders.CppFunctionPointers); - - // C++ init body for ReleaseX - AppendCppInitBodyFunctionPointerParameterRead( - funcName, - true, - default(TypeName), - TypeKind.None, - parameters, - typeof(void), - builders.CppInitBodyParameterReads); - - // C# init call arg for ReleaseX - AppendCsharpCsharpDelegate( - funcName, - builders.CsharpInitCall, - builders.CsharpCsharpDelegates); - - // C++ init body for handle array length - builders.CppInitBodyArrays.Append("\tPlugin::RefCounts"); - builders.CppInitBodyArrays.Append(funcNameSuffix); - builders.CppInitBodyArrays.AppendLine(" = (int32_t*)curMemory;"); - builders.CppInitBodyArrays.Append("\tcurMemory += "); - builders.CppInitBodyArrays.Append(maxSimultaneous); - builders.CppInitBodyArrays.AppendLine(" * sizeof(int32_t);"); - builders.CppInitBodyArrays.Append("\tPlugin::RefCountsLen"); - builders.CppInitBodyArrays.Append(funcNameSuffix); - builders.CppInitBodyArrays.Append(" = "); - builders.CppInitBodyArrays.Append(maxSimultaneous); - builders.CppInitBodyArrays.AppendLine(";"); - builders.CppInitBodyArrays.AppendLine("\t"); - - // C++ ref count state and functions - builders.CppGlobalStateAndFunctions.Append("\tint32_t RefCountsLen"); - builders.CppGlobalStateAndFunctions.Append(funcNameSuffix); - builders.CppGlobalStateAndFunctions.AppendLine(";"); - builders.CppGlobalStateAndFunctions.Append("\tint32_t* RefCounts"); - builders.CppGlobalStateAndFunctions.Append(funcNameSuffix); - builders.CppGlobalStateAndFunctions.AppendLine(";"); - builders.CppGlobalStateAndFunctions.AppendLine("\t"); - builders.CppGlobalStateAndFunctions.Append("\tvoid ReferenceManaged"); - builders.CppGlobalStateAndFunctions.Append(funcNameSuffix); - builders.CppGlobalStateAndFunctions.AppendLine("(int32_t handle)"); - builders.CppGlobalStateAndFunctions.AppendLine("\t{"); - builders.CppGlobalStateAndFunctions.Append("\t\tassert(handle >= 0 && handle < RefCountsLen"); - builders.CppGlobalStateAndFunctions.Append(funcNameSuffix); - builders.CppGlobalStateAndFunctions.AppendLine(");"); - builders.CppGlobalStateAndFunctions.AppendLine("\t\tif (handle != 0)"); - builders.CppGlobalStateAndFunctions.AppendLine("\t\t{"); - builders.CppGlobalStateAndFunctions.Append("\t\t\tRefCounts"); - builders.CppGlobalStateAndFunctions.Append(funcNameSuffix); - builders.CppGlobalStateAndFunctions.AppendLine("[handle]++;"); - builders.CppGlobalStateAndFunctions.AppendLine("\t\t}"); - builders.CppGlobalStateAndFunctions.AppendLine("\t}"); - builders.CppGlobalStateAndFunctions.AppendLine("\t"); - builders.CppGlobalStateAndFunctions.Append("\tvoid DereferenceManaged"); - builders.CppGlobalStateAndFunctions.Append(funcNameSuffix); - builders.CppGlobalStateAndFunctions.AppendLine("(int32_t handle)"); - builders.CppGlobalStateAndFunctions.AppendLine("\t{"); - builders.CppGlobalStateAndFunctions.Append("\t\tassert(handle >= 0 && handle < RefCountsLen"); - builders.CppGlobalStateAndFunctions.Append(funcNameSuffix); - builders.CppGlobalStateAndFunctions.AppendLine(");"); - builders.CppGlobalStateAndFunctions.AppendLine("\t\tif (handle != 0)"); - builders.CppGlobalStateAndFunctions.AppendLine("\t\t{"); - builders.CppGlobalStateAndFunctions.Append("\t\t\tint32_t numRemain = --RefCounts"); - builders.CppGlobalStateAndFunctions.Append(funcNameSuffix); - builders.CppGlobalStateAndFunctions.AppendLine("[handle];"); - builders.CppGlobalStateAndFunctions.AppendLine("\t\t\tif (numRemain == 0)"); - builders.CppGlobalStateAndFunctions.AppendLine("\t\t\t{"); - builders.CppGlobalStateAndFunctions.Append("\t\t\t\tRelease"); - builders.CppGlobalStateAndFunctions.Append(funcNameSuffix); - builders.CppGlobalStateAndFunctions.AppendLine("(handle);"); - builders.CppGlobalStateAndFunctions.AppendLine("\t\t\t}"); - builders.CppGlobalStateAndFunctions.AppendLine("\t\t}"); - builders.CppGlobalStateAndFunctions.AppendLine("\t}"); - builders.CppGlobalStateAndFunctions.AppendLine("\t"); - } - - // C++ type declaration - int indent = AppendCppTypeDeclaration( - GetTypeName(type), - isStatic, - typeParams, - typeParams != null ? - builders.CppTemplateSpecializationDeclarations : - builders.CppTypeDeclarations); - - // C++ type definition (beginning) - Type[] interfaceTypes = GetDirectInterfaces(type); - string baseTypeName; - string baseTypeNamespace; - Type[] baseTypeTypeParams; - switch (typeKind) - { - case TypeKind.FullStruct: - baseTypeName = null; - baseTypeNamespace = null; - baseTypeTypeParams = null; - break; - case TypeKind.ManagedStruct: - if (interfaceTypes.Length == 0) - { - baseTypeName = "ManagedType"; - baseTypeNamespace = "Plugin"; - baseTypeTypeParams = null; - } - else - { - baseTypeName = null; - baseTypeNamespace = null; - baseTypeTypeParams = null; - } - break; - default: - Type baseType = type.BaseType ?? typeof(object); - baseTypeName = baseType.Name; - baseTypeNamespace = baseType.Namespace; - baseTypeTypeParams = baseType.GetGenericArguments(); - break; - } - - AppendCppTypeDefinitionBegin( - GetTypeName(type), - typeKind, - typeParams, - GetTypeName(baseTypeName, baseTypeNamespace), - baseTypeTypeParams, - interfaceTypes, - isStatic, - indent, - builders.CppTypeDefinitions); - - // C++ method definition - Type[] cppCtorInterfaceTypes = GetCppCtorInitTypes( - type, - false); - int cppMethodDefinitionsIndent = AppendCppMethodDefinitionsBegin( - GetTypeName(type), - typeKind, - typeParams, - cppCtorInterfaceTypes, - isStatic, - (extraIndent, subject) => {}, - (extraIndent, subject) => {}, - indent, - builders.CppMethodDefinitions); - - // Constructors - if (typeKind == TypeKind.FullStruct) - { - AppendFullValueTypeDefaultConstructor( - type, - indent, - builders); - } - if (jsonType.Constructors != null) - { - foreach (JsonConstructor jsonCtor in jsonType.Constructors) - { - AppendConstructor( - jsonCtor.ParamTypes, - jsonCtor.Exceptions, - type, - isStatic, - typeKind, - assemblies, - typeParams, - genericArgTypes, - cppCtorInterfaceTypes, - indent, - builders); - } - } - - // Properties - if (jsonType.Properties != null) - { - foreach (JsonProperty jsonProperty in jsonType.Properties) - { - AppendProperty( - jsonProperty, - type, - isStatic, - typeKind, - typeParams, - genericArgTypes, - indent, - assemblies, - builders); - } - } - - // Fields - if (typeKind == TypeKind.FullStruct) - { - AppendFullValueTypeFields( - type, - indent + 1, - builders); - } - else - { - if (jsonType.Fields != null) - { - foreach (string jsonFieldName in jsonType.Fields) - { - AppendField( - jsonFieldName, - type, - isStatic, - typeKind, - typeParams, - genericArgTypes, - indent, - builders - ); - } - } - } - - // Events - if (jsonType.Events != null) - { - foreach (JsonEvent jsonEvent in jsonType.Events) - { - AppendEvent( - jsonEvent, - type, - isStatic, - typeKind, - typeParams, - indent, - builders - ); - } - } - - // Methods - if (jsonType.Methods != null) - { - MethodInfo[] methods = type.GetMethods(); - foreach (JsonMethod jsonMethod in jsonType.Methods) - { - AppendMethod( - jsonMethod, - assemblies, - type, - isStatic, - typeKind, - methods, - typeParams, - genericArgTypes, - indent, - builders); - } - } - - // Boxing - if (typeKind != TypeKind.Class) - { - AppendBoxing( - type, - typeKind, - typeParams, - indent, - builders); - } - - // C++ type definition (ending) - AppendCppTypeDefinitionEnd( - isStatic, - indent, - builders.CppTypeDefinitions); - - // C++ method definition (ending) - AppendCppMethodDefinitionsEnd( - cppMethodDefinitionsIndent, - builders.CppMethodDefinitions); - - // Generate iterator if this type implements IEnumerable - Type[] allInterfaces = type.GetInterfaces(); - foreach (Type interfaceType in allInterfaces) - { - if (interfaceType.IsGenericType - && interfaceType.GetGenericTypeDefinition() == typeof(IEnumerable<>)) - { - builders.TempStrBuilder.Length = 0; - AppendNamespace( - type.Namespace, - string.Empty, - builders.TempStrBuilder); - AppendTypeNameWithoutGenericSuffix( - type.Name, - builders.TempStrBuilder); - AppendTypeNames( - typeParams, - builders.TempStrBuilder); - string bindingEnumerableTypeName = builders.TempStrBuilder.ToString(); - - Type elementType = interfaceType.GetGenericArguments()[0]; - AppendGenericEnumerableIterator( - type, - typeof(IEnumerator<>).MakeGenericType(elementType), - elementType, - bindingEnumerableTypeName, - builders.CppTypeDefinitions, - builders.CppMethodDefinitions); - break; - } - } - } - - static void AppendBaseType( - Type type, - TypeName cppBaseTypeTypeName, - JsonBaseType jsonBaseType, - Assembly[] assemblies, - int defaultMaxSimultaneous, - StringBuilders builders) - { - int maxSimultaneous = jsonBaseType.MaxSimultaneous != 0 - ? jsonBaseType.MaxSimultaneous - : defaultMaxSimultaneous; - if (jsonBaseType.GenericTypes != null) - { - Type[] typeParams = GetTypes( - jsonBaseType.GenericTypes, - assemblies); - Type genericType = type.MakeGenericType(typeParams); - AppendBaseType( - genericType, - jsonBaseType, - cppBaseTypeTypeName, - typeParams, - maxSimultaneous, - assemblies, - builders); - } - else - { - AppendBaseType( - type, - jsonBaseType, - cppBaseTypeTypeName, - null, - maxSimultaneous, - assemblies, - builders); - } - } - - static void AppendReleaseFunctionNameSuffix( - TypeName typeTypeName, - Type[] typeParams, - StringBuilder output) - { - AppendNamespace( - typeTypeName.Namespace, - string.Empty, - output); - AppendTypeNameWithoutSuffixes( - typeTypeName.Name, - output); - if (typeParams != null) - { - for (int i = 0, len = typeParams.Length; i < len; ++i) - { - Type typeParam = typeParams[i]; - AppendNamespace( - typeParam.Namespace, - string.Empty, - output); - AppendTypeNameWithoutSuffixes( - typeParam.Name, - output); - if (i != len - 1) - { - output.Append('_'); - } - } - } - } - - static void AppendEnum( - Type type, - StringBuilders builders) - { - // C++ type declaration - int indent = AppendCppTypeDeclaration( - GetTypeName(type), - false, - null, - builders.CppTypeDeclarations); - - // C++ type definition (begin) - AppendCppTypeDefinitionBegin( - GetTypeName(type), - TypeKind.FullStruct, - null, - default(TypeName), - null, - null, - false, - indent, - builders.CppTypeDefinitions); - AppendIndent( - indent + 1, - builders.CppTypeDefinitions); - - // Primitive type field - Type underlyingType = Enum.GetUnderlyingType(type); - AppendCppPrimitiveTypeName( - underlyingType, - builders.CppTypeDefinitions); - builders.CppTypeDefinitions.AppendLine(" Value;"); - - // Enumerator fields - FieldInfo[] fields = type.GetFields( - BindingFlags.Static - | BindingFlags.Public); - foreach (FieldInfo field in fields) - { - AppendIndent( - indent + 1, - builders.CppTypeDefinitions); - builders.CppTypeDefinitions.Append("static const "); - AppendCppTypeFullName( - type, - builders.CppTypeDefinitions); - builders.CppTypeDefinitions.Append(' '); - builders.CppTypeDefinitions.Append(field.Name); - builders.CppTypeDefinitions.AppendLine(";"); - } - - // Constructor from primitive type - AppendIndent( - indent + 1, - builders.CppTypeDefinitions); - builders.CppTypeDefinitions.Append("explicit "); - builders.CppTypeDefinitions.Append(type.Name); - builders.CppTypeDefinitions.Append('('); - AppendCppPrimitiveTypeName( - underlyingType, - builders.CppTypeDefinitions); - builders.CppTypeDefinitions.AppendLine(" value);"); - - // Conversion operator to primitive type - AppendIndent( - indent + 1, - builders.CppTypeDefinitions); - builders.CppTypeDefinitions.Append("explicit operator "); - AppendCppPrimitiveTypeName( - underlyingType, - builders.CppTypeDefinitions); - builders.CppTypeDefinitions.AppendLine("() const;"); - - // Equality operator - AppendIndent( - indent + 1, - builders.CppTypeDefinitions); - builders.CppTypeDefinitions.Append("bool operator==("); - builders.CppTypeDefinitions.Append(type.Name); - builders.CppTypeDefinitions.AppendLine(" other);"); - - // Inequality operator - AppendIndent( - indent + 1, - builders.CppTypeDefinitions); - builders.CppTypeDefinitions.Append("bool operator!=("); - builders.CppTypeDefinitions.Append(type.Name); - builders.CppTypeDefinitions.AppendLine(" other);"); - - AppendNamespaceBeginning( - type.Namespace, - builders.CppMethodDefinitions); - - // Constructor from primitive type - AppendIndent( - indent, - builders.CppMethodDefinitions); - builders.CppMethodDefinitions.Append(type.Name); - builders.CppMethodDefinitions.Append("::"); - builders.CppMethodDefinitions.Append(type.Name); - builders.CppMethodDefinitions.Append('('); - AppendCppPrimitiveTypeName( - underlyingType, - builders.CppMethodDefinitions); - builders.CppMethodDefinitions.AppendLine(" value)"); - AppendIndent( - indent + 1, - builders.CppMethodDefinitions); - builders.CppMethodDefinitions.AppendLine(": Value(value)"); - AppendIndent( - indent, - builders.CppMethodDefinitions); - builders.CppMethodDefinitions.AppendLine("{"); - AppendIndent( - indent, - builders.CppMethodDefinitions); - builders.CppMethodDefinitions.AppendLine("}"); - AppendIndent( - indent, - builders.CppMethodDefinitions); - builders.CppMethodDefinitions.AppendLine(); - - // Conversion operator to primitive type - AppendIndent( - indent, - builders.CppMethodDefinitions); - AppendCppTypeFullName( - type, - builders.CppMethodDefinitions); - builders.CppMethodDefinitions.Append("::operator "); - AppendCppPrimitiveTypeName( - underlyingType, - builders.CppMethodDefinitions); - builders.CppMethodDefinitions.AppendLine("() const"); - AppendIndent( - indent, - builders.CppMethodDefinitions); - builders.CppMethodDefinitions.AppendLine("{"); - AppendIndent( - indent + 1, - builders.CppMethodDefinitions); - builders.CppMethodDefinitions.AppendLine("return Value;"); - AppendIndent( - indent, - builders.CppMethodDefinitions); - builders.CppMethodDefinitions.AppendLine("}"); - AppendIndent( - indent, - builders.CppMethodDefinitions); - builders.CppMethodDefinitions.AppendLine();; - - // Equality operator - AppendIndent( - indent, - builders.CppMethodDefinitions); - builders.CppMethodDefinitions.Append("bool "); - AppendCppTypeFullName( - type, - builders.CppMethodDefinitions); - builders.CppMethodDefinitions.Append("::operator==("); - builders.CppMethodDefinitions.Append(type.Name); - builders.CppMethodDefinitions.AppendLine(" other)"); - AppendIndent( - indent, - builders.CppMethodDefinitions); - builders.CppMethodDefinitions.AppendLine("{"); - AppendIndent( - indent + 1, - builders.CppMethodDefinitions); - builders.CppMethodDefinitions.AppendLine("return Value == other.Value;"); - AppendIndent( - indent, - builders.CppMethodDefinitions); - builders.CppMethodDefinitions.AppendLine("}"); - AppendIndent( - indent, - builders.CppMethodDefinitions); - builders.CppMethodDefinitions.AppendLine();; - - // Inequality operator - AppendIndent( - indent, - builders.CppMethodDefinitions); - builders.CppMethodDefinitions.Append("bool "); - AppendCppTypeFullName( - type, - builders.CppMethodDefinitions); - builders.CppMethodDefinitions.Append("::operator!=("); - builders.CppMethodDefinitions.Append(type.Name); - builders.CppMethodDefinitions.AppendLine(" other)"); - AppendIndent( - indent, - builders.CppMethodDefinitions); - builders.CppMethodDefinitions.AppendLine("{"); - AppendIndent( - indent + 1, - builders.CppMethodDefinitions); - builders.CppMethodDefinitions.AppendLine("return Value != other.Value;"); - AppendIndent( - indent, - builders.CppMethodDefinitions); - builders.CppMethodDefinitions.AppendLine("}"); - AppendIndent( - indent, - builders.CppMethodDefinitions); - builders.CppMethodDefinitions.AppendLine();; - - AppendBoxing( - type, - TypeKind.Enum, - null, - indent, - builders); - - AppendNamespaceEnding( - indent, - builders.CppMethodDefinitions); - AppendIndent( - indent, - builders.CppTypeDefinitions); - builders.CppTypeDefinitions.AppendLine("};"); - AppendNamespaceEnding( - indent, - builders.CppTypeDefinitions); - builders.CppTypeDefinitions.AppendLine();; - - // Static initialization - foreach (FieldInfo field in fields) - { - builders.CppMethodDefinitions.Append("const "); - AppendCppTypeFullName( - type, - builders.CppMethodDefinitions); - builders.CppMethodDefinitions.Append(' '); - AppendCppTypeFullName( - type, - builders.CppMethodDefinitions); - builders.CppMethodDefinitions.Append("::"); - builders.CppMethodDefinitions.Append(field.Name); - builders.CppMethodDefinitions.Append('('); - builders.CppMethodDefinitions.Append( - field.GetRawConstantValue()); - builders.CppMethodDefinitions.AppendLine(");"); - } - builders.CppMethodDefinitions.AppendLine();; - } - - static void AppendBoxing( - Type type, - TypeKind typeKind, - Type[] typeParams, - int indent, - StringBuilders builders) - { - string boxFuncName; - ParameterInfo[] boxCppParams; - AppendBoxingBindings( - type, - typeKind, - typeParams, - builders, - out boxFuncName, - out boxCppParams); - - for (Type baseType = type.BaseType; - baseType != null; - baseType = baseType.BaseType) - { - string boxMethodDefinitionName; - string boxMethodDeclarationName; - AppendCppBoxingMethodNames( - baseType, - builders.TempStrBuilder, - out boxMethodDefinitionName, - out boxMethodDeclarationName); - AppendCppBoxingMethodDeclaration( - boxMethodDeclarationName, - boxCppParams, - indent + 1, - builders.CppTypeDefinitions); - AppendCppBoxingMethodDefinition( - type, - typeParams, - baseType, - typeKind, - boxMethodDefinitionName, - boxFuncName, - boxCppParams, - indent, - builders.CppMethodDefinitions); - } - foreach (Type interfaceType in type.GetInterfaces()) - { - string boxMethodDefinitionName; - string boxMethodDeclarationName; - AppendCppBoxingMethodNames( - interfaceType, - builders.TempStrBuilder, - out boxMethodDefinitionName, - out boxMethodDeclarationName); - AppendCppBoxingMethodDeclaration( - boxMethodDeclarationName, - boxCppParams, - indent + 1, - builders.CppTypeDefinitions); - AppendCppBoxingMethodDefinition( - type, - typeParams, - interfaceType, - typeKind, - boxMethodDefinitionName, - boxFuncName, - boxCppParams, - indent, - builders.CppMethodDefinitions); - } - } - - static void AppendBoxingBindings( - Type type, - TypeKind typeKind, - Type[] typeParams, - StringBuilders builders, - out string boxFuncName, - out ParameterInfo[] boxCppParams) - { - builders.TempStrBuilder.Length = 0; - builders.TempStrBuilder.Append("Box"); - AppendTypeNameWithoutSuffixes( - type.Name, - builders.TempStrBuilder); - AppendTypeNames( - typeParams, - builders.TempStrBuilder); - boxFuncName = builders.TempStrBuilder.ToString(); - - ParameterInfo[] boxParams = { - new ParameterInfo - { - Name = "val", - ParameterType = type, - DereferencedParameterType = type, - IsOut = false, - IsRef = false, - Kind = typeKind - } - }; - - boxCppParams = new ParameterInfo[0]; - - // C# delegate types - AppendCsharpDelegateType( - boxFuncName, - true, - type, - typeKind, - typeof(object), - boxParams, - builders.CsharpDelegateTypes); - - // C# init call args - AppendCsharpCsharpDelegate( - boxFuncName, - builders.CsharpInitCall, - builders.CsharpCsharpDelegates); - - // C# box function - AppendCsharpFunctionBeginning( - typeof(object), - boxFuncName, - true, - TypeKind.Class, - typeof(object), - boxParams, - builders.CsharpFunctions); - builders.CsharpFunctions.Append( - "NativeScript.Bindings.ObjectStore.Store((object)val);"); - AppendCsharpFunctionReturn( - boxParams, - typeof(object), - TypeKind.Class, - null, - true, - builders.CsharpFunctions); - - // C++ function pointers - AppendCppFunctionPointerDefinition( - boxFuncName, - true, - GetTypeName(type), - typeKind, - boxParams, - typeof(object), - builders.CppFunctionPointers); - - // C++ init body - AppendCppInitBodyFunctionPointerParameterRead( - boxFuncName, - true, - GetTypeName(type), - typeKind, - boxParams, - typeof(object), - builders.CppInitBodyParameterReads); - } - - static void AppendUnboxing( - Type type, - TypeKind typeKind, - Type[] typeParams, - StringBuilders builders) - { - builders.TempStrBuilder.Length = 0; - builders.TempStrBuilder.Append("Unbox"); - AppendTypeNameWithoutSuffixes( - type.Name, - builders.TempStrBuilder); - AppendTypeNames( - typeParams, - builders.TempStrBuilder); - string unboxFuncName = builders.TempStrBuilder.ToString(); - - builders.TempStrBuilder.Length = 0; - builders.TempStrBuilder.Append("operator "); - AppendCppTypeFullName( - type, - builders.TempStrBuilder); - string unboxMethodDefinitionName = builders.TempStrBuilder.ToString(); - - builders.TempStrBuilder.Length = 0; - builders.TempStrBuilder.Append("explicit "); - builders.TempStrBuilder.Append(unboxMethodDefinitionName); - string unboxMethodDeclarationName = builders.TempStrBuilder.ToString(); - - ParameterInfo[] unboxParams = { - new ParameterInfo - { - Name = "val", - ParameterType = typeof(object), - DereferencedParameterType = typeof(object), - IsOut = false, - IsRef = false, - Kind = TypeKind.Class - } - }; - - ParameterInfo[] unboxCppParams = new ParameterInfo[0]; - - // C# init params - - // C# delegate types - AppendCsharpDelegateType( - unboxFuncName, - true, - type, - typeKind, - type, - unboxParams, - builders.CsharpDelegateTypes); - - // C# init call args - AppendCsharpCsharpDelegate( - unboxFuncName, - builders.CsharpInitCall, - builders.CsharpCsharpDelegates); - - // C# unbox function - AppendCsharpFunctionBeginning( - typeof(object), - unboxFuncName, - true, - TypeKind.Class, - type, - unboxParams, - builders.CsharpFunctions); - switch (typeKind) - { - case TypeKind.Class: - case TypeKind.ManagedStruct: - AppendHandleStoreTypeName( - type, - builders.CsharpFunctions); - builders.CsharpFunctions.Append(".Store(("); - AppendCsharpTypeFullName( - type, - builders.CsharpFunctions); - builders.CsharpFunctions.Append(")val);"); - break; - default: - builders.CsharpFunctions.Append('('); - AppendCsharpTypeFullName( - type, - builders.CsharpFunctions); - builders.CsharpFunctions.Append(")val;"); - break; - } - AppendCsharpFunctionReturn( - unboxParams, - type, - typeKind, - null, - true, - builders.CsharpFunctions); - - // C++ function pointers - AppendCppFunctionPointerDefinition( - unboxFuncName, - true, - GetTypeName(type), - typeKind, - unboxParams, - type, - builders.CppFunctionPointers); - - // C++ unbox method declaration and definition - AppendIndent( - 2, - builders.CppUnboxingMethodDeclarations); - AppendCppMethodDeclaration( - unboxMethodDeclarationName, - false, - false, - false, - null, - null, - unboxCppParams, - builders.CppUnboxingMethodDeclarations); - int indent = AppendNamespaceBeginning( - "System", - builders.CppMethodDefinitions); - AppendCppMethodDefinitionBegin( - GetTypeName(typeof(object)), - null, - unboxMethodDefinitionName, - null, - null, - unboxCppParams, - indent, - builders.CppMethodDefinitions); - AppendIndent( - indent, - builders.CppMethodDefinitions); - builders.CppMethodDefinitions.AppendLine("{"); - AppendIndent( - indent + 1, - builders.CppMethodDefinitions); - AppendCppTypeFullName( - type, - builders.CppMethodDefinitions); - builders.CppMethodDefinitions.Append(" returnVal("); - if (typeKind == TypeKind.ManagedStruct) - { - builders.CppMethodDefinitions.Append("Plugin::InternalUse::Only, "); - } - builders.CppMethodDefinitions.Append("Plugin::"); - builders.CppMethodDefinitions.Append(unboxFuncName); - builders.CppMethodDefinitions.AppendLine("(Handle));"); - AppendCppUnhandledExceptionHandling( - indent + 1, - builders.CppMethodDefinitions); - AppendIndent( - indent + 1, - builders.CppMethodDefinitions); - builders.CppMethodDefinitions.AppendLine("return returnVal;"); - AppendIndent( - indent, - builders.CppMethodDefinitions); - builders.CppMethodDefinitions.AppendLine("}"); - builders.CppMethodDefinitions.AppendLine("\t"); - - // C++ method definitions (end) - AppendCppMethodDefinitionsEnd( - indent, - builders.CppMethodDefinitions); - - // C++ init body - AppendCppInitBodyFunctionPointerParameterRead( - unboxFuncName, - true, - GetTypeName(type), - typeKind, - unboxParams, - type, - builders.CppInitBodyParameterReads); - } - - static void AppendCppBoxingMethodNames( - Type baseType, - StringBuilder tempBuilder, - out string boxMethodDefinitionName, - out string boxMethodDeclarationName) - { - tempBuilder.Length = 0; - tempBuilder.Append("operator "); - AppendCppTypeFullName( - baseType, - tempBuilder); - boxMethodDefinitionName = tempBuilder.ToString(); - - tempBuilder.Length = 0; - tempBuilder.Append("explicit "); - tempBuilder.Append(boxMethodDefinitionName); - boxMethodDeclarationName = tempBuilder.ToString(); - } - - static void AppendCppBoxingMethodDeclaration( - string boxMethodDeclarationName, - ParameterInfo[] boxCppParams, - int indent, - StringBuilder output) - { - AppendIndent( - indent, - output); - AppendCppMethodDeclaration( - boxMethodDeclarationName, - false, - false, - false, - null, - null, - boxCppParams, - output); - } - - static void AppendCppBoxingMethodDefinition( - Type enclosingType, - Type[] enclosingTypeTypeParams, - Type boxedType, - TypeKind typeKind, - string boxMethodDefinitionName, - string boxFuncName, - ParameterInfo[] boxCppParams, - int indent, - StringBuilder output) - { - AppendCppMethodDefinitionBegin( - GetTypeName(enclosingType), - null, - boxMethodDefinitionName, - enclosingTypeTypeParams, - null, - boxCppParams, - indent, - output); - AppendIndent( - indent, - output); - output.AppendLine("{"); - AppendIndent( - indent + 1, - output); - output.Append("int32_t handle = Plugin::"); - output.Append(boxFuncName); - output.Append('('); - if (typeKind == TypeKind.ManagedStruct) - { - output.Append("Handle"); - } - else - { - output.Append("*this"); - } - output.AppendLine(");"); - AppendCppUnhandledExceptionHandling( - indent + 1, - output); - AppendIndent( - indent + 1, - output); - output.AppendLine( - "if (handle)"); - AppendIndent( - indent + 1, - output); - output.AppendLine( - "{"); - AppendIndent( - indent + 2, - output); - AppendReferenceManagedHandleFunctionCall( - GetTypeName(typeof(object)), - TypeKind.Class, - null, - "handle", - output); - output.AppendLine(";"); - AppendIndent( - indent + 2, - output); - output.Append("return "); - AppendCppTypeFullName( - boxedType, - output); - output.AppendLine("(Plugin::InternalUse::Only, handle);"); - AppendIndent( - indent + 1, - output); - output.AppendLine( - "}"); - AppendIndent( - indent + 1, - output); - output.AppendLine("return nullptr;"); - AppendIndent( - indent, - output); - output.AppendLine("}"); - AppendIndent( - indent, - output); - output.AppendLine();; - } - - static void AppendHandleStoreTypeName( - Type type, - StringBuilder output) - { - output.Append("NativeScript.Bindings."); - if (IsManagedValueType(type)) - { - output.Append("StructStore<"); - AppendCsharpTypeFullName(type, output); - output.Append('>'); - } - else - { - output.Append("ObjectStore"); - } - } - - static void AppendConstructor( - string[] paramTypeNames, - string[] exceptionNames, - Type enclosingType, - bool enclosingTypeIsStatic, - TypeKind enclosingTypeKind, - Assembly[] assemblies, - Type[] enclosingTypeParams, - Type[] genericArgTypes, - Type[] interfaceTypes, - int indent, - StringBuilders builders) - { - // Get the constructor's parameters - ParameterInfo[] parameters; - if (enclosingType.IsValueType - && !enclosingType.IsPrimitive - && !enclosingType.IsEnum - && paramTypeNames.Length == 0) - { - // Allow parameterless constructor for structs - parameters = new ParameterInfo[0]; - } - else - { - string[] constructorParamTypeNames; - if (enclosingType.IsGenericType) - { - constructorParamTypeNames = OverrideGenericTypeNames( - paramTypeNames, - genericArgTypes, - enclosingTypeParams); - } - else - { - constructorParamTypeNames = paramTypeNames; - } - parameters = GetConstructorParameters( - enclosingType, - false, - constructorParamTypeNames); - } - - Type[] exceptionTypes = GetTypes( - exceptionNames, - assemblies); - - // Build uppercase function name - builders.TempStrBuilder.Length = 0; - AppendNamespace( - enclosingType.Namespace, - string.Empty, - builders.TempStrBuilder); - AppendTypeNameWithoutGenericSuffix( - enclosingType.Name, - builders.TempStrBuilder); - AppendTypeNames( - enclosingTypeParams, - builders.TempStrBuilder); - builders.TempStrBuilder.Append("Constructor"); - AppendParameterTypeNames( - parameters, - builders.TempStrBuilder); - string funcName = builders.TempStrBuilder.ToString(); - - TypeName enclosingTypeTypeName = GetTypeName(enclosingType); - - // Build C++ constructor method name - builders.TempStrBuilder.Length = 0; - AppendCppTypeName( - enclosingTypeTypeName, - builders.TempStrBuilder); - string cppMethodName = builders.TempStrBuilder.ToString(); - - // C# init param declaration - - // C# delegate type - Type delegateReturnType; - if (enclosingTypeKind == TypeKind.FullStruct) - { - delegateReturnType = enclosingType; - } - else - { - delegateReturnType = typeof(int); - } - AppendCsharpDelegateType( - funcName, - true, - enclosingType, - enclosingTypeKind, - delegateReturnType, - parameters, - builders.CsharpDelegateTypes); - - // C# init call param - AppendCsharpCsharpDelegate( - funcName, - builders.CsharpInitCall, - builders.CsharpCsharpDelegates); - - // C# function - if (enclosingTypeKind == TypeKind.FullStruct) - { - AppendCsharpFunctionBeginning( - enclosingType, - funcName, - true, - enclosingTypeKind, - enclosingType, - parameters, - builders.CsharpFunctions); - builders.CsharpFunctions.Append("new "); - AppendCsharpTypeFullName( - enclosingType, - builders.CsharpFunctions); - builders.CsharpFunctions.Append('('); - AppendCsharpFunctionCallParameters( - parameters, - builders.CsharpFunctions); - builders.CsharpFunctions.Append(");"); - AppendCsharpFunctionReturn( - parameters, - enclosingType, - enclosingTypeKind, - exceptionTypes, - true, - builders.CsharpFunctions); - } - else - { - AppendCsharpFunctionBeginning( - enclosingType, - funcName, - true, - enclosingTypeKind, - typeof(int), - parameters, - builders.CsharpFunctions); - AppendHandleStoreTypeName( - enclosingType, - builders.CsharpFunctions); - builders.CsharpFunctions.Append( - ".Store(new "); - AppendCsharpTypeFullName( - enclosingType, - builders.CsharpFunctions); - builders.CsharpFunctions.Append('('); - AppendCsharpFunctionCallParameters( - parameters, - builders.CsharpFunctions); - builders.CsharpFunctions.Append("));"); - AppendCsharpFunctionReturn( - parameters, - typeof(int), - TypeKind.Primitive, - exceptionTypes, - true, - builders.CsharpFunctions); - } - - // C++ function pointer - AppendCppFunctionPointerDefinition( - funcName, - true, - enclosingTypeTypeName, - enclosingTypeKind, - parameters, - enclosingType, - builders.CppFunctionPointers); - - // C++ type declaration - AppendIndent( - indent + 1, - builders.CppTypeDefinitions); - AppendCppMethodDeclaration( - cppMethodName, - enclosingTypeIsStatic, - false, - false, - null, - null, - parameters, - builders.CppTypeDefinitions); - - // C++ method definition - AppendCppMethodDefinitionBegin( - GetTypeName(enclosingType), - null, - cppMethodName, - enclosingTypeParams, - null, - parameters, - indent, - builders.CppMethodDefinitions); - if (enclosingTypeKind == TypeKind.Class) - { - AppendCppConstructorInitializerList( - interfaceTypes, - indent + 1, - builders.CppMethodDefinitions); - } - AppendIndent( - indent, - builders.CppMethodDefinitions); - builders.CppMethodDefinitions.AppendLine("{"); - AppendCppPluginFunctionCall( - true, - GetTypeName(enclosingType), - enclosingTypeKind, - enclosingTypeParams, - enclosingType, - funcName, - parameters, - indent + 1, - builders.CppMethodDefinitions); - if (enclosingTypeKind == TypeKind.FullStruct) - { - AppendIndent( - indent + 1, - builders.CppMethodDefinitions); - builders.CppMethodDefinitions.AppendLine( - "*this = returnValue;"); - } - else - { - AppendIndent( - indent + 1, - builders.CppMethodDefinitions); - builders.CppMethodDefinitions.AppendLine( - "Handle = returnValue;"); - AppendIndent( - indent + 1, - builders.CppMethodDefinitions); - builders.CppMethodDefinitions.AppendLine( - "if (returnValue)"); - AppendIndent( - indent + 1, - builders.CppMethodDefinitions); - builders.CppMethodDefinitions.AppendLine( - "{"); - AppendIndent( - indent + 2, - builders.CppMethodDefinitions); - AppendReferenceManagedHandleFunctionCall( - GetTypeName(enclosingType), - enclosingTypeKind, - enclosingTypeParams, - "returnValue", - builders.CppMethodDefinitions); - builders.CppMethodDefinitions.AppendLine(";"); - AppendIndent( - indent + 1, - builders.CppMethodDefinitions); - builders.CppMethodDefinitions.AppendLine( - "}"); - } - AppendIndent( - indent, - builders.CppMethodDefinitions); - builders.CppMethodDefinitions.AppendLine("}"); - AppendIndent( - indent, - builders.CppMethodDefinitions); - builders.CppMethodDefinitions.AppendLine();; - - // C++ init body - AppendCppInitBodyFunctionPointerParameterRead( - funcName, - true, - GetTypeName(enclosingType), - enclosingTypeKind, - parameters, - enclosingType, - builders.CppInitBodyParameterReads); - } - - static void AppendProperty( - JsonProperty jsonProperty, - Type enclosingType, - bool enclosingTypeIsStatic, - TypeKind enclosingTypeKind, - Type[] typeParams, - Type[] typeGenericArgumentTypes, - int indent, - Assembly[] assemblies, - StringBuilders builders) - { - JsonPropertyGet jsonPropertyGet = jsonProperty.Get; - if (jsonPropertyGet != null) - { - PropertyInfo property = null; - MethodInfo getMethod; - if (jsonPropertyGet.ParamTypes != null) - { - PropertyInfo[] properties = enclosingType.GetProperties(); - foreach (PropertyInfo curProperty in properties) - { - // Name must match - if (curProperty.Name != jsonProperty.Name) - { - continue; - } - - // Must have a get method - getMethod = curProperty.GetGetMethod(); - if (getMethod == null) - { - continue; - } - - // All parameters must match - if (CheckParametersMatch( - jsonPropertyGet.ParamTypes, - getMethod.GetParameters())) - { - property = curProperty; - break; - } - } - } - else - { - property = enclosingType.GetProperty(jsonProperty.Name); - } - - if (property == null) - { - builders.TempStrBuilder.Length = 0; - builders.TempStrBuilder.Append("Property '"); - builders.TempStrBuilder.Append(jsonProperty.Name); - builders.TempStrBuilder.Append("' not found on "); - builders.TempStrBuilder.Append(enclosingType); - throw new Exception(builders.TempStrBuilder.ToString()); - } - - getMethod = property.GetGetMethod(); - if (getMethod != null) - { - Type propertyType = property.PropertyType; - TypeKind propertyTypeKind = GetTypeKind(propertyType); - Type[] exceptionTypes = GetTypes( - jsonPropertyGet.Exceptions, - assemblies); - ParameterInfo[] parameters = ConvertParameters( - getMethod.GetParameters()); - OverrideGenericParameterTypes( - parameters, - typeGenericArgumentTypes, - typeParams); - AppendGetter( - property.Name, - "Property", - parameters, - enclosingTypeIsStatic, - enclosingTypeKind, - getMethod.IsStatic, - jsonPropertyGet.IsReadOnly, - enclosingType, - typeParams, - propertyType, - propertyTypeKind, - indent, - exceptionTypes, - builders); - } - } - - JsonPropertySet jsonPropertySet = jsonProperty.Set; - if (jsonPropertySet != null) - { - PropertyInfo property = null; - if (jsonPropertySet.ParamTypes != null) - { - PropertyInfo[] properties = enclosingType.GetProperties(); - foreach (PropertyInfo curProperty in properties) - { - // Name must match - if (curProperty.Name != jsonProperty.Name) - { - continue; - } - - // Must have a set method - MethodInfo setMethod = curProperty.GetSetMethod(); - if (setMethod == null) - { - continue; - } - - // All parameters must match - if (CheckParametersMatch( - jsonPropertySet.ParamTypes, - setMethod.GetParameters())) - { - property = curProperty; - break; - } - } - } - else - { - property = enclosingType.GetProperty(jsonProperty.Name); - } - - if (property == null) - { - builders.TempStrBuilder.Length = 0; - builders.TempStrBuilder.Append("Property '"); - builders.TempStrBuilder.Append(jsonProperty.Name); - builders.TempStrBuilder.Append("' not found on "); - builders.TempStrBuilder.Append(enclosingType); - throw new Exception(builders.TempStrBuilder.ToString()); - } - - MethodInfo method = property.GetSetMethod(); - if (method != null) - { - Type[] exceptionTypes = GetTypes( - jsonPropertySet.Exceptions, - assemblies); - ParameterInfo[] parameters = ConvertParameters( - method.GetParameters()); - OverrideGenericParameterTypes( - parameters, - typeGenericArgumentTypes, - typeParams); - AppendSetter( - property.Name, - "Property", - parameters, - enclosingTypeIsStatic, - enclosingTypeKind, - method.IsStatic, - jsonPropertySet.IsReadOnly, - enclosingType, - typeParams, - indent, - exceptionTypes, - builders); - } - } - } - - static void AppendFullValueTypeDefaultConstructor( - Type enclosingType, - int indent, - StringBuilders builders) - { - AppendIndent( - indent + 1, - builders.CppTypeDefinitions); - AppendTypeNameWithoutGenericSuffix( - enclosingType.Name, - builders.CppTypeDefinitions); - builders.CppTypeDefinitions.AppendLine("();"); - - AppendIndent( - indent, - builders.CppMethodDefinitions); - AppendTypeNameWithoutGenericSuffix( - enclosingType.Name, - builders.CppMethodDefinitions); - builders.CppMethodDefinitions.Append("::"); - AppendTypeNameWithoutGenericSuffix( - enclosingType.Name, - builders.CppMethodDefinitions); - builders.CppMethodDefinitions.AppendLine("()"); - AppendIndent( - indent, - builders.CppMethodDefinitions); - builders.CppMethodDefinitions.AppendLine("{"); - AppendIndent( - indent, - builders.CppMethodDefinitions); - builders.CppMethodDefinitions.AppendLine("}"); - AppendIndent( - indent, - builders.CppMethodDefinitions); - builders.CppMethodDefinitions.AppendLine();; - } - - static void AppendFullValueTypeFields( - Type enclosingType, - int indent, - StringBuilders builders) - { - FieldInfo[] fields = enclosingType.GetFields( - BindingFlags.Instance - | BindingFlags.Public - | BindingFlags.NonPublic); - Array.Sort(fields, DefaultFieldOrderComparer); - foreach (FieldInfo field in fields) - { - AppendIndent( - indent, - builders.CppTypeDefinitions); - AppendCppTypeFullName( - field.FieldType, - builders.CppTypeDefinitions); - builders.CppTypeDefinitions.Append(' '); - builders.CppTypeDefinitions.Append(field.Name); - builders.CppTypeDefinitions.AppendLine(";"); - } - } - - static void AppendField( - string jsonFieldName, - Type enclosingType, - bool enclosingTypeIsStatic, - TypeKind enclosingTypeKind, - Type[] typeTypeParams, - Type[] typeGenericArgumentTypes, - int indent, - StringBuilders builders) - { - FieldInfo field = enclosingType.GetField(jsonFieldName); - Type fieldType = OverrideGenericType( - field.FieldType, - typeGenericArgumentTypes, - typeTypeParams); - TypeKind fieldTypeKind = GetTypeKind(fieldType); - Type[] exceptionTypes = new Type[0]; - AppendGetter( - field.Name, - "Field", - new ParameterInfo[0], - enclosingTypeIsStatic, - enclosingTypeKind, - field.IsStatic, - true, - enclosingType, - typeTypeParams, - fieldType, - fieldTypeKind, - indent, - exceptionTypes, - builders); - ParameterInfo setParam = new ParameterInfo(); - setParam.Name = "value"; - setParam.ParameterType = fieldType; - setParam.IsOut = false; - setParam.IsRef = false; - setParam.DereferencedParameterType = setParam.ParameterType; - setParam.Kind = GetTypeKind( - setParam.DereferencedParameterType); - ParameterInfo[] parameters = { setParam }; - AppendSetter( - field.Name, - "Field", - parameters, - enclosingTypeIsStatic, - enclosingTypeKind, - field.IsStatic, - false, - enclosingType, - typeTypeParams, - indent, - exceptionTypes, - builders); - } - - static void AppendEvent( - JsonEvent jsonEvent, - Type enclosingType, - bool enclosingTypeIsStatic, - TypeKind enclosingTypeKind, - Type[] typeTypeParams, - int indent, - StringBuilders builders) - { - EventInfo eventInfo = enclosingType.GetEvent(jsonEvent.Name); - MethodInfo addMethod = eventInfo.GetAddMethod(); - MethodInfo removeMethod = eventInfo.GetRemoveMethod(); - Type eventType = eventInfo.EventHandlerType; - string uppercaseEventName = char.ToUpper(jsonEvent.Name[0]) - + jsonEvent.Name.Substring(1); - - ParameterInfo[] addRemoveParams = { - new ParameterInfo { - Name = "del", - ParameterType = eventType, - DereferencedParameterType = eventType, - IsOut = false, - IsRef = false, - Kind = TypeKind.Class, - IsVirtual = false - } - }; - - AppendEventAddRemoveMethod( - jsonEvent.Name, - uppercaseEventName, - "Add", - addMethod.IsStatic, - enclosingType, - enclosingTypeKind, - enclosingTypeIsStatic, - typeTypeParams, - addRemoveParams, - indent, - builders); - AppendEventAddRemoveMethod( - jsonEvent.Name, - uppercaseEventName, - "Remove", - removeMethod.IsStatic, - enclosingType, - enclosingTypeKind, - enclosingTypeIsStatic, - typeTypeParams, - addRemoveParams, - indent, - builders); - } - - static void AppendEventAddRemoveMethod( - string eventName, - string uppercaseEventName, - string operation, - bool methodIsStatic, - Type enclosingType, - TypeKind enclosingTypeKind, - bool enclosingTypeIsStatic, - Type[] typeTypeParams, - ParameterInfo[] methodParams, - int indent, - StringBuilders builders) - { - builders.TempStrBuilder.Length = 0; - AppendNamespace( - enclosingType.Namespace, - string.Empty, - builders.TempStrBuilder); - AppendTypeNameWithoutGenericSuffix( - enclosingType.Name, - builders.TempStrBuilder); - AppendTypeNames( - typeTypeParams, - builders.TempStrBuilder); - builders.TempStrBuilder.Append(operation); - builders.TempStrBuilder.Append("Event"); - builders.TempStrBuilder.Append(uppercaseEventName); - string funcName = builders.TempStrBuilder.ToString(); - - builders.TempStrBuilder.Length = 0; - builders.TempStrBuilder.Append(operation); - builders.TempStrBuilder.Append(uppercaseEventName); - string methodName = builders.TempStrBuilder.ToString(); - - // C# init param - - // C# delegate type - AppendCsharpDelegateType( - funcName, - methodIsStatic, - enclosingType, - enclosingTypeKind, - typeof(void), - methodParams, - builders.CsharpDelegateTypes); - - // C# init call arg - AppendCsharpCsharpDelegate( - funcName, - builders.CsharpInitCall, - builders.CsharpCsharpDelegates); - - // C# function - AppendCsharpFunctionBeginning( - enclosingType, - funcName, - methodIsStatic, - enclosingTypeKind, - typeof(void), - methodParams, - builders.CsharpFunctions); - AppendCsharpFunctionCallSubject( - enclosingType, - methodIsStatic, - builders.CsharpFunctions); - builders.CsharpFunctions.Append('.'); - builders.CsharpFunctions.Append(eventName); - // TODO: More safely differenciate between add/removing event delegates - if (funcName.Contains("RemoveEvent")) - { - builders.CsharpFunctions.Append(" -= del;"); - } - else - { - builders.CsharpFunctions.Append(" += del;"); - } - AppendCsharpFunctionEnd( - typeof(void), - null, - methodParams, - builders.CsharpFunctions); - - // C++ function pointer - AppendCppFunctionPointerDefinition( - funcName, - methodIsStatic, - GetTypeName(enclosingType), - enclosingTypeKind, - methodParams, - typeof(void), - builders.CppFunctionPointers); - - // C++ method declaration - Type cppReturnType = typeof(void); - string cppMethodName = methodName; - bool cppMethodIsStatic = methodIsStatic; - ParameterInfo[] cppParameters = methodParams; - ParameterInfo[] cppCallParameters = methodParams; - AppendIndent( - indent + 1, - builders.CppTypeDefinitions); - AppendCppMethodDeclaration( - cppMethodName, - enclosingTypeIsStatic, - false, - cppMethodIsStatic, - cppReturnType, - null, - cppParameters, - builders.CppTypeDefinitions); - - // C++ method definition - AppendCppMethodDefinitionBegin( - GetTypeName(enclosingType), - cppReturnType, - cppMethodName, - typeTypeParams, - null, - cppParameters, - indent, - builders.CppMethodDefinitions); - AppendIndent( - indent, - builders.CppMethodDefinitions); - builders.CppMethodDefinitions.AppendLine("{"); - AppendCppPluginFunctionCall( - methodIsStatic, - GetTypeName(enclosingType), - enclosingTypeKind, - typeTypeParams, - typeof(void), - funcName, - cppCallParameters, - indent + 1, - builders.CppMethodDefinitions); - AppendIndent( - indent, - builders.CppMethodDefinitions); - builders.CppMethodDefinitions.AppendLine("}"); - builders.CppMethodDefinitions.AppendLine("\t"); - - // C++ init body - AppendCppInitBodyFunctionPointerParameterRead( - funcName, - methodIsStatic, - GetTypeName(enclosingType), - enclosingTypeKind, - methodParams, - typeof(void), - builders.CppInitBodyParameterReads); - } - - static MethodInfo GetMethod( - JsonMethod jsonMethod, - Type enclosingType, - Type[] typeTypeParams, - Type[] genericArgTypes, - MethodInfo[] methods, - string[] methodGenericTypeNames) - { - // Map convenience method names to actual method names - switch (jsonMethod.Name) - { - case "+x": - jsonMethod.Name = "op_UnaryPlus"; - break; - case "-x": - jsonMethod.Name = "op_UnaryNegation"; - break; - case "!x": - jsonMethod.Name = "op_LogicalNot"; - break; - case "~x": - jsonMethod.Name = "op_OnesComplement"; - break; - case "x++": - jsonMethod.Name = "op_Increment"; - break; - case "x--": - jsonMethod.Name = "op_Decrement"; - break; - case "(true)x": - jsonMethod.Name = "op_True"; - break; - case "(false)x": - jsonMethod.Name = "op_False"; - break; - case "implicit": - jsonMethod.Name = "op_Implicit"; - break; - case "explicit": - jsonMethod.Name = "op_Explicit"; - break; - case "x+y": - jsonMethod.Name = "op_Addition"; - break; - case "x-y": - jsonMethod.Name = "op_Subtraction"; - break; - case "x*y": - jsonMethod.Name = "op_Multiply"; - break; - case "x/y": - jsonMethod.Name = "op_Division"; - break; - case "x%y": - jsonMethod.Name = "op_Modulus"; - break; - case "x&y": - jsonMethod.Name = "op_BitwiseAnd"; - break; - case "x|y": - jsonMethod.Name = "op_BitwiseOr"; - break; - case "x^y": - jsonMethod.Name = "op_ExclusiveOr"; - break; - case "x<>y": - jsonMethod.Name = "op_RightShift"; - break; - case "x==y": - jsonMethod.Name = "op_Equality"; - break; - case "x!=y": - jsonMethod.Name = "op_Inequality"; - break; - case "xy": - jsonMethod.Name = "op_GreaterThan"; - break; - case "x<=y": - jsonMethod.Name = "op_LessThanOrEqual"; - break; - case "x>=y": - jsonMethod.Name = "op_GreaterThanOrEqual"; - break; - } - - if (enclosingType.IsGenericType) - { - string[] overriddenParamTypeNames = OverrideGenericTypeNames( - jsonMethod.ParamTypes, - genericArgTypes, - typeTypeParams); - return GetMethod( - enclosingType, - methods, - jsonMethod.Name, - overriddenParamTypeNames, - methodGenericTypeNames); - } - else - { - return GetMethod( - enclosingType, - methods, - jsonMethod.Name, - jsonMethod.ParamTypes, - methodGenericTypeNames); - } - } - - static void AppendMethod( - JsonMethod jsonMethod, - Assembly[] assemblies, - Type enclosingType, - bool enclosingTypeIsStatic, - TypeKind enclosingTypeKind, - MethodInfo[] methods, - Type[] typeTypeParams, - Type[] genericArgTypes, - int indent, - StringBuilders builders) - { - Type[] exceptionTypes = GetTypes( - jsonMethod.Exceptions, - assemblies); - - if (jsonMethod.GenericParams != null) - { - // Generate for each set of generic types - bool generateDeclaration = true; - foreach (JsonGenericParams jsonGenericParams - in jsonMethod.GenericParams) - { - MethodInfo method = GetMethod( - jsonMethod, - enclosingType, - typeTypeParams, - genericArgTypes, - methods, - jsonGenericParams.Types); - Type[] methodTypeParams = GetTypes( - jsonGenericParams.Types, - assemblies); - method = method.MakeGenericMethod(methodTypeParams); - ParameterInfo[] parameters = ConvertParameters( - method.GetParameters()); - Type returnType = method.ReturnType; - TypeKind returnTypeKind = GetTypeKind(returnType); - AppendMethod( - enclosingType, - method.Name, - enclosingTypeIsStatic, - enclosingTypeKind, - method.IsStatic, - jsonMethod.IsReadOnly, - returnType, - returnTypeKind, - typeTypeParams, - methodTypeParams, - parameters, - generateDeclaration, - indent, - exceptionTypes, - builders); - generateDeclaration = false; - } - } - else - { - MethodInfo method = GetMethod( - jsonMethod, - enclosingType, - typeTypeParams, - genericArgTypes, - methods, - null); - ParameterInfo[] parameters = ConvertParameters( - method.GetParameters()); - Type returnType = method.ReturnType; - TypeKind returnTypeKind = GetTypeKind(returnType); - AppendMethod( - enclosingType, - method.Name, - enclosingTypeIsStatic, - enclosingTypeKind, - method.IsStatic, - jsonMethod.IsReadOnly, - returnType, - returnTypeKind, - typeTypeParams, - null, - parameters, - true, - indent, - exceptionTypes, - builders); - } - } - - static Type OverrideGenericType( - Type genericType, - Type[] genericArgumentTypes, - Type[] overrideTypes) - { - if (genericType.IsGenericParameter) - { - for (int i = 0, len = genericArgumentTypes.Length; i < len; ++i) - { - if (genericType == genericArgumentTypes[i]) - { - return overrideTypes[i]; - } - } - } - return genericType; - } - - static void OverrideGenericParameterTypes( - ParameterInfo[] parameters, - Type[] typeGenericArgumentTypes, - Type[] typeParams) - { - foreach (ParameterInfo info in parameters) - { - info.ParameterType = OverrideGenericType( - info.ParameterType, - typeGenericArgumentTypes, - typeParams); - } - } - - static string[] OverrideGenericTypeNames( - string[] typeNames, - Type[] genericArgTypes, - Type[] typeParams) - { - int numParams = typeNames.Length; - string[] overriddenParamTypeNames = new string[numParams]; - for (int i = 0; i < numParams; ++i) - { - string typeName = typeNames[i]; - foreach (Type genericArgType in genericArgTypes) - { - if (CheckTypeNameMatches( - typeName, - genericArgType)) - { - typeName = typeParams[i].FullName; - break; - } - } - overriddenParamTypeNames[i] = typeName; - } - return overriddenParamTypeNames; - } - - static void AppendMethod( - Type enclosingType, - string methodName, - bool enclosingTypeIsStatic, - TypeKind enclosingTypeKind, - bool methodIsStatic, - bool isReadOnly, - Type returnType, - TypeKind returnTypeKind, - Type[] enclosingTypeParams, - Type[] methodTypeParams, - ParameterInfo[] parameters, - bool generateDeclaration, - int indent, - Type[] exceptionTypes, - StringBuilders builders) - { - // Build uppercase function name - builders.TempStrBuilder.Length = 0; - AppendNamespace( - enclosingType.Namespace, - string.Empty, - builders.TempStrBuilder); - AppendTypeNameWithoutGenericSuffix( - enclosingType.Name, - builders.TempStrBuilder); - AppendTypeNames( - enclosingTypeParams, - builders.TempStrBuilder); - builders.TempStrBuilder.Append("Method"); - builders.TempStrBuilder.Append(methodName); - AppendTypeNames( - methodTypeParams, - builders.TempStrBuilder); - AppendParameterTypeNames( - parameters, - builders.TempStrBuilder); - string funcName = builders.TempStrBuilder.ToString(); - - // C# init param declaration - - // C# delegate type - AppendCsharpDelegateType( - funcName, - methodIsStatic, - enclosingType, - enclosingTypeKind, - returnType, - parameters, - builders.CsharpDelegateTypes); - - // C# init call param - AppendCsharpCsharpDelegate( - funcName, - builders.CsharpInitCall, - builders.CsharpCsharpDelegates); - - // C# function - AppendCsharpFunctionBeginning( - enclosingType, - funcName, - methodIsStatic, - enclosingTypeKind, - returnType, - parameters, - builders.CsharpFunctions); - if (methodName.StartsWith("op_")) - { - string op; - switch (methodName) - { - case "op_UnaryPlus": - op = "+"; - break; - case "op_UnaryNegation": - op = "-"; - break; - case "op_LogicalNot": - op = "!"; - break; - case "op_OnesComplement": - op = "~"; - break; - case "op_Increment": - op = "++"; - break; - case "op_Decrement": - op = "--"; - break; - case "op_Implicit": - op = string.Empty; - break; - case "op_Explicit": - builders.TempStrBuilder.Length = 0; - builders.TempStrBuilder.Append('('); - AppendTypeNameWithoutGenericSuffix( - returnType.Name, - builders.TempStrBuilder); - builders.TempStrBuilder.Append(')'); - op = builders.TempStrBuilder.ToString(); - break; - case "op_True": - op = "(true)"; - break; - case "op_False": - op = "(false)"; - break; - case "op_Addition": - op = "+"; - break; - case "op_Subtraction": - op = "-"; - break; - case "op_Multiply": - op = "*"; - break; - case "op_Division": - op = "/"; - break; - case "op_Modulus": - op = "%"; - break; - case "op_BitwiseAnd": - op = "&"; - break; - case "op_BitwiseOr": - op = "|"; - break; - case "op_ExclusiveOr": - op = "^"; - break; - case "op_LeftShift": - op = "<<"; - break; - case "op_RightShift": - op = ">>"; - break; - case "op_Equality": - op = "=="; - break; - case "op_Inequality": - op = "!="; - break; - case "op_LessThan": - op = "<"; - break; - case "op_GreaterThan": - op = ">"; - break; - case "op_LessThanOrEqual": - op = "<="; - break; - case "op_GreaterThanOrEqual": - op = ">="; - break; - default: - throw new Exception( - "Unsupported overloaded operator: " + methodName); - } - switch (parameters.Length) - { - case 1: - builders.CsharpFunctions.Append(op); - builders.CsharpFunctions.Append(parameters[0].Name); - break; - case 2: - builders.CsharpFunctions.Append(parameters[0].Name); - builders.CsharpFunctions.Append(' '); - builders.CsharpFunctions.Append(op); - builders.CsharpFunctions.Append(' '); - builders.CsharpFunctions.Append(parameters[1].Name); - break; - default: - throw new Exception( - "Unsupported number of overloaded operator params: " - + parameters.Length); - } - } - else - { - AppendCsharpFunctionCallSubject( - enclosingType, - methodIsStatic, - builders.CsharpFunctions); - builders.CsharpFunctions.Append('.'); - builders.CsharpFunctions.Append(methodName); - AppendCSharpTypeParameters( - methodTypeParams, - builders.CsharpFunctions); - builders.CsharpFunctions.Append('('); - AppendCsharpFunctionCallParameters( - parameters, - builders.CsharpFunctions); - builders.CsharpFunctions.Append(')'); - } - builders.CsharpFunctions.Append(';'); - if (!isReadOnly - && !methodIsStatic - && enclosingTypeKind == TypeKind.ManagedStruct) - { - AppendStructStoreReplace( - enclosingType, - "thisHandle", - "thiz", - builders.CsharpFunctions); - } - AppendCsharpFunctionReturn( - parameters, - returnType, - returnTypeKind, - exceptionTypes, - false, - builders.CsharpFunctions); - - // C++ function pointer - AppendCppFunctionPointerDefinition( - funcName, - methodIsStatic, - GetTypeName(enclosingType), - enclosingTypeKind, - parameters, - returnType, - builders.CppFunctionPointers); - - // C++ method declaration - string cppMethodName; - bool cppMethodIsStatic; - ParameterInfo[] cppParameters; - ParameterInfo[] cppCallParameters; - Type cppReturnType = returnType; - if (methodName.StartsWith("op_")) - { - switch (methodName) - { - case "op_UnaryPlus": - cppMethodName = "operator+"; - break; - case "op_UnaryNegation": - cppMethodName = "operator-"; - break; - case "op_LogicalNot": - cppMethodName = "operator!"; - break; - case "op_OnesComplement": - cppMethodName = "operator~"; - break; - case "op_Increment": - cppMethodName = "operator++"; - break; - case "op_Decrement": - cppMethodName = "operator--"; - break; - case "op_Implicit": - builders.TempStrBuilder.Length = 0; - builders.TempStrBuilder.Append("operator "); - AppendCppTypeFullName( - returnType, - builders.TempStrBuilder); - cppMethodName = builders.TempStrBuilder.ToString(); - cppReturnType = null; - break; - case "op_Explicit": - builders.TempStrBuilder.Length = 0; - builders.TempStrBuilder.Append("explicit operator "); - AppendCppTypeFullName( - returnType, - builders.TempStrBuilder); - cppMethodName = builders.TempStrBuilder.ToString(); - cppReturnType = null; - break; - case "op_True": - cppMethodName = "TrueOperator"; - break; - case "op_False": - cppMethodName = "FalseOperator"; - break; - case "op_Addition": - cppMethodName = "operator+"; - break; - case "op_Subtraction": - cppMethodName = "operator-"; - break; - case "op_Multiply": - cppMethodName = "operator*"; - break; - case "op_Division": - cppMethodName = "operator/"; - break; - case "op_Modulus": - cppMethodName = "operator%"; - break; - case "op_BitwiseAnd": - cppMethodName = "operator&"; - break; - case "op_BitwiseOr": - cppMethodName = "operator|"; - break; - case "op_ExclusiveOr": - cppMethodName = "operator^"; - break; - case "op_LeftShift": - cppMethodName = "operator<<"; - break; - case "op_RightShift": - cppMethodName = "operator>>"; - break; - case "op_Equality": - cppMethodName = "operator=="; - break; - case "op_Inequality": - cppMethodName = "operator!="; - break; - case "op_LessThan": - cppMethodName = "operator<"; - break; - case "op_GreaterThan": - cppMethodName = "operator>"; - break; - case "op_LessThanOrEqual": - cppMethodName = "operator<="; - break; - case "op_GreaterThanOrEqual": - cppMethodName = "operator>="; - break; - default: - throw new Exception( - "Unsupported overloaded operator: " + methodName); - } - cppMethodIsStatic = false; - ParameterInfo thisParam; - switch (enclosingTypeKind) - { - case TypeKind.Class: - case TypeKind.ManagedStruct: - thisParam = new ParameterInfo{ - Name = "Handle", - ParameterType = typeof(int), - DereferencedParameterType = typeof(int), - IsOut = false, - IsRef = false, - Kind = TypeKind.Primitive - }; - break; - default: - thisParam = new ParameterInfo{ - Name = "*this", - ParameterType = enclosingType, - DereferencedParameterType = enclosingType, - IsOut = false, - IsRef = false, - Kind = TypeKind.Primitive - }; - break; - } - switch (parameters.Length) - { - case 1: - cppParameters = new ParameterInfo[0]; - cppCallParameters = new [] { - thisParam }; - break; - case 2: - cppParameters = new [] { - parameters[0] }; - cppCallParameters = new [] { - thisParam, - parameters[0] - }; - break; - default: - throw new Exception( - "Unsupported number of overloaded operator parameters: " - + parameters.Length); - } - } - else - { - cppMethodName = methodName; - cppMethodIsStatic = methodIsStatic; - cppParameters = parameters; - cppCallParameters = parameters; - } - if (generateDeclaration) - { - AppendIndent( - indent + 1, - builders.CppTypeDefinitions); - AppendCppMethodDeclaration( - cppMethodName, - enclosingTypeIsStatic, - // Mark as virtual if method/class is not static or generic - cppMethodIsStatic || enclosingTypeIsStatic || methodTypeParams != null? false : true, - cppMethodIsStatic, - cppReturnType, - methodTypeParams, - cppParameters, - builders.CppTypeDefinitions); - } - - // C++ method definition - AppendCppMethodDefinitionBegin( - GetTypeName(enclosingType), - cppReturnType, - cppMethodName, - enclosingTypeParams, - methodTypeParams, - cppParameters, - indent, - builders.CppMethodDefinitions); - AppendIndent( - indent, - builders.CppMethodDefinitions); - builders.CppMethodDefinitions.AppendLine("{"); - AppendCppPluginFunctionCall( - methodIsStatic, - GetTypeName(enclosingType), - enclosingTypeKind, - enclosingTypeParams, - returnType, - funcName, - cppCallParameters, - indent + 1, - builders.CppMethodDefinitions); - AppendCppMethodReturn( - returnType, - returnTypeKind, - indent + 1, - builders.CppMethodDefinitions); - AppendIndent( - indent, - builders.CppMethodDefinitions); - builders.CppMethodDefinitions.AppendLine("}"); - builders.CppMethodDefinitions.AppendLine("\t"); - - // C++ init body - AppendCppInitBodyFunctionPointerParameterRead( - funcName, - methodIsStatic, - GetTypeName(enclosingType), - enclosingTypeKind, - parameters, - returnType, - builders.CppInitBodyParameterReads); - } - - static void AppendCSharpTypeParameters( - Type[] typeParams, - StringBuilder output) - { - if (typeParams != null && typeParams.Length > 0) - { - output.Append('<'); - for (int i = 0; i < typeParams.Length; ++i) - { - Type typeParam = typeParams[i]; - AppendCsharpTypeFullName(typeParam, output); - if (i != typeParams.Length - 1) - { - output.Append(", "); - } - } - output.Append('>'); - } - } - - static void AppendCppTypeParameters( - Type[] typeParams, - StringBuilder output) - { - if (typeParams != null && typeParams.Length > 0) - { - output.Append('<'); - for (int i = 0; i < typeParams.Length; ++i) - { - Type typeParam = typeParams[i]; - AppendCppTypeFullName(typeParam, output); - if (i != typeParams.Length - 1) - { - output.Append(", "); - } - } - output.Append('>'); - } - } - - static void AppendCppFunctionCall( - string funcName, - ParameterInfo[] parameters, - Type returnType, - bool enclosingTypeIsStatic, - int indent, - StringBuilder output) - { - foreach (ParameterInfo param in parameters) - { - if (param.Kind == TypeKind.Class - || param.Kind == TypeKind.ManagedStruct) - { - AppendIndent( - indent, - output); - output.Append("int "); - output.Append(param.Name); - output.Append("Handle = "); - AppendHandleStoreTypeName( - param.DereferencedParameterType, - output); - output.Append('.'); - if (param.Kind == TypeKind.Class) - { - output.Append("GetHandle"); - } - else - { - output.Append("Store"); - } - output.Append('('); - output.Append(param.Name); - output.AppendLine(");"); - } - } - if (!enclosingTypeIsStatic) - { - AppendIndent( - indent, - output); - output.AppendLine( - "int thisHandle = NativeScript.Bindings.ObjectStore.GetHandle(this);"); - } - AppendIndent( - indent, - output); - if (returnType != typeof(void)) - { - output.Append("var returnVal = "); - } - output.Append("NativeScript.Bindings."); - output.Append(funcName); - output.Append('('); - if (!enclosingTypeIsStatic) - { - output.Append("thisHandle"); - if (parameters.Length > 0) - { - output.Append(", "); - } - } - for (int i = 0; i < parameters.Length; ++i) - { - ParameterInfo param = parameters[i]; - output.Append(param.Name); - if (param.Kind == TypeKind.Class - || param.Kind == TypeKind.ManagedStruct) - { - output.Append("Handle"); - } - if (i != parameters.Length - 1) - { - output.Append(", "); - } - } - output.AppendLine(");"); - AppendIndent( - indent, - output); - output.AppendLine("if (NativeScript.Bindings.UnhandledCppException != null)"); - AppendIndent( - indent, - output); - output.AppendLine("{"); - AppendIndent( - indent + 1, - output); - output.AppendLine("Exception ex = NativeScript.Bindings.UnhandledCppException;"); - AppendIndent( - indent + 1, - output); - output.AppendLine("NativeScript.Bindings.UnhandledCppException = null;"); - AppendIndent( - indent + 1, - output); - output.AppendLine("throw ex;"); - AppendIndent( - indent, - output); - output.AppendLine("}"); - } - - static void AppendArray( - JsonArray jsonArray, - Assembly[] assemblies, - StringBuilders builders) - { - // Get element type - Type elementType = GetType( - jsonArray.Type, - assemblies); - TypeKind elementTypeKind = GetTypeKind(elementType); - - // Default ranks to just 1 - int[] ranks; - if (jsonArray.Ranks == null - || jsonArray.Ranks.Length == 0) - { - ranks = new[]{ 1 }; - } - else - { - ranks = jsonArray.Ranks; - } - - // C++ element proxy for [1-R] for all ranks R - Type[] cppTypeParams = { elementType }; - foreach (int rank in ranks) - { - // Build array name - builders.TempStrBuilder.Length = 0; - AppendCppArrayTypeName( - rank, - builders.TempStrBuilder); - string cppArrayTypeName = builders.TempStrBuilder.ToString(); - - for (int i = 1; i <= rank; ++i) - { - AppendArrayElementProxy( - elementType, - elementTypeKind, - i, - rank, - cppTypeParams, - cppArrayTypeName, - builders); - } - } - - foreach (int rank in ranks) - { - // Build array name - builders.TempStrBuilder.Length = 0; - AppendCppArrayTypeName( - rank, - builders.TempStrBuilder); - string cppArrayTypeName = builders.TempStrBuilder.ToString(); - - // Build array name with element type - builders.TempStrBuilder.Append('<'); - AppendCppTypeFullName( - elementType, - builders.TempStrBuilder); - builders.TempStrBuilder.Append('>'); - string cppGenericArrayTypeName = builders.TempStrBuilder.ToString(); - - // Build element proxy name - builders.TempStrBuilder.Length = 0; - AppendCppArrayElementProxyName( - 1, - rank, - elementType, - builders.TempStrBuilder); - string cppElementProxyTypeName = builders.TempStrBuilder.ToString(); - - // Build "TypeArray" name - builders.TempStrBuilder.Length = 0; - AppendNamespace( - elementType.Namespace, - string.Empty, - builders.TempStrBuilder); - AppendTypeNameWithoutGenericSuffix( - elementType.Name, - builders.TempStrBuilder); - builders.TempStrBuilder.Append(cppArrayTypeName); - string bindingArrayTypeName = builders.TempStrBuilder.ToString(); - - // MakeArrayType() creates a Type for a "vector" - // MakeArrayType(int) creates a Type for a multi-dimensional array - // Use MakeArrayType() instead of MakeArrayType(1) to create a vector - // instead of a multi-dimensional array with one dimension. - // This avoids problems like the name being "float[*]", which is - // invalid C# code. - Type arrayType; - if (rank == 1) - { - arrayType = elementType.MakeArrayType(); - } - else - { - arrayType = elementType.MakeArrayType(rank); - } - - // C++ type declaration - int indent = AppendCppTypeDeclaration( - GetTypeName(cppArrayTypeName, "System"), - false, - cppTypeParams, - builders.CppTemplateSpecializationDeclarations); - - // C++ type definition (beginning) - Type[] interfaceTypes = GetDirectInterfaces(arrayType); - AppendCppTypeDefinitionBegin( - GetTypeName(cppArrayTypeName, "System"), - TypeKind.Class, - cppTypeParams, - GetTypeName("Array", "System"), - null, - interfaceTypes, - false, - indent, - builders.CppTypeDefinitions); - - // C++ method definitions (beginning) - Type[] cppCtorInitTypes = GetCppCtorInitTypes( - arrayType, - false); - int localRank = rank; - int cppMethodDefinitionsIndent = AppendCppMethodDefinitionsBegin( - GetTypeName(cppArrayTypeName, "System"), - TypeKind.Class, - cppTypeParams, - cppCtorInitTypes, - false, - (extraIndent, subject) => { - AppendIndent( - extraIndent, - builders.CppMethodDefinitions); - builders.CppMethodDefinitions.Append(subject); - builders.CppMethodDefinitions.AppendLine( - "InternalLength = 0;"); - if (localRank > 1) - { - for (int i = 0; i < localRank; ++i) - { - AppendIndent( - extraIndent, - builders.CppMethodDefinitions); - builders.CppMethodDefinitions.Append(subject); - builders.CppMethodDefinitions.Append( - "InternalLengths["); - builders.CppMethodDefinitions.Append(i); - builders.CppMethodDefinitions.AppendLine( - "] = 0;"); - } - } - }, - (extraIndent, subject) => { - AppendIndent( - extraIndent, - builders.CppMethodDefinitions); - builders.CppMethodDefinitions.Append( - "InternalLength = "); - builders.CppMethodDefinitions.Append(subject); - builders.CppMethodDefinitions.AppendLine( - "InternalLength;"); - if (localRank > 1) - { - for (int i = 0; i < localRank; ++i) - { - AppendIndent( - extraIndent, - builders.CppMethodDefinitions); - builders.CppMethodDefinitions.Append( - "InternalLengths["); - builders.CppMethodDefinitions.Append(i); - builders.CppMethodDefinitions.Append( - "] = "); - builders.CppMethodDefinitions.Append(subject); - builders.CppMethodDefinitions.Append( - "InternalLengths["); - builders.CppMethodDefinitions.Append(i); - builders.CppMethodDefinitions.AppendLine( - "];"); - } - } - }, - indent, - builders.CppMethodDefinitions); - - // C++ fields - AppendIndent( - indent + 1, - builders.CppTypeDefinitions); - builders.CppTypeDefinitions.AppendLine( - "int32_t InternalLength;"); - if (rank > 1) - { - AppendIndent( - indent + 1, - builders.CppTypeDefinitions); - builders.CppTypeDefinitions.Append( - "int32_t InternalLengths["); - builders.CppTypeDefinitions.Append(rank); - builders.CppTypeDefinitions.AppendLine("];"); - } - - AppendArrayConstructor( - elementType, - arrayType, - cppArrayTypeName, - rank, - bindingArrayTypeName, - cppCtorInitTypes, - indent, - builders); - - // Base GetLength - AppendArrayCppGetLengthFunction( - indent, - cppArrayTypeName, - cppTypeParams, - builders); - - // GetLength for multi-dimensional arrays - if (rank > 1) - { - AppendArrayMultidimensionalGetLength( - elementType, - arrayType, - cppArrayTypeName, - rank, - bindingArrayTypeName, - indent, - builders); - } - - AppendArrayCppGetRankFunction( - indent, - cppArrayTypeName, - cppTypeParams, - rank, - builders); - - AppendArrayGetItem( - elementType, - elementTypeKind, - arrayType, - cppArrayTypeName, - rank, - builders); - - AppendArraySetItem( - elementType, - arrayType, - cppArrayTypeName, - rank, - builders); - - // C++ operator[] method declaration - AppendIndent( - indent + 1, - builders.CppTypeDefinitions); - builders.CppTypeDefinitions.Append("Plugin::"); - AppendCppArrayElementProxyName( - 1, - rank, - elementType, - builders.CppTypeDefinitions); - builders.CppTypeDefinitions.Append(' '); - AppendTypeNameWithoutGenericSuffix( - "operator[]", - builders.CppTypeDefinitions); - builders.CppTypeDefinitions.AppendLine("(int32_t index);"); - - // C++ operator[] method definition - AppendCppArrayIndexOperatorMethodDefinition( - 0, - cppMethodDefinitionsIndent, - GetTypeName(cppGenericArrayTypeName, "System"), - cppElementProxyTypeName, - builders.CppMethodDefinitions); - - // C++ type definition (end) - AppendCppTypeDefinitionEnd( - false, - indent, - builders.CppTypeDefinitions); - - // C++ method definitions (ending) - AppendCppMethodDefinitionsEnd( - cppMethodDefinitionsIndent, - builders.CppMethodDefinitions); - - if (rank == 1) - { - AppendArrayIterator( - elementType, - cppGenericArrayTypeName, - bindingArrayTypeName, - builders.CppTypeDefinitions, - builders.CppMethodDefinitions); - } - } - } - - static void AppendArrayIterator( - Type elementType, - string cppGenericArrayTypeName, - string bindingArrayTypeName, - StringBuilder cppTypeDefinitions, - StringBuilder cppMethodDefinitions) - { - // Iterator type definition - cppTypeDefinitions.AppendLine("namespace Plugin"); - cppTypeDefinitions.AppendLine("{"); - cppTypeDefinitions.Append("\tstruct "); - cppTypeDefinitions.Append(bindingArrayTypeName); - cppTypeDefinitions.AppendLine("Iterator"); - cppTypeDefinitions.AppendLine("\t{"); - cppTypeDefinitions.Append("\t\tSystem::"); - cppTypeDefinitions.Append(cppGenericArrayTypeName); - cppTypeDefinitions.AppendLine("& array;"); - cppTypeDefinitions.AppendLine("\t\tint index;"); - cppTypeDefinitions.Append("\t\t"); - cppTypeDefinitions.Append(bindingArrayTypeName); - cppTypeDefinitions.Append("Iterator(System::"); - cppTypeDefinitions.Append(cppGenericArrayTypeName); - cppTypeDefinitions.AppendLine("& array, int32_t index);"); - cppTypeDefinitions.Append("\t\t"); - cppTypeDefinitions.Append(bindingArrayTypeName); - cppTypeDefinitions.AppendLine("Iterator& operator++();"); - cppTypeDefinitions.Append("\t\tbool operator!=(const "); - cppTypeDefinitions.Append(bindingArrayTypeName); - cppTypeDefinitions.AppendLine("Iterator& other);"); - cppTypeDefinitions.Append("\t\t"); - AppendCppTypeFullName( - elementType, - cppTypeDefinitions); - cppTypeDefinitions.AppendLine(" operator*();"); - cppTypeDefinitions.AppendLine("\t};"); - cppTypeDefinitions.AppendLine("}"); - cppTypeDefinitions.AppendLine();; - - // begin() and end() declarations - cppTypeDefinitions.AppendLine("namespace System"); - cppTypeDefinitions.AppendLine("{"); - cppTypeDefinitions.Append("\tPlugin::"); - cppTypeDefinitions.Append(bindingArrayTypeName); - cppTypeDefinitions.Append("Iterator begin(System::"); - cppTypeDefinitions.Append(cppGenericArrayTypeName); - cppTypeDefinitions.AppendLine("& array);"); - cppTypeDefinitions.Append("\tPlugin::"); - cppTypeDefinitions.Append(bindingArrayTypeName); - cppTypeDefinitions.Append("Iterator end(System::"); - cppTypeDefinitions.Append(cppGenericArrayTypeName); - cppTypeDefinitions.AppendLine("& array);"); - cppTypeDefinitions.AppendLine("}"); - cppTypeDefinitions.AppendLine();; - - // Iterator method definitions - cppMethodDefinitions.AppendLine("namespace Plugin"); - cppMethodDefinitions.AppendLine("{"); - cppMethodDefinitions.Append('\t'); - cppMethodDefinitions.Append(bindingArrayTypeName); - cppMethodDefinitions.Append("Iterator::"); - cppMethodDefinitions.Append(bindingArrayTypeName); - cppMethodDefinitions.Append("Iterator(System::"); - cppMethodDefinitions.Append(cppGenericArrayTypeName); - cppMethodDefinitions.AppendLine("& array, int32_t index)"); - cppMethodDefinitions.AppendLine("\t\t: array(array)"); - cppMethodDefinitions.AppendLine("\t\t, index(index)"); - cppMethodDefinitions.AppendLine("\t{"); - cppMethodDefinitions.AppendLine("\t}"); - cppMethodDefinitions.AppendLine("\t"); - cppMethodDefinitions.Append('\t'); - cppMethodDefinitions.Append(bindingArrayTypeName); - cppMethodDefinitions.Append("Iterator& "); - cppMethodDefinitions.Append(bindingArrayTypeName); - cppMethodDefinitions.Append("Iterator::"); - cppMethodDefinitions.AppendLine("operator++()"); - cppMethodDefinitions.AppendLine("\t{"); - cppMethodDefinitions.AppendLine("\t\tindex++;"); - cppMethodDefinitions.AppendLine("\t\treturn *this;"); - cppMethodDefinitions.AppendLine("\t}"); - cppMethodDefinitions.AppendLine("\t"); - cppMethodDefinitions.Append("\tbool "); - cppMethodDefinitions.Append(bindingArrayTypeName); - cppMethodDefinitions.Append("Iterator::"); - cppMethodDefinitions.Append("operator!=(const "); - cppMethodDefinitions.Append(bindingArrayTypeName); - cppMethodDefinitions.AppendLine("Iterator& other)"); - cppMethodDefinitions.AppendLine("\t{"); - cppMethodDefinitions.AppendLine("\t\treturn index != other.index;"); - cppMethodDefinitions.AppendLine("\t}"); - cppMethodDefinitions.AppendLine("\t"); - cppMethodDefinitions.Append('\t'); - AppendCppTypeFullName( - elementType, - cppMethodDefinitions); - cppMethodDefinitions.Append(' '); - cppMethodDefinitions.Append(bindingArrayTypeName); - cppMethodDefinitions.Append("Iterator::"); - cppMethodDefinitions.AppendLine("operator*()"); - cppMethodDefinitions.AppendLine("\t{"); - cppMethodDefinitions.AppendLine("\t\treturn array[index];"); - cppMethodDefinitions.AppendLine("\t}"); - cppMethodDefinitions.AppendLine("}"); - cppMethodDefinitions.AppendLine();; - - // begin() and end() definitions - cppMethodDefinitions.AppendLine("namespace System"); - cppMethodDefinitions.AppendLine("{"); - cppMethodDefinitions.Append("\tPlugin::"); - cppMethodDefinitions.Append(bindingArrayTypeName); - cppMethodDefinitions.Append("Iterator begin(System::"); - cppMethodDefinitions.Append(cppGenericArrayTypeName); - cppMethodDefinitions.AppendLine("& array)"); - cppMethodDefinitions.AppendLine("\t{"); - cppMethodDefinitions.Append("\t\treturn Plugin::"); - cppMethodDefinitions.Append(bindingArrayTypeName); - cppMethodDefinitions.AppendLine("Iterator(array, 0);"); - cppMethodDefinitions.AppendLine("\t}"); - cppMethodDefinitions.AppendLine("\t"); - cppMethodDefinitions.Append("\tPlugin::"); - cppMethodDefinitions.Append(bindingArrayTypeName); - cppMethodDefinitions.Append("Iterator end(System::"); - cppMethodDefinitions.Append(cppGenericArrayTypeName); - cppMethodDefinitions.AppendLine("& array)"); - cppMethodDefinitions.AppendLine("\t{"); - cppMethodDefinitions.Append("\t\treturn Plugin::"); - cppMethodDefinitions.Append(bindingArrayTypeName); - cppMethodDefinitions.AppendLine("Iterator(array, array.GetLength() - 1);"); - cppMethodDefinitions.AppendLine("\t}"); - cppMethodDefinitions.AppendLine("}"); - cppMethodDefinitions.AppendLine();; - } - - static void AppendGenericEnumerableIterator( - Type enumerableType, - Type enumeratorType, - Type elementType, - string bindingEnumerableTypeName, - StringBuilder cppTypeDefinitions, - StringBuilder cppMethodDefinitions) - { - // Iterator type definition - cppTypeDefinitions.AppendLine("namespace Plugin"); - cppTypeDefinitions.AppendLine("{"); - cppTypeDefinitions.Append("\tstruct "); - cppTypeDefinitions.Append(bindingEnumerableTypeName); - cppTypeDefinitions.AppendLine("Iterator"); - cppTypeDefinitions.AppendLine("\t{"); - cppTypeDefinitions.Append("\t\t"); - AppendCppTypeFullName( - enumeratorType, - cppTypeDefinitions); - cppTypeDefinitions.AppendLine(" enumerator;"); - cppTypeDefinitions.AppendLine("\t\tbool hasMore;"); - cppTypeDefinitions.Append("\t\t"); - cppTypeDefinitions.Append(bindingEnumerableTypeName); - cppTypeDefinitions.AppendLine("Iterator(decltype(nullptr));"); - cppTypeDefinitions.Append("\t\t"); - cppTypeDefinitions.Append(bindingEnumerableTypeName); - cppTypeDefinitions.Append("Iterator("); - AppendCppTypeFullName( - enumerableType, - cppTypeDefinitions); - cppTypeDefinitions.AppendLine("& enumerable);"); - cppTypeDefinitions.Append("\t\t~"); - cppTypeDefinitions.Append(bindingEnumerableTypeName); - cppTypeDefinitions.AppendLine("Iterator();"); - cppTypeDefinitions.Append("\t\t"); - cppTypeDefinitions.Append(bindingEnumerableTypeName); - cppTypeDefinitions.AppendLine("Iterator& operator++();"); - cppTypeDefinitions.Append("\t\tbool operator!=(const "); - cppTypeDefinitions.Append(bindingEnumerableTypeName); - cppTypeDefinitions.AppendLine("Iterator& other);"); - cppTypeDefinitions.Append("\t\t"); - AppendCppTypeFullName( - elementType, - cppTypeDefinitions); - cppTypeDefinitions.AppendLine(" operator*();"); - cppTypeDefinitions.AppendLine("\t};"); - cppTypeDefinitions.AppendLine("}"); - cppTypeDefinitions.AppendLine();; - - // begin() and end() declarations - int indent = AppendNamespaceBeginning( - enumerableType.Namespace, - cppTypeDefinitions); - AppendIndent( - indent, - cppTypeDefinitions); - cppTypeDefinitions.Append("Plugin::"); - cppTypeDefinitions.Append(bindingEnumerableTypeName); - cppTypeDefinitions.Append("Iterator begin("); - AppendCppTypeFullName( - enumerableType, - cppTypeDefinitions); - cppTypeDefinitions.AppendLine("& enumerable);"); - AppendIndent( - indent, - cppTypeDefinitions); - cppTypeDefinitions.Append("Plugin::"); - cppTypeDefinitions.Append(bindingEnumerableTypeName); - cppTypeDefinitions.Append("Iterator end("); - AppendCppTypeFullName( - enumerableType, - cppTypeDefinitions); - cppTypeDefinitions.AppendLine("& enumerable);"); - AppendNamespaceEnding( - indent, - cppTypeDefinitions); - cppTypeDefinitions.AppendLine();; - - // Iterator method definitions - cppMethodDefinitions.AppendLine("namespace Plugin"); - cppMethodDefinitions.AppendLine("{"); - cppMethodDefinitions.Append('\t'); - cppMethodDefinitions.Append(bindingEnumerableTypeName); - cppMethodDefinitions.Append("Iterator::"); - cppMethodDefinitions.Append(bindingEnumerableTypeName); - cppMethodDefinitions.AppendLine("Iterator(decltype(nullptr))"); - cppMethodDefinitions.AppendLine("\t\t: enumerator(nullptr)"); - cppMethodDefinitions.AppendLine("\t\t, hasMore(false)"); - cppMethodDefinitions.AppendLine("\t{"); - cppMethodDefinitions.AppendLine("\t}"); - cppMethodDefinitions.AppendLine("\t"); - cppMethodDefinitions.Append('\t'); - cppMethodDefinitions.Append(bindingEnumerableTypeName); - cppMethodDefinitions.Append("Iterator::"); - cppMethodDefinitions.Append(bindingEnumerableTypeName); - cppMethodDefinitions.Append("Iterator("); - AppendCppTypeFullName( - enumerableType, - cppMethodDefinitions); - cppMethodDefinitions.AppendLine("& enumerable)"); - cppMethodDefinitions.AppendLine("\t\t: enumerator(enumerable.GetEnumerator())"); - cppMethodDefinitions.AppendLine("\t{"); - cppMethodDefinitions.AppendLine("\t\thasMore = enumerator.MoveNext();"); - cppMethodDefinitions.AppendLine("\t}"); - cppMethodDefinitions.AppendLine("\t"); - cppMethodDefinitions.Append('\t'); - cppMethodDefinitions.Append(bindingEnumerableTypeName); - cppMethodDefinitions.Append("Iterator::~"); - cppMethodDefinitions.Append(bindingEnumerableTypeName); - cppMethodDefinitions.AppendLine("Iterator()"); - cppMethodDefinitions.AppendLine("\t{"); - cppMethodDefinitions.AppendLine("\t\tif (enumerator != nullptr)"); - cppMethodDefinitions.AppendLine("\t\t{"); - cppMethodDefinitions.AppendLine("\t\t\tenumerator.Dispose();"); - cppMethodDefinitions.AppendLine("\t\t}"); - cppMethodDefinitions.AppendLine("\t}"); - cppMethodDefinitions.AppendLine("\t"); - cppMethodDefinitions.Append('\t'); - cppMethodDefinitions.Append(bindingEnumerableTypeName); - cppMethodDefinitions.Append("Iterator& "); - cppMethodDefinitions.Append(bindingEnumerableTypeName); - cppMethodDefinitions.Append("Iterator::"); - cppMethodDefinitions.AppendLine("operator++()"); - cppMethodDefinitions.AppendLine("\t{"); - cppMethodDefinitions.AppendLine("\t\thasMore = enumerator.MoveNext();"); - cppMethodDefinitions.AppendLine("\t\treturn *this;"); - cppMethodDefinitions.AppendLine("\t}"); - cppMethodDefinitions.AppendLine("\t"); - cppMethodDefinitions.Append("\tbool "); - cppMethodDefinitions.Append(bindingEnumerableTypeName); - cppMethodDefinitions.Append("Iterator::"); - cppMethodDefinitions.Append("operator!=(const "); - cppMethodDefinitions.Append(bindingEnumerableTypeName); - cppMethodDefinitions.AppendLine("Iterator& other)"); - cppMethodDefinitions.AppendLine("\t{"); - cppMethodDefinitions.AppendLine("\t\treturn hasMore;"); - cppMethodDefinitions.AppendLine("\t}"); - cppMethodDefinitions.AppendLine("\t"); - cppMethodDefinitions.Append('\t'); - AppendCppTypeFullName( - elementType, - cppMethodDefinitions); - cppMethodDefinitions.Append(' '); - cppMethodDefinitions.Append(bindingEnumerableTypeName); - cppMethodDefinitions.Append("Iterator::"); - cppMethodDefinitions.AppendLine("operator*()"); - cppMethodDefinitions.AppendLine("\t{"); - cppMethodDefinitions.AppendLine("\t\treturn enumerator.GetCurrent();"); - cppMethodDefinitions.AppendLine("\t}"); - cppMethodDefinitions.AppendLine("}"); - cppMethodDefinitions.AppendLine();; - - // begin() and end() definitions - indent = AppendNamespaceBeginning( - enumerableType.Namespace, - cppMethodDefinitions); - AppendIndent( - indent, - cppMethodDefinitions); - cppMethodDefinitions.Append("Plugin::"); - cppMethodDefinitions.Append(bindingEnumerableTypeName); - cppMethodDefinitions.Append("Iterator begin("); - AppendCppTypeFullName( - enumerableType, - cppMethodDefinitions); - cppMethodDefinitions.AppendLine("& enumerable)"); - AppendIndent( - indent, - cppMethodDefinitions); - cppMethodDefinitions.AppendLine("{"); - AppendIndent( - indent + 1, - cppMethodDefinitions); - cppMethodDefinitions.Append("return Plugin::"); - cppMethodDefinitions.Append(bindingEnumerableTypeName); - cppMethodDefinitions.AppendLine("Iterator(enumerable);"); - AppendIndent( - indent, - cppMethodDefinitions); - cppMethodDefinitions.AppendLine("}"); - AppendIndent( - indent, - cppMethodDefinitions); - cppMethodDefinitions.AppendLine();; - AppendIndent( - indent, - cppMethodDefinitions); - cppMethodDefinitions.Append("Plugin::"); - cppMethodDefinitions.Append(bindingEnumerableTypeName); - cppMethodDefinitions.Append("Iterator end("); - AppendCppTypeFullName( - enumerableType, - cppMethodDefinitions); - cppMethodDefinitions.AppendLine("& enumerable)"); - AppendIndent( - indent, - cppMethodDefinitions); - cppMethodDefinitions.AppendLine("{"); - AppendIndent( - indent + 1, - cppMethodDefinitions); - cppMethodDefinitions.Append("return Plugin::"); - cppMethodDefinitions.Append(bindingEnumerableTypeName); - cppMethodDefinitions.AppendLine("Iterator(nullptr);"); - AppendIndent( - indent, - cppMethodDefinitions); - cppMethodDefinitions.AppendLine("}"); - AppendNamespaceEnding( - indent, - cppMethodDefinitions); - cppMethodDefinitions.AppendLine();; - } - - static void AppendCppArrayIndexOperatorMethodDefinition( - int rank, - int indent, - TypeName enclosingTypeTypeName, - string nextCppElementProxyTypeName, - StringBuilder output) - { - AppendIndent( - indent, - output); - AppendCppTypeFullName( - GetTypeName(nextCppElementProxyTypeName, "Plugin"), - output); - output.Append(' '); - output.Append(enclosingTypeTypeName.Namespace); - output.Append("::"); - AppendTypeNameWithoutGenericSuffix( - enclosingTypeTypeName.Name, - output); - output.AppendLine("::operator[](int32_t index)"); - AppendIndent( - indent, - output); - output.AppendLine("{"); - AppendIndent( - indent + 1, - output); - output.Append("return Plugin::"); - output.Append(nextCppElementProxyTypeName); - output.Append("(Plugin::InternalUse::Only, Handle, "); - for (int i = 0; i < rank; ++i) - { - output.Append("Index"); - output.Append(i); - output.Append(", "); - } - output.AppendLine("index);"); - AppendIndent( - indent, - output); - output.AppendLine("}"); - AppendIndent( - indent, - output); - output.AppendLine();; - } - - static void AppendCppArrayTypeName( - int rank, - StringBuilder output) - { - output.Append("Array"); - output.Append(rank); - } - - static void AppendCppArrayElementProxyName( - int rank, - int maxRank, - Type elementType, - StringBuilder output) - { - output.Append("ArrayElementProxy"); - output.Append(rank); - output.Append('_'); - output.Append(maxRank); - output.Append('<'); - AppendCppTypeFullName( - elementType, - output); - output.Append('>'); - } - - static ParameterInfo[] BuildArrayGetItemsParams( - int rank, - string indexName) - { - ParameterInfo[] parameters = new ParameterInfo[rank]; - for (int i = 0; i < rank; ++i) - { - ParameterInfo param = new ParameterInfo(); - param.Name = indexName + i; - param.ParameterType = typeof(int); - param.IsOut = false; - param.IsRef = false; - param.DereferencedParameterType = param.ParameterType; - param.Kind = GetTypeKind( - param.DereferencedParameterType); - parameters[i] = param; - } - return parameters; - } - - static ParameterInfo[] BuildArraySetItemsParams( - int rank, - string indexName, - Type elementType) - { - ParameterInfo[] parameters = new ParameterInfo[rank+1]; - for (int i = 0; i < rank; ++i) - { - ParameterInfo param = new ParameterInfo(); - param.Name = indexName + i; - param.ParameterType = typeof(int); - param.IsOut = false; - param.IsRef = false; - param.DereferencedParameterType = param.ParameterType; - param.Kind = GetTypeKind( - param.DereferencedParameterType); - parameters[i] = param; - } - - ParameterInfo lastParamInfo = new ParameterInfo(); - lastParamInfo.Name = "item"; - lastParamInfo.ParameterType = elementType; - lastParamInfo.IsOut = false; - lastParamInfo.IsRef = false; - lastParamInfo.DereferencedParameterType = lastParamInfo.ParameterType; - lastParamInfo.Kind = GetTypeKind( - lastParamInfo.DereferencedParameterType); - parameters[rank] = lastParamInfo; - - return parameters; - } - - static void AppendArrayGetItemFuncName( - TypeName elementTypeTypeName, - string bindingArrayTypeName, - int rank, - StringBuilder output) - { - AppendNamespace( - elementTypeTypeName.Namespace, - string.Empty, - output); - output.Append(elementTypeTypeName.Name); - AppendTypeNameWithoutGenericSuffix( - bindingArrayTypeName, - output); - output.Append("GetItem"); - output.Append(rank); - } - - static void AppendArraySetItemFuncName( - TypeName elementTypeTypeName, - string bindingArrayTypeName, - int rank, - StringBuilder output) - { - AppendNamespace( - elementTypeTypeName.Namespace, - string.Empty, - output); - output.Append(elementTypeTypeName.Name); - AppendTypeNameWithoutGenericSuffix( - bindingArrayTypeName, - output); - output.Append("SetItem"); - output.Append(rank); - } - - static void AppendArrayElementProxy( - Type elementType, - TypeKind elementTypeKind, - int rank, - int maxRank, - Type[] cppTypeParams, - string cppArrayTypeName, - StringBuilders builders) - { - // Build element proxy name - builders.TempStrBuilder.Length = 0; - AppendCppArrayElementProxyName( - rank, - maxRank, - elementType, - builders.TempStrBuilder); - string cppElementProxyTypeName = builders.TempStrBuilder.ToString(); - - // Build next element proxy name - builders.TempStrBuilder.Length = 0; - AppendCppArrayElementProxyName( - rank + 1, - maxRank, - elementType, - builders.TempStrBuilder); - string nextCppElementProxyTypeName = builders.TempStrBuilder.ToString(); - - // GetItem name - builders.TempStrBuilder.Length = 0; - AppendArrayGetItemFuncName( - GetTypeName(elementType), - cppArrayTypeName, - rank, - builders.TempStrBuilder); - string getItemFuncName = builders.TempStrBuilder.ToString(); - - // SetItem name - builders.TempStrBuilder.Length = 0; - AppendArraySetItemFuncName( - GetTypeName(elementType), - cppArrayTypeName, - rank, - builders.TempStrBuilder); - string setItemFuncName = builders.TempStrBuilder.ToString(); - - // GetItem call params - ParameterInfo[] getItemCallParams = BuildArrayGetItemsParams( - rank, - "Index"); - - // SetItem params - ParameterInfo[] setItemCallParams = BuildArraySetItemsParams( - rank, - "Index", - elementType); - - // C++ element proxy type declaration - int indent = AppendNamespaceBeginning( - "Plugin", - builders.CppTemplateSpecializationDeclarations); - AppendIndent(indent, builders.CppTemplateSpecializationDeclarations); - builders.CppTemplateSpecializationDeclarations.Append("template<> struct "); - AppendTypeNameWithoutGenericSuffix( - cppElementProxyTypeName, - builders.CppTemplateSpecializationDeclarations); - builders.CppTemplateSpecializationDeclarations.AppendLine(";"); - AppendNamespaceEnding( - indent, - builders.CppTemplateSpecializationDeclarations); - builders.CppTemplateSpecializationDeclarations.AppendLine();; - - // C++ element proxy type definition - AppendNamespaceBeginning( - "Plugin", - builders.CppTypeDefinitions); - AppendIndent( - indent, - builders.CppTypeDefinitions); - builders.CppTypeDefinitions.Append("template<> struct "); - builders.CppTypeDefinitions.Append(cppElementProxyTypeName); - builders.CppTypeDefinitions.AppendLine();; - AppendIndent( - indent, - builders.CppTypeDefinitions); - builders.CppTypeDefinitions.AppendLine("{"); - AppendIndent( - indent + 1, - builders.CppTypeDefinitions); - builders.CppTypeDefinitions.AppendLine("int32_t Handle;"); - for (int i = 0; i < rank; ++i) - { - AppendIndent( - indent + 1, - builders.CppTypeDefinitions); - builders.CppTypeDefinitions.Append("int32_t Index"); - builders.CppTypeDefinitions.Append(i); - builders.CppTypeDefinitions.AppendLine(";"); - } - AppendIndent( - indent + 1, - builders.CppTypeDefinitions); - builders.CppTypeDefinitions.Append(cppElementProxyTypeName); - builders.CppTypeDefinitions.Append( - "(Plugin::InternalUse, int32_t handle, "); - for (int i = 0; i < rank; ++i) - { - builders.CppTypeDefinitions.Append("int32_t index"); - builders.CppTypeDefinitions.Append(i); - if (i != rank - 1) - { - builders.CppTypeDefinitions.Append(", "); - } - } - builders.CppTypeDefinitions.AppendLine(");"); - if (rank == maxRank) - { - AppendIndent( - indent + 1, - builders.CppTypeDefinitions); - builders.CppTypeDefinitions.Append("void operator=("); - AppendCppTypeFullName( - elementType, - builders.CppTypeDefinitions); - builders.CppTypeDefinitions.AppendLine(" item);"); - AppendIndent( - indent + 1, - builders.CppTypeDefinitions); - builders.CppTypeDefinitions.Append("operator "); - AppendCppTypeFullName( - elementType, - builders.CppTypeDefinitions); - builders.CppTypeDefinitions.AppendLine("();"); - } - else - { - AppendIndent( - indent + 1, - builders.CppTypeDefinitions); - builders.CppTypeDefinitions.Append("Plugin::"); - AppendCppArrayElementProxyName( - rank + 1, - maxRank, - elementType, - builders.CppTypeDefinitions); - builders.CppTypeDefinitions.Append(" operator[]("); - builders.CppTypeDefinitions.AppendLine("int32_t index);"); - } - AppendIndent( - indent, - builders.CppTypeDefinitions); - builders.CppTypeDefinitions.AppendLine("};"); - builders.CppTypeDefinitions.AppendLine("}"); - builders.CppTypeDefinitions.AppendLine();; - - // C++ element proxy method definitions (beginning) - int cppMethodDefinitionsIndent = AppendNamespaceBeginning( - "Plugin", - builders.CppMethodDefinitions); - - // C++ element proxy constructor definition - AppendIndent( - cppMethodDefinitionsIndent, - builders.CppMethodDefinitions); - builders.CppMethodDefinitions.Append(cppElementProxyTypeName); - builders.CppMethodDefinitions.Append( - "::ArrayElementProxy"); - builders.CppMethodDefinitions.Append(rank); - builders.CppMethodDefinitions.Append('_'); - builders.CppMethodDefinitions.Append(maxRank); - builders.CppMethodDefinitions.Append( - "(Plugin::InternalUse, int32_t handle, "); - for (int i = 0; i < rank; ++i) - { - builders.CppMethodDefinitions.Append("int32_t index"); - builders.CppMethodDefinitions.Append(i); - if (i != rank - 1) - { - builders.CppMethodDefinitions.Append(", "); - } - } - builders.CppMethodDefinitions.AppendLine(")"); - AppendIndent( - cppMethodDefinitionsIndent, - builders.CppMethodDefinitions); - builders.CppMethodDefinitions.AppendLine("{"); - AppendIndent( - cppMethodDefinitionsIndent + 1, - builders.CppMethodDefinitions); - builders.CppMethodDefinitions.AppendLine("Handle = handle;"); - for (int i = 0; i < rank; ++i) - { - AppendIndent( - cppMethodDefinitionsIndent + 1, - builders.CppMethodDefinitions); - builders.CppMethodDefinitions.Append("Index"); - builders.CppMethodDefinitions.Append(i); - builders.CppMethodDefinitions.Append(" = index"); - builders.CppMethodDefinitions.Append(i); - builders.CppMethodDefinitions.AppendLine(";"); - } - AppendIndent( - cppMethodDefinitionsIndent, - builders.CppMethodDefinitions); - builders.CppMethodDefinitions.AppendLine("}"); - AppendIndent( - cppMethodDefinitionsIndent, - builders.CppMethodDefinitions); - builders.CppMethodDefinitions.AppendLine();; - - if (rank == maxRank) - { - // C++ element proxy operator= definition - AppendIndent( - cppMethodDefinitionsIndent, - builders.CppMethodDefinitions); - builders.CppMethodDefinitions.Append("void "); - builders.CppMethodDefinitions.Append(cppElementProxyTypeName); - builders.CppMethodDefinitions.Append("::"); - builders.CppMethodDefinitions.Append("operator=("); - AppendCppTypeFullName( - elementType, - builders.CppMethodDefinitions); - builders.CppMethodDefinitions.AppendLine(" item)"); - AppendIndent( - cppMethodDefinitionsIndent, - builders.CppMethodDefinitions); - builders.CppMethodDefinitions.AppendLine("{"); - AppendCppPluginFunctionCall( - false, - GetTypeName(cppArrayTypeName, "System"), - TypeKind.Class, - cppTypeParams, - typeof(void), - setItemFuncName, - setItemCallParams, - cppMethodDefinitionsIndent + 1, - builders.CppMethodDefinitions); - AppendIndent( - cppMethodDefinitionsIndent, - builders.CppMethodDefinitions); - builders.CppMethodDefinitions.AppendLine("}"); - AppendIndent( - cppMethodDefinitionsIndent, - builders.CppMethodDefinitions); - builders.CppMethodDefinitions.AppendLine();; - - // C++ element proxy type conversion operator definition - AppendIndent( - cppMethodDefinitionsIndent, - builders.CppMethodDefinitions); - builders.CppMethodDefinitions.Append(cppElementProxyTypeName); - builders.CppMethodDefinitions.Append("::"); - builders.CppMethodDefinitions.Append("operator "); - AppendCppTypeFullName( - elementType, - builders.CppMethodDefinitions); - builders.CppMethodDefinitions.AppendLine("()"); - AppendIndent( - cppMethodDefinitionsIndent, - builders.CppMethodDefinitions); - builders.CppMethodDefinitions.AppendLine("{"); - AppendCppPluginFunctionCall( - false, - GetTypeName(cppArrayTypeName, "System"), - TypeKind.Class, - cppTypeParams, - elementType, - getItemFuncName, - getItemCallParams, - indent + 1, - builders.CppMethodDefinitions); - AppendCppMethodReturn( - elementType, - elementTypeKind, - indent + 1, - builders.CppMethodDefinitions); - AppendIndent( - cppMethodDefinitionsIndent, - builders.CppMethodDefinitions); - builders.CppMethodDefinitions.AppendLine("}"); - } - else - { - AppendCppArrayIndexOperatorMethodDefinition( - rank, - cppMethodDefinitionsIndent, - GetTypeName(cppElementProxyTypeName, "Plugin"), - nextCppElementProxyTypeName, - builders.CppMethodDefinitions); - } - - // C++ method definitions (ending) - AppendCppMethodDefinitionsEnd( - cppMethodDefinitionsIndent, - builders.CppMethodDefinitions); - } - - static void AppendArrayConstructor( - Type elementType, - Type arrayType, - string cppArrayTypeName, - int rank, - string csharpTypeName, - Type[] cppCtorInitTypes, - int indent, - StringBuilders builders) - { - builders.TempStrBuilder.Length = 0; - AppendNamespace( - elementType.Namespace, - string.Empty, - builders.TempStrBuilder); - AppendTypeNameWithoutGenericSuffix( - csharpTypeName, - builders.TempStrBuilder); - builders.TempStrBuilder.Append("Constructor"); - builders.TempStrBuilder.Append(rank); - string funcName = builders.TempStrBuilder.ToString(); - - ParameterInfo[] parameters = new ParameterInfo[rank]; - for (int i = 0; i < rank; ++i) - { - ParameterInfo info = new ParameterInfo(); - info.Name = "length" + i; - info.ParameterType = typeof(int); - info.IsOut = false; - info.IsRef = false; - info.DereferencedParameterType = info.ParameterType; - info.Kind = TypeKind.Primitive; - parameters[i] = info; - } - - TypeName cppArrayTypeTypeName = GetTypeName( - cppArrayTypeName, - "System"); - - // C# Delegate Type - AppendCsharpDelegateType( - funcName, - true, - arrayType, - TypeKind.Class, - arrayType, - parameters, - builders.CsharpDelegateTypes); - - // C# Init Call - AppendCsharpCsharpDelegate( - funcName, - builders.CsharpInitCall, - builders.CsharpCsharpDelegates); - - // C# Init Param - - // C# function - AppendCsharpFunctionBeginning( - arrayType, - funcName, - true, - TypeKind.Class, - arrayType, - parameters, - builders.CsharpFunctions); - AppendHandleStoreTypeName( - arrayType, - builders.CsharpFunctions); - builders.CsharpFunctions.Append(".Store(new "); - AppendCsharpTypeFullName( - elementType, - builders.CsharpFunctions); - builders.CsharpFunctions.Append('['); - for (int i = 0; i < rank; ++i) - { - builders.CsharpFunctions.Append("length"); - builders.CsharpFunctions.Append(i); - if (i != rank-1) - { - builders.CsharpFunctions.Append(", "); - } - } - builders.CsharpFunctions.Append("]);"); - AppendCsharpFunctionReturn( - parameters, - arrayType, - TypeKind.Class, - null, - true, - builders.CsharpFunctions); - - // C++ function pointer definition - AppendCppFunctionPointerDefinition( - funcName, - true, - cppArrayTypeTypeName, - TypeKind.Class, - parameters, - arrayType, - builders.CppFunctionPointers); - - // C++ init body - AppendCppInitBodyFunctionPointerParameterRead( - funcName, - true, - cppArrayTypeTypeName, - TypeKind.Class, - parameters, - arrayType, - builders.CppInitBodyParameterReads); - - // C++ method declaration - AppendIndent( - indent + 1, - builders.CppTypeDefinitions); - AppendCppMethodDeclaration( - cppArrayTypeName, - false, - false, - false, - null, - null, - parameters, - builders.CppTypeDefinitions); - - // C++ method definition - Type[] cppTypeParams = { elementType }; - AppendCppMethodDefinitionBegin( - GetTypeName(cppArrayTypeName, "System"), - null, - cppArrayTypeName, - cppTypeParams, - null, - parameters, - indent, - builders.CppMethodDefinitions); - string separator = ": "; - foreach (Type interfaceType in cppCtorInitTypes) - { - AppendIndent( - indent + 1, - builders.CppMethodDefinitions); - builders.CppMethodDefinitions.Append(separator); - AppendCppTypeFullName( - interfaceType, - builders.CppMethodDefinitions); - builders.CppMethodDefinitions.AppendLine("(nullptr)"); - separator = ", "; - } - AppendIndent( - indent, - builders.CppMethodDefinitions); - builders.CppMethodDefinitions.AppendLine("{"); - AppendCppPluginFunctionCall( - true, - cppArrayTypeTypeName, - TypeKind.Class, - cppTypeParams, - arrayType, - funcName, - parameters, - indent + 1, - builders.CppMethodDefinitions); - AppendIndent( - indent + 1, - builders.CppMethodDefinitions); - builders.CppMethodDefinitions.AppendLine( - "Handle = returnValue;"); - AppendIndent( - indent + 1, - builders.CppMethodDefinitions); - builders.CppMethodDefinitions.AppendLine( - "if (returnValue)"); - AppendIndent( - indent + 1, - builders.CppMethodDefinitions); - builders.CppMethodDefinitions.AppendLine( - "{"); - AppendIndent( - indent + 2, - builders.CppMethodDefinitions); - AppendReferenceManagedHandleFunctionCall( - cppArrayTypeTypeName, - TypeKind.Class, - cppTypeParams, - "returnValue", - builders.CppMethodDefinitions); - builders.CppMethodDefinitions.AppendLine(";"); - if (rank > 1) - { - AppendIndent( - indent + 2, - builders.CppMethodDefinitions); - builders.CppMethodDefinitions.Append("InternalLength = "); - for (int i = 0; i < rank; ++i) - { - builders.CppMethodDefinitions.Append("length"); - builders.CppMethodDefinitions.Append(i); - if (i != rank - 1) - { - builders.CppMethodDefinitions.Append(" * "); - } - } - builders.CppMethodDefinitions.AppendLine(";"); - for (int i = 0; i < rank; ++i) - { - AppendIndent( - indent + 2, - builders.CppMethodDefinitions); - builders.CppMethodDefinitions.Append("InternalLengths["); - builders.CppMethodDefinitions.Append(i); - builders.CppMethodDefinitions.Append("] = length"); - builders.CppMethodDefinitions.Append(i); - builders.CppMethodDefinitions.AppendLine(";"); - } - } - else - { - AppendIndent( - indent + 2, - builders.CppMethodDefinitions); - builders.CppMethodDefinitions.AppendLine( - "InternalLength = length0;"); - } - AppendIndent( - indent + 1, - builders.CppMethodDefinitions); - builders.CppMethodDefinitions.AppendLine( - "}"); - AppendIndent( - indent, - builders.CppMethodDefinitions); - builders.CppMethodDefinitions.AppendLine("}"); - AppendIndent( - indent, - builders.CppMethodDefinitions); - builders.CppMethodDefinitions.AppendLine();; - } - - static void AppendArrayCppGetLengthFunction( - int indent, - string cppArrayTypeName, - Type[] cppTypeParams, - StringBuilders builders) - { - ParameterInfo[] parameters = new ParameterInfo[0]; - - // C++ method declaration - AppendIndent( - indent + 1, - builders.CppTypeDefinitions); - AppendCppMethodDeclaration( - "GetLength", - false, - false, - false, - typeof(int), - null, - parameters, - builders.CppTypeDefinitions); - - // C++ method definition - AppendCppMethodDefinitionBegin( - GetTypeName(cppArrayTypeName, "System"), - typeof(int), - "GetLength", - cppTypeParams, - null, - parameters, - indent, - builders.CppMethodDefinitions); - AppendIndent( - indent, - builders.CppMethodDefinitions); - builders.CppMethodDefinitions.AppendLine("{"); - AppendIndent( - indent + 1, - builders.CppMethodDefinitions); - builders.CppMethodDefinitions.AppendLine( - "int32_t returnVal = InternalLength;"); - AppendIndent( - indent + 1, - builders.CppMethodDefinitions); - builders.CppMethodDefinitions.AppendLine("if (returnVal == 0)"); - AppendIndent( - indent + 1, - builders.CppMethodDefinitions); - builders.CppMethodDefinitions.AppendLine("{"); - AppendIndent( - indent + 2, - builders.CppMethodDefinitions); - builders.CppMethodDefinitions.AppendLine( - "returnVal = Array::GetLength();"); - AppendIndent( - indent + 2, - builders.CppMethodDefinitions); - builders.CppMethodDefinitions.AppendLine( - "InternalLength = returnVal;"); - AppendIndent( - indent + 1, - builders.CppMethodDefinitions); - builders.CppMethodDefinitions.AppendLine("};"); - AppendIndent( - indent + 1, - builders.CppMethodDefinitions); - builders.CppMethodDefinitions.AppendLine("return returnVal;"); - AppendIndent( - indent, - builders.CppMethodDefinitions); - builders.CppMethodDefinitions.AppendLine("}"); - AppendIndent( - indent, - builders.CppMethodDefinitions); - builders.CppMethodDefinitions.AppendLine();; - } - - static void AppendArrayCppGetRankFunction( - int indent, - string cppArrayTypeName, - Type[] cppTypeParams, - int rank, - StringBuilders builders) - { - ParameterInfo[] parameters = new ParameterInfo[0]; - - // C++ method declaration - AppendIndent( - indent + 1, - builders.CppTypeDefinitions); - AppendCppMethodDeclaration( - "GetRank", - false, - false, - false, - typeof(int), - null, - parameters, - builders.CppTypeDefinitions); - - // C++ method definition - AppendCppMethodDefinitionBegin( - GetTypeName(cppArrayTypeName, "System"), - typeof(int), - "GetRank", - cppTypeParams, - null, - parameters, - indent, - builders.CppMethodDefinitions); - AppendIndent( - indent, - builders.CppMethodDefinitions); - builders.CppMethodDefinitions.AppendLine("{"); - AppendIndent( - indent + 1, - builders.CppMethodDefinitions); - builders.CppMethodDefinitions.Append("return "); - builders.CppMethodDefinitions.Append(rank); - builders.CppMethodDefinitions.AppendLine(";"); - AppendIndent( - indent, - builders.CppMethodDefinitions); - builders.CppMethodDefinitions.AppendLine("}"); - AppendIndent( - indent, - builders.CppMethodDefinitions); - builders.CppMethodDefinitions.AppendLine();; - } - - static void AppendArrayMultidimensionalGetLength( - Type elementType, - Type arrayType, - string cppArrayTypeName, - int rank, - string csharpTypeName, - int indent, - StringBuilders builders) - { - builders.TempStrBuilder.Length = 0; - AppendNamespace( - elementType.Namespace, - string.Empty, - builders.TempStrBuilder); - AppendTypeNameWithoutGenericSuffix( - csharpTypeName, - builders.TempStrBuilder); - builders.TempStrBuilder.Append("GetLength"); - builders.TempStrBuilder.Append(rank); - string funcName = builders.TempStrBuilder.ToString(); - - ParameterInfo[] parameters = { - new ParameterInfo { - Name = "dimension", - ParameterType = typeof(int), - IsOut = false, - IsRef = false, - DereferencedParameterType = typeof(int), - Kind = TypeKind.Primitive, - } - }; - - TypeName cppArrayTypeTypeName = GetTypeName( - cppArrayTypeName, - "System"); - - // C# Delegate Type - AppendCsharpDelegateType( - funcName, - false, - arrayType, - TypeKind.Class, - typeof(int), - parameters, - builders.CsharpDelegateTypes); - - // C# Init Call - AppendCsharpCsharpDelegate( - funcName, - builders.CsharpInitCall, - builders.CsharpCsharpDelegates); - - // C# Init Param - - // C# function - AppendCsharpFunctionBeginning( - arrayType, - funcName, - false, - TypeKind.Class, - typeof(int), - parameters, - builders.CsharpFunctions); - builders.CsharpFunctions.Append( - "thiz.GetLength(dimension);"); - AppendCsharpFunctionReturn( - parameters, - typeof(int), - TypeKind.Primitive, - null, - false, - builders.CsharpFunctions); - - // C++ function pointer definition - AppendCppFunctionPointerDefinition( - funcName, - false, - cppArrayTypeTypeName, - TypeKind.Class, - parameters, - arrayType, - builders.CppFunctionPointers); - - // C++ init body - AppendCppInitBodyFunctionPointerParameterRead( - funcName, - false, - cppArrayTypeTypeName, - TypeKind.Class, - parameters, - arrayType, - builders.CppInitBodyParameterReads); - - // C++ method declaration - AppendIndent( - indent + 1, - builders.CppTypeDefinitions); - AppendCppMethodDeclaration( - "GetLength", - false, - false, - false, - typeof(int), - null, - parameters, - builders.CppTypeDefinitions); - - // C++ method definition - Type[] cppTypeParams = { elementType }; - AppendCppMethodDefinitionBegin( - GetTypeName(cppArrayTypeName, "System"), - typeof(int), - "GetLength", - cppTypeParams, - null, - parameters, - indent, - builders.CppMethodDefinitions); - AppendIndent( - indent, - builders.CppMethodDefinitions); - builders.CppMethodDefinitions.AppendLine("{"); - AppendIndent( - indent + 1, - builders.CppMethodDefinitions); - builders.CppMethodDefinitions.Append( - "assert(dimension >= 0 && dimension < "); - builders.CppMethodDefinitions.Append(rank); - builders.CppMethodDefinitions.AppendLine(");"); - AppendIndent( - indent + 1, - builders.CppMethodDefinitions); - builders.CppMethodDefinitions.AppendLine( - "int32_t length = InternalLengths[dimension];"); - AppendIndent( - indent + 1, - builders.CppMethodDefinitions); - builders.CppMethodDefinitions.AppendLine("if (length)"); - AppendIndent( - indent + 1, - builders.CppMethodDefinitions); - builders.CppMethodDefinitions.AppendLine("{"); - AppendIndent( - indent + 2, - builders.CppMethodDefinitions); - builders.CppMethodDefinitions.AppendLine("return length;"); - AppendIndent( - indent + 1, - builders.CppMethodDefinitions); - builders.CppMethodDefinitions.AppendLine("}"); - AppendCppPluginFunctionCall( - false, - GetTypeName(cppArrayTypeName, "System"), - TypeKind.Class, - cppTypeParams, - typeof(int), - funcName, - parameters, - indent + 1, - builders.CppMethodDefinitions); - AppendIndent( - indent + 1, - builders.CppMethodDefinitions); - builders.CppMethodDefinitions.AppendLine( - "InternalLengths[dimension] = returnValue;"); - AppendCppMethodReturn( - typeof(int), - TypeKind.Primitive, - indent + 1, - builders.CppMethodDefinitions); - AppendIndent( - indent, - builders.CppMethodDefinitions); - builders.CppMethodDefinitions.AppendLine("}"); - AppendIndent( - indent, - builders.CppMethodDefinitions); - builders.CppMethodDefinitions.AppendLine();; - } - - static void AppendArrayGetItem( - Type elementType, - TypeKind elementTypeKind, - Type arrayType, - string cppArrayTypeName, - int rank, - StringBuilders builders) - { - builders.TempStrBuilder.Length = 0; - AppendArrayGetItemFuncName( - GetTypeName(elementType), - cppArrayTypeName, - rank, - builders.TempStrBuilder); - string funcName = builders.TempStrBuilder.ToString(); - - ParameterInfo[] parameters = BuildArrayGetItemsParams( - rank, - "index"); - - // C# Delegate Type - AppendCsharpDelegateType( - funcName, - false, - arrayType, - TypeKind.Class, - elementType, - parameters, - builders.CsharpDelegateTypes); - - // C# Init Call - AppendCsharpCsharpDelegate( - funcName, - builders.CsharpInitCall, - builders.CsharpCsharpDelegates); - - // C# Init Param - - // C# function - AppendCsharpFunctionBeginning( - arrayType, - funcName, - false, - TypeKind.Class, - elementType, - parameters, - builders.CsharpFunctions); - builders.CsharpFunctions.Append("thiz["); - for (int i = 0; i < rank; ++i) - { - builders.CsharpFunctions.Append("index"); - builders.CsharpFunctions.Append(i); - if (i != rank-1) - { - builders.CsharpFunctions.Append(", "); - } - } - builders.CsharpFunctions.Append("];"); - AppendCsharpFunctionReturn( - parameters, - elementType, - elementTypeKind, - null, - false, - builders.CsharpFunctions); - - TypeName cppArrayTypeTypeName = GetTypeName( - "System", - cppArrayTypeName); - - // C++ function pointer definition - AppendCppFunctionPointerDefinition( - funcName, - false, - cppArrayTypeTypeName, - TypeKind.Class, - parameters, - elementType, - builders.CppFunctionPointers); - - // C++ init body - AppendCppInitBodyFunctionPointerParameterRead( - funcName, - false, - cppArrayTypeTypeName, - TypeKind.Class, - parameters, - elementType, - builders.CppInitBodyParameterReads); - } - - static void AppendArraySetItem( - Type elementType, - Type arrayType, - string cppArrayTypeName, - int rank, - StringBuilders builders) - { - builders.TempStrBuilder.Length = 0; - AppendArraySetItemFuncName( - GetTypeName(elementType), - cppArrayTypeName, - rank, - builders.TempStrBuilder); - string funcName = builders.TempStrBuilder.ToString(); - - // Build parameters as indexes then element - ParameterInfo[] parameters = BuildArraySetItemsParams( - rank, - "index", - elementType); - - // C# Delegate Type - AppendCsharpDelegateType( - funcName, - false, - arrayType, - TypeKind.Class, - typeof(void), - parameters, - builders.CsharpDelegateTypes); - - // C# Init Call - AppendCsharpCsharpDelegate( - funcName, - builders.CsharpInitCall, - builders.CsharpCsharpDelegates); - - // C# Init Param - - // C# function - AppendCsharpFunctionBeginning( - arrayType, - funcName, - false, - TypeKind.Class, - typeof(void), - parameters, - builders.CsharpFunctions); - builders.CsharpFunctions.Append("thiz["); - for (int i = 0; i < rank; ++i) - { - builders.CsharpFunctions.Append("index"); - builders.CsharpFunctions.Append(i); - if (i != rank-1) - { - builders.CsharpFunctions.Append(", "); - } - } - builders.CsharpFunctions.Append("] = item;"); - AppendCsharpFunctionReturn( - parameters, - typeof(void), - TypeKind.None, - null, - false, - builders.CsharpFunctions); - - TypeName cppArrayTypeTypeName = GetTypeName( - "System", - cppArrayTypeName); - - // C++ function pointer definition - AppendCppFunctionPointerDefinition( - funcName, - false, - cppArrayTypeTypeName, - TypeKind.Class, - parameters, - arrayType, - builders.CppFunctionPointers); - - // C++ init body - AppendCppInitBodyFunctionPointerParameterRead( - funcName, - false, - cppArrayTypeTypeName, - TypeKind.Class, - parameters, - arrayType, - builders.CppInitBodyParameterReads); - } - - static void AppendDelegate( - JsonDelegate jsonDelegate, - Assembly[] assemblies, - int defaultMaxSimultaneous, - StringBuilders builders) - { - Type type = GetType( - jsonDelegate.Type, - assemblies); - if (jsonDelegate.GenericParams != null) - { - for (int i = 0; i < jsonDelegate.GenericParams.Length; ++i) - { - // C++ template declaration - AppendCppTemplateDeclaration( - GetTypeName(type), - builders.CppTemplateDeclarations); - } - - foreach (JsonGenericParams jsonGenericParams - in jsonDelegate.GenericParams) - { - Type[] typeParams = GetTypes( - jsonGenericParams.Types, - assemblies); - Type genericType = type.MakeGenericType(typeParams); - - // Build numbered C++ class name (e.g. Action_2) - builders.TempStrBuilder.Length = 0; - AppendTypeNameWithoutSuffixes( - type.Name, - builders.TempStrBuilder); - builders.TempStrBuilder.Append('_'); - builders.TempStrBuilder.Append( - jsonGenericParams.Types.Length); - string cppTypeName = builders.TempStrBuilder.ToString(); - - // Max simultaneous handles of this type - int maxSimultaneous = jsonGenericParams.MaxSimultaneous != 0 - ? jsonGenericParams.MaxSimultaneous - : jsonDelegate.MaxSimultaneous != 0 - ? jsonDelegate.MaxSimultaneous - : defaultMaxSimultaneous; - - AppendDelegate( - genericType, - cppTypeName, - typeParams, - maxSimultaneous, - builders); - } - } - else - { - int maxSimultaneous = jsonDelegate.MaxSimultaneous != 0 - ? jsonDelegate.MaxSimultaneous - : defaultMaxSimultaneous; - AppendDelegate( - type, - type.Name, - null, - maxSimultaneous, - builders); - } - } - - static void AppendDelegate( - Type type, - string cppTypeName, - Type[] typeParams, - int maxSimultaneous, - StringBuilders builders) - { - builders.TempStrBuilder.Length = 0; - AppendNamespace( - type.Namespace, - string.Empty, - builders.TempStrBuilder); - AppendTypeNameWithoutSuffixes( - type.Name, - builders.TempStrBuilder); - AppendTypeNames( - typeParams, - builders.TempStrBuilder); - string bindingTypeName = builders.TempStrBuilder.ToString(); - - builders.TempStrBuilder.Length = 0; - builders.TempStrBuilder.Append("Release"); - builders.TempStrBuilder.Append(bindingTypeName); - string releaseFuncName = builders.TempStrBuilder.ToString(); - - builders.TempStrBuilder.Length = 0; - builders.TempStrBuilder.Append(bindingTypeName); - builders.TempStrBuilder.Append("Constructor"); - string constructorFuncName = builders.TempStrBuilder.ToString(); - - builders.TempStrBuilder.Length = 0; - builders.TempStrBuilder.Append(bindingTypeName); - builders.TempStrBuilder.Append("Add"); - string addFuncName = builders.TempStrBuilder.ToString(); - - builders.TempStrBuilder.Length = 0; - builders.TempStrBuilder.Append(bindingTypeName); - builders.TempStrBuilder.Append("Remove"); - string removeFuncName = builders.TempStrBuilder.ToString(); - - TypeName typeTypeName = GetTypeName(type); - - // C++ type declaration - int indent = AppendCppTypeDeclaration( - typeTypeName, - false, - typeParams, - typeParams != null ? - builders.CppTemplateSpecializationDeclarations : - builders.CppTypeDeclarations); - - ParameterInfo[] addRemoveParams = { - new ParameterInfo - { - Name = "del", - ParameterType = type, - DereferencedParameterType = type, - IsOut = false, - IsRef = false, - Kind = TypeKind.Class, - IsVirtual = true - }}; - - ParameterInfo[] releaseParams = { - new ParameterInfo - { - Name = "handle", - ParameterType = typeof(int), - DereferencedParameterType = typeof(int), - IsOut = false, - IsRef = false, - Kind = TypeKind.Primitive - }, - new ParameterInfo - { - Name = "classHandle", - ParameterType = typeof(int), - DereferencedParameterType = typeof(int), - IsOut = false, - IsRef = false, - Kind = TypeKind.Primitive - }}; - - ParameterInfo[] constructorParams = { - new ParameterInfo - { - Name = "cppHandle", - ParameterType = typeof(int), - DereferencedParameterType = typeof(int), - IsOut = false, - IsRef = false, - Kind = TypeKind.Primitive - }, - new ParameterInfo - { - Name = "handle", - ParameterType = typeof(int), - DereferencedParameterType = typeof(int), - IsOut = true, - IsRef = false, - Kind = TypeKind.Primitive - }, - new ParameterInfo - { - Name = "classHandle", - ParameterType = typeof(int), - DereferencedParameterType = typeof(int), - IsOut = true, - IsRef = false, - Kind = TypeKind.Primitive - }}; - - AppendCppPointerFreeListStateAndFunctions( - GetTypeName(cppTypeName, type.Namespace), - typeParams, - bindingTypeName, - builders.CppGlobalStateAndFunctions); - - AppendCppPointerFreeListInit( - typeParams, - GetTypeName(cppTypeName, type.Namespace), - maxSimultaneous, - bindingTypeName, - builders.CppInitBodyArrays, - builders.CppInitBodyFirstBoot); - - // C++ type definition (begin) - AppendCppTypeDefinitionBegin( - GetTypeName(cppTypeName, type.Namespace), - TypeKind.Class, - typeParams, - GetTypeName(typeof(object)), - null, - null, - false, - indent, - builders.CppTypeDefinitions); - - // C++ type fields - AppendIndent( - indent + 1, - builders.CppTypeDefinitions); - builders.CppTypeDefinitions.AppendLine("int32_t CppHandle;"); - AppendIndent( - indent + 1, - builders.CppTypeDefinitions); - builders.CppTypeDefinitions.AppendLine("int32_t ClassHandle;"); - - // C++ method declarations - AppendIndent( - indent + 1, - builders.CppTypeDefinitions); - AppendCppMethodDeclaration( - cppTypeName, - false, - false, - false, - null, - null, - new ParameterInfo[0], - builders.CppTypeDefinitions); - AppendIndent( - indent + 1, - builders.CppTypeDefinitions); - AppendCppMethodDeclaration( - "operator+=", - false, - false, - false, - typeof(void), - null, - addRemoveParams, - builders.CppTypeDefinitions); - AppendIndent( - indent + 1, - builders.CppTypeDefinitions); - AppendCppMethodDeclaration( - "operator-=", - false, - false, - false, - typeof(void), - null, - addRemoveParams, - builders.CppTypeDefinitions); - - // C++ function pointers - AppendCppFunctionPointerDefinition( - releaseFuncName, - true, - default(TypeName), - TypeKind.None, - releaseParams, - typeof(void), - builders.CppFunctionPointers); - AppendCppFunctionPointerDefinition( - constructorFuncName, - true, - default(TypeName), - TypeKind.None, - constructorParams, - typeof(void), - builders.CppFunctionPointers); - AppendCppFunctionPointerDefinition( - addFuncName, - false, - default(TypeName), - TypeKind.None, - addRemoveParams, - typeof(void), - builders.CppFunctionPointers); - AppendCppFunctionPointerDefinition( - removeFuncName, - false, - default(TypeName), - TypeKind.None, - addRemoveParams, - typeof(void), - builders.CppFunctionPointers); - - // C++ and C# init params - AppendCppInitBodyFunctionPointerParameterRead( - releaseFuncName, - true, - default(TypeName), - TypeKind.None, - releaseParams, - typeof(void), - builders.CppInitBodyParameterReads); - AppendCppInitBodyFunctionPointerParameterRead( - constructorFuncName, - true, - default(TypeName), - TypeKind.None, - constructorParams, - typeof(void), - builders.CppInitBodyParameterReads); - AppendCppInitBodyFunctionPointerParameterRead( - addFuncName, - false, - default(TypeName), - TypeKind.None, - addRemoveParams, - typeof(void), - builders.CppInitBodyParameterReads); - AppendCppInitBodyFunctionPointerParameterRead( - removeFuncName, - false, - default(TypeName), - TypeKind.None, - addRemoveParams, - typeof(void), - builders.CppInitBodyParameterReads); - AppendCsharpCsharpDelegate( - releaseFuncName, - builders.CsharpInitCall, - builders.CsharpCsharpDelegates); - AppendCsharpCsharpDelegate( - constructorFuncName, - builders.CsharpInitCall, - builders.CsharpCsharpDelegates); - AppendCsharpCsharpDelegate( - addFuncName, - builders.CsharpInitCall, - builders.CsharpCsharpDelegates); - AppendCsharpCsharpDelegate( - removeFuncName, - builders.CsharpInitCall, - builders.CsharpCsharpDelegates); - - // C++ method definitions (end) - int cppMethodDefinitionsIndent = AppendNamespaceBeginning( - type.Namespace, - builders.CppMethodDefinitions); - - AppendCppBaseTypeConstructor( - bindingTypeName, - typeTypeName, - TypeKind.Class, - cppTypeName, - typeParams, - new Type[0], - new ParameterInfo[0], - constructorParams, - true, - constructorFuncName, - cppMethodDefinitionsIndent, - builders.CppMethodDefinitions); - - AppendCppBaseTypeNullptrConstructor( - bindingTypeName, - typeTypeName, - typeParams, - new Type[0], - true, - cppMethodDefinitionsIndent, - builders.CppMethodDefinitions); - - AppendCppBaseTypeCopyConstructor( - bindingTypeName, - typeTypeName, - typeParams, - new Type[0], - true, - cppMethodDefinitionsIndent, - builders.CppMethodDefinitions); - - AppendCppBaseTypeMoveConstructor( - typeTypeName, - typeParams, - new Type[0], - true, - cppMethodDefinitionsIndent, - builders.CppMethodDefinitions); - - AppendCppBaseTypeHandleConstructor( - bindingTypeName, - typeTypeName, - typeParams, - new Type[0], - true, - cppMethodDefinitionsIndent, - builders.CppMethodDefinitions); - - AppendCppBaseTypeDestructor( - bindingTypeName, - typeTypeName, - typeParams, - true, - string.Empty, - releaseFuncName, - bindingTypeName, - cppMethodDefinitionsIndent, - builders.CppMethodDefinitions); - - AppendCppBaseTypeAssignmentOperatorSameType( - typeTypeName, - typeParams, - true, - cppMethodDefinitionsIndent, - builders.CppMethodDefinitions); - - AppendCppBaseTypeAssignmentOperatorNullptr( - typeTypeName, - typeParams, - true, - releaseFuncName, - cppMethodDefinitionsIndent, - builders.CppMethodDefinitions); - - AppendCppBaseTypeMoveAssignmentOperator( - bindingTypeName, - typeTypeName, - typeParams, - true, - releaseFuncName, - cppMethodDefinitionsIndent, - builders.CppMethodDefinitions); - - AppendCppBaseTypeEqualityOperator( - typeTypeName, - typeParams, - cppMethodDefinitionsIndent, - true, - builders.CppMethodDefinitions); - - AppendCppBaseTypeInequalityOperator( - typeTypeName, - typeParams, - cppMethodDefinitionsIndent, - true, - builders.CppMethodDefinitions); - - // C++ add - AppendCppMethodDefinitionBegin( - GetTypeName(type), - typeof(void), - "operator+=", - typeParams, - null, - addRemoveParams, - indent, - builders.CppMethodDefinitions); - AppendIndent( - indent, - builders.CppMethodDefinitions); - builders.CppMethodDefinitions.AppendLine("{"); - AppendIndent( - indent + 1, - builders.CppMethodDefinitions); - builders.CppMethodDefinitions.Append("Plugin::"); - builders.CppMethodDefinitions.Append(addFuncName); - builders.CppMethodDefinitions.AppendLine("(Handle, del.Handle);"); - AppendCppUnhandledExceptionHandling( - indent + 1, - builders.CppMethodDefinitions); - AppendIndent( - indent, - builders.CppMethodDefinitions); - builders.CppMethodDefinitions.AppendLine("}"); - AppendIndent( - indent, - builders.CppMethodDefinitions); - builders.CppMethodDefinitions.AppendLine();; - - // C++ remove - AppendCppMethodDefinitionBegin( - GetTypeName(type), - typeof(void), - "operator-=", - typeParams, - null, - addRemoveParams, - indent, - builders.CppMethodDefinitions); - AppendIndent( - indent, - builders.CppMethodDefinitions); - builders.CppMethodDefinitions.AppendLine("{"); - AppendIndent( - indent + 1, - builders.CppMethodDefinitions); - builders.CppMethodDefinitions.Append("Plugin::"); - builders.CppMethodDefinitions.Append(removeFuncName); - builders.CppMethodDefinitions.AppendLine("(Handle, del.Handle);"); - AppendCppUnhandledExceptionHandling( - indent + 1, - builders.CppMethodDefinitions); - AppendIndent( - indent, - builders.CppMethodDefinitions); - builders.CppMethodDefinitions.AppendLine("}"); - AppendIndent( - indent, - builders.CppMethodDefinitions); - builders.CppMethodDefinitions.AppendLine();; - - // C# GetDelegate call - AppendCsharpGetDelegateCall( - GetTypeName(type), - typeParams, - "NativeInvoke", - builders.CsharpGetDelegateCalls); - - // C# class (beginning) - builders.CsharpBaseTypes.Append("class "); - builders.CsharpBaseTypes.Append(bindingTypeName); - builders.CsharpBaseTypes.AppendLine();; - builders.CsharpBaseTypes.AppendLine("{"); - - // C# class fields - builders.CsharpBaseTypes.AppendLine("\tpublic int CppHandle;"); - builders.CsharpBaseTypes.Append("\tpublic "); - AppendCsharpTypeFullName( - type, - builders.CsharpBaseTypes); - builders.CsharpBaseTypes.AppendLine(" Delegate;"); - builders.CsharpBaseTypes.AppendLine("\t"); - - // C# class constructor - builders.CsharpBaseTypes.Append("\tpublic "); - builders.CsharpBaseTypes.Append(bindingTypeName); - builders.CsharpBaseTypes.AppendLine("(int cppHandle)"); - builders.CsharpBaseTypes.AppendLine("\t{"); - builders.CsharpBaseTypes.AppendLine("\t\tCppHandle = cppHandle;"); - builders.CsharpBaseTypes.AppendLine("\t\tDelegate = NativeInvoke;"); - builders.CsharpBaseTypes.AppendLine("\t}"); - builders.CsharpBaseTypes.AppendLine("\t"); - - // Build the name of the C++ binding function that C# calls - builders.TempStrBuilder.Length = 0; - AppendNativeInvokeFuncName( - type, - typeParams, - "NativeInvoke", - builders.TempStrBuilder); - string nativeInvokeFuncName = builders.TempStrBuilder.ToString(); - - // operator() is how C# forwards the delegate invocation to C++ - MethodInfo invokeMethod = type.GetMethod("Invoke"); - AppendBaseTypeCppMethodCall( - type, - bindingTypeName, - typeTypeName, - typeParams, - invokeMethod, - "NativeInvoke", - nativeInvokeFuncName, - "operator()", - false, - true, - indent, - builders); - - // C# class (ending) - builders.CsharpBaseTypes.AppendLine("}"); - builders.CsharpBaseTypes.AppendLine();; - - // Invoke() is how C++ invokes the delegate - AppendBaseTypeMethodCallsCsharpMethod( - type, - bindingTypeName, - typeParams, - invokeMethod, - "Invoke", - null, - indent, - builders); - - // C# constructor delegate type - AppendCsharpDelegateType( - constructorFuncName, - true, - type, - TypeKind.Class, - typeof(void), - constructorParams, - builders.CsharpDelegateTypes); - - AppendCsharpBaseTypeConstructorFunction( - type, - GetTypeName(bindingTypeName, string.Empty), - true, - constructorFuncName, - constructorParams, - new ParameterInfo[0], - builders.CsharpFunctions); - - // C# release delegate type - AppendCsharpDelegateType( - releaseFuncName, - true, - type, - TypeKind.Class, - typeof(void), - releaseParams, - builders.CsharpDelegateTypes); - - AppendCsharpBaseTypeReleaseFunction( - type, - GetTypeName(bindingTypeName, string.Empty), - true, - releaseFuncName, - null, - releaseParams, - builders.CsharpFunctions); - - // C# add delegate type - AppendCsharpDelegateType( - addFuncName, - false, - type, - TypeKind.Class, - typeof(void), - addRemoveParams, - builders.CsharpDelegateTypes); - - // C# add function - AppendCsharpFunctionBeginning( - type, - addFuncName, - false, - TypeKind.Class, - typeof(void), - addRemoveParams, - builders.CsharpFunctions); - builders.CsharpFunctions.Append("thiz += del;"); - AppendCsharpFunctionReturn( - addRemoveParams, - typeof(void), - TypeKind.Class, - null, - false, - builders.CsharpFunctions); - - // C# remove delegate type - AppendCsharpDelegateType( - removeFuncName, - false, - type, - TypeKind.Class, - typeof(void), - addRemoveParams, - builders.CsharpDelegateTypes); - - // C# remove function - AppendCsharpFunctionBeginning( - type, - removeFuncName, - false, - TypeKind.Class, - typeof(void), - addRemoveParams, - builders.CsharpFunctions); - builders.CsharpFunctions.Append("thiz -= del;"); - AppendCsharpFunctionReturn( - addRemoveParams, - typeof(void), - TypeKind.Class, - null, - false, - builders.CsharpFunctions); - - // C++ method definitions (end) - AppendCppMethodDefinitionsEnd( - indent, - builders.CppMethodDefinitions); - - // C++ type definition (end) - AppendCppTypeDefinitionEnd( - false, - indent, - builders.CppTypeDefinitions); - } - - static void AppendBaseType( - Type type, - JsonBaseType jsonBaseType, - TypeName baseTypeTypeName, - Type[] typeParams, - int maxSimultaneous, - Assembly[] assemblies, - StringBuilders builders) - { - // Get specified derived type name - TypeName derivedTypeTypeName = SplitJsonTypeName( - jsonBaseType.DerivedName); - - builders.TempStrBuilder.Length = 0; - builders.TempStrBuilder.Append("Release"); - builders.TempStrBuilder.Append(baseTypeTypeName.Name); - string releaseFuncName = builders.TempStrBuilder.ToString(); - - builders.TempStrBuilder.Length = 0; - AppendCppTypeName( - baseTypeTypeName, - builders.TempStrBuilder); - string cppBaseTypeName = builders.TempStrBuilder.ToString(); - - bool hasDefaultConstructor = !type.IsClass || - (type.GetConstructor(new Type[0]) != null || - type.GetConstructors().Length == 0); - - // Either use specified constructors, the default constructor, or - // nothing in the case of MonoBehaviour (where you can't call 'new') - JsonConstructor[] jsonConstructors = jsonBaseType.Constructors; - if (jsonConstructors == null) - { - // Base classes must have a default constructor or no - // constructors at all - if (!hasDefaultConstructor) - { - // Throw an exception so the user knows what to fix in the JSON - StringBuilder errorBuilder = new StringBuilder(1024); - errorBuilder.Append("Base type \""); - AppendCsharpTypeFullName( - type, - errorBuilder); - errorBuilder.Append( - ")\" doesn't have any specified constructors or a default constructor"); - throw new Exception(errorBuilder.ToString()); - } - - jsonConstructors = new[] - { - new JsonConstructor - { - ParamTypes = new string[0] - } - }; - } - - // Build constructor function names and parameter lists - int numConstructors = jsonConstructors.Length; - string[] constructorFuncNames = new string[numConstructors]; - string[] constructorFuncNameLowers = new string[numConstructors]; - ParameterInfo[][] cppConstructorParams = new ParameterInfo[numConstructors][]; - ParameterInfo[][] constructorParams = new ParameterInfo[numConstructors][]; - for (int i = 0; i < numConstructors; ++i) - { - JsonConstructor jsonCtor = jsonConstructors[i]; - Type[] paramTypes = GetTypes( - jsonCtor.ParamTypes, - assemblies); - - builders.TempStrBuilder.Length = 0; - builders.TempStrBuilder.Append(baseTypeTypeName.Name); - builders.TempStrBuilder.Append("Constructor"); - AppendTypeNames( - paramTypes, - builders.TempStrBuilder); - string constructorFuncName = builders.TempStrBuilder.ToString(); - - builders.TempStrBuilder[0] = char.ToLower( - builders.TempStrBuilder[0]); - string constructorFuncNameLower = builders.TempStrBuilder.ToString(); - - ParameterInfo[] parameters = GetConstructorParameters( - type, - true, - jsonCtor.ParamTypes); - int numParams = parameters.Length; - ParameterInfo[] fullParams = new ParameterInfo[numParams + 2]; - fullParams[0] = new ParameterInfo - { - Name = "cppHandle", - ParameterType = typeof(int), - DereferencedParameterType = typeof(int), - IsOut = false, - IsRef = false, - Kind = TypeKind.Primitive - }; - fullParams[1] = new ParameterInfo - { - Name = "handle", - ParameterType = typeof(int), - DereferencedParameterType = typeof(int), - IsOut = true, - IsRef = false, - Kind = TypeKind.Primitive - }; - Array.Copy( - parameters, - 0, - fullParams, - 2, - numParams); - - constructorFuncNames[i] = constructorFuncName; - constructorFuncNameLowers[i] = constructorFuncNameLower; - cppConstructorParams[i] = parameters; - constructorParams[i] = fullParams; - } - - // Determine what the C++ class should derive from - Type cppBaseClass; - Type[] cppBaseClassTypeParams; - Type[] cppCtorInitTypes = GetCppCtorInitTypes( - type, - true); - Type[] cppInterfaceTypes; - if (type.IsInterface) - { - cppBaseClass = typeof(object); - cppBaseClassTypeParams = null; - cppInterfaceTypes = new [] { type }; - } - else - { - cppBaseClass = type; - cppBaseClassTypeParams = typeParams; - cppInterfaceTypes = new Type[0]; - } - - AppendCppPointerFreeListStateAndFunctions( - baseTypeTypeName, - null, - baseTypeTypeName.Name, - builders.CppGlobalStateAndFunctions); - - AppendCppPointerFreeListInit( - null, - baseTypeTypeName, - maxSimultaneous, - baseTypeTypeName.Name, - builders.CppInitBodyArrays, - builders.CppInitBodyFirstBoot); - - // C++ type declaration - int indent = AppendCppTypeDeclaration( - baseTypeTypeName, - false, - null, - builders.CppTypeDeclarations); - - ParameterInfo[] releaseParams = { - new ParameterInfo - { - Name = "handle", - ParameterType = typeof(int), - DereferencedParameterType = typeof(int), - IsOut = false, - IsRef = false, - Kind = TypeKind.Primitive - }}; - - // C++ type definition (begin) - AppendCppTypeDefinitionBegin( - baseTypeTypeName, - TypeKind.Class, - null, - GetTypeName(cppBaseClass), - cppBaseClassTypeParams, - cppInterfaceTypes, - false, - indent, - builders.CppTypeDefinitions); - - // C++ type fields - AppendIndent( - indent + 1, - builders.CppTypeDefinitions); - builders.CppTypeDefinitions.AppendLine("int32_t CppHandle;"); - - // C++ constructor declarations - for (int i = 0; i < numConstructors; ++i) - { - AppendIndent( - indent + 1, - builders.CppTypeDefinitions); - AppendCppMethodDeclaration( - cppBaseTypeName, - false, - false, - false, - null, - null, - cppConstructorParams[i], - builders.CppTypeDefinitions); - } - - // C++ constructor declaration macro - builders.CppMacros.Append("#define "); - AppendUppercaseWithUnderscores( - derivedTypeTypeName.Namespace, - builders.CppMacros); - builders.CppMacros.Append('_'); - AppendUppercaseWithUnderscores( - derivedTypeTypeName.Name, - builders.CppMacros); - builders.CppMacros.AppendLine("_DEFAULT_CONSTRUCTOR_DECLARATION \\"); - AppendIndent(indent, builders.CppMacros); - builders.CppMacros.Append(derivedTypeTypeName.Name); - builders.CppMacros.AppendLine("(Plugin::InternalUse iu, int32_t handle);"); - AppendIndent(indent, builders.CppMacros); - builders.CppMacros.AppendLine();; - - // C++ constructor definition macro - builders.CppMacros.Append("#define "); - AppendUppercaseWithUnderscores( - derivedTypeTypeName.Namespace, - builders.CppMacros); - builders.CppMacros.Append('_'); - AppendUppercaseWithUnderscores( - derivedTypeTypeName.Name, - builders.CppMacros); - builders.CppMacros.AppendLine("_DEFAULT_CONSTRUCTOR_DEFINITION \\"); - AppendIndent(indent, builders.CppMacros); - builders.CppMacros.Append(derivedTypeTypeName.Name); - builders.CppMacros.Append("::"); - builders.CppMacros.Append(derivedTypeTypeName.Name); - builders.CppMacros.AppendLine("(Plugin::InternalUse iu, int32_t handle) \\"); - AppendCppConstructorInitializerList( - cppCtorInitTypes, - indent + 1, - builders.CppMacros, - " \\\n"); - AppendIndent(indent + 1, builders.CppMacros); - builders.CppMacros.Append(", "); - AppendCppTypeFullName( - baseTypeTypeName, - builders.CppMacros); - builders.CppMacros.AppendLine("(iu, handle) \\"); - AppendIndent(indent, builders.CppMacros); - builders.CppMacros.AppendLine("{ \\"); - AppendIndent(indent, builders.CppMacros); - builders.CppMacros.AppendLine("}"); - AppendIndent(indent, builders.CppMacros); - builders.CppMacros.AppendLine();; - - // C++ constructor inline definition macro - builders.CppMacros.Append("#define "); - AppendUppercaseWithUnderscores( - derivedTypeTypeName.Namespace, - builders.CppMacros); - builders.CppMacros.Append('_'); - AppendUppercaseWithUnderscores( - derivedTypeTypeName.Name, - builders.CppMacros); - builders.CppMacros.AppendLine("_DEFAULT_CONSTRUCTOR \\"); - AppendIndent(indent, builders.CppMacros); - builders.CppMacros.Append(derivedTypeTypeName.Name); - builders.CppMacros.AppendLine("(Plugin::InternalUse iu, int32_t handle) \\"); - AppendCppConstructorInitializerList( - cppCtorInitTypes, - indent + 1, - builders.CppMacros, - " \\\n"); - AppendIndent(indent + 1, builders.CppMacros); - builders.CppMacros.Append(", "); - AppendCppTypeFullName( - baseTypeTypeName, - builders.CppMacros); - builders.CppMacros.AppendLine("(iu, handle) \\"); - AppendIndent(indent, builders.CppMacros); - builders.CppMacros.AppendLine("{ \\"); - AppendIndent(indent, builders.CppMacros); - builders.CppMacros.AppendLine("}"); - AppendIndent(indent, builders.CppMacros); - builders.CppMacros.AppendLine();; - - // C++ default contents declaration macro - builders.CppMacros.Append("#define "); - AppendUppercaseWithUnderscores( - derivedTypeTypeName.Namespace, - builders.CppMacros); - builders.CppMacros.Append('_'); - AppendUppercaseWithUnderscores( - derivedTypeTypeName.Name, - builders.CppMacros); - builders.CppMacros.AppendLine("_DEFAULT_CONTENTS_DECLARATION \\"); - AppendIndent(indent, builders.CppMacros); - builders.CppMacros.AppendLine("void* operator new(size_t, void* p) noexcept; \\"); - AppendIndent(indent, builders.CppMacros); - builders.CppMacros.AppendLine("void operator delete(void*, size_t) noexcept; \\"); - AppendIndent(indent, builders.CppMacros); - builders.CppMacros.AppendLine();; - - // C++ default contents definition macro - builders.CppMacros.Append("#define "); - AppendUppercaseWithUnderscores( - derivedTypeTypeName.Namespace, - builders.CppMacros); - builders.CppMacros.Append('_'); - AppendUppercaseWithUnderscores( - derivedTypeTypeName.Name, - builders.CppMacros); - builders.CppMacros.AppendLine("_DEFAULT_CONTENTS_DEFINITION \\"); - AppendIndent(indent, builders.CppMacros); - builders.CppMacros.Append("void* "); - builders.CppMacros.Append(derivedTypeTypeName.Name); - builders.CppMacros.AppendLine("::operator new(size_t, void* p) noexcept\\"); - AppendIndent(indent, builders.CppMacros); - builders.CppMacros.AppendLine("{ \\"); - AppendIndent(indent + 1, builders.CppMacros); - builders.CppMacros.AppendLine("return p; \\"); - AppendIndent(indent, builders.CppMacros); - builders.CppMacros.AppendLine("} \\"); - AppendIndent(indent, builders.CppMacros); - builders.CppMacros.Append("void "); - builders.CppMacros.Append(derivedTypeTypeName.Name); - builders.CppMacros.AppendLine("::operator delete(void*, size_t) noexcept \\"); - AppendIndent(indent, builders.CppMacros); - builders.CppMacros.AppendLine("{ \\"); - AppendIndent(indent, builders.CppMacros); - builders.CppMacros.AppendLine("}"); - AppendIndent(indent, builders.CppMacros); - builders.CppMacros.AppendLine();; - - // C++ default contents inline definition macro - builders.CppMacros.Append("#define "); - AppendUppercaseWithUnderscores( - derivedTypeTypeName.Namespace, - builders.CppMacros); - builders.CppMacros.Append('_'); - AppendUppercaseWithUnderscores( - derivedTypeTypeName.Name, - builders.CppMacros); - builders.CppMacros.AppendLine("_DEFAULT_CONTENTS\\"); - AppendIndent(indent, builders.CppMacros); - builders.CppMacros.AppendLine("void* operator new(size_t, void* p) noexcept \\"); - AppendIndent(indent, builders.CppMacros); - builders.CppMacros.AppendLine("{ \\"); - AppendIndent(indent + 1, builders.CppMacros); - builders.CppMacros.AppendLine("return p; \\"); - AppendIndent(indent, builders.CppMacros); - builders.CppMacros.AppendLine("} \\"); - AppendIndent(indent, builders.CppMacros); - builders.CppMacros.AppendLine("void operator delete(void*, size_t) noexcept \\"); - AppendIndent(indent, builders.CppMacros); - builders.CppMacros.AppendLine("{ \\"); - AppendIndent(indent, builders.CppMacros); - builders.CppMacros.AppendLine("}"); - AppendIndent(indent, builders.CppMacros); - builders.CppMacros.AppendLine();; - - // C++ function pointers - AppendCppFunctionPointerDefinition( - releaseFuncName, - true, - default(TypeName), - TypeKind.None, - releaseParams, - typeof(void), - builders.CppFunctionPointers); - for (int i = 0; i < numConstructors; ++i) - { - AppendCppFunctionPointerDefinition( - constructorFuncNames[i], - true, - default(TypeName), - TypeKind.None, - constructorParams[i], - typeof(void), - builders.CppFunctionPointers); - } - - // C++ and C# init params - AppendCppInitBodyFunctionPointerParameterRead( - releaseFuncName, - true, - default(TypeName), - TypeKind.None, - releaseParams, - typeof(void), - builders.CppInitBodyParameterReads); - AppendCsharpCsharpDelegate( - releaseFuncName, - builders.CsharpInitCall, - builders.CsharpCsharpDelegates); - for (int i = 0; i < numConstructors; ++i) - { - string funcName = constructorFuncNames[i]; - AppendCppInitBodyFunctionPointerParameterRead( - funcName, - true, - default(TypeName), - TypeKind.None, - constructorParams[i], - typeof(void), - builders.CppInitBodyParameterReads); - AppendCsharpCsharpDelegate( - funcName, - builders.CsharpInitCall, - builders.CsharpCsharpDelegates); - } - - // C++ method definitions (end) - int cppMethodDefinitionsIndent = AppendNamespaceBeginning( - baseTypeTypeName.Namespace, - builders.CppMethodDefinitions); - - for (int i = 0; i < numConstructors; ++i) - { - AppendCppBaseTypeConstructor( - baseTypeTypeName.Name, - baseTypeTypeName, - TypeKind.Class, - cppBaseTypeName, - typeParams, - cppCtorInitTypes, - cppConstructorParams[i], - constructorParams[i], - false, - constructorFuncNames[i], - cppMethodDefinitionsIndent, - builders.CppMethodDefinitions); - } - - AppendCppBaseTypeNullptrConstructor( - baseTypeTypeName.Name, - baseTypeTypeName, - typeParams, - cppCtorInitTypes, - false, - cppMethodDefinitionsIndent, - builders.CppMethodDefinitions); - - AppendCppBaseTypeCopyConstructor( - baseTypeTypeName.Name, - baseTypeTypeName, - typeParams, - cppCtorInitTypes, - false, - cppMethodDefinitionsIndent, - builders.CppMethodDefinitions); - - AppendCppBaseTypeMoveConstructor( - baseTypeTypeName, - typeParams, - cppCtorInitTypes, - false, - cppMethodDefinitionsIndent, - builders.CppMethodDefinitions); - - AppendCppBaseTypeHandleConstructor( - baseTypeTypeName.Name, - baseTypeTypeName, - typeParams, - cppCtorInitTypes, - false, - cppMethodDefinitionsIndent, - builders.CppMethodDefinitions); - - AppendCppBaseTypeDestructor( - baseTypeTypeName.Name, - baseTypeTypeName, - typeParams, - false, - derivedTypeTypeName.Name, - releaseFuncName, - baseTypeTypeName.Name, - cppMethodDefinitionsIndent, - builders.CppMethodDefinitions); - - AppendCppBaseTypeAssignmentOperatorSameType( - baseTypeTypeName, - typeParams, - false, - cppMethodDefinitionsIndent, - builders.CppMethodDefinitions); - - AppendCppBaseTypeAssignmentOperatorNullptr( - baseTypeTypeName, - typeParams, - false, - releaseFuncName, - cppMethodDefinitionsIndent, - builders.CppMethodDefinitions); - - AppendCppBaseTypeMoveAssignmentOperator( - baseTypeTypeName.Name, - baseTypeTypeName, - typeParams, - false, - releaseFuncName, - cppMethodDefinitionsIndent, - builders.CppMethodDefinitions); - - AppendCppBaseTypeEqualityOperator( - baseTypeTypeName, - typeParams, - cppMethodDefinitionsIndent, - false, - builders.CppMethodDefinitions); - - AppendCppBaseTypeInequalityOperator( - baseTypeTypeName, - typeParams, - cppMethodDefinitionsIndent, - false, - builders.CppMethodDefinitions); - - if (!string.IsNullOrEmpty(derivedTypeTypeName.Name)) - { - // C++ whole object free list - AppendCppWholeObjectFreeListStateAndFunctions( - null, - baseTypeTypeName, - baseTypeTypeName.Name, - builders.CppGlobalStateAndFunctions); - AppendCppWholeObjectFreeListInit( - maxSimultaneous, - baseTypeTypeName.Name, - builders.CppInitBodyArrays, - builders.CppInitBodyFirstBoot); - - // C++ binding function to create the base class - builders.TempStrBuilder.Length = 0; - builders.TempStrBuilder.Append("New"); - builders.TempStrBuilder.Append(baseTypeTypeName.Name); - string cppDefaultConstructorBindingFunctionName = builders.TempStrBuilder.ToString(); - AppendIndent( - indent, - builders.CppMethodDefinitions); - builders.CppMethodDefinitions.Append("DLLEXPORT int32_t "); - builders.CppMethodDefinitions.Append(cppDefaultConstructorBindingFunctionName); - builders.CppMethodDefinitions.AppendLine("(int32_t handle)"); - AppendIndent( - indent, - builders.CppMethodDefinitions); - builders.CppMethodDefinitions.AppendLine("{"); - AppendIndent( - indent + 1, - builders.CppMethodDefinitions); - AppendCppTypeFullName( - baseTypeTypeName, - builders.CppMethodDefinitions); - builders.CppMethodDefinitions.Append("* memory = Plugin::StoreWhole"); - builders.CppMethodDefinitions.Append(baseTypeTypeName.Name); - builders.CppMethodDefinitions.AppendLine("();"); - AppendIndent( - indent + 1, - builders.CppMethodDefinitions); - AppendCppTypeFullName( - derivedTypeTypeName, - builders.CppMethodDefinitions); - builders.CppMethodDefinitions.Append("* thiz = new (memory) "); - AppendCppTypeFullName( - derivedTypeTypeName, - builders.CppMethodDefinitions); - builders.CppMethodDefinitions.AppendLine("(Plugin::InternalUse::Only, handle);"); - AppendIndent( - indent + 1, - builders.CppMethodDefinitions); - builders.CppMethodDefinitions.AppendLine("return thiz->CppHandle;"); - AppendIndent( - indent, - builders.CppMethodDefinitions); - builders.CppMethodDefinitions.AppendLine("}"); - builders.CppMethodDefinitions.AppendLine(); - - // C# usage of the C++ binding function to create from C# default constructor - ParameterInfo[] cppDefaultConstructorBindingFunctionParams = ConvertParameters( - new[] { typeof(int) }); - AppendCsharpDelegate( - true, - GetTypeName(string.Empty, string.Empty), - null, - cppDefaultConstructorBindingFunctionName, - cppDefaultConstructorBindingFunctionParams, - typeof(int), - TypeKind.None, - builders.CsharpCppDelegates); - AppendCsharpImport( - GetTypeName(string.Empty, string.Empty), - null, - cppDefaultConstructorBindingFunctionName, - ConvertParameters(Type.EmptyTypes), - typeof(int), - builders.CsharpImports); - AppendCsharpGetDelegateCall( - GetTypeName(string.Empty, string.Empty), - null, - cppDefaultConstructorBindingFunctionName, - builders.CsharpGetDelegateCalls); - - // C++ binding function to destroy the base class - builders.TempStrBuilder.Length = 0; - builders.TempStrBuilder.Append("Destroy"); - builders.TempStrBuilder.Append(baseTypeTypeName.Name); - string cppDestroyBindingFunctionName = builders.TempStrBuilder.ToString(); - AppendIndent( - indent, - builders.CppMethodDefinitions); - builders.CppMethodDefinitions.Append("DLLEXPORT void "); - builders.CppMethodDefinitions.Append(cppDestroyBindingFunctionName); - builders.CppMethodDefinitions.AppendLine("(int32_t cppHandle)"); - AppendIndent( - indent, - builders.CppMethodDefinitions); - builders.CppMethodDefinitions.AppendLine("{"); - AppendIndent( - indent + 1, - builders.CppMethodDefinitions); - AppendCppTypeFullName( - baseTypeTypeName, - builders.CppMethodDefinitions); - builders.CppMethodDefinitions.Append("* instance = Plugin::Get"); - builders.CppMethodDefinitions.Append(baseTypeTypeName.Name); - builders.CppMethodDefinitions.AppendLine("(cppHandle);"); - AppendIndent( - indent + 1, - builders.CppMethodDefinitions); - builders.CppMethodDefinitions.Append("instance->~"); - AppendCppTypeName( - baseTypeTypeName, - builders.CppMethodDefinitions); - builders.CppMethodDefinitions.AppendLine("();"); - AppendIndent( - indent, - builders.CppMethodDefinitions); - builders.CppMethodDefinitions.AppendLine("}"); - builders.CppMethodDefinitions.AppendLine(); - - // C# usage of the C++ binding function to destroy from C# default constructor - ParameterInfo[] cppDestroyBindingFunctionParams = ConvertParameters( - new [] { typeof(int) }); - AppendCsharpDelegate( - true, - GetTypeName(string.Empty, string.Empty), - null, - cppDestroyBindingFunctionName, - cppDestroyBindingFunctionParams, - typeof(void), - TypeKind.None, - builders.CsharpCppDelegates); - ParameterInfo[] cppDestroyImportFunctionParams = ConvertParameters( - new Type[0]); - AppendCsharpImport( - GetTypeName(string.Empty, string.Empty), - null, - cppDestroyBindingFunctionName, - cppDestroyImportFunctionParams, - typeof(void), - builders.CsharpImports); - AppendCsharpGetDelegateCall( - GetTypeName(string.Empty, string.Empty), - null, - cppDestroyBindingFunctionName, - builders.CsharpGetDelegateCalls); - - // C# DestroyFunction enumerator - builders.CsharpDestroyFunctionEnumerators.Append("\t\t\t"); - builders.CsharpDestroyFunctionEnumerators.Append(baseTypeTypeName.Name); - builders.CsharpDestroyFunctionEnumerators.AppendLine(","); - - // C# Destroy queue cases - builders.CsharpDestroyQueueCases.Append("\t\t\t\t\t\tcase DestroyFunction."); - builders.CsharpDestroyQueueCases.Append(baseTypeTypeName.Name); - builders.CsharpDestroyQueueCases.AppendLine(":"); - builders.CsharpDestroyQueueCases.Append("\t\t\t\t\t\t\t"); - builders.CsharpDestroyQueueCases.Append(cppDestroyBindingFunctionName); - builders.CsharpDestroyQueueCases.AppendLine("(entry.CppHandle);"); - builders.CsharpDestroyQueueCases.AppendLine("\t\t\t\t\t\t\tbreak;"); - } - - // C# class (beginning) - builders.CsharpBaseTypes.Append("namespace "); - builders.CsharpBaseTypes.Append(baseTypeTypeName.Namespace); - builders.CsharpBaseTypes.AppendLine();; - builders.CsharpBaseTypes.AppendLine("{"); - builders.CsharpBaseTypes.Append("\tclass "); - builders.CsharpBaseTypes.Append(baseTypeTypeName.Name); - if (jsonBaseType != null) - { - builders.CsharpBaseTypes.Append(" : "); - AppendCsharpTypeFullName( - type, - builders.CsharpBaseTypes); - } - builders.CsharpBaseTypes.AppendLine();; - builders.CsharpBaseTypes.AppendLine("\t{"); - - // C# class fields - builders.CsharpBaseTypes.AppendLine("\t\tpublic int CppHandle;"); - builders.CsharpBaseTypes.AppendLine("\t\t"); - - if (derivedTypeTypeName.Name != null) - { - // C# class default constructor if the base class has one - if (hasDefaultConstructor) - { - builders.CsharpBaseTypes.Append("\t\tpublic "); - builders.CsharpBaseTypes.Append(baseTypeTypeName.Name); - builders.CsharpBaseTypes.AppendLine("()"); - builders.CsharpBaseTypes.AppendLine("\t\t{"); - builders.CsharpBaseTypes.AppendLine( - "\t\t\tint handle = NativeScript.Bindings.ObjectStore.Store(this);"); - builders.CsharpBaseTypes.Append( - "\t\t\tCppHandle = NativeScript.Bindings.New"); - builders.CsharpBaseTypes.Append(baseTypeTypeName.Name); - builders.CsharpBaseTypes.AppendLine("(handle);"); - builders.CsharpBaseTypes.AppendLine("\t\t}"); - builders.CsharpBaseTypes.AppendLine("\t\t"); - } - - // C# finalizer/destructor - builders.CsharpBaseTypes.Append("\t\t~"); - builders.CsharpBaseTypes.Append(baseTypeTypeName.Name); - builders.CsharpBaseTypes.AppendLine("()"); - builders.CsharpBaseTypes.AppendLine("\t\t{"); - builders.CsharpBaseTypes.AppendLine("\t\t\tif (CppHandle != 0)"); - builders.CsharpBaseTypes.AppendLine("\t\t\t{"); - builders.CsharpBaseTypes.Append( - "\t\t\t\tNativeScript.Bindings.QueueDestroy(NativeScript.Bindings.DestroyFunction."); - builders.CsharpBaseTypes.Append(baseTypeTypeName.Name); - builders.CsharpBaseTypes.AppendLine(", CppHandle);"); - builders.CsharpBaseTypes.AppendLine("\t\t\t\tCppHandle = 0;"); - builders.CsharpBaseTypes.AppendLine("\t\t\t}"); - builders.CsharpBaseTypes.AppendLine("\t\t}"); - builders.CsharpBaseTypes.AppendLine("\t\t"); - } - - // C# class constructors - for (int i = 0; i < numConstructors; ++i) - { - builders.CsharpBaseTypes.Append("\t\tpublic "); - builders.CsharpBaseTypes.Append(baseTypeTypeName.Name); - builders.CsharpBaseTypes.Append("(int cppHandle"); - ParameterInfo[] parameters = cppConstructorParams[i]; - if (parameters.Length > 0) - { - builders.CsharpBaseTypes.Append(", "); - AppendCsharpParams( - parameters, - builders.CsharpBaseTypes); - } - builders.CsharpBaseTypes.AppendLine(")"); - builders.CsharpBaseTypes.Append("\t\t\t: base("); - AppendCsharpFunctionCallParameters( - parameters, - builders.CsharpBaseTypes); - builders.CsharpBaseTypes.AppendLine(")"); - builders.CsharpBaseTypes.AppendLine("\t\t{"); - builders.CsharpBaseTypes.AppendLine("\t\t\tCppHandle = cppHandle;"); - builders.CsharpBaseTypes.AppendLine("\t\t}"); - builders.CsharpBaseTypes.AppendLine("\t\t"); - } - - // C# constructor delegate type - for (int i = 0; i < numConstructors; ++i) - { - AppendCsharpDelegateType( - constructorFuncNames[i], - true, - type, - TypeKind.Class, - typeof(void), - constructorParams[i], - builders.CsharpDelegateTypes); - } - - for (int i = 0; i < numConstructors; ++i) - { - AppendCsharpBaseTypeConstructorFunction( - type, - baseTypeTypeName, - false, - constructorFuncNames[i], - constructorParams[i], - cppConstructorParams[i], - builders.CsharpFunctions); - } - - // C# release delegate type - AppendCsharpDelegateType( - releaseFuncName, - true, - type, - TypeKind.Class, - typeof(void), - releaseParams, - builders.CsharpDelegateTypes); - - AppendCsharpBaseTypeReleaseFunction( - type, - baseTypeTypeName, - false, - releaseFuncName, - jsonBaseType.DerivedName, - releaseParams, - builders.CsharpFunctions); - - // All abstract methods - foreach (MethodInfo methodInfo in type.GetMethods()) - { - // Property methods like "get_X" have a "special name" - if (methodInfo.IsAbstract && !methodInfo.IsSpecialName) - { - AppendBaseTypeNativeMethod( - type, - baseTypeTypeName, - typeParams, - methodInfo, - false, - indent, - builders); - } - } - - // All interface methods - if (type.IsInterface) - { - foreach (Type interfaceType in type.GetInterfaces()) - { - foreach (MethodInfo methodInfo in interfaceType.GetMethods()) - { - // Property methods like "get_X" have a "special name" - if (methodInfo.IsAbstract && !methodInfo.IsSpecialName) - { - AppendBaseTypeNativeMethod( - type, - baseTypeTypeName, - typeParams, - methodInfo, - false, - indent, - builders); - } - } - } - } - - // Specified virtual methods - if (jsonBaseType.OverrideMethods != null) - { - MethodInfo[] methods = type.GetMethods(); - Type[] genericArgTypes = type.GetGenericArguments(); - foreach (JsonMethod jsonMethod in jsonBaseType.OverrideMethods) - { - if (jsonMethod.GenericParams != null) - { - foreach (JsonGenericParams jsonGenericParams in - jsonMethod.GenericParams) - { - MethodInfo methodInfo = GetMethod( - jsonMethod, - type, - typeParams, - genericArgTypes, - methods, - jsonGenericParams.Types); - AppendBaseTypeNativeMethod( - type, - baseTypeTypeName, - typeParams, - methodInfo, - false, - indent, - builders); - } - } - else - { - MethodInfo methodInfo = GetMethod( - jsonMethod, - type, - typeParams, - genericArgTypes, - methods, - null); - AppendBaseTypeNativeMethod( - type, - baseTypeTypeName, - typeParams, - methodInfo, - false, - indent, - builders); - } - } - } - - // All abstract properties - foreach (PropertyInfo propertyInfo in type.GetProperties()) - { - MethodInfo getMethodInfo = propertyInfo.GetGetMethod(); - MethodInfo setMethodInfo = propertyInfo.GetSetMethod(); - if ((getMethodInfo == null || !getMethodInfo.IsAbstract) && - (setMethodInfo == null || !setMethodInfo.IsAbstract)) - { - continue; - } - AppendBaseTypeProperty( - type, - baseTypeTypeName.Name, - baseTypeTypeName, - typeParams, - propertyInfo, - getMethodInfo, - setMethodInfo, - indent, - builders); - } - - // All interface properties - if (type.IsInterface) - { - foreach (Type interfaceType in type.GetInterfaces()) - { - foreach (PropertyInfo propertyInfo in - interfaceType.GetProperties()) - { - MethodInfo getMethodInfo = propertyInfo.GetGetMethod(); - MethodInfo setMethodInfo = propertyInfo.GetSetMethod(); - if ((getMethodInfo == null || !getMethodInfo.IsAbstract) && - (setMethodInfo == null || !setMethodInfo.IsAbstract)) - { - continue; - } - AppendBaseTypeProperty( - type, - baseTypeTypeName.Name, - baseTypeTypeName, - typeParams, - propertyInfo, - getMethodInfo, - setMethodInfo, - indent, - builders); - } - } - } - - // Specified virtual properties - if (jsonBaseType.OverrideProperties != null) - { - PropertyInfo[] properties = type.GetProperties(); - foreach (JsonProperty jsonProperty in jsonBaseType.OverrideProperties) - { - PropertyInfo propertyInfo = null; - foreach (PropertyInfo curPropertyInfo in properties) - { - if (curPropertyInfo.Name == jsonProperty.Name) - { - propertyInfo = curPropertyInfo; - break; - } - } - if (propertyInfo == null) - { - // Throw an exception so the user knows what to fix in the JSON - StringBuilder errorBuilder = new StringBuilder(1024); - errorBuilder.Append("Property \""); - AppendCsharpTypeFullName( - type, - errorBuilder); - errorBuilder.Append('.'); - errorBuilder.Append(jsonProperty.Name); - errorBuilder.Append(")\" not found"); - throw new Exception(errorBuilder.ToString()); - } - - MethodInfo getMethodInfo = propertyInfo.GetGetMethod(); - MethodInfo setMethodInfo = propertyInfo.GetSetMethod(); - if ((getMethodInfo == null || !getMethodInfo.IsVirtual) && - (setMethodInfo == null || !setMethodInfo.IsVirtual)) - { - // Throw an exception so the user knows what to fix in the JSON - StringBuilder errorBuilder = new StringBuilder(1024); - errorBuilder.Append("Property \""); - AppendCsharpTypeFullName( - type, - errorBuilder); - errorBuilder.Append('.'); - errorBuilder.Append(jsonProperty.Name); - errorBuilder.Append( - ")\" doesn't have either a virtual 'get' or 'set' to override"); - throw new Exception(errorBuilder.ToString()); - } - AppendBaseTypeProperty( - type, - baseTypeTypeName.Name, - baseTypeTypeName, - typeParams, - propertyInfo, - getMethodInfo, - setMethodInfo, - indent, - builders); - } - } - - // All abstract events - foreach (EventInfo eventInfo in type.GetEvents()) - { - MethodInfo addMethodInfo = eventInfo.GetAddMethod(); - MethodInfo removeMethodInfo = eventInfo.GetRemoveMethod(); - if ((addMethodInfo == null || !addMethodInfo.IsAbstract) && - (removeMethodInfo == null || !removeMethodInfo.IsAbstract)) - { - continue; - } - AppendBaseTypeEvent( - type, - baseTypeTypeName, - typeParams, - eventInfo, - addMethodInfo, - removeMethodInfo, - indent, - builders); - } - - // All interface events - if (type.IsInterface) - { - foreach (Type interfaceType in type.GetInterfaces()) - { - foreach (EventInfo eventInfo in interfaceType.GetEvents()) - { - MethodInfo addMethodInfo = eventInfo.GetAddMethod(); - MethodInfo removeMethodInfo = eventInfo.GetRemoveMethod(); - if ((addMethodInfo == null || !addMethodInfo.IsAbstract) && - (removeMethodInfo == null || !removeMethodInfo.IsAbstract)) - { - continue; - } - AppendBaseTypeEvent( - type, - baseTypeTypeName, - typeParams, - eventInfo, - addMethodInfo, - removeMethodInfo, - indent, - builders); - } - } - } - - // Specified virtual events - if (jsonBaseType.OverrideEvents != null) - { - EventInfo[] events = type.GetEvents(); - foreach (JsonEvent jsonEvent in jsonBaseType.OverrideEvents) - { - EventInfo eventInfo = null; - foreach (EventInfo curEventInfo in events) - { - if (curEventInfo.Name == jsonEvent.Name) - { - eventInfo = curEventInfo; - break; - } - } - if (eventInfo == null) - { - // Throw an exception so the user knows what to fix in the JSON - StringBuilder errorBuilder = new StringBuilder(1024); - errorBuilder.Append("Event \""); - AppendCsharpTypeFullName( - type, - errorBuilder); - errorBuilder.Append('.'); - errorBuilder.Append(jsonEvent.Name); - errorBuilder.Append(")\" not found"); - throw new Exception(errorBuilder.ToString()); - } - - MethodInfo addMethodInfo = eventInfo.GetAddMethod(); - MethodInfo removeMethodInfo = eventInfo.GetRemoveMethod(); - if ((addMethodInfo == null || !addMethodInfo.IsVirtual) && - (removeMethodInfo == null || !removeMethodInfo.IsVirtual)) - { - // Throw an exception so the user knows what to fix in the JSON - StringBuilder errorBuilder = new StringBuilder(1024); - errorBuilder.Append("Event \""); - AppendCsharpTypeFullName( - type, - errorBuilder); - errorBuilder.Append('.'); - errorBuilder.Append(jsonEvent.Name); - errorBuilder.Append( - ")\" doesn't have either a virtual 'add' or 'remove' to override"); - throw new Exception(errorBuilder.ToString()); - } - AppendBaseTypeEvent( - type, - baseTypeTypeName, - typeParams, - eventInfo, - addMethodInfo, - removeMethodInfo, - indent, - builders); - } - } - - // C# class (ending) - builders.CsharpBaseTypes.AppendLine("\t}"); - builders.CsharpBaseTypes.AppendLine("}"); - builders.CsharpBaseTypes.AppendLine(); - - // C++ method definitions (end) - AppendCppMethodDefinitionsEnd( - indent, - builders.CppMethodDefinitions); - - // C++ type definition (end) - AppendCppTypeDefinitionEnd( - false, - indent, - builders.CppTypeDefinitions); - } - - static void AppendBaseTypeNativeMethod( - Type type, - TypeName typeTypeName, - Type[] typeParams, - MethodInfo methodInfo, - bool typeIsDelegate, - int indent, - StringBuilders builders) - { - AppendCsharpGetDelegateCall( - GetTypeName(type), - typeParams, - methodInfo.Name, - builders.CsharpGetDelegateCalls); - - // Build the name of the C++ binding function that C# calls - builders.TempStrBuilder.Length = 0; - AppendNativeInvokeFuncName( - type, - typeParams, - methodInfo.Name, - builders.TempStrBuilder); - string nativeInvokeFuncName = builders.TempStrBuilder.ToString(); - - AppendBaseTypeCppMethodCall( - type, - typeTypeName.Name, - typeTypeName, - typeParams, - methodInfo, - methodInfo.Name, - nativeInvokeFuncName, - methodInfo.Name, - IsNonDelegateClass(type), - typeIsDelegate, - indent, - builders); - } - - static void AppendBaseTypeProperty( - Type type, - string typeName, - TypeName typeTypeName, - Type[] typeParams, - PropertyInfo propertyInfo, - MethodInfo getMethodInfo, - MethodInfo setMethodInfo, - int indent, - StringBuilders builders) - { - bool isOverride = IsNonDelegateClass(type); - - ParameterInfo[] parameters; - if (getMethodInfo != null && getMethodInfo.IsVirtual) - { - parameters = ConvertParameters( - getMethodInfo.GetParameters()); - } - else - { - System.Reflection.ParameterInfo[] setParams = - setMethodInfo.GetParameters(); - parameters = ConvertParameters(setParams, 1); - } - - builders.CsharpBaseTypes.Append("\t\tpublic "); - if (isOverride) - { - builders.CsharpBaseTypes.Append("override "); - } - AppendCsharpTypeFullName( - propertyInfo.PropertyType, - builders.CsharpBaseTypes); - builders.CsharpBaseTypes.Append(' '); - if (parameters.Length == 0) - { - builders.CsharpBaseTypes.Append(propertyInfo.Name); - } - else - { - builders.CsharpBaseTypes.Append("this["); - AppendCsharpParams( - parameters, - builders.CsharpBaseTypes); - builders.CsharpBaseTypes.Append(']'); - } - builders.CsharpBaseTypes.AppendLine();; - builders.CsharpBaseTypes.AppendLine("\t\t{"); - - TypeKind propertyTypeKind = GetTypeKind( - propertyInfo.PropertyType); - - if (getMethodInfo != null && getMethodInfo.IsVirtual) - { - AppendBaseTypeNativePropertyOrEvent( - type, - typeName, - typeParams, - typeTypeName, - propertyInfo.Name, - propertyTypeKind, - getMethodInfo, - "Get", - false, - indent, - builders); - } - - if (setMethodInfo != null && setMethodInfo.IsVirtual) - { - AppendBaseTypeNativePropertyOrEvent( - type, - typeName, - typeParams, - typeTypeName, - propertyInfo.Name, - propertyTypeKind, - setMethodInfo, - "Set", - false, - indent, - builders); - } - - builders.CsharpBaseTypes.AppendLine("\t\t}"); - builders.CsharpBaseTypes.AppendLine("\t\t"); - } - - static void AppendBaseTypeEvent( - Type type, - TypeName typeTypeName, - Type[] typeParams, - EventInfo eventInfo, - MethodInfo addMethodInfo, - MethodInfo removeMethodInfo, - int indent, - StringBuilders builders) - { - bool isOverride = IsNonDelegateClass(type); - - builders.CsharpBaseTypes.Append("\t\tpublic "); - if (isOverride) - { - builders.CsharpBaseTypes.Append("override "); - } - builders.CsharpBaseTypes.Append("event "); - AppendCsharpTypeFullName( - eventInfo.EventHandlerType, - builders.CsharpBaseTypes); - builders.CsharpBaseTypes.Append(' '); - builders.CsharpBaseTypes.Append(eventInfo.Name); - builders.CsharpBaseTypes.AppendLine();; - builders.CsharpBaseTypes.AppendLine("\t\t{"); - - TypeKind eventHandlerTypeKind = GetTypeKind( - eventInfo.EventHandlerType); - - if (addMethodInfo != null && addMethodInfo.IsVirtual) - { - AppendBaseTypeNativePropertyOrEvent( - type, - typeTypeName.Name, - typeParams, - typeTypeName, - eventInfo.Name, - eventHandlerTypeKind, - addMethodInfo, - "Add", - false, - indent, - builders); - } - - if (removeMethodInfo != null && removeMethodInfo.IsVirtual) - { - AppendBaseTypeNativePropertyOrEvent( - type, - typeTypeName.Name, - typeParams, - typeTypeName, - eventInfo.Name, - eventHandlerTypeKind, - removeMethodInfo, - "Remove", - false, - indent, - builders); - } - - builders.CsharpBaseTypes.AppendLine("\t\t\t}"); - builders.CsharpBaseTypes.AppendLine("\t\t\t"); - } - - static void AppendBaseTypeNativePropertyOrEvent( - Type type, - string typeName, - Type[] typeParams, - TypeName typeTypeName, - string propertyOrEventName, - TypeKind propertyOrEventTypeKind, - MethodInfo methodInfo, - string operationType, - bool typeIsDelegate, - int indent, - StringBuilders builders) - { - builders.TempStrBuilder.Length = 0; - builders.TempStrBuilder.Append(operationType); - builders.TempStrBuilder.Append(propertyOrEventName); - string funcName = builders.TempStrBuilder.ToString(); - - AppendCsharpGetDelegateCall( - GetTypeName(type), - typeParams, - funcName, - builders.CsharpGetDelegateCalls); - - // Build the name of the C++ binding function that C# calls - builders.TempStrBuilder.Length = 0; - AppendNativeInvokeFuncName( - type, - typeParams, - funcName, - builders.TempStrBuilder); - string nativeInvokeFuncName = builders.TempStrBuilder.ToString(); - - ParameterInfo[] invokeParams = AppendBaseTypeCppNativeInvokeCall( - type, - typeName, - typeTypeName, - typeParams, - methodInfo, - funcName, - funcName, - typeIsDelegate, - indent, - builders); - - // C# method that calls the C++ binding function - ParameterInfo[] invokeParamsWithThis = PrependThisParameter( - invokeParams); - builders.CsharpBaseTypes.Append("\t\t\t"); - builders.CsharpBaseTypes.Append(char.ToLower(operationType[0])); - builders.CsharpBaseTypes.Append( - operationType, - 1, - operationType.Length - 1); - builders.CsharpBaseTypes.AppendLine();; - builders.CsharpBaseTypes.AppendLine("\t\t\t{"); - AppendCsharpBaseTypeCppMethodCallMethodBody( - methodInfo, - nativeInvokeFuncName, - invokeParamsWithThis, - propertyOrEventTypeKind, - 4, - builders.CsharpBaseTypes); - builders.CsharpBaseTypes.AppendLine("\t\t\t}"); - } - - static void AppendCsharpParams( - ParameterInfo[] parameters, - StringBuilder output) - { - for (int i = 0; i < parameters.Length; ++i) - { - ParameterInfo param = parameters[i]; - AppendCsharpTypeFullName( - param.ParameterType, - output); - output.Append(' '); - output.Append(param.Name); - if (i != parameters.Length - 1) - { - output.Append(", "); - } - } - } - - static void AppendBaseTypeMethodCallsCsharpMethod( - Type type, - string typeName, - Type[] typeParams, - MethodInfo methodInfo, - string methodName, - string csharpMethodName, - int indent, - StringBuilders builders) - { - builders.TempStrBuilder.Length = 0; - builders.TempStrBuilder.Append(typeName); - builders.TempStrBuilder.Append(methodName); - string funcName = builders.TempStrBuilder.ToString(); - - // C++ method declaration for the method - ParameterInfo[] invokeParams = ConvertParameters( - methodInfo.GetParameters()); - AppendIndent( - indent + 1, - builders.CppTypeDefinitions); - AppendCppMethodDeclaration( - methodName, - false, - false, - false, - methodInfo.ReturnType, - null, - invokeParams, - builders.CppTypeDefinitions); - - // C++ function pointer for the C# binding function - AppendCppFunctionPointerDefinition( - funcName, - false, - default(TypeName), - TypeKind.None, - invokeParams, - methodInfo.ReturnType, - builders.CppFunctionPointers); - - // C++ and C# Init parameter and body for the C# binding function - AppendCppInitBodyFunctionPointerParameterRead( - funcName, - false, - default(TypeName), - TypeKind.None, - invokeParams, - methodInfo.ReturnType, - builders.CppInitBodyParameterReads); - AppendCsharpCsharpDelegate( - funcName, - builders.CsharpInitCall, - builders.CsharpCsharpDelegates); - - // C++ method definition for the method - TypeKind returnTypeKind = GetTypeKind( - methodInfo.ReturnType); - AppendCppMethodDefinitionBegin( - GetTypeName(type), - methodInfo.ReturnType, - methodName, - typeParams, - null, - invokeParams, - indent, - builders.CppMethodDefinitions); - AppendIndent( - indent, - builders.CppMethodDefinitions); - builders.CppMethodDefinitions.AppendLine("{"); - AppendCppPluginFunctionCall( - false, - GetTypeName(type), - TypeKind.Class, - typeParams, - methodInfo.ReturnType, - funcName, - invokeParams, - indent + 1, - builders.CppMethodDefinitions); - AppendCppMethodReturn( - methodInfo.ReturnType, - returnTypeKind, - indent + 1, - builders.CppMethodDefinitions); - AppendIndent( - indent, - builders.CppMethodDefinitions); - builders.CppMethodDefinitions.AppendLine("}"); - AppendIndent( - indent, - builders.CppMethodDefinitions); - builders.CppMethodDefinitions.AppendLine();; - - // C# delegate type for the binding function that C++ calls - ParameterInfo[] invokeParamsWithThis = new ParameterInfo[ - invokeParams.Length + 1]; - for (int i = 0; i < invokeParams.Length; ++i) - { - invokeParamsWithThis[i+1] = invokeParams[i]; - } - invokeParamsWithThis[0] = new ParameterInfo { - Name = "thisHandle", - ParameterType = typeof(int), - DereferencedParameterType = typeof(int), - IsOut = false, - IsRef = false, - Kind = TypeKind.Primitive - }; - AppendCsharpDelegateType( - funcName, - true, - type, - TypeKind.Class, - methodInfo.ReturnType, - invokeParamsWithThis, - builders.CsharpDelegateTypes); - - // C# binding function that C++ calls to invoke the method - AppendCsharpFunctionBeginning( - type, - funcName, - true, - TypeKind.Class, - methodInfo.ReturnType, - invokeParamsWithThis, - builders.CsharpFunctions); - builders.CsharpFunctions.Append("(("); - AppendCsharpTypeFullName( - type, - builders.CsharpFunctions); - builders.CsharpFunctions.Append( - ")NativeScript.Bindings.ObjectStore.Get(thisHandle))"); - if (csharpMethodName != null) - { - builders.CsharpFunctions.Append('.'); - builders.CsharpFunctions.Append(csharpMethodName); - } - builders.CsharpFunctions.Append('('); - AppendCsharpFunctionCallParameters( - invokeParams, - builders.CsharpFunctions); - builders.CsharpFunctions.Append(");"); - AppendCsharpFunctionReturn( - invokeParams, - methodInfo.ReturnType, - returnTypeKind, - null, - false, - builders.CsharpFunctions); - } - - static void AppendNativeInvokeFuncName( - Type type, - Type[] typeParams, - string funcName, - StringBuilder output) - { - AppendNamespace( - type.Namespace, - string.Empty, - output); - AppendTypeNameWithoutSuffixes( - type.Name, - output); - AppendTypeNames( - typeParams, - output); - output.Append(funcName); - } - - static void AppendBaseTypeCppMethodCall( - Type type, - string typeName, - TypeName typeTypeName, - Type[] typeParams, - MethodInfo invokeMethod, - string funcName, - string nativeInvokeFuncName, - string methodName, - bool isOverride, - bool typeIsDelegate, - int indent, - StringBuilders builders) - { - ParameterInfo[] invokeParams = AppendBaseTypeCppNativeInvokeCall( - type, - typeName, - typeTypeName, - typeParams, - invokeMethod, - funcName, - methodName, - typeIsDelegate, - indent, - builders); - - // C# method that calls the C++ binding function - ParameterInfo[] invokeParamsWithThis = PrependThisParameter( - invokeParams); - TypeKind invokeReturnTypeKind = GetTypeKind( - invokeMethod.ReturnType); - AppendCsharpBaseTypeCppMethodCallMethod( - isOverride, - invokeMethod, - funcName, - invokeParams, - nativeInvokeFuncName, - invokeParamsWithThis, - invokeReturnTypeKind, - builders.CsharpBaseTypes); - } - - static ParameterInfo[] AppendBaseTypeCppNativeInvokeCall( - Type type, - string typeName, - TypeName typeTypeName, - Type[] typeParams, - MethodInfo invokeMethod, - string funcName, - string methodName, - bool typeIsDelegate, - int indent, - StringBuilders builders) - { - // C++ method declaration - ParameterInfo[] invokeParams = ConvertParameters( - invokeMethod.GetParameters()); - AppendIndent( - indent + 1, - builders.CppTypeDefinitions); - AppendCppMethodDeclaration( - methodName, - false, - true, - false, - invokeMethod.ReturnType, - null, - invokeParams, - builders.CppTypeDefinitions); - - // C++ method definition. This is a no-op that game code overrides. - AppendCppMethodDefinitionBegin( - typeTypeName, - invokeMethod.ReturnType, - methodName, - typeIsDelegate ? typeParams : null, - null, - invokeParams, - indent, - builders.CppMethodDefinitions); - AppendIndent( - indent, - builders.CppMethodDefinitions); - builders.CppMethodDefinitions.AppendLine("{"); - if (invokeMethod.ReturnType != typeof(void)) - { - TypeKind returnTypeKind = GetTypeKind(invokeMethod.ReturnType); - AppendIndent( - indent + 1, - builders.CppMethodDefinitions); - if (returnTypeKind == TypeKind.Class || - returnTypeKind == TypeKind.ManagedStruct) - { - builders.CppMethodDefinitions.AppendLine("return nullptr;"); - } - else - { - builders.CppMethodDefinitions.AppendLine("return {};"); - } - } - AppendIndent( - indent, - builders.CppMethodDefinitions); - builders.CppMethodDefinitions.AppendLine("}"); - AppendIndent( - indent, - builders.CppMethodDefinitions); - builders.CppMethodDefinitions.AppendLine();; - - // C++ binding function that C# calls. Calls the C++ method. - TypeKind invokeReturnTypeKind = GetTypeKind( - invokeMethod.ReturnType); - AppendCppBaseTypeMethodInvokeBindingFunction( - funcName, - type, - typeParams, - invokeMethod, - methodName, - invokeReturnTypeKind, - invokeParams, - indent, - typeName, - builders.CppMethodDefinitions); - - // C# delegate for the C++ binding function - AppendCsharpDelegate( - false, - GetTypeName(type), - typeParams, - funcName, - invokeParams, - invokeMethod.ReturnType, - invokeReturnTypeKind, - builders.CsharpCppDelegates); - - // C# import for the C++ binding function - AppendCsharpImport( - GetTypeName(type), - typeParams, - funcName, - invokeParams, - invokeMethod.ReturnType, - builders.CsharpImports); - - return invokeParams; - } - - static ParameterInfo[] PrependThisParameter( - ParameterInfo[] invokeParams) - { - ParameterInfo[] invokeParamsWithThis = new ParameterInfo[ - invokeParams.Length + 1]; - for (int i = 0; i < invokeParams.Length; ++i) - { - invokeParamsWithThis[i+1] = invokeParams[i]; - } - invokeParamsWithThis[0] = new ParameterInfo { - Name = "thisHandle", - ParameterType = typeof(int), - DereferencedParameterType = typeof(int), - IsOut = false, - IsRef = false, - Kind = TypeKind.Primitive - }; - return invokeParamsWithThis; - } - - static void AppendCsharpBaseTypeReleaseFunction( - Type type, - TypeName bindingTypeTypeName, - bool typeIsDelegate, - string releaseFuncName, - string derivedName, - ParameterInfo[] releaseParams, - StringBuilder output) - { - AppendCsharpFunctionBeginning( - type, - releaseFuncName, - true, - TypeKind.Class, - typeof(void), - releaseParams, - output); - if (typeIsDelegate || derivedName != null) - { - AppendCsharpTypeFullName( - bindingTypeTypeName, - output); - output.AppendLine(" thiz;"); - } - if (typeIsDelegate) - { - output.AppendLine("\t\t\t\tif (classHandle != 0)"); - output.AppendLine("\t\t\t\t{"); - output.Append("\t\t\t\t\tthiz = ("); - AppendCsharpTypeFullName( - bindingTypeTypeName, - output); - output.AppendLine(")ObjectStore.Remove(classHandle);"); - output.AppendLine("\t\t\t\t\tthiz.CppHandle = 0;"); - output.AppendLine("\t\t\t\t}"); - output.AppendLine("\t\t\t\t"); - } - if (derivedName != null) - { - output.Append("\t\t\t\tthiz = ("); - AppendCsharpTypeFullName( - bindingTypeTypeName, - output); - output.AppendLine(")ObjectStore.Get(handle);"); - output.AppendLine("\t\t\t\tint cppHandle = thiz.CppHandle;"); - output.AppendLine("\t\t\t\tthiz.CppHandle = 0;"); - output.Append("\t\t\t\tQueueDestroy(DestroyFunction."); - output.Append(bindingTypeTypeName.Name); - output.AppendLine(", cppHandle);"); - } - output.Append("\t\t\t\tObjectStore.Remove(handle);"); - AppendCsharpFunctionReturn( - releaseParams, - typeof(void), - TypeKind.Class, - null, - true, - output); - } - - static void AppendCsharpBaseTypeCppMethodCallMethod( - bool isOverride, - MethodInfo invokeMethod, - string funcName, - ParameterInfo[] invokeParams, - string nativeInvokeFuncName, - ParameterInfo[] invokeParamsWithThis, - TypeKind invokeReturnTypeKind, - StringBuilder output) - { - output.Append("\t\tpublic "); - if (isOverride) - { - output.Append("override "); - } - AppendCsharpTypeFullName( - invokeMethod.ReturnType, - output); - output.Append(' '); - output.Append(funcName); - output.Append("("); - AppendCsharpParams( - invokeParams, - output); - output.AppendLine(")"); - output.AppendLine("\t\t{"); - AppendCsharpBaseTypeCppMethodCallMethodBody( - invokeMethod, - nativeInvokeFuncName, - invokeParamsWithThis, - invokeReturnTypeKind, - 3, - output); - output.AppendLine("\t\t}"); - output.AppendLine("\t"); - } - - static void AppendCsharpBaseTypeCppMethodCallMethodBody( - MethodInfo invokeMethod, - string nativeInvokeFuncName, - ParameterInfo[] invokeParamsWithThis, - TypeKind invokeReturnTypeKind, - int indent, - StringBuilder output) - { - AppendIndent( - indent, - output); - output.AppendLine("if (CppHandle != 0)"); - AppendIndent( - indent, - output); - output.AppendLine("{"); - AppendIndent( - indent + 1, - output); - output.AppendLine("int thisHandle = CppHandle;"); - AppendCppFunctionCall( - nativeInvokeFuncName, - invokeParamsWithThis, - invokeMethod.ReturnType, - true, - indent + 1, - output); - if (invokeMethod.ReturnType != typeof(void)) - { - AppendIndent( - indent + 1, - output); - output.Append("return "); - switch (invokeReturnTypeKind) - { - case TypeKind.Class: - case TypeKind.ManagedStruct: - if (invokeMethod.ReturnType != typeof(object)) - { - output.Append('('); - AppendCsharpTypeFullName( - invokeMethod.ReturnType, - output); - output.Append(')'); - } - AppendHandleStoreTypeName( - invokeMethod.ReturnType, - output); - output.AppendLine(".Get(returnVal);"); - break; - default: - output.AppendLine("returnVal;"); - break; - } - } - AppendIndent( - indent, - output); - output.AppendLine("}"); - if (invokeMethod.ReturnType != typeof(void)) - { - AppendIndent( - indent, - output); - output.Append("return default("); - AppendCsharpTypeFullName( - invokeMethod.ReturnType, - output); - output.AppendLine(");"); - } - } - - static void AppendCsharpBaseTypeConstructorFunction( - Type type, - TypeName typeTypeName, - bool typeIsDelegate, - string constructorFuncName, - ParameterInfo[] constructorParams, - ParameterInfo[] cppConstructorParams, - StringBuilder output) - { - AppendCsharpFunctionBeginning( - type, - constructorFuncName, - true, - TypeKind.Class, - typeof(void), - constructorParams, - output); - output.Append("var thiz = new "); - AppendCsharpTypeFullName(typeTypeName, output); - output.Append("(cppHandle"); - if (cppConstructorParams.Length > 0) - { - output.Append(", "); - AppendCsharpFunctionCallParameters( - cppConstructorParams, - output); - } - output.AppendLine(");"); - if (typeIsDelegate) - { - output.AppendLine( - "\t\t\t\tclassHandle = NativeScript.Bindings.ObjectStore.Store(thiz);"); - output.Append( - "\t\t\t\thandle = NativeScript.Bindings.ObjectStore.Store(thiz.Delegate);"); - } - else - { - output.Append( - "\t\t\t\thandle = NativeScript.Bindings.ObjectStore.Store(thiz);"); - } - AppendCsharpFunctionReturn( - constructorParams, - typeof(void), - TypeKind.Class, - null, - true, - output); - } - - static void AppendCppBaseTypeMethodInvokeBindingFunction( - string funcName, - Type type, - Type[] typeParams, - MethodInfo method, - string methodName, - TypeKind methodReturnTypeKind, - ParameterInfo[] methodParams, - int indent, - string typeName, - StringBuilder output) - { - AppendIndent( - indent, - output); - output.Append("DLLEXPORT "); - if (method.ReturnType == typeof(void)) - { - output.Append("void"); - } - else if (method.ReturnType == typeof(bool)) - { - // C linkage requires us to use primitive types - output.Append("int32_t"); - } - else if (method.ReturnType == typeof(char)) - { - // C linkage requires us to use primitive types - output.Append("int16_t"); - } - else - { - switch (methodReturnTypeKind) - { - case TypeKind.Class: - case TypeKind.ManagedStruct: - output.Append("int32_t"); - break; - case TypeKind.Primitive: - AppendCppPrimitiveTypeName( - method.ReturnType, - output); - break; - default: - AppendCppTypeFullName( - method.ReturnType, - output); - break; - } - } - output.Append(' '); - AppendCsharpDelegateName( - GetTypeName(type), - typeParams, - funcName, - output); - output.Append("(int32_t cppHandle"); - if (methodParams.Length > 0) - { - output.Append(", "); - } - for (int i = 0; i < methodParams.Length; ++i) - { - ParameterInfo param = methodParams[i]; - switch (param.Kind) - { - case TypeKind.Class: - case TypeKind.ManagedStruct: - output.Append("int32_t "); - output.Append(param.Name); - output.Append("Handle"); - break; - case TypeKind.Primitive: - AppendCppPrimitiveTypeName( - param.ParameterType, - output); - output.Append(' '); - output.Append(param.Name); - break; - default: - AppendCppTypeFullName( - param.ParameterType, - output); - output.Append(' '); - output.Append(param.Name); - break; - } - if (i != methodParams.Length - 1) - { - output.Append(", "); - } - } - output.AppendLine(")"); - AppendIndent( - indent, - output); - output.AppendLine("{"); - AppendIndent( - indent + 1, - output); - output.AppendLine("try"); - AppendIndent( - indent + 1, - output); - output.AppendLine("{"); - foreach (ParameterInfo parameter in methodParams) - { - if (parameter.Kind == TypeKind.Class || - parameter.Kind == TypeKind.ManagedStruct) - { - AppendIndent( - indent + 2, - output); - output.Append("auto "); - output.Append(parameter.Name); - output.Append(" = "); - AppendCppTypeFullName( - parameter.ParameterType, - output); - output.Append("(Plugin::InternalUse::Only, "); - output.Append(parameter.Name); - output.AppendLine("Handle);"); - } - } - AppendIndent( - indent + 2, - output); - if (method.ReturnType != typeof(void)) - { - output.Append("return "); - } - output.Append("Plugin::Get"); - output.Append(typeName); - output.Append("(cppHandle)->"); - output.Append(methodName); - output.Append("("); - for (int i = 0; i < methodParams.Length; ++i) - { - ParameterInfo parameter = methodParams[i]; - if (parameter.Kind == TypeKind.Class || - parameter.Kind == TypeKind.ManagedStruct) - { - output.Append(parameter.Name); - } - else - { - output.Append(parameter.Name); - } - if (i != methodParams.Length - 1) - { - output.Append(", "); - } - } - output.Append(")"); - if ( - method.ReturnType != typeof(void) && - (methodReturnTypeKind == TypeKind.Class || - methodReturnTypeKind == TypeKind.ManagedStruct)) - { - output.Append(".Handle"); - } - output.AppendLine(";"); - AppendIndent( - indent + 1, - output); - output.AppendLine("}"); - AppendIndent( - indent + 1, - output); - output.AppendLine( - "catch (System::Exception ex)"); - AppendIndent( - indent + 1, - output); - output.AppendLine("{"); - AppendIndent( - indent + 2, - output); - output.AppendLine( - "Plugin::SetException(ex.Handle);"); - if (method.ReturnType != typeof(void)) - { - AppendIndent( - indent + 2, - output); - output.AppendLine( - "return {};"); - } - AppendIndent( - indent + 1, - output); - output.AppendLine("}"); - AppendIndent( - indent + 1, - output); - output.AppendLine("catch (...)"); - AppendIndent( - indent + 1, - output); - output.AppendLine("{"); - AppendIndent( - indent + 2, - output); - output.Append( - "System::String msg = \"Unhandled exception invoking "); - AppendCppTypeFullName( - type, - output); - output.AppendLine("\";"); - AppendIndent( - indent + 2, - output); - output.AppendLine( - "System::Exception ex(msg);"); - AppendIndent( - indent + 2, - output); - output.AppendLine( - "Plugin::SetException(ex.Handle);"); - if (method.ReturnType != typeof(void)) - { - AppendIndent( - indent + 2, - output); - output.AppendLine( - "return {};"); - } - AppendIndent( - indent + 1, - output); - output.AppendLine("}"); - AppendIndent( - indent, - output); - output.AppendLine("}"); - AppendIndent( - indent, - output); - output.AppendLine();; - } - - static void AppendCppBaseTypeInequalityOperator( - TypeName typeTypeName, - Type[] typeParams, - int cppMethodDefinitionsIndent, - bool typeIsDelegate, - StringBuilder output) - { - AppendIndent( - cppMethodDefinitionsIndent, - output); - output.Append("bool "); - AppendCppTypeFullName( - typeTypeName, - output); - AppendCppTypeParameters( - typeIsDelegate ? typeParams : null, - output); - output.Append("::operator!=(const "); - AppendCppTypeFullName( - typeTypeName, - output); - AppendCppTypeParameters( - typeIsDelegate ? typeParams : null, - output); - output.AppendLine("& other) const"); - AppendIndent( - cppMethodDefinitionsIndent, - output); - output.AppendLine("{"); - AppendIndent( - cppMethodDefinitionsIndent + 1, - output); - output.AppendLine( - "return Handle != other.Handle;"); - AppendIndent( - cppMethodDefinitionsIndent, - output); - output.AppendLine("}"); - AppendIndent( - cppMethodDefinitionsIndent, - output); - output.AppendLine();; - } - - static void AppendCppBaseTypeEqualityOperator( - TypeName typeTypeName, - Type[] typeParams, - int cppMethodDefinitionsIndent, - bool typeIsDelegate, - StringBuilder output) - { - AppendIndent( - cppMethodDefinitionsIndent, - output); - output.Append("bool "); - AppendCppTypeFullName( - typeTypeName, - output); - AppendCppTypeParameters( - typeIsDelegate ? typeParams : null, - output); - output.Append("::operator==(const "); - AppendCppTypeFullName( - typeTypeName, - output); - AppendCppTypeParameters( - typeIsDelegate ? typeParams : null, - output); - output.AppendLine("& other) const"); - AppendIndent( - cppMethodDefinitionsIndent, - output); - output.AppendLine("{"); - AppendIndent( - cppMethodDefinitionsIndent + 1, - output); - output.AppendLine( - "return Handle == other.Handle;"); - AppendIndent( - cppMethodDefinitionsIndent, - output); - output.AppendLine("}"); - AppendIndent( - cppMethodDefinitionsIndent, - output); - output.AppendLine();; - } - - static void AppendCppBaseTypeMoveAssignmentOperator( - string bindingTypeName, - TypeName typeTypeName, - Type[] typeParams, - bool typeIsDelegate, - string releaseFuncName, - int cppMethodDefinitionsIndent, - StringBuilder output) - { - AppendIndent( - cppMethodDefinitionsIndent, - output); - AppendCppTypeFullName( - typeTypeName, - output); - AppendCppTypeParameters( - typeIsDelegate ? typeParams : null, - output); - output.Append("& "); - AppendCppTypeFullName( - typeTypeName, - output); - AppendCppTypeParameters( - typeIsDelegate ? typeParams : null, - output); - output.Append("::operator=("); - AppendCppTypeFullName( - typeTypeName, - output); - AppendCppTypeParameters( - typeIsDelegate ? typeParams : null, - output); - output.AppendLine("&& other)"); - AppendIndent( - cppMethodDefinitionsIndent, - output); - output.AppendLine("{"); - AppendIndent( - cppMethodDefinitionsIndent + 1, - output); - output.Append("Plugin::Remove"); - output.Append(bindingTypeName); - output.AppendLine("(CppHandle);"); - AppendIndent( - cppMethodDefinitionsIndent + 1, - output); - output.AppendLine("CppHandle = 0;"); - AppendIndent( - cppMethodDefinitionsIndent + 1, - output); - output.AppendLine("if (Handle)"); - AppendIndent( - cppMethodDefinitionsIndent + 1, - output); - output.AppendLine("{"); - AppendIndent( - cppMethodDefinitionsIndent + 2, - output); - output.AppendLine("int32_t handle = Handle;"); - if (typeIsDelegate) - { - AppendIndent( - cppMethodDefinitionsIndent + 2, - output); - output.AppendLine("int32_t classHandle = ClassHandle;"); - } - AppendIndent( - cppMethodDefinitionsIndent + 2, - output); - output.AppendLine("Handle = 0;"); - if (typeIsDelegate) - { - AppendIndent( - cppMethodDefinitionsIndent + 2, - output); - output.AppendLine("ClassHandle = 0;"); - } - AppendIndent( - cppMethodDefinitionsIndent + 2, - output); - output.AppendLine( - "if (Plugin::DereferenceManagedClassNoRelease(handle))"); - AppendIndent( - cppMethodDefinitionsIndent + 2, - output); - output.AppendLine("{"); - AppendIndent( - cppMethodDefinitionsIndent + 3, - output); - output.Append("Plugin::"); - output.Append(releaseFuncName); - output.Append("(handle"); - if (typeIsDelegate) - { - output.Append(", classHandle"); - } - output.AppendLine(");"); - AppendCppUnhandledExceptionHandling( - cppMethodDefinitionsIndent + 3, - output); - AppendIndent( - cppMethodDefinitionsIndent + 2, - output); - output.AppendLine("}"); - AppendIndent( - cppMethodDefinitionsIndent + 1, - output); - output.AppendLine("}"); - if (typeIsDelegate) - { - AppendIndent( - cppMethodDefinitionsIndent + 1, - output); - output.AppendLine( - "ClassHandle = other.ClassHandle;"); - AppendIndent( - cppMethodDefinitionsIndent + 1, - output); - output.AppendLine("other.ClassHandle = 0;"); - } - AppendIndent( - cppMethodDefinitionsIndent + 1, - output); - output.AppendLine("Handle = other.Handle;"); - AppendIndent( - cppMethodDefinitionsIndent + 1, - output); - output.AppendLine("other.Handle = 0;"); - AppendIndent( - cppMethodDefinitionsIndent + 1, - output); - output.AppendLine("return *this;"); - AppendIndent( - cppMethodDefinitionsIndent, - output); - output.AppendLine("}"); - AppendIndent( - cppMethodDefinitionsIndent, - output); - output.AppendLine();; - } - - static void AppendCppBaseTypeAssignmentOperatorNullptr( - TypeName typeTypeName, - Type[] typeParams, - bool typeIsDelegate, - string releaseFuncName, - int cppMethodDefinitionsIndent, - StringBuilder output) - { - AppendIndent( - cppMethodDefinitionsIndent, - output); - AppendCppTypeFullName( - typeTypeName, - output); - AppendCppTypeParameters( - typeIsDelegate ? typeParams : null, - output); - output.Append("& "); - AppendCppTypeFullName( - typeTypeName, - output); - AppendCppTypeParameters( - typeIsDelegate ? typeParams : null, - output); - output.AppendLine( - "::operator=(decltype(nullptr))"); - AppendIndent( - cppMethodDefinitionsIndent, - output); - output.AppendLine("{"); - AppendIndent( - cppMethodDefinitionsIndent + 1, - output); - output.AppendLine("if (Handle)"); - AppendIndent( - cppMethodDefinitionsIndent + 1, - output); - output.AppendLine("{"); - AppendIndent( - cppMethodDefinitionsIndent + 2, - output); - output.AppendLine("int32_t handle = Handle;"); - if (typeIsDelegate) - { - AppendIndent( - cppMethodDefinitionsIndent + 2, - output); - output.AppendLine("int32_t classHandle = ClassHandle;"); - } - AppendIndent( - cppMethodDefinitionsIndent + 2, - output); - output.AppendLine("Handle = 0;"); - if (typeIsDelegate) - { - AppendIndent( - cppMethodDefinitionsIndent + 2, - output); - output.AppendLine("ClassHandle = 0;"); - } - AppendIndent( - cppMethodDefinitionsIndent + 2, - output); - output.AppendLine( - "if (Plugin::DereferenceManagedClassNoRelease(handle))"); - AppendIndent( - cppMethodDefinitionsIndent + 2, - output); - output.AppendLine("{"); - AppendIndent( - cppMethodDefinitionsIndent + 3, - output); - output.Append("Plugin::"); - output.Append(releaseFuncName); - output.Append("(handle"); - if (typeIsDelegate) - { - output.Append(", classHandle"); - } - output.AppendLine(");"); - AppendCppUnhandledExceptionHandling( - cppMethodDefinitionsIndent + 3, - output); - AppendIndent( - cppMethodDefinitionsIndent + 2, - output); - output.AppendLine("}"); - AppendIndent( - cppMethodDefinitionsIndent + 1, - output); - output.AppendLine("}"); - if (typeIsDelegate) - { - AppendIndent( - cppMethodDefinitionsIndent + 1, - output); - output.AppendLine("ClassHandle = 0;"); - } - AppendIndent( - cppMethodDefinitionsIndent + 1, - output); - output.AppendLine("Handle = 0;"); - AppendIndent( - cppMethodDefinitionsIndent + 1, - output); - output.AppendLine("return *this;"); - AppendIndent( - cppMethodDefinitionsIndent, - output); - output.AppendLine("}"); - AppendIndent( - cppMethodDefinitionsIndent, - output); - output.AppendLine();; - } - - static void AppendCppBaseTypeAssignmentOperatorSameType( - TypeName typeTypeName, - Type[] typeParams, - bool typeIsDelegate, - int cppMethodDefinitionsIndent, - StringBuilder output) - { - AppendIndent( - cppMethodDefinitionsIndent, - output); - AppendCppTypeFullName( - typeTypeName, - output); - AppendCppTypeParameters( - typeIsDelegate ? typeParams : null, - output); - output.Append("& "); - AppendCppTypeFullName( - typeTypeName, - output); - AppendCppTypeParameters( - typeIsDelegate ? typeParams : null, - output); - output.Append("::operator=(const "); - AppendCppTypeFullName( - typeTypeName, - output); - AppendCppTypeParameters( - typeIsDelegate ? typeParams : null, - output); - output.AppendLine("& other)"); - AppendIndent( - cppMethodDefinitionsIndent, - output); - output.AppendLine("{"); - AppendSetHandle( - typeTypeName, - TypeKind.Class, - typeParams, - cppMethodDefinitionsIndent + 1, - "this", - "other.Handle", - output); - if (typeIsDelegate) - { - AppendIndent( - cppMethodDefinitionsIndent + 1, - output); - output.AppendLine( - "ClassHandle = other.ClassHandle;"); - } - AppendIndent( - cppMethodDefinitionsIndent + 1, - output); - output.AppendLine("return *this;"); - AppendIndent( - cppMethodDefinitionsIndent, - output); - output.AppendLine("}"); - AppendIndent( - cppMethodDefinitionsIndent, - output); - output.AppendLine();; - } - - static void AppendCppBaseTypeDestructor( - string typeName, - TypeName typeTypeName, - Type[] typeParams, - bool typeIsDelegate, - string derivedTypeName, - string releaseFuncName, - string bindingTypeName, - int cppMethodDefinitionsIndent, - StringBuilder output) - { - AppendIndent( - cppMethodDefinitionsIndent, - output); - AppendCppTypeFullName( - typeTypeName, - output); - AppendCppTypeParameters( - typeIsDelegate ? typeParams : null, - output); - output.Append("::~"); - AppendCppTypeName( - typeTypeName, - output); - AppendCppTypeParameters( - typeIsDelegate ? typeParams : null, - output); - output.AppendLine("()"); - AppendIndent( - cppMethodDefinitionsIndent, - output); - output.AppendLine("{"); - if (!string.IsNullOrEmpty(derivedTypeName)) - { - AppendIndent( - cppMethodDefinitionsIndent + 1, - output); - output.Append("Plugin::RemoveWhole"); - output.Append(bindingTypeName); - output.AppendLine("(this);"); - } - AppendIndent( - cppMethodDefinitionsIndent + 1, - output); - output.Append("Plugin::Remove"); - output.Append(typeName); - output.AppendLine("(CppHandle);"); - AppendIndent( - cppMethodDefinitionsIndent + 1, - output); - output.AppendLine("CppHandle = 0;"); - AppendIndent( - cppMethodDefinitionsIndent + 1, - output); - output.AppendLine("if (Handle)"); - AppendIndent( - cppMethodDefinitionsIndent + 1, - output); - output.AppendLine("{"); - AppendIndent( - cppMethodDefinitionsIndent + 2, - output); - output.AppendLine("int32_t handle = Handle;"); - if (typeIsDelegate) - { - AppendIndent( - cppMethodDefinitionsIndent + 2, - output); - output.AppendLine("int32_t classHandle = ClassHandle;"); - } - AppendIndent( - cppMethodDefinitionsIndent + 2, - output); - output.AppendLine("Handle = 0;"); - if (typeIsDelegate) - { - AppendIndent( - cppMethodDefinitionsIndent + 2, - output); - output.AppendLine("ClassHandle = 0;"); - } - AppendIndent( - cppMethodDefinitionsIndent + 2, - output); - output.AppendLine( - "if (Plugin::DereferenceManagedClassNoRelease(handle))"); - AppendIndent( - cppMethodDefinitionsIndent + 2, - output); - output.AppendLine("{"); - AppendIndent( - cppMethodDefinitionsIndent + 3, - output); - output.Append("Plugin::"); - output.Append(releaseFuncName); - output.Append("(handle"); - if (typeIsDelegate) - { - output.Append(", classHandle"); - } - output.AppendLine(");"); - AppendCppUnhandledExceptionHandling( - cppMethodDefinitionsIndent + 3, - output); - AppendIndent( - cppMethodDefinitionsIndent + 2, - output); - output.AppendLine("}"); - AppendIndent( - cppMethodDefinitionsIndent + 1, - output); - output.AppendLine("}"); - AppendIndent( - cppMethodDefinitionsIndent, - output); - output.AppendLine("}"); - AppendIndent( - cppMethodDefinitionsIndent, - output); - output.AppendLine();; - } - - static void AppendCppBaseTypeHandleConstructor( - string bindingTypeName, - TypeName typeTypeName, - Type[] typeParams, - Type[] interfaceTypes, - bool typeIsDelegate, - int cppMethodDefinitionsIndent, - StringBuilder output) - { - AppendIndent( - cppMethodDefinitionsIndent, - output); - AppendCppTypeFullName( - typeTypeName, - output); - AppendCppTypeParameters( - typeIsDelegate ? typeParams : null, - output); - output.Append("::"); - AppendCppTypeName( - typeTypeName, - output); - output.AppendLine( - "(Plugin::InternalUse, int32_t handle)"); - AppendCppConstructorInitializerList( - interfaceTypes, - cppMethodDefinitionsIndent + 1, - output); - AppendIndent( - cppMethodDefinitionsIndent, - output); - output.AppendLine("{"); - AppendIndent( - cppMethodDefinitionsIndent + 1, - output); - output.AppendLine("Handle = handle;"); - AppendIndent( - cppMethodDefinitionsIndent + 1, - output); - output.Append("CppHandle = Plugin::Store"); - output.Append(bindingTypeName); - output.AppendLine("(this);"); - AppendIndent( - cppMethodDefinitionsIndent + 1, - output); - output.AppendLine("if (Handle)"); - AppendIndent( - cppMethodDefinitionsIndent + 1, - output); - output.AppendLine("{"); - AppendIndent( - cppMethodDefinitionsIndent + 2, - output); - output.AppendLine( - "Plugin::ReferenceManagedClass(Handle);"); - AppendIndent( - cppMethodDefinitionsIndent + 1, - output); - output.AppendLine("}"); - if (typeIsDelegate) - { - AppendIndent( - cppMethodDefinitionsIndent + 1, - output); - output.AppendLine( - "ClassHandle = 0;"); - } - AppendIndent( - cppMethodDefinitionsIndent, - output); - output.AppendLine("}"); - AppendIndent( - cppMethodDefinitionsIndent, - output); - output.AppendLine();; - } - - static void AppendCppBaseTypeMoveConstructor( - TypeName typeTypeName, - Type[] typeParams, - Type[] interfaceTypes, - bool typeIsDelegate, - int cppMethodDefinitionsIndent, - StringBuilder output) - { - AppendIndent( - cppMethodDefinitionsIndent, - output); - AppendCppTypeFullName( - typeTypeName, - output); - AppendCppTypeParameters( - typeIsDelegate ? typeParams : null, - output); - output.Append("::"); - AppendCppTypeName( - typeTypeName, - output); - output.Append("("); - AppendCppTypeFullName( - typeTypeName, - output); - AppendCppTypeParameters( - typeIsDelegate ? typeParams : null, - output); - output.AppendLine("&& other)"); - AppendCppConstructorInitializerList( - interfaceTypes, - cppMethodDefinitionsIndent + 1, - output); - AppendIndent( - cppMethodDefinitionsIndent, - output); - output.AppendLine("{"); - AppendIndent( - cppMethodDefinitionsIndent + 1, - output); - output.AppendLine( - "Handle = other.Handle;"); - AppendIndent( - cppMethodDefinitionsIndent + 1, - output); - output.AppendLine( - "CppHandle = other.CppHandle;"); - if (typeIsDelegate) - { - AppendIndent( - cppMethodDefinitionsIndent + 1, - output); - output.AppendLine( - "ClassHandle = other.ClassHandle;"); - } - AppendIndent( - cppMethodDefinitionsIndent + 1, - output); - output.AppendLine("other.Handle = 0;"); - AppendIndent( - cppMethodDefinitionsIndent + 1, - output); - output.AppendLine("other.CppHandle = 0;"); - if (typeIsDelegate) - { - AppendIndent( - cppMethodDefinitionsIndent + 1, - output); - output.AppendLine("other.ClassHandle = 0;"); - } - AppendIndent( - cppMethodDefinitionsIndent, - output); - output.AppendLine("}"); - AppendIndent( - cppMethodDefinitionsIndent, - output); - output.AppendLine();; - } - - static void AppendCppBaseTypeCopyConstructor( - string typeName, - TypeName typeTypeName, - Type[] typeParams, - Type[] interfaceTypes, - bool typeIsDelegate, - int cppMethodDefinitionsIndent, - StringBuilder output) - { - AppendIndent( - cppMethodDefinitionsIndent, - output); - AppendCppTypeFullName( - typeTypeName, - output); - AppendCppTypeParameters( - typeIsDelegate ? typeParams : null, - output); - output.Append("::"); - AppendCppTypeName( - typeTypeName, - output); - output.Append("(const "); - AppendCppTypeFullName( - typeTypeName, - output); - AppendCppTypeParameters( - typeIsDelegate ? typeParams : null, - output); - output.AppendLine("& other)"); - AppendCppConstructorInitializerList( - interfaceTypes, - cppMethodDefinitionsIndent + 1, - output); - AppendIndent( - cppMethodDefinitionsIndent, - output); - output.AppendLine("{"); - AppendIndent( - cppMethodDefinitionsIndent + 1, - output); - output.AppendLine( - "Handle = other.Handle;"); - AppendIndent( - cppMethodDefinitionsIndent + 1, - output); - output.Append("CppHandle = Plugin::Store"); - output.Append(typeName); - output.AppendLine("(this);"); - AppendIndent( - cppMethodDefinitionsIndent + 1, - output); - output.AppendLine("if (Handle)"); - AppendIndent( - cppMethodDefinitionsIndent + 1, - output); - output.AppendLine("{"); - AppendIndent( - cppMethodDefinitionsIndent + 2, - output); - output.AppendLine( - "Plugin::ReferenceManagedClass(Handle);"); - AppendIndent( - cppMethodDefinitionsIndent + 1, - output); - output.AppendLine("}"); - if (typeIsDelegate) - { - AppendIndent( - cppMethodDefinitionsIndent + 1, - output); - output.AppendLine( - "ClassHandle = other.ClassHandle;"); - } - AppendIndent( - cppMethodDefinitionsIndent, - output); - output.AppendLine("}"); - AppendIndent( - cppMethodDefinitionsIndent, - output); - output.AppendLine();; - } - - static void AppendCppBaseTypeNullptrConstructor( - string typeName, - TypeName cppTypeTypeName, - Type[] typeParams, - Type[] interfaceTypes, - bool typeIsDelegate, - int cppMethodDefinitionsIndent, - StringBuilder output) - { - AppendIndent( - cppMethodDefinitionsIndent, - output); - AppendCppTypeName( - cppTypeTypeName, - output); - AppendCppTypeParameters( - typeIsDelegate ? typeParams : null, - output); - output.Append("::"); - AppendCppTypeName( - cppTypeTypeName, - output); - output.AppendLine("(decltype(nullptr))"); - AppendCppConstructorInitializerList( - interfaceTypes, - cppMethodDefinitionsIndent + 1, - output); - AppendIndent( - cppMethodDefinitionsIndent, - output); - output.AppendLine("{"); - AppendIndent( - cppMethodDefinitionsIndent + 1, - output); - output.Append("CppHandle = Plugin::Store"); - output.Append(typeName); - output.AppendLine("(this);"); - if (typeIsDelegate) - { - AppendIndent( - cppMethodDefinitionsIndent + 1, - output); - output.AppendLine("ClassHandle = 0;"); - } - AppendIndent( - cppMethodDefinitionsIndent, - output); - output.AppendLine("}"); - AppendIndent( - cppMethodDefinitionsIndent, - output); - output.AppendLine();; - } - - static void AppendCppBaseTypeConstructor( - string bindingTypeName, - TypeName typeTypeName, - TypeKind typeKind, - string cppTypeName, - Type[] typeParams, - Type[] interfaceTypes, - ParameterInfo[] cppParameters, - ParameterInfo[] parameters, - bool typeIsDelegate, - string constructorFuncName, - int cppMethodDefinitionsIndent, - StringBuilder output) - { - AppendCppMethodDefinitionBegin( - typeTypeName, - null, - cppTypeName, - typeIsDelegate ? typeParams : null, - null, - cppParameters, - cppMethodDefinitionsIndent, - output); - AppendCppConstructorInitializerList( - interfaceTypes, - cppMethodDefinitionsIndent + 1, - output); - AppendIndent( - cppMethodDefinitionsIndent, - output); - output.AppendLine("{"); - AppendIndent( - cppMethodDefinitionsIndent + 1, - output); - output.Append("CppHandle = Plugin::Store"); - output.Append(bindingTypeName); - output.AppendLine("(this);"); - AppendIndent( - cppMethodDefinitionsIndent + 1, - output); - output.AppendLine("System::Int32* handle = (System::Int32*)&Handle;"); - AppendIndent( - cppMethodDefinitionsIndent + 1, - output); - output.AppendLine("int32_t cppHandle = CppHandle;"); - if (typeIsDelegate) - { - AppendIndent( - cppMethodDefinitionsIndent + 1, - output); - output.AppendLine("System::Int32* classHandle = (System::Int32*)&ClassHandle;"); - } - AppendCppPluginFunctionCall( - true, - GetTypeName(bindingTypeName, typeTypeName.Namespace), - typeKind, - typeParams, - null, - constructorFuncName, - parameters, - cppMethodDefinitionsIndent + 1, - output); - AppendIndent( - cppMethodDefinitionsIndent + 1, - output); - output.AppendLine("if (Handle)"); - AppendIndent( - cppMethodDefinitionsIndent + 1, - output); - output.AppendLine("{"); - AppendIndent( - cppMethodDefinitionsIndent + 2, - output); - output.AppendLine( - "Plugin::ReferenceManagedClass(Handle);"); - AppendIndent( - cppMethodDefinitionsIndent + 1, - output); - output.AppendLine("}"); - AppendIndent( - cppMethodDefinitionsIndent + 1, - output); - output.AppendLine("else"); - AppendIndent( - cppMethodDefinitionsIndent + 1, - output); - output.AppendLine("{"); - AppendIndent( - cppMethodDefinitionsIndent + 2, - output); - output.Append("Plugin::Remove"); - output.Append(bindingTypeName); - output.AppendLine("(CppHandle);"); - if (typeIsDelegate) - { - AppendIndent( - cppMethodDefinitionsIndent + 2, - output); - output.AppendLine("ClassHandle = 0;"); - } - AppendIndent( - cppMethodDefinitionsIndent + 2, - output); - output.AppendLine("CppHandle = 0;"); - AppendIndent( - cppMethodDefinitionsIndent + 1, - output); - output.AppendLine("}"); - AppendCppUnhandledExceptionHandling( - cppMethodDefinitionsIndent + 1, - output); - AppendIndent( - cppMethodDefinitionsIndent, - output); - output.AppendLine("}"); - AppendIndent( - cppMethodDefinitionsIndent, - output); - output.AppendLine();; - } - - static void AppendCppPointerFreeListInit( - Type[] typeParams, - TypeName cppTypeTypeName, - int maxSimultaneous, - string typeName, - StringBuilder output, - StringBuilder outputFirstBoot) - { - output.Append("\tPlugin::"); - output.Append(typeName); - output.Append("FreeListSize = "); - output.Append(maxSimultaneous); - output.AppendLine(";"); - - output.Append("\tPlugin::"); - output.Append(typeName); - output.Append("FreeList = ("); - AppendCppTypeFullName( - cppTypeTypeName, - output); - AppendCppTypeParameters( - typeParams, - output); - output.AppendLine("**)curMemory;"); - - output.Append("\tcurMemory += "); - output.Append(maxSimultaneous); - output.Append(" * sizeof("); - AppendCppTypeFullName( - cppTypeTypeName, - output); - AppendCppTypeParameters( - typeParams, - output); - output.AppendLine("*);"); - - output.AppendLine("\t"); - - outputFirstBoot.Append("\t\tfor (int32_t i = 0, end = Plugin::"); - outputFirstBoot.Append(typeName); - outputFirstBoot.AppendLine("FreeListSize - 1; i < end; ++i)"); - outputFirstBoot.AppendLine("\t\t{"); - outputFirstBoot.Append("\t\t\tPlugin::"); - outputFirstBoot.Append(typeName); - outputFirstBoot.Append("FreeList[i] = ("); - AppendCppTypeFullName( - cppTypeTypeName, - outputFirstBoot); - AppendCppTypeParameters( - typeParams, - outputFirstBoot); - outputFirstBoot.Append("*)(Plugin::"); - outputFirstBoot.Append(typeName); - outputFirstBoot.AppendLine("FreeList + i + 1);"); - outputFirstBoot.AppendLine("\t\t}"); - - outputFirstBoot.Append("\t\tPlugin::"); - outputFirstBoot.Append(typeName); - outputFirstBoot.Append("FreeList[Plugin::"); - outputFirstBoot.Append(typeName); - outputFirstBoot.AppendLine("FreeListSize - 1] = nullptr;"); - - outputFirstBoot.Append("\t\tPlugin::NextFree"); - outputFirstBoot.Append(typeName); - outputFirstBoot.Append(" = Plugin::"); - outputFirstBoot.Append(typeName); - outputFirstBoot.AppendLine("FreeList + 1;"); - - outputFirstBoot.AppendLine("\t\t"); - } - - static void AppendCppPointerFreeListStateAndFunctions( - TypeName cppTypeTypeName, - Type[] typeParams, - string bindingTypeName, - StringBuilder output) - { - // Section comment - output.Append("\t// Free list for "); - AppendCppTypeFullName( - cppTypeTypeName, - output); - AppendCppTypeParameters( - typeParams, - output); - output.AppendLine(" pointers"); - output.AppendLine("\t"); - - // Size variable - output.Append("\tint32_t "); - output.Append(bindingTypeName); - output.AppendLine("FreeListSize;"); - - // Free list variable - output.Append('\t'); - AppendCppTypeFullName( - cppTypeTypeName, - output); - AppendCppTypeParameters( - typeParams, - output); - output.Append("** "); - output.Append(bindingTypeName); - output.AppendLine("FreeList;"); - - // Next free variable - output.Append('\t'); - AppendCppTypeFullName( - cppTypeTypeName, - output); - AppendCppTypeParameters( - typeParams, - output); - output.Append("** NextFree"); - output.Append(bindingTypeName); - output.AppendLine(";"); - output.AppendLine("\t"); - - // Store function - output.Append("\tint32_t Store"); - output.Append(bindingTypeName); - output.Append('('); - AppendCppTypeFullName( - cppTypeTypeName, - output); - AppendCppTypeParameters( - typeParams, - output); - output.AppendLine("* del)"); - output.AppendLine("\t{"); - output.Append("\t\tassert(NextFree"); - output.Append(bindingTypeName); - output.AppendLine(" != nullptr);"); - output.Append("\t\t"); - AppendCppTypeFullName( - cppTypeTypeName, - output); - AppendCppTypeParameters( - typeParams, - output); - output.Append("** pNext = NextFree"); - output.Append(bindingTypeName); - output.AppendLine(";"); - output.Append("\t\tNextFree"); - output.Append(bindingTypeName); - output.Append(" = ("); - AppendCppTypeFullName( - cppTypeTypeName, - output); - AppendCppTypeParameters( - typeParams, - output); - output.AppendLine("**)*pNext;"); - output.AppendLine("\t\t*pNext = del;"); - output.Append("\t\treturn (int32_t)(pNext - "); - output.Append(bindingTypeName); - output.AppendLine("FreeList);"); - output.AppendLine("\t}"); - output.AppendLine("\t"); - - // Get function - output.Append('\t'); - AppendCppTypeFullName( - cppTypeTypeName, - output); - AppendCppTypeParameters( - typeParams, - output); - output.Append("* Get"); - output.Append(bindingTypeName); - output.AppendLine("(int32_t handle)"); - output.AppendLine("\t{"); - output.Append( - "\t\tassert(handle >= 0 && handle < "); - output.Append(bindingTypeName); - output.AppendLine("FreeListSize);"); - output.Append("\t\treturn "); - output.Append(bindingTypeName); - output.AppendLine("FreeList[handle];"); - output.AppendLine("\t}"); - output.AppendLine("\t"); - - // Remove function - output.Append("\tvoid Remove"); - output.Append(bindingTypeName); - output.AppendLine("(int32_t handle)"); - output.AppendLine("\t{"); - output.Append("\t\t"); - AppendCppTypeFullName( - cppTypeTypeName, - output); - AppendCppTypeParameters( - typeParams, - output); - output.Append("** pRelease = "); - output.Append(bindingTypeName); - output.AppendLine("FreeList + handle;"); - output.Append("\t\t*pRelease = ("); - AppendCppTypeFullName( - cppTypeTypeName, - output); - AppendCppTypeParameters( - typeParams, - output); - output.Append("*)NextFree"); - output.Append(bindingTypeName); - output.AppendLine(";"); - output.Append("\t\tNextFree"); - output.Append(bindingTypeName); - output.AppendLine(" = pRelease;"); - output.AppendLine("\t}"); - output.AppendLine("\t"); - } - - static void AppendCppWholeObjectFreeListInit( - int maxSimultaneous, - string bindingTypeName, - StringBuilder output, - StringBuilder outputFirstBoot) - { - output.Append("\tPlugin::"); - output.Append(bindingTypeName); - output.Append("FreeWholeListSize = "); - output.Append(maxSimultaneous); - output.AppendLine(";"); - - output.Append("\tPlugin::"); - output.Append(bindingTypeName); - output.Append("FreeWholeList = (Plugin::"); - output.Append(bindingTypeName); - output.AppendLine("FreeWholeListEntry*)curMemory;"); - - output.Append("\tcurMemory += "); - output.Append(maxSimultaneous); - output.Append(" * sizeof(Plugin::"); - output.Append(bindingTypeName); - output.AppendLine("FreeWholeListEntry);"); - - output.AppendLine("\t"); - - outputFirstBoot.Append("\t\tfor (int32_t i = 0, end = Plugin::"); - outputFirstBoot.Append(bindingTypeName); - outputFirstBoot.AppendLine("FreeWholeListSize - 1; i < end; ++i)"); - outputFirstBoot.AppendLine("\t\t{"); - outputFirstBoot.Append("\t\t\tPlugin::"); - outputFirstBoot.Append(bindingTypeName); - outputFirstBoot.Append("FreeWholeList[i].Next = Plugin::"); - outputFirstBoot.Append(bindingTypeName); - outputFirstBoot.AppendLine("FreeWholeList + i + 1;"); - outputFirstBoot.AppendLine("\t\t}"); - - outputFirstBoot.Append("\t\tPlugin::"); - outputFirstBoot.Append(bindingTypeName); - outputFirstBoot.Append("FreeWholeList[Plugin::"); - outputFirstBoot.Append(bindingTypeName); - outputFirstBoot.AppendLine("FreeWholeListSize - 1].Next = nullptr;"); - - outputFirstBoot.Append("\t\tPlugin::NextFreeWhole"); - outputFirstBoot.Append(bindingTypeName); - outputFirstBoot.Append(" = Plugin::"); - outputFirstBoot.Append(bindingTypeName); - outputFirstBoot.AppendLine("FreeWholeList + 1;"); - - outputFirstBoot.AppendLine("\t\t"); - } - - static void AppendCppWholeObjectFreeListStateAndFunctions( - Type[] typeParams, - TypeName cppTypeTypeName, - string bindingTypeName, - StringBuilder output) - { - // Section comment - output.Append("\t// Free list for whole "); - AppendCppTypeFullName( - cppTypeTypeName, - output); - AppendCppTypeParameters( - typeParams, - output); - output.AppendLine(" objects"); - output.AppendLine("\t"); - - // Union with a pointer and a whole object - output.Append("\tunion "); - output.Append(bindingTypeName); - output.AppendLine("FreeWholeListEntry"); - output.AppendLine("\t{"); - output.Append("\t\t"); - output.Append(bindingTypeName); - output.AppendLine("FreeWholeListEntry* Next;"); - output.Append("\t\t"); - AppendCppTypeFullName( - cppTypeTypeName, - output); - AppendCppTypeParameters( - typeParams, - output); - output.AppendLine(" Value;"); - output.AppendLine("\t};"); - - // Size - output.Append("\tint32_t "); - output.Append(bindingTypeName); - output.AppendLine("FreeWholeListSize;"); - - // Free list entries - output.Append('\t'); - output.Append(bindingTypeName); - output.Append("FreeWholeListEntry* "); - output.Append(bindingTypeName); - output.AppendLine("FreeWholeList;"); - - // Pointer to next free entry - output.Append('\t'); - output.Append(bindingTypeName); - output.Append("FreeWholeListEntry* NextFreeWhole"); - output.Append(bindingTypeName); - output.AppendLine(";"); - output.AppendLine("\t"); - - // Store function - output.Append('\t'); - AppendCppTypeFullName( - cppTypeTypeName, - output); - AppendCppTypeParameters( - typeParams, - output); - output.Append("* StoreWhole"); - output.Append(bindingTypeName); - output.AppendLine("()"); - output.AppendLine("\t{"); - output.Append("\t\tassert(NextFreeWhole"); - output.Append(bindingTypeName); - output.AppendLine(" != nullptr);"); - output.Append("\t\t"); - output.Append(bindingTypeName); - output.Append("FreeWholeListEntry* pNext = NextFreeWhole"); - output.Append(bindingTypeName); - output.AppendLine(";"); - output.Append("\t\tNextFreeWhole"); - output.Append(bindingTypeName); - output.AppendLine(" = pNext->Next;"); - output.AppendLine("\t\treturn &pNext->Value;"); - output.AppendLine("\t}"); - output.AppendLine("\t"); - - // Remove function - output.Append("\tvoid RemoveWhole"); - output.Append(bindingTypeName); - output.Append('('); - AppendCppTypeFullName( - cppTypeTypeName, - output); - AppendCppTypeParameters( - typeParams, - output); - output.AppendLine("* instance)"); - output.AppendLine("\t{"); - output.Append("\t\t"); - output.Append(bindingTypeName); - output.Append("FreeWholeListEntry* pRelease = ("); - output.Append(bindingTypeName); - output.AppendLine("FreeWholeListEntry*)instance;"); - output.Append("\t\tif (pRelease >= "); - output.Append(bindingTypeName); - output.Append("FreeWholeList && pRelease < "); - output.Append(bindingTypeName); - output.Append("FreeWholeList + ("); - output.Append(bindingTypeName); - output.AppendLine("FreeWholeListSize - 1))"); - output.AppendLine("\t\t{"); - output.Append("\t\t\tpRelease->Next = NextFreeWhole"); - output.Append(bindingTypeName); - output.AppendLine(";"); - output.Append("\t\t\tNextFreeWhole"); - output.Append(bindingTypeName); - output.AppendLine(" = pRelease->Next;"); - output.AppendLine("\t\t}"); - output.AppendLine("\t}"); - output.AppendLine("\t"); - } - - static void AppendCsharpDelegate( - bool isStatic, - TypeName typeTypeName, - Type[] typeParams, - string funcName, - ParameterInfo[] parameters, - Type returnType, - TypeKind returnTypeKind, - StringBuilder output) - { - output.AppendLine("\t\t[UnmanagedFunctionPointer(CallingConvention.Cdecl)]"); - output.Append("\t\tpublic delegate "); - if (returnType == typeof(void)) - { - output.Append("void"); - } - else - { - switch (returnTypeKind) - { - case TypeKind.Class: - case TypeKind.ManagedStruct: - output.Append("int"); - break; - default: - AppendCsharpTypeFullName( - returnType, - output); - break; - } - } - output.Append(' '); - AppendCsharpDelegateName( - typeTypeName, - typeParams, - funcName, - output); - output.Append("DelegateType("); - if (!isStatic) - { - output.Append("int thisHandle"); - if (parameters.Length > 0) - { - output.Append(", "); - } - } - for (int i = 0; i < parameters.Length; ++i) - { - ParameterInfo param = parameters[i]; - switch (param.Kind) - { - case TypeKind.FullStruct: - case TypeKind.Primitive: - case TypeKind.Enum: - AppendCsharpTypeFullName( - param.ParameterType, - output); - output.Append(" param"); - output.Append(i); - break; - default: - output.Append("int param"); - output.Append(i); - break; - } - if (i != parameters.Length-1) - { - output.Append(", "); - } - } - output.AppendLine(");"); - output.Append("\t\tpublic static "); - AppendCsharpDelegateName( - typeTypeName, - typeParams, - funcName, - output); - output.Append("DelegateType "); - AppendCsharpDelegateName( - typeTypeName, - typeParams, - funcName, - output); - output.AppendLine(";"); - output.AppendLine("\t\t"); - } - - static void AppendCsharpDelegateName( - TypeName typeTypeName, - Type[] typeParams, - string funcName, - StringBuilder output) - { - AppendNamespace( - typeTypeName.Namespace, - string.Empty, - output); - AppendTypeNameWithoutSuffixes( - typeTypeName.Name, - output); - AppendTypeNames( - typeParams, - output); - output.Append(funcName); - } - - static void AppendCsharpGetDelegateCall( - TypeName typeTypeName, - Type[] typeParams, - string funcName, - StringBuilder output) - { - output.Append("\t\t\t"); - AppendCsharpDelegateName( - typeTypeName, - typeParams, - funcName, - output); - output.Append(" = GetDelegate<"); - AppendCsharpDelegateName( - typeTypeName, - typeParams, - funcName, - output); - output.Append("DelegateType>(libraryHandle, \""); - AppendCsharpDelegateName( - typeTypeName, - typeParams, - funcName, - output); - output.AppendLine("\");"); - } - - static void AppendCsharpImport( - TypeName typeTypeName, - Type[] typeParams, - string funcName, - ParameterInfo[] parameters, - Type returnType, - StringBuilder output - ) - { - output.AppendLine("\t\t[DllImport(PLUGIN_NAME, CallingConvention = CallingConvention.Cdecl)]"); - output.Append("\t\tpublic static extern "); - AppendCsharpTypeFullName(returnType, output); - output.Append(' '); - AppendCsharpDelegateName( - typeTypeName, - typeParams, - funcName, - output); - output.Append("(int thisHandle"); - if (parameters.Length > 0) - { - output.Append(", "); - } - for (int i = 0; i < parameters.Length; ++i) - { - ParameterInfo param = parameters[i]; - switch (param.Kind) - { - case TypeKind.FullStruct: - case TypeKind.Primitive: - case TypeKind.Enum: - AppendCsharpTypeFullName( - param.ParameterType, - output); - output.Append(" param"); - output.Append(i); - break; - default: - output.Append("int param"); - output.Append(i); - break; - } - if (i != parameters.Length-1) - { - output.Append(", "); - } - } - output.AppendLine(");"); - output.AppendLine("\t\t"); - } - - static void AppendExceptions( - JsonDocument doc, - Assembly[] assemblies, - StringBuilders builders) - { - // Gather all specific types of exceptions - Dictionary exceptionTypes = new Dictionary(); - if (doc.Types != null) - { - foreach (JsonType jsonType in doc.Types) - { - if (jsonType.Methods != null) - { - foreach (JsonMethod jsonMethod in jsonType.Methods) - { - if (jsonMethod.Exceptions != null) - { - AddUniqueTypes( - jsonMethod.Exceptions, - exceptionTypes, - assemblies); - } - } - } - if (jsonType.Constructors != null) - { - foreach (JsonConstructor jsonCtor in jsonType.Constructors) - { - if (jsonCtor.Exceptions != null) - { - AddUniqueTypes( - jsonCtor.Exceptions, - exceptionTypes, - assemblies); - } - } - } - if (jsonType.Properties != null) - { - foreach (JsonProperty jsonProperty in jsonType.Properties) - { - JsonPropertyGet jsonPropertyGet = jsonProperty.Get; - if (jsonPropertyGet != null - && jsonPropertyGet.Exceptions != null) - { - AddUniqueTypes( - jsonPropertyGet.Exceptions, - exceptionTypes, - assemblies); - } - JsonPropertySet jsonPropertySet = jsonProperty.Set; - if (jsonPropertySet != null - && jsonPropertySet.Exceptions != null) - { - AddUniqueTypes( - jsonPropertySet.Exceptions, - exceptionTypes, - assemblies); - } - } - } - } - } - - foreach (Type exceptionType in exceptionTypes.Values) - { - // Build function name - builders.TempStrBuilder.Length = 0; - AppendCsharpSetCsharpExceptionFunctionName( - exceptionType, - builders.TempStrBuilder); - string funcName = builders.TempStrBuilder.ToString(); - - // C++ thrower type - int throwerIndent = AppendNamespaceBeginning( - exceptionType.Namespace, - builders.CppMethodDefinitions); - AppendIndent( - throwerIndent, - builders.CppMethodDefinitions); - builders.CppMethodDefinitions.Append("struct "); - builders.CppMethodDefinitions.Append(exceptionType.Name); - builders.CppMethodDefinitions.Append("Thrower : "); - AppendCppTypeFullName( - exceptionType, - builders.CppMethodDefinitions); - builders.CppMethodDefinitions.AppendLine();; - AppendIndent( - throwerIndent, - builders.CppMethodDefinitions); - builders.CppMethodDefinitions.AppendLine("{"); - AppendIndent( - throwerIndent + 1, - builders.CppMethodDefinitions); - builders.CppMethodDefinitions.Append(exceptionType.Name); - builders.CppMethodDefinitions.AppendLine("Thrower(int32_t handle)"); - AppendIndent( - throwerIndent + 2, - builders.CppMethodDefinitions); - builders.CppMethodDefinitions.AppendLine(": System::Runtime::InteropServices::_Exception(nullptr)"); - AppendIndent( - throwerIndent + 2, - builders.CppMethodDefinitions); - builders.CppMethodDefinitions.AppendLine(", System::Runtime::Serialization::ISerializable(nullptr)"); - AppendIndent( - throwerIndent + 2, - builders.CppMethodDefinitions); - builders.CppMethodDefinitions.AppendLine(", System::Exception(nullptr)"); - AppendIndent( - throwerIndent + 2, - builders.CppMethodDefinitions); - builders.CppMethodDefinitions.AppendLine(", System::SystemException(nullptr)"); - AppendIndent( - throwerIndent + 2, - builders.CppMethodDefinitions); - builders.CppMethodDefinitions.Append(", "); - AppendCppTypeFullName( - exceptionType, - builders.CppMethodDefinitions); - builders.CppMethodDefinitions.AppendLine("(Plugin::InternalUse::Only, handle)"); - AppendIndent( - throwerIndent + 1, - builders.CppMethodDefinitions); - builders.CppMethodDefinitions.AppendLine("{"); - AppendIndent( - throwerIndent + 1, - builders.CppMethodDefinitions); - builders.CppMethodDefinitions.AppendLine("}"); - AppendIndent( - throwerIndent, - builders.CppMethodDefinitions); - builders.CppMethodDefinitions.AppendLine();; - AppendIndent( - throwerIndent + 1, - builders.CppMethodDefinitions); - builders.CppMethodDefinitions.AppendLine("virtual void ThrowReferenceToThis()"); - AppendIndent( - throwerIndent + 1, - builders.CppMethodDefinitions); - builders.CppMethodDefinitions.AppendLine("{"); - AppendIndent( - throwerIndent + 2, - builders.CppMethodDefinitions); - builders.CppMethodDefinitions.AppendLine("throw *this;"); - AppendIndent( - throwerIndent + 1, - builders.CppMethodDefinitions); - builders.CppMethodDefinitions.AppendLine("}"); - AppendIndent( - throwerIndent, - builders.CppMethodDefinitions); - builders.CppMethodDefinitions.AppendLine("};"); - AppendNamespaceEnding( - throwerIndent, - builders.CppMethodDefinitions); - builders.CppMethodDefinitions.AppendLine();; - - // C++ function - builders.CppMethodDefinitions.Append("DLLEXPORT void "); - builders.CppMethodDefinitions.Append(funcName); - builders.CppMethodDefinitions.AppendLine("(int32_t handle)"); - builders.CppMethodDefinitions.AppendLine("{"); - builders.CppMethodDefinitions.AppendLine("\tdelete Plugin::unhandledCsharpException;"); - builders.CppMethodDefinitions.Append("\tPlugin::unhandledCsharpException = new "); - AppendCppTypeFullName( - exceptionType, - builders.CppMethodDefinitions); - builders.CppMethodDefinitions.AppendLine("Thrower(handle);"); - builders.CppMethodDefinitions.AppendLine("}"); - builders.CppMethodDefinitions.AppendLine(); - - // Build parameters - ParameterInfo[] parameters = ConvertParameters( - new[]{ typeof(int) }); - - // C# imports - AppendCsharpImport( - GetTypeName(string.Empty, string.Empty), - null, - funcName, - ConvertParameters(Type.EmptyTypes), - typeof(void), - builders.CsharpImports); - - // C# delegate - AppendCsharpDelegate( - true, - GetTypeName(string.Empty, string.Empty), - null, - funcName, - parameters, - typeof(void), - TypeKind.None, - builders.CsharpCppDelegates - ); - - // C# GetDelegate call - AppendCsharpGetDelegateCall( - GetTypeName(string.Empty, string.Empty), - null, - funcName, - builders.CsharpGetDelegateCalls); - } - } - - static void AddUniqueTypes( - string[] typeNames, - Dictionary types, - Assembly[] assemblies) - { - foreach (string typeName in typeNames) - { - if (!types.ContainsKey(typeName)) - { - Type type = GetType( - typeName, - assemblies); - types.Add( - typeName, - type); - } - } - } - - static void AppendGetter( - string fieldName, - string syntaxType, - ParameterInfo[] parameters, - bool enclosingTypeIsStatic, - TypeKind enclosingTypeKind, - bool methodIsStatic, - bool isReadOnly, - Type enclosingType, - Type[] enclosingTypeParams, - Type fieldType, - TypeKind fieldTypeKind, - int indent, - Type[] exceptionTypes, - StringBuilders builders) - { - // Build uppercase field name - builders.TempStrBuilder.Length = 0; - builders.TempStrBuilder.Append(char.ToUpper(fieldName[0])); - builders.TempStrBuilder.Append( - fieldName, - 1, - fieldName.Length-1); - string fieldNameUpper = builders.TempStrBuilder.ToString(); - - // Build uppercase function name - builders.TempStrBuilder.Length = 0; - AppendFieldPropertyFuncName( - GetTypeName(enclosingType), - enclosingTypeParams, - syntaxType, - "Get", - fieldName, - builders.TempStrBuilder); - string funcName = builders.TempStrBuilder.ToString(); - - // Build method name - builders.TempStrBuilder.Length = 0; - builders.TempStrBuilder.Append("Get"); - builders.TempStrBuilder.Append(fieldNameUpper); - string methodName = builders.TempStrBuilder.ToString(); - - // C# init param declaration - - // C# delegate type - AppendCsharpDelegateType( - funcName, - methodIsStatic, - enclosingType, - enclosingTypeKind, - fieldType, - parameters, - builders.CsharpDelegateTypes); - - // C# init call param - AppendCsharpCsharpDelegate( - funcName, - builders.CsharpInitCall, - builders.CsharpCsharpDelegates); - - // C# function - AppendCsharpFunctionBeginning( - enclosingType, - funcName, - methodIsStatic, - enclosingTypeKind, - fieldType, - parameters, - builders.CsharpFunctions); - AppendCsharpFunctionCallSubject( - enclosingType, - methodIsStatic, - builders.CsharpFunctions); - if (parameters.Length > 0) - { - builders.CsharpFunctions.Append('['); - for (int i = 0; i < parameters.Length; ++i) - { - builders.CsharpFunctions.Append(parameters[0].Name); - if (i != parameters.Length-1) - { - builders.CsharpFunctions.Append(", "); - } - } - builders.CsharpFunctions.Append("]"); - } - else - { - builders.CsharpFunctions.Append('.'); - builders.CsharpFunctions.Append(fieldName); - } - builders.CsharpFunctions.Append(';'); - if (!isReadOnly - && !methodIsStatic - && enclosingTypeKind == TypeKind.ManagedStruct) - { - AppendStructStoreReplace( - enclosingType, - "thisHandle", - "thiz", - builders.CsharpFunctions); - } - AppendCsharpFunctionReturn( - parameters, - fieldType, - fieldTypeKind, - exceptionTypes, - false, - builders.CsharpFunctions); - - // C++ function pointer - AppendCppFunctionPointerDefinition( - funcName, - methodIsStatic, - GetTypeName(enclosingType), - enclosingTypeKind, - parameters, - fieldType, - builders.CppFunctionPointers); - - // C++ method declaration - AppendIndent(indent + 1, builders.CppTypeDefinitions); - AppendCppMethodDeclaration( - methodName, - enclosingTypeIsStatic, - false, - methodIsStatic, - fieldType, - null, - parameters, - builders.CppTypeDefinitions); - - // C++ method definition - AppendCppMethodDefinitionBegin( - GetTypeName(enclosingType), - fieldType, - methodName, - enclosingTypeParams, - null, - parameters, - indent, - builders.CppMethodDefinitions); - AppendIndent(indent, builders.CppMethodDefinitions); - builders.CppMethodDefinitions.AppendLine("{"); - AppendCppPluginFunctionCall( - methodIsStatic, - GetTypeName(enclosingType), - enclosingTypeKind, - enclosingTypeParams, - fieldType, - funcName, - parameters, - indent + 1, - builders.CppMethodDefinitions); - AppendCppMethodReturn( - fieldType, - fieldTypeKind, - indent + 1, - builders.CppMethodDefinitions); - AppendIndent(indent, builders.CppMethodDefinitions); - builders.CppMethodDefinitions.AppendLine("}"); - AppendIndent(indent, builders.CppMethodDefinitions); - builders.CppMethodDefinitions.AppendLine();; - - // C++ init body - AppendCppInitBodyFunctionPointerParameterRead( - funcName, - methodIsStatic, - GetTypeName(enclosingType), - enclosingTypeKind, - parameters, - fieldType, - builders.CppInitBodyParameterReads); - } - - static void AppendSetter( - string fieldName, - string syntaxType, - ParameterInfo[] parameters, - bool enclosingTypeIsStatic, - TypeKind enclosingTypeKind, - bool methodIsStatic, - bool isReadOnly, - Type enclosingType, - Type[] enclosingTypeParams, - int indent, - Type[] exceptionTypes, - StringBuilders builders) - { - TypeName enclosingTypeTypeName = GetTypeName(enclosingType); - - // Build uppercased field name - builders.TempStrBuilder.Length = 0; - builders.TempStrBuilder.Append(char.ToUpper(fieldName[0])); - builders.TempStrBuilder.Append( - fieldName, - 1, - fieldName.Length-1); - string fieldNameUpper = builders.TempStrBuilder.ToString(); - - // Build uppercase function name - builders.TempStrBuilder.Length = 0; - AppendFieldPropertyFuncName( - enclosingTypeTypeName, - enclosingTypeParams, - syntaxType, - "Set", - fieldName, - builders.TempStrBuilder); - string funcName = builders.TempStrBuilder.ToString(); - - // Build method name - builders.TempStrBuilder.Length = 0; - builders.TempStrBuilder.Append("Set"); - builders.TempStrBuilder.Append(fieldNameUpper); - string methodName = builders.TempStrBuilder.ToString(); - - // C# init param declaration - - // C# delegate type - AppendCsharpDelegateType( - funcName, - methodIsStatic, - enclosingType, - enclosingTypeKind, - typeof(void), - parameters, - builders.CsharpDelegateTypes); - - // C# init call param - AppendCsharpCsharpDelegate( - funcName, - builders.CsharpInitCall, - builders.CsharpCsharpDelegates); - - // C# function - AppendCsharpFunctionBeginning( - enclosingType, - funcName, - methodIsStatic, - enclosingTypeKind, - typeof(void), - parameters, - builders.CsharpFunctions); - AppendCsharpFunctionCallSubject( - enclosingType, - methodIsStatic, - builders.CsharpFunctions); - if (parameters.Length > 1) - { - builders.CsharpFunctions.Append('['); - for (int i = 0, end = parameters.Length-1; i < end; ++i) - { - builders.CsharpFunctions.Append(parameters[i].Name); - if (i != end-1) - { - builders.CsharpFunctions.Append(", "); - } - } - builders.CsharpFunctions.Append("] = "); - builders.CsharpFunctions.Append(parameters[1].Name); - } - else - { - builders.CsharpFunctions.Append('.'); - builders.CsharpFunctions.Append(fieldName); - builders.CsharpFunctions.Append(" = "); - builders.CsharpFunctions.Append("value"); - } - builders.CsharpFunctions.Append(';'); - if (!isReadOnly - && !methodIsStatic - && enclosingTypeKind == TypeKind.ManagedStruct) - { - AppendStructStoreReplace( - enclosingType, - "thisHandle", - "thiz", - builders.CsharpFunctions); - } - AppendCsharpFunctionReturn( - parameters, - typeof(void), - TypeKind.None, - exceptionTypes, - false, - builders.CsharpFunctions); - - // C++ function pointer - AppendCppFunctionPointerDefinition( - funcName, - methodIsStatic, - enclosingTypeTypeName, - enclosingTypeKind, - parameters, - typeof(void), - builders.CppFunctionPointers); - - // C++ method declaration - AppendIndent(indent + 1, builders.CppTypeDefinitions); - AppendCppMethodDeclaration( - methodName, - enclosingTypeIsStatic, - false, - methodIsStatic, - typeof(void), - null, - parameters, - builders.CppTypeDefinitions); - - // C++ method definition - AppendCppMethodDefinitionBegin( - GetTypeName(enclosingType), - typeof(void), - methodName, - enclosingTypeParams, - null, - parameters, - indent, - builders.CppMethodDefinitions); - AppendIndent(indent, builders.CppMethodDefinitions); - builders.CppMethodDefinitions.AppendLine("{"); - AppendCppPluginFunctionCall( - methodIsStatic, - enclosingTypeTypeName, - enclosingTypeKind, - enclosingTypeParams, - null, - funcName, - parameters, - indent + 1, - builders.CppMethodDefinitions); - AppendIndent(indent, builders.CppMethodDefinitions); - builders.CppMethodDefinitions.AppendLine("}"); - AppendIndent(indent, builders.CppMethodDefinitions); - builders.CppMethodDefinitions.AppendLine();; - - // C++ init body - AppendCppInitBodyFunctionPointerParameterRead( - funcName, - methodIsStatic, - enclosingTypeTypeName, - enclosingTypeKind, - parameters, - typeof(void), - builders.CppInitBodyParameterReads); - } - - static void AppendFieldPropertyFuncName( - TypeName enclosingTypeTypeName, - Type[] enclosingTypeParams, - string syntaxType, - string operationType, - string fieldName, - StringBuilder output) - { - AppendNamespace( - enclosingTypeTypeName.Namespace, - string.Empty, - output); - AppendTypeNameWithoutGenericSuffix( - enclosingTypeTypeName.Name, - output); - AppendTypeNames( - enclosingTypeParams, - output); - output.Append(syntaxType); - output.Append(operationType); - output.Append(char.ToUpper(fieldName[0])); - output.Append(fieldName, 1, fieldName.Length-1); - } - - static void AppendCppTemplateDeclaration( - TypeName typeTypeName, - StringBuilder output) - { - int indent = AppendNamespaceBeginning( - typeTypeName.Namespace, - output); - AppendIndent( - indent, - output); - AppendCppTemplateTypenames( - typeTypeName.NumTypeParams, - 'T', - output); - output.Append("struct "); - AppendCppTypeName( - typeTypeName, - output); - output.Append(";"); - output.AppendLine();; - AppendNamespaceEnding( - indent, - output); - output.AppendLine();; - } - - static int AppendCppTypeDeclaration( - TypeName typeTypeName, - bool isStatic, - Type[] typeParams, - StringBuilder output) - { - int indent = AppendNamespaceBeginning( - typeTypeName.Namespace, - output); - AppendIndent(indent, output); - if (isStatic) - { - output.Append("namespace "); - AppendTypeNameWithoutGenericSuffix( - typeTypeName.Name, - output); - output.AppendLine();; - AppendIndent(indent, output); - output.AppendLine("{"); - AppendIndent(indent, output); - output.Append('}'); - } - else - { - if (typeParams != null) - { - output.Append("template<> "); - } - output.Append("struct "); - AppendCppTypeName( - typeTypeName, - output); - AppendCppTypeParameters( - typeParams, - output); - output.Append(";"); - } - output.AppendLine();; - AppendNamespaceEnding( - indent, - output); - output.AppendLine();; - return indent; - } - - static void AppendCppTypeDefinitionBegin( - TypeName typeTypeName, - TypeKind typeKind, - Type[] typeParams, - TypeName baseTypeTypeName, - Type[] baseTypeTypeParams, - Type[] interfaceTypes, - bool isStatic, - int indent, - StringBuilder output) - { - AppendNamespaceBeginning( - typeTypeName.Namespace, - output); - AppendIndent( - indent, - output); - if (isStatic) - { - output.Append("namespace "); - AppendTypeNameWithoutGenericSuffix( - typeTypeName.Name, - output); - } - else - { - if (typeParams != null) - { - output.Append("template<> "); - } - output.Append("struct "); - AppendCppTypeName( - typeTypeName, - output); - AppendCppTypeParameters(typeParams, output); - switch (typeKind) - { - case TypeKind.Class: - // Only add the base type if it's not System.Object or - // there are no interfaces (since they always extend it) - string separator = " : virtual "; - if ( - (baseTypeTypeName.Name != null && - (baseTypeTypeName.Namespace != "System" || - baseTypeTypeName.Name != "Object")) || - (interfaceTypes == null || - interfaceTypes.Length == 0)) - { - output.Append(separator); - separator = ", virtual "; - AppendCppTypeFullName( - GetTypeName( - baseTypeTypeName.Name ?? "Object", - baseTypeTypeName.Namespace ?? "System", - baseTypeTypeParams != null ? baseTypeTypeParams.Length : 0), - output); - AppendCppTypeParameters( - baseTypeTypeParams, - output); - } - if (interfaceTypes != null) - { - foreach (Type interfaceType in interfaceTypes) - { - output.Append(separator); - separator = ", virtual "; - AppendCppTypeFullName( - GetTypeName(interfaceType), - output); - AppendCppTypeParameters( - interfaceType.GetGenericArguments(), - output); - } - } - break; - case TypeKind.ManagedStruct: - output.Append(" : Plugin::ManagedType"); - break; - } - } - output.AppendLine();; - AppendIndent( - indent, - output); - output.AppendLine("{"); - if (!isStatic) - { - switch (typeKind) - { - case TypeKind.Class: - case TypeKind.ManagedStruct: - // Constructor from nullptr - AppendIndent(indent + 1, output); - AppendCppTypeName( - typeTypeName, - output); - output.AppendLine("(decltype(nullptr));"); - - // Constructor from handle - AppendIndent(indent + 1, output); - AppendCppTypeName( - typeTypeName, - output); - output.AppendLine( - "(Plugin::InternalUse, int32_t handle);"); - - // Copy constructor - AppendIndent(indent + 1, output); - AppendCppTypeName( - typeTypeName, - output); - output.Append("(const "); - AppendCppTypeName( - typeTypeName, - output); - AppendCppTypeParameters( - typeParams, - output); - output.AppendLine("& other);"); - - // Move constructor - AppendIndent(indent + 1, output); - AppendCppTypeName( - typeTypeName, - output); - output.Append('('); - AppendCppTypeName( - typeTypeName, - output); - AppendCppTypeParameters( - typeParams, - output); - output.AppendLine("&& other);"); - - // Destructor - AppendIndent(indent + 1, output); - output.Append("virtual ~"); - AppendCppTypeName( - typeTypeName, - output); - output.AppendLine("();"); - - // Assignment operator to same type - AppendIndent(indent + 1, output); - AppendCppTypeName( - typeTypeName, - output); - AppendCppTypeParameters( - typeParams, - output); - output.Append("& operator=(const "); - AppendCppTypeName( - typeTypeName, - output); - AppendCppTypeParameters( - typeParams, - output); - output.AppendLine("& other);"); - - // Assignment operator to nullptr - AppendIndent(indent + 1, output); - AppendCppTypeName( - typeTypeName, - output); - AppendCppTypeParameters( - typeParams, - output); - output.AppendLine("& operator=(decltype(nullptr));"); - - // Move assignment operator to same type - AppendIndent(indent + 1, output); - AppendCppTypeName( - typeTypeName, - output); - AppendCppTypeParameters( - typeParams, - output); - output.Append("& operator=("); - AppendCppTypeName( - typeTypeName, - output); - AppendCppTypeParameters( - typeParams, - output); - output.AppendLine("&& other);"); - - // Equality operator with same type - AppendIndent(indent + 1, output); - output.Append("bool operator==(const "); - AppendCppTypeName( - typeTypeName, - output); - AppendCppTypeParameters( - typeParams, - output); - output.AppendLine("& other) const;"); - - // Inequality operator with same type - AppendIndent(indent + 1, output); - output.Append("bool operator!=(const "); - AppendCppTypeName( - typeTypeName, - output); - AppendCppTypeParameters( - typeParams, - output); - output.AppendLine("& other) const;"); - break; - } - } - } - - static void AppendCppTypeDefinitionEnd( - bool isStatic, - int indent, - StringBuilder output) - { - AppendIndent( - indent, - output); - output.Append('}'); - if (!isStatic) - { - output.Append(';'); - } - output.AppendLine();; - AppendNamespaceEnding( - indent, - output); - output.AppendLine();; - } - - static int AppendCppMethodDefinitionsBegin( - TypeName enclosingTypeTypeName, - TypeKind enclosingTypeKind, - Type[] enclosingTypeParams, - Type[] interfaceTypes, - bool isStatic, - Action extraDefault, - Action extraCopy, - int indent, - StringBuilder output) - { - int cppMethodDefinitionsIndent = AppendNamespaceBeginning( - enclosingTypeTypeName.Namespace, - output); - if (!isStatic && ( - enclosingTypeKind == TypeKind.Class - || enclosingTypeKind == TypeKind.ManagedStruct)) - { - // Construct with nullptr - AppendIndent(indent, output); - AppendCppTypeName( - enclosingTypeTypeName, - output); - AppendCppTypeParameters( - enclosingTypeParams, - output); - output.Append("::"); - AppendCppTypeName( - enclosingTypeTypeName, - output); - output.AppendLine("(decltype(nullptr))"); - if (enclosingTypeKind == TypeKind.Class) - { - AppendCppConstructorInitializerList( - interfaceTypes, - indent + 1, - output); - } - AppendIndent(indent, output); - output.AppendLine("{"); - extraDefault(indent + 1, "this->"); - AppendIndent(indent, output); - output.AppendLine("}"); - AppendIndent(indent, output); - output.AppendLine();; - - // Handle constructor - AppendIndent(indent, output); - AppendCppTypeName( - enclosingTypeTypeName, - output); - AppendCppTypeParameters( - enclosingTypeParams, - output); - output.Append("::"); - AppendCppTypeName( - enclosingTypeTypeName, - output); - output.AppendLine("(Plugin::InternalUse, int32_t handle)"); - if (enclosingTypeKind == TypeKind.Class) - { - AppendCppConstructorInitializerList( - interfaceTypes, - indent + 1, - output); - } - AppendIndent(indent, output); - output.AppendLine("{"); - AppendIndent(indent + 1, output); - output.AppendLine("Handle = handle;"); - AppendIndent(indent + 1, output); - output.AppendLine("if (handle)"); - AppendIndent(indent + 1, output); - output.AppendLine("{"); - AppendIndent(indent + 2, output); - AppendReferenceManagedHandleFunctionCall( - enclosingTypeTypeName, - enclosingTypeKind, - enclosingTypeParams, - "handle", - output); - output.AppendLine(";"); - AppendIndent(indent + 1, output); - output.AppendLine("}"); - extraDefault(indent + 1, "this->"); - AppendIndent(indent, output); - output.AppendLine("}"); - AppendIndent(indent, output); - output.AppendLine();; - - // Copy constructor - AppendIndent(indent, output); - AppendCppTypeName( - enclosingTypeTypeName, - output); - AppendCppTypeParameters( - enclosingTypeParams, - output); - output.Append("::"); - AppendCppTypeName( - enclosingTypeTypeName, - output); - output.Append("(const "); - AppendCppTypeName( - enclosingTypeTypeName, - output); - AppendCppTypeParameters( - enclosingTypeParams, - output); - output.AppendLine("& other)"); - AppendIndent(indent + 1, output); - output.Append(": "); - AppendCppTypeName( - enclosingTypeTypeName, - output); - output.AppendLine("(Plugin::InternalUse::Only, other.Handle)"); - AppendIndent(indent, output); - output.AppendLine("{"); - extraCopy(indent + 1, "other."); - AppendIndent(indent, output); - output.AppendLine("}"); - AppendIndent(indent, output); - output.AppendLine();; - - // Move constructor - AppendIndent(indent, output); - AppendCppTypeName( - enclosingTypeTypeName, - output); - AppendCppTypeParameters( - enclosingTypeParams, - output); - output.Append("::"); - AppendCppTypeName( - enclosingTypeTypeName, - output); - output.Append("("); - AppendCppTypeName( - enclosingTypeTypeName, - output); - AppendCppTypeParameters( - enclosingTypeParams, - output); - output.AppendLine("&& other)"); - AppendIndent(indent, output); - output.Append("\t: "); - AppendCppTypeName( - enclosingTypeTypeName, - output); - output.AppendLine("(Plugin::InternalUse::Only, other.Handle)"); - AppendIndent(indent, output); - output.AppendLine("{"); - AppendIndent(indent + 1, output); - output.AppendLine("other.Handle = 0;"); - extraCopy(indent + 1, "other."); - extraDefault(indent + 1, "other."); - AppendIndent(indent, output); - output.AppendLine("}"); - AppendIndent(indent, output); - output.AppendLine();; - - // Destructor - AppendIndent(indent, output); - AppendCppTypeName( - enclosingTypeTypeName, - output); - AppendCppTypeParameters( - enclosingTypeParams, - output); - output.Append("::~"); - AppendCppTypeName( - enclosingTypeTypeName, - output); - AppendCppTypeParameters( - enclosingTypeParams, - output); - output.AppendLine("()"); - AppendIndent(indent, output); - output.AppendLine("{"); - AppendIndent(indent + 1, output); - output.AppendLine("if (Handle)"); - AppendIndent(indent + 1, output); - output.AppendLine("{"); - AppendIndent(indent + 2, output); - AppendDereferenceManagedHandleFunctionCall( - enclosingTypeTypeName, - enclosingTypeKind, - enclosingTypeParams, - "Handle", - output); - output.AppendLine(";"); - AppendIndent(indent + 2, output); - output.AppendLine("Handle = 0;"); - AppendIndent(indent + 1, output); - output.AppendLine("}"); - AppendIndent(indent, output); - output.AppendLine("}"); - AppendIndent(indent, output); - output.AppendLine();; - - // Assignment operator to same type - AppendIndent(indent, output); - AppendCppTypeName( - enclosingTypeTypeName, - output); - AppendCppTypeParameters( - enclosingTypeParams, - output); - output.Append("& "); - AppendCppTypeName( - enclosingTypeTypeName, - output); - AppendCppTypeParameters( - enclosingTypeParams, - output); - output.Append("::operator=(const "); - AppendCppTypeName( - enclosingTypeTypeName, - output); - AppendCppTypeParameters( - enclosingTypeParams, - output); - output.AppendLine("& other)"); - AppendIndent(indent, output); - output.AppendLine("{"); - AppendSetHandle( - enclosingTypeTypeName, - enclosingTypeKind, - enclosingTypeParams, - indent + 1, - "this", - "other.Handle", - output); - extraCopy(indent + 1, "other."); - AppendIndent(indent + 1, output); - output.AppendLine("return *this;"); - AppendIndent(indent, output); - output.AppendLine("}"); - AppendIndent(indent, output); - output.AppendLine();; - - // Assignment operator to nullptr - AppendIndent(indent, output); - AppendCppTypeName( - enclosingTypeTypeName, - output); - AppendCppTypeParameters( - enclosingTypeParams, - output); - output.Append("& "); - AppendCppTypeName( - enclosingTypeTypeName, - output); - AppendCppTypeParameters( - enclosingTypeParams, - output); - output.AppendLine("::operator=(decltype(nullptr))"); - AppendIndent(indent, output); - output.AppendLine("{"); - AppendIndent(indent + 1, output); - output.AppendLine("if (Handle)"); - AppendIndent(indent + 1, output); - output.AppendLine("{"); - AppendIndent(indent + 2, output); - AppendDereferenceManagedHandleFunctionCall( - enclosingTypeTypeName, - enclosingTypeKind, - enclosingTypeParams, - "Handle", - output); - output.AppendLine(";"); - AppendIndent(indent + 2, output); - output.AppendLine("Handle = 0;"); - AppendIndent(indent + 1, output); - output.AppendLine("}"); - AppendIndent(indent + 1, output); - output.AppendLine("return *this;"); - AppendIndent(indent, output); - output.AppendLine("}"); - AppendIndent(indent, output); - output.AppendLine();; - - // Move assignment operator to same type - AppendIndent(indent, output); - AppendCppTypeName( - enclosingTypeTypeName, - output); - AppendCppTypeParameters( - enclosingTypeParams, - output); - output.Append("& "); - AppendCppTypeName( - enclosingTypeTypeName, - output); - AppendCppTypeParameters( - enclosingTypeParams, - output); - output.Append("::operator=("); - AppendCppTypeName( - enclosingTypeTypeName, - output); - AppendCppTypeParameters( - enclosingTypeParams, - output); - output.AppendLine("&& other)"); - AppendIndent(indent, output); - output.AppendLine("{"); - AppendIndent(indent + 1, output); - output.AppendLine("if (Handle)"); - AppendIndent(indent + 1, output); - output.AppendLine("{"); - AppendIndent(indent + 2, output); - AppendDereferenceManagedHandleFunctionCall( - enclosingTypeTypeName, - enclosingTypeKind, - enclosingTypeParams, - "Handle", - output); - output.AppendLine(";"); - AppendIndent(indent + 1, output); - output.AppendLine("}"); - AppendIndent(indent + 1, output); - output.AppendLine("Handle = other.Handle;"); - extraCopy(indent + 1, "other."); - AppendIndent(indent + 1, output); - output.AppendLine("other.Handle = 0;"); - extraDefault(indent + 1, "other."); - AppendIndent(indent + 1, output); - output.AppendLine("return *this;"); - AppendIndent(indent, output); - output.AppendLine("}"); - AppendIndent(indent, output); - output.AppendLine();; - - // Equality operator with same type - AppendIndent(indent, output); - output.Append("bool "); - AppendCppTypeName( - enclosingTypeTypeName, - output); - AppendCppTypeParameters( - enclosingTypeParams, - output); - output.Append("::operator==(const "); - AppendCppTypeName( - enclosingTypeTypeName, - output); - AppendCppTypeParameters( - enclosingTypeParams, - output); - output.AppendLine("& other) const"); - AppendIndent(indent, output); - output.AppendLine("{"); - AppendIndent(indent + 1, output); - output.AppendLine("return Handle == other.Handle;"); - AppendIndent(indent, output); - output.AppendLine("}"); - AppendIndent(indent, output); - output.AppendLine();; - - // Inequality operator with same type - AppendIndent(indent, output); - output.Append("bool "); - AppendCppTypeName( - enclosingTypeTypeName, - output); - AppendCppTypeParameters( - enclosingTypeParams, - output); - output.Append("::operator!=(const "); - AppendCppTypeName( - enclosingTypeTypeName, - output); - AppendCppTypeParameters( - enclosingTypeParams, - output); - output.AppendLine("& other) const"); - AppendIndent(indent, output); - output.AppendLine("{"); - AppendIndent(indent + 1, output); - output.AppendLine("return Handle != other.Handle;"); - AppendIndent(indent, output); - output.AppendLine("}"); - AppendIndent(indent, output); - output.AppendLine();; - } - return cppMethodDefinitionsIndent; - } - - static void AppendSetHandle( - TypeName enclosingTypeTypeName, - TypeKind enclosingTypeKind, - Type[] enclosingTypeParams, - int indent, - string thisExpression, - string otherHandleExpression, - StringBuilder output) - { - string thisHandleExpression = thisExpression + "->Handle"; - AppendIndent(indent, output); - output.Append("if ("); - output.Append(thisHandleExpression); - output.AppendLine(")"); - AppendIndent(indent, output); - output.AppendLine("{"); - AppendIndent(indent + 1, output); - AppendDereferenceManagedHandleFunctionCall( - enclosingTypeTypeName, - enclosingTypeKind, - enclosingTypeParams, - thisHandleExpression, - output); - output.AppendLine(";"); - AppendIndent(indent, output); - output.AppendLine("}"); - AppendIndent(indent, output); - output.Append(thisHandleExpression); - output.Append(" = "); - output.Append(otherHandleExpression); - output.AppendLine(";"); - AppendIndent(indent, output); - output.Append("if ("); - output.Append(thisHandleExpression); - output.AppendLine(")"); - AppendIndent(indent, output); - output.AppendLine("{"); - AppendIndent(indent + 1, output); - AppendReferenceManagedHandleFunctionCall( - enclosingTypeTypeName, - enclosingTypeKind, - enclosingTypeParams, - thisHandleExpression, - output); - output.AppendLine(";"); - AppendIndent(indent, output); - output.AppendLine("}"); - } - - static void AppendReferenceManagedHandleFunctionCall( - TypeName enclosingTypeTypeName, - TypeKind enclosingTypeKind, - Type[] enclosingTypeParams, - string handleVariable, - StringBuilder output) - { - if (enclosingTypeKind == TypeKind.ManagedStruct) - { - output.Append("Plugin::ReferenceManaged"); - AppendReleaseFunctionNameSuffix( - enclosingTypeTypeName, - enclosingTypeParams, - output); - output.Append("(Handle)"); - } - else - { - output.Append("Plugin::ReferenceManagedClass("); - output.Append(handleVariable); - output.Append(")"); - } - } - - static void AppendDereferenceManagedHandleFunctionCall( - TypeName enclosingTypeTypeName, - TypeKind enclosingTypeKind, - Type[] enclosingTypeParams, - string handleVariable, - StringBuilder output) - { - if (enclosingTypeKind == TypeKind.ManagedStruct) - { - output.Append("Plugin::DereferenceManaged"); - AppendReleaseFunctionNameSuffix( - enclosingTypeTypeName, - enclosingTypeParams, - output); - output.Append("(Handle)"); - } - else - { - output.Append("Plugin::DereferenceManagedClass("); - output.Append(handleVariable); - output.Append(")"); - } - } - - static void AppendCppMethodDefinitionsEnd( - int indent, - StringBuilder output) - { - RemoveTrailingChars(output); - output.AppendLine();; - AppendNamespaceEnding( - indent, - output); - output.AppendLine();; - } - - static int AppendNamespaceBeginning( - string namespaceName, - StringBuilder output) - { - int startIndex = 0; - int indent = 0; - do - { - int separatorIndex = namespaceName.IndexOf( - '.', - startIndex); - int endIndex = separatorIndex < 0 - ? namespaceName.Length - 1 - : separatorIndex - 1; - int len = 1 + endIndex - startIndex; - AppendIndent(indent, output); - output.Append("namespace "); - output.Append(namespaceName, startIndex, len); - output.AppendLine();; - AppendIndent(indent, output); - output.AppendLine("{"); - if (separatorIndex < 0) - { - break; - } - startIndex = separatorIndex + 1; - indent++; - } - while (true); - return indent + 1; - } - - static void AppendNamespaceEnding( - int indent, - StringBuilder output) - { - indent--; - for (; indent >= 0; --indent) - { - AppendIndent(indent, output); - output.AppendLine("}"); - } - } - - static void AppendIndent( - int indent, - StringBuilder output) - { - output.Append('\t', indent); - } - - static void AppendCsharpCsharpDelegate( - string funcName, - StringBuilder initCallOutput, - StringBuilder delegateOutput) - { - initCallOutput.Append( - "\t\t\tMarshal.WriteIntPtr(memory, curMemory, Marshal.GetFunctionPointerForDelegate("); - initCallOutput.Append(funcName); - initCallOutput.Append("Delegate"); - initCallOutput.AppendLine("));"); - initCallOutput.AppendLine("\t\t\tcurMemory += IntPtr.Size;"); - - delegateOutput.Append("\t\tstatic readonly "); - delegateOutput.Append(funcName); - delegateOutput.Append("DelegateType "); - delegateOutput.Append(funcName); - delegateOutput.Append("Delegate = new "); - delegateOutput.Append(funcName); - delegateOutput.Append("DelegateType("); - delegateOutput.Append(funcName); - delegateOutput.AppendLine(");"); - } - - static void AppendCsharpDelegateType( - string funcName, - bool isStatic, - Type enclosingType, - TypeKind enclosingTypeKind, - Type returnType, - ParameterInfo[] parameters, - StringBuilder output) - { - output.AppendLine("\t\t[UnmanagedFunctionPointer(CallingConvention.Cdecl)]"); - output.Append("\t\tdelegate "); - - // Return type - if (IsFullValueType(returnType)) - { - AppendCsharpTypeFullName( - returnType, - output); - } - else - { - output.Append("int"); - } - - output.Append(' '); - output.Append(funcName); - output.Append("DelegateType("); - if (!isStatic) - { - if (enclosingTypeKind == TypeKind.FullStruct) - { - output.Append("ref "); - AppendCsharpTypeFullName( - enclosingType, - output); - output.Append(" thiz"); - } - else - { - output.Append("int thisHandle"); - } - if (parameters.Length > 0) - { - output.Append(", "); - } - } - AppendCsharpBindingParameterDeclaration( - parameters, - output); - output.AppendLine(");"); - } - - static void AppendCsharpFunctionBeginning( - Type enclosingType, - string funcName, - bool isStatic, - TypeKind enclosingTypeKind, - Type returnType, - ParameterInfo[] parameters, - StringBuilder output) - { - output.Append("\t\t[MonoPInvokeCallback(typeof("); - output.Append(funcName); - output.AppendLine("DelegateType))]"); - output.Append("\t\tstatic "); - - // Return type - if (returnType != null) - { - if (IsFullValueType(returnType)) - { - AppendCsharpTypeFullName( - returnType, - output); - } - else - { - output.Append("int"); - } - output.Append(' '); - } - - // Function name - output.Append(funcName); - - // Parameters - output.Append("("); - if (!isStatic) - { - if (enclosingTypeKind == TypeKind.FullStruct) - { - output.Append("ref "); - AppendCsharpTypeFullName( - enclosingType, - output); - output.Append(" thiz"); - } - else - { - output.Append("int thisHandle"); - } - if (parameters.Length > 0) - { - output.Append(", "); - } - } - AppendCsharpBindingParameterDeclaration( - parameters, - output); - output.AppendLine(")"); - output.AppendLine("\t\t{"); - output.Append("\t\t\t"); - - // Start try/catch block - output.AppendLine("try"); - output.AppendLine("\t\t\t{"); - output.Append("\t\t\t\t"); - - // Get "this" - if (!isStatic - && enclosingTypeKind != TypeKind.FullStruct) - { - output.Append("var thiz = ("); - AppendCsharpTypeFullName( - enclosingType, - output); - output.Append(')'); - AppendHandleStoreTypeName( - enclosingType, - output); - output.AppendLine( - ".Get(thisHandle);"); - output.Append( - "\t\t\t\t"); - } - - // Get managed type params from ObjectStore - foreach (ParameterInfo param in parameters) - { - Type paramType = param.DereferencedParameterType; - if (param.Kind == TypeKind.Class - || param.Kind == TypeKind.ManagedStruct) - { - output.Append("var "); - output.Append(param.Name); - output.Append(" = "); - if (paramType != typeof(object)) - { - output.Append('('); - AppendCsharpTypeFullName(paramType, output); - output.Append(')'); - } - AppendHandleStoreTypeName(paramType, output); - output.Append(".Get("); - output.Append(param.Name); - output.AppendLine("Handle);"); - output.Append("\t\t\t\t"); - } - } - - // Save return value as local variable - if (returnType != typeof(void)) - { - output.Append("var returnValue = "); - } - } - - static void AppendCsharpFunctionCallSubject( - Type enclosingType, - bool isStatic, - StringBuilder output) - { - if (isStatic) - { - AppendCsharpTypeFullName( - enclosingType, - output); - } - else - { - output.Append("thiz"); - } - } - - static void AppendCsharpFunctionCallParameters( - ParameterInfo[] parameters, - StringBuilder output) - { - for (int i = 0; i < parameters.Length; ++i) - { - ParameterInfo param = parameters[i]; - if (param.IsOut) - { - output.Append("out "); - } - else if (param.IsRef) - { - output.Append("ref "); - } - output.Append(param.Name); - if (i != parameters.Length - 1) - { - output.Append(", "); - } - } - } - - static void AppendStructStoreReplace( - Type enclosingType, - string handleVariable, - string structVariable, - StringBuilder output) - { - output.AppendLine(); - output.Append("\t\t\t\t"); - AppendHandleStoreTypeName( - enclosingType, - output); - output.Append(".Replace("); - output.Append(handleVariable); - output.Append(", ref "); - output.Append(structVariable); - output.Append(");"); - } - - static void AppendCsharpFunctionReturn( - ParameterInfo[] parameters, - Type returnType, - TypeKind returnTypeKind, - Type[] exceptionTypes, - bool forceReturnReturnValue, - StringBuilder output) - { - // Store reference out and ref params and overwrite handles - foreach (ParameterInfo param in parameters) - { - if ((param.Kind == TypeKind.Class - || param.Kind == TypeKind.ManagedStruct) - && (param.IsOut || param.IsRef)) - { - output.AppendLine(); - output.Append("\t\t\t\tint "); - output.Append(param.Name); - output.Append("HandleNew = "); - AppendHandleStoreTypeName( - param.DereferencedParameterType, - output); - output.Append('.'); - if (param.Kind == TypeKind.ManagedStruct) - { - output.Append("Store"); - } - else - { - output.Append("GetHandle"); - } - output.Append('('); - output.Append(param.Name); - output.AppendLine(");"); - output.Append("\t\t\t\t"); - output.Append(param.Name); - output.Append("Handle = "); - output.Append(param.Name); - output.Append("HandleNew;"); - } - } - - // Return - if (returnType != typeof(void)) - { - output.AppendLine(); - output.Append("\t\t\t\treturn "); - if ( - forceReturnReturnValue - || returnTypeKind == TypeKind.Enum - || returnTypeKind == TypeKind.FullStruct - || returnTypeKind == TypeKind.Primitive) - { - output.Append("returnValue"); - } - else - { - AppendHandleStoreTypeName( - returnType, - output); - output.Append('.'); - if (returnTypeKind == TypeKind.Class) - { - output.Append("GetHandle"); - } - else - { - output.Append("Store"); - } - output.Append("(returnValue)"); - } - output.Append(';'); - } - - // Returning ends the function - AppendCsharpFunctionEnd( - returnType, - exceptionTypes, - parameters, - output); - } - - static void AppendCsharpFunctionEnd( - Type returnType, - Type[] exceptionTypes, - ParameterInfo[] parameters, - StringBuilder output) - { - output.AppendLine();; - output.AppendLine("\t\t\t}"); - if (exceptionTypes == null - || Array.IndexOf( - exceptionTypes, - typeof(NullReferenceException)) < 0) - { - AppendCsharpCatchException( - typeof(NullReferenceException), - returnType, - parameters, - output); - } - if (exceptionTypes != null) - { - foreach (Type exceptionType in exceptionTypes) - { - AppendCsharpCatchException( - exceptionType, - returnType, - parameters, - output); - } - } - AppendCsharpCatchException( - typeof(Exception), - returnType, - parameters, - output); - output.AppendLine("\t\t}"); - output.AppendLine("\t\t"); - } - - static void AppendCsharpCatchException( - Type exceptionType, - Type returnType, - ParameterInfo[] parameters, - StringBuilder output) - { - output.Append("\t\t\tcatch ("); - AppendCsharpTypeFullName( - exceptionType, - output); - output.AppendLine(" ex)"); - output.AppendLine("\t\t\t{"); - output.AppendLine("\t\t\t\tUnityEngine.Debug.LogException(ex);"); - output.Append("\t\t\t\tNativeScript.Bindings."); - AppendCsharpSetCsharpExceptionFunctionName( - exceptionType, - output); - output.AppendLine("(NativeScript.Bindings.ObjectStore.Store(ex));"); - foreach (ParameterInfo param in parameters) - { - if (param.IsOut) - { - output.Append("\t\t\t\t"); - output.Append(param.Name); - if (param.Kind == TypeKind.Class - || param.Kind == TypeKind.ManagedStruct) - { - output.AppendLine("Handle = default(int);"); - } - else - { - output.Append(" = default("); - AppendCsharpTypeFullName( - param.DereferencedParameterType, - output); - output.AppendLine(");"); - } - } - } - if (returnType != typeof(void)) - { - output.Append("\t\t\t\treturn default("); - if (IsFullValueType(returnType)) - { - AppendCsharpTypeFullName( - returnType, - output); - } - else - { - output.Append("int"); - } - output.AppendLine(");"); - } - output.AppendLine("\t\t\t}"); - } - - static void AppendCsharpSetCsharpExceptionFunctionName( - Type exceptionType, - StringBuilder output - ) - { - output.Append("SetCsharpException"); - if (exceptionType != typeof(Exception)) - { - AppendNamespace( - exceptionType.Namespace, - string.Empty, - output); - AppendTypeNameWithoutGenericSuffix( - exceptionType.Name, - output); - } - } - - static void AppendCsharpBindingParameterDeclaration( - ParameterInfo[] parameters, - StringBuilder output) - { - for (int i = 0; i < parameters.Length; ++i) - { - ParameterInfo param = parameters[i]; - - // out or ref qualifiers if necessary - switch (param.Kind) - { - case TypeKind.FullStruct: - if (param.IsOut) - { - output.Append("out "); - } - else - { - output.Append("ref "); - } - break; - case TypeKind.ManagedStruct: - case TypeKind.Primitive: - case TypeKind.Enum: - case TypeKind.Class: - if (param.IsOut || param.IsRef) - { - output.Append("ref "); - } - break; - } - - // Param type- int for handles - switch (param.Kind) - { - case TypeKind.ManagedStruct: - case TypeKind.Class: - output.Append("int"); - break; - default: - AppendCsharpTypeFullName( - param.DereferencedParameterType, - output); - break; - } - - // Param name - output.Append(' '); - output.Append(param.Name); - - // Handle suffix if necessary - if (param.Kind == TypeKind.Class - || param.Kind == TypeKind.ManagedStruct) - { - output.Append("Handle"); - } - - if (i != parameters.Length - 1) - { - output.Append(", "); - } - } - } - - static void AppendCppParameterDeclaration( - ParameterInfo[] parameters, - Type[] methodTypeParameters, - bool includeDefaults, - StringBuilder output) - { - bool hasVarArgs = parameters.Length > 0 && - parameters[parameters.Length-1].IsVarArg; - for (int i = 0; i < parameters.Length; ++i) - { - ParameterInfo param = parameters[i]; - Type paramType = param.DereferencedParameterType; - - int typeParamIndex = ArrayIndexOf( - methodTypeParameters, - paramType); - if (typeParamIndex >= 0) - { - output.Append("MT"); - output.Append(typeParamIndex); - } - else - { - AppendCppTypeFullName( - paramType, - output); - } - - // Pointer (*) or reference (&) suffix if necessary - if (param.IsOut || param.IsRef) - { - output.Append('*'); - } - else if ( - param.Kind == TypeKind.FullStruct || - param.Kind == TypeKind.ManagedStruct || - param.Kind == TypeKind.Class || - param.IsVirtual) - { - output.Append('&'); - } - - // Param name - output.Append(' '); - output.Append(param.Name); - - // Default if desired, present, and the method has no var args - if (includeDefaults && param.HasDefault && !hasVarArgs) - { - output.Append(" = "); - if (param.DereferencedParameterType == typeof(string)) - { - if (param.DefaultValue != null) - { - throw new Exception( - "Non-null string default parameters aren't supported"); - } - output.Append("Plugin::NullString"); - } - else if (param.DefaultValue is bool) - { - bool val = (bool)param.DefaultValue; - output.Append(val ? "true" : "false"); - } - else if (param.DefaultValue is char) - { - char val = (char)param.DefaultValue; - output.Append('\''); - output.Append(val); - output.Append('\''); - } - else if ((param.DefaultValue is sbyte) || - (param.DefaultValue is byte) || - (param.DefaultValue is short) || - (param.DefaultValue is ushort) || - (param.DefaultValue is int) || - (param.DefaultValue is uint) || - (param.DefaultValue is long) || - (param.DefaultValue is ulong)) - { - output.Append(param.DefaultValue); - } - else - { - Type type = param.DefaultValue.GetType(); - if (type.IsEnum) - { - AppendCppTypeFullName( - type, - output); - output.Append("::"); - output.Append(param.DefaultValue); - } - else - { - StringBuilder error = new StringBuilder(); - error.Append("Default parameter type ("); - AppendCsharpTypeFullName( - param.DefaultValue.GetType(), - error); - error.Append(") not supported"); - throw new Exception(error.ToString()); - } - } - } - - if (i != parameters.Length - 1) - { - output.Append(", "); - } - } - } - - static void AppendCppInitBodyFunctionPointerParameterRead( - string globalVariableName, - bool isStatic, - TypeName enclosingTypeTypeName, - TypeKind enclosingTypeKind, - ParameterInfo[] parameters, - Type returnType, - StringBuilder output) - { - output.Append("\tPlugin::"); - output.Append(globalVariableName); - output.Append(" = *("); - AppendCppFunctionPointer( - string.Empty, // function name - isStatic, - enclosingTypeTypeName, - enclosingTypeKind, - parameters, - returnType, - 2, - output); - output.AppendLine(")curMemory;"); - output.Append("\tcurMemory += sizeof(Plugin::"); - output.Append(globalVariableName); - output.AppendLine(");"); - } - - static void AppendCppMethodDefinitionBegin( - TypeName enclosingTypeTypeName, - Type returnType, - string methodName, - Type[] enclosingTypeTypeParams, - Type[] methodTypeParams, - ParameterInfo[] parameters, - int indent, - StringBuilder output) - { - // Indent - AppendIndent( - indent, - output); - - // Template - if (methodTypeParams != null) - { - output.Append("template<> "); - } - - // Return type - if (returnType != null) - { - AppendCppTypeFullName( - returnType, - output); - output.Append(' '); - } - - // Type name - AppendCppTypeFullName( - enclosingTypeTypeName, - output); - AppendCppTypeParameters( - enclosingTypeTypeParams, - output); - output.Append("::"); - - // Method name - AppendTypeNameWithoutGenericSuffix( - methodName, - output); - - // Template parameters - AppendCppTypeParameters( - methodTypeParams, - output); - - // Parameters - output.Append('('); - AppendCppParameterDeclaration( - parameters, - null, // don't substitute method type params - false, - output); - output.AppendLine(")"); - } - - static void AppendCppMethodReturn( - Type returnType, - TypeKind returnTypeKind, - int indent, - StringBuilder output) - { - if (returnType != null && returnType != typeof(void)) - { - AppendIndent(indent, output); - output.Append("return "); - switch (returnTypeKind) - { - case TypeKind.Enum: - case TypeKind.FullStruct: - case TypeKind.Primitive: - output.Append("returnValue"); - break; - default: - AppendCppTypeFullName( - returnType, - output); - output.Append("(Plugin::InternalUse::Only, returnValue)"); - break; - } - output.AppendLine(";"); - } - } - - static void AppendCppPluginFunctionCall( - bool isStatic, - TypeName enclosingTypeTypeName, - TypeKind enclosingTypeKind, - Type[] enclosingTypeParams, - Type returnType, - string funcName, - ParameterInfo[] parameters, - int indent, - StringBuilder output) - { - // Gather handles for out and ref parameters - foreach (ParameterInfo param in parameters) - { - if ((param.Kind == TypeKind.Class - || param.Kind == TypeKind.ManagedStruct) - && (param.IsOut || param.IsRef)) - { - AppendIndent(indent, output); - output.Append("int32_t "); - output.Append(param.Name); - output.Append("Handle = "); - output.Append(param.Name); - output.AppendLine("->Handle;"); - } - } - - // Call the function - AppendIndent(indent, output); - if (returnType != null && returnType != typeof(void)) - { - output.Append("auto returnValue = "); - } - output.Append("Plugin::"); - output.Append(funcName); - output.Append("("); - if (!isStatic) - { - if (enclosingTypeKind == TypeKind.FullStruct) - { - output.Append("this"); - } - else - { - output.Append("Handle"); - } - if (parameters.Length > 0) - { - output.Append(", "); - } - } - for (int i = 0; i < parameters.Length; ++i) - { - ParameterInfo param = parameters[i]; - switch (param.Kind) - { - case TypeKind.FullStruct: - case TypeKind.Enum: - output.Append(param.Name); - break; - case TypeKind.Primitive: - if (param.IsOut || param.IsRef) - { - output.Append("&"); - output.Append(param.Name); - output.Append("->Value"); - } - else - { - output.Append(param.Name); - } - break; - default: - if (param.IsOut || param.IsRef) - { - output.Append('&'); - output.Append(param.Name); - } - else - { - output.Append(param.Name); - output.Append('.'); - } - output.Append("Handle"); - break; - } - if (i != parameters.Length - 1) - { - output.Append(", "); - } - } - output.AppendLine(");"); - - AppendCppUnhandledExceptionHandling( - indent, - output); - - // Set out and ref parameters - foreach (ParameterInfo param in parameters) - { - if ((param.Kind == TypeKind.Class - || param.Kind == TypeKind.ManagedStruct) - && (param.IsOut || param.IsRef)) - { - AppendSetHandle( - enclosingTypeTypeName, - enclosingTypeKind, - enclosingTypeParams, - indent, - param.Name, - param.Name + "Handle", - output); - } - } - } - - static void AppendCppUnhandledExceptionHandling( - int indent, - StringBuilder output) - { - AppendIndent(indent, output); - output.AppendLine("if (Plugin::unhandledCsharpException)"); - AppendIndent(indent, output); - output.AppendLine("{"); - AppendIndent(indent + 1, output); - output.AppendLine("System::Exception* ex = Plugin::unhandledCsharpException;"); - AppendIndent(indent + 1, output); - output.AppendLine("Plugin::unhandledCsharpException = nullptr;"); - AppendIndent(indent + 1, output); - output.AppendLine("ex->ThrowReferenceToThis();"); - AppendIndent(indent + 1, output); - output.AppendLine("delete ex;"); - AppendIndent(indent, output); - output.AppendLine("}"); - } - - static void AppendCppFunctionPointerDefinition( - string funcName, - bool isStatic, - TypeName enclosingTypeTypeName, - TypeKind enclosingTypeKind, - ParameterInfo[] parameters, - Type returnType, - StringBuilder output - ) - { - output.Append('\t'); - AppendCppFunctionPointer( - funcName, - isStatic, - enclosingTypeTypeName, - enclosingTypeKind, - parameters, - returnType, - 1, - output - ); - output.Append(';'); - output.AppendLine();; - } - - static void AppendCppFunctionPointer( - string funcName, - bool isStatic, - TypeName enclosingTypeTypeName, - TypeKind enclosingTypeKind, - ParameterInfo[] parameters, - Type returnType, - int numIndirectionLevels, - StringBuilder output) - { - // Return type - if (returnType == typeof(bool)) - { - // C linkage requires us to use primitive types - output.Append("int32_t"); - } - else if (returnType == typeof(char)) - { - // C linkage requires us to use primitive types - output.Append("int16_t"); - } - else if (returnType.IsPrimitive) - { - AppendCppPrimitiveTypeName(returnType, output); - } - else if (IsFullValueType(returnType)) - { - AppendCppTypeFullName(returnType, output); - } - else - { - output.Append("int32_t"); - } - - output.Append(" ("); - output.Append('*', numIndirectionLevels); - output.Append(funcName); - output.Append(")("); - if (!isStatic) - { - switch (enclosingTypeKind) - { - case TypeKind.FullStruct: - case TypeKind.Primitive: - AppendCppTypeFullName( - enclosingTypeTypeName, - output); - output.Append("* thiz"); - break; - default: - output.Append("int32_t thisHandle"); - break; - } - if (parameters.Length > 0) - { - output.Append(", "); - } - } - for (int i = 0; i < parameters.Length; ++i) - { - ParameterInfo param = parameters[i]; - switch (param.Kind) - { - case TypeKind.Primitive: - AppendCppPrimitiveTypeName( - param.DereferencedParameterType, - output); - if (param.IsOut || param.IsRef) - { - output.Append('*'); - } - break; - case TypeKind.Enum: - AppendCppTypeFullName( - param.DereferencedParameterType, - output); - if (param.IsOut || param.IsRef) - { - output.Append('*'); - } - break; - case TypeKind.FullStruct: - AppendCppTypeFullName( - param.DereferencedParameterType, - output); - if (param.IsOut || param.IsRef) - { - output.Append('*'); - } - else - { - output.Append('&'); - } - break; - case TypeKind.Class: - case TypeKind.ManagedStruct: - output.Append("int32_t"); - if (param.IsOut || param.IsRef) - { - output.Append('*'); - } - break; - } - output.Append(' '); - output.Append(param.Name); - if (param.Kind == TypeKind.Class - || param.Kind == TypeKind.ManagedStruct) - { - output.Append("Handle"); - } - if (i != parameters.Length - 1) - { - output.Append(", "); - } - } - output.Append(')'); - } - - static void AppendCppTemplateTypenames( - int numTypeParameters, - char prefix, - StringBuilder output) - { - if (numTypeParameters > 0) - { - output.Append("template<"); - for (int i = 0; i < numTypeParameters; ++i) - { - output.Append("typename "); - output.Append(prefix); - output.Append('T'); - output.Append(i); - if (i != numTypeParameters - 1) - { - output.Append(", "); - } - } - output.Append("> "); - } - } - - static void AppendCppMethodDeclaration( - string methodName, - bool enclosingTypeIsStatic, - bool methodIsVirtual, - bool methodIsStatic, - Type returnType, - Type[] methodTypeParameters, - ParameterInfo[] parameters, - StringBuilder output) - { - AppendCppTemplateTypenames( - methodTypeParameters == null ? 0 : methodTypeParameters.Length, - 'M', - output); - - if (!enclosingTypeIsStatic && methodIsStatic) - { - output.Append("static "); - } - - if (methodIsVirtual) - { - output.Append("virtual "); - } - - // Return type - if (returnType != null) - { - int typeParamIndex = ArrayIndexOf( - methodTypeParameters, - returnType); - if (typeParamIndex >= 0) - { - output.Append("MT"); - output.Append(typeParamIndex); - } - else - { - AppendCppTypeFullName( - returnType, - output); - } - output.Append(' '); - } - - // Method name might be a constructor/type name, so remove suffix - // just in case - AppendTypeNameWithoutGenericSuffix( - methodName, - output); - - // Parameters - output.Append('('); - AppendCppParameterDeclaration( - parameters, - methodTypeParameters, - true, - output); - output.Append(')'); - - output.AppendLine(";"); - } - - static void AppendCsharpTypeFullName( - Type type, - StringBuilder output) - { - if (type == typeof(void)) - { - output.Append("void"); - } - else if (type == typeof(bool)) - { - output.Append("bool"); - } - else if (type == typeof(sbyte)) - { - output.Append("sbyte"); - } - else if (type == typeof(byte)) - { - output.Append("byte"); - } - else if (type == typeof(short)) - { - output.Append("short"); - } - else if (type == typeof(ushort)) - { - output.Append("ushort"); - } - else if (type == typeof(int)) - { - output.Append("int"); - } - else if (type == typeof(uint)) - { - output.Append("uint"); - } - else if (type == typeof(long)) - { - output.Append("long"); - } - else if (type == typeof(ulong)) - { - output.Append("ulong"); - } - else if (type == typeof(char)) - { - output.Append("char"); - } - else if (type == typeof(float)) - { - output.Append("float"); - } - else if (type == typeof(double)) - { - output.Append("double"); - } - else if (type == typeof(string)) - { - output.Append("string"); - } - else if (type == typeof(object)) - { - output.Append("object"); - } - else if (type.IsArray) - { - AppendCsharpTypeFullName( - type.GetElementType(), - output); - output.Append('['); - output.Append(',', type.GetArrayRank()-1); - output.Append(']'); - } - else - { - AppendCsharpTypeFullName(GetTypeName(type), output); - Type[] genTypes = type.GetGenericArguments(); - AppendCSharpTypeParameters( - genTypes, - output); - } - } - - static void AppendCsharpTypeFullName( - TypeName typeName, - StringBuilder output) - { - if (!string.IsNullOrEmpty(typeName.Namespace)) - { - output.Append(typeName.Namespace); - output.Append('.'); - } - AppendTypeNameWithoutGenericSuffix(typeName.Name, output); - } - - static void AppendCppTypeFullName( - Type type, - StringBuilder output) - { - if (type == typeof(void)) - { - output.Append("void"); - } - else if (type == typeof(bool)) - { - output.Append("System::Boolean"); - } - else if (type == typeof(sbyte)) - { - output.Append("System::SByte"); - } - else if (type == typeof(byte)) - { - output.Append("System::Byte"); - } - else if (type == typeof(short)) - { - output.Append("System::Int16"); - } - else if (type == typeof(ushort)) - { - output.Append("System::UInt16"); - } - else if (type == typeof(int)) - { - output.Append("System::Int32"); - } - else if (type == typeof(uint)) - { - output.Append("System::UInt32"); - } - else if (type == typeof(long)) - { - output.Append("System::Int64"); - } - else if (type == typeof(ulong)) - { - output.Append("System::UInt64"); - } - else if (type == typeof(char)) - { - output.Append("System::Char"); - } - else if (type == typeof(float)) - { - output.Append("System::Single"); - } - else if (type == typeof(double)) - { - output.Append("System::Double"); - } - else if (type == typeof(string)) - { - output.Append("System::String"); - } - else if (type == typeof(IntPtr)) - { - output.Append("void*"); - } - else if (type.IsArray) - { - int rank = type.GetArrayRank(); - output.Append("System::Array"); - output.Append(rank); - output.Append('<'); - Type elementType = type.GetElementType(); - AppendCppTypeFullName( - elementType, - output); - output.Append('>'); - } - else if (IsDelegate(type)) - { - AppendCppTypeFullName( - GetTypeName(type), - output); - Type[] genTypes = type.GetGenericArguments(); - AppendCppTypeParameters( - genTypes, - output); - } - else - { - TypeName typeName = GetTypeName(type); - AppendCppTypeFullName(typeName, output); - Type[] genTypes = type.GetGenericArguments(); - AppendCppTypeParameters(genTypes, output); - } - } - - static void AppendCppTypeFullName( - TypeName typeName, - StringBuilder output) - { - AppendNamespace(typeName.Namespace, "::", output); - if (!string.IsNullOrEmpty(typeName.Namespace)) - { - output.Append("::"); - } - AppendCppTypeName(typeName, output); - } - - static void AppendCppTypeName( - TypeName typeName, - StringBuilder output) - { - AppendTypeNameWithoutGenericSuffix(typeName.Name, output); - if (typeName.NumTypeParams > 0) - { - output.Append('_'); - output.Append(typeName.NumTypeParams); - } - } - - static void AppendCppPrimitiveTypeName( - Type type, - StringBuilder output) - { - if (type == typeof(void)) - { - output.Append("void"); - } - else if (type == typeof(bool)) - { - output.Append("uint32_t"); // C# bool is 4 bytes - } - else if (type == typeof(sbyte)) - { - output.Append("int8_t"); - } - else if (type == typeof(byte)) - { - output.Append("uint8_t"); - } - else if (type == typeof(short)) - { - output.Append("int16_t"); - } - else if (type == typeof(ushort)) - { - output.Append("uint16_t"); - } - else if (type == typeof(int)) - { - output.Append("int32_t"); - } - else if (type == typeof(uint)) - { - output.Append("uint32_t"); - } - else if (type == typeof(long)) - { - output.Append("int64_t"); - } - else if (type == typeof(ulong)) - { - output.Append("uint64_t"); - } - else if (type == typeof(char)) - { - output.Append("uint16_t"); // C# char is 2 bytes - } - else if (type == typeof(float)) - { - output.Append("float"); - } - else if (type == typeof(double)) - { - output.Append("double"); - } - else if (type == typeof(IntPtr)) - { - output.Append("void*"); - } - else - { - throw new Exception(type + " is not a C++ primitive"); - } - } - - static void RemoveTrailingChars( - StringBuilders builders) - { - RemoveTrailingChars(builders.CsharpDelegateTypes); - RemoveTrailingChars(builders.CsharpStoreInitCalls); - RemoveTrailingChars(builders.CsharpInitCall); - RemoveTrailingChars(builders.CsharpBaseTypes); - RemoveTrailingChars(builders.CsharpFunctions); - RemoveTrailingChars(builders.CsharpCppDelegates); - RemoveTrailingChars(builders.CsharpCsharpDelegates); - RemoveTrailingChars(builders.CsharpImports); - RemoveTrailingChars(builders.CsharpGetDelegateCalls); - RemoveTrailingChars(builders.CsharpDestroyFunctionEnumerators); - RemoveTrailingChars(builders.CsharpDestroyQueueCases); - RemoveTrailingChars(builders.CppFunctionPointers); - RemoveTrailingChars(builders.CppTypeDeclarations); - RemoveTrailingChars(builders.CppTemplateDeclarations); - RemoveTrailingChars(builders.CppTemplateSpecializationDeclarations); - RemoveTrailingChars(builders.CppTypeDefinitions); - RemoveTrailingChars(builders.CppMethodDefinitions); - RemoveTrailingChars(builders.CppInitBodyParameterReads); - RemoveTrailingChars(builders.CppInitBodyArrays); - RemoveTrailingChars(builders.CppInitBodyFirstBoot); - RemoveTrailingChars(builders.CppGlobalStateAndFunctions); - RemoveTrailingChars(builders.CppUnboxingMethodDeclarations); - RemoveTrailingChars(builders.CppStringDefaultParams); - RemoveTrailingChars(builders.CppMacros); - } - - // Remove trailing chars (e.g. commas) for last elements - static void RemoveTrailingChars( - StringBuilder builder) - { - int len = builder.Length; - int i; - for (i = len - 1; i >= 0; --i) - { - char cur = builder[i]; - if (!char.IsWhiteSpace(cur) && cur != ',') - { - break; - } - } - - if (i < len - 1) - { - builder.Remove(i + 1, len - i - 1); - } - } - - static void InjectBuilders( - StringBuilders builders) - { - // Inject into source files - string csharpContents = File.ReadAllText(CsharpPath); - string cppHeaderContents = File.ReadAllText(CppHeaderPath); - string cppSourceContents = File.ReadAllText(CppSourcePath); - csharpContents = InjectIntoString( - csharpContents, - "/*BEGIN DELEGATE TYPES*/", - "\t\t/*END DELEGATE TYPES*/", - builders.CsharpDelegateTypes.ToString()); - csharpContents = InjectIntoString( - csharpContents, - "/*BEGIN STORE INIT CALLS*/", - "\t\t\t/*END STORE INIT CALLS*/", - builders.CsharpStoreInitCalls.ToString()); - csharpContents = InjectIntoString( - csharpContents, - "/*BEGIN INIT CALL*/", - "\t\t\t/*END INIT CALL*/", - builders.CsharpInitCall.ToString()); - csharpContents = InjectIntoString( - csharpContents, - "/*BEGIN BASE TYPES*/", - "/*END BASE TYPES*/", - builders.CsharpBaseTypes.ToString()); - csharpContents = InjectIntoString( - csharpContents, - "/*BEGIN FUNCTIONS*/", - "\t\t/*END FUNCTIONS*/", - builders.CsharpFunctions.ToString()); - csharpContents = InjectIntoString( - csharpContents, - "/*BEGIN CPP DELEGATES*/", - "\t\t/*END CPP DELEGATES*/", - builders.CsharpCppDelegates.ToString()); - csharpContents = InjectIntoString( - csharpContents, - "/*BEGIN CSHARP DELEGATES*/", - "\t\t/*END CSHARP DELEGATES*/", - builders.CsharpCsharpDelegates.ToString()); - csharpContents = InjectIntoString( - csharpContents, - "/*BEGIN IMPORTS*/", - "\t\t/*END IMPORTS*/", - builders.CsharpImports.ToString()); - csharpContents = InjectIntoString( - csharpContents, - "/*BEGIN GETDELEGATE CALLS*/", - "\t\t\t/*END GETDELEGATE CALLS*/", - builders.CsharpGetDelegateCalls.ToString()); - csharpContents = InjectIntoString( - csharpContents, - "/*BEGIN DESTROY FUNCTION ENUMERATORS*/", - "\t\t\t/*END DESTROY FUNCTION ENUMERATORS*/", - builders.CsharpDestroyFunctionEnumerators.ToString()); - csharpContents = InjectIntoString( - csharpContents, - "/*BEGIN DESTROY QUEUE CASES*/", - "\t\t\t\t\t\t/*END DESTROY QUEUE CASES*/", - builders.CsharpDestroyQueueCases.ToString()); - cppSourceContents = InjectIntoString( - cppSourceContents, - "/*BEGIN FUNCTION POINTERS*/", - "\t/*END FUNCTION POINTERS*/", - builders.CppFunctionPointers.ToString()); - cppHeaderContents = InjectIntoString( - cppHeaderContents, - "/*BEGIN TYPE DECLARATIONS*/", - "/*END TYPE DECLARATIONS*/", - builders.CppTypeDeclarations.ToString()); - cppHeaderContents = InjectIntoString( - cppHeaderContents, - "/*BEGIN TEMPLATE DECLARATIONS*/", - "/*END TEMPLATE DECLARATIONS*/", - builders.CppTemplateDeclarations.ToString()); - cppHeaderContents = InjectIntoString( - cppHeaderContents, - "/*BEGIN TEMPLATE SPECIALIZATION DECLARATIONS*/", - "/*END TEMPLATE SPECIALIZATION DECLARATIONS*/", - builders.CppTemplateSpecializationDeclarations.ToString()); - cppHeaderContents = InjectIntoString( - cppHeaderContents, - "/*BEGIN TYPE DEFINITIONS*/", - "/*END TYPE DEFINITIONS*/", - builders.CppTypeDefinitions.ToString()); - cppSourceContents = InjectIntoString( - cppSourceContents, - "/*BEGIN METHOD DEFINITIONS*/", - "/*END METHOD DEFINITIONS*/", - builders.CppMethodDefinitions.ToString()); - cppSourceContents = InjectIntoString( - cppSourceContents, - "/*BEGIN INIT BODY PARAMETER READS*/", - "\t/*END INIT BODY PARAMETER READS*/", - builders.CppInitBodyParameterReads.ToString()); - cppSourceContents = InjectIntoString( - cppSourceContents, - "/*BEGIN INIT BODY ARRAYS*/", - "\t/*END INIT BODY ARRAYS*/", - builders.CppInitBodyArrays.ToString()); - cppSourceContents = InjectIntoString( - cppSourceContents, - "/*BEGIN INIT BODY FIRST BOOT*/", - "\t\t/*END INIT BODY FIRST BOOT*/", - builders.CppInitBodyFirstBoot.ToString()); - cppSourceContents = InjectIntoString( - cppSourceContents, - "/*BEGIN GLOBAL STATE AND FUNCTIONS*/", - "\t/*END GLOBAL STATE AND FUNCTIONS*/", - builders.CppGlobalStateAndFunctions.ToString()); - cppHeaderContents = InjectIntoString( - cppHeaderContents, - "/*BEGIN UNBOXING METHOD DECLARATIONS*/", - "\t\t/*END UNBOXING METHOD DECLARATIONS*/", - builders.CppUnboxingMethodDeclarations.ToString()); - cppHeaderContents = InjectIntoString( - cppHeaderContents, - "/*BEGIN STRING DEFAULT PARAMETERS*/", - "\t/*END STRING DEFAULT PARAMETERS*/", - builders.CppStringDefaultParams.ToString()); - cppHeaderContents = InjectIntoString( - cppHeaderContents, - "/*BEGIN MACROS*/", - "/*END MACROS*/", - builders.CppMacros.ToString()); - - File.WriteAllText(CsharpPath, csharpContents); - File.WriteAllText(CppHeaderPath, cppHeaderContents); - File.WriteAllText(CppSourcePath, cppSourceContents); - } - - static string InjectIntoString( - string contents, - string beginMarker, - string endMarker, - string text) - { - int startIndex = 0; - while(true) - { - int beginIndex = contents.IndexOf(beginMarker, startIndex, StringComparison.OrdinalIgnoreCase); - if (beginIndex < 0) - { - return contents; - } - int afterBeginIndex = beginIndex + beginMarker.Length; - int endIndex = contents.IndexOf(endMarker, afterBeginIndex, StringComparison.OrdinalIgnoreCase); - if (endIndex < 0) - { - throw new Exception( - string.Format( - "No end ({0}) for begin ({1}) at {2} after {3}", - endMarker, - beginMarker, - beginIndex, - startIndex)); - } - string begin = contents.Substring(0, afterBeginIndex); - string end = contents.Substring(endIndex); - contents = begin + Environment.NewLine + text + Environment.NewLine + end; - startIndex = beginIndex + 1; - } - } - } -} diff --git a/Unity/Assets/NativeScript/VERSION.txt b/Unity/Assets/NativeScript/VERSION.txt deleted file mode 100644 index 1d71ef9..0000000 --- a/Unity/Assets/NativeScript/VERSION.txt +++ /dev/null @@ -1 +0,0 @@ -0.3 \ No newline at end of file diff --git a/Unity/Assets/NativeScriptConstants.cs b/Unity/Assets/NativeScriptConstants.cs deleted file mode 100644 index 54e6923..0000000 --- a/Unity/Assets/NativeScriptConstants.cs +++ /dev/null @@ -1,17 +0,0 @@ -/// -/// Constants used by the C++ scripting system. Redefine these with values -/// specific to your project. -/// -/// -/// Jackson Dunstan, 2017, http://JacksonDunstan.com -/// -/// -/// MIT -/// -public static class NativeScriptConstants -{ - /// - /// Path within the Unity project to the exposed types JSON file - /// - public const string JSON_CONFIG_PATH = "NativeScriptTypes.json"; -} \ No newline at end of file diff --git a/Unity/Assets/NativeScriptConstants.cs.meta b/Unity/Assets/NativeScriptConstants.cs.meta deleted file mode 100644 index c6cb93d..0000000 --- a/Unity/Assets/NativeScriptConstants.cs.meta +++ /dev/null @@ -1,12 +0,0 @@ -fileFormatVersion: 2 -guid: 317acc5bbfabb44e6821f3ffcaa4f172 -timeCreated: 1501975249 -licenseType: Free -MonoImporter: - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Unity/Assets/NativeScriptTypes.json b/Unity/Assets/NativeScriptTypes.json deleted file mode 100644 index c507547..0000000 --- a/Unity/Assets/NativeScriptTypes.json +++ /dev/null @@ -1,344 +0,0 @@ -{ - "Assemblies": [ - ], - "Types": [ - { - "Name": " System.IFormattable" - }, - { - "Name": " System.IConvertible" - }, - { - "Name": " System.IComparable" - }, - { - "Name": "System.IEquatable`1", - "GenericParams": [ - { - "Types": [ - "System.Boolean" - ] - }, - { - "Types": [ - "System.Char" - ] - }, - { - "Types": [ - "System.SByte" - ] - }, - { - "Types": [ - "System.Byte" - ] - }, - { - "Types": [ - "System.Int16" - ] - }, - { - "Types": [ - "System.UInt16" - ] - }, - { - "Types": [ - "System.Int32" - ] - }, - { - "Types": [ - "System.UInt32" - ] - }, - { - "Types": [ - "System.Int64" - ] - }, - { - "Types": [ - "System.UInt64" - ] - }, - { - "Types": [ - "System.Single" - ] - }, - { - "Types": [ - "System.Double" - ] - }, - { - "Types": [ - "System.Decimal" - ] - }, - { - "Types": [ - "UnityEngine.Vector3" - ] - } - ] - }, - { - "Name": "System.IComparable`1", - "GenericParams": [ - { - "Types": [ - "System.Boolean" - ] - }, - { - "Types": [ - "System.Char" - ] - }, - { - "Types": [ - "System.SByte" - ] - }, - { - "Types": [ - "System.Byte" - ] - }, - { - "Types": [ - "System.Int16" - ] - }, - { - "Types": [ - "System.UInt16" - ] - }, - { - "Types": [ - "System.Int32" - ] - }, - { - "Types": [ - "System.UInt32" - ] - }, - { - "Types": [ - "System.Int64" - ] - }, - { - "Types": [ - "System.UInt64" - ] - }, - { - "Types": [ - "System.Single" - ] - }, - { - "Types": [ - "System.Double" - ] - }, - { - "Types": [ - "System.Decimal" - ] - } - ] - }, - { - "Name": " System.Runtime.Serialization.IDeserializationCallback" - }, - { - "Name": "System.Decimal", - "Constructors": [ - { - "ParamTypes": [ - "System.Double" - ] - }, - { - "ParamTypes": [ - "System.UInt64" - ] - } - ] - }, - { - "Name": "UnityEngine.Vector3", - "Constructors": [ - { - "ParamTypes": [ - "System.Single", - "System.Single", - "System.Single" - ] - } - ], - "Methods": [ - { - "Name": "x+y", - "ParamTypes": [ - "UnityEngine.Vector3", - "UnityEngine.Vector3" - ] - } - ] - }, - { - "Name": "UnityEngine.Object", - "Properties": [ - { - "Name": "name", - "Get": {}, - "Set": {} - } - ] - }, - { - "Name": "UnityEngine.Component", - "Properties": [ - { - "Name": "transform", - "Get": {} - } - ] - }, - { - "Name": "UnityEngine.Transform", - "Properties": [ - { - "Name": "position", - "Get": {}, - "Set": { - "Exceptions": [ - "System.NullReferenceException" - ] - } - } - ] - }, - { - "Name": "System.Collections.IEnumerator", - "Methods": [ - { - "Name": "MoveNext", - "ParamTypes": [] - } - ], - "Properties": [ - { - "Name": "Current", - "Get": {}, - "Set": {} - } - ] - }, - { - "Name": "System.Runtime.Serialization.ISerializable" - }, - { - "Name": "System.Runtime.InteropServices._Exception" - }, - { - "Name": "UnityEngine.GameObject", - "Constructors": [ - ], - "Methods": [ - { - "Name": "AddComponent", - "ParamTypes": [], - "GenericParams": [ - { - "Types": [ - "MyGame.BaseBallScript" - ] - } - ] - }, - { - "Name": "CreatePrimitive", - "ParamTypes": [ - "UnityEngine.PrimitiveType" - ] - } - ] - }, - { - "Name": "UnityEngine.Debug", - "Methods": [ - { - "Name": "Log", - "ParamTypes": [ - "System.Object" - ] - } - ] - }, - { - "Name": "UnityEngine.Behaviour" - }, - { - "Name": "UnityEngine.MonoBehaviour", - "Properties": [ - { - "Name": "transform", - "Get": {}, - "Set": {} - } - ] - }, - { - "Name": "System.Exception", - "Constructors": [ - { - "ParamTypes": [ - "System.String" - ] - } - ] - }, - { - "Name": "System.SystemException" - }, - { - "Name": "System.NullReferenceException" - }, - { - "Name": "UnityEngine.PrimitiveType" - }, - { - "Name": "UnityEngine.Time", - "Properties": [ - { - "Name": "deltaTime", - "Get": {}, - "Set": {} - } - ] - }, - { - "Name": "MyGame.AbstractBaseBallScript", - "BaseTypes": [ - { - "BaseName": "MyGame.BaseBallScript", - "DerivedName": "MyGame.BallScript" - } - ] - } - ], - "Arrays": [ - ], - "Delegates": [ - ] -} \ No newline at end of file diff --git a/Unity/Assets/Plugins.meta b/Unity/Assets/Plugins.meta deleted file mode 100644 index 8b2c0f9..0000000 --- a/Unity/Assets/Plugins.meta +++ /dev/null @@ -1,9 +0,0 @@ -fileFormatVersion: 2 -guid: 5bbab78bd1d4c466284a92dfc30ac8c8 -folderAsset: yes -timeCreated: 1502586836 -licenseType: Free -DefaultImporter: - userData: - assetBundleName: - assetBundleVariant: diff --git a/Unity/ProjectSettings/ProjectVersion.txt b/Unity/ProjectSettings/ProjectVersion.txt deleted file mode 100644 index 7e64146..0000000 --- a/Unity/ProjectSettings/ProjectVersion.txt +++ /dev/null @@ -1,2 +0,0 @@ -m_EditorVersion: 2019.2.0f1 -m_EditorVersionWithRevision: 2019.2.0f1 (20c1667945cf) From a26e528b6c256378df47ea7da0ffbf181fe68481 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=A2=81=E9=93=96?= <> Date: Tue, 20 Jan 2026 18:13:29 +0800 Subject: [PATCH 02/33] =?UTF-8?q?=E4=BC=98=E5=8C=96=EF=BC=9AHost=20API=20?= =?UTF-8?q?=E4=BF=9D=E6=8C=81=20BridgeStringView=20=E9=99=8D=E4=BD=8E=20GC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Core/Tools/BridgeGen/Program.cs | 5 ++-- Core/csharp/Bridge.Core/Interop/Structs.cs | 18 +++++++++++++ Core/docs/BRIDGE_DESIGN.md | 12 ++++++--- .../RobotHost/Bind/FileAssetProvider.cs | 18 ++++++++++++- Tests/csharp/RobotHost/Bind/RobotHostApi.cs | 4 +-- .../csharp/RobotHost/Bind/RobotNullHostApi.cs | 15 +++++------ Tests/csharp/RobotHost/Bind/WorldState.cs | 3 +-- .../Bridge.AllCommandDispatcher.g.cs | 4 +-- .../Generated/IDemoAssetHostApi.g.cs | 2 +- .../RobotHost/Generated/IDemoLogHostApi.g.cs | 2 +- .../Managed/Bridge.Core/Interop/Structs.cs | 18 +++++++++++++ .../BridgeDispatchPerformanceTests.cs | 22 ++++++++++++++-- .../Bridge.AllCommandDispatcher.g.cs | 4 +-- .../Generated/IDemoAssetHostApi.g.cs | 2 +- .../Generated/IDemoLogHostApi.g.cs | 2 +- .../Runtime/DemoGameUnityAssetService.cs | 26 ++++++++++++++----- .../Runtime/DemoGameUnityHostApi.Asset.cs | 4 +-- .../Runtime/DemoGameUnityHostApi.Log.cs | 15 ++++++----- 18 files changed, 134 insertions(+), 42 deletions(-) diff --git a/Core/Tools/BridgeGen/Program.cs b/Core/Tools/BridgeGen/Program.cs index 30c3ae5..2daea8e 100644 --- a/Core/Tools/BridgeGen/Program.cs +++ b/Core/Tools/BridgeGen/Program.cs @@ -702,7 +702,7 @@ private static string MapCsHostArgType(string cppType) { return cppType switch { - "BridgeStringView" => "string", + "BridgeStringView" => "BridgeStringView", "BridgeLogLevel" => "BridgeLogLevel", "BridgeAssetType" => "BridgeAssetType", "BridgeAssetStatus" => "BridgeAssetStatus", @@ -715,6 +715,8 @@ private static string MapCsHostArgType(string cppType) private static string MapCsCoreCallArgType(string cppType) { + if (cppType == "BridgeStringView") + throw new InvalidOperationException("Core API(Host->Core)禁止使用 BridgeStringView;请改为传 handle/hash/id。"); return MapCsHostArgType(cppType); } @@ -722,7 +724,6 @@ private static string MapCsHostArgExpr(string cppType, string fieldExpr) { return cppType switch { - "BridgeStringView" => $"{fieldExpr}.ToManagedString()", _ => fieldExpr }; } diff --git a/Core/csharp/Bridge.Core/Interop/Structs.cs b/Core/csharp/Bridge.Core/Interop/Structs.cs index be9b104..6c30587 100644 --- a/Core/csharp/Bridge.Core/Interop/Structs.cs +++ b/Core/csharp/Bridge.Core/Interop/Structs.cs @@ -47,6 +47,24 @@ public string ToManagedString() // netstandard2.1+ 支持按长度读取 UTF-8,避免额外分配 byte[]。 return Marshal.PtrToStringUTF8(new IntPtr(unchecked((long)Ptr)), (int)Len) ?? string.Empty; } + + public unsafe ulong Fnv1a64() + { + if (Ptr == 0 || Len == 0) + return 0; + + const ulong offset = 1469598103934665603ul; + const ulong prime = 1099511628211ul; + + ulong hash = offset; + byte* p = (byte*)Ptr; + for (uint i = 0; i < Len; i++) + { + hash ^= p[i]; + hash *= prime; + } + return hash; + } } public enum BridgeLogLevel : uint diff --git a/Core/docs/BRIDGE_DESIGN.md b/Core/docs/BRIDGE_DESIGN.md index cfd403c..bdd3277 100644 --- a/Core/docs/BRIDGE_DESIGN.md +++ b/Core/docs/BRIDGE_DESIGN.md @@ -24,6 +24,12 @@ 禁止跨边界传递 Unity 对象、托管对象、List/Dictionary 等。 +### BridgeStringView(UTF-8 ptr+len) + +- Core→Host:生成的 Host API 参数保持为 `BridgeStringView`(默认不转 `string`),需要时才 `ToManagedString()`。 +- Host→Core:禁止使用 `BridgeStringView`(指针生命周期仅当帧有效);请改为传 `handle/hash/id`,或在 Host 侧做 key→handle 映射。 +- 如需做缓存/查找:可用 `BridgeStringView.Fnv1a64()` 计算 key 哈希(无分配),仅在必要时再解码。 + ## 数据流 ### Core → Host(命令) @@ -103,10 +109,10 @@ Host 侧拿到 Core 输出的 `CommandStream` 后,需要把 `CallHost(func_id, 环境:Windows,Release,bots=1000,frames=300,dt=1/60。 - C#(`--host null`) - - `all`:约 14.95M cmd/s,分配 ~208KB + - `all`:约 15.01M cmd/s,分配 ~232 bytes - C#(`--host full`) - - `all`:约 8.64M cmd/s,分配 ~488KB -- C++ 解析 baseline(仅解析 command stream):约 40.49M cmd/s + - `all`:约 8.01M cmd/s,分配 ~280KB +- C++ 解析 baseline(仅解析 command stream):约 40.00M cmd/s - Unity(EditMode / Performance Test Framework) - `TickAndDispatch_OneFrame(1)`:Avg ~0.01 ms - `TickAndDispatch_OneFrame(1000)`:Avg ~0.27 ms diff --git a/Tests/csharp/RobotHost/Bind/FileAssetProvider.cs b/Tests/csharp/RobotHost/Bind/FileAssetProvider.cs index 5099084..73a8ca9 100644 --- a/Tests/csharp/RobotHost/Bind/FileAssetProvider.cs +++ b/Tests/csharp/RobotHost/Bind/FileAssetProvider.cs @@ -1,9 +1,11 @@ using System.Collections.Generic; +using Bridge.Core; sealed class FileAssetProvider { private readonly string _root; private readonly Dictionary _handleCache = new(StringComparer.Ordinal); + private readonly Dictionary _handleCacheByKeyHash = new(); public FileAssetProvider(string root) { @@ -31,6 +33,21 @@ public bool TryGetHandle(string assetKey, out ulong handle) return true; } + public bool TryGetHandle(BridgeStringView assetKey, out ulong handle) + { + ulong keyHash = assetKey.Fnv1a64(); + if (keyHash != 0 && _handleCacheByKeyHash.TryGetValue(keyHash, out handle)) + return handle != 0; + + string key = assetKey.ToManagedString(); + bool ok = TryGetHandle(key, out handle); + + if (keyHash != 0) + _handleCacheByKeyHash[keyHash] = ok ? handle : 0; + + return ok; + } + private string? ResolvePath(string assetKey) { if (string.IsNullOrWhiteSpace(assetKey)) @@ -65,4 +82,3 @@ private static ulong Fnv1a64(byte[] bytes) return hash; } } - diff --git a/Tests/csharp/RobotHost/Bind/RobotHostApi.cs b/Tests/csharp/RobotHost/Bind/RobotHostApi.cs index 3c8f964..d3e9ff6 100644 --- a/Tests/csharp/RobotHost/Bind/RobotHostApi.cs +++ b/Tests/csharp/RobotHost/Bind/RobotHostApi.cs @@ -21,14 +21,14 @@ public RobotHostApi(BridgeCore core, WorldState world, FileAssetProvider assets) _assets = assets; } - public void Log(BridgeLogLevel level, string message) + public void Log(BridgeLogLevel level, BridgeStringView message) { Commands++; Logs++; _world.OnLog(level, message); } - public void LoadAsset(ulong requestId, BridgeAssetType assetType, string assetKey) + public void LoadAsset(ulong requestId, BridgeAssetType assetType, BridgeStringView assetKey) { _ = assetType; diff --git a/Tests/csharp/RobotHost/Bind/RobotNullHostApi.cs b/Tests/csharp/RobotHost/Bind/RobotNullHostApi.cs index d3d29c8..b8580a6 100644 --- a/Tests/csharp/RobotHost/Bind/RobotNullHostApi.cs +++ b/Tests/csharp/RobotHost/Bind/RobotNullHostApi.cs @@ -4,7 +4,6 @@ sealed class RobotNullHostApi : IRobotHostApi { private readonly BridgeCore _core; - private readonly FileAssetProvider _assets; public ulong Commands { get; private set; } public ulong AssetRequests { get; private set; } @@ -16,10 +15,10 @@ sealed class RobotNullHostApi : IRobotHostApi public RobotNullHostApi(BridgeCore core, FileAssetProvider assets) { _core = core; - _assets = assets; + _ = assets; } - public void Log(BridgeLogLevel level, string message) + public void Log(BridgeLogLevel level, BridgeStringView message) { _ = level; _ = message; @@ -27,17 +26,17 @@ public void Log(BridgeLogLevel level, string message) Logs++; } - public void LoadAsset(ulong requestId, BridgeAssetType assetType, string assetKey) + public void LoadAsset(ulong requestId, BridgeAssetType assetType, BridgeStringView assetKey) { _ = assetType; Commands++; AssetRequests++; - if (_assets.TryGetHandle(assetKey, out ulong handle)) - _core.AssetLoaded(requestId, handle, BridgeAssetStatus.Ok); - else - _core.AssetLoaded(requestId, 0, BridgeAssetStatus.NotFound); + ulong handle = assetKey.Fnv1a64(); + if (handle == 0) + handle = 1; + _core.AssetLoaded(requestId, handle, BridgeAssetStatus.Ok); } public void SpawnEntity(ulong entityId, ulong prefabHandle, BridgeTransform transform, uint flags) diff --git a/Tests/csharp/RobotHost/Bind/WorldState.cs b/Tests/csharp/RobotHost/Bind/WorldState.cs index 5ad33d4..89c4f7c 100644 --- a/Tests/csharp/RobotHost/Bind/WorldState.cs +++ b/Tests/csharp/RobotHost/Bind/WorldState.cs @@ -5,7 +5,7 @@ sealed class WorldState { private readonly Dictionary _entities = new(); - public void OnLog(BridgeLogLevel level, string message) + public void OnLog(BridgeLogLevel level, BridgeStringView message) { _ = level; _ = message; @@ -46,4 +46,3 @@ public Entity(ulong prefabHandle, BridgeTransform transform) } } } - diff --git a/Tests/csharp/RobotHost/Generated/Bridge.AllCommandDispatcher.g.cs b/Tests/csharp/RobotHost/Generated/Bridge.AllCommandDispatcher.g.cs index 1052c03..65ac9e0 100644 --- a/Tests/csharp/RobotHost/Generated/Bridge.AllCommandDispatcher.g.cs +++ b/Tests/csharp/RobotHost/Generated/Bridge.AllCommandDispatcher.g.cs @@ -48,7 +48,7 @@ public static unsafe void Dispatch(CommandStream stream, THost host) if (payloadSize == (uint)sizeof(DemoAsset.Bindings.HostArgs_LoadAsset)) { var a = *((DemoAsset.Bindings.HostArgs_LoadAsset*)payloadPtr); - host.LoadAsset(a.RequestId, a.AssetType, a.AssetKey.ToManagedString()); + host.LoadAsset(a.RequestId, a.AssetType, a.AssetKey); } break; } @@ -84,7 +84,7 @@ public static unsafe void Dispatch(CommandStream stream, THost host) if (payloadSize == (uint)sizeof(DemoLog.Bindings.HostArgs_Log)) { var a = *((DemoLog.Bindings.HostArgs_Log*)payloadPtr); - host.Log(a.Level, a.Message.ToManagedString()); + host.Log(a.Level, a.Message); } break; } diff --git a/Tests/csharp/RobotHost/Generated/IDemoAssetHostApi.g.cs b/Tests/csharp/RobotHost/Generated/IDemoAssetHostApi.g.cs index c5fa10d..b0f6ac0 100644 --- a/Tests/csharp/RobotHost/Generated/IDemoAssetHostApi.g.cs +++ b/Tests/csharp/RobotHost/Generated/IDemoAssetHostApi.g.cs @@ -8,6 +8,6 @@ namespace DemoAsset.Bindings { public interface IDemoAssetHostApi { - void LoadAsset(ulong requestId, BridgeAssetType assetType, string assetKey); + void LoadAsset(ulong requestId, BridgeAssetType assetType, BridgeStringView assetKey); } } diff --git a/Tests/csharp/RobotHost/Generated/IDemoLogHostApi.g.cs b/Tests/csharp/RobotHost/Generated/IDemoLogHostApi.g.cs index 41676fb..dd59015 100644 --- a/Tests/csharp/RobotHost/Generated/IDemoLogHostApi.g.cs +++ b/Tests/csharp/RobotHost/Generated/IDemoLogHostApi.g.cs @@ -8,6 +8,6 @@ namespace DemoLog.Bindings { public interface IDemoLogHostApi { - void Log(BridgeLogLevel level, string message); + void Log(BridgeLogLevel level, BridgeStringView message); } } diff --git a/Tests/unity/Assets/BridgeCore/Managed/Bridge.Core/Interop/Structs.cs b/Tests/unity/Assets/BridgeCore/Managed/Bridge.Core/Interop/Structs.cs index be9b104..6c30587 100644 --- a/Tests/unity/Assets/BridgeCore/Managed/Bridge.Core/Interop/Structs.cs +++ b/Tests/unity/Assets/BridgeCore/Managed/Bridge.Core/Interop/Structs.cs @@ -47,6 +47,24 @@ public string ToManagedString() // netstandard2.1+ 支持按长度读取 UTF-8,避免额外分配 byte[]。 return Marshal.PtrToStringUTF8(new IntPtr(unchecked((long)Ptr)), (int)Len) ?? string.Empty; } + + public unsafe ulong Fnv1a64() + { + if (Ptr == 0 || Len == 0) + return 0; + + const ulong offset = 1469598103934665603ul; + const ulong prime = 1099511628211ul; + + ulong hash = offset; + byte* p = (byte*)Ptr; + for (uint i = 0; i < Len; i++) + { + hash ^= p[i]; + hash *= prime; + } + return hash; + } } public enum BridgeLogLevel : uint diff --git a/Tests/unity/Assets/BridgeDemoGame/Editor/Performance/BridgeDispatchPerformanceTests.cs b/Tests/unity/Assets/BridgeDemoGame/Editor/Performance/BridgeDispatchPerformanceTests.cs index 4d91eed..7bbf1df 100644 --- a/Tests/unity/Assets/BridgeDemoGame/Editor/Performance/BridgeDispatchPerformanceTests.cs +++ b/Tests/unity/Assets/BridgeDemoGame/Editor/Performance/BridgeDispatchPerformanceTests.cs @@ -20,7 +20,7 @@ public NullHostApi(BridgeCore core) _core = core; } - public void LoadAsset(ulong requestId, BridgeAssetType assetType, string assetKey) + public void LoadAsset(ulong requestId, BridgeAssetType assetType, BridgeStringView assetKey) { _ = assetType; _ = assetKey; @@ -47,13 +47,31 @@ public void DestroyEntity(ulong entityId) _ = entityId; } - public void Log(BridgeLogLevel level, string message) + public void Log(BridgeLogLevel level, BridgeStringView message) { _ = level; _ = message; } } + [Test, Performance] + [TestCase(1)] + [TestCase(1000)] + public void EmptyLoop(int bots) + { + Measure.Method(() => + { + for (int i = 0; i < bots; i++) + { + } + }) + .WarmupCount(5) + .MeasurementCount(30) + .IterationsPerMeasurement(1) + .GC() + .Run(); + } + [Test, Performance] [TestCase(1)] [TestCase(1000)] diff --git a/Tests/unity/Assets/BridgeDemoGame/Generated/Bridge.AllCommandDispatcher.g.cs b/Tests/unity/Assets/BridgeDemoGame/Generated/Bridge.AllCommandDispatcher.g.cs index 1052c03..65ac9e0 100644 --- a/Tests/unity/Assets/BridgeDemoGame/Generated/Bridge.AllCommandDispatcher.g.cs +++ b/Tests/unity/Assets/BridgeDemoGame/Generated/Bridge.AllCommandDispatcher.g.cs @@ -48,7 +48,7 @@ public static unsafe void Dispatch(CommandStream stream, THost host) if (payloadSize == (uint)sizeof(DemoAsset.Bindings.HostArgs_LoadAsset)) { var a = *((DemoAsset.Bindings.HostArgs_LoadAsset*)payloadPtr); - host.LoadAsset(a.RequestId, a.AssetType, a.AssetKey.ToManagedString()); + host.LoadAsset(a.RequestId, a.AssetType, a.AssetKey); } break; } @@ -84,7 +84,7 @@ public static unsafe void Dispatch(CommandStream stream, THost host) if (payloadSize == (uint)sizeof(DemoLog.Bindings.HostArgs_Log)) { var a = *((DemoLog.Bindings.HostArgs_Log*)payloadPtr); - host.Log(a.Level, a.Message.ToManagedString()); + host.Log(a.Level, a.Message); } break; } diff --git a/Tests/unity/Assets/BridgeDemoGame/Generated/IDemoAssetHostApi.g.cs b/Tests/unity/Assets/BridgeDemoGame/Generated/IDemoAssetHostApi.g.cs index c5fa10d..b0f6ac0 100644 --- a/Tests/unity/Assets/BridgeDemoGame/Generated/IDemoAssetHostApi.g.cs +++ b/Tests/unity/Assets/BridgeDemoGame/Generated/IDemoAssetHostApi.g.cs @@ -8,6 +8,6 @@ namespace DemoAsset.Bindings { public interface IDemoAssetHostApi { - void LoadAsset(ulong requestId, BridgeAssetType assetType, string assetKey); + void LoadAsset(ulong requestId, BridgeAssetType assetType, BridgeStringView assetKey); } } diff --git a/Tests/unity/Assets/BridgeDemoGame/Generated/IDemoLogHostApi.g.cs b/Tests/unity/Assets/BridgeDemoGame/Generated/IDemoLogHostApi.g.cs index 41676fb..dd59015 100644 --- a/Tests/unity/Assets/BridgeDemoGame/Generated/IDemoLogHostApi.g.cs +++ b/Tests/unity/Assets/BridgeDemoGame/Generated/IDemoLogHostApi.g.cs @@ -8,6 +8,6 @@ namespace DemoLog.Bindings { public interface IDemoLogHostApi { - void Log(BridgeLogLevel level, string message); + void Log(BridgeLogLevel level, BridgeStringView message); } } diff --git a/Tests/unity/Assets/BridgeDemoGame/Runtime/DemoGameUnityAssetService.cs b/Tests/unity/Assets/BridgeDemoGame/Runtime/DemoGameUnityAssetService.cs index 9e9bbd2..f63ae70 100644 --- a/Tests/unity/Assets/BridgeDemoGame/Runtime/DemoGameUnityAssetService.cs +++ b/Tests/unity/Assets/BridgeDemoGame/Runtime/DemoGameUnityAssetService.cs @@ -9,6 +9,7 @@ namespace BridgeDemoGame { public sealed class DemoGameUnityAssetService : MonoBehaviour { + private readonly Dictionary _assetKeyIntern = new Dictionary(); private readonly Dictionary _pending = new Dictionary(StringComparer.Ordinal); private readonly Dictionary _assetKeyToHandle = new Dictionary(StringComparer.Ordinal); private readonly Dictionary _handleToAsset = new Dictionary(); @@ -18,7 +19,7 @@ public bool TryGetTextAsset(ulong handle, out TextAsset asset) return _handleToAsset.TryGetValue(handle, out asset); } - public void RequestLoad(BridgeCore core, ulong requestId, BridgeAssetType assetType, string assetKey) + public void RequestLoad(BridgeCore core, ulong requestId, BridgeAssetType assetType, BridgeStringView assetKey) { if (core == null) return; @@ -29,30 +30,43 @@ public void RequestLoad(BridgeCore core, ulong requestId, BridgeAssetType assetT return; } - if (string.IsNullOrEmpty(assetKey)) + if (assetKey.Ptr == 0 || assetKey.Len == 0) { core.AssetLoaded(requestId, 0, BridgeAssetStatus.NotFound); return; } - if (_assetKeyToHandle.TryGetValue(assetKey, out ulong cachedHandle) && cachedHandle != 0) + string key = InternKey(assetKey); + if (_assetKeyToHandle.TryGetValue(key, out ulong cachedHandle) && cachedHandle != 0) { core.AssetLoaded(requestId, cachedHandle, BridgeAssetStatus.Ok); return; } - if (_pending.TryGetValue(assetKey, out PendingAssetLoad pending)) + if (_pending.TryGetValue(key, out PendingAssetLoad pending)) { pending.Waiters.Add(new PendingRequest(core, requestId)); return; } - pending = new PendingAssetLoad(assetKey); + pending = new PendingAssetLoad(key); pending.Waiters.Add(new PendingRequest(core, requestId)); - _pending.Add(assetKey, pending); + _pending.Add(key, pending); StartCoroutine(LoadCoroutine(pending)); } + private string InternKey(BridgeStringView key) + { + ulong hash = key.Fnv1a64(); + if (hash != 0 && _assetKeyIntern.TryGetValue(hash, out string cached) && !string.IsNullOrEmpty(cached)) + return cached; + + string s = key.ToManagedString(); + if (hash != 0 && !string.IsNullOrEmpty(s)) + _assetKeyIntern[hash] = s; + return s; + } + private IEnumerator LoadCoroutine(PendingAssetLoad pending) { ResourceRequest req = Resources.LoadAsync(pending.AssetKey); diff --git a/Tests/unity/Assets/BridgeDemoGame/Runtime/DemoGameUnityHostApi.Asset.cs b/Tests/unity/Assets/BridgeDemoGame/Runtime/DemoGameUnityHostApi.Asset.cs index b27941f..40bcfed 100644 --- a/Tests/unity/Assets/BridgeDemoGame/Runtime/DemoGameUnityHostApi.Asset.cs +++ b/Tests/unity/Assets/BridgeDemoGame/Runtime/DemoGameUnityHostApi.Asset.cs @@ -5,7 +5,7 @@ namespace BridgeDemoGame { public sealed partial class DemoGameUnityHostApi : IDemoAssetHostApi { - public void LoadAsset(ulong requestId, BridgeAssetType assetType, string assetKey) + public void LoadAsset(ulong requestId, BridgeAssetType assetType, BridgeStringView assetKey) { Commands++; AssetRequests++; @@ -13,4 +13,4 @@ public void LoadAsset(ulong requestId, BridgeAssetType assetType, string assetKe _assets.RequestLoad(_core, requestId, assetType, assetKey); } } -} \ No newline at end of file +} diff --git a/Tests/unity/Assets/BridgeDemoGame/Runtime/DemoGameUnityHostApi.Log.cs b/Tests/unity/Assets/BridgeDemoGame/Runtime/DemoGameUnityHostApi.Log.cs index 11e228f..f6e9b36 100644 --- a/Tests/unity/Assets/BridgeDemoGame/Runtime/DemoGameUnityHostApi.Log.cs +++ b/Tests/unity/Assets/BridgeDemoGame/Runtime/DemoGameUnityHostApi.Log.cs @@ -6,27 +6,30 @@ namespace BridgeDemoGame { public sealed partial class DemoGameUnityHostApi: IDemoLogHostApi { - public void Log(BridgeLogLevel level, string message) + public void Log(BridgeLogLevel level, BridgeStringView message) { Commands++; Logs++; + if (!_enableRendering) + return; + + string msg = message.ToManagedString(); switch (level) { case BridgeLogLevel.Debug: - Debug.Log(message); + Debug.Log(msg); break; case BridgeLogLevel.Info: - Debug.Log(message); + Debug.Log(msg); break; case BridgeLogLevel.Warn: - Debug.LogWarning(message); + Debug.LogWarning(msg); break; default: - Debug.LogError(message); + Debug.LogError(msg); break; } } } } - From 3530b16d19f81b6be47d384b3a5f578d6bad9c1b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=A2=81=E9=93=96?= <> Date: Tue, 20 Jan 2026 18:17:30 +0800 Subject: [PATCH 03/33] =?UTF-8?q?perf:=20Unity=20=E6=80=A7=E8=83=BD?= =?UTF-8?q?=E6=B5=8B=E8=AF=95=E8=AE=B0=E5=BD=95=20GC.Alloc.Bytes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Core/docs/BRIDGE_DESIGN.md | 1 + .../BridgeDispatchPerformanceTests.cs | 19 +++++++++++++++++-- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/Core/docs/BRIDGE_DESIGN.md b/Core/docs/BRIDGE_DESIGN.md index bdd3277..2dd7dac 100644 --- a/Core/docs/BRIDGE_DESIGN.md +++ b/Core/docs/BRIDGE_DESIGN.md @@ -116,6 +116,7 @@ Host 侧拿到 Core 输出的 `CommandStream` 后,需要把 `CallHost(func_id, - Unity(EditMode / Performance Test Framework) - `TickAndDispatch_OneFrame(1)`:Avg ~0.01 ms - `TickAndDispatch_OneFrame(1000)`:Avg ~0.27 ms + - `GC.Alloc.Bytes`:Avg = 0 b(基于 `GC.GetAllocatedBytesForCurrentThread()` 的自定义指标) 对应命令: diff --git a/Tests/unity/Assets/BridgeDemoGame/Editor/Performance/BridgeDispatchPerformanceTests.cs b/Tests/unity/Assets/BridgeDemoGame/Editor/Performance/BridgeDispatchPerformanceTests.cs index 7bbf1df..6c63252 100644 --- a/Tests/unity/Assets/BridgeDemoGame/Editor/Performance/BridgeDispatchPerformanceTests.cs +++ b/Tests/unity/Assets/BridgeDemoGame/Editor/Performance/BridgeDispatchPerformanceTests.cs @@ -11,6 +11,8 @@ namespace BridgeDemoGame.Tests { public sealed class BridgeDispatchPerformanceTests { + private static readonly SampleGroup AllocatedBytes = new SampleGroup("GC.Alloc.Bytes", SampleUnit.Byte, false); + private sealed class NullHostApi : IDemoAssetHostApi, IDemoEntityHostApi, IDemoLogHostApi { private readonly BridgeCore _core; @@ -59,16 +61,23 @@ public void Log(BridgeLogLevel level, BridgeStringView message) [TestCase(1000)] public void EmptyLoop(int bots) { + long allocBefore = 0; + Measure.Method(() => { for (int i = 0; i < bots; i++) { } }) + .SetUp(() => allocBefore = System.GC.GetAllocatedBytesForCurrentThread()) + .CleanUp(() => + { + long allocAfter = System.GC.GetAllocatedBytesForCurrentThread(); + Measure.Custom(AllocatedBytes, allocAfter - allocBefore); + }) .WarmupCount(5) .MeasurementCount(30) .IterationsPerMeasurement(1) - .GC() .Run(); } @@ -93,6 +102,7 @@ public void TickAndDispatch_OneFrame(int bots) } const float dt = 1.0f / 60.0f; + long allocBefore = 0; try { @@ -106,10 +116,15 @@ public void TickAndDispatch_OneFrame(int bots) BridgeAllCommandDispatcher.Dispatch(stream, hosts[i]); } }) + .SetUp(() => allocBefore = System.GC.GetAllocatedBytesForCurrentThread()) + .CleanUp(() => + { + long allocAfter = System.GC.GetAllocatedBytesForCurrentThread(); + Measure.Custom(AllocatedBytes, allocAfter - allocBefore); + }) .WarmupCount(5) .MeasurementCount(30) .IterationsPerMeasurement(1) - .GC() .Run(); } finally From ef3d267095dca86814cba57e43c6f184c9b893a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=A2=81=E9=93=96?= <> Date: Tue, 20 Jan 2026 18:20:15 +0800 Subject: [PATCH 04/33] =?UTF-8?q?perf:=20RobotHost=20=E9=A2=84=E5=88=86?= =?UTF-8?q?=E9=85=8D=20WorldState=20=E5=87=8F=E5=B0=91=E8=BF=90=E8=A1=8C?= =?UTF-8?q?=E6=9C=9F=20GC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Core/docs/BRIDGE_DESIGN.md | 2 +- Tests/csharp/RobotHost/Bind/WorldState.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Core/docs/BRIDGE_DESIGN.md b/Core/docs/BRIDGE_DESIGN.md index 2dd7dac..b21158a 100644 --- a/Core/docs/BRIDGE_DESIGN.md +++ b/Core/docs/BRIDGE_DESIGN.md @@ -111,7 +111,7 @@ Host 侧拿到 Core 输出的 `CommandStream` 后,需要把 `CallHost(func_id, - C#(`--host null`) - `all`:约 15.01M cmd/s,分配 ~232 bytes - C#(`--host full`) - - `all`:约 8.01M cmd/s,分配 ~280KB + - `all`:约 8.26M cmd/s,分配 ~512 bytes(示例 WorldState 预分配避免运行期扩容) - C++ 解析 baseline(仅解析 command stream):约 40.00M cmd/s - Unity(EditMode / Performance Test Framework) - `TickAndDispatch_OneFrame(1)`:Avg ~0.01 ms diff --git a/Tests/csharp/RobotHost/Bind/WorldState.cs b/Tests/csharp/RobotHost/Bind/WorldState.cs index 89c4f7c..136bedc 100644 --- a/Tests/csharp/RobotHost/Bind/WorldState.cs +++ b/Tests/csharp/RobotHost/Bind/WorldState.cs @@ -3,7 +3,7 @@ sealed class WorldState { - private readonly Dictionary _entities = new(); + private readonly Dictionary _entities = new(capacity: 4); public void OnLog(BridgeLogLevel level, BridgeStringView message) { From 16e13ad1482f2bf025f31849581a39b21c28b07f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=A2=81=E9=93=96?= <> Date: Tue, 20 Jan 2026 18:49:08 +0800 Subject: [PATCH 05/33] =?UTF-8?q?perf:=20=E5=90=88=E5=B9=B6=20Tick+GetComm?= =?UTF-8?q?andStream=20=E5=B9=B6=E4=BC=98=E5=8C=96=20command=20stream?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Core/Tools/BridgeGen/Program.cs | 8 +++----- Core/cpp/include/bridge/bridge.h | 11 ++++++++++- Core/cpp/src/api/bridge_api.cpp | 14 ++++++++++++++ Core/cpp/src/core/command_stream.cpp | 14 ++++++++++---- Core/cpp/src/core/command_stream.h | 1 + Core/csharp/Bridge.Core/BridgeCore.cs | 13 +++++++++++++ .../csharp/Bridge.Core/Interop/BridgeNative.cs | 7 +++++++ .../Generated/Bridge.AllCommandDispatcher.g.cs | 8 +++----- Tests/csharp/RobotHost/Program.cs | 8 ++------ .../Managed/Bridge.Core/BridgeCore.cs | 13 +++++++++++++ .../Bridge.Core/Interop/BridgeNative.cs | 18 ++++++++++++++++++ .../BridgeDispatchPerformanceTests.cs | 3 +-- .../Generated/Bridge.AllCommandDispatcher.g.cs | 8 +++----- .../Runtime/DemoGameUnityHostApi.Entity.cs | 2 +- .../Runtime/DemoGameUnityHostApi.cs | 2 +- .../Runtime/DemoGameUnityRunner.cs | 4 +--- 16 files changed, 101 insertions(+), 33 deletions(-) diff --git a/Core/Tools/BridgeGen/Program.cs b/Core/Tools/BridgeGen/Program.cs index 2daea8e..d9db863 100644 --- a/Core/Tools/BridgeGen/Program.cs +++ b/Core/Tools/BridgeGen/Program.cs @@ -497,15 +497,13 @@ private static string EmitAllDispatcher(IReadOnlyList modules) sb.AppendLine(); sb.AppendLine(" while (cursor < end)"); sb.AppendLine(" {"); - sb.AppendLine(" long remaining = end - cursor;"); - sb.AppendLine(" if (remaining < sizeof(BridgeCommandHeader))"); + sb.AppendLine(" int remaining = (int)(end - cursor);"); + sb.AppendLine(" if (remaining < (int)sizeof(BridgeCommandHeader))"); sb.AppendLine(" break;"); sb.AppendLine(); sb.AppendLine(" var header = (BridgeCommandHeader*)cursor;"); sb.AppendLine(" int size = header->Size;"); - sb.AppendLine(" if (size <= 0)"); - sb.AppendLine(" break;"); - sb.AppendLine(" if (size < sizeof(BridgeCommandHeader) || size > remaining)"); + sb.AppendLine(" if ((uint)size < (uint)sizeof(BridgeCommandHeader) || (uint)size > (uint)remaining)"); sb.AppendLine(" break;"); sb.AppendLine(); sb.AppendLine(" if (header->Type == (ushort)BridgeCommandType.CallHost && size >= sizeof(BridgeCmdCallHost))"); diff --git a/Core/cpp/include/bridge/bridge.h b/Core/cpp/include/bridge/bridge.h index b25ab4f..54af2ed 100644 --- a/Core/cpp/include/bridge/bridge.h +++ b/Core/cpp/include/bridge/bridge.h @@ -174,6 +174,16 @@ typedef struct BridgeCmdCallHost BRIDGE_API void BRIDGE_CALL BridgeCore_Tick(BridgeCore* core, float dt); +// 组合调用:Tick + GetCommandStream(减少 Host 侧 P/Invoke 次数)。 +// 等价于: +// BridgeCore_Tick(core, dt); +// BridgeCore_GetCommandStream(core, out_ptr, out_len); +BRIDGE_API BridgeResult BRIDGE_CALL BridgeCore_TickAndGetCommandStream( + BridgeCore* core, + float dt, + const void** out_ptr, + uint32_t* out_len); + // 返回最近一次 BridgeCore_Tick 生成的 command stream(连续字节流)指针。 // 返回的内存由 Core 持有,只保证在下一次 BridgeCore_Tick(或 BridgeCore_Destroy)前有效。 BRIDGE_API BridgeResult BRIDGE_CALL BridgeCore_GetCommandStream( @@ -196,4 +206,3 @@ BRIDGE_API BridgeResult BRIDGE_CALL BridgeCore_PushCallCore( #ifdef __cplusplus } // extern "C" #endif - diff --git a/Core/cpp/src/api/bridge_api.cpp b/Core/cpp/src/api/bridge_api.cpp index 310ee19..0b35edc 100644 --- a/Core/cpp/src/api/bridge_api.cpp +++ b/Core/cpp/src/api/bridge_api.cpp @@ -33,6 +33,20 @@ void BRIDGE_CALL BridgeCore_Tick(BridgeCore* core, float dt) bridge::Tick(*core, dt); } +BridgeResult BRIDGE_CALL BridgeCore_TickAndGetCommandStream( + BridgeCore* core, + float dt, + const void** out_ptr, + uint32_t* out_len) +{ + if (!core) + { + return BRIDGE_INVALID_ARGUMENT; + } + bridge::Tick(*core, dt); + return bridge::GetCommandStream(*core, out_ptr, out_len); +} + BridgeResult BRIDGE_CALL BridgeCore_GetCommandStream( const BridgeCore* core, const void** out_ptr, diff --git a/Core/cpp/src/core/command_stream.cpp b/Core/cpp/src/core/command_stream.cpp index 55d1e19..11abf6a 100644 --- a/Core/cpp/src/core/command_stream.cpp +++ b/Core/cpp/src/core/command_stream.cpp @@ -11,15 +11,22 @@ namespace bridge void CommandStream::Clear() { bytes_.clear(); - strings_.clear(); + strings_used_ = 0; } BridgeStringView CommandStream::StoreUtf8(std::string utf8) { - auto stored = std::make_unique(std::move(utf8)); + if (strings_used_ >= strings_.size()) + { + strings_.emplace_back(std::make_unique()); + } + + std::string* stored = strings_[strings_used_].get(); + *stored = std::move(utf8); + const char* p = stored->data(); const uint32_t len = static_cast(stored->size()); - strings_.emplace_back(std::move(stored)); + strings_used_++; BridgeStringView view{}; view.ptr = static_cast(reinterpret_cast(p)); @@ -37,4 +44,3 @@ namespace bridge return static_cast(bytes_.size()); } } - diff --git a/Core/cpp/src/core/command_stream.h b/Core/cpp/src/core/command_stream.h index 7016c51..410bdc5 100644 --- a/Core/cpp/src/core/command_stream.h +++ b/Core/cpp/src/core/command_stream.h @@ -67,5 +67,6 @@ namespace bridge private: std::vector bytes_; std::vector> strings_; + size_t strings_used_ = 0; }; } diff --git a/Core/csharp/Bridge.Core/BridgeCore.cs b/Core/csharp/Bridge.Core/BridgeCore.cs index 540fe45..34d2d7d 100644 --- a/Core/csharp/Bridge.Core/BridgeCore.cs +++ b/Core/csharp/Bridge.Core/BridgeCore.cs @@ -31,6 +31,19 @@ public void Tick(float dt) BridgeNative.BridgeCore_Tick(_handle, dt); } + /// + /// 推进 Core 一帧,并直接返回本帧生成的命令字节流(减少一次 P/Invoke)。 + /// + public CommandStream TickAndGetCommandStream(float dt) + { + ThrowIfDisposed(); + var result = BridgeNative.BridgeCore_TickAndGetCommandStream(_handle, dt, out var ptr, out var len); + if (result != BridgeResult.Ok || ptr == IntPtr.Zero || len == 0) + return CommandStream.Empty; + + return new CommandStream(ptr, len); + } + /// /// 获取最近一次 生成的命令字节流(command stream)。 /// diff --git a/Core/csharp/Bridge.Core/Interop/BridgeNative.cs b/Core/csharp/Bridge.Core/Interop/BridgeNative.cs index 1d65fce..3f772c8 100644 --- a/Core/csharp/Bridge.Core/Interop/BridgeNative.cs +++ b/Core/csharp/Bridge.Core/Interop/BridgeNative.cs @@ -19,6 +19,13 @@ internal static class BridgeNative [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl)] internal static extern void BridgeCore_Tick(IntPtr core, float dt); + [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern BridgeResult BridgeCore_TickAndGetCommandStream( + IntPtr core, + float dt, + out IntPtr ptr, + out uint len); + [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl)] internal static extern BridgeResult BridgeCore_GetCommandStream( IntPtr core, diff --git a/Tests/csharp/RobotHost/Generated/Bridge.AllCommandDispatcher.g.cs b/Tests/csharp/RobotHost/Generated/Bridge.AllCommandDispatcher.g.cs index 65ac9e0..70f722f 100644 --- a/Tests/csharp/RobotHost/Generated/Bridge.AllCommandDispatcher.g.cs +++ b/Tests/csharp/RobotHost/Generated/Bridge.AllCommandDispatcher.g.cs @@ -22,15 +22,13 @@ public static unsafe void Dispatch(CommandStream stream, THost host) while (cursor < end) { - long remaining = end - cursor; - if (remaining < sizeof(BridgeCommandHeader)) + int remaining = (int)(end - cursor); + if (remaining < (int)sizeof(BridgeCommandHeader)) break; var header = (BridgeCommandHeader*)cursor; int size = header->Size; - if (size <= 0) - break; - if (size < sizeof(BridgeCommandHeader) || size > remaining) + if ((uint)size < (uint)sizeof(BridgeCommandHeader) || (uint)size > (uint)remaining) break; if (header->Type == (ushort)BridgeCommandType.CallHost && size >= sizeof(BridgeCmdCallHost)) diff --git a/Tests/csharp/RobotHost/Program.cs b/Tests/csharp/RobotHost/Program.cs index ed7d429..0ee3903 100644 --- a/Tests/csharp/RobotHost/Program.cs +++ b/Tests/csharp/RobotHost/Program.cs @@ -116,9 +116,7 @@ private static RunResult Run(int bots, int frames, float dt, string assetsRoot, for (int i = 0; i < cores.Length; i++) { var core = cores[i]; - core.Tick(dt); - - var stream = core.GetCommandStream(); + var stream = core.TickAndGetCommandStream(dt); BridgeAllCommandDispatcher.Dispatch(stream, hosts[i]); } } @@ -181,9 +179,7 @@ private static RunResult Run(int bots, int frames, float dt, string assetsRoot, for (int i = 0; i < cores.Length; i++) { var core = cores[i]; - core.Tick(dt); - - var stream = core.GetCommandStream(); + var stream = core.TickAndGetCommandStream(dt); BridgeAllCommandDispatcher.Dispatch(stream, hosts[i]); } } diff --git a/Tests/unity/Assets/BridgeCore/Managed/Bridge.Core/BridgeCore.cs b/Tests/unity/Assets/BridgeCore/Managed/Bridge.Core/BridgeCore.cs index 540fe45..34d2d7d 100644 --- a/Tests/unity/Assets/BridgeCore/Managed/Bridge.Core/BridgeCore.cs +++ b/Tests/unity/Assets/BridgeCore/Managed/Bridge.Core/BridgeCore.cs @@ -31,6 +31,19 @@ public void Tick(float dt) BridgeNative.BridgeCore_Tick(_handle, dt); } + /// + /// 推进 Core 一帧,并直接返回本帧生成的命令字节流(减少一次 P/Invoke)。 + /// + public CommandStream TickAndGetCommandStream(float dt) + { + ThrowIfDisposed(); + var result = BridgeNative.BridgeCore_TickAndGetCommandStream(_handle, dt, out var ptr, out var len); + if (result != BridgeResult.Ok || ptr == IntPtr.Zero || len == 0) + return CommandStream.Empty; + + return new CommandStream(ptr, len); + } + /// /// 获取最近一次 生成的命令字节流(command stream)。 /// diff --git a/Tests/unity/Assets/BridgeCore/Managed/Bridge.Core/Interop/BridgeNative.cs b/Tests/unity/Assets/BridgeCore/Managed/Bridge.Core/Interop/BridgeNative.cs index 4840b9a..b170c1b 100644 --- a/Tests/unity/Assets/BridgeCore/Managed/Bridge.Core/Interop/BridgeNative.cs +++ b/Tests/unity/Assets/BridgeCore/Managed/Bridge.Core/Interop/BridgeNative.cs @@ -25,6 +25,9 @@ internal static class BridgeNative [UnmanagedFunctionPointer(CallingConvention.Cdecl)] private delegate void BridgeCore_TickDelegate(IntPtr core, float dt); + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + private delegate BridgeResult BridgeCore_TickAndGetCommandStreamDelegate(IntPtr core, float dt, out IntPtr ptr, out uint len); + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] private delegate BridgeResult BridgeCore_GetCommandStreamDelegate(IntPtr core, out IntPtr ptr, out uint len); @@ -36,6 +39,7 @@ internal static class BridgeNative private static BridgeCore_CreateDelegate s_create; private static BridgeCore_DestroyDelegate s_destroy; private static BridgeCore_TickDelegate s_tick; + private static BridgeCore_TickAndGetCommandStreamDelegate s_tickAndGetCommandStream; private static BridgeCore_GetCommandStreamDelegate s_getCommandStream; private static BridgeCore_PushCallCoreDelegate s_pushCallCore; @@ -54,6 +58,7 @@ private static void EnsureBound() s_create = GetDelegate(module, "BridgeCore_Create"); s_destroy = GetDelegate(module, "BridgeCore_Destroy"); s_tick = GetDelegate(module, "BridgeCore_Tick"); + s_tickAndGetCommandStream = GetDelegate(module, "BridgeCore_TickAndGetCommandStream"); s_getCommandStream = GetDelegate(module, "BridgeCore_GetCommandStream"); s_pushCallCore = GetDelegate(module, "BridgeCore_PushCallCore"); s_boundModule = module; @@ -92,6 +97,12 @@ internal static void BridgeCore_Tick(IntPtr core, float dt) s_tick(core, dt); } + internal static BridgeResult BridgeCore_TickAndGetCommandStream(IntPtr core, float dt, out IntPtr ptr, out uint len) + { + EnsureBound(); + return s_tickAndGetCommandStream(core, dt, out ptr, out len); + } + internal static BridgeResult BridgeCore_GetCommandStream(IntPtr core, out IntPtr ptr, out uint len) { EnsureBound(); @@ -118,6 +129,13 @@ internal static BridgeResult BridgeCore_PushCallCore(IntPtr core, uint funcId, I [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl)] internal static extern void BridgeCore_Tick(IntPtr core, float dt); + [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern BridgeResult BridgeCore_TickAndGetCommandStream( + IntPtr core, + float dt, + out IntPtr ptr, + out uint len); + [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl)] internal static extern BridgeResult BridgeCore_GetCommandStream( IntPtr core, diff --git a/Tests/unity/Assets/BridgeDemoGame/Editor/Performance/BridgeDispatchPerformanceTests.cs b/Tests/unity/Assets/BridgeDemoGame/Editor/Performance/BridgeDispatchPerformanceTests.cs index 6c63252..3805116 100644 --- a/Tests/unity/Assets/BridgeDemoGame/Editor/Performance/BridgeDispatchPerformanceTests.cs +++ b/Tests/unity/Assets/BridgeDemoGame/Editor/Performance/BridgeDispatchPerformanceTests.cs @@ -111,8 +111,7 @@ public void TickAndDispatch_OneFrame(int bots) for (int i = 0; i < bots; i++) { var core = cores[i]; - core.Tick(dt); - var stream = core.GetCommandStream(); + var stream = core.TickAndGetCommandStream(dt); BridgeAllCommandDispatcher.Dispatch(stream, hosts[i]); } }) diff --git a/Tests/unity/Assets/BridgeDemoGame/Generated/Bridge.AllCommandDispatcher.g.cs b/Tests/unity/Assets/BridgeDemoGame/Generated/Bridge.AllCommandDispatcher.g.cs index 65ac9e0..70f722f 100644 --- a/Tests/unity/Assets/BridgeDemoGame/Generated/Bridge.AllCommandDispatcher.g.cs +++ b/Tests/unity/Assets/BridgeDemoGame/Generated/Bridge.AllCommandDispatcher.g.cs @@ -22,15 +22,13 @@ public static unsafe void Dispatch(CommandStream stream, THost host) while (cursor < end) { - long remaining = end - cursor; - if (remaining < sizeof(BridgeCommandHeader)) + int remaining = (int)(end - cursor); + if (remaining < (int)sizeof(BridgeCommandHeader)) break; var header = (BridgeCommandHeader*)cursor; int size = header->Size; - if (size <= 0) - break; - if (size < sizeof(BridgeCommandHeader) || size > remaining) + if ((uint)size < (uint)sizeof(BridgeCommandHeader) || (uint)size > (uint)remaining) break; if (header->Type == (ushort)BridgeCommandType.CallHost && size >= sizeof(BridgeCmdCallHost)) diff --git a/Tests/unity/Assets/BridgeDemoGame/Runtime/DemoGameUnityHostApi.Entity.cs b/Tests/unity/Assets/BridgeDemoGame/Runtime/DemoGameUnityHostApi.Entity.cs index eaf1e6d..64eef91 100644 --- a/Tests/unity/Assets/BridgeDemoGame/Runtime/DemoGameUnityHostApi.Entity.cs +++ b/Tests/unity/Assets/BridgeDemoGame/Runtime/DemoGameUnityHostApi.Entity.cs @@ -57,4 +57,4 @@ public void DestroyEntity(ulong entityId) } } } -} \ No newline at end of file +} diff --git a/Tests/unity/Assets/BridgeDemoGame/Runtime/DemoGameUnityHostApi.cs b/Tests/unity/Assets/BridgeDemoGame/Runtime/DemoGameUnityHostApi.cs index 8b496dc..7923496 100644 --- a/Tests/unity/Assets/BridgeDemoGame/Runtime/DemoGameUnityHostApi.cs +++ b/Tests/unity/Assets/BridgeDemoGame/Runtime/DemoGameUnityHostApi.cs @@ -29,7 +29,7 @@ public DemoGameUnityHostApi(BridgeCore core, DemoGameUnityAssetService assets, b _enableRendering = enableRendering; } - private static void ApplyTransform(Transform t, BridgeTransform transform, uint mask) + private static void ApplyTransform(Transform t, in BridgeTransform transform, uint mask) { if ((mask & 1u) != 0) t.position = new Vector3(transform.Position.X, transform.Position.Y, transform.Position.Z); diff --git a/Tests/unity/Assets/BridgeDemoGame/Runtime/DemoGameUnityRunner.cs b/Tests/unity/Assets/BridgeDemoGame/Runtime/DemoGameUnityRunner.cs index b13e493..3cea7ab 100644 --- a/Tests/unity/Assets/BridgeDemoGame/Runtime/DemoGameUnityRunner.cs +++ b/Tests/unity/Assets/BridgeDemoGame/Runtime/DemoGameUnityRunner.cs @@ -47,9 +47,7 @@ private void Update() for (int i = 0; i < _cores.Length; i++) { BridgeCore core = _cores[i]; - core.Tick(dt); - - CommandStream stream = core.GetCommandStream(); + CommandStream stream = core.TickAndGetCommandStream(dt); BridgeAllCommandDispatcher.Dispatch(stream, _hosts[i]); } } From 721db36589d86f74b67489c345c47807d0e3c089 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=A2=81=E9=93=96?= <> Date: Tue, 20 Jan 2026 18:56:58 +0800 Subject: [PATCH 06/33] =?UTF-8?q?perf:=20=E6=89=B9=E9=87=8F=20TickManyAndG?= =?UTF-8?q?etCommandStreams=EF=BC=88=E6=9C=BA=E5=99=A8=E4=BA=BA=E5=8E=8B?= =?UTF-8?q?=E6=B5=8B=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Core/cpp/include/bridge/bridge.h | 10 ++++++ Core/cpp/src/api/bridge_api.cpp | 28 +++++++++++++++ Core/csharp/Bridge.Core/BridgeCore.cs | 36 +++++++++++++++++++ .../Bridge.Core/Interop/BridgeNative.cs | 8 +++++ Tests/csharp/RobotHost/Program.cs | 18 +++++----- .../Managed/Bridge.Core/BridgeCore.cs | 36 +++++++++++++++++++ .../Bridge.Core/Interop/BridgeNative.cs | 29 +++++++++++++++ 7 files changed, 155 insertions(+), 10 deletions(-) diff --git a/Core/cpp/include/bridge/bridge.h b/Core/cpp/include/bridge/bridge.h index 54af2ed..c445639 100644 --- a/Core/cpp/include/bridge/bridge.h +++ b/Core/cpp/include/bridge/bridge.h @@ -184,6 +184,16 @@ BRIDGE_API BridgeResult BRIDGE_CALL BridgeCore_TickAndGetCommandStream( const void** out_ptr, uint32_t* out_len); +// 批量 Tick + 获取 command streams(机器人/压测用)。 +// - cores / out_ptrs / out_lens 均为长度为 count 的数组指针。 +// - 成功返回后:out_ptrs[i] / out_lens[i] 为 cores[i] 本帧的 stream。 +BRIDGE_API BridgeResult BRIDGE_CALL BridgeCore_TickManyAndGetCommandStreams( + BridgeCore** cores, + uint32_t count, + float dt, + const void** out_ptrs, + uint32_t* out_lens); + // 返回最近一次 BridgeCore_Tick 生成的 command stream(连续字节流)指针。 // 返回的内存由 Core 持有,只保证在下一次 BridgeCore_Tick(或 BridgeCore_Destroy)前有效。 BRIDGE_API BridgeResult BRIDGE_CALL BridgeCore_GetCommandStream( diff --git a/Core/cpp/src/api/bridge_api.cpp b/Core/cpp/src/api/bridge_api.cpp index 0b35edc..e2a2a9a 100644 --- a/Core/cpp/src/api/bridge_api.cpp +++ b/Core/cpp/src/api/bridge_api.cpp @@ -47,6 +47,34 @@ BridgeResult BRIDGE_CALL BridgeCore_TickAndGetCommandStream( return bridge::GetCommandStream(*core, out_ptr, out_len); } +BridgeResult BRIDGE_CALL BridgeCore_TickManyAndGetCommandStreams( + BridgeCore** cores, + uint32_t count, + float dt, + const void** out_ptrs, + uint32_t* out_lens) +{ + if (!cores || count == 0 || !out_ptrs || !out_lens) + { + return BRIDGE_INVALID_ARGUMENT; + } + + for (uint32_t i = 0; i < count; i++) + { + auto* core = cores[i]; + if (!core) + { + out_ptrs[i] = nullptr; + out_lens[i] = 0; + continue; + } + + bridge::Tick(*core, dt); + (void)bridge::GetCommandStream(*core, &out_ptrs[i], &out_lens[i]); + } + return BRIDGE_OK; +} + BridgeResult BRIDGE_CALL BridgeCore_GetCommandStream( const BridgeCore* core, const void** out_ptr, diff --git a/Core/csharp/Bridge.Core/BridgeCore.cs b/Core/csharp/Bridge.Core/BridgeCore.cs index 34d2d7d..a8993da 100644 --- a/Core/csharp/Bridge.Core/BridgeCore.cs +++ b/Core/csharp/Bridge.Core/BridgeCore.cs @@ -44,6 +44,42 @@ public CommandStream TickAndGetCommandStream(float dt) return new CommandStream(ptr, len); } + public static unsafe void TickManyAndGetCommandStreams(BridgeCore[] cores, float dt, CommandStream[] streams) + { + if (cores == null) + throw new ArgumentNullException(nameof(cores)); + if (streams == null) + throw new ArgumentNullException(nameof(streams)); + if (streams.Length < cores.Length) + throw new ArgumentException("streams.Length must be >= cores.Length", nameof(streams)); + + int count = cores.Length; + if (count == 0) + return; + + IntPtr* corePtrs = stackalloc IntPtr[count]; + for (int i = 0; i < count; i++) + { + BridgeCore core = cores[i] ?? throw new ArgumentNullException(nameof(cores), $"cores[{i}] is null"); + core.ThrowIfDisposed(); + corePtrs[i] = core._handle; + } + + IntPtr* outPtrs = stackalloc IntPtr[count]; + uint* outLens = stackalloc uint[count]; + + var result = BridgeNative.BridgeCore_TickManyAndGetCommandStreams(corePtrs, (uint)count, dt, outPtrs, outLens); + if (result != BridgeResult.Ok) + throw new InvalidOperationException($"BridgeCore_TickManyAndGetCommandStreams failed: {result}"); + + for (int i = 0; i < count; i++) + { + IntPtr ptr = outPtrs[i]; + uint len = outLens[i]; + streams[i] = (ptr == IntPtr.Zero || len == 0) ? CommandStream.Empty : new CommandStream(ptr, len); + } + } + /// /// 获取最近一次 生成的命令字节流(command stream)。 /// diff --git a/Core/csharp/Bridge.Core/Interop/BridgeNative.cs b/Core/csharp/Bridge.Core/Interop/BridgeNative.cs index 3f772c8..b4b1fb9 100644 --- a/Core/csharp/Bridge.Core/Interop/BridgeNative.cs +++ b/Core/csharp/Bridge.Core/Interop/BridgeNative.cs @@ -26,6 +26,14 @@ internal static extern BridgeResult BridgeCore_TickAndGetCommandStream( out IntPtr ptr, out uint len); + [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern unsafe BridgeResult BridgeCore_TickManyAndGetCommandStreams( + IntPtr* cores, + uint count, + float dt, + IntPtr* outPtrs, + uint* outLens); + [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl)] internal static extern BridgeResult BridgeCore_GetCommandStream( IntPtr core, diff --git a/Tests/csharp/RobotHost/Program.cs b/Tests/csharp/RobotHost/Program.cs index 0ee3903..bb81f6f 100644 --- a/Tests/csharp/RobotHost/Program.cs +++ b/Tests/csharp/RobotHost/Program.cs @@ -106,6 +106,8 @@ private static RunResult Run(int bots, int frames, float dt, string assetsRoot, hosts[i] = new RobotNullHostApi(core, assetProvider); } + var streams = new CommandStream[bots]; + long allocBefore = GC.GetAllocatedBytesForCurrentThread(); var sw = Stopwatch.StartNew(); @@ -113,12 +115,9 @@ private static RunResult Run(int bots, int frames, float dt, string assetsRoot, { for (int frame = 0; frame < frames; frame++) { + BridgeCore.TickManyAndGetCommandStreams(cores, dt, streams); for (int i = 0; i < cores.Length; i++) - { - var core = cores[i]; - var stream = core.TickAndGetCommandStream(dt); - BridgeAllCommandDispatcher.Dispatch(stream, hosts[i]); - } + BridgeAllCommandDispatcher.Dispatch(streams[i], hosts[i]); } } finally @@ -169,6 +168,8 @@ private static RunResult Run(int bots, int frames, float dt, string assetsRoot, hosts[i] = new RobotHostApi(core, world, assetProvider); } + var streams = new CommandStream[bots]; + long allocBefore = GC.GetAllocatedBytesForCurrentThread(); var sw = Stopwatch.StartNew(); @@ -176,12 +177,9 @@ private static RunResult Run(int bots, int frames, float dt, string assetsRoot, { for (int frame = 0; frame < frames; frame++) { + BridgeCore.TickManyAndGetCommandStreams(cores, dt, streams); for (int i = 0; i < cores.Length; i++) - { - var core = cores[i]; - var stream = core.TickAndGetCommandStream(dt); - BridgeAllCommandDispatcher.Dispatch(stream, hosts[i]); - } + BridgeAllCommandDispatcher.Dispatch(streams[i], hosts[i]); } } finally diff --git a/Tests/unity/Assets/BridgeCore/Managed/Bridge.Core/BridgeCore.cs b/Tests/unity/Assets/BridgeCore/Managed/Bridge.Core/BridgeCore.cs index 34d2d7d..a8993da 100644 --- a/Tests/unity/Assets/BridgeCore/Managed/Bridge.Core/BridgeCore.cs +++ b/Tests/unity/Assets/BridgeCore/Managed/Bridge.Core/BridgeCore.cs @@ -44,6 +44,42 @@ public CommandStream TickAndGetCommandStream(float dt) return new CommandStream(ptr, len); } + public static unsafe void TickManyAndGetCommandStreams(BridgeCore[] cores, float dt, CommandStream[] streams) + { + if (cores == null) + throw new ArgumentNullException(nameof(cores)); + if (streams == null) + throw new ArgumentNullException(nameof(streams)); + if (streams.Length < cores.Length) + throw new ArgumentException("streams.Length must be >= cores.Length", nameof(streams)); + + int count = cores.Length; + if (count == 0) + return; + + IntPtr* corePtrs = stackalloc IntPtr[count]; + for (int i = 0; i < count; i++) + { + BridgeCore core = cores[i] ?? throw new ArgumentNullException(nameof(cores), $"cores[{i}] is null"); + core.ThrowIfDisposed(); + corePtrs[i] = core._handle; + } + + IntPtr* outPtrs = stackalloc IntPtr[count]; + uint* outLens = stackalloc uint[count]; + + var result = BridgeNative.BridgeCore_TickManyAndGetCommandStreams(corePtrs, (uint)count, dt, outPtrs, outLens); + if (result != BridgeResult.Ok) + throw new InvalidOperationException($"BridgeCore_TickManyAndGetCommandStreams failed: {result}"); + + for (int i = 0; i < count; i++) + { + IntPtr ptr = outPtrs[i]; + uint len = outLens[i]; + streams[i] = (ptr == IntPtr.Zero || len == 0) ? CommandStream.Empty : new CommandStream(ptr, len); + } + } + /// /// 获取最近一次 生成的命令字节流(command stream)。 /// diff --git a/Tests/unity/Assets/BridgeCore/Managed/Bridge.Core/Interop/BridgeNative.cs b/Tests/unity/Assets/BridgeCore/Managed/Bridge.Core/Interop/BridgeNative.cs index b170c1b..767ccaa 100644 --- a/Tests/unity/Assets/BridgeCore/Managed/Bridge.Core/Interop/BridgeNative.cs +++ b/Tests/unity/Assets/BridgeCore/Managed/Bridge.Core/Interop/BridgeNative.cs @@ -28,6 +28,14 @@ internal static class BridgeNative [UnmanagedFunctionPointer(CallingConvention.Cdecl)] private delegate BridgeResult BridgeCore_TickAndGetCommandStreamDelegate(IntPtr core, float dt, out IntPtr ptr, out uint len); + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + private unsafe delegate BridgeResult BridgeCore_TickManyAndGetCommandStreamsDelegate( + IntPtr* cores, + uint count, + float dt, + IntPtr* outPtrs, + uint* outLens); + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] private delegate BridgeResult BridgeCore_GetCommandStreamDelegate(IntPtr core, out IntPtr ptr, out uint len); @@ -40,6 +48,7 @@ internal static class BridgeNative private static BridgeCore_DestroyDelegate s_destroy; private static BridgeCore_TickDelegate s_tick; private static BridgeCore_TickAndGetCommandStreamDelegate s_tickAndGetCommandStream; + private static BridgeCore_TickManyAndGetCommandStreamsDelegate s_tickManyAndGetCommandStreams; private static BridgeCore_GetCommandStreamDelegate s_getCommandStream; private static BridgeCore_PushCallCoreDelegate s_pushCallCore; @@ -59,6 +68,7 @@ private static void EnsureBound() s_destroy = GetDelegate(module, "BridgeCore_Destroy"); s_tick = GetDelegate(module, "BridgeCore_Tick"); s_tickAndGetCommandStream = GetDelegate(module, "BridgeCore_TickAndGetCommandStream"); + s_tickManyAndGetCommandStreams = GetDelegate(module, "BridgeCore_TickManyAndGetCommandStreams"); s_getCommandStream = GetDelegate(module, "BridgeCore_GetCommandStream"); s_pushCallCore = GetDelegate(module, "BridgeCore_PushCallCore"); s_boundModule = module; @@ -103,6 +113,17 @@ internal static BridgeResult BridgeCore_TickAndGetCommandStream(IntPtr core, flo return s_tickAndGetCommandStream(core, dt, out ptr, out len); } + internal static unsafe BridgeResult BridgeCore_TickManyAndGetCommandStreams( + IntPtr* cores, + uint count, + float dt, + IntPtr* outPtrs, + uint* outLens) + { + EnsureBound(); + return s_tickManyAndGetCommandStreams(cores, count, dt, outPtrs, outLens); + } + internal static BridgeResult BridgeCore_GetCommandStream(IntPtr core, out IntPtr ptr, out uint len) { EnsureBound(); @@ -136,6 +157,14 @@ internal static extern BridgeResult BridgeCore_TickAndGetCommandStream( out IntPtr ptr, out uint len); + [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern unsafe BridgeResult BridgeCore_TickManyAndGetCommandStreams( + IntPtr* cores, + uint count, + float dt, + IntPtr* outPtrs, + uint* outLens); + [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl)] internal static extern BridgeResult BridgeCore_GetCommandStream( IntPtr core, From 967cec4a7368b1c8698dbb9cbe73261694c2b572 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=A2=81=E9=93=96?= <> Date: Tue, 20 Jan 2026 18:58:21 +0800 Subject: [PATCH 07/33] =?UTF-8?q?docs:=20=E6=9B=B4=E6=96=B0=E6=80=A7?= =?UTF-8?q?=E8=83=BD=E6=95=B0=E6=8D=AE=E4=B8=8E=E6=89=B9=E9=87=8F=20tick?= =?UTF-8?q?=20=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Core/docs/BRIDGE_DESIGN.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Core/docs/BRIDGE_DESIGN.md b/Core/docs/BRIDGE_DESIGN.md index b21158a..a039c98 100644 --- a/Core/docs/BRIDGE_DESIGN.md +++ b/Core/docs/BRIDGE_DESIGN.md @@ -103,15 +103,16 @@ Host 侧拿到 Core 输出的 `CommandStream` 后,需要把 `CallHost(func_id, - 分发器使用 `unsafe` + `sizeof(T)` + 指针解引用读取 payload,避免 `Marshal.PtrToStructure` 的反射与分配。 - Host→Core 的 `PushCallCore(payload)` 使用 `unmanaged` 泛型直接传栈上数据指针,避免 `AllocHGlobal`。 +- 为减少 Host 侧 native 调用次数:提供 `BridgeCore_TickAndGetCommandStream` 与 `BridgeCore_TickManyAndGetCommandStreams`。 ### 基准结果(示例) 环境:Windows,Release,bots=1000,frames=300,dt=1/60。 - C#(`--host null`) - - `all`:约 15.01M cmd/s,分配 ~232 bytes + - `all`:约 17.17M cmd/s,分配 ~184 bytes - C#(`--host full`) - - `all`:约 8.26M cmd/s,分配 ~512 bytes(示例 WorldState 预分配避免运行期扩容) + - `all`:约 8.93M cmd/s,分配 ~464 bytes(示例 WorldState 预分配避免运行期扩容) - C++ 解析 baseline(仅解析 command stream):约 40.00M cmd/s - Unity(EditMode / Performance Test Framework) - `TickAndDispatch_OneFrame(1)`:Avg ~0.01 ms From 5438f94319e40b09bad0aeb9a2acd315e5be9c9f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=A2=81=E9=93=96?= <> Date: Tue, 20 Jan 2026 19:00:52 +0800 Subject: [PATCH 08/33] =?UTF-8?q?perf(unity):=20DemoGameUnityRunner=20?= =?UTF-8?q?=E4=BD=BF=E7=94=A8=E6=89=B9=E9=87=8F=20tick?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../BridgeDemoGame/Runtime/DemoGameUnityRunner.cs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Tests/unity/Assets/BridgeDemoGame/Runtime/DemoGameUnityRunner.cs b/Tests/unity/Assets/BridgeDemoGame/Runtime/DemoGameUnityRunner.cs index 3cea7ab..35e3ec6 100644 --- a/Tests/unity/Assets/BridgeDemoGame/Runtime/DemoGameUnityRunner.cs +++ b/Tests/unity/Assets/BridgeDemoGame/Runtime/DemoGameUnityRunner.cs @@ -17,6 +17,7 @@ public sealed class DemoGameUnityRunner : MonoBehaviour private BridgeCore[] _cores = Array.Empty(); private DemoGameUnityHostApi[] _hosts = Array.Empty(); + private CommandStream[] _streams = Array.Empty(); private DemoGameUnityAssetService _assets; private void Awake() @@ -31,6 +32,7 @@ private void Start() int bots = Mathf.Max(1, Bots); _cores = new BridgeCore[bots]; _hosts = new DemoGameUnityHostApi[bots]; + _streams = new CommandStream[bots]; bool render = EnableRendering && bots <= MaxBotsWithRendering; for (int i = 0; i < bots; i++) @@ -44,12 +46,9 @@ private void Start() private void Update() { float dt = Time.deltaTime; + BridgeCore.TickManyAndGetCommandStreams(_cores, dt, _streams); for (int i = 0; i < _cores.Length; i++) - { - BridgeCore core = _cores[i]; - CommandStream stream = core.TickAndGetCommandStream(dt); - BridgeAllCommandDispatcher.Dispatch(stream, _hosts[i]); - } + BridgeAllCommandDispatcher.Dispatch(_streams[i], _hosts[i]); } private void OnDestroy() @@ -60,6 +59,7 @@ private void OnDestroy() } _cores = Array.Empty(); _hosts = Array.Empty(); + _streams = Array.Empty(); } } } From a1d8a026589b977225079aac7d53201289c0e355 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=A2=81=E9=93=96?= <> Date: Wed, 21 Jan 2026 13:18:36 +0800 Subject: [PATCH 09/33] Unity: add BridgeCore package and IL2CPP source-plugin workflow --- AGENTS.md | 2 +- Core/Tools/BridgeGen/Program.cs | 39 ++- Core/csharp/Bridge.Core/BridgeCore.cs | 98 ++++++-- Core/docs/BRIDGE_DESIGN.md | 2 +- Core/docs/UNITY_WIN_NATIVE_LOADING.md | 2 +- .../Editor.meta | 3 +- .../Editor/Bridge.Core.Unity.Editor.asmdef | 12 + .../Bridge.Core.Unity.Editor.asmdef.meta | 7 + .../Editor/BridgeCoreIl2cppBuild.cs | 46 ++++ .../Editor/BridgeCoreIl2cppBuild.cs.meta | 2 + .../Editor/BridgeCoreNativeSourceSync.cs | 174 ++++++++++++++ .../Editor/BridgeCoreNativeSourceSync.cs.meta | 2 + .../Editor/BridgeCorePerfCli.cs | 226 ++++++++++++++++++ .../Editor/BridgeCorePerfCli.cs.meta | 2 + .../Editor/BridgeCoreRuntimeUnitTestBuild.cs | 75 ++++++ .../BridgeCoreRuntimeUnitTestBuild.cs.meta | 2 + .../Editor/BridgeCoreWinHotReload.cs | 0 .../Editor/BridgeCoreWinHotReload.cs.meta | 1 - .../Editor/BridgeCoreWinSync.cs | 0 .../Editor/BridgeCoreWinSync.cs.meta | 1 - .../README.md | 7 + .../README.md.meta | 1 - .../Runtime.meta | 3 +- .../Runtime/Bridge.Core.Unity.meta | 3 +- .../Bridge.Core.Unity.asmdef | 0 .../Bridge.Core.Unity.asmdef.meta | 0 .../Bridge.Core.Unity}/BridgeCoreWinLoader.cs | 0 .../BridgeCoreWinLoader.cs.meta | 1 - .../Runtime}/Bridge.Core.meta | 3 +- .../Runtime}/Bridge.Core/Bridge.Core.asmdef | 0 .../Bridge.Core/Bridge.Core.asmdef.meta | 0 .../Runtime/Bridge.Core/BridgeCore.cs | 191 +++++++++++++++ .../Runtime}/Bridge.Core/BridgeCore.cs.meta | 1 - .../Runtime}/Bridge.Core/CommandStream.cs | 1 - .../Bridge.Core/CommandStream.cs.meta | 1 - .../Runtime}/Bridge.Core/Interop.meta | 3 +- .../Bridge.Core/Interop/BridgeNative.cs | 0 .../Bridge.Core/Interop/BridgeNative.cs.meta | 1 - .../Runtime}/Bridge.Core/Interop/Structs.cs | 0 .../Bridge.Core/Interop/Structs.cs.meta | 1 - .../package.json | 10 + .../package.json.meta | 7 + Tests/cpp/demo_game/CMakeLists.txt | 4 +- .../generated/demo_asset_bindings.generated.h | 0 .../demo_entity_bindings.generated.h | 0 .../generated/demo_log_bindings.generated.h | 0 Tests/cpp/robot_runner/CMakeLists.txt | 2 +- Tests/csharp/RobotHost/Bind/RobotHostApi.cs | 8 +- .../csharp/RobotHost/Bind/RobotNullHostApi.cs | 6 +- Tests/csharp/RobotHost/Bind/WorldState.cs | 4 +- .../Bridge.AllCommandDispatcher.g.cs | 14 +- .../Generated/IDemoEntityHostApi.g.cs | 4 +- Tests/csharp/RobotHost/Program.cs | 120 ++++++++-- .../Managed/Bridge.Core/BridgeCore.cs | 127 ---------- .../BridgeDispatchPerformanceTests.cs | 4 +- .../Bridge.AllCommandDispatcher.g.cs | 14 +- .../Generated/IDemoEntityHostApi.g.cs | 4 +- .../PlayModeTests.meta} | 3 +- .../BridgeDemoGame.PlayModeTests.asmdef | 12 + .../BridgeDemoGame.PlayModeTests.asmdef.meta | 8 + .../PlayModeTests/BridgeRuntimeSmokeTests.cs | 77 ++++++ .../BridgeRuntimeSmokeTests.cs.meta | 12 + .../Runtime/BridgeDemoGame.Runtime.asmdef | 7 + .../BridgeDemoGame.Runtime.asmdef.meta | 7 + .../Assets/BridgeDemoGame/Runtime/Host.meta | 8 + .../{ => Host}/DemoGameUnityAssetService.cs | 0 .../DemoGameUnityAssetService.cs.meta | 1 - .../{ => Host}/DemoGameUnityHostApi.Asset.cs | 0 .../DemoGameUnityHostApi.Asset.cs.meta | 1 - .../{ => Host}/DemoGameUnityHostApi.Entity.cs | 4 +- .../DemoGameUnityHostApi.Entity.cs.meta | 1 - .../{ => Host}/DemoGameUnityHostApi.Log.cs | 0 .../DemoGameUnityHostApi.Log.cs.meta | 1 - .../{ => Host}/DemoGameUnityHostApi.cs | 0 .../{ => Host}/DemoGameUnityHostApi.cs.meta | 1 - .../Assets/BridgeDemoGame/Runtime/Runner.meta | 8 + .../{ => Runner}/DemoGameUnityRunner.cs | 0 .../{ => Runner}/DemoGameUnityRunner.cs.meta | 1 - Tests/unity/Packages/manifest.json | 2 + Tests/unity/Packages/packages-lock.json | 13 + .../UnityConnectSettings.asset | 2 + 81 files changed, 1167 insertions(+), 243 deletions(-) rename {Tests/unity/Assets/BridgeCore => Packages/com.unitynativescripting.bridgecore}/Editor.meta (76%) create mode 100644 Packages/com.unitynativescripting.bridgecore/Editor/Bridge.Core.Unity.Editor.asmdef create mode 100644 Packages/com.unitynativescripting.bridgecore/Editor/Bridge.Core.Unity.Editor.asmdef.meta create mode 100644 Packages/com.unitynativescripting.bridgecore/Editor/BridgeCoreIl2cppBuild.cs create mode 100644 Packages/com.unitynativescripting.bridgecore/Editor/BridgeCoreIl2cppBuild.cs.meta create mode 100644 Packages/com.unitynativescripting.bridgecore/Editor/BridgeCoreNativeSourceSync.cs create mode 100644 Packages/com.unitynativescripting.bridgecore/Editor/BridgeCoreNativeSourceSync.cs.meta create mode 100644 Packages/com.unitynativescripting.bridgecore/Editor/BridgeCorePerfCli.cs create mode 100644 Packages/com.unitynativescripting.bridgecore/Editor/BridgeCorePerfCli.cs.meta create mode 100644 Packages/com.unitynativescripting.bridgecore/Editor/BridgeCoreRuntimeUnitTestBuild.cs create mode 100644 Packages/com.unitynativescripting.bridgecore/Editor/BridgeCoreRuntimeUnitTestBuild.cs.meta rename {Tests/unity/Assets/BridgeCore => Packages/com.unitynativescripting.bridgecore}/Editor/BridgeCoreWinHotReload.cs (100%) rename {Tests/unity/Assets/BridgeCore => Packages/com.unitynativescripting.bridgecore}/Editor/BridgeCoreWinHotReload.cs.meta (99%) rename {Tests/unity/Assets/BridgeCore => Packages/com.unitynativescripting.bridgecore}/Editor/BridgeCoreWinSync.cs (100%) rename {Tests/unity/Assets/BridgeCore => Packages/com.unitynativescripting.bridgecore}/Editor/BridgeCoreWinSync.cs.meta (99%) rename {Tests/unity/Assets/BridgeCore => Packages/com.unitynativescripting.bridgecore}/README.md (57%) rename {Tests/unity/Assets/BridgeCore => Packages/com.unitynativescripting.bridgecore}/README.md.meta (99%) rename {Tests/unity/Assets/BridgeCore => Packages/com.unitynativescripting.bridgecore}/Runtime.meta (76%) rename Tests/unity/Assets/BridgeCore.meta => Packages/com.unitynativescripting.bridgecore/Runtime/Bridge.Core.Unity.meta (76%) rename {Tests/unity/Assets/BridgeCore/Runtime => Packages/com.unitynativescripting.bridgecore/Runtime/Bridge.Core.Unity}/Bridge.Core.Unity.asmdef (100%) rename {Tests/unity/Assets/BridgeCore/Runtime => Packages/com.unitynativescripting.bridgecore/Runtime/Bridge.Core.Unity}/Bridge.Core.Unity.asmdef.meta (100%) rename {Tests/unity/Assets/BridgeCore/Runtime => Packages/com.unitynativescripting.bridgecore/Runtime/Bridge.Core.Unity}/BridgeCoreWinLoader.cs (100%) rename {Tests/unity/Assets/BridgeCore/Runtime => Packages/com.unitynativescripting.bridgecore/Runtime/Bridge.Core.Unity}/BridgeCoreWinLoader.cs.meta (99%) rename {Tests/unity/Assets/BridgeCore/Managed => Packages/com.unitynativescripting.bridgecore/Runtime}/Bridge.Core.meta (76%) rename {Tests/unity/Assets/BridgeCore/Managed => Packages/com.unitynativescripting.bridgecore/Runtime}/Bridge.Core/Bridge.Core.asmdef (100%) rename {Tests/unity/Assets/BridgeCore/Managed => Packages/com.unitynativescripting.bridgecore/Runtime}/Bridge.Core/Bridge.Core.asmdef.meta (100%) create mode 100644 Packages/com.unitynativescripting.bridgecore/Runtime/Bridge.Core/BridgeCore.cs rename {Tests/unity/Assets/BridgeCore/Managed => Packages/com.unitynativescripting.bridgecore/Runtime}/Bridge.Core/BridgeCore.cs.meta (99%) rename {Tests/unity/Assets/BridgeCore/Managed => Packages/com.unitynativescripting.bridgecore/Runtime}/Bridge.Core/CommandStream.cs (99%) rename {Tests/unity/Assets/BridgeCore/Managed => Packages/com.unitynativescripting.bridgecore/Runtime}/Bridge.Core/CommandStream.cs.meta (99%) rename {Tests/unity/Assets/BridgeCore/Managed => Packages/com.unitynativescripting.bridgecore/Runtime}/Bridge.Core/Interop.meta (76%) rename {Tests/unity/Assets/BridgeCore/Managed => Packages/com.unitynativescripting.bridgecore/Runtime}/Bridge.Core/Interop/BridgeNative.cs (100%) rename {Tests/unity/Assets/BridgeCore/Managed => Packages/com.unitynativescripting.bridgecore/Runtime}/Bridge.Core/Interop/BridgeNative.cs.meta (99%) rename {Tests/unity/Assets/BridgeCore/Managed => Packages/com.unitynativescripting.bridgecore/Runtime}/Bridge.Core/Interop/Structs.cs (100%) rename {Tests/unity/Assets/BridgeCore/Managed => Packages/com.unitynativescripting.bridgecore/Runtime}/Bridge.Core/Interop/Structs.cs.meta (99%) create mode 100644 Packages/com.unitynativescripting.bridgecore/package.json create mode 100644 Packages/com.unitynativescripting.bridgecore/package.json.meta rename Tests/cpp/{demo_asset => }/generated/demo_asset_bindings.generated.h (100%) rename Tests/cpp/{demo_entity => }/generated/demo_entity_bindings.generated.h (100%) rename Tests/cpp/{demo_log => }/generated/demo_log_bindings.generated.h (100%) delete mode 100644 Tests/unity/Assets/BridgeCore/Managed/Bridge.Core/BridgeCore.cs rename Tests/unity/Assets/{BridgeCore/Managed.meta => BridgeDemoGame/PlayModeTests.meta} (76%) create mode 100644 Tests/unity/Assets/BridgeDemoGame/PlayModeTests/BridgeDemoGame.PlayModeTests.asmdef create mode 100644 Tests/unity/Assets/BridgeDemoGame/PlayModeTests/BridgeDemoGame.PlayModeTests.asmdef.meta create mode 100644 Tests/unity/Assets/BridgeDemoGame/PlayModeTests/BridgeRuntimeSmokeTests.cs create mode 100644 Tests/unity/Assets/BridgeDemoGame/PlayModeTests/BridgeRuntimeSmokeTests.cs.meta create mode 100644 Tests/unity/Assets/BridgeDemoGame/Runtime/BridgeDemoGame.Runtime.asmdef create mode 100644 Tests/unity/Assets/BridgeDemoGame/Runtime/BridgeDemoGame.Runtime.asmdef.meta create mode 100644 Tests/unity/Assets/BridgeDemoGame/Runtime/Host.meta rename Tests/unity/Assets/BridgeDemoGame/Runtime/{ => Host}/DemoGameUnityAssetService.cs (100%) rename Tests/unity/Assets/BridgeDemoGame/Runtime/{ => Host}/DemoGameUnityAssetService.cs.meta (99%) rename Tests/unity/Assets/BridgeDemoGame/Runtime/{ => Host}/DemoGameUnityHostApi.Asset.cs (100%) rename Tests/unity/Assets/BridgeDemoGame/Runtime/{ => Host}/DemoGameUnityHostApi.Asset.cs.meta (99%) rename Tests/unity/Assets/BridgeDemoGame/Runtime/{ => Host}/DemoGameUnityHostApi.Entity.cs (91%) rename Tests/unity/Assets/BridgeDemoGame/Runtime/{ => Host}/DemoGameUnityHostApi.Entity.cs.meta (99%) rename Tests/unity/Assets/BridgeDemoGame/Runtime/{ => Host}/DemoGameUnityHostApi.Log.cs (100%) rename Tests/unity/Assets/BridgeDemoGame/Runtime/{ => Host}/DemoGameUnityHostApi.Log.cs.meta (99%) rename Tests/unity/Assets/BridgeDemoGame/Runtime/{ => Host}/DemoGameUnityHostApi.cs (100%) rename Tests/unity/Assets/BridgeDemoGame/Runtime/{ => Host}/DemoGameUnityHostApi.cs.meta (99%) create mode 100644 Tests/unity/Assets/BridgeDemoGame/Runtime/Runner.meta rename Tests/unity/Assets/BridgeDemoGame/Runtime/{ => Runner}/DemoGameUnityRunner.cs (100%) rename Tests/unity/Assets/BridgeDemoGame/Runtime/{ => Runner}/DemoGameUnityRunner.cs.meta (99%) diff --git a/AGENTS.md b/AGENTS.md index b1f4f89..e54227d 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -49,7 +49,7 @@ dotnet build Tests/csharp/RobotHost/RobotHost.csproj -c Release - C ABI 结构体变更必须同步更新:`Core/csharp/Bridge.Core/Interop/Structs.cs`。 - 业务侧接口通过宏文件定义并生成: - 定义:`Tests/defs/*.def`(建议一个 `.def` 对应一个业务模块/子系统) - - 生成(C++):`Tests/cpp//generated/_bindings.generated.h` + - 生成(C++):`Tests/cpp/generated/_bindings.generated.h` - 生成(C# Host):`Tests/csharp/RobotHost/Generated/.*.g.cs` - 生成(Unity Host):`Tests/unity/Assets/BridgeDemoGame/Generated/.*.g.cs` - 跨边界只传:blittable struct、ID/handle(`uint64`)、UTF-8 字符串视图(`ptr+len`,仅在当帧有效)。 diff --git a/Core/Tools/BridgeGen/Program.cs b/Core/Tools/BridgeGen/Program.cs index d9db863..ac2726e 100644 --- a/Core/Tools/BridgeGen/Program.cs +++ b/Core/Tools/BridgeGen/Program.cs @@ -21,7 +21,7 @@ private static int Main(string[] args) throw new InvalidOperationException($"未找到任何 .def 文件:{defsDir}。请创建 Tests/defs/*.def 或使用 --api 指定输入。"); } - // outCpp 约定为 Tests 目录(默认:/Tests),每个模块输出到 Tests/cpp//generated + // outCpp 约定为 Tests 目录(默认:/Tests),所有模块输出到 Tests/cpp/generated string outCpp = GetArg(args, "--out-cpp") ?? Path.Combine(repoRoot, "Tests"); string outCs = GetArg(args, "--out-cs") ?? Path.Combine(repoRoot, "Tests", "csharp", "RobotHost", "Generated"); @@ -203,10 +203,9 @@ private static string CppNamespaceFromModule(string module) private static string ResolveOutCppDir(string repoRoot, string outCppArg, string module) { - // 默认 outCpp 为 Tests/cpp 根目录;每个模块输出到 Tests/cpp//generated + // 默认 outCpp 为 Tests;所有模块输出到 Tests/cpp/generated(集中一个目录,便于 CMake include) string outCppRoot = Path.IsPathRooted(outCppArg) ? outCppArg : Path.Combine(repoRoot, outCppArg); - string cppNs = CppNamespaceFromModule(module); - return Path.Combine(outCppRoot, "cpp", cppNs, "generated"); + return Path.Combine(outCppRoot, "cpp", "generated"); } private sealed record ApiModel(List HostFns, List CoreFns) @@ -533,7 +532,11 @@ private static string EmitAllDispatcher(IReadOnlyList modules) sb.Append(fn.Name); sb.AppendLine("))"); sb.AppendLine(" {"); - sb.Append(" var a = *(("); + sb.Append(" ref readonly "); + sb.Append(m.CsNamespace); + sb.Append(".HostArgs_"); + sb.Append(fn.Name); + sb.Append(" a = ref *(("); sb.Append(m.CsNamespace); sb.Append(".HostArgs_"); sb.Append(fn.Name); @@ -620,7 +623,7 @@ private static string EmitHostApi(ApiModel model, string module, string csNamesp { if (i > 0) sb.Append(", "); var arg = fn.Args[i]; - sb.Append(MapCsHostArgType(arg.CppType)); + sb.Append(MapCsHostArgParamType(arg.CppType)); sb.Append(' '); sb.Append(ToCamel(arg.Name)); } @@ -647,7 +650,7 @@ private static string EmitCoreCalls(ApiModel model, string module, string csName foreach (var arg in fn.Args) { sb.Append(", "); - sb.Append(MapCsCoreCallArgType(arg.CppType)); + sb.Append(MapCsCoreCallArgParamType(arg.CppType)); sb.Append(' '); sb.Append(ToCamel(arg.Name)); } @@ -711,6 +714,17 @@ private static string MapCsHostArgType(string cppType) }; } + private static string MapCsHostArgParamType(string cppType) + { + string type = MapCsHostArgType(cppType); + return cppType switch + { + // Hot path:避免 48B+ struct 的值拷贝(尤其是 SetTransform 高频)。 + "BridgeTransform" => "in " + type, + _ => type, + }; + } + private static string MapCsCoreCallArgType(string cppType) { if (cppType == "BridgeStringView") @@ -718,10 +732,21 @@ private static string MapCsCoreCallArgType(string cppType) return MapCsHostArgType(cppType); } + private static string MapCsCoreCallArgParamType(string cppType) + { + string type = MapCsCoreCallArgType(cppType); + return cppType switch + { + "BridgeTransform" => "in " + type, + _ => type, + }; + } + private static string MapCsHostArgExpr(string cppType, string fieldExpr) { return cppType switch { + "BridgeTransform" => "in " + fieldExpr, _ => fieldExpr }; } diff --git a/Core/csharp/Bridge.Core/BridgeCore.cs b/Core/csharp/Bridge.Core/BridgeCore.cs index a8993da..4914876 100644 --- a/Core/csharp/Bridge.Core/BridgeCore.cs +++ b/Core/csharp/Bridge.Core/BridgeCore.cs @@ -7,6 +7,12 @@ namespace Bridge.Core /// public sealed class BridgeCore : IDisposable { + private const int StackAllocMaxCount = 1024; + + [ThreadStatic] private static IntPtr[]? s_tickManyCorePtrs; + [ThreadStatic] private static IntPtr[]? s_tickManyOutPtrs; + [ThreadStatic] private static uint[]? s_tickManyOutLens; + private IntPtr _handle; public BridgeCore(ulong seed = 1, bool robotMode = false) @@ -44,6 +50,19 @@ public CommandStream TickAndGetCommandStream(float dt) return new CommandStream(ptr, len); } + /// + /// 预分配 在大规模 cores 下的临时缓冲,避免首帧分配计入性能统计。 + /// + public static void PrepareTickManyCache(int count) + { + if (count <= StackAllocMaxCount) + return; + if (count < 0) + throw new ArgumentOutOfRangeException(nameof(count)); + + EnsureTickManyArrays(count); + } + public static unsafe void TickManyAndGetCommandStreams(BridgeCore[] cores, float dt, CommandStream[] streams) { if (cores == null) @@ -57,29 +76,74 @@ public static unsafe void TickManyAndGetCommandStreams(BridgeCore[] cores, float if (count == 0) return; - IntPtr* corePtrs = stackalloc IntPtr[count]; - for (int i = 0; i < count; i++) + if (count <= StackAllocMaxCount) { - BridgeCore core = cores[i] ?? throw new ArgumentNullException(nameof(cores), $"cores[{i}] is null"); - core.ThrowIfDisposed(); - corePtrs[i] = core._handle; + IntPtr* corePtrs = stackalloc IntPtr[count]; + for (int i = 0; i < count; i++) + { + BridgeCore core = cores[i] ?? throw new ArgumentNullException(nameof(cores), $"cores[{i}] is null"); + core.ThrowIfDisposed(); + corePtrs[i] = core._handle; + } + + IntPtr* outPtrs = stackalloc IntPtr[count]; + uint* outLens = stackalloc uint[count]; + + var result = BridgeNative.BridgeCore_TickManyAndGetCommandStreams(corePtrs, (uint)count, dt, outPtrs, outLens); + if (result != BridgeResult.Ok) + throw new InvalidOperationException($"BridgeCore_TickManyAndGetCommandStreams failed: {result}"); + + for (int i = 0; i < count; i++) + { + IntPtr ptr = outPtrs[i]; + uint len = outLens[i]; + streams[i] = (ptr == IntPtr.Zero || len == 0) ? CommandStream.Empty : new CommandStream(ptr, len); + } } - - IntPtr* outPtrs = stackalloc IntPtr[count]; - uint* outLens = stackalloc uint[count]; - - var result = BridgeNative.BridgeCore_TickManyAndGetCommandStreams(corePtrs, (uint)count, dt, outPtrs, outLens); - if (result != BridgeResult.Ok) - throw new InvalidOperationException($"BridgeCore_TickManyAndGetCommandStreams failed: {result}"); - - for (int i = 0; i < count; i++) + else { - IntPtr ptr = outPtrs[i]; - uint len = outLens[i]; - streams[i] = (ptr == IntPtr.Zero || len == 0) ? CommandStream.Empty : new CommandStream(ptr, len); + EnsureTickManyArrays(count); + + IntPtr[] corePtrsManaged = s_tickManyCorePtrs!; + IntPtr[] outPtrsManaged = s_tickManyOutPtrs!; + uint[] outLensManaged = s_tickManyOutLens!; + + for (int i = 0; i < count; i++) + { + BridgeCore core = cores[i] ?? throw new ArgumentNullException(nameof(cores), $"cores[{i}] is null"); + core.ThrowIfDisposed(); + corePtrsManaged[i] = core._handle; + } + + fixed (IntPtr* corePtrs = corePtrsManaged) + fixed (IntPtr* outPtrs = outPtrsManaged) + fixed (uint* outLens = outLensManaged) + { + var result = BridgeNative.BridgeCore_TickManyAndGetCommandStreams(corePtrs, (uint)count, dt, outPtrs, outLens); + if (result != BridgeResult.Ok) + throw new InvalidOperationException($"BridgeCore_TickManyAndGetCommandStreams failed: {result}"); + } + + for (int i = 0; i < count; i++) + { + IntPtr ptr = outPtrsManaged[i]; + uint len = outLensManaged[i]; + streams[i] = (ptr == IntPtr.Zero || len == 0) ? CommandStream.Empty : new CommandStream(ptr, len); + } } } + private static void EnsureTickManyArrays(int count) + { + s_tickManyCorePtrs ??= new IntPtr[count]; + s_tickManyOutPtrs ??= new IntPtr[count]; + s_tickManyOutLens ??= new uint[count]; + + if (s_tickManyCorePtrs.Length < count) s_tickManyCorePtrs = new IntPtr[count]; + if (s_tickManyOutPtrs.Length < count) s_tickManyOutPtrs = new IntPtr[count]; + if (s_tickManyOutLens.Length < count) s_tickManyOutLens = new uint[count]; + } + /// /// 获取最近一次 生成的命令字节流(command stream)。 /// diff --git a/Core/docs/BRIDGE_DESIGN.md b/Core/docs/BRIDGE_DESIGN.md index a039c98..eeabebf 100644 --- a/Core/docs/BRIDGE_DESIGN.md +++ b/Core/docs/BRIDGE_DESIGN.md @@ -82,7 +82,7 @@ Core 只关心 `assetKey` 与 `handle`,不关心 AB 细节。 业务接口(func_id 与 payload 结构)通过宏文件定义并由生成器产出: - 定义:`Tests/defs/*.def`(建议一个 `.def` 对应一个模块/子系统) -- 生成(C++):`Tests/cpp//generated/_bindings.generated.h` +- 生成(C++):`Tests/cpp/generated/_bindings.generated.h` - 生成(C# Host):`Tests/csharp/RobotHost/Generated/.*.g.cs` - 生成(Unity Host):`Tests/unity/Assets/BridgeDemoGame/Generated/.*.g.cs` diff --git a/Core/docs/UNITY_WIN_NATIVE_LOADING.md b/Core/docs/UNITY_WIN_NATIVE_LOADING.md index 1a3ce10..68ceead 100644 --- a/Core/docs/UNITY_WIN_NATIVE_LOADING.md +++ b/Core/docs/UNITY_WIN_NATIVE_LOADING.md @@ -63,4 +63,4 @@ Player 通常不需要“复制到临时目录”来绕开锁问题,因为运 - Editor:从“源 DLL”复制到 `Library/BridgeNative//` 并加载 - Editor:可选的“同步 DLL 到 Assets/Plugins(仅用于出包)”工具 -对应实现位于 `Tests/unity/Assets/BridgeCore/`(不提交二进制 DLL)。 +对应实现位于 `Packages/com.unitynativescripting.bridgecore/`(不提交二进制 DLL)。 diff --git a/Tests/unity/Assets/BridgeCore/Editor.meta b/Packages/com.unitynativescripting.bridgecore/Editor.meta similarity index 76% rename from Tests/unity/Assets/BridgeCore/Editor.meta rename to Packages/com.unitynativescripting.bridgecore/Editor.meta index 7288872..b44b455 100644 --- a/Tests/unity/Assets/BridgeCore/Editor.meta +++ b/Packages/com.unitynativescripting.bridgecore/Editor.meta @@ -1,9 +1,8 @@ fileFormatVersion: 2 -guid: 1a7a8f63a0b64f47b8c815b6b7bb70c9 +guid: 1d2d3e96e9297a9458fbe26386f00124 folderAsset: yes DefaultImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: - diff --git a/Packages/com.unitynativescripting.bridgecore/Editor/Bridge.Core.Unity.Editor.asmdef b/Packages/com.unitynativescripting.bridgecore/Editor/Bridge.Core.Unity.Editor.asmdef new file mode 100644 index 0000000..15d8168 --- /dev/null +++ b/Packages/com.unitynativescripting.bridgecore/Editor/Bridge.Core.Unity.Editor.asmdef @@ -0,0 +1,12 @@ +{ + "name": "Bridge.Core.Unity.Editor", + "references": [ + "Bridge.Core.Unity", + "UnityEditor.TestRunner", + "UnityEngine.TestRunner", + "Unity.PerformanceTesting" + ], + "includePlatforms": [ + "Editor" + ] +} diff --git a/Packages/com.unitynativescripting.bridgecore/Editor/Bridge.Core.Unity.Editor.asmdef.meta b/Packages/com.unitynativescripting.bridgecore/Editor/Bridge.Core.Unity.Editor.asmdef.meta new file mode 100644 index 0000000..060396f --- /dev/null +++ b/Packages/com.unitynativescripting.bridgecore/Editor/Bridge.Core.Unity.Editor.asmdef.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 3ab35be79f3ae1647ba7baed77a6727f +AssemblyDefinitionImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unitynativescripting.bridgecore/Editor/BridgeCoreIl2cppBuild.cs b/Packages/com.unitynativescripting.bridgecore/Editor/BridgeCoreIl2cppBuild.cs new file mode 100644 index 0000000..c70e803 --- /dev/null +++ b/Packages/com.unitynativescripting.bridgecore/Editor/BridgeCoreIl2cppBuild.cs @@ -0,0 +1,46 @@ +using System; +using System.IO; +using UnityEditor; +using UnityEditor.Build.Reporting; +using UnityEngine; + +namespace Bridge.Core.Unity.Editor +{ + public static class BridgeCoreIl2cppBuild + { + // 命令行示例: + // Unity.exe -batchmode -quit -projectPath -executeMethod Bridge.Core.Unity.Editor.BridgeCoreIl2cppBuild.BuildWindows64 -logFile + public static void BuildWindows64() + { + if (!Application.isBatchMode) + Debug.Log("BridgeCore: BuildWindows64 invoked (non-batchmode)."); + + BridgeCoreNativeSourceSync.SyncSourcesForIl2Cpp(); + + EditorUserBuildSettings.SwitchActiveBuildTarget(BuildTargetGroup.Standalone, BuildTarget.StandaloneWindows64); + PlayerSettings.SetScriptingBackend(BuildTargetGroup.Standalone, ScriptingImplementation.IL2CPP); + + string projectRoot = Directory.GetParent(Application.dataPath).FullName; + string outputRoot = Path.GetFullPath(Path.Combine(projectRoot, "..", "..", "build", "unity_il2cpp")); + Directory.CreateDirectory(outputRoot); + + string locationPathName = Path.Combine(outputRoot, "BridgeDemoGame.exe"); + + var options = new BuildPlayerOptions + { + scenes = new[] { "Assets/BridgeDemoGame/Test.unity" }, + locationPathName = locationPathName, + target = BuildTarget.StandaloneWindows64, + options = BuildOptions.None, + }; + + Debug.Log("BridgeCore: building IL2CPP player -> " + locationPathName); + BuildReport report = BuildPipeline.BuildPlayer(options); + if (report.summary.result != BuildResult.Succeeded) + { + throw new Exception("BridgeCore: IL2CPP build failed: " + report.summary.result); + } + } + } +} + diff --git a/Packages/com.unitynativescripting.bridgecore/Editor/BridgeCoreIl2cppBuild.cs.meta b/Packages/com.unitynativescripting.bridgecore/Editor/BridgeCoreIl2cppBuild.cs.meta new file mode 100644 index 0000000..92455e3 --- /dev/null +++ b/Packages/com.unitynativescripting.bridgecore/Editor/BridgeCoreIl2cppBuild.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 43c7d0b9dc3772649a736b42cd1e9c35 \ No newline at end of file diff --git a/Packages/com.unitynativescripting.bridgecore/Editor/BridgeCoreNativeSourceSync.cs b/Packages/com.unitynativescripting.bridgecore/Editor/BridgeCoreNativeSourceSync.cs new file mode 100644 index 0000000..42a845d --- /dev/null +++ b/Packages/com.unitynativescripting.bridgecore/Editor/BridgeCoreNativeSourceSync.cs @@ -0,0 +1,174 @@ +using System; +using System.IO; +using UnityEditor; +using UnityEngine; + +namespace Bridge.Core.Unity.Editor +{ + public static class BridgeCoreNativeSourceSync + { + private const string DestRelativeDir = "Assets/Plugins/x86_64/BridgeCoreSource"; + + [MenuItem("BridgeCore/Windows/Sync C++ Sources (for IL2CPP source plugin)")] + public static void SyncSourcesForIl2Cpp() + { + if (!EnsureWindows()) + return; + + string projectRoot = Directory.GetParent(Application.dataPath).FullName; + string repoRoot = FindRepoRoot(projectRoot); + if (string.IsNullOrEmpty(repoRoot)) + return; + + string destDirAbs = Path.Combine(projectRoot, DestRelativeDir.Replace('/', Path.DirectorySeparatorChar)); + + try + { + EditorUtility.DisplayProgressBar("BridgeCore", "Syncing native sources...", 0.2f); + + if (Directory.Exists(destDirAbs)) + Directory.Delete(destDirAbs, recursive: true); + Directory.CreateDirectory(destDirAbs); + + // Unity 的 source plugin 在出包阶段会把 .cpp/.h 汇总到构建目录并“扁平化”路径, + // 所以这里直接把所需最小文件集也扁平化到插件根目录,并在拷贝时改写 include 路径。 + // + // 规则:把 统一改成 "xxx.h",把相对路径 include 改成同名头文件。 + CopyFlatWithRewrite(repoRoot, destDirAbs); + + string generatedDir = Path.Combine(repoRoot, "Tests", "cpp", "generated"); + if (Directory.Exists(generatedDir)) + { + // 注意:Unity 会把 Plugins 目录下的 .h 当作插件资源参与打包, + // 同名文件会被判定为“插件冲突”并导致 Player Build 失败。 + // 因此这里保证每个生成头文件只拷贝一份(放到插件根目录,便于 include)。 + foreach (string file in Directory.GetFiles(generatedDir, "*.generated.h", SearchOption.TopDirectoryOnly)) + { + string dst = Path.Combine(destDirAbs, Path.GetFileName(file)); + CopyTextWithIncludeRewrite(file, dst); + } + } + + File.WriteAllText(Path.Combine(destDirAbs, "README.txt"), + "Auto-generated by BridgeCoreNativeSourceSync.\n" + + "Delete this folder and re-sync if you change native sources.\n"); + + AssetDatabase.Refresh(ImportAssetOptions.ForceUpdate); + Debug.Log("BridgeCore: synced native sources -> " + DestRelativeDir); + } + catch (Exception e) + { + Debug.LogError("BridgeCore: sync native sources failed:\n" + e); + } + finally + { + EditorUtility.ClearProgressBar(); + } + } + + public static string GetDestRelativeDir() => DestRelativeDir; + + private static bool EnsureWindows() + { +#if !UNITY_EDITOR_WIN + EditorUtility.DisplayDialog("BridgeCore", "此菜单仅用于 Windows Editor。", "OK"); + return false; +#else + return true; +#endif + } + + private static void CopyFlatWithRewrite(string repoRoot, string destDirAbs) + { + var files = new[] + { + Path.Combine(repoRoot, "Core", "cpp", "include", "bridge", "bridge.h"), + Path.Combine(repoRoot, "Core", "cpp", "include", "bridge", "runtime", "core_app.h"), + Path.Combine(repoRoot, "Core", "cpp", "include", "bridge", "runtime", "core_context.h"), + Path.Combine(repoRoot, "Core", "cpp", "include", "bridge", "runtime", "game_entry.h"), + + Path.Combine(repoRoot, "Core", "cpp", "src", "core", "command_stream.h"), + Path.Combine(repoRoot, "Core", "cpp", "src", "core", "command_stream.cpp"), + Path.Combine(repoRoot, "Core", "cpp", "src", "core", "core_instance.h"), + Path.Combine(repoRoot, "Core", "cpp", "src", "core", "core_instance.cpp"), + Path.Combine(repoRoot, "Core", "cpp", "src", "api", "bridge_api.cpp"), + + Path.Combine(repoRoot, "Tests", "cpp", "demo_game", "src", "demo_asset_app.h"), + Path.Combine(repoRoot, "Tests", "cpp", "demo_game", "src", "demo_asset_app.cpp"), + Path.Combine(repoRoot, "Tests", "cpp", "demo_game", "src", "game_entry.cpp"), + }; + + for (int i = 0; i < files.Length; i++) + { + string src = files[i]; + if (!File.Exists(src)) + throw new FileNotFoundException("Missing source file: " + src); + + string dst = Path.Combine(destDirAbs, Path.GetFileName(src)); + CopyTextWithIncludeRewrite(src, dst); + } + } + + private static void CopyTextWithIncludeRewrite(string src, string dst) + { + string ext = Path.GetExtension(src).ToLowerInvariant(); + if (!IsNativeSourceOrHeader(ext)) + { + File.Copy(src, dst, overwrite: true); + return; + } + + string text = File.ReadAllText(src); + + // bridge public headers + text = text.Replace("#include ", "#include \"bridge.h\""); + text = text.Replace("#include ", "#include \"core_app.h\""); + text = text.Replace("#include ", "#include \"core_context.h\""); + text = text.Replace("#include ", "#include \"game_entry.h\""); + + // bridge_api.cpp relative include (when copied out of src/api) + text = text.Replace("#include \"../core/core_instance.h\"", "#include \"core_instance.h\""); + + File.WriteAllText(dst, text); + } + + private static bool IsNativeSourceOrHeader(string ext) + { + if (string.IsNullOrEmpty(ext)) + return false; + + switch (ext.ToLowerInvariant()) + { + case ".h": + case ".hpp": + case ".c": + case ".cc": + case ".cpp": + case ".m": + case ".mm": + return true; + default: + return false; + } + } + + private static string FindRepoRoot(string startDir) + { + string dir = startDir; + for (int i = 0; i < 12; i++) + { + if (File.Exists(Path.Combine(dir, "CMakeLists.txt")) && + Directory.Exists(Path.Combine(dir, "Core"))) + return dir; + + var parent = Directory.GetParent(dir); + if (parent == null) + break; + dir = parent.FullName; + } + + EditorUtility.DisplayDialog("BridgeCore", "无法定位仓库根目录。起始目录:" + startDir, "OK"); + return string.Empty; + } + } +} diff --git a/Packages/com.unitynativescripting.bridgecore/Editor/BridgeCoreNativeSourceSync.cs.meta b/Packages/com.unitynativescripting.bridgecore/Editor/BridgeCoreNativeSourceSync.cs.meta new file mode 100644 index 0000000..ed1a8f7 --- /dev/null +++ b/Packages/com.unitynativescripting.bridgecore/Editor/BridgeCoreNativeSourceSync.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: f98e826f6c5ea024088bdf79e8463c7e \ No newline at end of file diff --git a/Packages/com.unitynativescripting.bridgecore/Editor/BridgeCorePerfCli.cs b/Packages/com.unitynativescripting.bridgecore/Editor/BridgeCorePerfCli.cs new file mode 100644 index 0000000..ff53ba8 --- /dev/null +++ b/Packages/com.unitynativescripting.bridgecore/Editor/BridgeCorePerfCli.cs @@ -0,0 +1,226 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text.RegularExpressions; +using UnityEditor; +using UnityEditor.TestTools.TestRunner.Api; +using UnityEngine; +using Unity.PerformanceTesting.Data; + +namespace Bridge.Core.Unity.Editor +{ + public static class BridgeCorePerfCli + { + // 命令行示例: + // Unity.exe -batchmode -nographics -projectPath -executeMethod Bridge.Core.Unity.Editor.BridgeCorePerfCli.RunEditMode -testResults -perfTestResults -logFile + public static void RunEditMode() + { + string[] args = Environment.GetCommandLineArgs(); + string xmlPath = FindOption(args, "testResults") ?? Path.Combine(Directory.GetCurrentDirectory(), "TestResults.xml"); + string perfPath = FindOption(args, "perfTestResults") ?? Path.Combine(Directory.GetCurrentDirectory(), "PerfResults.json"); + + var callbacks = ScriptableObject.CreateInstance(); + callbacks.SetPaths(xmlPath, perfPath); + + var api = ScriptableObject.CreateInstance(); + api.RegisterCallbacks(callbacks); + + var filter = new Filter + { + testMode = TestMode.EditMode, + assemblyNames = new[] { "BridgeDemoGame.PerformanceTests" }, + }; + + var settings = new ExecutionSettings(filter) + { + runSynchronously = false + }; + + Debug.Log("BridgeCorePerfCli: running EditMode performance tests..."); + api.Execute(settings); + } + + private static string FindOption(string[] args, string name) + { + string dash = "-" + name; + for (int i = 0; i < args.Length - 1; i++) + { + if (string.Equals(args[i], dash, StringComparison.OrdinalIgnoreCase)) + return args[i + 1]; + } + return null; + } + + private sealed class ResultsAndPerfSavingCallbacks : ScriptableObject, ICallbacks + { + private string _xmlPath = string.Empty; + private string _perfPath = string.Empty; + + public int ExitCode { get; private set; } = 1; + + public void SetPaths(string xmlPath, string perfPath) + { + _xmlPath = xmlPath ?? string.Empty; + _perfPath = perfPath ?? string.Empty; + } + + public void RunStarted(ITestAdaptor testsToRun) + { + } + + public void RunFinished(ITestResultAdaptor result) + { + try + { + if (!string.IsNullOrWhiteSpace(_xmlPath)) + { + EnsureDir(_xmlPath); + TestRunnerApi.SaveResultToFile(result, _xmlPath); + Debug.Log("BridgeCorePerfCli: saved test results -> " + _xmlPath); + } + } + catch (Exception e) + { + Debug.LogError("BridgeCorePerfCli: failed to save test results:\n" + e); + } + + try + { + if (!string.IsNullOrWhiteSpace(_perfPath)) + { + var run = ExtractPerformanceRunData(GetTestOutputsRecursively(result)); + if (run != null) + { + string json = JsonUtility.ToJson(run, true); + EnsureDir(_perfPath); + File.WriteAllText(_perfPath, json); + Debug.Log("BridgeCorePerfCli: saved perf results -> " + _perfPath); + } + else + { + Debug.LogWarning("BridgeCorePerfCli: no perf markers found in test output (perfResults.json not written)."); + } + } + } + catch (Exception e) + { + Debug.LogError("BridgeCorePerfCli: failed to save perf results:\n" + e); + } + + ExitCode = (result.FailCount > 0 || result.InconclusiveCount > 0) ? 1 : 0; + EditorApplication.Exit(ExitCode); + } + + public void TestStarted(ITestAdaptor test) + { + } + + public void TestFinished(ITestResultAdaptor result) + { + } + + private static void EnsureDir(string filePath) + { + string dir = Path.GetDirectoryName(filePath); + if (string.IsNullOrWhiteSpace(dir)) + return; + Directory.CreateDirectory(dir); + } + + private static string[] GetTestOutputsRecursively(ITestResultAdaptor testResults) + { + var outputs = new List(256); + AccumulateTestRunOutputRecursively(testResults, outputs); + return outputs.ToArray(); + } + + private static void AccumulateTestRunOutputRecursively(ITestResultAdaptor parent, List outputs) + { + foreach (var child in parent.Children) + AccumulateTestRunOutputRecursively(child, outputs); + + string output = parent.Output; + if (!string.IsNullOrEmpty(output)) + outputs.Add(output); + } + + private static Run ExtractPerformanceRunData(string[] testOutputs) + { + if (testOutputs == null || testOutputs.Length == 0) + return null; + + Run run = ExtractPerformanceTestRunInfo(testOutputs); + if (run == null) + return null; + + DeserializeTestResults(testOutputs, run); + return run; + } + + private static Run ExtractPerformanceTestRunInfo(string[] testOutputs) + { + foreach (string output in testOutputs) + { + const string pattern = @"##performancetestruninfo2:(.+)\n"; + var matches = Regex.Match(output, pattern); + if (!matches.Success || matches.Groups.Count < 2) + continue; + + string json = matches.Groups[1].Value; + if (string.IsNullOrEmpty(json)) + return null; + + return JsonUtility.FromJson(json); + } + return null; + } + + private static void DeserializeTestResults(string[] testOutputs, Run run) + { + foreach (string output in testOutputs) + { + foreach (string line in output.Split('\n')) + { + string json = GetJsonFromHashtag("performancetestresult2", line); + if (json == null) + continue; + + var result = JsonUtility.FromJson(json); + if (result != null) + run.Results.Add(result); + } + } + } + + private static string GetJsonFromHashtag(string tag, string line) + { + string prefix = "##" + tag + ":"; + if (!line.Contains(prefix)) + return null; + + int jsonStart = line.IndexOf('{'); + if (jsonStart < 0) + return null; + + int open = 0; + int i = jsonStart; + while (i < line.Length && (open > 0 || i == jsonStart)) + { + char c = line[i]; + switch (c) + { + case '{': open++; break; + case '}': open--; break; + } + i++; + } + + if (open != 0) + return null; + + return line.Substring(jsonStart, i - jsonStart); + } + } + } +} diff --git a/Packages/com.unitynativescripting.bridgecore/Editor/BridgeCorePerfCli.cs.meta b/Packages/com.unitynativescripting.bridgecore/Editor/BridgeCorePerfCli.cs.meta new file mode 100644 index 0000000..6c2cb2b --- /dev/null +++ b/Packages/com.unitynativescripting.bridgecore/Editor/BridgeCorePerfCli.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 533dc320f6daf0a4bab4c20cef8126fb \ No newline at end of file diff --git a/Packages/com.unitynativescripting.bridgecore/Editor/BridgeCoreRuntimeUnitTestBuild.cs b/Packages/com.unitynativescripting.bridgecore/Editor/BridgeCoreRuntimeUnitTestBuild.cs new file mode 100644 index 0000000..e63e10f --- /dev/null +++ b/Packages/com.unitynativescripting.bridgecore/Editor/BridgeCoreRuntimeUnitTestBuild.cs @@ -0,0 +1,75 @@ +using System; +using System.Linq; +using System.Reflection; +using UnityEditor; +using UnityEngine; + +namespace Bridge.Core.Unity.Editor +{ + public static class BridgeCoreRuntimeUnitTestBuild + { + // 命令行示例: + // Unity.exe -quit -batchmode -nographics -logFile -projectPath -executeMethod Bridge.Core.Unity.Editor.BridgeCoreRuntimeUnitTestBuild.BuildUnitTest + // /headless /ScriptBackend IL2CPP /BuildTarget StandaloneWindows64 + public static void BuildUnitTest() + { + // Player 下依赖 bridge_core.dll,确保同步到 Assets/Plugins 并正确配置导入器 + BridgeCoreWinSync.SyncForPlayer(); + +#if UNITY_2021_2_OR_NEWER + // RuntimeUnitTestToolkit 的 /Headless 会走 Dedicated Server 子目标。 + // 这里强制回到普通 Player,避免环境里残留 Server 子目标导致构建失败。 + EditorUserBuildSettings.standaloneBuildSubtarget = StandaloneBuildSubtarget.Player; +#endif + + InvokeUnitTestBuilder(); + } + + private static void InvokeUnitTestBuilder() + { + Type builderType = AppDomain.CurrentDomain + .GetAssemblies() + .Select(a => + { + try { return a.GetType("UnitTestBuilder", throwOnError: false); } + catch { return null; } + }) + .FirstOrDefault(t => t != null); + + if (builderType == null) + throw new InvalidOperationException("UnitTestBuilder not found. Ensure RuntimeUnitTestToolkit is installed in this Unity project."); + + MethodInfo[] candidates = builderType + .GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static) + .Where(m => string.Equals(m.Name, "BuildUnitTest", StringComparison.Ordinal)) + .ToArray(); + + if (candidates.Length == 0) + throw new MissingMethodException("UnitTestBuilder", "BuildUnitTest"); + + MethodInfo mi = candidates.FirstOrDefault(m => m.GetParameters().Length == 0); + object[] invokeArgs = null; + + if (mi == null) + { + mi = candidates.FirstOrDefault(m => + { + var ps = m.GetParameters(); + return ps.Length == 1 && ps[0].ParameterType == typeof(string[]); + }); + if (mi != null) + invokeArgs = new object[] { Environment.GetCommandLineArgs() }; + } + + if (mi == null) + { + mi = candidates[0]; + var ps = mi.GetParameters(); + invokeArgs = ps.Length == 0 ? null : new object[ps.Length]; + } + + Debug.Log("BridgeCoreRuntimeUnitTestBuild: invoking UnitTestBuilder.BuildUnitTest ..."); + mi.Invoke(null, invokeArgs); + } + } +} diff --git a/Packages/com.unitynativescripting.bridgecore/Editor/BridgeCoreRuntimeUnitTestBuild.cs.meta b/Packages/com.unitynativescripting.bridgecore/Editor/BridgeCoreRuntimeUnitTestBuild.cs.meta new file mode 100644 index 0000000..5d99d39 --- /dev/null +++ b/Packages/com.unitynativescripting.bridgecore/Editor/BridgeCoreRuntimeUnitTestBuild.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 0418938fc9a528f449e7aa4e4e37e7d1 \ No newline at end of file diff --git a/Tests/unity/Assets/BridgeCore/Editor/BridgeCoreWinHotReload.cs b/Packages/com.unitynativescripting.bridgecore/Editor/BridgeCoreWinHotReload.cs similarity index 100% rename from Tests/unity/Assets/BridgeCore/Editor/BridgeCoreWinHotReload.cs rename to Packages/com.unitynativescripting.bridgecore/Editor/BridgeCoreWinHotReload.cs diff --git a/Tests/unity/Assets/BridgeCore/Editor/BridgeCoreWinHotReload.cs.meta b/Packages/com.unitynativescripting.bridgecore/Editor/BridgeCoreWinHotReload.cs.meta similarity index 99% rename from Tests/unity/Assets/BridgeCore/Editor/BridgeCoreWinHotReload.cs.meta rename to Packages/com.unitynativescripting.bridgecore/Editor/BridgeCoreWinHotReload.cs.meta index dd899c4..82aa638 100644 --- a/Tests/unity/Assets/BridgeCore/Editor/BridgeCoreWinHotReload.cs.meta +++ b/Packages/com.unitynativescripting.bridgecore/Editor/BridgeCoreWinHotReload.cs.meta @@ -9,4 +9,3 @@ MonoImporter: userData: assetBundleName: assetBundleVariant: - diff --git a/Tests/unity/Assets/BridgeCore/Editor/BridgeCoreWinSync.cs b/Packages/com.unitynativescripting.bridgecore/Editor/BridgeCoreWinSync.cs similarity index 100% rename from Tests/unity/Assets/BridgeCore/Editor/BridgeCoreWinSync.cs rename to Packages/com.unitynativescripting.bridgecore/Editor/BridgeCoreWinSync.cs diff --git a/Tests/unity/Assets/BridgeCore/Editor/BridgeCoreWinSync.cs.meta b/Packages/com.unitynativescripting.bridgecore/Editor/BridgeCoreWinSync.cs.meta similarity index 99% rename from Tests/unity/Assets/BridgeCore/Editor/BridgeCoreWinSync.cs.meta rename to Packages/com.unitynativescripting.bridgecore/Editor/BridgeCoreWinSync.cs.meta index 6122c68..c65ac67 100644 --- a/Tests/unity/Assets/BridgeCore/Editor/BridgeCoreWinSync.cs.meta +++ b/Packages/com.unitynativescripting.bridgecore/Editor/BridgeCoreWinSync.cs.meta @@ -9,4 +9,3 @@ MonoImporter: userData: assetBundleName: assetBundleVariant: - diff --git a/Tests/unity/Assets/BridgeCore/README.md b/Packages/com.unitynativescripting.bridgecore/README.md similarity index 57% rename from Tests/unity/Assets/BridgeCore/README.md rename to Packages/com.unitynativescripting.bridgecore/README.md index 72e5efe..9a77387 100644 --- a/Tests/unity/Assets/BridgeCore/README.md +++ b/Packages/com.unitynativescripting.bridgecore/README.md @@ -1,5 +1,12 @@ # BridgeCore(Unity 侧) +## 作为 Unity Package 使用 + +此目录为标准 UPM 包(`com.unitynativescripting.bridgecore`)。在其他 Unity 工程中可通过 `Packages/manifest.json` 引用: + +- Git(推荐):`"com.unitynativescripting.bridgecore": "git+.git?path=/Packages/com.unitynativescripting.bridgecore"` +- 本地开发:`"com.unitynativescripting.bridgecore": "file:/Packages/com.unitynativescripting.bridgecore"` + 此目录仅提供 **Windows Editor** 下的原生 DLL 加载支持: - 运行时从 `Library/BridgeNative//bridge_core.dll` 加载,避免锁定固定源文件 diff --git a/Tests/unity/Assets/BridgeCore/README.md.meta b/Packages/com.unitynativescripting.bridgecore/README.md.meta similarity index 99% rename from Tests/unity/Assets/BridgeCore/README.md.meta rename to Packages/com.unitynativescripting.bridgecore/README.md.meta index 4adbc07..dd63133 100644 --- a/Tests/unity/Assets/BridgeCore/README.md.meta +++ b/Packages/com.unitynativescripting.bridgecore/README.md.meta @@ -5,4 +5,3 @@ TextScriptImporter: userData: assetBundleName: assetBundleVariant: - diff --git a/Tests/unity/Assets/BridgeCore/Runtime.meta b/Packages/com.unitynativescripting.bridgecore/Runtime.meta similarity index 76% rename from Tests/unity/Assets/BridgeCore/Runtime.meta rename to Packages/com.unitynativescripting.bridgecore/Runtime.meta index faa4a3e..d796681 100644 --- a/Tests/unity/Assets/BridgeCore/Runtime.meta +++ b/Packages/com.unitynativescripting.bridgecore/Runtime.meta @@ -1,9 +1,8 @@ fileFormatVersion: 2 -guid: 68c0e37d26ce4c98bdc3a62bbd7984e0 +guid: 6ce5d14460898e048ac4aa9114ca610f folderAsset: yes DefaultImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: - diff --git a/Tests/unity/Assets/BridgeCore.meta b/Packages/com.unitynativescripting.bridgecore/Runtime/Bridge.Core.Unity.meta similarity index 76% rename from Tests/unity/Assets/BridgeCore.meta rename to Packages/com.unitynativescripting.bridgecore/Runtime/Bridge.Core.Unity.meta index 97fe715..b911889 100644 --- a/Tests/unity/Assets/BridgeCore.meta +++ b/Packages/com.unitynativescripting.bridgecore/Runtime/Bridge.Core.Unity.meta @@ -1,9 +1,8 @@ fileFormatVersion: 2 -guid: 9a3d65f0cde84a1fb2f5b7c9a1e4c2d1 +guid: 17491c44e867fa14a8686feefaa5f75a folderAsset: yes DefaultImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: - diff --git a/Tests/unity/Assets/BridgeCore/Runtime/Bridge.Core.Unity.asmdef b/Packages/com.unitynativescripting.bridgecore/Runtime/Bridge.Core.Unity/Bridge.Core.Unity.asmdef similarity index 100% rename from Tests/unity/Assets/BridgeCore/Runtime/Bridge.Core.Unity.asmdef rename to Packages/com.unitynativescripting.bridgecore/Runtime/Bridge.Core.Unity/Bridge.Core.Unity.asmdef diff --git a/Tests/unity/Assets/BridgeCore/Runtime/Bridge.Core.Unity.asmdef.meta b/Packages/com.unitynativescripting.bridgecore/Runtime/Bridge.Core.Unity/Bridge.Core.Unity.asmdef.meta similarity index 100% rename from Tests/unity/Assets/BridgeCore/Runtime/Bridge.Core.Unity.asmdef.meta rename to Packages/com.unitynativescripting.bridgecore/Runtime/Bridge.Core.Unity/Bridge.Core.Unity.asmdef.meta diff --git a/Tests/unity/Assets/BridgeCore/Runtime/BridgeCoreWinLoader.cs b/Packages/com.unitynativescripting.bridgecore/Runtime/Bridge.Core.Unity/BridgeCoreWinLoader.cs similarity index 100% rename from Tests/unity/Assets/BridgeCore/Runtime/BridgeCoreWinLoader.cs rename to Packages/com.unitynativescripting.bridgecore/Runtime/Bridge.Core.Unity/BridgeCoreWinLoader.cs diff --git a/Tests/unity/Assets/BridgeCore/Runtime/BridgeCoreWinLoader.cs.meta b/Packages/com.unitynativescripting.bridgecore/Runtime/Bridge.Core.Unity/BridgeCoreWinLoader.cs.meta similarity index 99% rename from Tests/unity/Assets/BridgeCore/Runtime/BridgeCoreWinLoader.cs.meta rename to Packages/com.unitynativescripting.bridgecore/Runtime/Bridge.Core.Unity/BridgeCoreWinLoader.cs.meta index 3cb8cd7..43fdb02 100644 --- a/Tests/unity/Assets/BridgeCore/Runtime/BridgeCoreWinLoader.cs.meta +++ b/Packages/com.unitynativescripting.bridgecore/Runtime/Bridge.Core.Unity/BridgeCoreWinLoader.cs.meta @@ -9,4 +9,3 @@ MonoImporter: userData: assetBundleName: assetBundleVariant: - diff --git a/Tests/unity/Assets/BridgeCore/Managed/Bridge.Core.meta b/Packages/com.unitynativescripting.bridgecore/Runtime/Bridge.Core.meta similarity index 76% rename from Tests/unity/Assets/BridgeCore/Managed/Bridge.Core.meta rename to Packages/com.unitynativescripting.bridgecore/Runtime/Bridge.Core.meta index 9ad2a1d..97de7c4 100644 --- a/Tests/unity/Assets/BridgeCore/Managed/Bridge.Core.meta +++ b/Packages/com.unitynativescripting.bridgecore/Runtime/Bridge.Core.meta @@ -1,9 +1,8 @@ fileFormatVersion: 2 -guid: 0a1b9c0b1a3c4d5e9f1a2b3c4d5e6f70 +guid: 896db550b6c776942bc12a96ca2b8a87 folderAsset: yes DefaultImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: - diff --git a/Tests/unity/Assets/BridgeCore/Managed/Bridge.Core/Bridge.Core.asmdef b/Packages/com.unitynativescripting.bridgecore/Runtime/Bridge.Core/Bridge.Core.asmdef similarity index 100% rename from Tests/unity/Assets/BridgeCore/Managed/Bridge.Core/Bridge.Core.asmdef rename to Packages/com.unitynativescripting.bridgecore/Runtime/Bridge.Core/Bridge.Core.asmdef diff --git a/Tests/unity/Assets/BridgeCore/Managed/Bridge.Core/Bridge.Core.asmdef.meta b/Packages/com.unitynativescripting.bridgecore/Runtime/Bridge.Core/Bridge.Core.asmdef.meta similarity index 100% rename from Tests/unity/Assets/BridgeCore/Managed/Bridge.Core/Bridge.Core.asmdef.meta rename to Packages/com.unitynativescripting.bridgecore/Runtime/Bridge.Core/Bridge.Core.asmdef.meta diff --git a/Packages/com.unitynativescripting.bridgecore/Runtime/Bridge.Core/BridgeCore.cs b/Packages/com.unitynativescripting.bridgecore/Runtime/Bridge.Core/BridgeCore.cs new file mode 100644 index 0000000..4914876 --- /dev/null +++ b/Packages/com.unitynativescripting.bridgecore/Runtime/Bridge.Core/BridgeCore.cs @@ -0,0 +1,191 @@ +using System; + +namespace Bridge.Core +{ + /// + /// 原生 BridgeCore 的托管封装(Host 侧入口)。 + /// + public sealed class BridgeCore : IDisposable + { + private const int StackAllocMaxCount = 1024; + + [ThreadStatic] private static IntPtr[]? s_tickManyCorePtrs; + [ThreadStatic] private static IntPtr[]? s_tickManyOutPtrs; + [ThreadStatic] private static uint[]? s_tickManyOutLens; + + private IntPtr _handle; + + public BridgeCore(ulong seed = 1, bool robotMode = false) + { + var cfg = new BridgeCoreConfig + { + Seed = seed, + Mode = (uint)(robotMode ? BridgeMode.Robot : BridgeMode.Game) + }; + + _handle = BridgeNative.BridgeCore_Create(cfg); + if (_handle == IntPtr.Zero) + throw new InvalidOperationException("BridgeCore_Create returned null"); + } + + /// + /// 推进 Core 一帧(或一个逻辑 tick)。 + /// + public void Tick(float dt) + { + ThrowIfDisposed(); + BridgeNative.BridgeCore_Tick(_handle, dt); + } + + /// + /// 推进 Core 一帧,并直接返回本帧生成的命令字节流(减少一次 P/Invoke)。 + /// + public CommandStream TickAndGetCommandStream(float dt) + { + ThrowIfDisposed(); + var result = BridgeNative.BridgeCore_TickAndGetCommandStream(_handle, dt, out var ptr, out var len); + if (result != BridgeResult.Ok || ptr == IntPtr.Zero || len == 0) + return CommandStream.Empty; + + return new CommandStream(ptr, len); + } + + /// + /// 预分配 在大规模 cores 下的临时缓冲,避免首帧分配计入性能统计。 + /// + public static void PrepareTickManyCache(int count) + { + if (count <= StackAllocMaxCount) + return; + if (count < 0) + throw new ArgumentOutOfRangeException(nameof(count)); + + EnsureTickManyArrays(count); + } + + public static unsafe void TickManyAndGetCommandStreams(BridgeCore[] cores, float dt, CommandStream[] streams) + { + if (cores == null) + throw new ArgumentNullException(nameof(cores)); + if (streams == null) + throw new ArgumentNullException(nameof(streams)); + if (streams.Length < cores.Length) + throw new ArgumentException("streams.Length must be >= cores.Length", nameof(streams)); + + int count = cores.Length; + if (count == 0) + return; + + if (count <= StackAllocMaxCount) + { + IntPtr* corePtrs = stackalloc IntPtr[count]; + for (int i = 0; i < count; i++) + { + BridgeCore core = cores[i] ?? throw new ArgumentNullException(nameof(cores), $"cores[{i}] is null"); + core.ThrowIfDisposed(); + corePtrs[i] = core._handle; + } + + IntPtr* outPtrs = stackalloc IntPtr[count]; + uint* outLens = stackalloc uint[count]; + + var result = BridgeNative.BridgeCore_TickManyAndGetCommandStreams(corePtrs, (uint)count, dt, outPtrs, outLens); + if (result != BridgeResult.Ok) + throw new InvalidOperationException($"BridgeCore_TickManyAndGetCommandStreams failed: {result}"); + + for (int i = 0; i < count; i++) + { + IntPtr ptr = outPtrs[i]; + uint len = outLens[i]; + streams[i] = (ptr == IntPtr.Zero || len == 0) ? CommandStream.Empty : new CommandStream(ptr, len); + } + } + else + { + EnsureTickManyArrays(count); + + IntPtr[] corePtrsManaged = s_tickManyCorePtrs!; + IntPtr[] outPtrsManaged = s_tickManyOutPtrs!; + uint[] outLensManaged = s_tickManyOutLens!; + + for (int i = 0; i < count; i++) + { + BridgeCore core = cores[i] ?? throw new ArgumentNullException(nameof(cores), $"cores[{i}] is null"); + core.ThrowIfDisposed(); + corePtrsManaged[i] = core._handle; + } + + fixed (IntPtr* corePtrs = corePtrsManaged) + fixed (IntPtr* outPtrs = outPtrsManaged) + fixed (uint* outLens = outLensManaged) + { + var result = BridgeNative.BridgeCore_TickManyAndGetCommandStreams(corePtrs, (uint)count, dt, outPtrs, outLens); + if (result != BridgeResult.Ok) + throw new InvalidOperationException($"BridgeCore_TickManyAndGetCommandStreams failed: {result}"); + } + + for (int i = 0; i < count; i++) + { + IntPtr ptr = outPtrsManaged[i]; + uint len = outLensManaged[i]; + streams[i] = (ptr == IntPtr.Zero || len == 0) ? CommandStream.Empty : new CommandStream(ptr, len); + } + } + } + + private static void EnsureTickManyArrays(int count) + { + s_tickManyCorePtrs ??= new IntPtr[count]; + s_tickManyOutPtrs ??= new IntPtr[count]; + s_tickManyOutLens ??= new uint[count]; + + if (s_tickManyCorePtrs.Length < count) s_tickManyCorePtrs = new IntPtr[count]; + if (s_tickManyOutPtrs.Length < count) s_tickManyOutPtrs = new IntPtr[count]; + if (s_tickManyOutLens.Length < count) s_tickManyOutLens = new uint[count]; + } + + /// + /// 获取最近一次 生成的命令字节流(command stream)。 + /// + /// + /// 返回指针由原生侧持有,只保证在下一次 (或 )前有效。 + /// + public CommandStream GetCommandStream() + { + ThrowIfDisposed(); + var result = BridgeNative.BridgeCore_GetCommandStream(_handle, out var ptr, out var len); + if (result != BridgeResult.Ok || ptr == IntPtr.Zero || len == 0) + return CommandStream.Empty; + + return new CommandStream(ptr, len); + } + + public void PushCallCore(uint funcId) + { + ThrowIfDisposed(); + BridgeNative.BridgeCore_PushCallCore(_handle, funcId, IntPtr.Zero, 0); + } + + public unsafe void PushCallCore(uint funcId, T payload) where T : unmanaged + { + ThrowIfDisposed(); + BridgeNative.BridgeCore_PushCallCore(_handle, funcId, (IntPtr)(&payload), (uint)sizeof(T)); + } + + public void Dispose() + { + if (_handle != IntPtr.Zero) + { + BridgeNative.BridgeCore_Destroy(_handle); + _handle = IntPtr.Zero; + } + GC.SuppressFinalize(this); + } + + private void ThrowIfDisposed() + { + if (_handle == IntPtr.Zero) + throw new ObjectDisposedException(nameof(BridgeCore)); + } + } +} diff --git a/Tests/unity/Assets/BridgeCore/Managed/Bridge.Core/BridgeCore.cs.meta b/Packages/com.unitynativescripting.bridgecore/Runtime/Bridge.Core/BridgeCore.cs.meta similarity index 99% rename from Tests/unity/Assets/BridgeCore/Managed/Bridge.Core/BridgeCore.cs.meta rename to Packages/com.unitynativescripting.bridgecore/Runtime/Bridge.Core/BridgeCore.cs.meta index e41f58d..b25eec3 100644 --- a/Tests/unity/Assets/BridgeCore/Managed/Bridge.Core/BridgeCore.cs.meta +++ b/Packages/com.unitynativescripting.bridgecore/Runtime/Bridge.Core/BridgeCore.cs.meta @@ -9,4 +9,3 @@ MonoImporter: userData: assetBundleName: assetBundleVariant: - diff --git a/Tests/unity/Assets/BridgeCore/Managed/Bridge.Core/CommandStream.cs b/Packages/com.unitynativescripting.bridgecore/Runtime/Bridge.Core/CommandStream.cs similarity index 99% rename from Tests/unity/Assets/BridgeCore/Managed/Bridge.Core/CommandStream.cs rename to Packages/com.unitynativescripting.bridgecore/Runtime/Bridge.Core/CommandStream.cs index 7608889..cc6cdfe 100644 --- a/Tests/unity/Assets/BridgeCore/Managed/Bridge.Core/CommandStream.cs +++ b/Packages/com.unitynativescripting.bridgecore/Runtime/Bridge.Core/CommandStream.cs @@ -21,4 +21,3 @@ internal CommandStream(IntPtr ptr, uint length) } } } - diff --git a/Tests/unity/Assets/BridgeCore/Managed/Bridge.Core/CommandStream.cs.meta b/Packages/com.unitynativescripting.bridgecore/Runtime/Bridge.Core/CommandStream.cs.meta similarity index 99% rename from Tests/unity/Assets/BridgeCore/Managed/Bridge.Core/CommandStream.cs.meta rename to Packages/com.unitynativescripting.bridgecore/Runtime/Bridge.Core/CommandStream.cs.meta index 261847b..d955359 100644 --- a/Tests/unity/Assets/BridgeCore/Managed/Bridge.Core/CommandStream.cs.meta +++ b/Packages/com.unitynativescripting.bridgecore/Runtime/Bridge.Core/CommandStream.cs.meta @@ -9,4 +9,3 @@ MonoImporter: userData: assetBundleName: assetBundleVariant: - diff --git a/Tests/unity/Assets/BridgeCore/Managed/Bridge.Core/Interop.meta b/Packages/com.unitynativescripting.bridgecore/Runtime/Bridge.Core/Interop.meta similarity index 76% rename from Tests/unity/Assets/BridgeCore/Managed/Bridge.Core/Interop.meta rename to Packages/com.unitynativescripting.bridgecore/Runtime/Bridge.Core/Interop.meta index 938a6ff..fa46928 100644 --- a/Tests/unity/Assets/BridgeCore/Managed/Bridge.Core/Interop.meta +++ b/Packages/com.unitynativescripting.bridgecore/Runtime/Bridge.Core/Interop.meta @@ -1,9 +1,8 @@ fileFormatVersion: 2 -guid: 4b6f3c1a2d4e4f5a8b9c0d1e2f3a4b5c +guid: acd0d11cf4c3f404997c96b9eb462434 folderAsset: yes DefaultImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: - diff --git a/Tests/unity/Assets/BridgeCore/Managed/Bridge.Core/Interop/BridgeNative.cs b/Packages/com.unitynativescripting.bridgecore/Runtime/Bridge.Core/Interop/BridgeNative.cs similarity index 100% rename from Tests/unity/Assets/BridgeCore/Managed/Bridge.Core/Interop/BridgeNative.cs rename to Packages/com.unitynativescripting.bridgecore/Runtime/Bridge.Core/Interop/BridgeNative.cs diff --git a/Tests/unity/Assets/BridgeCore/Managed/Bridge.Core/Interop/BridgeNative.cs.meta b/Packages/com.unitynativescripting.bridgecore/Runtime/Bridge.Core/Interop/BridgeNative.cs.meta similarity index 99% rename from Tests/unity/Assets/BridgeCore/Managed/Bridge.Core/Interop/BridgeNative.cs.meta rename to Packages/com.unitynativescripting.bridgecore/Runtime/Bridge.Core/Interop/BridgeNative.cs.meta index 13e928f..35097bc 100644 --- a/Tests/unity/Assets/BridgeCore/Managed/Bridge.Core/Interop/BridgeNative.cs.meta +++ b/Packages/com.unitynativescripting.bridgecore/Runtime/Bridge.Core/Interop/BridgeNative.cs.meta @@ -9,4 +9,3 @@ MonoImporter: userData: assetBundleName: assetBundleVariant: - diff --git a/Tests/unity/Assets/BridgeCore/Managed/Bridge.Core/Interop/Structs.cs b/Packages/com.unitynativescripting.bridgecore/Runtime/Bridge.Core/Interop/Structs.cs similarity index 100% rename from Tests/unity/Assets/BridgeCore/Managed/Bridge.Core/Interop/Structs.cs rename to Packages/com.unitynativescripting.bridgecore/Runtime/Bridge.Core/Interop/Structs.cs diff --git a/Tests/unity/Assets/BridgeCore/Managed/Bridge.Core/Interop/Structs.cs.meta b/Packages/com.unitynativescripting.bridgecore/Runtime/Bridge.Core/Interop/Structs.cs.meta similarity index 99% rename from Tests/unity/Assets/BridgeCore/Managed/Bridge.Core/Interop/Structs.cs.meta rename to Packages/com.unitynativescripting.bridgecore/Runtime/Bridge.Core/Interop/Structs.cs.meta index 3248d78..2df867a 100644 --- a/Tests/unity/Assets/BridgeCore/Managed/Bridge.Core/Interop/Structs.cs.meta +++ b/Packages/com.unitynativescripting.bridgecore/Runtime/Bridge.Core/Interop/Structs.cs.meta @@ -9,4 +9,3 @@ MonoImporter: userData: assetBundleName: assetBundleVariant: - diff --git a/Packages/com.unitynativescripting.bridgecore/package.json b/Packages/com.unitynativescripting.bridgecore/package.json new file mode 100644 index 0000000..44da5cc --- /dev/null +++ b/Packages/com.unitynativescripting.bridgecore/package.json @@ -0,0 +1,10 @@ +{ + "name": "com.unitynativescripting.bridgecore", + "version": "0.1.0", + "displayName": "Bridge Core (UnityNativeScripting)", + "description": "Core-first native runtime bridge (command stream polling, no native->managed callbacks).", + "unity": "6000.0", + "author": { + "name": "UnityNativeScripting" + } +} diff --git a/Packages/com.unitynativescripting.bridgecore/package.json.meta b/Packages/com.unitynativescripting.bridgecore/package.json.meta new file mode 100644 index 0000000..aa1cda1 --- /dev/null +++ b/Packages/com.unitynativescripting.bridgecore/package.json.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: c1f8ebe805640eb40b31bb88cc6f18a1 +PackageManifestImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Tests/cpp/demo_game/CMakeLists.txt b/Tests/cpp/demo_game/CMakeLists.txt index 3f36183..cd1b81c 100644 --- a/Tests/cpp/demo_game/CMakeLists.txt +++ b/Tests/cpp/demo_game/CMakeLists.txt @@ -11,9 +11,7 @@ target_link_libraries(bridge_demo_game PUBLIC bridge_runtime) target_compile_features(bridge_demo_game PUBLIC cxx_std_20) target_include_directories(bridge_demo_game PRIVATE - ${CMAKE_SOURCE_DIR}/Tests/cpp/demo_asset/generated - ${CMAKE_SOURCE_DIR}/Tests/cpp/demo_entity/generated - ${CMAKE_SOURCE_DIR}/Tests/cpp/demo_log/generated + ${CMAKE_SOURCE_DIR}/Tests/cpp/generated ) if (MSVC) diff --git a/Tests/cpp/demo_asset/generated/demo_asset_bindings.generated.h b/Tests/cpp/generated/demo_asset_bindings.generated.h similarity index 100% rename from Tests/cpp/demo_asset/generated/demo_asset_bindings.generated.h rename to Tests/cpp/generated/demo_asset_bindings.generated.h diff --git a/Tests/cpp/demo_entity/generated/demo_entity_bindings.generated.h b/Tests/cpp/generated/demo_entity_bindings.generated.h similarity index 100% rename from Tests/cpp/demo_entity/generated/demo_entity_bindings.generated.h rename to Tests/cpp/generated/demo_entity_bindings.generated.h diff --git a/Tests/cpp/demo_log/generated/demo_log_bindings.generated.h b/Tests/cpp/generated/demo_log_bindings.generated.h similarity index 100% rename from Tests/cpp/demo_log/generated/demo_log_bindings.generated.h rename to Tests/cpp/generated/demo_log_bindings.generated.h diff --git a/Tests/cpp/robot_runner/CMakeLists.txt b/Tests/cpp/robot_runner/CMakeLists.txt index c35ffbc..96a3af6 100644 --- a/Tests/cpp/robot_runner/CMakeLists.txt +++ b/Tests/cpp/robot_runner/CMakeLists.txt @@ -6,7 +6,7 @@ target_link_libraries(bridge_robot_runner PRIVATE bridge_core) target_compile_features(bridge_robot_runner PRIVATE cxx_std_20) target_include_directories(bridge_robot_runner PRIVATE - ${CMAKE_SOURCE_DIR}/Tests/cpp/demo_asset/generated + ${CMAKE_SOURCE_DIR}/Tests/cpp/generated ) if (MSVC) diff --git a/Tests/csharp/RobotHost/Bind/RobotHostApi.cs b/Tests/csharp/RobotHost/Bind/RobotHostApi.cs index d3e9ff6..671f42b 100644 --- a/Tests/csharp/RobotHost/Bind/RobotHostApi.cs +++ b/Tests/csharp/RobotHost/Bind/RobotHostApi.cs @@ -41,18 +41,18 @@ public void LoadAsset(ulong requestId, BridgeAssetType assetType, BridgeStringVi _core.AssetLoaded(requestId, 0, BridgeAssetStatus.NotFound); } - public void SpawnEntity(ulong entityId, ulong prefabHandle, BridgeTransform transform, uint flags) + public void SpawnEntity(ulong entityId, ulong prefabHandle, in BridgeTransform transform, uint flags) { Commands++; Spawns++; - _world.OnSpawn(entityId, prefabHandle, transform, flags); + _world.OnSpawn(entityId, prefabHandle, in transform, flags); } - public void SetTransform(ulong entityId, uint mask, BridgeTransform transform) + public void SetTransform(ulong entityId, uint mask, in BridgeTransform transform) { Commands++; Transforms++; - _world.OnSetTransform(entityId, mask, transform); + _world.OnSetTransform(entityId, mask, in transform); } public void DestroyEntity(ulong entityId) diff --git a/Tests/csharp/RobotHost/Bind/RobotNullHostApi.cs b/Tests/csharp/RobotHost/Bind/RobotNullHostApi.cs index b8580a6..82c68a7 100644 --- a/Tests/csharp/RobotHost/Bind/RobotNullHostApi.cs +++ b/Tests/csharp/RobotHost/Bind/RobotNullHostApi.cs @@ -39,21 +39,19 @@ public void LoadAsset(ulong requestId, BridgeAssetType assetType, BridgeStringVi _core.AssetLoaded(requestId, handle, BridgeAssetStatus.Ok); } - public void SpawnEntity(ulong entityId, ulong prefabHandle, BridgeTransform transform, uint flags) + public void SpawnEntity(ulong entityId, ulong prefabHandle, in BridgeTransform transform, uint flags) { _ = entityId; _ = prefabHandle; - _ = transform; _ = flags; Commands++; Spawns++; } - public void SetTransform(ulong entityId, uint mask, BridgeTransform transform) + public void SetTransform(ulong entityId, uint mask, in BridgeTransform transform) { _ = entityId; _ = mask; - _ = transform; Commands++; Transforms++; } diff --git a/Tests/csharp/RobotHost/Bind/WorldState.cs b/Tests/csharp/RobotHost/Bind/WorldState.cs index 136bedc..0d9f8fa 100644 --- a/Tests/csharp/RobotHost/Bind/WorldState.cs +++ b/Tests/csharp/RobotHost/Bind/WorldState.cs @@ -11,13 +11,13 @@ public void OnLog(BridgeLogLevel level, BridgeStringView message) _ = message; } - public void OnSpawn(ulong entityId, ulong prefabHandle, BridgeTransform transform, uint flags) + public void OnSpawn(ulong entityId, ulong prefabHandle, in BridgeTransform transform, uint flags) { _ = flags; _entities[entityId] = new Entity(prefabHandle, transform); } - public void OnSetTransform(ulong entityId, uint mask, BridgeTransform transform) + public void OnSetTransform(ulong entityId, uint mask, in BridgeTransform transform) { if (_entities.TryGetValue(entityId, out var entity)) { diff --git a/Tests/csharp/RobotHost/Generated/Bridge.AllCommandDispatcher.g.cs b/Tests/csharp/RobotHost/Generated/Bridge.AllCommandDispatcher.g.cs index 70f722f..2c3638c 100644 --- a/Tests/csharp/RobotHost/Generated/Bridge.AllCommandDispatcher.g.cs +++ b/Tests/csharp/RobotHost/Generated/Bridge.AllCommandDispatcher.g.cs @@ -45,7 +45,7 @@ public static unsafe void Dispatch(CommandStream stream, THost host) { if (payloadSize == (uint)sizeof(DemoAsset.Bindings.HostArgs_LoadAsset)) { - var a = *((DemoAsset.Bindings.HostArgs_LoadAsset*)payloadPtr); + ref readonly DemoAsset.Bindings.HostArgs_LoadAsset a = ref *((DemoAsset.Bindings.HostArgs_LoadAsset*)payloadPtr); host.LoadAsset(a.RequestId, a.AssetType, a.AssetKey); } break; @@ -54,8 +54,8 @@ public static unsafe void Dispatch(CommandStream stream, THost host) { if (payloadSize == (uint)sizeof(DemoEntity.Bindings.HostArgs_SpawnEntity)) { - var a = *((DemoEntity.Bindings.HostArgs_SpawnEntity*)payloadPtr); - host.SpawnEntity(a.EntityId, a.PrefabHandle, a.Transform, a.Flags); + ref readonly DemoEntity.Bindings.HostArgs_SpawnEntity a = ref *((DemoEntity.Bindings.HostArgs_SpawnEntity*)payloadPtr); + host.SpawnEntity(a.EntityId, a.PrefabHandle, in a.Transform, a.Flags); } break; } @@ -63,8 +63,8 @@ public static unsafe void Dispatch(CommandStream stream, THost host) { if (payloadSize == (uint)sizeof(DemoEntity.Bindings.HostArgs_SetTransform)) { - var a = *((DemoEntity.Bindings.HostArgs_SetTransform*)payloadPtr); - host.SetTransform(a.EntityId, a.Mask, a.Transform); + ref readonly DemoEntity.Bindings.HostArgs_SetTransform a = ref *((DemoEntity.Bindings.HostArgs_SetTransform*)payloadPtr); + host.SetTransform(a.EntityId, a.Mask, in a.Transform); } break; } @@ -72,7 +72,7 @@ public static unsafe void Dispatch(CommandStream stream, THost host) { if (payloadSize == (uint)sizeof(DemoEntity.Bindings.HostArgs_DestroyEntity)) { - var a = *((DemoEntity.Bindings.HostArgs_DestroyEntity*)payloadPtr); + ref readonly DemoEntity.Bindings.HostArgs_DestroyEntity a = ref *((DemoEntity.Bindings.HostArgs_DestroyEntity*)payloadPtr); host.DestroyEntity(a.EntityId); } break; @@ -81,7 +81,7 @@ public static unsafe void Dispatch(CommandStream stream, THost host) { if (payloadSize == (uint)sizeof(DemoLog.Bindings.HostArgs_Log)) { - var a = *((DemoLog.Bindings.HostArgs_Log*)payloadPtr); + ref readonly DemoLog.Bindings.HostArgs_Log a = ref *((DemoLog.Bindings.HostArgs_Log*)payloadPtr); host.Log(a.Level, a.Message); } break; diff --git a/Tests/csharp/RobotHost/Generated/IDemoEntityHostApi.g.cs b/Tests/csharp/RobotHost/Generated/IDemoEntityHostApi.g.cs index 449e796..7274832 100644 --- a/Tests/csharp/RobotHost/Generated/IDemoEntityHostApi.g.cs +++ b/Tests/csharp/RobotHost/Generated/IDemoEntityHostApi.g.cs @@ -8,8 +8,8 @@ namespace DemoEntity.Bindings { public interface IDemoEntityHostApi { - void SpawnEntity(ulong entityId, ulong prefabHandle, BridgeTransform transform, uint flags); - void SetTransform(ulong entityId, uint mask, BridgeTransform transform); + void SpawnEntity(ulong entityId, ulong prefabHandle, in BridgeTransform transform, uint flags); + void SetTransform(ulong entityId, uint mask, in BridgeTransform transform); void DestroyEntity(ulong entityId); } } diff --git a/Tests/csharp/RobotHost/Program.cs b/Tests/csharp/RobotHost/Program.cs index bb81f6f..0a6a172 100644 --- a/Tests/csharp/RobotHost/Program.cs +++ b/Tests/csharp/RobotHost/Program.cs @@ -108,8 +108,36 @@ private static RunResult Run(int bots, int frames, float dt, string assetsRoot, var streams = new CommandStream[bots]; + BridgeCore.PrepareTickManyCache(bots); + + // Warmup:触发首次 P/Invoke/JIT,避免把一次性开销计入性能数据。 + int warmupFrames = frames > 0 ? 1 : 0; + for (int frame = 0; frame < warmupFrames; frame++) + { + BridgeCore.TickManyAndGetCommandStreams(cores, dt, streams); + for (int i = 0; i < cores.Length; i++) + BridgeAllCommandDispatcher.Dispatch(streams[i], hosts[i]); + } + + ulong baseCommands = 0; + ulong baseAssetRequests = 0; + ulong baseLogs = 0; + ulong baseSpawns = 0; + ulong baseTransforms = 0; + ulong baseDestroys = 0; + for (int i = 0; i < hosts.Length; i++) + { + baseCommands += hosts[i].Commands; + baseAssetRequests += hosts[i].AssetRequests; + baseLogs += hosts[i].Logs; + baseSpawns += hosts[i].Spawns; + baseTransforms += hosts[i].Transforms; + baseDestroys += hosts[i].Destroys; + } + long allocBefore = GC.GetAllocatedBytesForCurrentThread(); var sw = Stopwatch.StartNew(); + long allocAfter = allocBefore; try { @@ -123,12 +151,11 @@ private static RunResult Run(int bots, int frames, float dt, string assetsRoot, finally { sw.Stop(); + allocAfter = GC.GetAllocatedBytesForCurrentThread(); for (int i = 0; i < cores.Length; i++) cores[i].Dispose(); } - long allocAfter = GC.GetAllocatedBytesForCurrentThread(); - ulong totalCommands = 0; ulong totalAssetRequests = 0; ulong totalLogs = 0; @@ -136,20 +163,27 @@ private static RunResult Run(int bots, int frames, float dt, string assetsRoot, ulong totalTransforms = 0; ulong totalDestroys = 0; - for (int i = 0; i < hosts.Length; i++) - { - totalCommands += hosts[i].Commands; - totalAssetRequests += hosts[i].AssetRequests; - totalLogs += hosts[i].Logs; + for (int i = 0; i < hosts.Length; i++) + { + totalCommands += hosts[i].Commands; + totalAssetRequests += hosts[i].AssetRequests; + totalLogs += hosts[i].Logs; totalSpawns += hosts[i].Spawns; totalTransforms += hosts[i].Transforms; - totalDestroys += hosts[i].Destroys; - } + totalDestroys += hosts[i].Destroys; + } - return new RunResult( - elapsedSeconds: sw.Elapsed.TotalSeconds, - allocatedBytes: allocAfter - allocBefore, - totalCommands: totalCommands, + totalCommands -= baseCommands; + totalAssetRequests -= baseAssetRequests; + totalLogs -= baseLogs; + totalSpawns -= baseSpawns; + totalTransforms -= baseTransforms; + totalDestroys -= baseDestroys; + + return new RunResult( + elapsedSeconds: sw.Elapsed.TotalSeconds, + allocatedBytes: allocAfter - allocBefore, + totalCommands: totalCommands, totalAssetRequests: totalAssetRequests, totalLogs: totalLogs, totalSpawns: totalSpawns, @@ -170,8 +204,36 @@ private static RunResult Run(int bots, int frames, float dt, string assetsRoot, var streams = new CommandStream[bots]; + BridgeCore.PrepareTickManyCache(bots); + + // Warmup:触发首次 P/Invoke/JIT,避免把一次性开销计入性能数据。 + int warmupFrames = frames > 0 ? 1 : 0; + for (int frame = 0; frame < warmupFrames; frame++) + { + BridgeCore.TickManyAndGetCommandStreams(cores, dt, streams); + for (int i = 0; i < cores.Length; i++) + BridgeAllCommandDispatcher.Dispatch(streams[i], hosts[i]); + } + + ulong baseCommands = 0; + ulong baseAssetRequests = 0; + ulong baseLogs = 0; + ulong baseSpawns = 0; + ulong baseTransforms = 0; + ulong baseDestroys = 0; + for (int i = 0; i < hosts.Length; i++) + { + baseCommands += hosts[i].Commands; + baseAssetRequests += hosts[i].AssetRequests; + baseLogs += hosts[i].Logs; + baseSpawns += hosts[i].Spawns; + baseTransforms += hosts[i].Transforms; + baseDestroys += hosts[i].Destroys; + } + long allocBefore = GC.GetAllocatedBytesForCurrentThread(); var sw = Stopwatch.StartNew(); + long allocAfter = allocBefore; try { @@ -185,12 +247,11 @@ private static RunResult Run(int bots, int frames, float dt, string assetsRoot, finally { sw.Stop(); + allocAfter = GC.GetAllocatedBytesForCurrentThread(); for (int i = 0; i < cores.Length; i++) cores[i].Dispose(); } - long allocAfter = GC.GetAllocatedBytesForCurrentThread(); - ulong totalCommands = 0; ulong totalAssetRequests = 0; ulong totalLogs = 0; @@ -198,20 +259,27 @@ private static RunResult Run(int bots, int frames, float dt, string assetsRoot, ulong totalTransforms = 0; ulong totalDestroys = 0; - for (int i = 0; i < hosts.Length; i++) - { - totalCommands += hosts[i].Commands; - totalAssetRequests += hosts[i].AssetRequests; - totalLogs += hosts[i].Logs; + for (int i = 0; i < hosts.Length; i++) + { + totalCommands += hosts[i].Commands; + totalAssetRequests += hosts[i].AssetRequests; + totalLogs += hosts[i].Logs; totalSpawns += hosts[i].Spawns; totalTransforms += hosts[i].Transforms; - totalDestroys += hosts[i].Destroys; - } + totalDestroys += hosts[i].Destroys; + } - return new RunResult( - elapsedSeconds: sw.Elapsed.TotalSeconds, - allocatedBytes: allocAfter - allocBefore, - totalCommands: totalCommands, + totalCommands -= baseCommands; + totalAssetRequests -= baseAssetRequests; + totalLogs -= baseLogs; + totalSpawns -= baseSpawns; + totalTransforms -= baseTransforms; + totalDestroys -= baseDestroys; + + return new RunResult( + elapsedSeconds: sw.Elapsed.TotalSeconds, + allocatedBytes: allocAfter - allocBefore, + totalCommands: totalCommands, totalAssetRequests: totalAssetRequests, totalLogs: totalLogs, totalSpawns: totalSpawns, diff --git a/Tests/unity/Assets/BridgeCore/Managed/Bridge.Core/BridgeCore.cs b/Tests/unity/Assets/BridgeCore/Managed/Bridge.Core/BridgeCore.cs deleted file mode 100644 index a8993da..0000000 --- a/Tests/unity/Assets/BridgeCore/Managed/Bridge.Core/BridgeCore.cs +++ /dev/null @@ -1,127 +0,0 @@ -using System; - -namespace Bridge.Core -{ - /// - /// 原生 BridgeCore 的托管封装(Host 侧入口)。 - /// - public sealed class BridgeCore : IDisposable - { - private IntPtr _handle; - - public BridgeCore(ulong seed = 1, bool robotMode = false) - { - var cfg = new BridgeCoreConfig - { - Seed = seed, - Mode = (uint)(robotMode ? BridgeMode.Robot : BridgeMode.Game) - }; - - _handle = BridgeNative.BridgeCore_Create(cfg); - if (_handle == IntPtr.Zero) - throw new InvalidOperationException("BridgeCore_Create returned null"); - } - - /// - /// 推进 Core 一帧(或一个逻辑 tick)。 - /// - public void Tick(float dt) - { - ThrowIfDisposed(); - BridgeNative.BridgeCore_Tick(_handle, dt); - } - - /// - /// 推进 Core 一帧,并直接返回本帧生成的命令字节流(减少一次 P/Invoke)。 - /// - public CommandStream TickAndGetCommandStream(float dt) - { - ThrowIfDisposed(); - var result = BridgeNative.BridgeCore_TickAndGetCommandStream(_handle, dt, out var ptr, out var len); - if (result != BridgeResult.Ok || ptr == IntPtr.Zero || len == 0) - return CommandStream.Empty; - - return new CommandStream(ptr, len); - } - - public static unsafe void TickManyAndGetCommandStreams(BridgeCore[] cores, float dt, CommandStream[] streams) - { - if (cores == null) - throw new ArgumentNullException(nameof(cores)); - if (streams == null) - throw new ArgumentNullException(nameof(streams)); - if (streams.Length < cores.Length) - throw new ArgumentException("streams.Length must be >= cores.Length", nameof(streams)); - - int count = cores.Length; - if (count == 0) - return; - - IntPtr* corePtrs = stackalloc IntPtr[count]; - for (int i = 0; i < count; i++) - { - BridgeCore core = cores[i] ?? throw new ArgumentNullException(nameof(cores), $"cores[{i}] is null"); - core.ThrowIfDisposed(); - corePtrs[i] = core._handle; - } - - IntPtr* outPtrs = stackalloc IntPtr[count]; - uint* outLens = stackalloc uint[count]; - - var result = BridgeNative.BridgeCore_TickManyAndGetCommandStreams(corePtrs, (uint)count, dt, outPtrs, outLens); - if (result != BridgeResult.Ok) - throw new InvalidOperationException($"BridgeCore_TickManyAndGetCommandStreams failed: {result}"); - - for (int i = 0; i < count; i++) - { - IntPtr ptr = outPtrs[i]; - uint len = outLens[i]; - streams[i] = (ptr == IntPtr.Zero || len == 0) ? CommandStream.Empty : new CommandStream(ptr, len); - } - } - - /// - /// 获取最近一次 生成的命令字节流(command stream)。 - /// - /// - /// 返回指针由原生侧持有,只保证在下一次 (或 )前有效。 - /// - public CommandStream GetCommandStream() - { - ThrowIfDisposed(); - var result = BridgeNative.BridgeCore_GetCommandStream(_handle, out var ptr, out var len); - if (result != BridgeResult.Ok || ptr == IntPtr.Zero || len == 0) - return CommandStream.Empty; - - return new CommandStream(ptr, len); - } - - public void PushCallCore(uint funcId) - { - ThrowIfDisposed(); - BridgeNative.BridgeCore_PushCallCore(_handle, funcId, IntPtr.Zero, 0); - } - - public unsafe void PushCallCore(uint funcId, T payload) where T : unmanaged - { - ThrowIfDisposed(); - BridgeNative.BridgeCore_PushCallCore(_handle, funcId, (IntPtr)(&payload), (uint)sizeof(T)); - } - - public void Dispose() - { - if (_handle != IntPtr.Zero) - { - BridgeNative.BridgeCore_Destroy(_handle); - _handle = IntPtr.Zero; - } - GC.SuppressFinalize(this); - } - - private void ThrowIfDisposed() - { - if (_handle == IntPtr.Zero) - throw new ObjectDisposedException(nameof(BridgeCore)); - } - } -} diff --git a/Tests/unity/Assets/BridgeDemoGame/Editor/Performance/BridgeDispatchPerformanceTests.cs b/Tests/unity/Assets/BridgeDemoGame/Editor/Performance/BridgeDispatchPerformanceTests.cs index 3805116..18ef262 100644 --- a/Tests/unity/Assets/BridgeDemoGame/Editor/Performance/BridgeDispatchPerformanceTests.cs +++ b/Tests/unity/Assets/BridgeDemoGame/Editor/Performance/BridgeDispatchPerformanceTests.cs @@ -29,7 +29,7 @@ public void LoadAsset(ulong requestId, BridgeAssetType assetType, BridgeStringVi _core.AssetLoaded(requestId, handle: 1, BridgeAssetStatus.Ok); } - public void SpawnEntity(ulong entityId, ulong prefabHandle, BridgeTransform transform, uint flags) + public void SpawnEntity(ulong entityId, ulong prefabHandle, in BridgeTransform transform, uint flags) { _ = entityId; _ = prefabHandle; @@ -37,7 +37,7 @@ public void SpawnEntity(ulong entityId, ulong prefabHandle, BridgeTransform tran _ = flags; } - public void SetTransform(ulong entityId, uint mask, BridgeTransform transform) + public void SetTransform(ulong entityId, uint mask, in BridgeTransform transform) { _ = entityId; _ = mask; diff --git a/Tests/unity/Assets/BridgeDemoGame/Generated/Bridge.AllCommandDispatcher.g.cs b/Tests/unity/Assets/BridgeDemoGame/Generated/Bridge.AllCommandDispatcher.g.cs index 70f722f..2c3638c 100644 --- a/Tests/unity/Assets/BridgeDemoGame/Generated/Bridge.AllCommandDispatcher.g.cs +++ b/Tests/unity/Assets/BridgeDemoGame/Generated/Bridge.AllCommandDispatcher.g.cs @@ -45,7 +45,7 @@ public static unsafe void Dispatch(CommandStream stream, THost host) { if (payloadSize == (uint)sizeof(DemoAsset.Bindings.HostArgs_LoadAsset)) { - var a = *((DemoAsset.Bindings.HostArgs_LoadAsset*)payloadPtr); + ref readonly DemoAsset.Bindings.HostArgs_LoadAsset a = ref *((DemoAsset.Bindings.HostArgs_LoadAsset*)payloadPtr); host.LoadAsset(a.RequestId, a.AssetType, a.AssetKey); } break; @@ -54,8 +54,8 @@ public static unsafe void Dispatch(CommandStream stream, THost host) { if (payloadSize == (uint)sizeof(DemoEntity.Bindings.HostArgs_SpawnEntity)) { - var a = *((DemoEntity.Bindings.HostArgs_SpawnEntity*)payloadPtr); - host.SpawnEntity(a.EntityId, a.PrefabHandle, a.Transform, a.Flags); + ref readonly DemoEntity.Bindings.HostArgs_SpawnEntity a = ref *((DemoEntity.Bindings.HostArgs_SpawnEntity*)payloadPtr); + host.SpawnEntity(a.EntityId, a.PrefabHandle, in a.Transform, a.Flags); } break; } @@ -63,8 +63,8 @@ public static unsafe void Dispatch(CommandStream stream, THost host) { if (payloadSize == (uint)sizeof(DemoEntity.Bindings.HostArgs_SetTransform)) { - var a = *((DemoEntity.Bindings.HostArgs_SetTransform*)payloadPtr); - host.SetTransform(a.EntityId, a.Mask, a.Transform); + ref readonly DemoEntity.Bindings.HostArgs_SetTransform a = ref *((DemoEntity.Bindings.HostArgs_SetTransform*)payloadPtr); + host.SetTransform(a.EntityId, a.Mask, in a.Transform); } break; } @@ -72,7 +72,7 @@ public static unsafe void Dispatch(CommandStream stream, THost host) { if (payloadSize == (uint)sizeof(DemoEntity.Bindings.HostArgs_DestroyEntity)) { - var a = *((DemoEntity.Bindings.HostArgs_DestroyEntity*)payloadPtr); + ref readonly DemoEntity.Bindings.HostArgs_DestroyEntity a = ref *((DemoEntity.Bindings.HostArgs_DestroyEntity*)payloadPtr); host.DestroyEntity(a.EntityId); } break; @@ -81,7 +81,7 @@ public static unsafe void Dispatch(CommandStream stream, THost host) { if (payloadSize == (uint)sizeof(DemoLog.Bindings.HostArgs_Log)) { - var a = *((DemoLog.Bindings.HostArgs_Log*)payloadPtr); + ref readonly DemoLog.Bindings.HostArgs_Log a = ref *((DemoLog.Bindings.HostArgs_Log*)payloadPtr); host.Log(a.Level, a.Message); } break; diff --git a/Tests/unity/Assets/BridgeDemoGame/Generated/IDemoEntityHostApi.g.cs b/Tests/unity/Assets/BridgeDemoGame/Generated/IDemoEntityHostApi.g.cs index 449e796..7274832 100644 --- a/Tests/unity/Assets/BridgeDemoGame/Generated/IDemoEntityHostApi.g.cs +++ b/Tests/unity/Assets/BridgeDemoGame/Generated/IDemoEntityHostApi.g.cs @@ -8,8 +8,8 @@ namespace DemoEntity.Bindings { public interface IDemoEntityHostApi { - void SpawnEntity(ulong entityId, ulong prefabHandle, BridgeTransform transform, uint flags); - void SetTransform(ulong entityId, uint mask, BridgeTransform transform); + void SpawnEntity(ulong entityId, ulong prefabHandle, in BridgeTransform transform, uint flags); + void SetTransform(ulong entityId, uint mask, in BridgeTransform transform); void DestroyEntity(ulong entityId); } } diff --git a/Tests/unity/Assets/BridgeCore/Managed.meta b/Tests/unity/Assets/BridgeDemoGame/PlayModeTests.meta similarity index 76% rename from Tests/unity/Assets/BridgeCore/Managed.meta rename to Tests/unity/Assets/BridgeDemoGame/PlayModeTests.meta index 3cac82b..6479357 100644 --- a/Tests/unity/Assets/BridgeCore/Managed.meta +++ b/Tests/unity/Assets/BridgeDemoGame/PlayModeTests.meta @@ -1,9 +1,8 @@ fileFormatVersion: 2 -guid: 2d1d2a6c1a6a4b5fb9b6c7c3cdbd6e17 +guid: c225dc2fad3453d47ac270dc8cde87ff folderAsset: yes DefaultImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: - diff --git a/Tests/unity/Assets/BridgeDemoGame/PlayModeTests/BridgeDemoGame.PlayModeTests.asmdef b/Tests/unity/Assets/BridgeDemoGame/PlayModeTests/BridgeDemoGame.PlayModeTests.asmdef new file mode 100644 index 0000000..c2df323 --- /dev/null +++ b/Tests/unity/Assets/BridgeDemoGame/PlayModeTests/BridgeDemoGame.PlayModeTests.asmdef @@ -0,0 +1,12 @@ +{ + "name": "BridgeDemoGame.PlayModeTests", + "references": [ + "Bridge.Core", + "Bridge.Core.Unity", + "BridgeDemoGame.Generated" + ], + "optionalUnityReferences": [ + "TestAssemblies" + ] +} + diff --git a/Tests/unity/Assets/BridgeDemoGame/PlayModeTests/BridgeDemoGame.PlayModeTests.asmdef.meta b/Tests/unity/Assets/BridgeDemoGame/PlayModeTests/BridgeDemoGame.PlayModeTests.asmdef.meta new file mode 100644 index 0000000..80d3277 --- /dev/null +++ b/Tests/unity/Assets/BridgeDemoGame/PlayModeTests/BridgeDemoGame.PlayModeTests.asmdef.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 3b1a96996cd998d4a9e8cdabf4b45943 +AssemblyDefinitionImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: + diff --git a/Tests/unity/Assets/BridgeDemoGame/PlayModeTests/BridgeRuntimeSmokeTests.cs b/Tests/unity/Assets/BridgeDemoGame/PlayModeTests/BridgeRuntimeSmokeTests.cs new file mode 100644 index 0000000..dd53829 --- /dev/null +++ b/Tests/unity/Assets/BridgeDemoGame/PlayModeTests/BridgeRuntimeSmokeTests.cs @@ -0,0 +1,77 @@ +using System.Collections; +using Bridge.Bindings; +using Bridge.Core; +using Bridge.Core.Unity; +using DemoAsset.Bindings; +using DemoEntity.Bindings; +using DemoLog.Bindings; +using NUnit.Framework; +using UnityEngine.TestTools; + +namespace BridgeDemoGame.PlayModeTests +{ + public sealed class BridgeRuntimeSmokeTests + { + private sealed class NullHostApi : IDemoAssetHostApi, IDemoEntityHostApi, IDemoLogHostApi + { + private readonly BridgeCore _core; + + public NullHostApi(BridgeCore core) + { + _core = core; + } + + public void LoadAsset(ulong requestId, BridgeAssetType assetType, BridgeStringView assetKey) + { + _ = assetType; + _ = assetKey; + _core.AssetLoaded(requestId, handle: 1, BridgeAssetStatus.Ok); + } + + public void SpawnEntity(ulong entityId, ulong prefabHandle, in BridgeTransform transform, uint flags) + { + _ = entityId; + _ = prefabHandle; + _ = transform; + _ = flags; + } + + public void SetTransform(ulong entityId, uint mask, in BridgeTransform transform) + { + _ = entityId; + _ = mask; + _ = transform; + } + + public void DestroyEntity(ulong entityId) + { + _ = entityId; + } + + public void Log(BridgeLogLevel level, BridgeStringView message) + { + _ = level; + _ = message; + } + } + + [UnityTest] + public IEnumerator TickAndDispatch_60Frames_NoException() + { +#if UNITY_EDITOR_WIN + BridgeCoreWinLoader.TryEnsureLoaded(); +#endif + using (var core = new BridgeCore(seed: 1, robotMode: true)) + { + var host = new NullHostApi(core); + for (int i = 0; i < 60; i++) + { + var stream = core.TickAndGetCommandStream(1.0f / 60.0f); + BridgeAllCommandDispatcher.Dispatch(stream, host); + yield return null; + } + } + } + } +} + diff --git a/Tests/unity/Assets/BridgeDemoGame/PlayModeTests/BridgeRuntimeSmokeTests.cs.meta b/Tests/unity/Assets/BridgeDemoGame/PlayModeTests/BridgeRuntimeSmokeTests.cs.meta new file mode 100644 index 0000000..5fbdbff --- /dev/null +++ b/Tests/unity/Assets/BridgeDemoGame/PlayModeTests/BridgeRuntimeSmokeTests.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 8fd5b62b9f6a0a64e9cf5c6cbd0a1fbe +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: + diff --git a/Tests/unity/Assets/BridgeDemoGame/Runtime/BridgeDemoGame.Runtime.asmdef b/Tests/unity/Assets/BridgeDemoGame/Runtime/BridgeDemoGame.Runtime.asmdef new file mode 100644 index 0000000..56218cf --- /dev/null +++ b/Tests/unity/Assets/BridgeDemoGame/Runtime/BridgeDemoGame.Runtime.asmdef @@ -0,0 +1,7 @@ +{ + "name": "BridgeDemoGame.Runtime", + "references": [ + "Bridge.Core", + "BridgeDemoGame.Generated" + ] +} diff --git a/Tests/unity/Assets/BridgeDemoGame/Runtime/BridgeDemoGame.Runtime.asmdef.meta b/Tests/unity/Assets/BridgeDemoGame/Runtime/BridgeDemoGame.Runtime.asmdef.meta new file mode 100644 index 0000000..af0f71e --- /dev/null +++ b/Tests/unity/Assets/BridgeDemoGame/Runtime/BridgeDemoGame.Runtime.asmdef.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 45dce2bf4803469b88d471990362587b +AssemblyDefinitionImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Tests/unity/Assets/BridgeDemoGame/Runtime/Host.meta b/Tests/unity/Assets/BridgeDemoGame/Runtime/Host.meta new file mode 100644 index 0000000..51cf478 --- /dev/null +++ b/Tests/unity/Assets/BridgeDemoGame/Runtime/Host.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 77ef319ef4454381aa33ac981657e742 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Tests/unity/Assets/BridgeDemoGame/Runtime/DemoGameUnityAssetService.cs b/Tests/unity/Assets/BridgeDemoGame/Runtime/Host/DemoGameUnityAssetService.cs similarity index 100% rename from Tests/unity/Assets/BridgeDemoGame/Runtime/DemoGameUnityAssetService.cs rename to Tests/unity/Assets/BridgeDemoGame/Runtime/Host/DemoGameUnityAssetService.cs diff --git a/Tests/unity/Assets/BridgeDemoGame/Runtime/DemoGameUnityAssetService.cs.meta b/Tests/unity/Assets/BridgeDemoGame/Runtime/Host/DemoGameUnityAssetService.cs.meta similarity index 99% rename from Tests/unity/Assets/BridgeDemoGame/Runtime/DemoGameUnityAssetService.cs.meta rename to Tests/unity/Assets/BridgeDemoGame/Runtime/Host/DemoGameUnityAssetService.cs.meta index f4548fa..da494e1 100644 --- a/Tests/unity/Assets/BridgeDemoGame/Runtime/DemoGameUnityAssetService.cs.meta +++ b/Tests/unity/Assets/BridgeDemoGame/Runtime/Host/DemoGameUnityAssetService.cs.meta @@ -9,4 +9,3 @@ MonoImporter: userData: assetBundleName: assetBundleVariant: - diff --git a/Tests/unity/Assets/BridgeDemoGame/Runtime/DemoGameUnityHostApi.Asset.cs b/Tests/unity/Assets/BridgeDemoGame/Runtime/Host/DemoGameUnityHostApi.Asset.cs similarity index 100% rename from Tests/unity/Assets/BridgeDemoGame/Runtime/DemoGameUnityHostApi.Asset.cs rename to Tests/unity/Assets/BridgeDemoGame/Runtime/Host/DemoGameUnityHostApi.Asset.cs diff --git a/Tests/unity/Assets/BridgeDemoGame/Runtime/DemoGameUnityHostApi.Asset.cs.meta b/Tests/unity/Assets/BridgeDemoGame/Runtime/Host/DemoGameUnityHostApi.Asset.cs.meta similarity index 99% rename from Tests/unity/Assets/BridgeDemoGame/Runtime/DemoGameUnityHostApi.Asset.cs.meta rename to Tests/unity/Assets/BridgeDemoGame/Runtime/Host/DemoGameUnityHostApi.Asset.cs.meta index 077c05d..618c798 100644 --- a/Tests/unity/Assets/BridgeDemoGame/Runtime/DemoGameUnityHostApi.Asset.cs.meta +++ b/Tests/unity/Assets/BridgeDemoGame/Runtime/Host/DemoGameUnityHostApi.Asset.cs.meta @@ -9,4 +9,3 @@ MonoImporter: userData: assetBundleName: assetBundleVariant: - diff --git a/Tests/unity/Assets/BridgeDemoGame/Runtime/DemoGameUnityHostApi.Entity.cs b/Tests/unity/Assets/BridgeDemoGame/Runtime/Host/DemoGameUnityHostApi.Entity.cs similarity index 91% rename from Tests/unity/Assets/BridgeDemoGame/Runtime/DemoGameUnityHostApi.Entity.cs rename to Tests/unity/Assets/BridgeDemoGame/Runtime/Host/DemoGameUnityHostApi.Entity.cs index 64eef91..0d2e81c 100644 --- a/Tests/unity/Assets/BridgeDemoGame/Runtime/DemoGameUnityHostApi.Entity.cs +++ b/Tests/unity/Assets/BridgeDemoGame/Runtime/Host/DemoGameUnityHostApi.Entity.cs @@ -6,7 +6,7 @@ namespace BridgeDemoGame { public sealed partial class DemoGameUnityHostApi : IDemoEntityHostApi { - public void SpawnEntity(ulong entityId, ulong prefabHandle, BridgeTransform transform, uint flags) + public void SpawnEntity(ulong entityId, ulong prefabHandle, in BridgeTransform transform, uint flags) { _ = prefabHandle; _ = flags; @@ -29,7 +29,7 @@ public void SpawnEntity(ulong entityId, ulong prefabHandle, BridgeTransform tran _entities[entityId] = go; } - public void SetTransform(ulong entityId, uint mask, BridgeTransform transform) + public void SetTransform(ulong entityId, uint mask, in BridgeTransform transform) { Commands++; Transforms++; diff --git a/Tests/unity/Assets/BridgeDemoGame/Runtime/DemoGameUnityHostApi.Entity.cs.meta b/Tests/unity/Assets/BridgeDemoGame/Runtime/Host/DemoGameUnityHostApi.Entity.cs.meta similarity index 99% rename from Tests/unity/Assets/BridgeDemoGame/Runtime/DemoGameUnityHostApi.Entity.cs.meta rename to Tests/unity/Assets/BridgeDemoGame/Runtime/Host/DemoGameUnityHostApi.Entity.cs.meta index 22d674a..50f7beb 100644 --- a/Tests/unity/Assets/BridgeDemoGame/Runtime/DemoGameUnityHostApi.Entity.cs.meta +++ b/Tests/unity/Assets/BridgeDemoGame/Runtime/Host/DemoGameUnityHostApi.Entity.cs.meta @@ -9,4 +9,3 @@ MonoImporter: userData: assetBundleName: assetBundleVariant: - diff --git a/Tests/unity/Assets/BridgeDemoGame/Runtime/DemoGameUnityHostApi.Log.cs b/Tests/unity/Assets/BridgeDemoGame/Runtime/Host/DemoGameUnityHostApi.Log.cs similarity index 100% rename from Tests/unity/Assets/BridgeDemoGame/Runtime/DemoGameUnityHostApi.Log.cs rename to Tests/unity/Assets/BridgeDemoGame/Runtime/Host/DemoGameUnityHostApi.Log.cs diff --git a/Tests/unity/Assets/BridgeDemoGame/Runtime/DemoGameUnityHostApi.Log.cs.meta b/Tests/unity/Assets/BridgeDemoGame/Runtime/Host/DemoGameUnityHostApi.Log.cs.meta similarity index 99% rename from Tests/unity/Assets/BridgeDemoGame/Runtime/DemoGameUnityHostApi.Log.cs.meta rename to Tests/unity/Assets/BridgeDemoGame/Runtime/Host/DemoGameUnityHostApi.Log.cs.meta index 5d0b71e..37d8e35 100644 --- a/Tests/unity/Assets/BridgeDemoGame/Runtime/DemoGameUnityHostApi.Log.cs.meta +++ b/Tests/unity/Assets/BridgeDemoGame/Runtime/Host/DemoGameUnityHostApi.Log.cs.meta @@ -9,4 +9,3 @@ MonoImporter: userData: assetBundleName: assetBundleVariant: - diff --git a/Tests/unity/Assets/BridgeDemoGame/Runtime/DemoGameUnityHostApi.cs b/Tests/unity/Assets/BridgeDemoGame/Runtime/Host/DemoGameUnityHostApi.cs similarity index 100% rename from Tests/unity/Assets/BridgeDemoGame/Runtime/DemoGameUnityHostApi.cs rename to Tests/unity/Assets/BridgeDemoGame/Runtime/Host/DemoGameUnityHostApi.cs diff --git a/Tests/unity/Assets/BridgeDemoGame/Runtime/DemoGameUnityHostApi.cs.meta b/Tests/unity/Assets/BridgeDemoGame/Runtime/Host/DemoGameUnityHostApi.cs.meta similarity index 99% rename from Tests/unity/Assets/BridgeDemoGame/Runtime/DemoGameUnityHostApi.cs.meta rename to Tests/unity/Assets/BridgeDemoGame/Runtime/Host/DemoGameUnityHostApi.cs.meta index 37fa085..5aaad39 100644 --- a/Tests/unity/Assets/BridgeDemoGame/Runtime/DemoGameUnityHostApi.cs.meta +++ b/Tests/unity/Assets/BridgeDemoGame/Runtime/Host/DemoGameUnityHostApi.cs.meta @@ -9,4 +9,3 @@ MonoImporter: userData: assetBundleName: assetBundleVariant: - diff --git a/Tests/unity/Assets/BridgeDemoGame/Runtime/Runner.meta b/Tests/unity/Assets/BridgeDemoGame/Runtime/Runner.meta new file mode 100644 index 0000000..e00fddd --- /dev/null +++ b/Tests/unity/Assets/BridgeDemoGame/Runtime/Runner.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 26b61929c9824a008a2dc2e17c57e93d +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Tests/unity/Assets/BridgeDemoGame/Runtime/DemoGameUnityRunner.cs b/Tests/unity/Assets/BridgeDemoGame/Runtime/Runner/DemoGameUnityRunner.cs similarity index 100% rename from Tests/unity/Assets/BridgeDemoGame/Runtime/DemoGameUnityRunner.cs rename to Tests/unity/Assets/BridgeDemoGame/Runtime/Runner/DemoGameUnityRunner.cs diff --git a/Tests/unity/Assets/BridgeDemoGame/Runtime/DemoGameUnityRunner.cs.meta b/Tests/unity/Assets/BridgeDemoGame/Runtime/Runner/DemoGameUnityRunner.cs.meta similarity index 99% rename from Tests/unity/Assets/BridgeDemoGame/Runtime/DemoGameUnityRunner.cs.meta rename to Tests/unity/Assets/BridgeDemoGame/Runtime/Runner/DemoGameUnityRunner.cs.meta index 4d65dff..0a2fc26 100644 --- a/Tests/unity/Assets/BridgeDemoGame/Runtime/DemoGameUnityRunner.cs.meta +++ b/Tests/unity/Assets/BridgeDemoGame/Runtime/Runner/DemoGameUnityRunner.cs.meta @@ -9,4 +9,3 @@ MonoImporter: userData: assetBundleName: assetBundleVariant: - diff --git a/Tests/unity/Packages/manifest.json b/Tests/unity/Packages/manifest.json index 501ef4b..d63e2e9 100644 --- a/Tests/unity/Packages/manifest.json +++ b/Tests/unity/Packages/manifest.json @@ -1,5 +1,7 @@ { "dependencies": { + "com.unitynativescripting.bridgecore": "file:../../../Packages/com.unitynativescripting.bridgecore", + "com.cysharp.runtimeunittesttoolkit": "https://github.com/Cysharp/RuntimeUnitTestToolkit.git?path=RuntimeUnitTestToolkit/Assets/RuntimeUnitTestToolkit#2.6.1", "com.unity.2d.sprite": "1.0.0", "com.unity.2d.tilemap": "1.0.0", "com.unity.ads": "4.4.2", diff --git a/Tests/unity/Packages/packages-lock.json b/Tests/unity/Packages/packages-lock.json index b870019..9e3df13 100644 --- a/Tests/unity/Packages/packages-lock.json +++ b/Tests/unity/Packages/packages-lock.json @@ -1,5 +1,12 @@ { "dependencies": { + "com.cysharp.runtimeunittesttoolkit": { + "version": "https://github.com/Cysharp/RuntimeUnitTestToolkit.git?path=RuntimeUnitTestToolkit/Assets/RuntimeUnitTestToolkit#2.6.1", + "depth": 0, + "source": "git", + "dependencies": {}, + "hash": "eec2dd0bbf7a627cad80a529ba328585178e5747" + }, "com.unity.2d.sprite": { "version": "1.0.0", "depth": 0, @@ -177,6 +184,12 @@ }, "url": "https://packages.unity.com" }, + "com.unitynativescripting.bridgecore": { + "version": "file:../../../Packages/com.unitynativescripting.bridgecore", + "depth": 0, + "source": "local", + "dependencies": {} + }, "com.unity.modules.accessibility": { "version": "1.0.0", "depth": 0, diff --git a/Tests/unity/ProjectSettings/UnityConnectSettings.asset b/Tests/unity/ProjectSettings/UnityConnectSettings.asset index c3ae9a0..2d81664 100644 --- a/Tests/unity/ProjectSettings/UnityConnectSettings.asset +++ b/Tests/unity/ProjectSettings/UnityConnectSettings.asset @@ -9,6 +9,7 @@ UnityConnectSettings: m_EventOldUrl: https://api.uca.cloud.unity3d.com/v1/events m_EventUrl: https://cdp.cloud.unity3d.com/v1/events m_ConfigUrl: https://config.uca.cloud.unity3d.com + m_DashboardUrl: https://dashboard.unity3d.com m_TestInitMode: 0 CrashReportingSettings: m_EventUrl: https://perf-events.cloud.unity3d.com @@ -22,6 +23,7 @@ UnityConnectSettings: m_Enabled: 0 m_TestMode: 0 m_InitializeOnStartup: 1 + m_PackageRequiringCoreStatsPresent: 1 UnityAdsSettings: m_Enabled: 0 m_InitializeOnStartup: 1 From 2c200b3f7379b5d7dbad253e3b61611b247fc54b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=A2=81=E9=93=96?= <> Date: Wed, 21 Jan 2026 14:04:40 +0800 Subject: [PATCH 10/33] =?UTF-8?q?IL2CPP=20=E6=BA=90=E7=A0=81=E6=8F=92?= =?UTF-8?q?=E4=BB=B6=E6=A8=A1=E5=BC=8F=E4=B8=8E=20RUTTT=20=E5=90=9E?= =?UTF-8?q?=E5=90=90=E6=B5=8B=E8=AF=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Core/docs/UNITY_IL2CPP_SOURCE_BUILD.md | 94 +++++++++ Core/docs/UNITY_WIN_NATIVE_LOADING.md | 2 + .../Editor/BridgeCoreRuntimeUnitTestBuild.cs | 21 +- .../README.md | 33 +++- .../Bridge.Core/Interop/BridgeNative.cs | 8 + .../BridgeSourceModeThroughputTests.cs | 179 ++++++++++++++++++ .../BridgeSourceModeThroughputTests.cs.meta | 12 ++ Tests/unity/Assets/BridgeDemoGame/README.md | 39 ++-- 8 files changed, 369 insertions(+), 19 deletions(-) create mode 100644 Core/docs/UNITY_IL2CPP_SOURCE_BUILD.md create mode 100644 Tests/unity/Assets/BridgeDemoGame/PlayModeTests/BridgeSourceModeThroughputTests.cs create mode 100644 Tests/unity/Assets/BridgeDemoGame/PlayModeTests/BridgeSourceModeThroughputTests.cs.meta diff --git a/Core/docs/UNITY_IL2CPP_SOURCE_BUILD.md b/Core/docs/UNITY_IL2CPP_SOURCE_BUILD.md new file mode 100644 index 0000000..d82baec --- /dev/null +++ b/Core/docs/UNITY_IL2CPP_SOURCE_BUILD.md @@ -0,0 +1,94 @@ +# Unity(Windows)IL2CPP:源码插件(C++ Source Plugin)编译与 il2cppOutput 解读 + +本文记录 Unity Windows 平台在 **IL2CPP Player** 下,把 C++ 以“源码插件”的方式编进 `GameAssembly.dll` 的实际流程,以及如何用 `il2cppOutput` 目录反查/定位问题与优化点。 + +> 结论先说:源码被编进 `GameAssembly.dll` ≠ P/Invoke 一定不会去找 DLL。是否走“内部直连”取决于 IL2CPP 生成代码中的 P/Invoke 解析路径。 + +## 1. 参与目录(按流水线顺序) + +### 1.1 仓库内 C++ 源码(来源) + +- `Core/cpp/include/bridge/*.h`:稳定 C ABI(例如 `bridge.h`) +- `Core/cpp/src/**`:Core 运行时实现 +- `Tests/cpp/generated/*.generated.h`:业务宏定义生成的绑定头 +- `Tests/cpp/demo_game/src/**`:示例业务(用于测试/演示) + +### 1.2 Unity 工程内“源码插件”(同步目标) + +通过 `Packages/com.unitynativescripting.bridgecore/Editor/BridgeCoreNativeSourceSync.cs` 同步到: + +- `Tests/unity/Assets/Plugins/x86_64/BridgeCoreSource/` + +同步时会做两件事: + +1) **扁平化(flatten)文件路径**:避免 Unity 构建阶段再次扁平化后 include 路径失效。 +2) **改写 include**:把 `` 与相对路径 include 改成同目录 `\"xxx.h\"`。 + +### 1.3 Bee 构建产物(真正被编译的输入目录) + +Unity Player 构建时,Bee 会把源码插件与 IL2CPP 生成的 C++ 汇总到类似: + +- `Tests/unity/Library/Bee/artifacts/WinPlayerBuildProgram/il2cppOutput/cpp/` + +你可以在 `Tests/unity/Library/Bee/Player*.dag.json` 里看到: + +- 源码插件文件(例如 `Assets/Plugins/x86_64/BridgeCoreSource/bridge_api.cpp`)被复制/参与编译 +- IL2CPP 生成的 `Bridge.Core.cpp` 等被编译 +- 最终链接产物为 `GameAssembly.dll` + +### 1.4 build 输出中的 il2cppOutput(便于你分析的“镜像”) + +Player 构建完成后,Unity 会把“将要编译/已生成”的 C++ 文件复制一份到: + +- `build/unity_il2cpp/_BackUpThisFolder_ButDontShipItWithYourGame/il2cppOutput/` + +这个目录是你要看的重点: + +- 既包含 IL2CPP 从 C# 翻译出的 `*.cpp`(例如 `Bridge.Core.cpp`、`BridgeDemoGame.Runtime.cpp`) +- 也包含我们同步进来的源码插件 `*.cpp/*.h`(例如 `bridge_api.cpp`、`core_instance.cpp`) + +因此它非常适合用来做: + +- 定位 P/Invoke 是否仍在动态加载 DLL +- 观察 IL2CPP 对托管代码生成的 C++ 形态(分配、异常路径、数组访问等) +- 在“最终编译前”就做针对性优化分析 + +## 2. 如何确认“已经按源码编译进 GameAssembly” + +满足任一即可: + +1) 在 `build/.../il2cppOutput/` 里能看到 `bridge_api.cpp`、`core_instance.cpp` 等源码插件文件。 +2) 在 `Tests/unity/Library/Bee/Player*.dag.json` 搜索 `BridgeCoreSource`,能看到这些文件作为编译输入。 + +## 3. 关键点:P/Invoke 到底走哪条路 + +即使 C++ 源码已经编进 `GameAssembly.dll`,如果 IL2CPP 生成的 P/Invoke wrapper 仍然走: + +- `il2cpp_codegen_resolve_pinvoke("bridge_core", "BridgeCore_Create", ...)` + +那么运行时依然会尝试加载 `bridge_core.dll`(或等价动态库),缺失就会出现: + +- `DllNotFoundException: Unable to load DLL 'bridge_core'` + +你可以直接在: + +- `build/.../il2cppOutput/Bridge.Core.cpp` + +里搜索 `il2cpp_codegen_resolve_pinvoke` 来确认。 + +同时你会看到 IL2CPP 生成代码里存在一个“内部直连”的分支: + +- `FORCE_PINVOKE_INTERNAL` 或 `FORCE_PINVOKE__INTERNAL` + +当宏生效时,wrapper 会改为直接调用同名 C 函数符号(由链接器在 `GameAssembly.dll` 内解析),不再动态加载 DLL。 + +## 4. 接下来我们要做什么(和测试的关系) + +后续所有性能/吞吐测试会统一采用 **源码插件模式(IL2CPP)**: + +1) 构建前同步 C++ 源码到 `Assets/Plugins/x86_64/BridgeCoreSource` +2) 构建 IL2CPP Player(含 RuntimeUnitTestToolkit 的测试 Runner) +3) 运行 Player 执行测试并输出结果/性能日志 + +同时需要把 `Bridge.Core` 的 P/Invoke 解析路径切换到“内部直连”,否则 Player 运行期仍会因找不到 `bridge_core.dll` 而失败。 + diff --git a/Core/docs/UNITY_WIN_NATIVE_LOADING.md b/Core/docs/UNITY_WIN_NATIVE_LOADING.md index 68ceead..4df42b2 100644 --- a/Core/docs/UNITY_WIN_NATIVE_LOADING.md +++ b/Core/docs/UNITY_WIN_NATIVE_LOADING.md @@ -2,6 +2,8 @@ 目标:在 Unity Editor(Windows)中使用 `bridge_core.dll` 跑起来,同时支持“重编译后覆盖 DLL”而不被 Windows 文件锁卡死;出包阶段再切换到更标准的插件/源码编译方案。 +> IL2CPP “源码插件编译进 GameAssembly.dll” 的细节与 `il2cppOutput` 解读见:`Core/docs/UNITY_IL2CPP_SOURCE_BUILD.md`。 + ## 背景:为什么会被锁 Windows 下一个 DLL 被进程加载后,其文件会被锁定(不能覆盖/删除)。Unity Editor 在域重载、脚本重编译、迭代调试时经常需要替换原生 DLL,如果直接加载固定路径(例如 `Assets/Plugins/.../bridge_core.dll`),就会出现: diff --git a/Packages/com.unitynativescripting.bridgecore/Editor/BridgeCoreRuntimeUnitTestBuild.cs b/Packages/com.unitynativescripting.bridgecore/Editor/BridgeCoreRuntimeUnitTestBuild.cs index e63e10f..6b79bde 100644 --- a/Packages/com.unitynativescripting.bridgecore/Editor/BridgeCoreRuntimeUnitTestBuild.cs +++ b/Packages/com.unitynativescripting.bridgecore/Editor/BridgeCoreRuntimeUnitTestBuild.cs @@ -13,8 +13,14 @@ public static class BridgeCoreRuntimeUnitTestBuild // /headless /ScriptBackend IL2CPP /BuildTarget StandaloneWindows64 public static void BuildUnitTest() { - // Player 下依赖 bridge_core.dll,确保同步到 Assets/Plugins 并正确配置导入器 - BridgeCoreWinSync.SyncForPlayer(); + // 按构建后端选择模式: + // - IL2CPP:走“源码插件”模式(C++ 编进 GameAssembly.dll) + // - Mono2x:走“native dll 插件”模式(复制到 Assets/Plugins 供 Player 加载) + string backend = FindSlashOption(Environment.GetCommandLineArgs(), "ScriptBackend"); + if (string.Equals(backend, "IL2CPP", StringComparison.OrdinalIgnoreCase)) + BridgeCoreNativeSourceSync.SyncSourcesForIl2Cpp(); + else + BridgeCoreWinSync.SyncForPlayer(); #if UNITY_2021_2_OR_NEWER // RuntimeUnitTestToolkit 的 /Headless 会走 Dedicated Server 子目标。 @@ -25,6 +31,17 @@ public static void BuildUnitTest() InvokeUnitTestBuilder(); } + private static string FindSlashOption(string[] args, string name) + { + string key = "/" + name; + for (int i = 0; i < args.Length - 1; i++) + { + if (string.Equals(args[i], key, StringComparison.OrdinalIgnoreCase)) + return args[i + 1]; + } + return null; + } + private static void InvokeUnitTestBuilder() { Type builderType = AppDomain.CurrentDomain diff --git a/Packages/com.unitynativescripting.bridgecore/README.md b/Packages/com.unitynativescripting.bridgecore/README.md index 9a77387..d1bbae8 100644 --- a/Packages/com.unitynativescripting.bridgecore/README.md +++ b/Packages/com.unitynativescripting.bridgecore/README.md @@ -7,14 +7,39 @@ - Git(推荐):`"com.unitynativescripting.bridgecore": "git+.git?path=/Packages/com.unitynativescripting.bridgecore"` - 本地开发:`"com.unitynativescripting.bridgecore": "file:/Packages/com.unitynativescripting.bridgecore"` -此目录仅提供 **Windows Editor** 下的原生 DLL 加载支持: +## 两种运行模式(推荐组合) -- 运行时从 `Library/BridgeNative//bridge_core.dll` 加载,避免锁定固定源文件 +### 1) Windows Editor:Copy-Then-Load(热替换友好) + +- 运行时从 `Library/BridgeNative//bridge_core.dll` 加载,避免锁定固定源文件(便于热替换/重编译覆盖) - 源 DLL 默认从仓库构建输出 `build/bin/Release/bridge_core.dll` 查找(会自动向上寻找仓库根目录) - 也可通过环境变量 `BRIDGE_CORE_DLL` 指定源 DLL 的绝对路径 -Unity 菜单: +Unity 菜单(Windows Editor): -- `BridgeCore/Windows/Build + Hot Reload (Release)`:触发 CMake 编译并重新加载 +- `BridgeCore/Windows/Build bridge_core.dll (Release)` +- `BridgeCore/Windows/Build + Hot Reload (Release)` +- `BridgeCore/Windows/Reload bridge_core.dll (from build output)` 更多说明见:`Core/docs/UNITY_WIN_NATIVE_LOADING.md`。 + +### 2) Player:IL2CPP 源码插件(编进 GameAssembly.dll) + +- 同步 C++ 源码到 `Assets/Plugins/x86_64/BridgeCoreSource` +- Unity IL2CPP Player Build 时会把这些 `*.cpp/*.h` 与 il2cppOutput 一起编译进 `GameAssembly.dll` + +Unity 菜单(Windows Editor): + +- `BridgeCore/Windows/Sync C++ Sources (for IL2CPP source plugin)` + +更多说明见:`Core/docs/UNITY_IL2CPP_SOURCE_BUILD.md`。 + +### 3) Player:Mono / DLL 插件(可选) + +- 把构建产物 `bridge_core.dll` 同步到 `Assets/Plugins/BridgeCore/Win64/bridge_core.dll` +- 插件导入器会被配置为:**不在 Editor 自动加载**(避免锁定),仅用于 Player + +Unity 菜单(Windows Editor): + +- `BridgeCore/Windows/Sync bridge_core.dll (for Player)` +- `BridgeCore/Windows/Configure Plugin Importer` diff --git a/Packages/com.unitynativescripting.bridgecore/Runtime/Bridge.Core/Interop/BridgeNative.cs b/Packages/com.unitynativescripting.bridgecore/Runtime/Bridge.Core/Interop/BridgeNative.cs index 767ccaa..ada1def 100644 --- a/Packages/com.unitynativescripting.bridgecore/Runtime/Bridge.Core/Interop/BridgeNative.cs +++ b/Packages/com.unitynativescripting.bridgecore/Runtime/Bridge.Core/Interop/BridgeNative.cs @@ -10,6 +10,9 @@ namespace Bridge.Core internal static class BridgeNative { #if UNITY_EDITOR_WIN + // Windows Editor 下使用 “Copy-Then-Load + GetProcAddress” 模式: + // - 避免 Unity 自动加载/锁定固定 DLL 路径 + // - 支持重编译后覆盖源 DLL,再热重载 [DllImport("kernel32.dll", CharSet = CharSet.Ansi, ExactSpelling = true, SetLastError = true)] private static extern IntPtr GetProcAddress(IntPtr libraryHandle, string symbolName); @@ -135,8 +138,13 @@ internal static BridgeResult BridgeCore_PushCallCore(IntPtr core, uint funcId, I EnsureBound(); return s_pushCallCore(core, funcId, payload, payloadSize); } +#else +#if ENABLE_IL2CPP && !UNITY_EDITOR + // IL2CPP Player 下如果把 C++ 以“源码插件”编进 GameAssembly.dll,应使用 __Internal 走内部符号解析,避免运行时动态加载 bridge_core.dll。 + private const string LibraryName = "__Internal"; #else private const string LibraryName = "bridge_core"; +#endif [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl)] internal static extern BridgeVersion Bridge_GetVersion(); diff --git a/Tests/unity/Assets/BridgeDemoGame/PlayModeTests/BridgeSourceModeThroughputTests.cs b/Tests/unity/Assets/BridgeDemoGame/PlayModeTests/BridgeSourceModeThroughputTests.cs new file mode 100644 index 0000000..9c3e091 --- /dev/null +++ b/Tests/unity/Assets/BridgeDemoGame/PlayModeTests/BridgeSourceModeThroughputTests.cs @@ -0,0 +1,179 @@ +using System; +using System.Diagnostics; +using Bridge.Bindings; +using Bridge.Core; +using DemoAsset.Bindings; +using DemoEntity.Bindings; +using DemoLog.Bindings; +using NUnit.Framework; +using Debug = UnityEngine.Debug; + +namespace BridgeDemoGame.Tests +{ + public sealed class BridgeSourceModeThroughputTests + { + private sealed class NullHostApi : IDemoAssetHostApi, IDemoEntityHostApi, IDemoLogHostApi + { + private readonly BridgeCore _core; + + public NullHostApi(BridgeCore core) + { + _core = core; + } + + public void LoadAsset(ulong requestId, BridgeAssetType assetType, BridgeStringView assetKey) + { + _ = assetType; + _ = assetKey; + _core.AssetLoaded(requestId, handle: 1, BridgeAssetStatus.Ok); + } + + public void SpawnEntity(ulong entityId, ulong prefabHandle, in BridgeTransform transform, uint flags) + { + _ = entityId; + _ = prefabHandle; + _ = transform; + _ = flags; + } + + public void SetTransform(ulong entityId, uint mask, in BridgeTransform transform) + { + _ = entityId; + _ = mask; + _ = transform; + } + + public void DestroyEntity(ulong entityId) + { + _ = entityId; + } + + public void Log(BridgeLogLevel level, BridgeStringView message) + { + _ = level; + _ = message; + } + } + + [Test] + public void TickManyAndDispatch_Throughput_1Bot() + { + RunThroughput(bots: 1); + } + + [Test] + public void TickManyAndDispatch_Throughput_1kBots() + { + RunThroughput(bots: 1000); + } + + [Test] + public void TickManyAndDispatch_Throughput_10kBots() + { + RunThroughput(bots: 10000); + } + + private static void RunThroughput(int bots) + { + if (bots <= 0) + throw new ArgumentOutOfRangeException(nameof(bots)); + + const int warmupFrames = 60; + const int measureFrames = 300; + const float dt = 1.0f / 60.0f; + + BridgeCore.PrepareTickManyCache(bots); + + Debug.Log("BridgeSourceModeThroughputTests: start bots=" + bots); + + var cores = new BridgeCore[bots]; + var hosts = new NullHostApi[bots]; + var streams = new CommandStream[bots]; + + for (int i = 0; i < bots; i++) + { + var core = new BridgeCore(seed: (ulong)(i + 1), robotMode: true); + cores[i] = core; + hosts[i] = new NullHostApi(core); + } + + try + { + RunFrames(cores, hosts, streams, warmupFrames, dt, out _); + + bool allocSupported = false; + long allocBefore = 0; +#if !ENABLE_IL2CPP || UNITY_EDITOR + allocBefore = TryGetAllocatedBytesForCurrentThread(out allocSupported); +#endif + var sw = Stopwatch.StartNew(); + RunFrames(cores, hosts, streams, measureFrames, dt, out ulong totalBytes); + sw.Stop(); + + long allocAfter = 0; +#if !ENABLE_IL2CPP || UNITY_EDITOR + allocAfter = allocSupported ? TryGetAllocatedBytesForCurrentThread(out _) : 0; +#endif + + double seconds = Math.Max(1e-9, sw.Elapsed.TotalSeconds); + double ticks = (double)bots * measureFrames; + double ticksPerSecond = ticks / seconds; + double mibPerSecond = (totalBytes / (1024.0 * 1024.0)) / seconds; + long allocBytes = allocSupported ? (allocAfter - allocBefore) : -1; + + Debug.Log(string.Format( + "##bridgeperf: mode=il2cpp_source ticks_per_sec={0:0.00} mib_per_sec={1:0.00} bots={2} frames={3} elapsed_ms={4:0.00} alloc_bytes={5} total_bytes={6}", + ticksPerSecond, + mibPerSecond, + bots, + measureFrames, + sw.Elapsed.TotalMilliseconds, + allocBytes, + totalBytes)); + + Debug.Log("BridgeSourceModeThroughputTests: done bots=" + bots); + } + finally + { + for (int i = 0; i < bots; i++) + cores[i].Dispose(); + } + } + + private static void RunFrames( + BridgeCore[] cores, + NullHostApi[] hosts, + CommandStream[] streams, + int frames, + float dt, + out ulong totalBytes) + { + totalBytes = 0; + + for (int frame = 0; frame < frames; frame++) + { + BridgeCore.TickManyAndGetCommandStreams(cores, dt, streams); + for (int i = 0; i < cores.Length; i++) + { + CommandStream stream = streams[i]; + totalBytes += stream.Length; + BridgeAllCommandDispatcher.Dispatch(stream, hosts[i]); + } + } + } + + private static long TryGetAllocatedBytesForCurrentThread(out bool supported) + { + try + { + supported = true; + return GC.GetAllocatedBytesForCurrentThread(); + } + catch + { + supported = false; + return 0; + } + } + } +} diff --git a/Tests/unity/Assets/BridgeDemoGame/PlayModeTests/BridgeSourceModeThroughputTests.cs.meta b/Tests/unity/Assets/BridgeDemoGame/PlayModeTests/BridgeSourceModeThroughputTests.cs.meta new file mode 100644 index 0000000..8c3d861 --- /dev/null +++ b/Tests/unity/Assets/BridgeDemoGame/PlayModeTests/BridgeSourceModeThroughputTests.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 21a00ec32eac4cd4946b24cda6996584 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: + diff --git a/Tests/unity/Assets/BridgeDemoGame/README.md b/Tests/unity/Assets/BridgeDemoGame/README.md index 0a2469a..4842884 100644 --- a/Tests/unity/Assets/BridgeDemoGame/README.md +++ b/Tests/unity/Assets/BridgeDemoGame/README.md @@ -38,25 +38,38 @@ cmake --build build --config Release - 环境变量 `BRIDGE_CORE_DLL`:可指定源 `bridge_core.dll` 的绝对路径(优先级最高) - `DemoGameUnityRunner.Bots`:多实例(超过 `MaxBotsWithRendering` 会自动关闭渲染命令) -## 性能测试(Unity Performance Test Framework) +## 测试 / 性能(RuntimeUnitTestToolkit + IL2CPP 源码模式) -已在工程内加入 `com.unity.test-framework.performance`,并提供 EditMode 性能用例: +工程已引入 `com.cysharp.runtimeunittesttoolkit`,用于在 **Player** 下运行 NUnit 测试(可用于 Mono / IL2CPP)。 -- `BridgeDemoGame.Tests.BridgeDispatchPerformanceTests.TickAndDispatch_OneFrame` +其中吞吐测试会输出类似: -命令行运行(Windows / PowerShell): +- `##bridgeperf: mode=il2cpp_source ...` + +### IL2CPP(源码插件)跑测试 + +命令行(Windows / PowerShell): ```powershell -& "C:\\Program Files\\Unity\\Hub\\Editor\\6000.0.40f1\\Editor\\Unity.exe" ` - -batchmode -nographics -quit ` - -projectPath "D:\\UGit\\UnityNativeScripting\\Tests\\unity" ` - -runTests -testPlatform EditMode ` - -testResults "D:\\UGit\\UnityNativeScripting\\build\\unity-editmode-test-results.xml" ` - -perfTestResults "D:\\UGit\\UnityNativeScripting\\build\\unity-editmode-perf-results.json" ` - -logFile "D:\\UGit\\UnityNativeScripting\\build\\unity-editmode-test.log" +$unity = "C:\Program Files\Unity\Hub\Editor\6000.0.40f1\Editor\Unity.exe" +$proj = "D:\UGit\UnityNativeScripting\Tests\unity" +$out = "D:\UGit\UnityNativeScripting\build\ruttt_il2cpp\test.exe" + +& $unity -quit -batchmode -nographics ` + -projectPath $proj ` + -executeMethod Bridge.Core.Unity.Editor.BridgeCoreRuntimeUnitTestBuild.BuildUnitTest ` + /ScriptBackend IL2CPP /BuildTarget StandaloneWindows64 /buildPath $out ` + -logFile "D:\UGit\UnityNativeScripting\build\ruttt_il2cpp\build.log" + +& $out -batchmode -nographics -logFile "D:\UGit\UnityNativeScripting\build\ruttt_il2cpp\run.log" ``` +说明: + +- `BuildUnitTest` 会在 IL2CPP 下自动执行 `BridgeCore/Windows/Sync C++ Sources`,把 C++ 源码同步到 `Assets/Plugins/x86_64/BridgeCoreSource`,并在 Player Build 时编进 `GameAssembly.dll`。 +- 这些测试位于 `Assets/BridgeDemoGame/PlayModeTests/`(例如 `BridgeRuntimeSmokeTests` / `BridgeSourceModeThroughputTests`)。 + 注意: -- `-testPlatform` 在 Unity 6 下建议使用 `EditMode` / `PlayMode`(大小写匹配)。 -- 如果 `Tests/unity` 工程已在 Unity Editor 中打开,命令行跑测试会被锁定;请先关闭该工程的 Editor 实例。 +- 如果 `build/unity_il2cpp/BridgeDemoGame.exe`(或 unit test player)仍在运行,重建可能会因为文件被映射而失败;请先结束进程再 build。 +- 如果 `Tests/unity` 工程已在 Unity Editor 中打开,命令行 build 也可能被锁定;建议先关闭该工程的 Editor 实例。 From 71d7614e1608a7de723c54f30b6ad1108e34fd1f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=A2=81=E9=93=96?= <> Date: Wed, 21 Jan 2026 14:43:45 +0800 Subject: [PATCH 11/33] =?UTF-8?q?Mono=20GC=20=E6=B5=8B=E8=AF=95=E4=B8=8E?= =?UTF-8?q?=20IL2CPP=20=E5=90=9E=E5=90=90=E5=88=86=E7=A6=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Editor/BridgeCoreRuntimeUnitTestBuild.cs | 3 + .../PlayModeTests/BridgeMonoGcTests.cs | 187 ++++++++++++++++++ .../PlayModeTests/BridgeMonoGcTests.cs.meta | 12 ++ .../BridgeSourceModeThroughputTests.cs | 23 ++- Tests/unity/Assets/BridgeDemoGame/README.md | 44 ++++- 5 files changed, 254 insertions(+), 15 deletions(-) create mode 100644 Tests/unity/Assets/BridgeDemoGame/PlayModeTests/BridgeMonoGcTests.cs create mode 100644 Tests/unity/Assets/BridgeDemoGame/PlayModeTests/BridgeMonoGcTests.cs.meta diff --git a/Packages/com.unitynativescripting.bridgecore/Editor/BridgeCoreRuntimeUnitTestBuild.cs b/Packages/com.unitynativescripting.bridgecore/Editor/BridgeCoreRuntimeUnitTestBuild.cs index 6b79bde..7b0add1 100644 --- a/Packages/com.unitynativescripting.bridgecore/Editor/BridgeCoreRuntimeUnitTestBuild.cs +++ b/Packages/com.unitynativescripting.bridgecore/Editor/BridgeCoreRuntimeUnitTestBuild.cs @@ -22,6 +22,9 @@ public static void BuildUnitTest() else BridgeCoreWinSync.SyncForPlayer(); + // 确保 AssetDatabase 与磁盘状态一致(尤其是批处理模式下的“外部删除/新增脚本文件”)。 + AssetDatabase.Refresh(ImportAssetOptions.ForceUpdate); + #if UNITY_2021_2_OR_NEWER // RuntimeUnitTestToolkit 的 /Headless 会走 Dedicated Server 子目标。 // 这里强制回到普通 Player,避免环境里残留 Server 子目标导致构建失败。 diff --git a/Tests/unity/Assets/BridgeDemoGame/PlayModeTests/BridgeMonoGcTests.cs b/Tests/unity/Assets/BridgeDemoGame/PlayModeTests/BridgeMonoGcTests.cs new file mode 100644 index 0000000..976fb59 --- /dev/null +++ b/Tests/unity/Assets/BridgeDemoGame/PlayModeTests/BridgeMonoGcTests.cs @@ -0,0 +1,187 @@ +#if !ENABLE_IL2CPP +using System; +using System.Diagnostics; +using Bridge.Bindings; +using Bridge.Core; +using DemoAsset.Bindings; +using DemoEntity.Bindings; +using DemoLog.Bindings; +using NUnit.Framework; +using Debug = UnityEngine.Debug; + +namespace BridgeDemoGame.PlayModeTests +{ + public sealed class BridgeMonoGcTests + { + private sealed class NullHostApi : IDemoAssetHostApi, IDemoEntityHostApi, IDemoLogHostApi + { + private readonly BridgeCore _core; + + public NullHostApi(BridgeCore core) + { + _core = core; + } + + public void LoadAsset(ulong requestId, BridgeAssetType assetType, BridgeStringView assetKey) + { + _ = assetType; + _ = assetKey; + _core.AssetLoaded(requestId, handle: 1, BridgeAssetStatus.Ok); + } + + public void SpawnEntity(ulong entityId, ulong prefabHandle, in BridgeTransform transform, uint flags) + { + _ = entityId; + _ = prefabHandle; + _ = transform; + _ = flags; + } + + public void SetTransform(ulong entityId, uint mask, in BridgeTransform transform) + { + _ = entityId; + _ = mask; + _ = transform; + } + + public void DestroyEntity(ulong entityId) + { + _ = entityId; + } + + public void Log(BridgeLogLevel level, BridgeStringView message) + { + _ = level; + _ = message; + } + } + + [Test] + public void TickAndDispatch_NoGcAlloc_1Bot() + { + const int warmupFrames = 60; + const int measureFrames = 600; + const float dt = 1.0f / 60.0f; + + using (var core = new BridgeCore(seed: 1, robotMode: true)) + { + var host = new NullHostApi(core); + + RunSingleCoreFrames(core, host, warmupFrames, dt, out _); + + CollectAndWait(); + long allocBefore = GC.GetAllocatedBytesForCurrentThread(); + + var sw = Stopwatch.StartNew(); + RunSingleCoreFrames(core, host, measureFrames, dt, out ulong totalBytes); + sw.Stop(); + + long allocAfter = GC.GetAllocatedBytesForCurrentThread(); + long allocBytes = allocAfter - allocBefore; + + Debug.Log(string.Format( + "##bridgegc: mode=mono alloc_bytes={0} bots=1 frames={1} elapsed_ms={2:0.00} total_bytes={3}", + allocBytes, + measureFrames, + sw.Elapsed.TotalMilliseconds, + totalBytes)); + + if (allocBytes != 0) + throw new Exception("GC allocated bytes != 0: " + allocBytes); + } + } + + [Test] + public void TickManyAndDispatch_NoGcAlloc_10000Bots() + { + const int bots = 10000; + const int warmupFrames = 10; + const int measureFrames = 60; + const float dt = 1.0f / 60.0f; + + BridgeCore.PrepareTickManyCache(bots); + + var cores = new BridgeCore[bots]; + var hosts = new NullHostApi[bots]; + var streams = new CommandStream[bots]; + + for (int i = 0; i < bots; i++) + { + var core = new BridgeCore(seed: (ulong)(i + 1), robotMode: true); + cores[i] = core; + hosts[i] = new NullHostApi(core); + } + + try + { + RunManyCoreFrames(cores, hosts, streams, warmupFrames, dt, out _); + + CollectAndWait(); + long allocBefore = GC.GetAllocatedBytesForCurrentThread(); + + var sw = Stopwatch.StartNew(); + RunManyCoreFrames(cores, hosts, streams, measureFrames, dt, out ulong totalBytes); + sw.Stop(); + + long allocAfter = GC.GetAllocatedBytesForCurrentThread(); + long allocBytes = allocAfter - allocBefore; + + Debug.Log(string.Format( + "##bridgegc: mode=mono alloc_bytes={0} bots={1} frames={2} elapsed_ms={3:0.00} total_bytes={4}", + allocBytes, + bots, + measureFrames, + sw.Elapsed.TotalMilliseconds, + totalBytes)); + + if (allocBytes != 0) + throw new Exception("GC allocated bytes != 0: " + allocBytes); + } + finally + { + for (int i = 0; i < bots; i++) + cores[i].Dispose(); + } + } + + private static void RunSingleCoreFrames(BridgeCore core, NullHostApi host, int frames, float dt, out ulong totalBytes) + { + totalBytes = 0; + for (int i = 0; i < frames; i++) + { + CommandStream stream = core.TickAndGetCommandStream(dt); + totalBytes += stream.Length; + BridgeAllCommandDispatcher.Dispatch(stream, host); + } + } + + private static void RunManyCoreFrames( + BridgeCore[] cores, + NullHostApi[] hosts, + CommandStream[] streams, + int frames, + float dt, + out ulong totalBytes) + { + totalBytes = 0; + for (int frame = 0; frame < frames; frame++) + { + BridgeCore.TickManyAndGetCommandStreams(cores, dt, streams); + for (int i = 0; i < cores.Length; i++) + { + CommandStream stream = streams[i]; + totalBytes += stream.Length; + BridgeAllCommandDispatcher.Dispatch(stream, hosts[i]); + } + } + } + + private static void CollectAndWait() + { + GC.Collect(); + GC.WaitForPendingFinalizers(); + GC.Collect(); + } + } +} +#endif diff --git a/Tests/unity/Assets/BridgeDemoGame/PlayModeTests/BridgeMonoGcTests.cs.meta b/Tests/unity/Assets/BridgeDemoGame/PlayModeTests/BridgeMonoGcTests.cs.meta new file mode 100644 index 0000000..e414fb5 --- /dev/null +++ b/Tests/unity/Assets/BridgeDemoGame/PlayModeTests/BridgeMonoGcTests.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 677a3945b351486ea117f1c54e0fdac8 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: + diff --git a/Tests/unity/Assets/BridgeDemoGame/PlayModeTests/BridgeSourceModeThroughputTests.cs b/Tests/unity/Assets/BridgeDemoGame/PlayModeTests/BridgeSourceModeThroughputTests.cs index 9c3e091..04ec3ab 100644 --- a/Tests/unity/Assets/BridgeDemoGame/PlayModeTests/BridgeSourceModeThroughputTests.cs +++ b/Tests/unity/Assets/BridgeDemoGame/PlayModeTests/BridgeSourceModeThroughputTests.cs @@ -1,14 +1,17 @@ +#if ENABLE_IL2CPP using System; +using System.Collections; using System.Diagnostics; using Bridge.Bindings; using Bridge.Core; using DemoAsset.Bindings; using DemoEntity.Bindings; using DemoLog.Bindings; -using NUnit.Framework; using Debug = UnityEngine.Debug; +using NUnit.Framework; +using UnityEngine.TestTools; -namespace BridgeDemoGame.Tests +namespace BridgeDemoGame.PlayModeTests { public sealed class BridgeSourceModeThroughputTests { @@ -55,22 +58,25 @@ public void Log(BridgeLogLevel level, BridgeStringView message) } } - [Test] - public void TickManyAndDispatch_Throughput_1Bot() + [UnityTest] + public IEnumerator TickManyAndDispatch_Throughput_1Bot() { RunThroughput(bots: 1); + yield break; } - [Test] - public void TickManyAndDispatch_Throughput_1kBots() + [UnityTest] + public IEnumerator TickManyAndDispatch_Throughput_1kBots() { RunThroughput(bots: 1000); + yield break; } - [Test] - public void TickManyAndDispatch_Throughput_10kBots() + [UnityTest] + public IEnumerator TickManyAndDispatch_Throughput_10kBots() { RunThroughput(bots: 10000); + yield break; } private static void RunThroughput(int bots) @@ -177,3 +183,4 @@ private static long TryGetAllocatedBytesForCurrentThread(out bool supported) } } } +#endif diff --git a/Tests/unity/Assets/BridgeDemoGame/README.md b/Tests/unity/Assets/BridgeDemoGame/README.md index 4842884..f2dad62 100644 --- a/Tests/unity/Assets/BridgeDemoGame/README.md +++ b/Tests/unity/Assets/BridgeDemoGame/README.md @@ -38,13 +38,14 @@ cmake --build build --config Release - 环境变量 `BRIDGE_CORE_DLL`:可指定源 `bridge_core.dll` 的绝对路径(优先级最高) - `DemoGameUnityRunner.Bots`:多实例(超过 `MaxBotsWithRendering` 会自动关闭渲染命令) -## 测试 / 性能(RuntimeUnitTestToolkit + IL2CPP 源码模式) +## 测试(RuntimeUnitTestToolkit) 工程已引入 `com.cysharp.runtimeunittesttoolkit`,用于在 **Player** 下运行 NUnit 测试(可用于 Mono / IL2CPP)。 -其中吞吐测试会输出类似: +我们按后端分两类: -- `##bridgeperf: mode=il2cpp_source ...` +- **IL2CPP Player(源码插件)**:只看吞吐/性能(`##bridgeperf: ...`) +- **Mono Player(DLL 插件)**:只看 GC 分配(`##bridgegc: ...`) ### IL2CPP(源码插件)跑测试 @@ -53,21 +54,50 @@ cmake --build build --config Release ```powershell $unity = "C:\Program Files\Unity\Hub\Editor\6000.0.40f1\Editor\Unity.exe" $proj = "D:\UGit\UnityNativeScripting\Tests\unity" -$out = "D:\UGit\UnityNativeScripting\build\ruttt_il2cpp\test.exe" +$out = "D:\UGit\UnityNativeScripting\build\ruttt_il2cpp_source\test.exe" & $unity -quit -batchmode -nographics ` -projectPath $proj ` -executeMethod Bridge.Core.Unity.Editor.BridgeCoreRuntimeUnitTestBuild.BuildUnitTest ` /ScriptBackend IL2CPP /BuildTarget StandaloneWindows64 /buildPath $out ` - -logFile "D:\UGit\UnityNativeScripting\build\ruttt_il2cpp\build.log" + -logFile "D:\UGit\UnityNativeScripting\build\ruttt_il2cpp_source\build.log" -& $out -batchmode -nographics -logFile "D:\UGit\UnityNativeScripting\build\ruttt_il2cpp\run.log" +& $out -batchmode -nographics -logFile "D:\UGit\UnityNativeScripting\build\ruttt_il2cpp_source\run.log" ``` 说明: - `BuildUnitTest` 会在 IL2CPP 下自动执行 `BridgeCore/Windows/Sync C++ Sources`,把 C++ 源码同步到 `Assets/Plugins/x86_64/BridgeCoreSource`,并在 Player Build 时编进 `GameAssembly.dll`。 -- 这些测试位于 `Assets/BridgeDemoGame/PlayModeTests/`(例如 `BridgeRuntimeSmokeTests` / `BridgeSourceModeThroughputTests`)。 +- 这些测试位于 `Assets/BridgeDemoGame/PlayModeTests/`(例如 `BridgeRuntimeSmokeTests` / `BridgeSourceModeThroughputTests`)。吞吐结果会输出:`##bridgeperf: mode=il2cpp_source ...` + +### Mono(DLL 插件)跑测试(GC) + +命令行(Windows / PowerShell): + +```powershell +$unity = "C:\Program Files\Unity\Hub\Editor\6000.0.40f1\Editor\Unity.exe" +$proj = "D:\UGit\UnityNativeScripting\Tests\unity" +$out = "D:\UGit\UnityNativeScripting\build\ruttt_mono\test.exe" + +& $unity -quit -batchmode -nographics ` + -projectPath $proj ` + -executeMethod Bridge.Core.Unity.Editor.BridgeCoreRuntimeUnitTestBuild.BuildUnitTest ` + /ScriptBackend Mono2x /BuildTarget StandaloneWindows64 /buildPath $out ` + -logFile "D:\UGit\UnityNativeScripting\build\ruttt_mono\build.log" + +Push-Location (Split-Path $out) +& .\test.exe -batchmode -nographics -logFile "D:\UGit\UnityNativeScripting\build\ruttt_mono\run.log" +Pop-Location +``` + +说明: + +- `BuildUnitTest` 会在 Mono 下自动执行 `BridgeCore/Windows/Sync bridge_core.dll (for Player)`,把 `build/bin/Release/bridge_core.dll` 同步为 Unity 的 Player 插件。 +- GC 测试位于 `Assets/BridgeDemoGame/PlayModeTests/BridgeMonoGcTests.cs`,结果会输出:`##bridgegc: mode=mono ...` + +注意: + +- Mono Player 运行时需要把工作目录设为 build 输出目录(包含 `MonoBleedingEdge/`),否则可能无法启动或无法输出日志。 注意: From 46c54af4c7fbd021e7cc856f6f19b997b5531436 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=A2=81=E9=93=96?= <> Date: Wed, 21 Jan 2026 17:00:57 +0800 Subject: [PATCH 12/33] =?UTF-8?q?perf:=20=E4=BC=98=E5=8C=96=20command=20st?= =?UTF-8?q?ream/IL2CPP=20=E5=88=86=E5=8F=91=E5=B9=B6=E5=8A=A0=E5=85=A5?= =?UTF-8?q?=E6=80=A7=E8=83=BD=E8=AE=B0=E5=BD=95=E8=84=9A=E6=9C=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 6 + Core/Tools/BridgeGen/Program.cs | 122 ++++ Core/cpp/src/api/bridge_api.cpp | 15 +- Core/cpp/src/core/command_stream.cpp | 10 - Core/cpp/src/core/command_stream.h | 37 +- Core/cpp/src/core/core_instance.cpp | 19 +- Core/csharp/Bridge.Core/BridgeCore.cs | 75 ++ Core/docs/BRIDGE_DESIGN.md | 4 +- .../Runtime/Bridge.Core/BridgeCore.cs | 81 +++ README.md | 13 + Tests/csharp/RobotHost/Bind/RobotHostApi.cs | 13 +- .../csharp/RobotHost/Bind/RobotNullHostApi.cs | 13 +- Tests/csharp/RobotHost/Bind/WorldState.cs | 68 +- .../Bridge.AllCommandDispatcher.g.cs | 95 +++ Tests/csharp/RobotHost/Program.cs | 11 +- .../Bridge.AllCommandDispatcher.g.cs | 95 +++ .../PlayModeTests/BridgeRuntimeSmokeTests.cs | 17 +- .../BridgeSourceModeThroughputTests.cs | 26 +- .../Host/DemoGameUnityHostApi.Asset.cs | 4 +- .../Host/DemoGameUnityHostApi.Entity.cs | 8 +- .../Runtime/Host/DemoGameUnityHostApi.Log.cs | 4 +- .../Runtime/Host/DemoGameUnityHostApi.cs | 3 +- .../Runtime/Runner/DemoGameUnityRunner.cs | 13 +- Tools/RunPerf.ps1 | 655 ++++++++++++++++++ 24 files changed, 1324 insertions(+), 83 deletions(-) create mode 100644 Tools/RunPerf.ps1 diff --git a/.gitignore b/.gitignore index 08b61b2..b08f0c0 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,12 @@ # Unity upgrade logs Tests/unity/Logs +# Unity performance test framework (generated) +Tests/unity/Assets/Resources/PerformanceTestRunInfo.json +Tests/unity/Assets/Resources/PerformanceTestRunInfo.json.meta +Tests/unity/Assets/Resources/PerformanceTestRunSettings.json +Tests/unity/Assets/Resources/PerformanceTestRunSettings.json.meta + # Build outputs build/ Core/**/bin/ diff --git a/Core/Tools/BridgeGen/Program.cs b/Core/Tools/BridgeGen/Program.cs index ac2726e..3b9ec91 100644 --- a/Core/Tools/BridgeGen/Program.cs +++ b/Core/Tools/BridgeGen/Program.cs @@ -469,10 +469,132 @@ private static string EmitAllDispatcher(IReadOnlyList modules) sb.AppendLine("namespace Bridge.Bindings"); sb.AppendLine("{"); sb.AppendLine(" /// "); + sb.AppendLine(" /// Host API 基类:用虚函数分发替代接口调用,降低 IL2CPP 下的 dispatch 开销。"); + sb.AppendLine(" /// "); + sb.AppendLine(" public abstract class BridgeAllHostApiBase"); + bool wroteBaseList = false; + foreach (var m in modules) + { + if (m.Model.HostFns.Count == 0) + continue; + sb.Append(wroteBaseList ? ", " : " : "); + wroteBaseList = true; + sb.Append(m.CsNamespace); + sb.Append(".I"); + sb.Append(m.Module); + sb.Append("HostApi"); + } + if (wroteBaseList) + sb.AppendLine(); + sb.AppendLine(" {"); + foreach (var m in modules) + { + if (m.Model.HostFns.Count == 0) + continue; + + foreach (var fn in m.Model.HostFns) + { + sb.Append(" public abstract void "); + sb.Append(fn.Name); + sb.Append('('); + for (int i = 0; i < fn.Args.Count; i++) + { + if (i > 0) sb.Append(", "); + var arg = fn.Args[i]; + sb.Append(MapCsHostArgParamType(arg.CppType)); + sb.Append(' '); + sb.Append(ToCamel(arg.Name)); + } + sb.AppendLine(");"); + } + } + sb.AppendLine(" }"); + sb.AppendLine(); + sb.AppendLine(" /// "); sb.AppendLine(" /// 单次扫描 command stream,并按 func_id 分发到各模块 Host API。"); sb.AppendLine(" /// "); sb.AppendLine(" public static class BridgeAllCommandDispatcher"); sb.AppendLine(" {"); + sb.AppendLine(" public static unsafe void DispatchFast(CommandStream stream, BridgeAllHostApiBase host)"); + sb.AppendLine(" {"); + sb.AppendLine(" if (stream.IsEmpty || host == null)"); + sb.AppendLine(" return;"); + sb.AppendLine(); + sb.AppendLine(" byte* cursor = (byte*)stream.Ptr;"); + sb.AppendLine(" byte* end = cursor + (int)stream.Length;"); + sb.AppendLine(); + sb.AppendLine(" while (cursor < end)"); + sb.AppendLine(" {"); + sb.AppendLine(" int remaining = (int)(end - cursor);"); + sb.AppendLine(" if (remaining < (int)sizeof(BridgeCommandHeader))"); + sb.AppendLine(" break;"); + sb.AppendLine(); + sb.AppendLine(" var header = (BridgeCommandHeader*)cursor;"); + sb.AppendLine(" int size = header->Size;"); + sb.AppendLine(" if ((uint)size < (uint)sizeof(BridgeCommandHeader) || (uint)size > (uint)remaining)"); + sb.AppendLine(" break;"); + sb.AppendLine(); + sb.AppendLine(" if (header->Type == (ushort)BridgeCommandType.CallHost && size >= sizeof(BridgeCmdCallHost))"); + sb.AppendLine(" {"); + sb.AppendLine(" var cmd = (BridgeCmdCallHost*)cursor;"); + sb.AppendLine(" uint payloadSize = cmd->PayloadSize;"); + sb.AppendLine(" if (payloadSize <= (uint)(size - sizeof(BridgeCmdCallHost)))"); + sb.AppendLine(" {"); + sb.AppendLine(" byte* payloadPtr = cursor + sizeof(BridgeCmdCallHost);"); + sb.AppendLine(); + sb.AppendLine(" switch (cmd->FuncId)"); + sb.AppendLine(" {"); + + foreach (var m in modules) + { + if (m.Model.HostFns.Count == 0) + continue; + + foreach (var fn in m.Model.HostFns) + { + uint id = ComputeHostFuncId(m.Module, fn.Name); + sb.AppendLine($" case 0x{id:X8}u:"); + sb.AppendLine(" {"); + sb.Append(" if (payloadSize == (uint)sizeof("); + sb.Append(m.CsNamespace); + sb.Append(".HostArgs_"); + sb.Append(fn.Name); + sb.AppendLine("))"); + sb.AppendLine(" {"); + sb.Append(" ref readonly "); + sb.Append(m.CsNamespace); + sb.Append(".HostArgs_"); + sb.Append(fn.Name); + sb.Append(" a = ref *(("); + sb.Append(m.CsNamespace); + sb.Append(".HostArgs_"); + sb.Append(fn.Name); + sb.AppendLine("*)payloadPtr);"); + sb.Append(" host."); + sb.Append(fn.Name); + sb.Append('('); + for (int i = 0; i < fn.Args.Count; i++) + { + if (i > 0) sb.Append(", "); + var arg = fn.Args[i]; + string field = $"a.{ToPascal(arg.Name)}"; + sb.Append(MapCsHostArgExpr(arg.CppType, field)); + } + sb.AppendLine(");"); + sb.AppendLine(" }"); + sb.AppendLine(" break;"); + sb.AppendLine(" }"); + } + } + + sb.AppendLine(" }"); + sb.AppendLine(" }"); + sb.AppendLine(" }"); + sb.AppendLine(); + sb.AppendLine(" cursor += size;"); + sb.AppendLine(" }"); + sb.AppendLine(" }"); + sb.AppendLine(); sb.AppendLine(" public static unsafe void Dispatch(CommandStream stream, THost host)"); sb.Append(" where THost : class"); diff --git a/Core/cpp/src/api/bridge_api.cpp b/Core/cpp/src/api/bridge_api.cpp index e2a2a9a..7f1a47a 100644 --- a/Core/cpp/src/api/bridge_api.cpp +++ b/Core/cpp/src/api/bridge_api.cpp @@ -39,12 +39,14 @@ BridgeResult BRIDGE_CALL BridgeCore_TickAndGetCommandStream( const void** out_ptr, uint32_t* out_len) { - if (!core) + if (!core || !out_ptr || !out_len) { return BRIDGE_INVALID_ARGUMENT; } bridge::Tick(*core, dt); - return bridge::GetCommandStream(*core, out_ptr, out_len); + *out_ptr = core->commands.Data(); + *out_len = core->commands.Size(); + return BRIDGE_OK; } BridgeResult BRIDGE_CALL BridgeCore_TickManyAndGetCommandStreams( @@ -70,7 +72,8 @@ BridgeResult BRIDGE_CALL BridgeCore_TickManyAndGetCommandStreams( } bridge::Tick(*core, dt); - (void)bridge::GetCommandStream(*core, &out_ptrs[i], &out_lens[i]); + out_ptrs[i] = core->commands.Data(); + out_lens[i] = core->commands.Size(); } return BRIDGE_OK; } @@ -80,11 +83,13 @@ BridgeResult BRIDGE_CALL BridgeCore_GetCommandStream( const void** out_ptr, uint32_t* out_len) { - if (!core) + if (!core || !out_ptr || !out_len) { return BRIDGE_INVALID_ARGUMENT; } - return bridge::GetCommandStream(*core, out_ptr, out_len); + *out_ptr = core->commands.Data(); + *out_len = core->commands.Size(); + return BRIDGE_OK; } BridgeResult BRIDGE_CALL BridgeCore_PushCallCore( diff --git a/Core/cpp/src/core/command_stream.cpp b/Core/cpp/src/core/command_stream.cpp index 11abf6a..348b9db 100644 --- a/Core/cpp/src/core/command_stream.cpp +++ b/Core/cpp/src/core/command_stream.cpp @@ -33,14 +33,4 @@ namespace bridge view.len = len; return view; } - - const uint8_t* CommandStream::Data() const - { - return bytes_.empty() ? nullptr : bytes_.data(); - } - - uint32_t CommandStream::Size() const - { - return static_cast(bytes_.size()); - } } diff --git a/Core/cpp/src/core/command_stream.h b/Core/cpp/src/core/command_stream.h index 410bdc5..d0585f0 100644 --- a/Core/cpp/src/core/command_stream.h +++ b/Core/cpp/src/core/command_stream.h @@ -26,15 +26,25 @@ namespace bridge // Store UTF-8 bytes and return a view that remains valid until Clear(). BridgeStringView StoreUtf8(std::string utf8); + uint8_t* Allocate(size_t size) + { + if (size == 0) + { + return nullptr; + } + const size_t oldSize = bytes_.size(); + bytes_.resize(oldSize + size); + return bytes_.data() + oldSize; + } + void PushBytes(const void* data, size_t size) { if (!data || size == 0) { return; } - const size_t oldSize = bytes_.size(); - bytes_.resize(oldSize + size); - std::memcpy(bytes_.data() + oldSize, data, size); + uint8_t* dst = Allocate(size); + std::memcpy(dst, data, size); } void PushZeroBytes(size_t size) @@ -43,9 +53,8 @@ namespace bridge { return; } - const size_t oldSize = bytes_.size(); - bytes_.resize(oldSize + size); - std::memset(bytes_.data() + oldSize, 0, size); + uint8_t* dst = Allocate(size); + std::memset(dst, 0, size); } template @@ -56,13 +65,19 @@ namespace bridge static_assert(sizeof(T) % 8 == 0, "Command size must be 8-byte aligned"); static_assert(sizeof(T) <= UINT16_MAX, "Command struct too large for header.size"); - const size_t oldSize = bytes_.size(); - bytes_.resize(oldSize + sizeof(T)); - std::memcpy(bytes_.data() + oldSize, &command, sizeof(T)); + uint8_t* dst = Allocate(sizeof(T)); + std::memcpy(dst, &command, sizeof(T)); } - const uint8_t* Data() const; - uint32_t Size() const; + const uint8_t* Data() const + { + return bytes_.empty() ? nullptr : bytes_.data(); + } + + uint32_t Size() const + { + return static_cast(bytes_.size()); + } private: std::vector bytes_; diff --git a/Core/cpp/src/core/core_instance.cpp b/Core/cpp/src/core/core_instance.cpp index 44bbef9..c4afa3e 100644 --- a/Core/cpp/src/core/core_instance.cpp +++ b/Core/cpp/src/core/core_instance.cpp @@ -64,9 +64,22 @@ namespace bridge cmd.func_id = funcId; cmd.payload_size = payloadSize; - core_.commands.PushBytes(&cmd, sizeof(cmd)); - core_.commands.PushBytes(payload, payloadSize); - core_.commands.PushZeroBytes(alignedTotal - static_cast(sizeof(cmd)) - payloadSize); + uint8_t* dst = core_.commands.Allocate(static_cast(alignedTotal)); + if (!dst) + { + return; + } + + std::memcpy(dst, &cmd, sizeof(cmd)); + if (payloadSize > 0) + { + std::memcpy(dst + sizeof(cmd), payload, payloadSize); + } + const uint32_t pad = alignedTotal - static_cast(sizeof(cmd)) - payloadSize; + if (pad > 0) + { + std::memset(dst + sizeof(cmd) + payloadSize, 0, pad); + } } BridgeTransform CoreContext::IdentityTransform() diff --git a/Core/csharp/Bridge.Core/BridgeCore.cs b/Core/csharp/Bridge.Core/BridgeCore.cs index 4914876..c0ed571 100644 --- a/Core/csharp/Bridge.Core/BridgeCore.cs +++ b/Core/csharp/Bridge.Core/BridgeCore.cs @@ -28,6 +28,15 @@ public BridgeCore(ulong seed = 1, bool robotMode = false) throw new InvalidOperationException("BridgeCore_Create returned null"); } + public IntPtr UnsafeHandle + { + get + { + ThrowIfDisposed(); + return _handle; + } + } + /// /// 推进 Core 一帧(或一个逻辑 tick)。 /// @@ -133,6 +142,63 @@ public static unsafe void TickManyAndGetCommandStreams(BridgeCore[] cores, float } } + public static unsafe void TickManyAndGetCommandStreams(IntPtr[] coreHandles, float dt, CommandStream[] streams) + { + if (coreHandles == null) + throw new ArgumentNullException(nameof(coreHandles)); + if (streams == null) + throw new ArgumentNullException(nameof(streams)); + if (streams.Length < coreHandles.Length) + throw new ArgumentException("streams.Length must be >= coreHandles.Length", nameof(streams)); + + int count = coreHandles.Length; + if (count == 0) + return; + + if (count <= StackAllocMaxCount) + { + fixed (IntPtr* corePtrs = coreHandles) + { + IntPtr* outPtrs = stackalloc IntPtr[count]; + uint* outLens = stackalloc uint[count]; + + var result = BridgeNative.BridgeCore_TickManyAndGetCommandStreams(corePtrs, (uint)count, dt, outPtrs, outLens); + if (result != BridgeResult.Ok) + throw new InvalidOperationException($"BridgeCore_TickManyAndGetCommandStreams failed: {result}"); + + for (int i = 0; i < count; i++) + { + IntPtr ptr = outPtrs[i]; + uint len = outLens[i]; + streams[i] = (ptr == IntPtr.Zero || len == 0) ? CommandStream.Empty : new CommandStream(ptr, len); + } + } + } + else + { + EnsureTickManyOutArrays(count); + + IntPtr[] outPtrsManaged = s_tickManyOutPtrs!; + uint[] outLensManaged = s_tickManyOutLens!; + + fixed (IntPtr* corePtrs = coreHandles) + fixed (IntPtr* outPtrs = outPtrsManaged) + fixed (uint* outLens = outLensManaged) + { + var result = BridgeNative.BridgeCore_TickManyAndGetCommandStreams(corePtrs, (uint)count, dt, outPtrs, outLens); + if (result != BridgeResult.Ok) + throw new InvalidOperationException($"BridgeCore_TickManyAndGetCommandStreams failed: {result}"); + } + + for (int i = 0; i < count; i++) + { + IntPtr ptr = outPtrsManaged[i]; + uint len = outLensManaged[i]; + streams[i] = (ptr == IntPtr.Zero || len == 0) ? CommandStream.Empty : new CommandStream(ptr, len); + } + } + } + private static void EnsureTickManyArrays(int count) { s_tickManyCorePtrs ??= new IntPtr[count]; @@ -144,6 +210,15 @@ private static void EnsureTickManyArrays(int count) if (s_tickManyOutLens.Length < count) s_tickManyOutLens = new uint[count]; } + private static void EnsureTickManyOutArrays(int count) + { + s_tickManyOutPtrs ??= new IntPtr[count]; + s_tickManyOutLens ??= new uint[count]; + + if (s_tickManyOutPtrs.Length < count) s_tickManyOutPtrs = new IntPtr[count]; + if (s_tickManyOutLens.Length < count) s_tickManyOutLens = new uint[count]; + } + /// /// 获取最近一次 生成的命令字节流(command stream)。 /// diff --git a/Core/docs/BRIDGE_DESIGN.md b/Core/docs/BRIDGE_DESIGN.md index eeabebf..57d0ee0 100644 --- a/Core/docs/BRIDGE_DESIGN.md +++ b/Core/docs/BRIDGE_DESIGN.md @@ -95,7 +95,8 @@ Host 侧拿到 Core 输出的 `CommandStream` 后,需要把 `CallHost(func_id, 为性能与 Unity/IL2CPP 友好,本仓库只保留一种分发策略(不依赖 native→managed 回调): - **单次扫描聚合分发(all)** - - 生成 `Bridge.Bindings.BridgeAllCommandDispatcher.Dispatch(stream, host)` + - 生成 `Bridge.Bindings.BridgeAllCommandDispatcher.DispatchFast(stream, host)`(建议:host 继承 `Bridge.Bindings.BridgeAllHostApiBase`,IL2CPP 下更快) + - 同时保留 `Bridge.Bindings.BridgeAllCommandDispatcher.Dispatch(stream, host)`(接口约束泛型版本,便于旧代码/多态) - 单 pass 扫描,并按 `func_id` 分发到各模块 Host API - 模块化的边界仍然体现在:`IHostApi` / `*.Structs.g.cs` / `*.CoreCalls.g.cs` @@ -104,6 +105,7 @@ Host 侧拿到 Core 输出的 `CommandStream` 后,需要把 `CallHost(func_id, - 分发器使用 `unsafe` + `sizeof(T)` + 指针解引用读取 payload,避免 `Marshal.PtrToStructure` 的反射与分配。 - Host→Core 的 `PushCallCore(payload)` 使用 `unmanaged` 泛型直接传栈上数据指针,避免 `AllocHGlobal`。 - 为减少 Host 侧 native 调用次数:提供 `BridgeCore_TickAndGetCommandStream` 与 `BridgeCore_TickManyAndGetCommandStreams`。 +- 在 IL2CPP/大规模多实例场景下,推荐缓存 `BridgeCore.UnsafeHandle`,并使用 `TickManyAndGetCommandStreams(IntPtr[] coreHandles, ...)` 避免每帧提取 handle。 ### 基准结果(示例) diff --git a/Packages/com.unitynativescripting.bridgecore/Runtime/Bridge.Core/BridgeCore.cs b/Packages/com.unitynativescripting.bridgecore/Runtime/Bridge.Core/BridgeCore.cs index 4914876..594ad29 100644 --- a/Packages/com.unitynativescripting.bridgecore/Runtime/Bridge.Core/BridgeCore.cs +++ b/Packages/com.unitynativescripting.bridgecore/Runtime/Bridge.Core/BridgeCore.cs @@ -7,7 +7,13 @@ namespace Bridge.Core /// public sealed class BridgeCore : IDisposable { +#if ENABLE_IL2CPP + // IL2CPP 会对 stackalloc 生成 alloca + memset(0),在大规模 tick many 下是可观的额外成本。 + // 这里直接走 ThreadStatic 托管数组 + fixed,避免每帧栈上清零。 + private const int StackAllocMaxCount = 0; +#else private const int StackAllocMaxCount = 1024; +#endif [ThreadStatic] private static IntPtr[]? s_tickManyCorePtrs; [ThreadStatic] private static IntPtr[]? s_tickManyOutPtrs; @@ -28,6 +34,15 @@ public BridgeCore(ulong seed = 1, bool robotMode = false) throw new InvalidOperationException("BridgeCore_Create returned null"); } + public IntPtr UnsafeHandle + { + get + { + ThrowIfDisposed(); + return _handle; + } + } + /// /// 推进 Core 一帧(或一个逻辑 tick)。 /// @@ -133,6 +148,63 @@ public static unsafe void TickManyAndGetCommandStreams(BridgeCore[] cores, float } } + public static unsafe void TickManyAndGetCommandStreams(IntPtr[] coreHandles, float dt, CommandStream[] streams) + { + if (coreHandles == null) + throw new ArgumentNullException(nameof(coreHandles)); + if (streams == null) + throw new ArgumentNullException(nameof(streams)); + if (streams.Length < coreHandles.Length) + throw new ArgumentException("streams.Length must be >= coreHandles.Length", nameof(streams)); + + int count = coreHandles.Length; + if (count == 0) + return; + + if (count <= StackAllocMaxCount) + { + fixed (IntPtr* corePtrs = coreHandles) + { + IntPtr* outPtrs = stackalloc IntPtr[count]; + uint* outLens = stackalloc uint[count]; + + var result = BridgeNative.BridgeCore_TickManyAndGetCommandStreams(corePtrs, (uint)count, dt, outPtrs, outLens); + if (result != BridgeResult.Ok) + throw new InvalidOperationException($"BridgeCore_TickManyAndGetCommandStreams failed: {result}"); + + for (int i = 0; i < count; i++) + { + IntPtr ptr = outPtrs[i]; + uint len = outLens[i]; + streams[i] = (ptr == IntPtr.Zero || len == 0) ? CommandStream.Empty : new CommandStream(ptr, len); + } + } + } + else + { + EnsureTickManyOutArrays(count); + + IntPtr[] outPtrsManaged = s_tickManyOutPtrs!; + uint[] outLensManaged = s_tickManyOutLens!; + + fixed (IntPtr* corePtrs = coreHandles) + fixed (IntPtr* outPtrs = outPtrsManaged) + fixed (uint* outLens = outLensManaged) + { + var result = BridgeNative.BridgeCore_TickManyAndGetCommandStreams(corePtrs, (uint)count, dt, outPtrs, outLens); + if (result != BridgeResult.Ok) + throw new InvalidOperationException($"BridgeCore_TickManyAndGetCommandStreams failed: {result}"); + } + + for (int i = 0; i < count; i++) + { + IntPtr ptr = outPtrsManaged[i]; + uint len = outLensManaged[i]; + streams[i] = (ptr == IntPtr.Zero || len == 0) ? CommandStream.Empty : new CommandStream(ptr, len); + } + } + } + private static void EnsureTickManyArrays(int count) { s_tickManyCorePtrs ??= new IntPtr[count]; @@ -144,6 +216,15 @@ private static void EnsureTickManyArrays(int count) if (s_tickManyOutLens.Length < count) s_tickManyOutLens = new uint[count]; } + private static void EnsureTickManyOutArrays(int count) + { + s_tickManyOutPtrs ??= new IntPtr[count]; + s_tickManyOutLens ??= new uint[count]; + + if (s_tickManyOutPtrs.Length < count) s_tickManyOutPtrs = new IntPtr[count]; + if (s_tickManyOutLens.Length < count) s_tickManyOutLens = new uint[count]; + } + /// /// 获取最近一次 生成的命令字节流(command stream)。 /// diff --git a/README.md b/README.md index 28e6e2c..a2e4080 100644 --- a/README.md +++ b/README.md @@ -60,3 +60,16 @@ dotnet run --project Core/Tools/BridgeGen/BridgeGen.csproj -c Release -- --out-c - 架构设计:`Core/docs/BRIDGE_DESIGN.md` - 构建与运行:`Core/docs/BUILD.md` - Unity Windows 原生库加载:`Core/docs/UNITY_WIN_NATIVE_LOADING.md` + +## 性能测试(带历史记录) + +仓库提供一个 PowerShell 脚本用于跑机器人/Unity 性能用例,并把每次结果追加写入历史文件: + +```powershell +powershell -ExecutionPolicy Bypass -File Tools/RunPerf.ps1 -Bots 1000 -Frames 3000 -Tag "baseline" +``` + +- 默认输出:`build/perf_history.jsonl`(每行一条 JSON 记录) +- 单次 run 的日志/产物:`build/perf_runs//` +- 可选:`-NoUnity` / `-NoUnityEditMode` / `-NoUnityIl2cpp` / `-NoBuild` +- 可选:`-UnityVersion 6000.0.40f1` 或 `-UnityExe ` 用于指定 Unity 版本/路径 diff --git a/Tests/csharp/RobotHost/Bind/RobotHostApi.cs b/Tests/csharp/RobotHost/Bind/RobotHostApi.cs index 671f42b..c1e6c9e 100644 --- a/Tests/csharp/RobotHost/Bind/RobotHostApi.cs +++ b/Tests/csharp/RobotHost/Bind/RobotHostApi.cs @@ -1,7 +1,8 @@ +using Bridge.Bindings; using Bridge.Core; using DemoAsset.Bindings; -sealed class RobotHostApi : IRobotHostApi +sealed class RobotHostApi : BridgeAllHostApiBase, IRobotHostApi { private readonly BridgeCore _core; private readonly WorldState _world; @@ -21,14 +22,14 @@ public RobotHostApi(BridgeCore core, WorldState world, FileAssetProvider assets) _assets = assets; } - public void Log(BridgeLogLevel level, BridgeStringView message) + public override void Log(BridgeLogLevel level, BridgeStringView message) { Commands++; Logs++; _world.OnLog(level, message); } - public void LoadAsset(ulong requestId, BridgeAssetType assetType, BridgeStringView assetKey) + public override void LoadAsset(ulong requestId, BridgeAssetType assetType, BridgeStringView assetKey) { _ = assetType; @@ -41,21 +42,21 @@ public void LoadAsset(ulong requestId, BridgeAssetType assetType, BridgeStringVi _core.AssetLoaded(requestId, 0, BridgeAssetStatus.NotFound); } - public void SpawnEntity(ulong entityId, ulong prefabHandle, in BridgeTransform transform, uint flags) + public override void SpawnEntity(ulong entityId, ulong prefabHandle, in BridgeTransform transform, uint flags) { Commands++; Spawns++; _world.OnSpawn(entityId, prefabHandle, in transform, flags); } - public void SetTransform(ulong entityId, uint mask, in BridgeTransform transform) + public override void SetTransform(ulong entityId, uint mask, in BridgeTransform transform) { Commands++; Transforms++; _world.OnSetTransform(entityId, mask, in transform); } - public void DestroyEntity(ulong entityId) + public override void DestroyEntity(ulong entityId) { Commands++; Destroys++; diff --git a/Tests/csharp/RobotHost/Bind/RobotNullHostApi.cs b/Tests/csharp/RobotHost/Bind/RobotNullHostApi.cs index 82c68a7..1bb9aca 100644 --- a/Tests/csharp/RobotHost/Bind/RobotNullHostApi.cs +++ b/Tests/csharp/RobotHost/Bind/RobotNullHostApi.cs @@ -1,7 +1,8 @@ +using Bridge.Bindings; using Bridge.Core; using DemoAsset.Bindings; -sealed class RobotNullHostApi : IRobotHostApi +sealed class RobotNullHostApi : BridgeAllHostApiBase, IRobotHostApi { private readonly BridgeCore _core; @@ -18,7 +19,7 @@ public RobotNullHostApi(BridgeCore core, FileAssetProvider assets) _ = assets; } - public void Log(BridgeLogLevel level, BridgeStringView message) + public override void Log(BridgeLogLevel level, BridgeStringView message) { _ = level; _ = message; @@ -26,7 +27,7 @@ public void Log(BridgeLogLevel level, BridgeStringView message) Logs++; } - public void LoadAsset(ulong requestId, BridgeAssetType assetType, BridgeStringView assetKey) + public override void LoadAsset(ulong requestId, BridgeAssetType assetType, BridgeStringView assetKey) { _ = assetType; @@ -39,7 +40,7 @@ public void LoadAsset(ulong requestId, BridgeAssetType assetType, BridgeStringVi _core.AssetLoaded(requestId, handle, BridgeAssetStatus.Ok); } - public void SpawnEntity(ulong entityId, ulong prefabHandle, in BridgeTransform transform, uint flags) + public override void SpawnEntity(ulong entityId, ulong prefabHandle, in BridgeTransform transform, uint flags) { _ = entityId; _ = prefabHandle; @@ -48,7 +49,7 @@ public void SpawnEntity(ulong entityId, ulong prefabHandle, in BridgeTransform t Spawns++; } - public void SetTransform(ulong entityId, uint mask, in BridgeTransform transform) + public override void SetTransform(ulong entityId, uint mask, in BridgeTransform transform) { _ = entityId; _ = mask; @@ -56,7 +57,7 @@ public void SetTransform(ulong entityId, uint mask, in BridgeTransform transform Transforms++; } - public void DestroyEntity(ulong entityId) + public override void DestroyEntity(ulong entityId) { _ = entityId; Commands++; diff --git a/Tests/csharp/RobotHost/Bind/WorldState.cs b/Tests/csharp/RobotHost/Bind/WorldState.cs index 0d9f8fa..860adca 100644 --- a/Tests/csharp/RobotHost/Bind/WorldState.cs +++ b/Tests/csharp/RobotHost/Bind/WorldState.cs @@ -1,9 +1,15 @@ using System.Collections.Generic; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; using Bridge.Core; sealed class WorldState { - private readonly Dictionary _entities = new(capacity: 4); + private bool _hasSingleEntity; + private ulong _singleEntityId; + private Entity _singleEntity; + + private Dictionary? _entities; public void OnLog(BridgeLogLevel level, BridgeStringView message) { @@ -14,30 +20,76 @@ public void OnLog(BridgeLogLevel level, BridgeStringView message) public void OnSpawn(ulong entityId, ulong prefabHandle, in BridgeTransform transform, uint flags) { _ = flags; - _entities[entityId] = new Entity(prefabHandle, transform); + + if (_entities == null) + { + if (!_hasSingleEntity || entityId == _singleEntityId) + { + _hasSingleEntity = true; + _singleEntityId = entityId; + _singleEntity.PrefabHandle = prefabHandle; + _singleEntity.Transform = transform; + return; + } + + EnsureEntities(); + } + + _entities![entityId] = new Entity(prefabHandle, transform); } public void OnSetTransform(ulong entityId, uint mask, in BridgeTransform transform) { - if (_entities.TryGetValue(entityId, out var entity)) + if (_entities == null) { - var tr = entity.Transform; + if (!_hasSingleEntity || entityId != _singleEntityId) + return; + + var tr = _singleEntity.Transform; if ((mask & 1u) != 0) tr.Position = transform.Position; if ((mask & 2u) != 0) tr.Rotation = transform.Rotation; if ((mask & 4u) != 0) tr.Scale = transform.Scale; - _entities[entityId] = new Entity(entity.PrefabHandle, tr); + _singleEntity.Transform = tr; + return; } + + ref Entity entity = ref CollectionsMarshal.GetValueRefOrNullRef(_entities, entityId); + if (Unsafe.IsNullRef(ref entity)) + return; + + var tr2 = entity.Transform; + if ((mask & 1u) != 0) tr2.Position = transform.Position; + if ((mask & 2u) != 0) tr2.Rotation = transform.Rotation; + if ((mask & 4u) != 0) tr2.Scale = transform.Scale; + entity.Transform = tr2; } public void OnDestroy(ulong entityId) { + if (_entities == null) + { + if (_hasSingleEntity && entityId == _singleEntityId) + _hasSingleEntity = false; + return; + } + _entities.Remove(entityId); } - private readonly struct Entity + private void EnsureEntities() + { + if (_entities != null) + return; + + _entities = new Dictionary(capacity: 4); + _entities[_singleEntityId] = _singleEntity; + _hasSingleEntity = false; + } + + private struct Entity { - public readonly ulong PrefabHandle; - public readonly BridgeTransform Transform; + public ulong PrefabHandle; + public BridgeTransform Transform; public Entity(ulong prefabHandle, BridgeTransform transform) { diff --git a/Tests/csharp/RobotHost/Generated/Bridge.AllCommandDispatcher.g.cs b/Tests/csharp/RobotHost/Generated/Bridge.AllCommandDispatcher.g.cs index 2c3638c..384659d 100644 --- a/Tests/csharp/RobotHost/Generated/Bridge.AllCommandDispatcher.g.cs +++ b/Tests/csharp/RobotHost/Generated/Bridge.AllCommandDispatcher.g.cs @@ -6,11 +6,106 @@ namespace Bridge.Bindings { + /// + /// Host API 基类:用虚函数分发替代接口调用,降低 IL2CPP 下的 dispatch 开销。 + /// + public abstract class BridgeAllHostApiBase + : DemoAsset.Bindings.IDemoAssetHostApi, DemoEntity.Bindings.IDemoEntityHostApi, DemoLog.Bindings.IDemoLogHostApi + { + public abstract void LoadAsset(ulong requestId, BridgeAssetType assetType, BridgeStringView assetKey); + public abstract void SpawnEntity(ulong entityId, ulong prefabHandle, in BridgeTransform transform, uint flags); + public abstract void SetTransform(ulong entityId, uint mask, in BridgeTransform transform); + public abstract void DestroyEntity(ulong entityId); + public abstract void Log(BridgeLogLevel level, BridgeStringView message); + } + /// /// 单次扫描 command stream,并按 func_id 分发到各模块 Host API。 /// public static class BridgeAllCommandDispatcher { + public static unsafe void DispatchFast(CommandStream stream, BridgeAllHostApiBase host) + { + if (stream.IsEmpty || host == null) + return; + + byte* cursor = (byte*)stream.Ptr; + byte* end = cursor + (int)stream.Length; + + while (cursor < end) + { + int remaining = (int)(end - cursor); + if (remaining < (int)sizeof(BridgeCommandHeader)) + break; + + var header = (BridgeCommandHeader*)cursor; + int size = header->Size; + if ((uint)size < (uint)sizeof(BridgeCommandHeader) || (uint)size > (uint)remaining) + break; + + if (header->Type == (ushort)BridgeCommandType.CallHost && size >= sizeof(BridgeCmdCallHost)) + { + var cmd = (BridgeCmdCallHost*)cursor; + uint payloadSize = cmd->PayloadSize; + if (payloadSize <= (uint)(size - sizeof(BridgeCmdCallHost))) + { + byte* payloadPtr = cursor + sizeof(BridgeCmdCallHost); + + switch (cmd->FuncId) + { + case 0x82A5E93Au: + { + if (payloadSize == (uint)sizeof(DemoAsset.Bindings.HostArgs_LoadAsset)) + { + ref readonly DemoAsset.Bindings.HostArgs_LoadAsset a = ref *((DemoAsset.Bindings.HostArgs_LoadAsset*)payloadPtr); + host.LoadAsset(a.RequestId, a.AssetType, a.AssetKey); + } + break; + } + case 0xBCAA331Du: + { + if (payloadSize == (uint)sizeof(DemoEntity.Bindings.HostArgs_SpawnEntity)) + { + ref readonly DemoEntity.Bindings.HostArgs_SpawnEntity a = ref *((DemoEntity.Bindings.HostArgs_SpawnEntity*)payloadPtr); + host.SpawnEntity(a.EntityId, a.PrefabHandle, in a.Transform, a.Flags); + } + break; + } + case 0x20DA0B6Fu: + { + if (payloadSize == (uint)sizeof(DemoEntity.Bindings.HostArgs_SetTransform)) + { + ref readonly DemoEntity.Bindings.HostArgs_SetTransform a = ref *((DemoEntity.Bindings.HostArgs_SetTransform*)payloadPtr); + host.SetTransform(a.EntityId, a.Mask, in a.Transform); + } + break; + } + case 0xC7C1C59Cu: + { + if (payloadSize == (uint)sizeof(DemoEntity.Bindings.HostArgs_DestroyEntity)) + { + ref readonly DemoEntity.Bindings.HostArgs_DestroyEntity a = ref *((DemoEntity.Bindings.HostArgs_DestroyEntity*)payloadPtr); + host.DestroyEntity(a.EntityId); + } + break; + } + case 0xDA3184A2u: + { + if (payloadSize == (uint)sizeof(DemoLog.Bindings.HostArgs_Log)) + { + ref readonly DemoLog.Bindings.HostArgs_Log a = ref *((DemoLog.Bindings.HostArgs_Log*)payloadPtr); + host.Log(a.Level, a.Message); + } + break; + } + } + } + } + + cursor += size; + } + } + public static unsafe void Dispatch(CommandStream stream, THost host) where THost : class, DemoAsset.Bindings.IDemoAssetHostApi, DemoEntity.Bindings.IDemoEntityHostApi, DemoLog.Bindings.IDemoLogHostApi { diff --git a/Tests/csharp/RobotHost/Program.cs b/Tests/csharp/RobotHost/Program.cs index 0a6a172..bbf1455 100644 --- a/Tests/csharp/RobotHost/Program.cs +++ b/Tests/csharp/RobotHost/Program.cs @@ -95,6 +95,7 @@ private static RunResult Run(int bots, int frames, float dt, string assetsRoot, _ = assetProvider.TryGetHandle("Main/Prefabs/Bot", out _); var cores = new BridgeCore[bots]; + var coreHandles = new IntPtr[bots]; if (nullHost) { @@ -103,6 +104,7 @@ private static RunResult Run(int bots, int frames, float dt, string assetsRoot, { var core = new BridgeCore(seed: (ulong)(i + 1), robotMode: true); cores[i] = core; + coreHandles[i] = core.UnsafeHandle; hosts[i] = new RobotNullHostApi(core, assetProvider); } @@ -114,7 +116,7 @@ private static RunResult Run(int bots, int frames, float dt, string assetsRoot, int warmupFrames = frames > 0 ? 1 : 0; for (int frame = 0; frame < warmupFrames; frame++) { - BridgeCore.TickManyAndGetCommandStreams(cores, dt, streams); + BridgeCore.TickManyAndGetCommandStreams(coreHandles, dt, streams); for (int i = 0; i < cores.Length; i++) BridgeAllCommandDispatcher.Dispatch(streams[i], hosts[i]); } @@ -143,7 +145,7 @@ private static RunResult Run(int bots, int frames, float dt, string assetsRoot, { for (int frame = 0; frame < frames; frame++) { - BridgeCore.TickManyAndGetCommandStreams(cores, dt, streams); + BridgeCore.TickManyAndGetCommandStreams(coreHandles, dt, streams); for (int i = 0; i < cores.Length; i++) BridgeAllCommandDispatcher.Dispatch(streams[i], hosts[i]); } @@ -197,6 +199,7 @@ private static RunResult Run(int bots, int frames, float dt, string assetsRoot, { var core = new BridgeCore(seed: (ulong)(i + 1), robotMode: true); cores[i] = core; + coreHandles[i] = core.UnsafeHandle; var world = new WorldState(); hosts[i] = new RobotHostApi(core, world, assetProvider); @@ -210,7 +213,7 @@ private static RunResult Run(int bots, int frames, float dt, string assetsRoot, int warmupFrames = frames > 0 ? 1 : 0; for (int frame = 0; frame < warmupFrames; frame++) { - BridgeCore.TickManyAndGetCommandStreams(cores, dt, streams); + BridgeCore.TickManyAndGetCommandStreams(coreHandles, dt, streams); for (int i = 0; i < cores.Length; i++) BridgeAllCommandDispatcher.Dispatch(streams[i], hosts[i]); } @@ -239,7 +242,7 @@ private static RunResult Run(int bots, int frames, float dt, string assetsRoot, { for (int frame = 0; frame < frames; frame++) { - BridgeCore.TickManyAndGetCommandStreams(cores, dt, streams); + BridgeCore.TickManyAndGetCommandStreams(coreHandles, dt, streams); for (int i = 0; i < cores.Length; i++) BridgeAllCommandDispatcher.Dispatch(streams[i], hosts[i]); } diff --git a/Tests/unity/Assets/BridgeDemoGame/Generated/Bridge.AllCommandDispatcher.g.cs b/Tests/unity/Assets/BridgeDemoGame/Generated/Bridge.AllCommandDispatcher.g.cs index 2c3638c..384659d 100644 --- a/Tests/unity/Assets/BridgeDemoGame/Generated/Bridge.AllCommandDispatcher.g.cs +++ b/Tests/unity/Assets/BridgeDemoGame/Generated/Bridge.AllCommandDispatcher.g.cs @@ -6,11 +6,106 @@ namespace Bridge.Bindings { + /// + /// Host API 基类:用虚函数分发替代接口调用,降低 IL2CPP 下的 dispatch 开销。 + /// + public abstract class BridgeAllHostApiBase + : DemoAsset.Bindings.IDemoAssetHostApi, DemoEntity.Bindings.IDemoEntityHostApi, DemoLog.Bindings.IDemoLogHostApi + { + public abstract void LoadAsset(ulong requestId, BridgeAssetType assetType, BridgeStringView assetKey); + public abstract void SpawnEntity(ulong entityId, ulong prefabHandle, in BridgeTransform transform, uint flags); + public abstract void SetTransform(ulong entityId, uint mask, in BridgeTransform transform); + public abstract void DestroyEntity(ulong entityId); + public abstract void Log(BridgeLogLevel level, BridgeStringView message); + } + /// /// 单次扫描 command stream,并按 func_id 分发到各模块 Host API。 /// public static class BridgeAllCommandDispatcher { + public static unsafe void DispatchFast(CommandStream stream, BridgeAllHostApiBase host) + { + if (stream.IsEmpty || host == null) + return; + + byte* cursor = (byte*)stream.Ptr; + byte* end = cursor + (int)stream.Length; + + while (cursor < end) + { + int remaining = (int)(end - cursor); + if (remaining < (int)sizeof(BridgeCommandHeader)) + break; + + var header = (BridgeCommandHeader*)cursor; + int size = header->Size; + if ((uint)size < (uint)sizeof(BridgeCommandHeader) || (uint)size > (uint)remaining) + break; + + if (header->Type == (ushort)BridgeCommandType.CallHost && size >= sizeof(BridgeCmdCallHost)) + { + var cmd = (BridgeCmdCallHost*)cursor; + uint payloadSize = cmd->PayloadSize; + if (payloadSize <= (uint)(size - sizeof(BridgeCmdCallHost))) + { + byte* payloadPtr = cursor + sizeof(BridgeCmdCallHost); + + switch (cmd->FuncId) + { + case 0x82A5E93Au: + { + if (payloadSize == (uint)sizeof(DemoAsset.Bindings.HostArgs_LoadAsset)) + { + ref readonly DemoAsset.Bindings.HostArgs_LoadAsset a = ref *((DemoAsset.Bindings.HostArgs_LoadAsset*)payloadPtr); + host.LoadAsset(a.RequestId, a.AssetType, a.AssetKey); + } + break; + } + case 0xBCAA331Du: + { + if (payloadSize == (uint)sizeof(DemoEntity.Bindings.HostArgs_SpawnEntity)) + { + ref readonly DemoEntity.Bindings.HostArgs_SpawnEntity a = ref *((DemoEntity.Bindings.HostArgs_SpawnEntity*)payloadPtr); + host.SpawnEntity(a.EntityId, a.PrefabHandle, in a.Transform, a.Flags); + } + break; + } + case 0x20DA0B6Fu: + { + if (payloadSize == (uint)sizeof(DemoEntity.Bindings.HostArgs_SetTransform)) + { + ref readonly DemoEntity.Bindings.HostArgs_SetTransform a = ref *((DemoEntity.Bindings.HostArgs_SetTransform*)payloadPtr); + host.SetTransform(a.EntityId, a.Mask, in a.Transform); + } + break; + } + case 0xC7C1C59Cu: + { + if (payloadSize == (uint)sizeof(DemoEntity.Bindings.HostArgs_DestroyEntity)) + { + ref readonly DemoEntity.Bindings.HostArgs_DestroyEntity a = ref *((DemoEntity.Bindings.HostArgs_DestroyEntity*)payloadPtr); + host.DestroyEntity(a.EntityId); + } + break; + } + case 0xDA3184A2u: + { + if (payloadSize == (uint)sizeof(DemoLog.Bindings.HostArgs_Log)) + { + ref readonly DemoLog.Bindings.HostArgs_Log a = ref *((DemoLog.Bindings.HostArgs_Log*)payloadPtr); + host.Log(a.Level, a.Message); + } + break; + } + } + } + } + + cursor += size; + } + } + public static unsafe void Dispatch(CommandStream stream, THost host) where THost : class, DemoAsset.Bindings.IDemoAssetHostApi, DemoEntity.Bindings.IDemoEntityHostApi, DemoLog.Bindings.IDemoLogHostApi { diff --git a/Tests/unity/Assets/BridgeDemoGame/PlayModeTests/BridgeRuntimeSmokeTests.cs b/Tests/unity/Assets/BridgeDemoGame/PlayModeTests/BridgeRuntimeSmokeTests.cs index dd53829..ce61580 100644 --- a/Tests/unity/Assets/BridgeDemoGame/PlayModeTests/BridgeRuntimeSmokeTests.cs +++ b/Tests/unity/Assets/BridgeDemoGame/PlayModeTests/BridgeRuntimeSmokeTests.cs @@ -12,7 +12,7 @@ namespace BridgeDemoGame.PlayModeTests { public sealed class BridgeRuntimeSmokeTests { - private sealed class NullHostApi : IDemoAssetHostApi, IDemoEntityHostApi, IDemoLogHostApi + private sealed class NullHostApi : BridgeAllHostApiBase { private readonly BridgeCore _core; @@ -21,14 +21,14 @@ public NullHostApi(BridgeCore core) _core = core; } - public void LoadAsset(ulong requestId, BridgeAssetType assetType, BridgeStringView assetKey) + public override void LoadAsset(ulong requestId, BridgeAssetType assetType, BridgeStringView assetKey) { _ = assetType; _ = assetKey; _core.AssetLoaded(requestId, handle: 1, BridgeAssetStatus.Ok); } - public void SpawnEntity(ulong entityId, ulong prefabHandle, in BridgeTransform transform, uint flags) + public override void SpawnEntity(ulong entityId, ulong prefabHandle, in BridgeTransform transform, uint flags) { _ = entityId; _ = prefabHandle; @@ -36,19 +36,19 @@ public void SpawnEntity(ulong entityId, ulong prefabHandle, in BridgeTransform t _ = flags; } - public void SetTransform(ulong entityId, uint mask, in BridgeTransform transform) + public override void SetTransform(ulong entityId, uint mask, in BridgeTransform transform) { _ = entityId; _ = mask; _ = transform; } - public void DestroyEntity(ulong entityId) + public override void DestroyEntity(ulong entityId) { _ = entityId; } - public void Log(BridgeLogLevel level, BridgeStringView message) + public override void Log(BridgeLogLevel level, BridgeStringView message) { _ = level; _ = message; @@ -67,11 +67,14 @@ public IEnumerator TickAndDispatch_60Frames_NoException() for (int i = 0; i < 60; i++) { var stream = core.TickAndGetCommandStream(1.0f / 60.0f); +#if ENABLE_IL2CPP + BridgeAllCommandDispatcher.DispatchFast(stream, host); +#else BridgeAllCommandDispatcher.Dispatch(stream, host); +#endif yield return null; } } } } } - diff --git a/Tests/unity/Assets/BridgeDemoGame/PlayModeTests/BridgeSourceModeThroughputTests.cs b/Tests/unity/Assets/BridgeDemoGame/PlayModeTests/BridgeSourceModeThroughputTests.cs index 04ec3ab..63b9868 100644 --- a/Tests/unity/Assets/BridgeDemoGame/PlayModeTests/BridgeSourceModeThroughputTests.cs +++ b/Tests/unity/Assets/BridgeDemoGame/PlayModeTests/BridgeSourceModeThroughputTests.cs @@ -15,7 +15,7 @@ namespace BridgeDemoGame.PlayModeTests { public sealed class BridgeSourceModeThroughputTests { - private sealed class NullHostApi : IDemoAssetHostApi, IDemoEntityHostApi, IDemoLogHostApi + private sealed class NullHostApi : BridgeAllHostApiBase { private readonly BridgeCore _core; @@ -24,14 +24,14 @@ public NullHostApi(BridgeCore core) _core = core; } - public void LoadAsset(ulong requestId, BridgeAssetType assetType, BridgeStringView assetKey) + public override void LoadAsset(ulong requestId, BridgeAssetType assetType, BridgeStringView assetKey) { _ = assetType; _ = assetKey; _core.AssetLoaded(requestId, handle: 1, BridgeAssetStatus.Ok); } - public void SpawnEntity(ulong entityId, ulong prefabHandle, in BridgeTransform transform, uint flags) + public override void SpawnEntity(ulong entityId, ulong prefabHandle, in BridgeTransform transform, uint flags) { _ = entityId; _ = prefabHandle; @@ -39,19 +39,19 @@ public void SpawnEntity(ulong entityId, ulong prefabHandle, in BridgeTransform t _ = flags; } - public void SetTransform(ulong entityId, uint mask, in BridgeTransform transform) + public override void SetTransform(ulong entityId, uint mask, in BridgeTransform transform) { _ = entityId; _ = mask; _ = transform; } - public void DestroyEntity(ulong entityId) + public override void DestroyEntity(ulong entityId) { _ = entityId; } - public void Log(BridgeLogLevel level, BridgeStringView message) + public override void Log(BridgeLogLevel level, BridgeStringView message) { _ = level; _ = message; @@ -93,6 +93,7 @@ private static void RunThroughput(int bots) Debug.Log("BridgeSourceModeThroughputTests: start bots=" + bots); var cores = new BridgeCore[bots]; + var coreHandles = new IntPtr[bots]; var hosts = new NullHostApi[bots]; var streams = new CommandStream[bots]; @@ -100,12 +101,13 @@ private static void RunThroughput(int bots) { var core = new BridgeCore(seed: (ulong)(i + 1), robotMode: true); cores[i] = core; + coreHandles[i] = core.UnsafeHandle; hosts[i] = new NullHostApi(core); } try { - RunFrames(cores, hosts, streams, warmupFrames, dt, out _); + RunFrames(coreHandles, hosts, streams, warmupFrames, dt, out _); bool allocSupported = false; long allocBefore = 0; @@ -113,7 +115,7 @@ private static void RunThroughput(int bots) allocBefore = TryGetAllocatedBytesForCurrentThread(out allocSupported); #endif var sw = Stopwatch.StartNew(); - RunFrames(cores, hosts, streams, measureFrames, dt, out ulong totalBytes); + RunFrames(coreHandles, hosts, streams, measureFrames, dt, out ulong totalBytes); sw.Stop(); long allocAfter = 0; @@ -147,7 +149,7 @@ private static void RunThroughput(int bots) } private static void RunFrames( - BridgeCore[] cores, + IntPtr[] coreHandles, NullHostApi[] hosts, CommandStream[] streams, int frames, @@ -158,12 +160,12 @@ private static void RunFrames( for (int frame = 0; frame < frames; frame++) { - BridgeCore.TickManyAndGetCommandStreams(cores, dt, streams); - for (int i = 0; i < cores.Length; i++) + BridgeCore.TickManyAndGetCommandStreams(coreHandles, dt, streams); + for (int i = 0; i < coreHandles.Length; i++) { CommandStream stream = streams[i]; totalBytes += stream.Length; - BridgeAllCommandDispatcher.Dispatch(stream, hosts[i]); + BridgeAllCommandDispatcher.DispatchFast(stream, hosts[i]); } } } diff --git a/Tests/unity/Assets/BridgeDemoGame/Runtime/Host/DemoGameUnityHostApi.Asset.cs b/Tests/unity/Assets/BridgeDemoGame/Runtime/Host/DemoGameUnityHostApi.Asset.cs index 40bcfed..060c76e 100644 --- a/Tests/unity/Assets/BridgeDemoGame/Runtime/Host/DemoGameUnityHostApi.Asset.cs +++ b/Tests/unity/Assets/BridgeDemoGame/Runtime/Host/DemoGameUnityHostApi.Asset.cs @@ -3,9 +3,9 @@ namespace BridgeDemoGame { - public sealed partial class DemoGameUnityHostApi : IDemoAssetHostApi + public sealed partial class DemoGameUnityHostApi { - public void LoadAsset(ulong requestId, BridgeAssetType assetType, BridgeStringView assetKey) + public override void LoadAsset(ulong requestId, BridgeAssetType assetType, BridgeStringView assetKey) { Commands++; AssetRequests++; diff --git a/Tests/unity/Assets/BridgeDemoGame/Runtime/Host/DemoGameUnityHostApi.Entity.cs b/Tests/unity/Assets/BridgeDemoGame/Runtime/Host/DemoGameUnityHostApi.Entity.cs index 0d2e81c..9010206 100644 --- a/Tests/unity/Assets/BridgeDemoGame/Runtime/Host/DemoGameUnityHostApi.Entity.cs +++ b/Tests/unity/Assets/BridgeDemoGame/Runtime/Host/DemoGameUnityHostApi.Entity.cs @@ -4,9 +4,9 @@ namespace BridgeDemoGame { - public sealed partial class DemoGameUnityHostApi : IDemoEntityHostApi + public sealed partial class DemoGameUnityHostApi { - public void SpawnEntity(ulong entityId, ulong prefabHandle, in BridgeTransform transform, uint flags) + public override void SpawnEntity(ulong entityId, ulong prefabHandle, in BridgeTransform transform, uint flags) { _ = prefabHandle; _ = flags; @@ -29,7 +29,7 @@ public void SpawnEntity(ulong entityId, ulong prefabHandle, in BridgeTransform t _entities[entityId] = go; } - public void SetTransform(ulong entityId, uint mask, in BridgeTransform transform) + public override void SetTransform(ulong entityId, uint mask, in BridgeTransform transform) { Commands++; Transforms++; @@ -41,7 +41,7 @@ public void SetTransform(ulong entityId, uint mask, in BridgeTransform transform ApplyTransform(go.transform, transform, mask); } - public void DestroyEntity(ulong entityId) + public override void DestroyEntity(ulong entityId) { Commands++; Destroys++; diff --git a/Tests/unity/Assets/BridgeDemoGame/Runtime/Host/DemoGameUnityHostApi.Log.cs b/Tests/unity/Assets/BridgeDemoGame/Runtime/Host/DemoGameUnityHostApi.Log.cs index f6e9b36..63843bb 100644 --- a/Tests/unity/Assets/BridgeDemoGame/Runtime/Host/DemoGameUnityHostApi.Log.cs +++ b/Tests/unity/Assets/BridgeDemoGame/Runtime/Host/DemoGameUnityHostApi.Log.cs @@ -4,9 +4,9 @@ namespace BridgeDemoGame { - public sealed partial class DemoGameUnityHostApi: IDemoLogHostApi + public sealed partial class DemoGameUnityHostApi { - public void Log(BridgeLogLevel level, BridgeStringView message) + public override void Log(BridgeLogLevel level, BridgeStringView message) { Commands++; Logs++; diff --git a/Tests/unity/Assets/BridgeDemoGame/Runtime/Host/DemoGameUnityHostApi.cs b/Tests/unity/Assets/BridgeDemoGame/Runtime/Host/DemoGameUnityHostApi.cs index 7923496..5f382b3 100644 --- a/Tests/unity/Assets/BridgeDemoGame/Runtime/Host/DemoGameUnityHostApi.cs +++ b/Tests/unity/Assets/BridgeDemoGame/Runtime/Host/DemoGameUnityHostApi.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using Bridge.Bindings; using Bridge.Core; using DemoAsset.Bindings; using DemoEntity.Bindings; @@ -7,7 +8,7 @@ namespace BridgeDemoGame { - public sealed partial class DemoGameUnityHostApi + public sealed partial class DemoGameUnityHostApi : BridgeAllHostApiBase { private readonly BridgeCore _core; private readonly DemoGameUnityAssetService _assets; diff --git a/Tests/unity/Assets/BridgeDemoGame/Runtime/Runner/DemoGameUnityRunner.cs b/Tests/unity/Assets/BridgeDemoGame/Runtime/Runner/DemoGameUnityRunner.cs index 35e3ec6..1c66756 100644 --- a/Tests/unity/Assets/BridgeDemoGame/Runtime/Runner/DemoGameUnityRunner.cs +++ b/Tests/unity/Assets/BridgeDemoGame/Runtime/Runner/DemoGameUnityRunner.cs @@ -16,6 +16,7 @@ public sealed class DemoGameUnityRunner : MonoBehaviour public int MaxBotsWithRendering = 32; private BridgeCore[] _cores = Array.Empty(); + private IntPtr[] _coreHandles = Array.Empty(); private DemoGameUnityHostApi[] _hosts = Array.Empty(); private CommandStream[] _streams = Array.Empty(); private DemoGameUnityAssetService _assets; @@ -30,7 +31,9 @@ private void Awake() private void Start() { int bots = Mathf.Max(1, Bots); + BridgeCore.PrepareTickManyCache(bots); _cores = new BridgeCore[bots]; + _coreHandles = new IntPtr[bots]; _hosts = new DemoGameUnityHostApi[bots]; _streams = new CommandStream[bots]; @@ -39,6 +42,7 @@ private void Start() { var core = new BridgeCore(seed: (ulong)(i + 1), robotMode: RobotMode); _cores[i] = core; + _coreHandles[i] = core.UnsafeHandle; _hosts[i] = new DemoGameUnityHostApi(core, _assets, render); } } @@ -46,9 +50,15 @@ private void Start() private void Update() { float dt = Time.deltaTime; - BridgeCore.TickManyAndGetCommandStreams(_cores, dt, _streams); + BridgeCore.TickManyAndGetCommandStreams(_coreHandles, dt, _streams); for (int i = 0; i < _cores.Length; i++) + { +#if ENABLE_IL2CPP + BridgeAllCommandDispatcher.DispatchFast(_streams[i], _hosts[i]); +#else BridgeAllCommandDispatcher.Dispatch(_streams[i], _hosts[i]); +#endif + } } private void OnDestroy() @@ -58,6 +68,7 @@ private void OnDestroy() try { _cores[i].Dispose(); } catch { } } _cores = Array.Empty(); + _coreHandles = Array.Empty(); _hosts = Array.Empty(); _streams = Array.Empty(); } diff --git a/Tools/RunPerf.ps1 b/Tools/RunPerf.ps1 new file mode 100644 index 0000000..b0a0cae --- /dev/null +++ b/Tools/RunPerf.ps1 @@ -0,0 +1,655 @@ +param( + [int]$Bots = 1000, + [int]$Frames = 3000, + [double]$Dt = 0.0166667, + + [string]$OutFile = "", + [string]$Tag = "", + + [string]$UnityVersion = "", + [string]$UnityExe = "", + [switch]$NoUnity, + [switch]$NoUnityEditMode, + [switch]$NoUnityIl2cpp, + + [switch]$NoBuild +) + +Set-StrictMode -Version Latest + +$ErrorActionPreference = "Stop" + +try +{ + [Console]::OutputEncoding = [System.Text.Encoding]::UTF8 + $OutputEncoding = [System.Text.Encoding]::UTF8 +} +catch +{ +} + +function New-Dir([string]$Path) +{ + if ([string]::IsNullOrWhiteSpace($Path)) { return } + New-Item -ItemType Directory -Force -Path $Path | Out-Null +} + +function Wait-FileUpdated( + [string]$Path, + [DateTime]$NotBeforeUtc, + [int]$TimeoutSeconds = 600, + [int]$MinLength = 1 +) +{ + $deadline = [DateTime]::UtcNow.AddSeconds($TimeoutSeconds) + while ([DateTime]::UtcNow -lt $deadline) + { + if (Test-Path $Path) + { + try + { + $fi = Get-Item $Path + if ($fi.Length -ge $MinLength -and $fi.LastWriteTimeUtc -ge $NotBeforeUtc) + { + return $true + } + } + catch + { + } + } + Start-Sleep -Milliseconds 500 + } + return $false +} + +function Try-Get([scriptblock]$Thunk) +{ + try { return & $Thunk } catch { return $null } +} + +function Invoke-External( + [string]$Name, + [string]$FilePath, + [string[]]$ArgumentList, + [string]$WorkDir, + [string]$OutputFile +) +{ + $started = Get-Date + $exitCode = $null + try + { + Write-Host "==> $Name" + Push-Location $WorkDir + if (-not [string]::IsNullOrWhiteSpace($OutputFile)) + { + New-Dir (Split-Path -Parent $OutputFile) + if (Test-Path $OutputFile) { Remove-Item -Force $OutputFile } + & $FilePath @ArgumentList 2>&1 | Tee-Object -FilePath $OutputFile | Out-Host + } + else + { + & $FilePath @ArgumentList 2>&1 | Out-Host + } + $exitCode = $LASTEXITCODE + Pop-Location + Write-Host "<= $Name exitCode=$exitCode" + + return [ordered]@{ + ok = ($exitCode -eq 0) + name = $Name + file = $FilePath + args = $ArgumentList + workDir = $WorkDir + exitCode = $exitCode + startedUtc = $started.ToUniversalTime().ToString("o") + endedUtc = (Get-Date).ToUniversalTime().ToString("o") + outputFile = $OutputFile + } + } + catch + { + try { Pop-Location } catch { } + $err = $_.Exception.ToString() + if (-not [string]::IsNullOrWhiteSpace($OutputFile)) + { + Set-Content -Path $OutputFile -Value $err -Encoding UTF8 + } + return [ordered]@{ + ok = $false + name = $Name + file = $FilePath + args = $ArgumentList + workDir = $WorkDir + exitCode = $exitCode + startedUtc = $started.ToUniversalTime().ToString("o") + endedUtc = (Get-Date).ToUniversalTime().ToString("o") + outputFile = $OutputFile + error = $err + } + } +} + +function Find-UnityExe() +{ + if (-not [string]::IsNullOrWhiteSpace($UnityExe) -and (Test-Path $UnityExe)) + { + return (Resolve-Path $UnityExe).Path + } + + $hub = "C:\Program Files\Unity\Hub\Editor" + if (-not (Test-Path $hub)) + { + return $null + } + + $candidates = Get-ChildItem $hub -Directory | ForEach-Object { + $exe = Join-Path $_.FullName 'Editor\Unity.exe' + if (Test-Path $exe) + { + [ordered]@{ + version = $_.Name + exe = $exe + } + } + } | Where-Object { $_ -ne $null } + + if (-not $candidates -or $candidates.Count -eq 0) + { + return $null + } + + if (-not [string]::IsNullOrWhiteSpace($UnityVersion)) + { + $match = $candidates | Where-Object { $_.version -eq $UnityVersion } | Select-Object -First 1 + if ($match) { return $match.exe } + } + + $testHasIl2cpp = { + param([string]$unityExePath) + try + { + $editorDir = Split-Path -Parent $unityExePath # ...\\Editor + $variations = @( + Join-Path $editorDir "Data\\PlaybackEngines\\windowsstandalonesupport\\Variations" + Join-Path $editorDir "Data\\PlaybackEngines\\WindowsStandaloneSupport\\Variations" + ) + + foreach ($v in $variations) + { + if (Test-Path $v) + { + if (Test-Path (Join-Path $v "il2cpp")) { return $true } + $any = Get-ChildItem $v -Directory -ErrorAction SilentlyContinue | Where-Object { $_.Name -match "il2cpp" } | Select-Object -First 1 + if ($any) { return $true } + } + } + } + catch + { + } + return $false + } + + $preferred = $candidates | Where-Object { $_.version -eq "6000.0.40f1" } | Select-Object -First 1 + if ($preferred) + { + if ($NoUnityIl2cpp -or (& $testHasIl2cpp $preferred.exe)) + { + return $preferred.exe + } + } + + if (-not $NoUnityIl2cpp) + { + # Prefer an Editor that actually has Windows IL2CPP variations installed. + $withIl2cpp = $candidates | Where-Object { & $testHasIl2cpp $_.exe } | Sort-Object { $_.version } | Select-Object -Last 1 + if ($withIl2cpp) { return $withIl2cpp.exe } + } + + return (($candidates | Sort-Object { $_.version } | Select-Object -Last 1).exe) +} + +function Get-UnityIl2cppBuildFailureReason([string]$LogPath) +{ + if (-not (Test-Path $LogPath)) + { + return $null + } + + $tail = (Get-Content $LogPath -Tail 400) -join "`n" + if ([string]::IsNullOrWhiteSpace($tail)) + { + return $null + } + + if ($tail -like "*IL2CPP) is not installed*") + { + return "IL2CPP module is not installed (Unity Hub -> Install -> Windows Build Support (IL2CPP))." + } + + if ($tail -like "*Build Finished, Result: Failure*") + { + return "Unity player build failed (see build log)." + } + + if ($tail -like "*Error building Player*") + { + return "Unity error building player (see build log)." + } + + if ($tail -like "*Project has invalid dependencies:*") + { + return "Unity package resolution failed (Project has invalid dependencies; see build log)." + } + + return $null +} + +function Get-UnityProjectLockReason([string]$ConsoleOutputPath) +{ + if (-not (Test-Path $ConsoleOutputPath)) + { + return $null + } + + $text = Get-Content $ConsoleOutputPath -Raw + if ([string]::IsNullOrWhiteSpace($text)) + { + return $null + } + + if ($text -like "*another Unity instance is running with this project open*") + { + return "Unity project is already open (close the Editor instance for Tests/unity, or run on a separate project copy)." + } + + return $null +} + +function Parse-RobotHostOutput([string]$Text) +{ + $getInt = { + param([string]$pattern) + $m = [regex]::Match($Text, $pattern) + if ($m.Success) { return [long]$m.Groups[1].Value } + return $null + } + $getDouble = { + param([string]$pattern) + $m = [regex]::Match($Text, $pattern) + if ($m.Success) { return [double]$m.Groups[1].Value } + return $null + } + + return [ordered]@{ + elapsed_s = & $getDouble "\[all\] elapsed: ([0-9.]+) s" + alloc_bytes = & $getInt "\[all\] allocated \(thread\): (-?\d+) bytes" + total_commands = & $getInt "\[all\] total commands handled: (\d+)" + commands_per_s = & $getDouble "\[all\] commands/sec: (\d+)" + asset_requests = & $getInt "\[all\] total asset requests: (\d+)" + logs = & $getInt "\[all\] total logs: (\d+)" + spawns = & $getInt "\[all\] total spawns: (\d+)" + transforms = & $getInt "\[all\] total transforms: (\d+)" + destroys = & $getInt "\[all\] total destroys: (\d+)" + } +} + +function Parse-RobotRunnerOutput([string]$Text) +{ + $getInt = { + param([string]$pattern) + $m = [regex]::Match($Text, $pattern) + if ($m.Success) { return [long]$m.Groups[1].Value } + return $null + } + $getDouble = { + param([string]$pattern) + $m = [regex]::Match($Text, $pattern) + if ($m.Success) { return [double]$m.Groups[1].Value } + return $null + } + + return [ordered]@{ + elapsed_s = & $getDouble "elapsed: ([0-9.]+) s" + total_commands = & $getInt "total commands parsed: (\d+)" + commands_per_s = & $getDouble "commands/sec: (\d+)" + ticks = & $getInt "ticks: (\d+)" + asset_requests = & $getInt "total asset requests: (\d+)" + } +} + +function Parse-UnityEditModePerf([string]$PerfJsonPath) +{ + if (-not (Test-Path $PerfJsonPath)) + { + return $null + } + + $json = Get-Content $PerfJsonPath -Raw | ConvertFrom-Json + $results = @() + + foreach ($r in ($json.Results | Where-Object { $_ -ne $null })) + { + $time = $r.SampleGroups | Where-Object Name -eq "Time" | Select-Object -First 1 + $gc = $r.SampleGroups | Where-Object Name -eq "GC.Alloc.Bytes" | Select-Object -First 1 + + $results += [ordered]@{ + name = $r.Name + time_avg_ms = Try-Get { [double]$time.Average } + time_median_ms = Try-Get { [double]$time.Median } + gc_avg_bytes = Try-Get { [double]$gc.Average } + } + } + + return [ordered]@{ + testSuite = $json.TestSuite + editor = $json.Editor + hardware = $json.Hardware + results = $results + } +} + +function Parse-BridgePerfLog([string]$LogPath) +{ + if (-not (Test-Path $LogPath)) + { + return $null + } + + $lines = Get-Content $LogPath + $re = [regex]::new("##bridgeperf: mode=(\S+) ticks_per_sec=([0-9.]+) mib_per_sec=([0-9.]+) bots=(\d+) frames=(\d+) elapsed_ms=([0-9.]+) alloc_bytes=(-?\d+) total_bytes=(\d+)") + + $items = @{} + foreach ($line in $lines) + { + $m = $re.Match($line) + if (-not $m.Success) { continue } + + $bots = [int]$m.Groups[4].Value + if ($items.ContainsKey($bots)) { continue } + + $items[$bots] = [ordered]@{ + mode = $m.Groups[1].Value + ticks_per_s = [double]$m.Groups[2].Value + mib_per_s = [double]$m.Groups[3].Value + bots = $bots + frames = [int]$m.Groups[5].Value + elapsed_ms = [double]$m.Groups[6].Value + alloc_bytes = [long]$m.Groups[7].Value + total_bytes = [long]$m.Groups[8].Value + } + } + + return ($items.Values | Sort-Object bots) +} + +$repoRoot = (Resolve-Path (Join-Path $PSScriptRoot "..")).Path + +if ([string]::IsNullOrWhiteSpace($OutFile)) +{ + $OutFile = Join-Path $repoRoot "build\\perf_history.jsonl" +} + +$runId = (Get-Date -Format "yyyyMMdd_HHmmss") +$runDir = Join-Path $repoRoot ("build\\perf_runs\\$runId") +New-Dir $runDir +New-Dir (Split-Path $OutFile) + +Write-Host "RunId: $runId" +Write-Host "RunDir: $runDir" +Write-Host "OutFile: $OutFile" + +$git = $null +if (Get-Command git -ErrorAction SilentlyContinue) +{ + try + { + Push-Location $repoRoot + $commit = (& git rev-parse HEAD 2>$null).Trim() + $branch = (& git rev-parse --abbrev-ref HEAD 2>$null).Trim() + $dirty = ((& git status --porcelain 2>$null) | Measure-Object).Count -gt 0 + Pop-Location + $git = [ordered]@{ commit = $commit; branch = $branch; dirty = $dirty } + } + catch + { + try { Pop-Location } catch { } + } +} + +$machine = [ordered]@{ + computerName = $env:COMPUTERNAME + osVersion = [System.Environment]::OSVersion.VersionString + dotnet = Try-Get { (& dotnet --version 2>$null).Trim() } + cmake = Try-Get { ((& cmake --version 2>$null) | Select-Object -First 1).Trim() } + cpu = Try-Get { (Get-CimInstance Win32_Processor | Select-Object -First 1 -ExpandProperty Name).Trim() } +} + +$steps = [ordered]@{} +$results = [ordered]@{} + +if (-not $NoBuild) +{ + if (-not (Test-Path (Join-Path $repoRoot "build\\CMakeCache.txt"))) + { + $steps.cmake_configure = Invoke-External ` + -Name "cmake_configure" ` + -FilePath "cmake" ` + -ArgumentList @("-S", ".", "-B", "build", "-DCMAKE_BUILD_TYPE=Release") ` + -WorkDir $repoRoot ` + -OutputFile (Join-Path $runDir "cmake_configure.log") + } + + $steps.cmake_build = Invoke-External ` + -Name "cmake_build" ` + -FilePath "cmake" ` + -ArgumentList @("--build", "build", "--config", "Release") ` + -WorkDir $repoRoot ` + -OutputFile (Join-Path $runDir "cmake_build.log") + + $steps.dotnet_build_bridgecore = Invoke-External ` + -Name "dotnet_build_bridgecore" ` + -FilePath "dotnet" ` + -ArgumentList @("build", "Core\\csharp\\Bridge.Core\\Bridge.Core.csproj", "-c", "Release") ` + -WorkDir $repoRoot ` + -OutputFile (Join-Path $runDir "dotnet_build_bridgecore.log") + + $steps.dotnet_build_robothost = Invoke-External ` + -Name "dotnet_build_robothost" ` + -FilePath "dotnet" ` + -ArgumentList @("build", "Tests\\csharp\\RobotHost\\RobotHost.csproj", "-c", "Release") ` + -WorkDir $repoRoot ` + -OutputFile (Join-Path $runDir "dotnet_build_robothost.log") +} + +$steps.robothost_null = Invoke-External ` + -Name "robothost_null" ` + -FilePath "dotnet" ` + -ArgumentList @("run", "--project", "Tests\\csharp\\RobotHost\\RobotHost.csproj", "-c", "Release", "--", "$Bots", "$Frames", "$Dt", "--host", "null") ` + -WorkDir $repoRoot ` + -OutputFile (Join-Path $runDir "robothost_null.txt") + +if ($steps.robothost_null.ok) +{ + $results.robothost_null = Parse-RobotHostOutput (Get-Content (Join-Path $runDir "robothost_null.txt") -Raw) +} + +$steps.robothost_full = Invoke-External ` + -Name "robothost_full" ` + -FilePath "dotnet" ` + -ArgumentList @("run", "--project", "Tests\\csharp\\RobotHost\\RobotHost.csproj", "-c", "Release", "--", "$Bots", "$Frames", "$Dt", "--host", "full") ` + -WorkDir $repoRoot ` + -OutputFile (Join-Path $runDir "robothost_full.txt") + +if ($steps.robothost_full.ok) +{ + $results.robothost_full = Parse-RobotHostOutput (Get-Content (Join-Path $runDir "robothost_full.txt") -Raw) +} + +$robotExe = Join-Path $repoRoot "build\\bin\\Release\\bridge_robot_runner.exe" +if (Test-Path $robotExe) +{ + $steps.robot_runner = Invoke-External ` + -Name "robot_runner" ` + -FilePath $robotExe ` + -ArgumentList @("$Bots", "$Frames", "$Dt") ` + -WorkDir $repoRoot ` + -OutputFile (Join-Path $runDir "robot_runner.txt") + + if ($steps.robot_runner.ok) + { + $results.robot_runner = Parse-RobotRunnerOutput (Get-Content (Join-Path $runDir "robot_runner.txt") -Raw) + } +} +else +{ + $steps.robot_runner = [ordered]@{ ok = $false; error = "missing: $robotExe" } +} + +$unity = $null +if (-not $NoUnity) +{ + $unity = Find-UnityExe + if (-not $unity) + { + $steps.unity = [ordered]@{ ok = $false; error = "Unity.exe not found. Pass -UnityExe or install via Unity Hub." } + } + else + { + Write-Host "Unity: $unity" + } +} + +if ($unity -and -not $NoUnityEditMode) +{ + $proj = Join-Path $repoRoot "Tests\\unity" + $unityEditModeXml = Join-Path $runDir "unity-editmode-test-results.xml" + $unityEditModePerf = Join-Path $runDir "unity-editmode-perf-results.json" + $unityEditModeLog = Join-Path $runDir "unity-editmode-test.log" + + $steps.unity_editmode = Invoke-External ` + -Name "unity_editmode" ` + -FilePath $unity ` + -ArgumentList @("-runTests", "-batchmode", "-nographics", "-projectPath", $proj, "-testPlatform", "EditMode", "-testResults", $unityEditModeXml, "-perfTestResults", $unityEditModePerf, "-logFile", $unityEditModeLog) ` + -WorkDir $repoRoot ` + -OutputFile (Join-Path $runDir "unity_editmode_console.txt") + + if ($steps.unity_editmode.ok) + { + $startedUtc = [DateTime]::Parse($steps.unity_editmode.startedUtc).ToUniversalTime() + if (Wait-FileUpdated -Path $unityEditModePerf -NotBeforeUtc $startedUtc -TimeoutSeconds 1800 -MinLength 32) + { + $results.unity_editmode = Parse-UnityEditModePerf $unityEditModePerf + } + else + { + $results.unity_editmode = [ordered]@{ + error = "unity editmode perf results not produced in time" + perfJson = $unityEditModePerf + } + } + } + else + { + $lock = Get-UnityProjectLockReason -ConsoleOutputPath $steps.unity_editmode.outputFile + if ($lock) + { + $steps.unity_editmode.error = $lock + $results.unity_editmode = [ordered]@{ error = $lock } + } + } +} + +if ($unity -and -not $NoUnityIl2cpp) +{ + $proj = Join-Path $repoRoot "Tests\\unity" + $rutttDir = Join-Path $runDir "ruttt_il2cpp_source" + New-Dir $rutttDir + $rutttExe = Join-Path $rutttDir "test.exe" + $rutttBuildLog = Join-Path $rutttDir "build.log" + $rutttRunLog = Join-Path $rutttDir "run.log" + + $steps.unity_ruttt_build_il2cpp = Invoke-External ` + -Name "unity_ruttt_build_il2cpp" ` + -FilePath $unity ` + -ArgumentList @("-quit", "-batchmode", "-nographics", "-projectPath", $proj, "-executeMethod", "Bridge.Core.Unity.Editor.BridgeCoreRuntimeUnitTestBuild.BuildUnitTest", "/ScriptBackend", "IL2CPP", "/BuildTarget", "StandaloneWindows64", "/buildPath", $rutttExe, "-logFile", $rutttBuildLog) ` + -WorkDir $repoRoot ` + -OutputFile (Join-Path $rutttDir "unity_build_console.txt") + + $lock = Get-UnityProjectLockReason -ConsoleOutputPath $steps.unity_ruttt_build_il2cpp.outputFile + + $reason = Get-UnityIl2cppBuildFailureReason -LogPath $rutttBuildLog + $exeReady = (Test-Path $rutttExe) -and ((Get-Item $rutttExe).Length -ge 1024) + + if ($lock) + { + $steps.unity_ruttt_build_il2cpp.ok = $false + $steps.unity_ruttt_build_il2cpp.error = $lock + } + elseif ($reason) + { + $steps.unity_ruttt_build_il2cpp.ok = $false + $steps.unity_ruttt_build_il2cpp.error = $reason + } + elseif (-not $exeReady) + { + # Unity sometimes returns exitCode=0 even on build failure; treat missing exe as failure. + $steps.unity_ruttt_build_il2cpp.ok = $false + $steps.unity_ruttt_build_il2cpp.error = "unity il2cpp test.exe not produced (see build log)." + } + + if ($steps.unity_ruttt_build_il2cpp.ok) + { + $steps.unity_ruttt_run_il2cpp = Invoke-External ` + -Name "unity_ruttt_run_il2cpp" ` + -FilePath $rutttExe ` + -ArgumentList @("-batchmode", "-nographics", "-logFile", $rutttRunLog) ` + -WorkDir $rutttDir ` + -OutputFile (Join-Path $rutttDir "player_console.txt") + + if ($steps.unity_ruttt_run_il2cpp.ok) + { + $runStartedUtc = Try-Get { [DateTime]::Parse($steps.unity_ruttt_run_il2cpp.startedUtc).ToUniversalTime() } + if ($runStartedUtc -and (Wait-FileUpdated -Path $rutttRunLog -NotBeforeUtc $runStartedUtc -TimeoutSeconds 1800 -MinLength 256)) + { + $results.unity_il2cpp_source = Parse-BridgePerfLog $rutttRunLog + } + else + { + $results.unity_il2cpp_source = [ordered]@{ + error = "unity il2cpp run.log not produced in time" + runLog = $rutttRunLog + } + } + } + } + else + { + $err = Try-Get { [string]$steps.unity_ruttt_build_il2cpp.error } + if ([string]::IsNullOrWhiteSpace($err)) { $err = "unity il2cpp build failed" } + $results.unity_il2cpp_source = [ordered]@{ + error = $err + exe = $rutttExe + log = $rutttBuildLog + } + } +} + +$record = [ordered]@{ + tsUtc = (Get-Date).ToUniversalTime().ToString("o") + runId = $runId + tag = $Tag + git = $git + machine = $machine + params = [ordered]@{ bots = $Bots; frames = $Frames; dt = $Dt } + runDir = $runDir + steps = $steps + results = $results +} + +$line = $record | ConvertTo-Json -Depth 32 -Compress +Add-Content -Path $OutFile -Value $line -Encoding UTF8 + +Write-Host "Appended: $OutFile" From 23e79d6453ceb813f2c2978364a51fc3f6217078 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=A2=81=E9=93=96?= <> Date: Wed, 21 Jan 2026 17:45:10 +0800 Subject: [PATCH 13/33] =?UTF-8?q?perf:=20IL2CPP=20TickMany=20=E5=86=99?= =?UTF-8?q?=E5=85=A5=E4=BC=98=E5=8C=96=E4=B8=8E=20DispatchFast=20=E7=A9=BA?= =?UTF-8?q?=E6=B5=81=E6=A3=80=E6=9F=A5=E5=86=85=E8=81=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Core/Tools/BridgeGen/Program.cs | 2 +- Core/csharp/Bridge.Core/BridgeCore.cs | 48 +++++++++++-------- .../Runtime/Bridge.Core/BridgeCore.cs | 48 +++++++++++-------- .../Bridge.AllCommandDispatcher.g.cs | 26 +++++----- .../Bridge.AllCommandDispatcher.g.cs | 26 +++++----- 5 files changed, 83 insertions(+), 67 deletions(-) diff --git a/Core/Tools/BridgeGen/Program.cs b/Core/Tools/BridgeGen/Program.cs index 3b9ec91..9519fc4 100644 --- a/Core/Tools/BridgeGen/Program.cs +++ b/Core/Tools/BridgeGen/Program.cs @@ -517,7 +517,7 @@ private static string EmitAllDispatcher(IReadOnlyList modules) sb.AppendLine(" {"); sb.AppendLine(" public static unsafe void DispatchFast(CommandStream stream, BridgeAllHostApiBase host)"); sb.AppendLine(" {"); - sb.AppendLine(" if (stream.IsEmpty || host == null)"); + sb.AppendLine(" if (host == null || stream.Ptr == System.IntPtr.Zero || stream.Length == 0)"); sb.AppendLine(" return;"); sb.AppendLine(); sb.AppendLine(" byte* cursor = (byte*)stream.Ptr;"); diff --git a/Core/csharp/Bridge.Core/BridgeCore.cs b/Core/csharp/Bridge.Core/BridgeCore.cs index c0ed571..06a26be 100644 --- a/Core/csharp/Bridge.Core/BridgeCore.cs +++ b/Core/csharp/Bridge.Core/BridgeCore.cs @@ -102,11 +102,14 @@ public static unsafe void TickManyAndGetCommandStreams(BridgeCore[] cores, float if (result != BridgeResult.Ok) throw new InvalidOperationException($"BridgeCore_TickManyAndGetCommandStreams failed: {result}"); - for (int i = 0; i < count; i++) + fixed (CommandStream* dst = streams) { - IntPtr ptr = outPtrs[i]; - uint len = outLens[i]; - streams[i] = (ptr == IntPtr.Zero || len == 0) ? CommandStream.Empty : new CommandStream(ptr, len); + for (int i = 0; i < count; i++) + { + IntPtr ptr = outPtrs[i]; + uint len = outLens[i]; + dst[i] = (ptr == IntPtr.Zero || len == 0) ? default : new CommandStream(ptr, len); + } } } else @@ -127,17 +130,18 @@ public static unsafe void TickManyAndGetCommandStreams(BridgeCore[] cores, float fixed (IntPtr* corePtrs = corePtrsManaged) fixed (IntPtr* outPtrs = outPtrsManaged) fixed (uint* outLens = outLensManaged) + fixed (CommandStream* dst = streams) { var result = BridgeNative.BridgeCore_TickManyAndGetCommandStreams(corePtrs, (uint)count, dt, outPtrs, outLens); if (result != BridgeResult.Ok) throw new InvalidOperationException($"BridgeCore_TickManyAndGetCommandStreams failed: {result}"); - } - for (int i = 0; i < count; i++) - { - IntPtr ptr = outPtrsManaged[i]; - uint len = outLensManaged[i]; - streams[i] = (ptr == IntPtr.Zero || len == 0) ? CommandStream.Empty : new CommandStream(ptr, len); + for (int i = 0; i < count; i++) + { + IntPtr ptr = outPtrs[i]; + uint len = outLens[i]; + dst[i] = (ptr == IntPtr.Zero || len == 0) ? default : new CommandStream(ptr, len); + } } } } @@ -166,11 +170,14 @@ public static unsafe void TickManyAndGetCommandStreams(IntPtr[] coreHandles, flo if (result != BridgeResult.Ok) throw new InvalidOperationException($"BridgeCore_TickManyAndGetCommandStreams failed: {result}"); - for (int i = 0; i < count; i++) + fixed (CommandStream* dst = streams) { - IntPtr ptr = outPtrs[i]; - uint len = outLens[i]; - streams[i] = (ptr == IntPtr.Zero || len == 0) ? CommandStream.Empty : new CommandStream(ptr, len); + for (int i = 0; i < count; i++) + { + IntPtr ptr = outPtrs[i]; + uint len = outLens[i]; + dst[i] = (ptr == IntPtr.Zero || len == 0) ? default : new CommandStream(ptr, len); + } } } } @@ -184,17 +191,18 @@ public static unsafe void TickManyAndGetCommandStreams(IntPtr[] coreHandles, flo fixed (IntPtr* corePtrs = coreHandles) fixed (IntPtr* outPtrs = outPtrsManaged) fixed (uint* outLens = outLensManaged) + fixed (CommandStream* dst = streams) { var result = BridgeNative.BridgeCore_TickManyAndGetCommandStreams(corePtrs, (uint)count, dt, outPtrs, outLens); if (result != BridgeResult.Ok) throw new InvalidOperationException($"BridgeCore_TickManyAndGetCommandStreams failed: {result}"); - } - for (int i = 0; i < count; i++) - { - IntPtr ptr = outPtrsManaged[i]; - uint len = outLensManaged[i]; - streams[i] = (ptr == IntPtr.Zero || len == 0) ? CommandStream.Empty : new CommandStream(ptr, len); + for (int i = 0; i < count; i++) + { + IntPtr ptr = outPtrs[i]; + uint len = outLens[i]; + dst[i] = (ptr == IntPtr.Zero || len == 0) ? default : new CommandStream(ptr, len); + } } } } diff --git a/Packages/com.unitynativescripting.bridgecore/Runtime/Bridge.Core/BridgeCore.cs b/Packages/com.unitynativescripting.bridgecore/Runtime/Bridge.Core/BridgeCore.cs index 594ad29..1c82fee 100644 --- a/Packages/com.unitynativescripting.bridgecore/Runtime/Bridge.Core/BridgeCore.cs +++ b/Packages/com.unitynativescripting.bridgecore/Runtime/Bridge.Core/BridgeCore.cs @@ -108,11 +108,14 @@ public static unsafe void TickManyAndGetCommandStreams(BridgeCore[] cores, float if (result != BridgeResult.Ok) throw new InvalidOperationException($"BridgeCore_TickManyAndGetCommandStreams failed: {result}"); - for (int i = 0; i < count; i++) + fixed (CommandStream* dst = streams) { - IntPtr ptr = outPtrs[i]; - uint len = outLens[i]; - streams[i] = (ptr == IntPtr.Zero || len == 0) ? CommandStream.Empty : new CommandStream(ptr, len); + for (int i = 0; i < count; i++) + { + IntPtr ptr = outPtrs[i]; + uint len = outLens[i]; + dst[i] = (ptr == IntPtr.Zero || len == 0) ? default : new CommandStream(ptr, len); + } } } else @@ -133,17 +136,18 @@ public static unsafe void TickManyAndGetCommandStreams(BridgeCore[] cores, float fixed (IntPtr* corePtrs = corePtrsManaged) fixed (IntPtr* outPtrs = outPtrsManaged) fixed (uint* outLens = outLensManaged) + fixed (CommandStream* dst = streams) { var result = BridgeNative.BridgeCore_TickManyAndGetCommandStreams(corePtrs, (uint)count, dt, outPtrs, outLens); if (result != BridgeResult.Ok) throw new InvalidOperationException($"BridgeCore_TickManyAndGetCommandStreams failed: {result}"); - } - for (int i = 0; i < count; i++) - { - IntPtr ptr = outPtrsManaged[i]; - uint len = outLensManaged[i]; - streams[i] = (ptr == IntPtr.Zero || len == 0) ? CommandStream.Empty : new CommandStream(ptr, len); + for (int i = 0; i < count; i++) + { + IntPtr ptr = outPtrs[i]; + uint len = outLens[i]; + dst[i] = (ptr == IntPtr.Zero || len == 0) ? default : new CommandStream(ptr, len); + } } } } @@ -172,11 +176,14 @@ public static unsafe void TickManyAndGetCommandStreams(IntPtr[] coreHandles, flo if (result != BridgeResult.Ok) throw new InvalidOperationException($"BridgeCore_TickManyAndGetCommandStreams failed: {result}"); - for (int i = 0; i < count; i++) + fixed (CommandStream* dst = streams) { - IntPtr ptr = outPtrs[i]; - uint len = outLens[i]; - streams[i] = (ptr == IntPtr.Zero || len == 0) ? CommandStream.Empty : new CommandStream(ptr, len); + for (int i = 0; i < count; i++) + { + IntPtr ptr = outPtrs[i]; + uint len = outLens[i]; + dst[i] = (ptr == IntPtr.Zero || len == 0) ? default : new CommandStream(ptr, len); + } } } } @@ -190,17 +197,18 @@ public static unsafe void TickManyAndGetCommandStreams(IntPtr[] coreHandles, flo fixed (IntPtr* corePtrs = coreHandles) fixed (IntPtr* outPtrs = outPtrsManaged) fixed (uint* outLens = outLensManaged) + fixed (CommandStream* dst = streams) { var result = BridgeNative.BridgeCore_TickManyAndGetCommandStreams(corePtrs, (uint)count, dt, outPtrs, outLens); if (result != BridgeResult.Ok) throw new InvalidOperationException($"BridgeCore_TickManyAndGetCommandStreams failed: {result}"); - } - for (int i = 0; i < count; i++) - { - IntPtr ptr = outPtrsManaged[i]; - uint len = outLensManaged[i]; - streams[i] = (ptr == IntPtr.Zero || len == 0) ? CommandStream.Empty : new CommandStream(ptr, len); + for (int i = 0; i < count; i++) + { + IntPtr ptr = outPtrs[i]; + uint len = outLens[i]; + dst[i] = (ptr == IntPtr.Zero || len == 0) ? default : new CommandStream(ptr, len); + } } } } diff --git a/Tests/csharp/RobotHost/Generated/Bridge.AllCommandDispatcher.g.cs b/Tests/csharp/RobotHost/Generated/Bridge.AllCommandDispatcher.g.cs index 384659d..821e617 100644 --- a/Tests/csharp/RobotHost/Generated/Bridge.AllCommandDispatcher.g.cs +++ b/Tests/csharp/RobotHost/Generated/Bridge.AllCommandDispatcher.g.cs @@ -26,17 +26,17 @@ public static class BridgeAllCommandDispatcher { public static unsafe void DispatchFast(CommandStream stream, BridgeAllHostApiBase host) { - if (stream.IsEmpty || host == null) + if (host == null || stream.Ptr == System.IntPtr.Zero || stream.Length == 0) return; byte* cursor = (byte*)stream.Ptr; byte* end = cursor + (int)stream.Length; - while (cursor < end) - { - int remaining = (int)(end - cursor); - if (remaining < (int)sizeof(BridgeCommandHeader)) - break; + while (cursor < end) + { + int remaining = (int)(end - cursor); + if (remaining < (int)sizeof(BridgeCommandHeader)) + break; var header = (BridgeCommandHeader*)cursor; int size = header->Size; @@ -102,13 +102,13 @@ public static unsafe void DispatchFast(CommandStream stream, BridgeAllHostApiBas } } - cursor += size; - } - } - - public static unsafe void Dispatch(CommandStream stream, THost host) - where THost : class, DemoAsset.Bindings.IDemoAssetHostApi, DemoEntity.Bindings.IDemoEntityHostApi, DemoLog.Bindings.IDemoLogHostApi - { + cursor += size; + } + } + + public static unsafe void Dispatch(CommandStream stream, THost host) + where THost : class, DemoAsset.Bindings.IDemoAssetHostApi, DemoEntity.Bindings.IDemoEntityHostApi, DemoLog.Bindings.IDemoLogHostApi + { if (stream.IsEmpty || host == null) return; diff --git a/Tests/unity/Assets/BridgeDemoGame/Generated/Bridge.AllCommandDispatcher.g.cs b/Tests/unity/Assets/BridgeDemoGame/Generated/Bridge.AllCommandDispatcher.g.cs index 384659d..821e617 100644 --- a/Tests/unity/Assets/BridgeDemoGame/Generated/Bridge.AllCommandDispatcher.g.cs +++ b/Tests/unity/Assets/BridgeDemoGame/Generated/Bridge.AllCommandDispatcher.g.cs @@ -26,17 +26,17 @@ public static class BridgeAllCommandDispatcher { public static unsafe void DispatchFast(CommandStream stream, BridgeAllHostApiBase host) { - if (stream.IsEmpty || host == null) + if (host == null || stream.Ptr == System.IntPtr.Zero || stream.Length == 0) return; byte* cursor = (byte*)stream.Ptr; byte* end = cursor + (int)stream.Length; - while (cursor < end) - { - int remaining = (int)(end - cursor); - if (remaining < (int)sizeof(BridgeCommandHeader)) - break; + while (cursor < end) + { + int remaining = (int)(end - cursor); + if (remaining < (int)sizeof(BridgeCommandHeader)) + break; var header = (BridgeCommandHeader*)cursor; int size = header->Size; @@ -102,13 +102,13 @@ public static unsafe void DispatchFast(CommandStream stream, BridgeAllHostApiBas } } - cursor += size; - } - } - - public static unsafe void Dispatch(CommandStream stream, THost host) - where THost : class, DemoAsset.Bindings.IDemoAssetHostApi, DemoEntity.Bindings.IDemoEntityHostApi, DemoLog.Bindings.IDemoLogHostApi - { + cursor += size; + } + } + + public static unsafe void Dispatch(CommandStream stream, THost host) + where THost : class, DemoAsset.Bindings.IDemoAssetHostApi, DemoEntity.Bindings.IDemoEntityHostApi, DemoLog.Bindings.IDemoLogHostApi + { if (stream.IsEmpty || host == null) return; From 229898bd5f7d2b44525b15d3a5e7612ebab389cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=A2=81=E9=93=96?= <> Date: Wed, 21 Jan 2026 17:51:05 +0800 Subject: [PATCH 14/33] =?UTF-8?q?perf:=20RunPerf=20=E8=BF=BD=E5=8A=A0?= =?UTF-8?q?=E5=86=99=E5=85=A5=20README=20=E6=91=98=E8=A6=81=E8=A1=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 10 ++++ Tools/RunPerf.ps1 | 122 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 132 insertions(+) diff --git a/README.md b/README.md index a2e4080..a2b84a8 100644 --- a/README.md +++ b/README.md @@ -73,3 +73,13 @@ powershell -ExecutionPolicy Bypass -File Tools/RunPerf.ps1 -Bots 1000 -Frames 30 - 单次 run 的日志/产物:`build/perf_runs//` - 可选:`-NoUnity` / `-NoUnityEditMode` / `-NoUnityIl2cpp` / `-NoBuild` - 可选:`-UnityVersion 6000.0.40f1` 或 `-UnityExe ` 用于指定 Unity 版本/路径 + +### 性能摘要(自动追加) + +下表由 `Tools/RunPerf.ps1` 自动追加(更完整的数据仍以 `build/perf_history.jsonl` 为准)。 + + +| tsUtc | runId | tag | git | robothost_null cmd/s | robot_runner cmd/s | il2cpp_source 1k ticks/s | il2cpp_source 10k ticks/s | +|---|---|---|---|---:|---:|---:|---:| + + diff --git a/Tools/RunPerf.ps1 b/Tools/RunPerf.ps1 index b0a0cae..e75a022 100644 --- a/Tools/RunPerf.ps1 +++ b/Tools/RunPerf.ps1 @@ -6,6 +6,9 @@ param( [string]$OutFile = "", [string]$Tag = "", + [switch]$NoReadme, + [string]$ReadmeFile = "", + [string]$UnityVersion = "", [string]$UnityExe = "", [switch]$NoUnity, @@ -385,6 +388,99 @@ function Parse-BridgePerfLog([string]$LogPath) return ($items.Values | Sort-Object bots) } +function Update-PerfReadme( + [string]$ReadmePath, + $Record +) +{ + if ([string]::IsNullOrWhiteSpace($ReadmePath)) + { + return + } + + if (-not (Test-Path $ReadmePath)) + { + return + } + + $text = Get-Content $ReadmePath -Raw + $nl = if ($text.Contains("`r`n")) { "`r`n" } else { "`n" } + + $start = "" + $end = "" + + if (-not $text.Contains($start) -or -not $text.Contains($end)) + { + $section = @( + "### 性能摘要(自动追加)", + "", + "下表由 `Tools/RunPerf.ps1` 自动追加(更完整的数据仍以 `build/perf_history.jsonl` 为准)。", + "", + $start, + "| tsUtc | runId | tag | git | robothost_null cmd/s | robot_runner cmd/s | il2cpp_source 1k ticks/s | il2cpp_source 10k ticks/s |", + "|---|---|---|---|---:|---:|---:|---:|", + $end, + "" + ) -join $nl + + $text = $text.TrimEnd() + ($nl + $nl) + $section + } + + $runId = Try-Get { [string]$Record.runId } + if ([string]::IsNullOrWhiteSpace($runId)) + { + return + } + + if ($text -match [regex]::Escape("| $runId |")) + { + return + } + + $tsUtc = Try-Get { [string]$Record.tsUtc } + if ([string]::IsNullOrWhiteSpace($tsUtc)) { $tsUtc = (Get-Date).ToUniversalTime().ToString("o") } + + $tag = Try-Get { [string]$Record.tag } + $commit = Try-Get { [string]$Record.git.commit } + if (-not [string]::IsNullOrWhiteSpace($commit) -and $commit.Length -gt 7) { $commit = $commit.Substring(0, 7) } + $dirty = Try-Get { [bool]$Record.git.dirty } + if ($dirty) { $commit = "$commit*" } + + $rhNull = Try-Get { [double]$Record.results.robothost_null.commands_per_s } + $rr = Try-Get { [double]$Record.results.robot_runner.commands_per_s } + + $il2 = Try-Get { $Record.results.unity_il2cpp_source } + $il2_1k = $null + $il2_10k = $null + try + { + if ($il2 -is [System.Array]) + { + $il2_1k = ($il2 | Where-Object bots -eq 1000 | Select-Object -First 1).ticks_per_s + $il2_10k = ($il2 | Where-Object bots -eq 10000 | Select-Object -First 1).ticks_per_s + } + } + catch + { + } + + $fmt0 = { param($v) if ($null -eq $v) { "n/a" } else { "{0:0}" -f $v } } + $fmt2 = { param($v) if ($null -eq $v) { "n/a" } else { "{0:0.00}" -f $v } } + + $row = @( + "| $tsUtc | $runId | $tag | $commit |", + " $(& $fmt0 $rhNull) |", + " $(& $fmt0 $rr) |", + " $(& $fmt2 $il2_1k) |", + " $(& $fmt2 $il2_10k) |" + ) -join "" + + $replacement = $row + $nl + $end + $text = [regex]::Replace($text, [regex]::Escape($end), [System.Text.RegularExpressions.MatchEvaluator]{ param($m) $replacement }, 1) + + Set-Content -Path $ReadmePath -Value $text -Encoding UTF8 +} + $repoRoot = (Resolve-Path (Join-Path $PSScriptRoot "..")).Path if ([string]::IsNullOrWhiteSpace($OutFile)) @@ -392,6 +488,19 @@ if ([string]::IsNullOrWhiteSpace($OutFile)) $OutFile = Join-Path $repoRoot "build\\perf_history.jsonl" } +$readmePath = $null +if (-not $NoReadme) +{ + if ([string]::IsNullOrWhiteSpace($ReadmeFile)) + { + $readmePath = Join-Path $repoRoot "README.md" + } + else + { + $readmePath = (Resolve-Path $ReadmeFile).Path + } +} + $runId = (Get-Date -Format "yyyyMMdd_HHmmss") $runDir = Join-Path $repoRoot ("build\\perf_runs\\$runId") New-Dir $runDir @@ -653,3 +762,16 @@ $line = $record | ConvertTo-Json -Depth 32 -Compress Add-Content -Path $OutFile -Value $line -Encoding UTF8 Write-Host "Appended: $OutFile" + +if ($readmePath) +{ + try + { + Update-PerfReadme -ReadmePath $readmePath -Record $record + Write-Host "Updated: $readmePath" + } + catch + { + Write-Warning ("Failed to update README perf table: " + $_.Exception.Message) + } +} From ccc6c1be00c6a0a3191b3ca57f6826d6dc2d6c30 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=A2=81=E9=93=96?= <> Date: Wed, 21 Jan 2026 18:08:23 +0800 Subject: [PATCH 15/33] =?UTF-8?q?perf:=20RunPerf=20=E5=9B=9E=E5=A1=AB/?= =?UTF-8?q?=E9=87=8D=E5=BB=BA=20README=20=E6=80=A7=E8=83=BD=E8=A1=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 19 +++++- Tools/RunPerf.ps1 | 147 ++++++++++++++++++++++++++++++++-------------- 2 files changed, 120 insertions(+), 46 deletions(-) diff --git a/README.md b/README.md index a2b84a8..7c1d20c 100644 --- a/README.md +++ b/README.md @@ -78,8 +78,21 @@ powershell -ExecutionPolicy Bypass -File Tools/RunPerf.ps1 -Bots 1000 -Frames 30 下表由 `Tools/RunPerf.ps1` 自动追加(更完整的数据仍以 `build/perf_history.jsonl` 为准)。 - -| tsUtc | runId | tag | git | robothost_null cmd/s | robot_runner cmd/s | il2cpp_source 1k ticks/s | il2cpp_source 10k ticks/s | -|---|---|---|---|---:|---:|---:|---:| + +| tsUtc | runId | tag | git | robothost_null cmd/s | robot_runner cmd/s | il2cpp_source 1k ticks/s | il2cpp_source 10k ticks/s | +|---|---|---|---|---:|---:|---:|---:| +| 2026-01-21T09:50:23.6962380Z | 20260121_175019 | readme_table_test | 23e79d6* | 53571 | 2000000 | n/a | n/a | +| 2026-01-21T09:46:22.1895560Z | 20260121_174537 | post_23e79d6 | 23e79d6 | 23447208 | 58632532 | 50646588.11 | 32289520.76 | +| 2026-01-21T09:41:02.1140619Z | 20260121_174007 | il2cpp_opt4_revert_typed | 46c54af* | 24891834 | 56602493 | 50043370.92 | 31107456.56 | +| 2026-01-21T09:37:31.9048310Z | 20260121_173649 | il2cpp_opt4_rerun | 46c54af* | 25635026 | 61322383 | 48721863.12 | 31246354.59 | +| 2026-01-21T09:34:52.0737234Z | 20260121_173358 | il2cpp_opt4_typed_fix | 46c54af* | 24150548 | 60397744 | 49961696.03 | 29169514.75 | +| 2026-01-21T09:33:07.3524273Z | 20260121_173240 | il2cpp_opt4_typed | 46c54af* | 25081209 | 58809475 | n/a | n/a | +| 2026-01-21T09:18:09.6002287Z | 20260121_161722 | | 71d7614* | 24554530 | 60572076 | n/a | n/a | +| 2026-01-21T09:17:51.7355502Z | 20260121_171649 | il2cpp_opt3_gen | 46c54af* | 25158498 | 55715319 | 46472000.62 | 31124464.66 | +| 2026-01-21T09:14:04.8744916Z | 20260121_171308 | il2cpp_opt2 | 46c54af* | 25314022 | 57046355 | 49433980.92 | 33451864.44 | +| 2026-01-21T09:09:53.4839892Z | 20260121_160935 | dispatchfast | 71d7614* | 24999667 | 56703065 | n/a | n/a | +| 2026-01-21T09:02:21.8370259Z | 20260121_170122 | post_commit | 46c54af | 22331042 | 60740046 | 47947066.44 | 32652492.58 | + + diff --git a/Tools/RunPerf.ps1 b/Tools/RunPerf.ps1 index e75a022..f800eac 100644 --- a/Tools/RunPerf.ps1 +++ b/Tools/RunPerf.ps1 @@ -8,6 +8,8 @@ param( [switch]$NoReadme, [string]$ReadmeFile = "", + [int]$ReadmeMaxRows = 20, + [switch]$UpdateReadmeOnly, [string]$UnityVersion = "", [string]$UnityExe = "", @@ -390,7 +392,8 @@ function Parse-BridgePerfLog([string]$LogPath) function Update-PerfReadme( [string]$ReadmePath, - $Record + [string]$HistoryPath, + [int]$MaxRows ) { if ([string]::IsNullOrWhiteSpace($ReadmePath)) @@ -426,57 +429,101 @@ function Update-PerfReadme( $text = $text.TrimEnd() + ($nl + $nl) + $section } - $runId = Try-Get { [string]$Record.runId } - if ([string]::IsNullOrWhiteSpace($runId)) - { - return - } + $tableHeader = "| tsUtc | runId | tag | git | robothost_null cmd/s | robot_runner cmd/s | il2cpp_source 1k ticks/s | il2cpp_source 10k ticks/s |" + $tableSep = "|---|---|---|---|---:|---:|---:|---:|" - if ($text -match [regex]::Escape("| $runId |")) + $rows = New-Object System.Collections.Generic.List[string] + + if (Test-Path $HistoryPath) { - return - } + $tailCount = [Math]::Max(1, [Math]::Min(5000, $MaxRows * 50)) + $lines = Get-Content $HistoryPath -Tail $tailCount - $tsUtc = Try-Get { [string]$Record.tsUtc } - if ([string]::IsNullOrWhiteSpace($tsUtc)) { $tsUtc = (Get-Date).ToUniversalTime().ToString("o") } + $seen = New-Object System.Collections.Generic.HashSet[string] + for ($i = $lines.Count - 1; $i -ge 0; $i--) + { + if ($rows.Count -ge $MaxRows) { break } - $tag = Try-Get { [string]$Record.tag } - $commit = Try-Get { [string]$Record.git.commit } - if (-not [string]::IsNullOrWhiteSpace($commit) -and $commit.Length -gt 7) { $commit = $commit.Substring(0, 7) } - $dirty = Try-Get { [bool]$Record.git.dirty } - if ($dirty) { $commit = "$commit*" } + $line = $lines[$i] + if ([string]::IsNullOrWhiteSpace($line)) { continue } - $rhNull = Try-Get { [double]$Record.results.robothost_null.commands_per_s } - $rr = Try-Get { [double]$Record.results.robot_runner.commands_per_s } + $rec = $null + try { $rec = $line | ConvertFrom-Json } catch { continue } + if (-not $rec) { continue } - $il2 = Try-Get { $Record.results.unity_il2cpp_source } - $il2_1k = $null - $il2_10k = $null - try - { - if ($il2 -is [System.Array]) - { - $il2_1k = ($il2 | Where-Object bots -eq 1000 | Select-Object -First 1).ticks_per_s - $il2_10k = ($il2 | Where-Object bots -eq 10000 | Select-Object -First 1).ticks_per_s + $runId = Try-Get { [string]$rec.runId } + if ([string]::IsNullOrWhiteSpace($runId)) { continue } + if (-not $seen.Add($runId)) { continue } + + $tsUtcObj = Try-Get { $rec.tsUtc } + $tsUtc = $null + if ($tsUtcObj -is [DateTime]) + { + $tsUtc = $tsUtcObj.ToUniversalTime().ToString("o") + } + else + { + $tsUtc = Try-Get { [string]$tsUtcObj } + } + if ([string]::IsNullOrWhiteSpace($tsUtc)) { $tsUtc = "n/a" } + + $tag = Try-Get { [string]$rec.tag } + if ([string]::IsNullOrWhiteSpace($tag)) { $tag = "" } + + $commit = Try-Get { [string]$rec.git.commit } + if (-not [string]::IsNullOrWhiteSpace($commit) -and $commit.Length -gt 7) { $commit = $commit.Substring(0, 7) } + if ([string]::IsNullOrWhiteSpace($commit)) { $commit = "n/a" } + $dirty = Try-Get { [bool]$rec.git.dirty } + if ($dirty) { $commit = "$commit*" } + + $rhNull = Try-Get { [double]$rec.results.robothost_null.commands_per_s } + $rr = Try-Get { [double]$rec.results.robot_runner.commands_per_s } + + $il2 = Try-Get { $rec.results.unity_il2cpp_source } + $il2_1k = $null + $il2_10k = $null + try + { + if ($il2 -is [System.Array]) + { + $il2_1k = ($il2 | Where-Object bots -eq 1000 | Select-Object -First 1).ticks_per_s + $il2_10k = ($il2 | Where-Object bots -eq 10000 | Select-Object -First 1).ticks_per_s + } + } + catch + { + } + + $fmt0 = { param($v) if ($null -eq $v) { "n/a" } else { "{0:0}" -f $v } } + $fmt2 = { param($v) if ($null -eq $v) { "n/a" } else { "{0:0.00}" -f $v } } + + $rows.Add(@( + "| $tsUtc | $runId | $tag | $commit |", + " $(& $fmt0 $rhNull) |", + " $(& $fmt0 $rr) |", + " $(& $fmt2 $il2_1k) |", + " $(& $fmt2 $il2_10k) |" + ) -join "") } } - catch - { - } - $fmt0 = { param($v) if ($null -eq $v) { "n/a" } else { "{0:0}" -f $v } } - $fmt2 = { param($v) if ($null -eq $v) { "n/a" } else { "{0:0.00}" -f $v } } + $blockLines = New-Object System.Collections.Generic.List[string] + $blockLines.Add($start) + $blockLines.Add($tableHeader) + $blockLines.Add($tableSep) + foreach ($r in $rows) { $blockLines.Add($r) } + $blockLines.Add($end) - $row = @( - "| $tsUtc | $runId | $tag | $commit |", - " $(& $fmt0 $rhNull) |", - " $(& $fmt0 $rr) |", - " $(& $fmt2 $il2_1k) |", - " $(& $fmt2 $il2_10k) |" - ) -join "" - - $replacement = $row + $nl + $end - $text = [regex]::Replace($text, [regex]::Escape($end), [System.Text.RegularExpressions.MatchEvaluator]{ param($m) $replacement }, 1) + $block = ($blockLines -join $nl) + $pattern = "(?s)" + [regex]::Escape($start) + ".*?" + [regex]::Escape($end) + if ([regex]::IsMatch($text, $pattern)) + { + $text = [regex]::Replace($text, $pattern, [System.Text.RegularExpressions.MatchEvaluator]{ param($m) $block }, 1) + } + else + { + $text = $text.TrimEnd() + ($nl + $nl) + $block + $nl + } Set-Content -Path $ReadmePath -Value $text -Encoding UTF8 } @@ -501,6 +548,20 @@ if (-not $NoReadme) } } +if ($UpdateReadmeOnly) +{ + if ($readmePath) + { + Update-PerfReadme -ReadmePath $readmePath -HistoryPath $OutFile -MaxRows $ReadmeMaxRows + Write-Host "Updated: $readmePath" + } + else + { + Write-Host "README update disabled (-NoReadme)" + } + exit 0 +} + $runId = (Get-Date -Format "yyyyMMdd_HHmmss") $runDir = Join-Path $repoRoot ("build\\perf_runs\\$runId") New-Dir $runDir @@ -767,7 +828,7 @@ if ($readmePath) { try { - Update-PerfReadme -ReadmePath $readmePath -Record $record + Update-PerfReadme -ReadmePath $readmePath -HistoryPath $OutFile -MaxRows $ReadmeMaxRows Write-Host "Updated: $readmePath" } catch From 4359f814f1cd5c932d4aad2c52c2d694276ffa4f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=A2=81=E9=93=96?= <> Date: Wed, 21 Jan 2026 18:11:25 +0800 Subject: [PATCH 16/33] =?UTF-8?q?perf:=20README=20=E6=80=A7=E8=83=BD?= =?UTF-8?q?=E8=A1=A8=E6=8C=89=E6=97=B6=E9=97=B4=E6=8E=92=E5=BA=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 1 + Tools/RunPerf.ps1 | 61 ++++++++++++++++++++++++++++++++++++++--------- 2 files changed, 51 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 7c1d20c..267dac9 100644 --- a/README.md +++ b/README.md @@ -96,3 +96,4 @@ powershell -ExecutionPolicy Bypass -File Tools/RunPerf.ps1 -Bots 1000 -Frames 30 + diff --git a/Tools/RunPerf.ps1 b/Tools/RunPerf.ps1 index f800eac..50d4718 100644 --- a/Tools/RunPerf.ps1 +++ b/Tools/RunPerf.ps1 @@ -9,6 +9,8 @@ param( [switch]$NoReadme, [string]$ReadmeFile = "", [int]$ReadmeMaxRows = 20, + [ValidateSet("desc", "asc")] + [string]$ReadmeSort = "desc", [switch]$UpdateReadmeOnly, [string]$UnityVersion = "", @@ -393,7 +395,8 @@ function Parse-BridgePerfLog([string]$LogPath) function Update-PerfReadme( [string]$ReadmePath, [string]$HistoryPath, - [int]$MaxRows + [int]$MaxRows, + [string]$Sort ) { if ([string]::IsNullOrWhiteSpace($ReadmePath)) @@ -436,15 +439,14 @@ function Update-PerfReadme( if (Test-Path $HistoryPath) { - $tailCount = [Math]::Max(1, [Math]::Min(5000, $MaxRows * 50)) + $tailCount = [Math]::Max(1, [Math]::Min(20000, $MaxRows * 200)) $lines = Get-Content $HistoryPath -Tail $tailCount + $items = New-Object System.Collections.Generic.List[object] $seen = New-Object System.Collections.Generic.HashSet[string] - for ($i = $lines.Count - 1; $i -ge 0; $i--) - { - if ($rows.Count -ge $MaxRows) { break } - $line = $lines[$i] + foreach ($line in $lines) + { if ([string]::IsNullOrWhiteSpace($line)) { continue } $rec = $null @@ -456,14 +458,51 @@ function Update-PerfReadme( if (-not $seen.Add($runId)) { continue } $tsUtcObj = Try-Get { $rec.tsUtc } - $tsUtc = $null + $tsText = $null if ($tsUtcObj -is [DateTime]) { - $tsUtc = $tsUtcObj.ToUniversalTime().ToString("o") + $tsText = $tsUtcObj.ToUniversalTime().ToString("o") + } + else + { + $tsText = Try-Get { [string]$tsUtcObj } + } + + $ts = $null + if (-not [string]::IsNullOrWhiteSpace($tsText)) + { + $ts = Try-Get { [DateTime]::Parse($tsText).ToUniversalTime() } + } + + if (-not $ts) + { + $ts = Try-Get { [DateTime]::ParseExact($runId, "yyyyMMdd_HHmmss", $null).ToUniversalTime() } + } + + $items.Add([pscustomobject]@{ + ts = $ts + tsTxt = $tsText + rec = $rec + }) + } + + $sorted = + if ($Sort -eq "asc") { $items | Sort-Object ts, @{ Expression = { $_.rec.runId }; Descending = $false } } + else { $items | Sort-Object ts, @{ Expression = { $_.rec.runId }; Descending = $true } -Descending } + + foreach ($it in ($sorted | Select-Object -First $MaxRows)) + { + $rec = $it.rec + $runId = Try-Get { [string]$rec.runId } + + $tsUtc = $null + if ($it.ts) + { + $tsUtc = $it.ts.ToString("o") } else { - $tsUtc = Try-Get { [string]$tsUtcObj } + $tsUtc = $it.tsTxt } if ([string]::IsNullOrWhiteSpace($tsUtc)) { $tsUtc = "n/a" } @@ -552,7 +591,7 @@ if ($UpdateReadmeOnly) { if ($readmePath) { - Update-PerfReadme -ReadmePath $readmePath -HistoryPath $OutFile -MaxRows $ReadmeMaxRows + Update-PerfReadme -ReadmePath $readmePath -HistoryPath $OutFile -MaxRows $ReadmeMaxRows -Sort $ReadmeSort Write-Host "Updated: $readmePath" } else @@ -828,7 +867,7 @@ if ($readmePath) { try { - Update-PerfReadme -ReadmePath $readmePath -HistoryPath $OutFile -MaxRows $ReadmeMaxRows + Update-PerfReadme -ReadmePath $readmePath -HistoryPath $OutFile -MaxRows $ReadmeMaxRows -Sort $ReadmeSort Write-Host "Updated: $readmePath" } catch From 198f95d37e5aed439bddb796a9442c840a269326 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=A2=81=E9=93=96?= <> Date: Wed, 21 Jan 2026 18:13:45 +0800 Subject: [PATCH 17/33] =?UTF-8?q?perf:=20README=20=E8=A1=A8=E5=A2=9E?= =?UTF-8?q?=E5=8A=A0=20C++=20runner=20ticks/s?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 27 ++++++++++++++------------- Tools/RunPerf.ps1 | 28 ++++++++++++++++++++++++---- 2 files changed, 38 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index 267dac9..e5b8a0d 100644 --- a/README.md +++ b/README.md @@ -79,21 +79,22 @@ powershell -ExecutionPolicy Bypass -File Tools/RunPerf.ps1 -Bots 1000 -Frames 30 下表由 `Tools/RunPerf.ps1` 自动追加(更完整的数据仍以 `build/perf_history.jsonl` 为准)。 -| tsUtc | runId | tag | git | robothost_null cmd/s | robot_runner cmd/s | il2cpp_source 1k ticks/s | il2cpp_source 10k ticks/s | -|---|---|---|---|---:|---:|---:|---:| -| 2026-01-21T09:50:23.6962380Z | 20260121_175019 | readme_table_test | 23e79d6* | 53571 | 2000000 | n/a | n/a | -| 2026-01-21T09:46:22.1895560Z | 20260121_174537 | post_23e79d6 | 23e79d6 | 23447208 | 58632532 | 50646588.11 | 32289520.76 | -| 2026-01-21T09:41:02.1140619Z | 20260121_174007 | il2cpp_opt4_revert_typed | 46c54af* | 24891834 | 56602493 | 50043370.92 | 31107456.56 | -| 2026-01-21T09:37:31.9048310Z | 20260121_173649 | il2cpp_opt4_rerun | 46c54af* | 25635026 | 61322383 | 48721863.12 | 31246354.59 | -| 2026-01-21T09:34:52.0737234Z | 20260121_173358 | il2cpp_opt4_typed_fix | 46c54af* | 24150548 | 60397744 | 49961696.03 | 29169514.75 | -| 2026-01-21T09:33:07.3524273Z | 20260121_173240 | il2cpp_opt4_typed | 46c54af* | 25081209 | 58809475 | n/a | n/a | -| 2026-01-21T09:18:09.6002287Z | 20260121_161722 | | 71d7614* | 24554530 | 60572076 | n/a | n/a | -| 2026-01-21T09:17:51.7355502Z | 20260121_171649 | il2cpp_opt3_gen | 46c54af* | 25158498 | 55715319 | 46472000.62 | 31124464.66 | -| 2026-01-21T09:14:04.8744916Z | 20260121_171308 | il2cpp_opt2 | 46c54af* | 25314022 | 57046355 | 49433980.92 | 33451864.44 | -| 2026-01-21T09:09:53.4839892Z | 20260121_160935 | dispatchfast | 71d7614* | 24999667 | 56703065 | n/a | n/a | -| 2026-01-21T09:02:21.8370259Z | 20260121_170122 | post_commit | 46c54af | 22331042 | 60740046 | 47947066.44 | 32652492.58 | +| tsUtc | runId | tag | git | robothost_null cmd/s | robot_runner cmd/s | robot_runner ticks/s | il2cpp_source 1k ticks/s | il2cpp_source 10k ticks/s | +|---|---|---|---|---:|---:|---:|---:|---:| +| 2026-01-21T09:50:23.6962380Z | 20260121_175019 | readme_table_test | 23e79d6* | 53571 | 2000000 | n/a | n/a | n/a | +| 2026-01-21T09:46:22.1895560Z | 20260121_174537 | post_23e79d6 | 23e79d6 | 23447208 | 58632532 | 58823529.41 | 50646588.11 | 32289520.76 | +| 2026-01-21T09:41:02.1140619Z | 20260121_174007 | il2cpp_opt4_revert_typed | 46c54af* | 24891834 | 56602493 | 56603773.58 | 50043370.92 | 31107456.56 | +| 2026-01-21T09:37:31.9048310Z | 20260121_173649 | il2cpp_opt4_rerun | 46c54af* | 25635026 | 61322383 | 61224489.80 | 48721863.12 | 31246354.59 | +| 2026-01-21T09:34:52.0737234Z | 20260121_173358 | il2cpp_opt4_typed_fix | 46c54af* | 24150548 | 60397744 | 60000000.00 | 49961696.03 | 29169514.75 | +| 2026-01-21T09:33:07.3524273Z | 20260121_173240 | il2cpp_opt4_typed | 46c54af* | 25081209 | 58809475 | 58823529.41 | n/a | n/a | +| 2026-01-21T09:18:09.6002287Z | 20260121_161722 | | 71d7614* | 24554530 | 60572076 | 60000000.00 | n/a | n/a | +| 2026-01-21T09:17:51.7355502Z | 20260121_171649 | il2cpp_opt3_gen | 46c54af* | 25158498 | 55715319 | 55555555.56 | 46472000.62 | 31124464.66 | +| 2026-01-21T09:14:04.8744916Z | 20260121_171308 | il2cpp_opt2 | 46c54af* | 25314022 | 57046355 | 56603773.58 | 49433980.92 | 33451864.44 | +| 2026-01-21T09:09:53.4839892Z | 20260121_160935 | dispatchfast | 71d7614* | 24999667 | 56703065 | 56603773.58 | n/a | n/a | +| 2026-01-21T09:02:21.8370259Z | 20260121_170122 | post_commit | 46c54af | 22331042 | 60740046 | 61224489.80 | 47947066.44 | 32652492.58 | + diff --git a/Tools/RunPerf.ps1 b/Tools/RunPerf.ps1 index 50d4718..8466c4d 100644 --- a/Tools/RunPerf.ps1 +++ b/Tools/RunPerf.ps1 @@ -318,11 +318,20 @@ function Parse-RobotRunnerOutput([string]$Text) return $null } + $elapsed_s = & $getDouble "elapsed: ([0-9.]+) s" + $ticks = & $getInt "ticks: (\d+)" + $ticks_per_s = $null + if ($elapsed_s -and $elapsed_s -gt 1e-9 -and $ticks -ne $null) + { + $ticks_per_s = [double]$ticks / [double]$elapsed_s + } + return [ordered]@{ - elapsed_s = & $getDouble "elapsed: ([0-9.]+) s" + elapsed_s = $elapsed_s total_commands = & $getInt "total commands parsed: (\d+)" commands_per_s = & $getDouble "commands/sec: (\d+)" - ticks = & $getInt "ticks: (\d+)" + ticks = $ticks + ticks_per_s = $ticks_per_s asset_requests = & $getInt "total asset requests: (\d+)" } } @@ -432,8 +441,8 @@ function Update-PerfReadme( $text = $text.TrimEnd() + ($nl + $nl) + $section } - $tableHeader = "| tsUtc | runId | tag | git | robothost_null cmd/s | robot_runner cmd/s | il2cpp_source 1k ticks/s | il2cpp_source 10k ticks/s |" - $tableSep = "|---|---|---|---|---:|---:|---:|---:|" + $tableHeader = "| tsUtc | runId | tag | git | robothost_null cmd/s | robot_runner cmd/s | robot_runner ticks/s | il2cpp_source 1k ticks/s | il2cpp_source 10k ticks/s |" + $tableSep = "|---|---|---|---|---:|---:|---:|---:|---:|" $rows = New-Object System.Collections.Generic.List[string] @@ -517,6 +526,16 @@ function Update-PerfReadme( $rhNull = Try-Get { [double]$rec.results.robothost_null.commands_per_s } $rr = Try-Get { [double]$rec.results.robot_runner.commands_per_s } + $rrTicksPerS = Try-Get { [double]$rec.results.robot_runner.ticks_per_s } + if ($rrTicksPerS -eq $null) + { + $rrElapsed = Try-Get { [double]$rec.results.robot_runner.elapsed_s } + $rrTicks = Try-Get { [double]$rec.results.robot_runner.ticks } + if ($rrElapsed -and $rrElapsed -gt 1e-9 -and $rrTicks -ne $null) + { + $rrTicksPerS = $rrTicks / $rrElapsed + } + } $il2 = Try-Get { $rec.results.unity_il2cpp_source } $il2_1k = $null @@ -540,6 +559,7 @@ function Update-PerfReadme( "| $tsUtc | $runId | $tag | $commit |", " $(& $fmt0 $rhNull) |", " $(& $fmt0 $rr) |", + " $(& $fmt2 $rrTicksPerS) |", " $(& $fmt2 $il2_1k) |", " $(& $fmt2 $il2_10k) |" ) -join "") From be619d5a6429cbc9e1799de30afba5ac64a18f7a Mon Sep 17 00:00:00 2001 From: lcals Date: Wed, 21 Jan 2026 18:23:37 +0800 Subject: [PATCH 18/33] =?UTF-8?q?=E6=9B=B4=E6=96=B0=E6=96=87=E6=A1=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 37 ++++++++++++++++++------------------- 1 file changed, 18 insertions(+), 19 deletions(-) diff --git a/README.md b/README.md index e5b8a0d..da2c4a6 100644 --- a/README.md +++ b/README.md @@ -78,23 +78,22 @@ powershell -ExecutionPolicy Bypass -File Tools/RunPerf.ps1 -Bots 1000 -Frames 30 下表由 `Tools/RunPerf.ps1` 自动追加(更完整的数据仍以 `build/perf_history.jsonl` 为准)。 - -| tsUtc | runId | tag | git | robothost_null cmd/s | robot_runner cmd/s | robot_runner ticks/s | il2cpp_source 1k ticks/s | il2cpp_source 10k ticks/s | -|---|---|---|---|---:|---:|---:|---:|---:| -| 2026-01-21T09:50:23.6962380Z | 20260121_175019 | readme_table_test | 23e79d6* | 53571 | 2000000 | n/a | n/a | n/a | -| 2026-01-21T09:46:22.1895560Z | 20260121_174537 | post_23e79d6 | 23e79d6 | 23447208 | 58632532 | 58823529.41 | 50646588.11 | 32289520.76 | -| 2026-01-21T09:41:02.1140619Z | 20260121_174007 | il2cpp_opt4_revert_typed | 46c54af* | 24891834 | 56602493 | 56603773.58 | 50043370.92 | 31107456.56 | -| 2026-01-21T09:37:31.9048310Z | 20260121_173649 | il2cpp_opt4_rerun | 46c54af* | 25635026 | 61322383 | 61224489.80 | 48721863.12 | 31246354.59 | -| 2026-01-21T09:34:52.0737234Z | 20260121_173358 | il2cpp_opt4_typed_fix | 46c54af* | 24150548 | 60397744 | 60000000.00 | 49961696.03 | 29169514.75 | -| 2026-01-21T09:33:07.3524273Z | 20260121_173240 | il2cpp_opt4_typed | 46c54af* | 25081209 | 58809475 | 58823529.41 | n/a | n/a | -| 2026-01-21T09:18:09.6002287Z | 20260121_161722 | | 71d7614* | 24554530 | 60572076 | 60000000.00 | n/a | n/a | -| 2026-01-21T09:17:51.7355502Z | 20260121_171649 | il2cpp_opt3_gen | 46c54af* | 25158498 | 55715319 | 55555555.56 | 46472000.62 | 31124464.66 | -| 2026-01-21T09:14:04.8744916Z | 20260121_171308 | il2cpp_opt2 | 46c54af* | 25314022 | 57046355 | 56603773.58 | 49433980.92 | 33451864.44 | -| 2026-01-21T09:09:53.4839892Z | 20260121_160935 | dispatchfast | 71d7614* | 24999667 | 56703065 | 56603773.58 | n/a | n/a | -| 2026-01-21T09:02:21.8370259Z | 20260121_170122 | post_commit | 46c54af | 22331042 | 60740046 | 61224489.80 | 47947066.44 | 32652492.58 | + +| tsUtc | runId | tag | git | robothost_null cmd/s | robot_runner cmd/s | robot_runner ticks/s | il2cpp_source 1k ticks/s | il2cpp_source 10k ticks/s | +|---|---|---|---|---:|---:|---:|---:|---:| +| 2026-01-21T09:46:22.1895560Z | 20260121_174537 | post_23e79d6 | 23e79d6 | 23447208 | 58632532 | 58823529.41 | 50646588.11 | 32289520.76 | +| 2026-01-21T09:41:02.1140619Z | 20260121_174007 | il2cpp_opt4_revert_typed | 46c54af* | 24891834 | 56602493 | 56603773.58 | 50043370.92 | 31107456.56 | +| 2026-01-21T09:37:31.9048310Z | 20260121_173649 | il2cpp_opt4_rerun | 46c54af* | 25635026 | 61322383 | 61224489.80 | 48721863.12 | 31246354.59 | +| 2026-01-21T09:34:52.0737234Z | 20260121_173358 | il2cpp_opt4_typed_fix | 46c54af* | 24150548 | 60397744 | 60000000.00 | 49961696.03 | 29169514.75 | +| 2026-01-21T09:33:07.3524273Z | 20260121_173240 | il2cpp_opt4_typed | 46c54af* | 25081209 | 58809475 | 58823529.41 | n/a | n/a | +| 2026-01-21T09:18:09.6002287Z | 20260121_161722 | | 71d7614* | 24554530 | 60572076 | 60000000.00 | n/a | n/a | +| 2026-01-21T09:17:51.7355502Z | 20260121_171649 | il2cpp_opt3_gen | 46c54af* | 25158498 | 55715319 | 55555555.56 | 46472000.62 | 31124464.66 | +| 2026-01-21T09:14:04.8744916Z | 20260121_171308 | il2cpp_opt2 | 46c54af* | 25314022 | 57046355 | 56603773.58 | 49433980.92 | 33451864.44 | +| 2026-01-21T09:09:53.4839892Z | 20260121_160935 | dispatchfast | 71d7614* | 24999667 | 56703065 | 56603773.58 | n/a | n/a | +| 2026-01-21T09:02:21.8370259Z | 20260121_170122 | post_commit | 46c54af | 22331042 | 60740046 | 61224489.80 | 47947066.44 | 32652492.58 | - - - - - + + + + + From 98be1d5e969185ec7cfca7b33da4931b4f4174f8 Mon Sep 17 00:00:00 2001 From: lcals Date: Wed, 21 Jan 2026 18:29:15 +0800 Subject: [PATCH 19/33] =?UTF-8?q?=E6=9B=B4=E6=96=B0=E6=96=87=E6=A1=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Core/docs/PERF_OPTIMIZATIONS.md | 103 ++++++++++++++++++++++++++++++++ README.md | 2 +- 2 files changed, 104 insertions(+), 1 deletion(-) create mode 100644 Core/docs/PERF_OPTIMIZATIONS.md diff --git a/Core/docs/PERF_OPTIMIZATIONS.md b/Core/docs/PERF_OPTIMIZATIONS.md new file mode 100644 index 0000000..a870818 --- /dev/null +++ b/Core/docs/PERF_OPTIMIZATIONS.md @@ -0,0 +1,103 @@ +# 性能优化记录(仅记录已验证提升) + +本文件用于固化“已经验证能提升性能”的改动点与复现方式,避免反复踩坑。 + +## 记录规范(只记“确定提升”的) + +- 每条优化至少复验 2 次(避免噪声),并且核心指标有提升才写入本文件。 +- 每条记录必须能复现:写清楚 Unity 版本、`RunPerf` 参数、对比基线(tag/runId/commit)。 +- 性能数字以 `README.md` 的性能摘要表为准;本文件只记录“做了什么 + 为什么有效 + 怎么复现”。 + +## 如何跑性能 + +仓库统一用 `Tools/RunPerf.ps1`: + +```powershell +pwsh -NoProfile -ExecutionPolicy Bypass -File Tools/RunPerf.ps1 -UnityVersion 6000.0.40f1 -Tag "" +``` + +- 每次 run 的完整原始数据:`build/perf_history.jsonl`(不建议提交,只用于本机追溯/回归分析) +- 单次 run 产物:`build/perf_runs//` +- Unity IL2CPP Source 模式产物:`build/perf_runs//ruttt_il2cpp_source/.../il2cppOutput/` + +建议固定参数(bots/frames/dt)后再对比;如果只做快速 smoke,可加 `-NoBuild`。 + +## 如何用 IL2CPP 输出定位热点 + +1. 跑一次 IL2CPP Source 模式(RunPerf 默认会跑)。 +2. 打开 `build/perf_runs//ruttt_il2cpp_source/.../il2cppOutput/` +3. 常用搜索: + - `VirtualActionInvoker`:通常意味着虚调用/接口调用在热点路径上 + - `SetAt(`:通常意味着数组写入走了额外的边界检查/写屏障路径 + +## 已验证有效的优化点 + +### 1) IL2CPP 下批量 Tick 写回 streams 的数组写入优化 + +**引入** +- git:`23e79d6` + +**现象(IL2CPP 输出)** +- `CommandStream[]` 逐个 `streams[i] = ...` 会生成 `SetAt(...)` 路径,额外开销明显。 + +**改动** +- 在 `TickManyAndGetCommandStreams` 写回阶段,改为 `fixed (CommandStream* dst = streams)`,用 `dst[i] = ...` 直接写入。 + +**位置** +- `Core/csharp/Bridge.Core/BridgeCore.cs` +- `Packages/com.unitynativescripting.bridgecore/Runtime/Bridge.Core/BridgeCore.cs` + +**效果** +- IL2CPP 输出中数组写回从 `SetAt(...)` 变为通过 `GetAddressAt(0)` 获取底层指针后直接赋值。 + +### 2) DispatchFast 空流判断内联(减少一次属性调用) + +**引入** +- git:`23e79d6` + +**现象(IL2CPP 输出)** +- `stream.IsEmpty` 会变成一次属性调用(哪怕很小也会落在热点)。 + +**改动** +- `DispatchFast` 入口判断改为 `host == null || stream.Ptr == IntPtr.Zero || stream.Length == 0`。 + +**位置** +- 生成器:`Core/Tools/BridgeGen/Program.cs` +- 生成物: + - `Tests/csharp/RobotHost/Generated/Bridge.AllCommandDispatcher.g.cs` + - `Tests/unity/Assets/BridgeDemoGame/Generated/Bridge.AllCommandDispatcher.g.cs` + +## 优化流程建议(只在提升时记录/提交) + +1. 做一次“小步”改动(只动一个热点点位)。 +2. 跑 `Tools/RunPerf.ps1` 并打 `-Tag`。 +3. 对比 `README.md` 的摘要表(或直接看 `build/perf_history.jsonl`)确认核心指标提升: + - Unity IL2CPP Source:`il2cpp_source 1k ticks/s`、`il2cpp_source 10k ticks/s` + - C++ runner:`robot_runner ticks/s`(原生解析+tick 的基线) +4. 如果回退:回滚代码与 README 变更,不提交。 +5. 如果提升:再跑一次复验(减少噪声),然后提交代码 + 记录。 + +## 新增记录模板 + +复制这一段追加到“已验证有效的优化点”下面: + +```markdown +### N) <标题(一句话说明改动)> + +**引入** +- git: +- 验证:Unity ;tag=;runId=(复验 2 次) +- 对比:tag=;runId= + +**现象(IL2CPP 输出)** +- <你在 il2cppOutput 里看到的热点/函数名/调用路径> + +**改动** +- <做了什么> + +**位置** +- <文件路径 / 生成器路径 / 生成物路径> + +**效果** +- <为什么有效(减少虚调用/减少数组写屏障/减少分配/减少拷贝等)> +``` diff --git a/README.md b/README.md index da2c4a6..f9ea901 100644 --- a/README.md +++ b/README.md @@ -60,6 +60,7 @@ dotnet run --project Core/Tools/BridgeGen/BridgeGen.csproj -c Release -- --out-c - 架构设计:`Core/docs/BRIDGE_DESIGN.md` - 构建与运行:`Core/docs/BUILD.md` - Unity Windows 原生库加载:`Core/docs/UNITY_WIN_NATIVE_LOADING.md` +- 性能优化记录:`Core/docs/PERF_OPTIMIZATIONS.md` ## 性能测试(带历史记录) @@ -96,4 +97,3 @@ powershell -ExecutionPolicy Bypass -File Tools/RunPerf.ps1 -Bots 1000 -Frames 30 - From 2772303b54b3eb919e2e141560c98a6db37b1a63 Mon Sep 17 00:00:00 2001 From: lcals Date: Wed, 21 Jan 2026 19:28:33 +0800 Subject: [PATCH 20/33] perf: stabilize IL2CPP runs and speed stream loop --- .../BridgeDemoGame.PlayModeTests.asmdef | 4 +- .../BridgeSourceModeThroughputTests.cs | 19 ++- Tools/RunPerf.ps1 | 127 ++++++++++++++++-- 3 files changed, 128 insertions(+), 22 deletions(-) diff --git a/Tests/unity/Assets/BridgeDemoGame/PlayModeTests/BridgeDemoGame.PlayModeTests.asmdef b/Tests/unity/Assets/BridgeDemoGame/PlayModeTests/BridgeDemoGame.PlayModeTests.asmdef index c2df323..c214e69 100644 --- a/Tests/unity/Assets/BridgeDemoGame/PlayModeTests/BridgeDemoGame.PlayModeTests.asmdef +++ b/Tests/unity/Assets/BridgeDemoGame/PlayModeTests/BridgeDemoGame.PlayModeTests.asmdef @@ -7,6 +7,6 @@ ], "optionalUnityReferences": [ "TestAssemblies" - ] + ], + "allowUnsafeCode": true } - diff --git a/Tests/unity/Assets/BridgeDemoGame/PlayModeTests/BridgeSourceModeThroughputTests.cs b/Tests/unity/Assets/BridgeDemoGame/PlayModeTests/BridgeSourceModeThroughputTests.cs index 63b9868..36e175f 100644 --- a/Tests/unity/Assets/BridgeDemoGame/PlayModeTests/BridgeSourceModeThroughputTests.cs +++ b/Tests/unity/Assets/BridgeDemoGame/PlayModeTests/BridgeSourceModeThroughputTests.cs @@ -157,15 +157,22 @@ private static void RunFrames( out ulong totalBytes) { totalBytes = 0; + int count = coreHandles.Length; - for (int frame = 0; frame < frames; frame++) + unsafe { - BridgeCore.TickManyAndGetCommandStreams(coreHandles, dt, streams); - for (int i = 0; i < coreHandles.Length; i++) + fixed (CommandStream* streamsPtr = streams) { - CommandStream stream = streams[i]; - totalBytes += stream.Length; - BridgeAllCommandDispatcher.DispatchFast(stream, hosts[i]); + for (int frame = 0; frame < frames; frame++) + { + BridgeCore.TickManyAndGetCommandStreams(coreHandles, dt, streams); + for (int i = 0; i < count; i++) + { + CommandStream stream = streamsPtr[i]; + totalBytes += stream.Length; + BridgeAllCommandDispatcher.DispatchFast(stream, hosts[i]); + } + } } } } diff --git a/Tools/RunPerf.ps1 b/Tools/RunPerf.ps1 index 8466c4d..c18c65a 100644 --- a/Tools/RunPerf.ps1 +++ b/Tools/RunPerf.ps1 @@ -15,6 +15,8 @@ param( [string]$UnityVersion = "", [string]$UnityExe = "", + [ValidateRange(1, 20)] + [int]$UnityIl2cppRepeat = 1, [switch]$NoUnity, [switch]$NoUnityEditMode, [switch]$NoUnityIl2cpp, @@ -75,6 +77,25 @@ function Try-Get([scriptblock]$Thunk) try { return & $Thunk } catch { return $null } } +function Get-Median([double[]]$Values) +{ + if (-not $Values -or $Values.Count -eq 0) + { + return $null + } + + $sorted = $Values | Sort-Object + $n = $sorted.Count + if (($n % 2) -eq 1) + { + return [double]$sorted[[int]($n / 2)] + } + + $a = [double]$sorted[($n / 2) - 1] + $b = [double]$sorted[($n / 2)] + return ($a + $b) / 2.0 +} + function Invoke-External( [string]$Name, [string]$FilePath, @@ -831,27 +852,105 @@ if ($unity -and -not $NoUnityIl2cpp) if ($steps.unity_ruttt_build_il2cpp.ok) { - $steps.unity_ruttt_run_il2cpp = Invoke-External ` - -Name "unity_ruttt_run_il2cpp" ` - -FilePath $rutttExe ` - -ArgumentList @("-batchmode", "-nographics", "-logFile", $rutttRunLog) ` - -WorkDir $rutttDir ` - -OutputFile (Join-Path $rutttDir "player_console.txt") + $repeat = [Math]::Max(1, $UnityIl2cppRepeat) + $runs = New-Object System.Collections.Generic.List[object] - if ($steps.unity_ruttt_run_il2cpp.ok) + for ($i = 1; $i -le $repeat; $i++) { - $runStartedUtc = Try-Get { [DateTime]::Parse($steps.unity_ruttt_run_il2cpp.startedUtc).ToUniversalTime() } - if ($runStartedUtc -and (Wait-FileUpdated -Path $rutttRunLog -NotBeforeUtc $runStartedUtc -TimeoutSeconds 1800 -MinLength 256)) + $runLog = if ($i -eq 1) { $rutttRunLog } else { (Join-Path $rutttDir ("run_{0}.log" -f $i)) } + $playerConsole = if ($i -eq 1) { (Join-Path $rutttDir "player_console.txt") } else { (Join-Path $rutttDir ("player_console_{0}.txt" -f $i)) } + $stepName = if ($repeat -le 1) { "unity_ruttt_run_il2cpp" } else { ("unity_ruttt_run_il2cpp_{0}" -f $i) } + + $step = Invoke-External ` + -Name $stepName ` + -FilePath $rutttExe ` + -ArgumentList @("-batchmode", "-nographics", "-logFile", $runLog) ` + -WorkDir $rutttDir ` + -OutputFile $playerConsole + + if ($i -eq 1) { - $results.unity_il2cpp_source = Parse-BridgePerfLog $rutttRunLog + $steps.unity_ruttt_run_il2cpp = $step } - else + + if (-not $step.ok) + { + continue + } + + $runStartedUtc = Try-Get { [DateTime]::Parse($step.startedUtc).ToUniversalTime() } + if (-not $runStartedUtc) { - $results.unity_il2cpp_source = [ordered]@{ - error = "unity il2cpp run.log not produced in time" - runLog = $rutttRunLog + continue + } + + if (-not (Wait-FileUpdated -Path $runLog -NotBeforeUtc $runStartedUtc -TimeoutSeconds 1800 -MinLength 256)) + { + continue + } + + $parsed = Try-Get { Parse-BridgePerfLog $runLog } + if ($parsed) + { + $runs.Add($parsed) | Out-Null + } + } + + if ($runs.Count -eq 0) + { + $results.unity_il2cpp_source = [ordered]@{ + error = "unity il2cpp run.log not produced in time" + runLog = $rutttRunLog + } + } + elseif ($runs.Count -eq 1) + { + $results.unity_il2cpp_source = $runs[0] + } + else + { + $flat = New-Object System.Collections.Generic.List[object] + foreach ($r in $runs) + { + foreach ($it in $r) + { + if ($null -eq $it) { continue } + + $flat.Add([pscustomobject]@{ + mode = [string]$it.mode + ticks_per_s = [double]$it.ticks_per_s + mib_per_s = [double]$it.mib_per_s + bots = [int]$it.bots + frames = [int]$it.frames + elapsed_ms = [double]$it.elapsed_ms + alloc_bytes = [long]$it.alloc_bytes + total_bytes = [long]$it.total_bytes + }) | Out-Null } } + + $median = New-Object System.Collections.Generic.List[object] + foreach ($g in ($flat | Group-Object bots)) + { + $sample = $g.Group | Select-Object -First 1 + $ticks = @($g.Group | ForEach-Object { [double]$_.ticks_per_s }) + $mib = @($g.Group | ForEach-Object { [double]$_.mib_per_s }) + $elapsed = @($g.Group | ForEach-Object { [double]$_.elapsed_ms }) + + $median.Add([ordered]@{ + mode = $sample.mode + ticks_per_s = (Get-Median $ticks) + mib_per_s = (Get-Median $mib) + bots = [int]$g.Name + frames = $sample.frames + elapsed_ms = (Get-Median $elapsed) + alloc_bytes = $sample.alloc_bytes + total_bytes = $sample.total_bytes + }) | Out-Null + } + + $results.unity_il2cpp_source = $median | Sort-Object bots + $results.unity_il2cpp_source_repeat = $repeat } } else From 0d3443a3faf4631b3e57bd69ab71a99c23cd10ea Mon Sep 17 00:00:00 2001 From: lcals Date: Wed, 21 Jan 2026 19:29:00 +0800 Subject: [PATCH 21/33] docs: record verified IL2CPP stream-loop optimization --- Core/docs/PERF_OPTIMIZATIONS.md | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/Core/docs/PERF_OPTIMIZATIONS.md b/Core/docs/PERF_OPTIMIZATIONS.md index a870818..00fb12f 100644 --- a/Core/docs/PERF_OPTIMIZATIONS.md +++ b/Core/docs/PERF_OPTIMIZATIONS.md @@ -13,7 +13,7 @@ 仓库统一用 `Tools/RunPerf.ps1`: ```powershell -pwsh -NoProfile -ExecutionPolicy Bypass -File Tools/RunPerf.ps1 -UnityVersion 6000.0.40f1 -Tag "" +pwsh -NoProfile -ExecutionPolicy Bypass -File Tools/RunPerf.ps1 -UnityVersion 6000.0.40f1 -UnityIl2cppRepeat 3 -Tag "" ``` - 每次 run 的完整原始数据:`build/perf_history.jsonl`(不建议提交,只用于本机追溯/回归分析) @@ -67,6 +67,24 @@ pwsh -NoProfile -ExecutionPolicy Bypass -File Tools/RunPerf.ps1 -UnityVersion 60 - `Tests/csharp/RobotHost/Generated/Bridge.AllCommandDispatcher.g.cs` - `Tests/unity/Assets/BridgeDemoGame/Generated/Bridge.AllCommandDispatcher.g.cs` +### 3) IL2CPP 下遍历 `CommandStream[]`:用 `fixed` 读指针避免 `GetAt(...)` + +**引入** +- git:`2772303` + +**现象(IL2CPP 输出)** +- `streams[i]`(struct 数组取值)会生成 `GetAt(...)` 路径,并带边界检查与 struct 拷贝,在 10k bots 下会被放大。 + +**改动** +- 在批量帧循环里对 `CommandStream[] streams` 做一次 `fixed (CommandStream* streamsPtr = streams)`,用 `streamsPtr[i]` 读取。 + +**位置** +- `Tests/unity/Assets/BridgeDemoGame/PlayModeTests/BridgeSourceModeThroughputTests.cs` +- `Tests/unity/Assets/BridgeDemoGame/PlayModeTests/BridgeDemoGame.PlayModeTests.asmdef`(开启 `allowUnsafeCode`) + +**效果** +- IL2CPP 输出中 `streams[i]` 从 `GetAt(...)` 变为通过 `GetAddressAt(0)` 获取底层指针后直接索引读取(减少边界检查/拷贝开销)。 + ## 优化流程建议(只在提升时记录/提交) 1. 做一次“小步”改动(只动一个热点点位)。 From d5fa6a1eca08deb8d0fd884e482ba02cf5378422 Mon Sep 17 00:00:00 2001 From: lcals Date: Wed, 21 Jan 2026 20:21:30 +0800 Subject: [PATCH 22/33] DemoEntity: add SetPosition to reduce per-tick payload --- Core/Tools/BridgeGen/Program.cs | 2 + Tests/cpp/demo_game/src/demo_asset_app.cpp | 6 +-- .../demo_entity_bindings.generated.h | 15 +++++++ Tests/csharp/RobotHost/Bind/RobotHostApi.cs | 7 +++ .../csharp/RobotHost/Bind/RobotNullHostApi.cs | 8 ++++ Tests/csharp/RobotHost/Bind/WorldState.cs | 22 ++++++++++ .../Bridge.AllCommandDispatcher.g.cs | 43 +++++++++++++------ .../RobotHost/Generated/DemoEntity.Ids.g.cs | 1 + .../Generated/DemoEntity.Structs.g.cs | 7 +++ .../Generated/IDemoEntityHostApi.g.cs | 1 + Tests/defs/demo_entity_api.def | 2 +- .../BridgeDispatchPerformanceTests.cs | 6 +++ .../Bridge.AllCommandDispatcher.g.cs | 43 +++++++++++++------ .../Generated/DemoEntity.Ids.g.cs | 1 + .../Generated/DemoEntity.Structs.g.cs | 7 +++ .../Generated/IDemoEntityHostApi.g.cs | 1 + .../PlayModeTests/BridgeMonoGcTests.cs | 6 +++ .../PlayModeTests/BridgeRuntimeSmokeTests.cs | 6 +++ .../BridgeSourceModeThroughputTests.cs | 6 +++ .../Host/DemoGameUnityHostApi.Entity.cs | 12 ++++++ 20 files changed, 174 insertions(+), 28 deletions(-) diff --git a/Core/Tools/BridgeGen/Program.cs b/Core/Tools/BridgeGen/Program.cs index 9519fc4..6d1bd2b 100644 --- a/Core/Tools/BridgeGen/Program.cs +++ b/Core/Tools/BridgeGen/Program.cs @@ -815,6 +815,8 @@ private static string MapCsInteropType(string cppType) "BridgeLogLevel" => "BridgeLogLevel", "BridgeAssetType" => "BridgeAssetType", "BridgeAssetStatus" => "BridgeAssetStatus", + "BridgeVec3" => "BridgeVec3", + "BridgeQuat" => "BridgeQuat", "BridgeTransform" => "BridgeTransform", "BridgeStringView" => "BridgeStringView", _ => throw new InvalidOperationException($"未支持的 C++ 类型:{cppType}") diff --git a/Tests/cpp/demo_game/src/demo_asset_app.cpp b/Tests/cpp/demo_game/src/demo_asset_app.cpp index 0e5665c..88ef637 100644 --- a/Tests/cpp/demo_game/src/demo_asset_app.cpp +++ b/Tests/cpp/demo_game/src/demo_asset_app.cpp @@ -38,9 +38,9 @@ namespace bridge if (entity_spawned_) { t_ += dt; - BridgeTransform tr = CoreContext::IdentityTransform(); - tr.position.x = t_; - demo_entity::SetTransform(ctx, entity_id_, /*mask*/ 1u, tr); + BridgeVec3 pos{}; + pos.x = t_; + demo_entity::SetPosition(ctx, entity_id_, pos); } } diff --git a/Tests/cpp/generated/demo_entity_bindings.generated.h b/Tests/cpp/generated/demo_entity_bindings.generated.h index 8509a1a..dacee06 100644 --- a/Tests/cpp/generated/demo_entity_bindings.generated.h +++ b/Tests/cpp/generated/demo_entity_bindings.generated.h @@ -13,6 +13,7 @@ namespace demo_entity { SpawnEntity = 0xBCAA331Du, SetTransform = 0x20DA0B6Fu, + SetPosition = 0x5B16AE9Eu, DestroyEntity = 0xC7C1C59Cu, }; @@ -35,6 +36,12 @@ namespace demo_entity BridgeTransform transform; }; + struct HostArgs_SetPosition + { + uint64_t entityId; + BridgeVec3 position; + }; + struct HostArgs_DestroyEntity { uint64_t entityId; @@ -60,6 +67,14 @@ namespace demo_entity ctx.CallHost(static_cast(HostFuncId::SetTransform), &a, static_cast(sizeof(a))); } + inline void SetPosition(bridge::CoreContext& ctx, uint64_t entityId, BridgeVec3 position) + { + HostArgs_SetPosition a{}; + a.entityId = entityId; + a.position = position; + ctx.CallHost(static_cast(HostFuncId::SetPosition), &a, static_cast(sizeof(a))); + } + inline void DestroyEntity(bridge::CoreContext& ctx, uint64_t entityId) { HostArgs_DestroyEntity a{}; diff --git a/Tests/csharp/RobotHost/Bind/RobotHostApi.cs b/Tests/csharp/RobotHost/Bind/RobotHostApi.cs index c1e6c9e..9d8d833 100644 --- a/Tests/csharp/RobotHost/Bind/RobotHostApi.cs +++ b/Tests/csharp/RobotHost/Bind/RobotHostApi.cs @@ -56,6 +56,13 @@ public override void SetTransform(ulong entityId, uint mask, in BridgeTransform _world.OnSetTransform(entityId, mask, in transform); } + public override void SetPosition(ulong entityId, BridgeVec3 position) + { + Commands++; + Transforms++; + _world.OnSetPosition(entityId, position); + } + public override void DestroyEntity(ulong entityId) { Commands++; diff --git a/Tests/csharp/RobotHost/Bind/RobotNullHostApi.cs b/Tests/csharp/RobotHost/Bind/RobotNullHostApi.cs index 1bb9aca..ff75753 100644 --- a/Tests/csharp/RobotHost/Bind/RobotNullHostApi.cs +++ b/Tests/csharp/RobotHost/Bind/RobotNullHostApi.cs @@ -57,6 +57,14 @@ public override void SetTransform(ulong entityId, uint mask, in BridgeTransform Transforms++; } + public override void SetPosition(ulong entityId, BridgeVec3 position) + { + _ = entityId; + _ = position; + Commands++; + Transforms++; + } + public override void DestroyEntity(ulong entityId) { _ = entityId; diff --git a/Tests/csharp/RobotHost/Bind/WorldState.cs b/Tests/csharp/RobotHost/Bind/WorldState.cs index 860adca..8b21620 100644 --- a/Tests/csharp/RobotHost/Bind/WorldState.cs +++ b/Tests/csharp/RobotHost/Bind/WorldState.cs @@ -64,6 +64,28 @@ public void OnSetTransform(ulong entityId, uint mask, in BridgeTransform transfo entity.Transform = tr2; } + public void OnSetPosition(ulong entityId, BridgeVec3 position) + { + if (_entities == null) + { + if (!_hasSingleEntity || entityId != _singleEntityId) + return; + + var tr = _singleEntity.Transform; + tr.Position = position; + _singleEntity.Transform = tr; + return; + } + + ref Entity entity = ref CollectionsMarshal.GetValueRefOrNullRef(_entities, entityId); + if (Unsafe.IsNullRef(ref entity)) + return; + + var tr2 = entity.Transform; + tr2.Position = position; + entity.Transform = tr2; + } + public void OnDestroy(ulong entityId) { if (_entities == null) diff --git a/Tests/csharp/RobotHost/Generated/Bridge.AllCommandDispatcher.g.cs b/Tests/csharp/RobotHost/Generated/Bridge.AllCommandDispatcher.g.cs index 821e617..81d801f 100644 --- a/Tests/csharp/RobotHost/Generated/Bridge.AllCommandDispatcher.g.cs +++ b/Tests/csharp/RobotHost/Generated/Bridge.AllCommandDispatcher.g.cs @@ -15,6 +15,7 @@ public abstract class BridgeAllHostApiBase public abstract void LoadAsset(ulong requestId, BridgeAssetType assetType, BridgeStringView assetKey); public abstract void SpawnEntity(ulong entityId, ulong prefabHandle, in BridgeTransform transform, uint flags); public abstract void SetTransform(ulong entityId, uint mask, in BridgeTransform transform); + public abstract void SetPosition(ulong entityId, BridgeVec3 position); public abstract void DestroyEntity(ulong entityId); public abstract void Log(BridgeLogLevel level, BridgeStringView message); } @@ -32,11 +33,11 @@ public static unsafe void DispatchFast(CommandStream stream, BridgeAllHostApiBas byte* cursor = (byte*)stream.Ptr; byte* end = cursor + (int)stream.Length; - while (cursor < end) - { - int remaining = (int)(end - cursor); - if (remaining < (int)sizeof(BridgeCommandHeader)) - break; + while (cursor < end) + { + int remaining = (int)(end - cursor); + if (remaining < (int)sizeof(BridgeCommandHeader)) + break; var header = (BridgeCommandHeader*)cursor; int size = header->Size; @@ -80,6 +81,15 @@ public static unsafe void DispatchFast(CommandStream stream, BridgeAllHostApiBas } break; } + case 0x5B16AE9Eu: + { + if (payloadSize == (uint)sizeof(DemoEntity.Bindings.HostArgs_SetPosition)) + { + ref readonly DemoEntity.Bindings.HostArgs_SetPosition a = ref *((DemoEntity.Bindings.HostArgs_SetPosition*)payloadPtr); + host.SetPosition(a.EntityId, a.Position); + } + break; + } case 0xC7C1C59Cu: { if (payloadSize == (uint)sizeof(DemoEntity.Bindings.HostArgs_DestroyEntity)) @@ -102,13 +112,13 @@ public static unsafe void DispatchFast(CommandStream stream, BridgeAllHostApiBas } } - cursor += size; - } - } - - public static unsafe void Dispatch(CommandStream stream, THost host) - where THost : class, DemoAsset.Bindings.IDemoAssetHostApi, DemoEntity.Bindings.IDemoEntityHostApi, DemoLog.Bindings.IDemoLogHostApi - { + cursor += size; + } + } + + public static unsafe void Dispatch(CommandStream stream, THost host) + where THost : class, DemoAsset.Bindings.IDemoAssetHostApi, DemoEntity.Bindings.IDemoEntityHostApi, DemoLog.Bindings.IDemoLogHostApi + { if (stream.IsEmpty || host == null) return; @@ -163,6 +173,15 @@ public static unsafe void Dispatch(CommandStream stream, THost host) } break; } + case 0x5B16AE9Eu: + { + if (payloadSize == (uint)sizeof(DemoEntity.Bindings.HostArgs_SetPosition)) + { + ref readonly DemoEntity.Bindings.HostArgs_SetPosition a = ref *((DemoEntity.Bindings.HostArgs_SetPosition*)payloadPtr); + host.SetPosition(a.EntityId, a.Position); + } + break; + } case 0xC7C1C59Cu: { if (payloadSize == (uint)sizeof(DemoEntity.Bindings.HostArgs_DestroyEntity)) diff --git a/Tests/csharp/RobotHost/Generated/DemoEntity.Ids.g.cs b/Tests/csharp/RobotHost/Generated/DemoEntity.Ids.g.cs index 139525c..c4a2c12 100644 --- a/Tests/csharp/RobotHost/Generated/DemoEntity.Ids.g.cs +++ b/Tests/csharp/RobotHost/Generated/DemoEntity.Ids.g.cs @@ -8,6 +8,7 @@ public enum HostFuncId : uint { SpawnEntity = 0xBCAA331Du, SetTransform = 0x20DA0B6Fu, + SetPosition = 0x5B16AE9Eu, DestroyEntity = 0xC7C1C59Cu, } diff --git a/Tests/csharp/RobotHost/Generated/DemoEntity.Structs.g.cs b/Tests/csharp/RobotHost/Generated/DemoEntity.Structs.g.cs index 48c0308..ff2166e 100644 --- a/Tests/csharp/RobotHost/Generated/DemoEntity.Structs.g.cs +++ b/Tests/csharp/RobotHost/Generated/DemoEntity.Structs.g.cs @@ -24,6 +24,13 @@ public struct HostArgs_SetTransform public BridgeTransform Transform; } + [StructLayout(LayoutKind.Sequential)] + public struct HostArgs_SetPosition + { + public ulong EntityId; + public BridgeVec3 Position; + } + [StructLayout(LayoutKind.Sequential)] public struct HostArgs_DestroyEntity { diff --git a/Tests/csharp/RobotHost/Generated/IDemoEntityHostApi.g.cs b/Tests/csharp/RobotHost/Generated/IDemoEntityHostApi.g.cs index 7274832..3636a7a 100644 --- a/Tests/csharp/RobotHost/Generated/IDemoEntityHostApi.g.cs +++ b/Tests/csharp/RobotHost/Generated/IDemoEntityHostApi.g.cs @@ -10,6 +10,7 @@ public interface IDemoEntityHostApi { void SpawnEntity(ulong entityId, ulong prefabHandle, in BridgeTransform transform, uint flags); void SetTransform(ulong entityId, uint mask, in BridgeTransform transform); + void SetPosition(ulong entityId, BridgeVec3 position); void DestroyEntity(ulong entityId); } } diff --git a/Tests/defs/demo_entity_api.def b/Tests/defs/demo_entity_api.def index d0710f4..221fcf9 100644 --- a/Tests/defs/demo_entity_api.def +++ b/Tests/defs/demo_entity_api.def @@ -2,5 +2,5 @@ BRIDGE_HOST_API(SpawnEntity, uint64_t entityId, uint64_t prefabHandle, BridgeTransform transform, uint32_t flags) BRIDGE_HOST_API(SetTransform, uint64_t entityId, uint32_t mask, BridgeTransform transform) +BRIDGE_HOST_API(SetPosition, uint64_t entityId, BridgeVec3 position) BRIDGE_HOST_API(DestroyEntity, uint64_t entityId) - diff --git a/Tests/unity/Assets/BridgeDemoGame/Editor/Performance/BridgeDispatchPerformanceTests.cs b/Tests/unity/Assets/BridgeDemoGame/Editor/Performance/BridgeDispatchPerformanceTests.cs index 18ef262..df2ef15 100644 --- a/Tests/unity/Assets/BridgeDemoGame/Editor/Performance/BridgeDispatchPerformanceTests.cs +++ b/Tests/unity/Assets/BridgeDemoGame/Editor/Performance/BridgeDispatchPerformanceTests.cs @@ -44,6 +44,12 @@ public void SetTransform(ulong entityId, uint mask, in BridgeTransform transform _ = transform; } + public void SetPosition(ulong entityId, BridgeVec3 position) + { + _ = entityId; + _ = position; + } + public void DestroyEntity(ulong entityId) { _ = entityId; diff --git a/Tests/unity/Assets/BridgeDemoGame/Generated/Bridge.AllCommandDispatcher.g.cs b/Tests/unity/Assets/BridgeDemoGame/Generated/Bridge.AllCommandDispatcher.g.cs index 821e617..81d801f 100644 --- a/Tests/unity/Assets/BridgeDemoGame/Generated/Bridge.AllCommandDispatcher.g.cs +++ b/Tests/unity/Assets/BridgeDemoGame/Generated/Bridge.AllCommandDispatcher.g.cs @@ -15,6 +15,7 @@ public abstract class BridgeAllHostApiBase public abstract void LoadAsset(ulong requestId, BridgeAssetType assetType, BridgeStringView assetKey); public abstract void SpawnEntity(ulong entityId, ulong prefabHandle, in BridgeTransform transform, uint flags); public abstract void SetTransform(ulong entityId, uint mask, in BridgeTransform transform); + public abstract void SetPosition(ulong entityId, BridgeVec3 position); public abstract void DestroyEntity(ulong entityId); public abstract void Log(BridgeLogLevel level, BridgeStringView message); } @@ -32,11 +33,11 @@ public static unsafe void DispatchFast(CommandStream stream, BridgeAllHostApiBas byte* cursor = (byte*)stream.Ptr; byte* end = cursor + (int)stream.Length; - while (cursor < end) - { - int remaining = (int)(end - cursor); - if (remaining < (int)sizeof(BridgeCommandHeader)) - break; + while (cursor < end) + { + int remaining = (int)(end - cursor); + if (remaining < (int)sizeof(BridgeCommandHeader)) + break; var header = (BridgeCommandHeader*)cursor; int size = header->Size; @@ -80,6 +81,15 @@ public static unsafe void DispatchFast(CommandStream stream, BridgeAllHostApiBas } break; } + case 0x5B16AE9Eu: + { + if (payloadSize == (uint)sizeof(DemoEntity.Bindings.HostArgs_SetPosition)) + { + ref readonly DemoEntity.Bindings.HostArgs_SetPosition a = ref *((DemoEntity.Bindings.HostArgs_SetPosition*)payloadPtr); + host.SetPosition(a.EntityId, a.Position); + } + break; + } case 0xC7C1C59Cu: { if (payloadSize == (uint)sizeof(DemoEntity.Bindings.HostArgs_DestroyEntity)) @@ -102,13 +112,13 @@ public static unsafe void DispatchFast(CommandStream stream, BridgeAllHostApiBas } } - cursor += size; - } - } - - public static unsafe void Dispatch(CommandStream stream, THost host) - where THost : class, DemoAsset.Bindings.IDemoAssetHostApi, DemoEntity.Bindings.IDemoEntityHostApi, DemoLog.Bindings.IDemoLogHostApi - { + cursor += size; + } + } + + public static unsafe void Dispatch(CommandStream stream, THost host) + where THost : class, DemoAsset.Bindings.IDemoAssetHostApi, DemoEntity.Bindings.IDemoEntityHostApi, DemoLog.Bindings.IDemoLogHostApi + { if (stream.IsEmpty || host == null) return; @@ -163,6 +173,15 @@ public static unsafe void Dispatch(CommandStream stream, THost host) } break; } + case 0x5B16AE9Eu: + { + if (payloadSize == (uint)sizeof(DemoEntity.Bindings.HostArgs_SetPosition)) + { + ref readonly DemoEntity.Bindings.HostArgs_SetPosition a = ref *((DemoEntity.Bindings.HostArgs_SetPosition*)payloadPtr); + host.SetPosition(a.EntityId, a.Position); + } + break; + } case 0xC7C1C59Cu: { if (payloadSize == (uint)sizeof(DemoEntity.Bindings.HostArgs_DestroyEntity)) diff --git a/Tests/unity/Assets/BridgeDemoGame/Generated/DemoEntity.Ids.g.cs b/Tests/unity/Assets/BridgeDemoGame/Generated/DemoEntity.Ids.g.cs index 139525c..c4a2c12 100644 --- a/Tests/unity/Assets/BridgeDemoGame/Generated/DemoEntity.Ids.g.cs +++ b/Tests/unity/Assets/BridgeDemoGame/Generated/DemoEntity.Ids.g.cs @@ -8,6 +8,7 @@ public enum HostFuncId : uint { SpawnEntity = 0xBCAA331Du, SetTransform = 0x20DA0B6Fu, + SetPosition = 0x5B16AE9Eu, DestroyEntity = 0xC7C1C59Cu, } diff --git a/Tests/unity/Assets/BridgeDemoGame/Generated/DemoEntity.Structs.g.cs b/Tests/unity/Assets/BridgeDemoGame/Generated/DemoEntity.Structs.g.cs index 48c0308..ff2166e 100644 --- a/Tests/unity/Assets/BridgeDemoGame/Generated/DemoEntity.Structs.g.cs +++ b/Tests/unity/Assets/BridgeDemoGame/Generated/DemoEntity.Structs.g.cs @@ -24,6 +24,13 @@ public struct HostArgs_SetTransform public BridgeTransform Transform; } + [StructLayout(LayoutKind.Sequential)] + public struct HostArgs_SetPosition + { + public ulong EntityId; + public BridgeVec3 Position; + } + [StructLayout(LayoutKind.Sequential)] public struct HostArgs_DestroyEntity { diff --git a/Tests/unity/Assets/BridgeDemoGame/Generated/IDemoEntityHostApi.g.cs b/Tests/unity/Assets/BridgeDemoGame/Generated/IDemoEntityHostApi.g.cs index 7274832..3636a7a 100644 --- a/Tests/unity/Assets/BridgeDemoGame/Generated/IDemoEntityHostApi.g.cs +++ b/Tests/unity/Assets/BridgeDemoGame/Generated/IDemoEntityHostApi.g.cs @@ -10,6 +10,7 @@ public interface IDemoEntityHostApi { void SpawnEntity(ulong entityId, ulong prefabHandle, in BridgeTransform transform, uint flags); void SetTransform(ulong entityId, uint mask, in BridgeTransform transform); + void SetPosition(ulong entityId, BridgeVec3 position); void DestroyEntity(ulong entityId); } } diff --git a/Tests/unity/Assets/BridgeDemoGame/PlayModeTests/BridgeMonoGcTests.cs b/Tests/unity/Assets/BridgeDemoGame/PlayModeTests/BridgeMonoGcTests.cs index 976fb59..eaa7f53 100644 --- a/Tests/unity/Assets/BridgeDemoGame/PlayModeTests/BridgeMonoGcTests.cs +++ b/Tests/unity/Assets/BridgeDemoGame/PlayModeTests/BridgeMonoGcTests.cs @@ -44,6 +44,12 @@ public void SetTransform(ulong entityId, uint mask, in BridgeTransform transform _ = transform; } + public void SetPosition(ulong entityId, BridgeVec3 position) + { + _ = entityId; + _ = position; + } + public void DestroyEntity(ulong entityId) { _ = entityId; diff --git a/Tests/unity/Assets/BridgeDemoGame/PlayModeTests/BridgeRuntimeSmokeTests.cs b/Tests/unity/Assets/BridgeDemoGame/PlayModeTests/BridgeRuntimeSmokeTests.cs index ce61580..9a4aa42 100644 --- a/Tests/unity/Assets/BridgeDemoGame/PlayModeTests/BridgeRuntimeSmokeTests.cs +++ b/Tests/unity/Assets/BridgeDemoGame/PlayModeTests/BridgeRuntimeSmokeTests.cs @@ -43,6 +43,12 @@ public override void SetTransform(ulong entityId, uint mask, in BridgeTransform _ = transform; } + public override void SetPosition(ulong entityId, BridgeVec3 position) + { + _ = entityId; + _ = position; + } + public override void DestroyEntity(ulong entityId) { _ = entityId; diff --git a/Tests/unity/Assets/BridgeDemoGame/PlayModeTests/BridgeSourceModeThroughputTests.cs b/Tests/unity/Assets/BridgeDemoGame/PlayModeTests/BridgeSourceModeThroughputTests.cs index 36e175f..1a9c051 100644 --- a/Tests/unity/Assets/BridgeDemoGame/PlayModeTests/BridgeSourceModeThroughputTests.cs +++ b/Tests/unity/Assets/BridgeDemoGame/PlayModeTests/BridgeSourceModeThroughputTests.cs @@ -46,6 +46,12 @@ public override void SetTransform(ulong entityId, uint mask, in BridgeTransform _ = transform; } + public override void SetPosition(ulong entityId, BridgeVec3 position) + { + _ = entityId; + _ = position; + } + public override void DestroyEntity(ulong entityId) { _ = entityId; diff --git a/Tests/unity/Assets/BridgeDemoGame/Runtime/Host/DemoGameUnityHostApi.Entity.cs b/Tests/unity/Assets/BridgeDemoGame/Runtime/Host/DemoGameUnityHostApi.Entity.cs index 9010206..5727a30 100644 --- a/Tests/unity/Assets/BridgeDemoGame/Runtime/Host/DemoGameUnityHostApi.Entity.cs +++ b/Tests/unity/Assets/BridgeDemoGame/Runtime/Host/DemoGameUnityHostApi.Entity.cs @@ -41,6 +41,18 @@ public override void SetTransform(ulong entityId, uint mask, in BridgeTransform ApplyTransform(go.transform, transform, mask); } + public override void SetPosition(ulong entityId, BridgeVec3 position) + { + Commands++; + Transforms++; + + if (!_enableRendering) + return; + + if (_entities.TryGetValue(entityId, out GameObject go) && go != null) + go.transform.position = new Vector3(position.X, position.Y, position.Z); + } + public override void DestroyEntity(ulong entityId) { Commands++; From 25f9c9c9674d9000eebd43cc9e10985c1202252e Mon Sep 17 00:00:00 2001 From: lcals Date: Wed, 21 Jan 2026 20:25:52 +0800 Subject: [PATCH 23/33] Perf: record SetPosition optimization --- Core/docs/PERF_OPTIMIZATIONS.md | 31 +++++++++++++++++++++++++++++++ README.md | 28 +++++++++++++++------------- Tools/RunPerf.ps1 | 3 +++ 3 files changed, 49 insertions(+), 13 deletions(-) diff --git a/Core/docs/PERF_OPTIMIZATIONS.md b/Core/docs/PERF_OPTIMIZATIONS.md index 00fb12f..3df010b 100644 --- a/Core/docs/PERF_OPTIMIZATIONS.md +++ b/Core/docs/PERF_OPTIMIZATIONS.md @@ -85,6 +85,37 @@ pwsh -NoProfile -ExecutionPolicy Bypass -File Tools/RunPerf.ps1 -UnityVersion 60 **效果** - IL2CPP 输出中 `streams[i]` 从 `GetAt(...)` 变为通过 `GetAddressAt(0)` 获取底层指针后直接索引读取(减少边界检查/拷贝开销)。 +### 4) 用更小的 Host 命令替代 “每帧全量 Transform” + +**引入** +- git:`d5fa6a1` +- 验证:Unity `6000.0.40f1` + - tag=`post_d5fa6a1_setposition`;runId=`20260121_202154` + - tag=`post_d5fa6a1_setposition_rerun`;runId=`20260121_202436` +- 对比基线:tag=`post_2772303_r5`;runId=`20260121_193135` + +**现象** +- Demo 业务每帧只更新 position.x,但仍通过 `SetTransform(entityId, mask=1, BridgeTransform)` 发送全量 `BridgeTransform`(payload 64B,单 tick stream=80B)。 +- 在 10k bots 下,这会放大跨边界拷贝与 Host 侧解析成本。 + +**改动** +- 为 `DemoEntity` 增加更小 payload 的 Host API:`SetPosition(entityId, BridgeVec3 position)`。 +- Demo 业务侧(C++)每帧改为发 `SetPosition`,把每 tick stream 从 80B 降到 40B。 +- RobotHost/Unity Host 增加对应实现(计入 `Transforms` 统计;Unity 侧直接设置 `Transform.position`)。 + +**位置** +- 定义:`Tests/defs/demo_entity_api.def` +- 生成器:`Core/Tools/BridgeGen/Program.cs`(补齐 `BridgeVec3/BridgeQuat` 类型映射) +- Demo 业务:`Tests/cpp/demo_game/src/demo_asset_app.cpp` +- RobotHost:`Tests/csharp/RobotHost/Bind/RobotHostApi.cs`、`Tests/csharp/RobotHost/Bind/WorldState.cs` +- Unity Host:`Tests/unity/Assets/BridgeDemoGame/Runtime/Host/DemoGameUnityHostApi.Entity.cs` + +**效果(本机)** +- Unity IL2CPP Source(repeat=5) + - 1k ticks/s:约 `50.34M` → `55.52M` + - 10k ticks/s:约 `31.06M` → `33.67M` +- `total_bytes` 约减半(10k*300:`240,000,000` → `120,000,000`),解析与拷贝成本显著下降。 + ## 优化流程建议(只在提升时记录/提交) 1. 做一次“小步”改动(只动一个热点点位)。 diff --git a/README.md b/README.md index f9ea901..a88b9cc 100644 --- a/README.md +++ b/README.md @@ -79,21 +79,23 @@ powershell -ExecutionPolicy Bypass -File Tools/RunPerf.ps1 -Bots 1000 -Frames 30 下表由 `Tools/RunPerf.ps1` 自动追加(更完整的数据仍以 `build/perf_history.jsonl` 为准)。 - -| tsUtc | runId | tag | git | robothost_null cmd/s | robot_runner cmd/s | robot_runner ticks/s | il2cpp_source 1k ticks/s | il2cpp_source 10k ticks/s | -|---|---|---|---|---:|---:|---:|---:|---:| -| 2026-01-21T09:46:22.1895560Z | 20260121_174537 | post_23e79d6 | 23e79d6 | 23447208 | 58632532 | 58823529.41 | 50646588.11 | 32289520.76 | -| 2026-01-21T09:41:02.1140619Z | 20260121_174007 | il2cpp_opt4_revert_typed | 46c54af* | 24891834 | 56602493 | 56603773.58 | 50043370.92 | 31107456.56 | -| 2026-01-21T09:37:31.9048310Z | 20260121_173649 | il2cpp_opt4_rerun | 46c54af* | 25635026 | 61322383 | 61224489.80 | 48721863.12 | 31246354.59 | -| 2026-01-21T09:34:52.0737234Z | 20260121_173358 | il2cpp_opt4_typed_fix | 46c54af* | 24150548 | 60397744 | 60000000.00 | 49961696.03 | 29169514.75 | -| 2026-01-21T09:33:07.3524273Z | 20260121_173240 | il2cpp_opt4_typed | 46c54af* | 25081209 | 58809475 | 58823529.41 | n/a | n/a | -| 2026-01-21T09:18:09.6002287Z | 20260121_161722 | | 71d7614* | 24554530 | 60572076 | 60000000.00 | n/a | n/a | -| 2026-01-21T09:17:51.7355502Z | 20260121_171649 | il2cpp_opt3_gen | 46c54af* | 25158498 | 55715319 | 55555555.56 | 46472000.62 | 31124464.66 | -| 2026-01-21T09:14:04.8744916Z | 20260121_171308 | il2cpp_opt2 | 46c54af* | 25314022 | 57046355 | 56603773.58 | 49433980.92 | 33451864.44 | -| 2026-01-21T09:09:53.4839892Z | 20260121_160935 | dispatchfast | 71d7614* | 24999667 | 56703065 | 56603773.58 | n/a | n/a | -| 2026-01-21T09:02:21.8370259Z | 20260121_170122 | post_commit | 46c54af | 22331042 | 60740046 | 61224489.80 | 47947066.44 | 32652492.58 | + +| tsUtc | runId | tag | git | robothost_null cmd/s | robot_runner cmd/s | robot_runner ticks/s | il2cpp_source 1k ticks/s | il2cpp_source 10k ticks/s | +|---|---|---|---|---:|---:|---:|---:|---:| +| 2026-01-21T12:22:32.4341938Z | 20260121_202154 | post_d5fa6a1_setposition | d5fa6a1 | 27401987 | 76187915 | 76923076.92 | 55518543.19 | 33672905.88 | +| 2026-01-21T12:08:02.0093094Z | 20260121_200706 | baseline_r11 | 0d3443a | 22894010 | 57608306 | 57692307.69 | 50491450.11 | 31203746.95 | +| 2026-01-21T11:32:08.5443073Z | 20260121_193135 | post_2772303_r5 | 0d3443a | 22939969 | 59002556 | 58823529.41 | 50338948.92 | 31063843.45 | +| 2026-01-21T11:30:02.2954247Z | 20260121_192929 | post_2772303 | 0d3443a | 24758375 | 54120785 | 54545454.55 | 50497399.38 | 30900438.79 | +| 2026-01-21T11:14:51.1784595Z | 20260121_191407 | baseline_payload_checks | 98be1d5 | 23288884 | 58962241 | 58823529.41 | 41732162.98 | 30506561.45 | +| 2026-01-21T11:04:08.5733790Z | 20260121_190339 | baseline_pair | 98be1d5 | 25024758 | 59328831 | 58823529.41 | 49724855.80 | 30624025.77 | +| 2026-01-21T11:00:11.1960690Z | 20260121_185933 | baseline_rerun2 | 98be1d5 | 24866432 | 60605938 | 60000000.00 | 49637645.19 | 30804679.85 | +| 2026-01-21T10:57:13.8541013Z | 20260121_185636 | baseline_rerun | 98be1d5 | 24181264 | 60877586 | 61224489.80 | 48282743.75 | 32490177.14 | +| 2026-01-21T09:46:22.1895560Z | 20260121_174537 | post_23e79d6 | 23e79d6 | 23447208 | 58632532 | 58823529.41 | 50646588.11 | 32289520.76 | +| 2026-01-21T09:02:21.8370259Z | 20260121_170122 | post_commit | 46c54af | 22331042 | 60740046 | 61224489.80 | 47947066.44 | 32652492.58 | + + diff --git a/Tools/RunPerf.ps1 b/Tools/RunPerf.ps1 index c18c65a..5aaf903 100644 --- a/Tools/RunPerf.ps1 +++ b/Tools/RunPerf.ps1 @@ -487,6 +487,9 @@ function Update-PerfReadme( if ([string]::IsNullOrWhiteSpace($runId)) { continue } if (-not $seen.Add($runId)) { continue } + $dirty = Try-Get { [bool]$rec.git.dirty } + if ($dirty) { continue } + $tsUtcObj = Try-Get { $rec.tsUtc } $tsText = $null if ($tsUtcObj -is [DateTime]) From c4840551bcf1f79c09aa36f000cba0c71fa1a022 Mon Sep 17 00:00:00 2001 From: lcals Date: Wed, 21 Jan 2026 20:44:50 +0800 Subject: [PATCH 24/33] perf: generic DispatchFast for IL2CPP devirtualization --- Core/Tools/BridgeGen/Program.cs | 6 +++++- .../RobotHost/Generated/Bridge.AllCommandDispatcher.g.cs | 6 +++++- .../Generated/Bridge.AllCommandDispatcher.g.cs | 6 +++++- 3 files changed, 15 insertions(+), 3 deletions(-) diff --git a/Core/Tools/BridgeGen/Program.cs b/Core/Tools/BridgeGen/Program.cs index 6d1bd2b..52ba442 100644 --- a/Core/Tools/BridgeGen/Program.cs +++ b/Core/Tools/BridgeGen/Program.cs @@ -515,7 +515,8 @@ private static string EmitAllDispatcher(IReadOnlyList modules) sb.AppendLine(" /// "); sb.AppendLine(" public static class BridgeAllCommandDispatcher"); sb.AppendLine(" {"); - sb.AppendLine(" public static unsafe void DispatchFast(CommandStream stream, BridgeAllHostApiBase host)"); + sb.AppendLine(" public static unsafe void DispatchFast(CommandStream stream, THost host)"); + sb.AppendLine(" where THost : BridgeAllHostApiBase"); sb.AppendLine(" {"); sb.AppendLine(" if (host == null || stream.Ptr == System.IntPtr.Zero || stream.Length == 0)"); sb.AppendLine(" return;"); @@ -595,6 +596,9 @@ private static string EmitAllDispatcher(IReadOnlyList modules) sb.AppendLine(" }"); sb.AppendLine(" }"); sb.AppendLine(); + sb.AppendLine(" public static unsafe void DispatchFast(CommandStream stream, BridgeAllHostApiBase host)"); + sb.AppendLine(" => DispatchFast(stream, host);"); + sb.AppendLine(); sb.AppendLine(" public static unsafe void Dispatch(CommandStream stream, THost host)"); sb.Append(" where THost : class"); diff --git a/Tests/csharp/RobotHost/Generated/Bridge.AllCommandDispatcher.g.cs b/Tests/csharp/RobotHost/Generated/Bridge.AllCommandDispatcher.g.cs index 81d801f..9188224 100644 --- a/Tests/csharp/RobotHost/Generated/Bridge.AllCommandDispatcher.g.cs +++ b/Tests/csharp/RobotHost/Generated/Bridge.AllCommandDispatcher.g.cs @@ -25,7 +25,8 @@ public abstract class BridgeAllHostApiBase /// public static class BridgeAllCommandDispatcher { - public static unsafe void DispatchFast(CommandStream stream, BridgeAllHostApiBase host) + public static unsafe void DispatchFast(CommandStream stream, THost host) + where THost : BridgeAllHostApiBase { if (host == null || stream.Ptr == System.IntPtr.Zero || stream.Length == 0) return; @@ -116,6 +117,9 @@ public static unsafe void DispatchFast(CommandStream stream, BridgeAllHostApiBas } } + public static unsafe void DispatchFast(CommandStream stream, BridgeAllHostApiBase host) + => DispatchFast(stream, host); + public static unsafe void Dispatch(CommandStream stream, THost host) where THost : class, DemoAsset.Bindings.IDemoAssetHostApi, DemoEntity.Bindings.IDemoEntityHostApi, DemoLog.Bindings.IDemoLogHostApi { diff --git a/Tests/unity/Assets/BridgeDemoGame/Generated/Bridge.AllCommandDispatcher.g.cs b/Tests/unity/Assets/BridgeDemoGame/Generated/Bridge.AllCommandDispatcher.g.cs index 81d801f..9188224 100644 --- a/Tests/unity/Assets/BridgeDemoGame/Generated/Bridge.AllCommandDispatcher.g.cs +++ b/Tests/unity/Assets/BridgeDemoGame/Generated/Bridge.AllCommandDispatcher.g.cs @@ -25,7 +25,8 @@ public abstract class BridgeAllHostApiBase /// public static class BridgeAllCommandDispatcher { - public static unsafe void DispatchFast(CommandStream stream, BridgeAllHostApiBase host) + public static unsafe void DispatchFast(CommandStream stream, THost host) + where THost : BridgeAllHostApiBase { if (host == null || stream.Ptr == System.IntPtr.Zero || stream.Length == 0) return; @@ -116,6 +117,9 @@ public static unsafe void DispatchFast(CommandStream stream, BridgeAllHostApiBas } } + public static unsafe void DispatchFast(CommandStream stream, BridgeAllHostApiBase host) + => DispatchFast(stream, host); + public static unsafe void Dispatch(CommandStream stream, THost host) where THost : class, DemoAsset.Bindings.IDemoAssetHostApi, DemoEntity.Bindings.IDemoEntityHostApi, DemoLog.Bindings.IDemoLogHostApi { From 283a88624414a05d7031045bdb5f93c17107412f Mon Sep 17 00:00:00 2001 From: lcals Date: Wed, 21 Jan 2026 21:00:26 +0800 Subject: [PATCH 25/33] perf: record DispatchFast generic benchmark --- Core/docs/PERF_OPTIMIZATIONS.md | 25 +++++++++++++++++++++++++ README.md | 3 +++ 2 files changed, 28 insertions(+) diff --git a/Core/docs/PERF_OPTIMIZATIONS.md b/Core/docs/PERF_OPTIMIZATIONS.md index 3df010b..bcf0449 100644 --- a/Core/docs/PERF_OPTIMIZATIONS.md +++ b/Core/docs/PERF_OPTIMIZATIONS.md @@ -116,6 +116,31 @@ pwsh -NoProfile -ExecutionPolicy Bypass -File Tools/RunPerf.ps1 -UnityVersion 60 - 10k ticks/s:约 `31.06M` → `33.67M` - `total_bytes` 约减半(10k*300:`240,000,000` → `120,000,000`),解析与拷贝成本显著下降。 +### 5) `DispatchFast` 改为泛型(避免 Host 参数上溯) + +**引入** +- git:`c484055` +- 验证:Unity `6000.0.40f1` + - tag=`post_c484055_dispatchfast_generic`;runId=`20260121_205232`(repeat=3) + - tag=`post_c484055_dispatchfast_generic_rerun`;runId=`20260121_205751`(repeat=3) +- 对比:tag=`post_d5fa6a1_setposition`;runId=`20260121_202154`(repeat=5) + +**现象(IL2CPP 输出)** +- 调用点如果把 Host 上溯到 `BridgeAllHostApiBase`,IL2CPP 的热路径更容易固定走虚调用分发(`VirtualActionInvoker`)。 + +**改动** +- 把生成的 `DispatchFast` 改成泛型:`DispatchFast(CommandStream, THost host) where THost : BridgeAllHostApiBase`。 +- 保留旧签名重载 `DispatchFast(CommandStream, BridgeAllHostApiBase)`,内部 forward 到泛型版本(兼容既有调用点)。 + +**位置** +- 生成器:`Core/Tools/BridgeGen/Program.cs` +- 生成物: + - `Tests/csharp/RobotHost/Generated/Bridge.AllCommandDispatcher.g.cs` + - `Tests/unity/Assets/BridgeDemoGame/Generated/Bridge.AllCommandDispatcher.g.cs` + +**效果** +- Unity IL2CPP Source 的 `ticks/s`(1k/10k)在本机有稳定提升(见 `README.md` 性能摘要表与对应 runId)。 + ## 优化流程建议(只在提升时记录/提交) 1. 做一次“小步”改动(只动一个热点点位)。 diff --git a/README.md b/README.md index a88b9cc..81fc430 100644 --- a/README.md +++ b/README.md @@ -82,6 +82,7 @@ powershell -ExecutionPolicy Bypass -File Tools/RunPerf.ps1 -Bots 1000 -Frames 30 | tsUtc | runId | tag | git | robothost_null cmd/s | robot_runner cmd/s | robot_runner ticks/s | il2cpp_source 1k ticks/s | il2cpp_source 10k ticks/s | |---|---|---|---|---:|---:|---:|---:|---:| +| 2026-01-21T12:53:22.0211694Z | 20260121_205232 | post_c484055_dispatchfast_generic | c484055 | 25094858 | 76026471 | 76923076.92 | 56037059.18 | 34641512.31 | | 2026-01-21T12:22:32.4341938Z | 20260121_202154 | post_d5fa6a1_setposition | d5fa6a1 | 27401987 | 76187915 | 76923076.92 | 55518543.19 | 33672905.88 | | 2026-01-21T12:08:02.0093094Z | 20260121_200706 | baseline_r11 | 0d3443a | 22894010 | 57608306 | 57692307.69 | 50491450.11 | 31203746.95 | | 2026-01-21T11:32:08.5443073Z | 20260121_193135 | post_2772303_r5 | 0d3443a | 22939969 | 59002556 | 58823529.41 | 50338948.92 | 31063843.45 | @@ -99,3 +100,5 @@ powershell -ExecutionPolicy Bypass -File Tools/RunPerf.ps1 -Bots 1000 -Frames 30 + + From 912e0e56ad4df0abcf2be4c21f4b3b734c2c71b6 Mon Sep 17 00:00:00 2001 From: lcals Date: Wed, 21 Jan 2026 21:05:16 +0800 Subject: [PATCH 26/33] perf: add DispatchFastUnchecked for trusted streams --- Core/Tools/BridgeGen/Program.cs | 71 ++++++++++++++ .../Bridge.AllCommandDispatcher.g.cs | 93 ++++++++++++++++--- .../Bridge.AllCommandDispatcher.g.cs | 93 ++++++++++++++++--- .../PlayModeTests/BridgeRuntimeSmokeTests.cs | 2 +- .../BridgeSourceModeThroughputTests.cs | 2 +- .../Runtime/Runner/DemoGameUnityRunner.cs | 2 +- 6 files changed, 236 insertions(+), 27 deletions(-) diff --git a/Core/Tools/BridgeGen/Program.cs b/Core/Tools/BridgeGen/Program.cs index 52ba442..c321960 100644 --- a/Core/Tools/BridgeGen/Program.cs +++ b/Core/Tools/BridgeGen/Program.cs @@ -596,6 +596,77 @@ private static string EmitAllDispatcher(IReadOnlyList modules) sb.AppendLine(" }"); sb.AppendLine(" }"); sb.AppendLine(); + + sb.AppendLine(" public static unsafe void DispatchFastUnchecked(CommandStream stream, THost host)"); + sb.AppendLine(" where THost : BridgeAllHostApiBase"); + sb.AppendLine(" {"); + sb.AppendLine(" if (host == null || stream.Ptr == System.IntPtr.Zero || stream.Length == 0)"); + sb.AppendLine(" return;"); + sb.AppendLine(); + sb.AppendLine(" byte* cursor = (byte*)stream.Ptr;"); + sb.AppendLine(" byte* end = cursor + (int)stream.Length;"); + sb.AppendLine(); + sb.AppendLine(" while (cursor < end)"); + sb.AppendLine(" {"); + sb.AppendLine(" int remaining = (int)(end - cursor);"); + sb.AppendLine(" if (remaining < (int)sizeof(BridgeCmdCallHost))"); + sb.AppendLine(" break;"); + sb.AppendLine(); + sb.AppendLine(" var cmd = (BridgeCmdCallHost*)cursor;"); + sb.AppendLine(" int size = cmd->Header.Size;"); + sb.AppendLine(" if ((uint)size < (uint)sizeof(BridgeCmdCallHost) || (uint)size > (uint)remaining)"); + sb.AppendLine(" break;"); + sb.AppendLine(); + sb.AppendLine(" byte* payloadPtr = cursor + sizeof(BridgeCmdCallHost);"); + sb.AppendLine(); + sb.AppendLine(" switch (cmd->FuncId)"); + sb.AppendLine(" {"); + + foreach (var m in modules) + { + if (m.Model.HostFns.Count == 0) + continue; + + foreach (var fn in m.Model.HostFns) + { + uint id = ComputeHostFuncId(m.Module, fn.Name); + sb.AppendLine($" case 0x{id:X8}u:"); + sb.AppendLine(" {"); + sb.Append(" ref readonly "); + sb.Append(m.CsNamespace); + sb.Append(".HostArgs_"); + sb.Append(fn.Name); + sb.Append(" a = ref *(("); + sb.Append(m.CsNamespace); + sb.Append(".HostArgs_"); + sb.Append(fn.Name); + sb.AppendLine("*)payloadPtr);"); + sb.Append(" host."); + sb.Append(fn.Name); + sb.Append('('); + for (int i = 0; i < fn.Args.Count; i++) + { + if (i > 0) sb.Append(", "); + var arg = fn.Args[i]; + string field = $"a.{ToPascal(arg.Name)}"; + sb.Append(MapCsHostArgExpr(arg.CppType, field)); + } + sb.AppendLine(");"); + sb.AppendLine(" break;"); + sb.AppendLine(" }"); + } + } + + sb.AppendLine(" }"); + sb.AppendLine(); + sb.AppendLine(" cursor += size;"); + sb.AppendLine(" }"); + sb.AppendLine(" }"); + sb.AppendLine(); + sb.AppendLine(" public static unsafe void DispatchFastUnchecked(CommandStream stream, BridgeAllHostApiBase host)"); + sb.AppendLine(" => DispatchFastUnchecked(stream, host);"); + sb.AppendLine(); + sb.AppendLine(" public static unsafe void DispatchFast(CommandStream stream, BridgeAllHostApiBase host)"); sb.AppendLine(" => DispatchFast(stream, host);"); sb.AppendLine(); diff --git a/Tests/csharp/RobotHost/Generated/Bridge.AllCommandDispatcher.g.cs b/Tests/csharp/RobotHost/Generated/Bridge.AllCommandDispatcher.g.cs index 9188224..4f8cff8 100644 --- a/Tests/csharp/RobotHost/Generated/Bridge.AllCommandDispatcher.g.cs +++ b/Tests/csharp/RobotHost/Generated/Bridge.AllCommandDispatcher.g.cs @@ -25,9 +25,9 @@ public abstract class BridgeAllHostApiBase /// public static class BridgeAllCommandDispatcher { - public static unsafe void DispatchFast(CommandStream stream, THost host) - where THost : BridgeAllHostApiBase - { + public static unsafe void DispatchFast(CommandStream stream, THost host) + where THost : BridgeAllHostApiBase + { if (host == null || stream.Ptr == System.IntPtr.Zero || stream.Length == 0) return; @@ -113,15 +113,84 @@ public static unsafe void DispatchFast(CommandStream stream, THost host) } } - cursor += size; - } - } - - public static unsafe void DispatchFast(CommandStream stream, BridgeAllHostApiBase host) - => DispatchFast(stream, host); - - public static unsafe void Dispatch(CommandStream stream, THost host) - where THost : class, DemoAsset.Bindings.IDemoAssetHostApi, DemoEntity.Bindings.IDemoEntityHostApi, DemoLog.Bindings.IDemoLogHostApi + cursor += size; + } + } + + public static unsafe void DispatchFastUnchecked(CommandStream stream, THost host) + where THost : BridgeAllHostApiBase + { + if (host == null || stream.Ptr == System.IntPtr.Zero || stream.Length == 0) + return; + + byte* cursor = (byte*)stream.Ptr; + byte* end = cursor + (int)stream.Length; + + while (cursor < end) + { + int remaining = (int)(end - cursor); + if (remaining < (int)sizeof(BridgeCmdCallHost)) + break; + + var cmd = (BridgeCmdCallHost*)cursor; + int size = cmd->Header.Size; + if ((uint)size < (uint)sizeof(BridgeCmdCallHost) || (uint)size > (uint)remaining) + break; + + byte* payloadPtr = cursor + sizeof(BridgeCmdCallHost); + + switch (cmd->FuncId) + { + case 0x82A5E93Au: + { + ref readonly DemoAsset.Bindings.HostArgs_LoadAsset a = ref *((DemoAsset.Bindings.HostArgs_LoadAsset*)payloadPtr); + host.LoadAsset(a.RequestId, a.AssetType, a.AssetKey); + break; + } + case 0xBCAA331Du: + { + ref readonly DemoEntity.Bindings.HostArgs_SpawnEntity a = ref *((DemoEntity.Bindings.HostArgs_SpawnEntity*)payloadPtr); + host.SpawnEntity(a.EntityId, a.PrefabHandle, in a.Transform, a.Flags); + break; + } + case 0x20DA0B6Fu: + { + ref readonly DemoEntity.Bindings.HostArgs_SetTransform a = ref *((DemoEntity.Bindings.HostArgs_SetTransform*)payloadPtr); + host.SetTransform(a.EntityId, a.Mask, in a.Transform); + break; + } + case 0x5B16AE9Eu: + { + ref readonly DemoEntity.Bindings.HostArgs_SetPosition a = ref *((DemoEntity.Bindings.HostArgs_SetPosition*)payloadPtr); + host.SetPosition(a.EntityId, a.Position); + break; + } + case 0xC7C1C59Cu: + { + ref readonly DemoEntity.Bindings.HostArgs_DestroyEntity a = ref *((DemoEntity.Bindings.HostArgs_DestroyEntity*)payloadPtr); + host.DestroyEntity(a.EntityId); + break; + } + case 0xDA3184A2u: + { + ref readonly DemoLog.Bindings.HostArgs_Log a = ref *((DemoLog.Bindings.HostArgs_Log*)payloadPtr); + host.Log(a.Level, a.Message); + break; + } + } + + cursor += size; + } + } + + public static unsafe void DispatchFastUnchecked(CommandStream stream, BridgeAllHostApiBase host) + => DispatchFastUnchecked(stream, host); + + public static unsafe void DispatchFast(CommandStream stream, BridgeAllHostApiBase host) + => DispatchFast(stream, host); + + public static unsafe void Dispatch(CommandStream stream, THost host) + where THost : class, DemoAsset.Bindings.IDemoAssetHostApi, DemoEntity.Bindings.IDemoEntityHostApi, DemoLog.Bindings.IDemoLogHostApi { if (stream.IsEmpty || host == null) return; diff --git a/Tests/unity/Assets/BridgeDemoGame/Generated/Bridge.AllCommandDispatcher.g.cs b/Tests/unity/Assets/BridgeDemoGame/Generated/Bridge.AllCommandDispatcher.g.cs index 9188224..4f8cff8 100644 --- a/Tests/unity/Assets/BridgeDemoGame/Generated/Bridge.AllCommandDispatcher.g.cs +++ b/Tests/unity/Assets/BridgeDemoGame/Generated/Bridge.AllCommandDispatcher.g.cs @@ -25,9 +25,9 @@ public abstract class BridgeAllHostApiBase /// public static class BridgeAllCommandDispatcher { - public static unsafe void DispatchFast(CommandStream stream, THost host) - where THost : BridgeAllHostApiBase - { + public static unsafe void DispatchFast(CommandStream stream, THost host) + where THost : BridgeAllHostApiBase + { if (host == null || stream.Ptr == System.IntPtr.Zero || stream.Length == 0) return; @@ -113,15 +113,84 @@ public static unsafe void DispatchFast(CommandStream stream, THost host) } } - cursor += size; - } - } - - public static unsafe void DispatchFast(CommandStream stream, BridgeAllHostApiBase host) - => DispatchFast(stream, host); - - public static unsafe void Dispatch(CommandStream stream, THost host) - where THost : class, DemoAsset.Bindings.IDemoAssetHostApi, DemoEntity.Bindings.IDemoEntityHostApi, DemoLog.Bindings.IDemoLogHostApi + cursor += size; + } + } + + public static unsafe void DispatchFastUnchecked(CommandStream stream, THost host) + where THost : BridgeAllHostApiBase + { + if (host == null || stream.Ptr == System.IntPtr.Zero || stream.Length == 0) + return; + + byte* cursor = (byte*)stream.Ptr; + byte* end = cursor + (int)stream.Length; + + while (cursor < end) + { + int remaining = (int)(end - cursor); + if (remaining < (int)sizeof(BridgeCmdCallHost)) + break; + + var cmd = (BridgeCmdCallHost*)cursor; + int size = cmd->Header.Size; + if ((uint)size < (uint)sizeof(BridgeCmdCallHost) || (uint)size > (uint)remaining) + break; + + byte* payloadPtr = cursor + sizeof(BridgeCmdCallHost); + + switch (cmd->FuncId) + { + case 0x82A5E93Au: + { + ref readonly DemoAsset.Bindings.HostArgs_LoadAsset a = ref *((DemoAsset.Bindings.HostArgs_LoadAsset*)payloadPtr); + host.LoadAsset(a.RequestId, a.AssetType, a.AssetKey); + break; + } + case 0xBCAA331Du: + { + ref readonly DemoEntity.Bindings.HostArgs_SpawnEntity a = ref *((DemoEntity.Bindings.HostArgs_SpawnEntity*)payloadPtr); + host.SpawnEntity(a.EntityId, a.PrefabHandle, in a.Transform, a.Flags); + break; + } + case 0x20DA0B6Fu: + { + ref readonly DemoEntity.Bindings.HostArgs_SetTransform a = ref *((DemoEntity.Bindings.HostArgs_SetTransform*)payloadPtr); + host.SetTransform(a.EntityId, a.Mask, in a.Transform); + break; + } + case 0x5B16AE9Eu: + { + ref readonly DemoEntity.Bindings.HostArgs_SetPosition a = ref *((DemoEntity.Bindings.HostArgs_SetPosition*)payloadPtr); + host.SetPosition(a.EntityId, a.Position); + break; + } + case 0xC7C1C59Cu: + { + ref readonly DemoEntity.Bindings.HostArgs_DestroyEntity a = ref *((DemoEntity.Bindings.HostArgs_DestroyEntity*)payloadPtr); + host.DestroyEntity(a.EntityId); + break; + } + case 0xDA3184A2u: + { + ref readonly DemoLog.Bindings.HostArgs_Log a = ref *((DemoLog.Bindings.HostArgs_Log*)payloadPtr); + host.Log(a.Level, a.Message); + break; + } + } + + cursor += size; + } + } + + public static unsafe void DispatchFastUnchecked(CommandStream stream, BridgeAllHostApiBase host) + => DispatchFastUnchecked(stream, host); + + public static unsafe void DispatchFast(CommandStream stream, BridgeAllHostApiBase host) + => DispatchFast(stream, host); + + public static unsafe void Dispatch(CommandStream stream, THost host) + where THost : class, DemoAsset.Bindings.IDemoAssetHostApi, DemoEntity.Bindings.IDemoEntityHostApi, DemoLog.Bindings.IDemoLogHostApi { if (stream.IsEmpty || host == null) return; diff --git a/Tests/unity/Assets/BridgeDemoGame/PlayModeTests/BridgeRuntimeSmokeTests.cs b/Tests/unity/Assets/BridgeDemoGame/PlayModeTests/BridgeRuntimeSmokeTests.cs index 9a4aa42..29ac71e 100644 --- a/Tests/unity/Assets/BridgeDemoGame/PlayModeTests/BridgeRuntimeSmokeTests.cs +++ b/Tests/unity/Assets/BridgeDemoGame/PlayModeTests/BridgeRuntimeSmokeTests.cs @@ -74,7 +74,7 @@ public IEnumerator TickAndDispatch_60Frames_NoException() { var stream = core.TickAndGetCommandStream(1.0f / 60.0f); #if ENABLE_IL2CPP - BridgeAllCommandDispatcher.DispatchFast(stream, host); + BridgeAllCommandDispatcher.DispatchFastUnchecked(stream, host); #else BridgeAllCommandDispatcher.Dispatch(stream, host); #endif diff --git a/Tests/unity/Assets/BridgeDemoGame/PlayModeTests/BridgeSourceModeThroughputTests.cs b/Tests/unity/Assets/BridgeDemoGame/PlayModeTests/BridgeSourceModeThroughputTests.cs index 1a9c051..7d44bd8 100644 --- a/Tests/unity/Assets/BridgeDemoGame/PlayModeTests/BridgeSourceModeThroughputTests.cs +++ b/Tests/unity/Assets/BridgeDemoGame/PlayModeTests/BridgeSourceModeThroughputTests.cs @@ -176,7 +176,7 @@ private static void RunFrames( { CommandStream stream = streamsPtr[i]; totalBytes += stream.Length; - BridgeAllCommandDispatcher.DispatchFast(stream, hosts[i]); + BridgeAllCommandDispatcher.DispatchFastUnchecked(stream, hosts[i]); } } } diff --git a/Tests/unity/Assets/BridgeDemoGame/Runtime/Runner/DemoGameUnityRunner.cs b/Tests/unity/Assets/BridgeDemoGame/Runtime/Runner/DemoGameUnityRunner.cs index 1c66756..c3fd916 100644 --- a/Tests/unity/Assets/BridgeDemoGame/Runtime/Runner/DemoGameUnityRunner.cs +++ b/Tests/unity/Assets/BridgeDemoGame/Runtime/Runner/DemoGameUnityRunner.cs @@ -54,7 +54,7 @@ private void Update() for (int i = 0; i < _cores.Length; i++) { #if ENABLE_IL2CPP - BridgeAllCommandDispatcher.DispatchFast(_streams[i], _hosts[i]); + BridgeAllCommandDispatcher.DispatchFastUnchecked(_streams[i], _hosts[i]); #else BridgeAllCommandDispatcher.Dispatch(_streams[i], _hosts[i]); #endif From 326156ad8abd89ec3529ec516eb0c9129c6368c8 Mon Sep 17 00:00:00 2001 From: lcals Date: Wed, 21 Jan 2026 21:07:32 +0800 Subject: [PATCH 27/33] perf: record DispatchFastUnchecked benchmark --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 81fc430..a7bb22f 100644 --- a/README.md +++ b/README.md @@ -82,6 +82,7 @@ powershell -ExecutionPolicy Bypass -File Tools/RunPerf.ps1 -Bots 1000 -Frames 30 | tsUtc | runId | tag | git | robothost_null cmd/s | robot_runner cmd/s | robot_runner ticks/s | il2cpp_source 1k ticks/s | il2cpp_source 10k ticks/s | |---|---|---|---|---:|---:|---:|---:|---:| +| 2026-01-21T13:06:31.6271292Z | 20260121_210530 | post_912e0e5_dispatchfast_unchecked | 912e0e5 | 24472001 | 75259385 | 75000000.00 | 57012542.76 | 35951479.88 | | 2026-01-21T12:53:22.0211694Z | 20260121_205232 | post_c484055_dispatchfast_generic | c484055 | 25094858 | 76026471 | 76923076.92 | 56037059.18 | 34641512.31 | | 2026-01-21T12:22:32.4341938Z | 20260121_202154 | post_d5fa6a1_setposition | d5fa6a1 | 27401987 | 76187915 | 76923076.92 | 55518543.19 | 33672905.88 | | 2026-01-21T12:08:02.0093094Z | 20260121_200706 | baseline_r11 | 0d3443a | 22894010 | 57608306 | 57692307.69 | 50491450.11 | 31203746.95 | @@ -102,3 +103,4 @@ powershell -ExecutionPolicy Bypass -File Tools/RunPerf.ps1 -Bots 1000 -Frames 30 + From 9219989cbadf35eb18e2f229195f9a145bf163c6 Mon Sep 17 00:00:00 2001 From: lcals Date: Wed, 21 Jan 2026 21:18:29 +0800 Subject: [PATCH 28/33] perf: stabilize IL2CPP throughput measurement window --- .../PlayModeTests/BridgeSourceModeThroughputTests.cs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/Tests/unity/Assets/BridgeDemoGame/PlayModeTests/BridgeSourceModeThroughputTests.cs b/Tests/unity/Assets/BridgeDemoGame/PlayModeTests/BridgeSourceModeThroughputTests.cs index 7d44bd8..2ba2dc6 100644 --- a/Tests/unity/Assets/BridgeDemoGame/PlayModeTests/BridgeSourceModeThroughputTests.cs +++ b/Tests/unity/Assets/BridgeDemoGame/PlayModeTests/BridgeSourceModeThroughputTests.cs @@ -90,8 +90,14 @@ private static void RunThroughput(int bots) if (bots <= 0) throw new ArgumentOutOfRangeException(nameof(bots)); - const int warmupFrames = 60; - const int measureFrames = 300; + // NOTE: 旧值(warmup=60/measure=300)会让计时窗口非常短: + // - bots=1000 时只有 ~5ms + // - bots=10000 时也只有 ~80ms + // 容易被调度抖动/后台任务放大,导致 ticks/s 波动很大。 + // 这里按目标 ticks 数动态放大 frames,让计时窗口更稳定。 + const int targetTicks = 30_000_000; + int measureFrames = Math.Clamp(targetTicks / bots, 300, 30_000); + int warmupFrames = Math.Clamp(measureFrames / 10, 60, 3_000); const float dt = 1.0f / 60.0f; BridgeCore.PrepareTickManyCache(bots); From 4bfba43d73e401ea770dc4f9e6a66ba571f18424 Mon Sep 17 00:00:00 2001 From: lcals Date: Wed, 21 Jan 2026 21:32:01 +0800 Subject: [PATCH 29/33] perf: shrink CallHost command header --- Core/Tools/BridgeGen/Program.cs | 26 +- Core/cpp/include/bridge/bridge.h | 4 +- Core/cpp/src/core/core_instance.cpp | 1 - Core/csharp/Bridge.Core/Interop/Structs.cs | 2 - .../Runtime/Bridge.Core/Interop/Structs.cs | 2 - Tests/cpp/robot_runner/main.cpp | 3 +- .../Bridge.AllCommandDispatcher.g.cs | 272 +++++++++--------- .../Bridge.AllCommandDispatcher.g.cs | 272 +++++++++--------- 8 files changed, 279 insertions(+), 303 deletions(-) diff --git a/Core/Tools/BridgeGen/Program.cs b/Core/Tools/BridgeGen/Program.cs index c321960..42a8711 100644 --- a/Core/Tools/BridgeGen/Program.cs +++ b/Core/Tools/BridgeGen/Program.cs @@ -538,13 +538,11 @@ private static string EmitAllDispatcher(IReadOnlyList modules) sb.AppendLine(" if (header->Type == (ushort)BridgeCommandType.CallHost && size >= sizeof(BridgeCmdCallHost))"); sb.AppendLine(" {"); sb.AppendLine(" var cmd = (BridgeCmdCallHost*)cursor;"); - sb.AppendLine(" uint payloadSize = cmd->PayloadSize;"); - sb.AppendLine(" if (payloadSize <= (uint)(size - sizeof(BridgeCmdCallHost)))"); - sb.AppendLine(" {"); - sb.AppendLine(" byte* payloadPtr = cursor + sizeof(BridgeCmdCallHost);"); + sb.AppendLine(" uint payloadBytes = (uint)(size - sizeof(BridgeCmdCallHost));"); + sb.AppendLine(" byte* payloadPtr = cursor + sizeof(BridgeCmdCallHost);"); sb.AppendLine(); - sb.AppendLine(" switch (cmd->FuncId)"); - sb.AppendLine(" {"); + sb.AppendLine(" switch (cmd->FuncId)"); + sb.AppendLine(" {"); foreach (var m in modules) { @@ -556,7 +554,7 @@ private static string EmitAllDispatcher(IReadOnlyList modules) uint id = ComputeHostFuncId(m.Module, fn.Name); sb.AppendLine($" case 0x{id:X8}u:"); sb.AppendLine(" {"); - sb.Append(" if (payloadSize == (uint)sizeof("); + sb.Append(" if (payloadBytes >= (uint)sizeof("); sb.Append(m.CsNamespace); sb.Append(".HostArgs_"); sb.Append(fn.Name); @@ -588,7 +586,6 @@ private static string EmitAllDispatcher(IReadOnlyList modules) } } - sb.AppendLine(" }"); sb.AppendLine(" }"); sb.AppendLine(" }"); sb.AppendLine(); @@ -705,13 +702,11 @@ private static string EmitAllDispatcher(IReadOnlyList modules) sb.AppendLine(" if (header->Type == (ushort)BridgeCommandType.CallHost && size >= sizeof(BridgeCmdCallHost))"); sb.AppendLine(" {"); sb.AppendLine(" var cmd = (BridgeCmdCallHost*)cursor;"); - sb.AppendLine(" uint payloadSize = cmd->PayloadSize;"); - sb.AppendLine(" if (payloadSize <= (uint)(size - sizeof(BridgeCmdCallHost)))"); - sb.AppendLine(" {"); - sb.AppendLine(" byte* payloadPtr = cursor + sizeof(BridgeCmdCallHost);"); + sb.AppendLine(" uint payloadBytes = (uint)(size - sizeof(BridgeCmdCallHost));"); + sb.AppendLine(" byte* payloadPtr = cursor + sizeof(BridgeCmdCallHost);"); sb.AppendLine(); - sb.AppendLine(" switch (cmd->FuncId)"); - sb.AppendLine(" {"); + sb.AppendLine(" switch (cmd->FuncId)"); + sb.AppendLine(" {"); foreach (var m in modules) { @@ -723,7 +718,7 @@ private static string EmitAllDispatcher(IReadOnlyList modules) uint id = ComputeHostFuncId(m.Module, fn.Name); sb.AppendLine($" case 0x{id:X8}u:"); sb.AppendLine(" {"); - sb.Append(" if (payloadSize == (uint)sizeof("); + sb.Append(" if (payloadBytes >= (uint)sizeof("); sb.Append(m.CsNamespace); sb.Append(".HostArgs_"); sb.Append(fn.Name); @@ -755,7 +750,6 @@ private static string EmitAllDispatcher(IReadOnlyList modules) } } - sb.AppendLine(" }"); sb.AppendLine(" }"); sb.AppendLine(" }"); sb.AppendLine(); diff --git a/Core/cpp/include/bridge/bridge.h b/Core/cpp/include/bridge/bridge.h index c445639..2edac4c 100644 --- a/Core/cpp/include/bridge/bridge.h +++ b/Core/cpp/include/bridge/bridge.h @@ -160,16 +160,14 @@ typedef struct BridgeCommandHeader uint16_t type; // BridgeCommandType // 命令总大小(包含 header+后续数据),必须 8 字节对齐 uint16_t size; - uint32_t reserved0; } BridgeCommandHeader; // 通用 Host 调用命令头: -// - payload 紧跟其后(payload_size 字节),并按 8 字节补齐到 header.size +// - payload 紧跟其后,并按 8 字节补齐到 header.size typedef struct BridgeCmdCallHost { BridgeCommandHeader header; uint32_t func_id; - uint32_t payload_size; } BridgeCmdCallHost; BRIDGE_API void BRIDGE_CALL BridgeCore_Tick(BridgeCore* core, float dt); diff --git a/Core/cpp/src/core/core_instance.cpp b/Core/cpp/src/core/core_instance.cpp index c4afa3e..b0e6e3b 100644 --- a/Core/cpp/src/core/core_instance.cpp +++ b/Core/cpp/src/core/core_instance.cpp @@ -62,7 +62,6 @@ namespace bridge cmd.header.type = BRIDGE_CMD_CALL_HOST; cmd.header.size = static_cast(alignedTotal); cmd.func_id = funcId; - cmd.payload_size = payloadSize; uint8_t* dst = core_.commands.Allocate(static_cast(alignedTotal)); if (!dst) diff --git a/Core/csharp/Bridge.Core/Interop/Structs.cs b/Core/csharp/Bridge.Core/Interop/Structs.cs index 6c30587..17d2087 100644 --- a/Core/csharp/Bridge.Core/Interop/Structs.cs +++ b/Core/csharp/Bridge.Core/Interop/Structs.cs @@ -119,7 +119,6 @@ public struct BridgeCommandHeader { public ushort Type; public ushort Size; - public uint Reserved0; } public enum BridgeCommandType : ushort @@ -133,6 +132,5 @@ public struct BridgeCmdCallHost { public BridgeCommandHeader Header; public uint FuncId; - public uint PayloadSize; } } diff --git a/Packages/com.unitynativescripting.bridgecore/Runtime/Bridge.Core/Interop/Structs.cs b/Packages/com.unitynativescripting.bridgecore/Runtime/Bridge.Core/Interop/Structs.cs index 6c30587..17d2087 100644 --- a/Packages/com.unitynativescripting.bridgecore/Runtime/Bridge.Core/Interop/Structs.cs +++ b/Packages/com.unitynativescripting.bridgecore/Runtime/Bridge.Core/Interop/Structs.cs @@ -119,7 +119,6 @@ public struct BridgeCommandHeader { public ushort Type; public ushort Size; - public uint Reserved0; } public enum BridgeCommandType : ushort @@ -133,6 +132,5 @@ public struct BridgeCmdCallHost { public BridgeCommandHeader Header; public uint FuncId; - public uint PayloadSize; } } diff --git a/Tests/cpp/robot_runner/main.cpp b/Tests/cpp/robot_runner/main.cpp index f51b2ae..3d59e6d 100644 --- a/Tests/cpp/robot_runner/main.cpp +++ b/Tests/cpp/robot_runner/main.cpp @@ -114,8 +114,9 @@ int main(int argc, char** argv) header->size >= sizeof(BridgeCmdCallHost)) { const auto* cmd = reinterpret_cast(header); + const uint32_t payload_bytes = static_cast(header->size) - static_cast(sizeof(BridgeCmdCallHost)); if (cmd->func_id == static_cast(demo_asset::HostFuncId::LoadAsset) && - cmd->payload_size == sizeof(demo_asset::HostArgs_LoadAsset)) + payload_bytes >= sizeof(demo_asset::HostArgs_LoadAsset)) { ++totalAssetRequests; const uint8_t* payload = reinterpret_cast(cmd) + sizeof(BridgeCmdCallHost); diff --git a/Tests/csharp/RobotHost/Generated/Bridge.AllCommandDispatcher.g.cs b/Tests/csharp/RobotHost/Generated/Bridge.AllCommandDispatcher.g.cs index 4f8cff8..47151f9 100644 --- a/Tests/csharp/RobotHost/Generated/Bridge.AllCommandDispatcher.g.cs +++ b/Tests/csharp/RobotHost/Generated/Bridge.AllCommandDispatcher.g.cs @@ -45,74 +45,71 @@ public static unsafe void DispatchFast(CommandStream stream, THost host) if ((uint)size < (uint)sizeof(BridgeCommandHeader) || (uint)size > (uint)remaining) break; - if (header->Type == (ushort)BridgeCommandType.CallHost && size >= sizeof(BridgeCmdCallHost)) - { - var cmd = (BridgeCmdCallHost*)cursor; - uint payloadSize = cmd->PayloadSize; - if (payloadSize <= (uint)(size - sizeof(BridgeCmdCallHost))) - { - byte* payloadPtr = cursor + sizeof(BridgeCmdCallHost); - - switch (cmd->FuncId) - { - case 0x82A5E93Au: - { - if (payloadSize == (uint)sizeof(DemoAsset.Bindings.HostArgs_LoadAsset)) - { - ref readonly DemoAsset.Bindings.HostArgs_LoadAsset a = ref *((DemoAsset.Bindings.HostArgs_LoadAsset*)payloadPtr); - host.LoadAsset(a.RequestId, a.AssetType, a.AssetKey); - } - break; - } - case 0xBCAA331Du: - { - if (payloadSize == (uint)sizeof(DemoEntity.Bindings.HostArgs_SpawnEntity)) - { - ref readonly DemoEntity.Bindings.HostArgs_SpawnEntity a = ref *((DemoEntity.Bindings.HostArgs_SpawnEntity*)payloadPtr); - host.SpawnEntity(a.EntityId, a.PrefabHandle, in a.Transform, a.Flags); - } - break; - } - case 0x20DA0B6Fu: - { - if (payloadSize == (uint)sizeof(DemoEntity.Bindings.HostArgs_SetTransform)) - { - ref readonly DemoEntity.Bindings.HostArgs_SetTransform a = ref *((DemoEntity.Bindings.HostArgs_SetTransform*)payloadPtr); - host.SetTransform(a.EntityId, a.Mask, in a.Transform); - } - break; - } - case 0x5B16AE9Eu: - { - if (payloadSize == (uint)sizeof(DemoEntity.Bindings.HostArgs_SetPosition)) - { - ref readonly DemoEntity.Bindings.HostArgs_SetPosition a = ref *((DemoEntity.Bindings.HostArgs_SetPosition*)payloadPtr); - host.SetPosition(a.EntityId, a.Position); - } - break; - } - case 0xC7C1C59Cu: - { - if (payloadSize == (uint)sizeof(DemoEntity.Bindings.HostArgs_DestroyEntity)) - { - ref readonly DemoEntity.Bindings.HostArgs_DestroyEntity a = ref *((DemoEntity.Bindings.HostArgs_DestroyEntity*)payloadPtr); - host.DestroyEntity(a.EntityId); - } - break; - } - case 0xDA3184A2u: - { - if (payloadSize == (uint)sizeof(DemoLog.Bindings.HostArgs_Log)) - { - ref readonly DemoLog.Bindings.HostArgs_Log a = ref *((DemoLog.Bindings.HostArgs_Log*)payloadPtr); - host.Log(a.Level, a.Message); - } - break; - } - } - } - } - + if (header->Type == (ushort)BridgeCommandType.CallHost && size >= sizeof(BridgeCmdCallHost)) + { + var cmd = (BridgeCmdCallHost*)cursor; + uint payloadBytes = (uint)(size - sizeof(BridgeCmdCallHost)); + byte* payloadPtr = cursor + sizeof(BridgeCmdCallHost); + + switch (cmd->FuncId) + { + case 0x82A5E93Au: + { + if (payloadBytes >= (uint)sizeof(DemoAsset.Bindings.HostArgs_LoadAsset)) + { + ref readonly DemoAsset.Bindings.HostArgs_LoadAsset a = ref *((DemoAsset.Bindings.HostArgs_LoadAsset*)payloadPtr); + host.LoadAsset(a.RequestId, a.AssetType, a.AssetKey); + } + break; + } + case 0xBCAA331Du: + { + if (payloadBytes >= (uint)sizeof(DemoEntity.Bindings.HostArgs_SpawnEntity)) + { + ref readonly DemoEntity.Bindings.HostArgs_SpawnEntity a = ref *((DemoEntity.Bindings.HostArgs_SpawnEntity*)payloadPtr); + host.SpawnEntity(a.EntityId, a.PrefabHandle, in a.Transform, a.Flags); + } + break; + } + case 0x20DA0B6Fu: + { + if (payloadBytes >= (uint)sizeof(DemoEntity.Bindings.HostArgs_SetTransform)) + { + ref readonly DemoEntity.Bindings.HostArgs_SetTransform a = ref *((DemoEntity.Bindings.HostArgs_SetTransform*)payloadPtr); + host.SetTransform(a.EntityId, a.Mask, in a.Transform); + } + break; + } + case 0x5B16AE9Eu: + { + if (payloadBytes >= (uint)sizeof(DemoEntity.Bindings.HostArgs_SetPosition)) + { + ref readonly DemoEntity.Bindings.HostArgs_SetPosition a = ref *((DemoEntity.Bindings.HostArgs_SetPosition*)payloadPtr); + host.SetPosition(a.EntityId, a.Position); + } + break; + } + case 0xC7C1C59Cu: + { + if (payloadBytes >= (uint)sizeof(DemoEntity.Bindings.HostArgs_DestroyEntity)) + { + ref readonly DemoEntity.Bindings.HostArgs_DestroyEntity a = ref *((DemoEntity.Bindings.HostArgs_DestroyEntity*)payloadPtr); + host.DestroyEntity(a.EntityId); + } + break; + } + case 0xDA3184A2u: + { + if (payloadBytes >= (uint)sizeof(DemoLog.Bindings.HostArgs_Log)) + { + ref readonly DemoLog.Bindings.HostArgs_Log a = ref *((DemoLog.Bindings.HostArgs_Log*)payloadPtr); + host.Log(a.Level, a.Message); + } + break; + } + } + } + cursor += size; } } @@ -209,76 +206,73 @@ public static unsafe void Dispatch(CommandStream stream, THost host) if ((uint)size < (uint)sizeof(BridgeCommandHeader) || (uint)size > (uint)remaining) break; - if (header->Type == (ushort)BridgeCommandType.CallHost && size >= sizeof(BridgeCmdCallHost)) - { - var cmd = (BridgeCmdCallHost*)cursor; - uint payloadSize = cmd->PayloadSize; - if (payloadSize <= (uint)(size - sizeof(BridgeCmdCallHost))) - { - byte* payloadPtr = cursor + sizeof(BridgeCmdCallHost); - - switch (cmd->FuncId) - { - case 0x82A5E93Au: - { - if (payloadSize == (uint)sizeof(DemoAsset.Bindings.HostArgs_LoadAsset)) - { - ref readonly DemoAsset.Bindings.HostArgs_LoadAsset a = ref *((DemoAsset.Bindings.HostArgs_LoadAsset*)payloadPtr); - host.LoadAsset(a.RequestId, a.AssetType, a.AssetKey); - } - break; - } - case 0xBCAA331Du: - { - if (payloadSize == (uint)sizeof(DemoEntity.Bindings.HostArgs_SpawnEntity)) - { - ref readonly DemoEntity.Bindings.HostArgs_SpawnEntity a = ref *((DemoEntity.Bindings.HostArgs_SpawnEntity*)payloadPtr); - host.SpawnEntity(a.EntityId, a.PrefabHandle, in a.Transform, a.Flags); - } - break; - } - case 0x20DA0B6Fu: - { - if (payloadSize == (uint)sizeof(DemoEntity.Bindings.HostArgs_SetTransform)) - { - ref readonly DemoEntity.Bindings.HostArgs_SetTransform a = ref *((DemoEntity.Bindings.HostArgs_SetTransform*)payloadPtr); - host.SetTransform(a.EntityId, a.Mask, in a.Transform); - } - break; - } - case 0x5B16AE9Eu: - { - if (payloadSize == (uint)sizeof(DemoEntity.Bindings.HostArgs_SetPosition)) - { - ref readonly DemoEntity.Bindings.HostArgs_SetPosition a = ref *((DemoEntity.Bindings.HostArgs_SetPosition*)payloadPtr); - host.SetPosition(a.EntityId, a.Position); - } - break; - } - case 0xC7C1C59Cu: - { - if (payloadSize == (uint)sizeof(DemoEntity.Bindings.HostArgs_DestroyEntity)) - { - ref readonly DemoEntity.Bindings.HostArgs_DestroyEntity a = ref *((DemoEntity.Bindings.HostArgs_DestroyEntity*)payloadPtr); - host.DestroyEntity(a.EntityId); - } - break; - } - case 0xDA3184A2u: - { - if (payloadSize == (uint)sizeof(DemoLog.Bindings.HostArgs_Log)) - { - ref readonly DemoLog.Bindings.HostArgs_Log a = ref *((DemoLog.Bindings.HostArgs_Log*)payloadPtr); - host.Log(a.Level, a.Message); - } - break; - } - } - } - } - - cursor += size; - } - } + if (header->Type == (ushort)BridgeCommandType.CallHost && size >= sizeof(BridgeCmdCallHost)) + { + var cmd = (BridgeCmdCallHost*)cursor; + uint payloadBytes = (uint)(size - sizeof(BridgeCmdCallHost)); + byte* payloadPtr = cursor + sizeof(BridgeCmdCallHost); + + switch (cmd->FuncId) + { + case 0x82A5E93Au: + { + if (payloadBytes >= (uint)sizeof(DemoAsset.Bindings.HostArgs_LoadAsset)) + { + ref readonly DemoAsset.Bindings.HostArgs_LoadAsset a = ref *((DemoAsset.Bindings.HostArgs_LoadAsset*)payloadPtr); + host.LoadAsset(a.RequestId, a.AssetType, a.AssetKey); + } + break; + } + case 0xBCAA331Du: + { + if (payloadBytes >= (uint)sizeof(DemoEntity.Bindings.HostArgs_SpawnEntity)) + { + ref readonly DemoEntity.Bindings.HostArgs_SpawnEntity a = ref *((DemoEntity.Bindings.HostArgs_SpawnEntity*)payloadPtr); + host.SpawnEntity(a.EntityId, a.PrefabHandle, in a.Transform, a.Flags); + } + break; + } + case 0x20DA0B6Fu: + { + if (payloadBytes >= (uint)sizeof(DemoEntity.Bindings.HostArgs_SetTransform)) + { + ref readonly DemoEntity.Bindings.HostArgs_SetTransform a = ref *((DemoEntity.Bindings.HostArgs_SetTransform*)payloadPtr); + host.SetTransform(a.EntityId, a.Mask, in a.Transform); + } + break; + } + case 0x5B16AE9Eu: + { + if (payloadBytes >= (uint)sizeof(DemoEntity.Bindings.HostArgs_SetPosition)) + { + ref readonly DemoEntity.Bindings.HostArgs_SetPosition a = ref *((DemoEntity.Bindings.HostArgs_SetPosition*)payloadPtr); + host.SetPosition(a.EntityId, a.Position); + } + break; + } + case 0xC7C1C59Cu: + { + if (payloadBytes >= (uint)sizeof(DemoEntity.Bindings.HostArgs_DestroyEntity)) + { + ref readonly DemoEntity.Bindings.HostArgs_DestroyEntity a = ref *((DemoEntity.Bindings.HostArgs_DestroyEntity*)payloadPtr); + host.DestroyEntity(a.EntityId); + } + break; + } + case 0xDA3184A2u: + { + if (payloadBytes >= (uint)sizeof(DemoLog.Bindings.HostArgs_Log)) + { + ref readonly DemoLog.Bindings.HostArgs_Log a = ref *((DemoLog.Bindings.HostArgs_Log*)payloadPtr); + host.Log(a.Level, a.Message); + } + break; + } + } + } + + cursor += size; + } + } } } diff --git a/Tests/unity/Assets/BridgeDemoGame/Generated/Bridge.AllCommandDispatcher.g.cs b/Tests/unity/Assets/BridgeDemoGame/Generated/Bridge.AllCommandDispatcher.g.cs index 4f8cff8..47151f9 100644 --- a/Tests/unity/Assets/BridgeDemoGame/Generated/Bridge.AllCommandDispatcher.g.cs +++ b/Tests/unity/Assets/BridgeDemoGame/Generated/Bridge.AllCommandDispatcher.g.cs @@ -45,74 +45,71 @@ public static unsafe void DispatchFast(CommandStream stream, THost host) if ((uint)size < (uint)sizeof(BridgeCommandHeader) || (uint)size > (uint)remaining) break; - if (header->Type == (ushort)BridgeCommandType.CallHost && size >= sizeof(BridgeCmdCallHost)) - { - var cmd = (BridgeCmdCallHost*)cursor; - uint payloadSize = cmd->PayloadSize; - if (payloadSize <= (uint)(size - sizeof(BridgeCmdCallHost))) - { - byte* payloadPtr = cursor + sizeof(BridgeCmdCallHost); - - switch (cmd->FuncId) - { - case 0x82A5E93Au: - { - if (payloadSize == (uint)sizeof(DemoAsset.Bindings.HostArgs_LoadAsset)) - { - ref readonly DemoAsset.Bindings.HostArgs_LoadAsset a = ref *((DemoAsset.Bindings.HostArgs_LoadAsset*)payloadPtr); - host.LoadAsset(a.RequestId, a.AssetType, a.AssetKey); - } - break; - } - case 0xBCAA331Du: - { - if (payloadSize == (uint)sizeof(DemoEntity.Bindings.HostArgs_SpawnEntity)) - { - ref readonly DemoEntity.Bindings.HostArgs_SpawnEntity a = ref *((DemoEntity.Bindings.HostArgs_SpawnEntity*)payloadPtr); - host.SpawnEntity(a.EntityId, a.PrefabHandle, in a.Transform, a.Flags); - } - break; - } - case 0x20DA0B6Fu: - { - if (payloadSize == (uint)sizeof(DemoEntity.Bindings.HostArgs_SetTransform)) - { - ref readonly DemoEntity.Bindings.HostArgs_SetTransform a = ref *((DemoEntity.Bindings.HostArgs_SetTransform*)payloadPtr); - host.SetTransform(a.EntityId, a.Mask, in a.Transform); - } - break; - } - case 0x5B16AE9Eu: - { - if (payloadSize == (uint)sizeof(DemoEntity.Bindings.HostArgs_SetPosition)) - { - ref readonly DemoEntity.Bindings.HostArgs_SetPosition a = ref *((DemoEntity.Bindings.HostArgs_SetPosition*)payloadPtr); - host.SetPosition(a.EntityId, a.Position); - } - break; - } - case 0xC7C1C59Cu: - { - if (payloadSize == (uint)sizeof(DemoEntity.Bindings.HostArgs_DestroyEntity)) - { - ref readonly DemoEntity.Bindings.HostArgs_DestroyEntity a = ref *((DemoEntity.Bindings.HostArgs_DestroyEntity*)payloadPtr); - host.DestroyEntity(a.EntityId); - } - break; - } - case 0xDA3184A2u: - { - if (payloadSize == (uint)sizeof(DemoLog.Bindings.HostArgs_Log)) - { - ref readonly DemoLog.Bindings.HostArgs_Log a = ref *((DemoLog.Bindings.HostArgs_Log*)payloadPtr); - host.Log(a.Level, a.Message); - } - break; - } - } - } - } - + if (header->Type == (ushort)BridgeCommandType.CallHost && size >= sizeof(BridgeCmdCallHost)) + { + var cmd = (BridgeCmdCallHost*)cursor; + uint payloadBytes = (uint)(size - sizeof(BridgeCmdCallHost)); + byte* payloadPtr = cursor + sizeof(BridgeCmdCallHost); + + switch (cmd->FuncId) + { + case 0x82A5E93Au: + { + if (payloadBytes >= (uint)sizeof(DemoAsset.Bindings.HostArgs_LoadAsset)) + { + ref readonly DemoAsset.Bindings.HostArgs_LoadAsset a = ref *((DemoAsset.Bindings.HostArgs_LoadAsset*)payloadPtr); + host.LoadAsset(a.RequestId, a.AssetType, a.AssetKey); + } + break; + } + case 0xBCAA331Du: + { + if (payloadBytes >= (uint)sizeof(DemoEntity.Bindings.HostArgs_SpawnEntity)) + { + ref readonly DemoEntity.Bindings.HostArgs_SpawnEntity a = ref *((DemoEntity.Bindings.HostArgs_SpawnEntity*)payloadPtr); + host.SpawnEntity(a.EntityId, a.PrefabHandle, in a.Transform, a.Flags); + } + break; + } + case 0x20DA0B6Fu: + { + if (payloadBytes >= (uint)sizeof(DemoEntity.Bindings.HostArgs_SetTransform)) + { + ref readonly DemoEntity.Bindings.HostArgs_SetTransform a = ref *((DemoEntity.Bindings.HostArgs_SetTransform*)payloadPtr); + host.SetTransform(a.EntityId, a.Mask, in a.Transform); + } + break; + } + case 0x5B16AE9Eu: + { + if (payloadBytes >= (uint)sizeof(DemoEntity.Bindings.HostArgs_SetPosition)) + { + ref readonly DemoEntity.Bindings.HostArgs_SetPosition a = ref *((DemoEntity.Bindings.HostArgs_SetPosition*)payloadPtr); + host.SetPosition(a.EntityId, a.Position); + } + break; + } + case 0xC7C1C59Cu: + { + if (payloadBytes >= (uint)sizeof(DemoEntity.Bindings.HostArgs_DestroyEntity)) + { + ref readonly DemoEntity.Bindings.HostArgs_DestroyEntity a = ref *((DemoEntity.Bindings.HostArgs_DestroyEntity*)payloadPtr); + host.DestroyEntity(a.EntityId); + } + break; + } + case 0xDA3184A2u: + { + if (payloadBytes >= (uint)sizeof(DemoLog.Bindings.HostArgs_Log)) + { + ref readonly DemoLog.Bindings.HostArgs_Log a = ref *((DemoLog.Bindings.HostArgs_Log*)payloadPtr); + host.Log(a.Level, a.Message); + } + break; + } + } + } + cursor += size; } } @@ -209,76 +206,73 @@ public static unsafe void Dispatch(CommandStream stream, THost host) if ((uint)size < (uint)sizeof(BridgeCommandHeader) || (uint)size > (uint)remaining) break; - if (header->Type == (ushort)BridgeCommandType.CallHost && size >= sizeof(BridgeCmdCallHost)) - { - var cmd = (BridgeCmdCallHost*)cursor; - uint payloadSize = cmd->PayloadSize; - if (payloadSize <= (uint)(size - sizeof(BridgeCmdCallHost))) - { - byte* payloadPtr = cursor + sizeof(BridgeCmdCallHost); - - switch (cmd->FuncId) - { - case 0x82A5E93Au: - { - if (payloadSize == (uint)sizeof(DemoAsset.Bindings.HostArgs_LoadAsset)) - { - ref readonly DemoAsset.Bindings.HostArgs_LoadAsset a = ref *((DemoAsset.Bindings.HostArgs_LoadAsset*)payloadPtr); - host.LoadAsset(a.RequestId, a.AssetType, a.AssetKey); - } - break; - } - case 0xBCAA331Du: - { - if (payloadSize == (uint)sizeof(DemoEntity.Bindings.HostArgs_SpawnEntity)) - { - ref readonly DemoEntity.Bindings.HostArgs_SpawnEntity a = ref *((DemoEntity.Bindings.HostArgs_SpawnEntity*)payloadPtr); - host.SpawnEntity(a.EntityId, a.PrefabHandle, in a.Transform, a.Flags); - } - break; - } - case 0x20DA0B6Fu: - { - if (payloadSize == (uint)sizeof(DemoEntity.Bindings.HostArgs_SetTransform)) - { - ref readonly DemoEntity.Bindings.HostArgs_SetTransform a = ref *((DemoEntity.Bindings.HostArgs_SetTransform*)payloadPtr); - host.SetTransform(a.EntityId, a.Mask, in a.Transform); - } - break; - } - case 0x5B16AE9Eu: - { - if (payloadSize == (uint)sizeof(DemoEntity.Bindings.HostArgs_SetPosition)) - { - ref readonly DemoEntity.Bindings.HostArgs_SetPosition a = ref *((DemoEntity.Bindings.HostArgs_SetPosition*)payloadPtr); - host.SetPosition(a.EntityId, a.Position); - } - break; - } - case 0xC7C1C59Cu: - { - if (payloadSize == (uint)sizeof(DemoEntity.Bindings.HostArgs_DestroyEntity)) - { - ref readonly DemoEntity.Bindings.HostArgs_DestroyEntity a = ref *((DemoEntity.Bindings.HostArgs_DestroyEntity*)payloadPtr); - host.DestroyEntity(a.EntityId); - } - break; - } - case 0xDA3184A2u: - { - if (payloadSize == (uint)sizeof(DemoLog.Bindings.HostArgs_Log)) - { - ref readonly DemoLog.Bindings.HostArgs_Log a = ref *((DemoLog.Bindings.HostArgs_Log*)payloadPtr); - host.Log(a.Level, a.Message); - } - break; - } - } - } - } - - cursor += size; - } - } + if (header->Type == (ushort)BridgeCommandType.CallHost && size >= sizeof(BridgeCmdCallHost)) + { + var cmd = (BridgeCmdCallHost*)cursor; + uint payloadBytes = (uint)(size - sizeof(BridgeCmdCallHost)); + byte* payloadPtr = cursor + sizeof(BridgeCmdCallHost); + + switch (cmd->FuncId) + { + case 0x82A5E93Au: + { + if (payloadBytes >= (uint)sizeof(DemoAsset.Bindings.HostArgs_LoadAsset)) + { + ref readonly DemoAsset.Bindings.HostArgs_LoadAsset a = ref *((DemoAsset.Bindings.HostArgs_LoadAsset*)payloadPtr); + host.LoadAsset(a.RequestId, a.AssetType, a.AssetKey); + } + break; + } + case 0xBCAA331Du: + { + if (payloadBytes >= (uint)sizeof(DemoEntity.Bindings.HostArgs_SpawnEntity)) + { + ref readonly DemoEntity.Bindings.HostArgs_SpawnEntity a = ref *((DemoEntity.Bindings.HostArgs_SpawnEntity*)payloadPtr); + host.SpawnEntity(a.EntityId, a.PrefabHandle, in a.Transform, a.Flags); + } + break; + } + case 0x20DA0B6Fu: + { + if (payloadBytes >= (uint)sizeof(DemoEntity.Bindings.HostArgs_SetTransform)) + { + ref readonly DemoEntity.Bindings.HostArgs_SetTransform a = ref *((DemoEntity.Bindings.HostArgs_SetTransform*)payloadPtr); + host.SetTransform(a.EntityId, a.Mask, in a.Transform); + } + break; + } + case 0x5B16AE9Eu: + { + if (payloadBytes >= (uint)sizeof(DemoEntity.Bindings.HostArgs_SetPosition)) + { + ref readonly DemoEntity.Bindings.HostArgs_SetPosition a = ref *((DemoEntity.Bindings.HostArgs_SetPosition*)payloadPtr); + host.SetPosition(a.EntityId, a.Position); + } + break; + } + case 0xC7C1C59Cu: + { + if (payloadBytes >= (uint)sizeof(DemoEntity.Bindings.HostArgs_DestroyEntity)) + { + ref readonly DemoEntity.Bindings.HostArgs_DestroyEntity a = ref *((DemoEntity.Bindings.HostArgs_DestroyEntity*)payloadPtr); + host.DestroyEntity(a.EntityId); + } + break; + } + case 0xDA3184A2u: + { + if (payloadBytes >= (uint)sizeof(DemoLog.Bindings.HostArgs_Log)) + { + ref readonly DemoLog.Bindings.HostArgs_Log a = ref *((DemoLog.Bindings.HostArgs_Log*)payloadPtr); + host.Log(a.Level, a.Message); + } + break; + } + } + } + + cursor += size; + } + } } } From 43137f0497278fa730a2dbdee60ba80710c28ff2 Mon Sep 17 00:00:00 2001 From: lcals Date: Wed, 21 Jan 2026 21:37:05 +0800 Subject: [PATCH 30/33] perf: record CallHost header shrink gains --- Core/docs/PERF_OPTIMIZATIONS.md | 34 +++++++++++++++++++++++++++++++++ README.md | 7 +++++++ 2 files changed, 41 insertions(+) diff --git a/Core/docs/PERF_OPTIMIZATIONS.md b/Core/docs/PERF_OPTIMIZATIONS.md index bcf0449..150d89b 100644 --- a/Core/docs/PERF_OPTIMIZATIONS.md +++ b/Core/docs/PERF_OPTIMIZATIONS.md @@ -141,6 +141,40 @@ pwsh -NoProfile -ExecutionPolicy Bypass -File Tools/RunPerf.ps1 -UnityVersion 60 **效果** - Unity IL2CPP Source 的 `ticks/s`(1k/10k)在本机有稳定提升(见 `README.md` 性能摘要表与对应 runId)。 +### 6) 缩小 `CallHost` 命令头(每 tick stream:40B → 32B) + +**引入** +- git:`4bfba43` +- 验证:Unity `6000.0.40f1` + - tag=`post_4bfba43_shrink_header`;runId=`20260121_213218`(repeat=3) + - tag=`post_4bfba43_shrink_header_rerun`;runId=`20260121_213500`(repeat=3) +- 对比:tag=`probe_9219989_stable_window`;runId=`20260121_211854`(repeat=3) + +**现象** +- Robot mode 下每 tick 主要只发一个 `SetPosition`,旧格式单条命令为: + - `BridgeCmdCallHost` 16B + `HostArgs_SetPosition` 24B = 40B +- 在大 bots(10k)下,解析与内存带宽压力会被放大(`total_bytes` 线性增长)。 + +**改动** +- 缩小 Core→Host command header: + - `BridgeCommandHeader`:去掉 `reserved0`(8B → 4B) + - `BridgeCmdCallHost`:去掉 `payload_size`(16B → 8B) +- Host 侧 payload 校验改为:`payloadBytes = header.size - sizeof(BridgeCmdCallHost)`(包含 padding),并用 `payloadBytes >= sizeof(Args)` 做安全检查。 +- 同步更新 C++ Core 写入、C# interop structs、生成器与解析端(RobotRunner/dispatcher)。 + +**位置** +- C ABI:`Core/cpp/include/bridge/bridge.h` +- Core 写入:`Core/cpp/src/core/core_instance.cpp` +- C# structs: + - `Core/csharp/Bridge.Core/Interop/Structs.cs` + - `Packages/com.unitynativescripting.bridgecore/Runtime/Bridge.Core/Interop/Structs.cs` +- 生成器:`Core/Tools/BridgeGen/Program.cs` +- 解析端:`Tests/cpp/robot_runner/main.cpp` + +**效果(本机)** +- `total_bytes`:10k*3000 从约 `1,200,000,000` 降到 `960,000,000`(-20%) +- Unity IL2CPP Source:10k `ticks/s` 约 `34.17M` → `38.64M`(明显提升,见对应 runId) + ## 优化流程建议(只在提升时记录/提交) 1. 做一次“小步”改动(只动一个热点点位)。 diff --git a/README.md b/README.md index a7bb22f..393a3e3 100644 --- a/README.md +++ b/README.md @@ -82,6 +82,12 @@ powershell -ExecutionPolicy Bypass -File Tools/RunPerf.ps1 -Bots 1000 -Frames 30 | tsUtc | runId | tag | git | robothost_null cmd/s | robot_runner cmd/s | robot_runner ticks/s | il2cpp_source 1k ticks/s | il2cpp_source 10k ticks/s | |---|---|---|---|---:|---:|---:|---:|---:| +| 2026-01-21T13:33:27.2531131Z | 20260121_213218 | post_4bfba43_shrink_header | 4bfba43 | 24956397 | 82791134 | 83333333.33 | 53676144.98 | 38640229.71 | +| 2026-01-21T13:19:57.4007236Z | 20260121_211854 | probe_9219989_stable_window | 9219989 | 24159430 | 80006607 | 78947368.42 | 49798159.76 | 34168195.22 | +| 2026-01-21T13:15:08.8643720Z | 20260121_211406 | post_912e0e5_unchecked_now | 326156a | 25574750 | 74101492 | 73170731.71 | 56039152.69 | 37078326.73 | +| 2026-01-21T13:13:38.1183595Z | 20260121_211235 | baseline_c484055_now | c484055 | 26166305 | 76538414 | 76923076.92 | 56114623.47 | 36469951.80 | +| 2026-01-21T13:11:18.7568374Z | 20260121_211030 | verify_dispatchfast_unchecked_noreadme_1 | 326156a | 26111954 | 79490078 | 78947368.42 | 56328507.86 | 33492085.82 | +| 2026-01-21T13:08:58.7206512Z | 20260121_210811 | post_912e0e5_dispatchfast_unchecked_rerun | 326156a | 24878322 | 77301476 | 76923076.92 | 56203982.99 | 34179309.21 | | 2026-01-21T13:06:31.6271292Z | 20260121_210530 | post_912e0e5_dispatchfast_unchecked | 912e0e5 | 24472001 | 75259385 | 75000000.00 | 57012542.76 | 35951479.88 | | 2026-01-21T12:53:22.0211694Z | 20260121_205232 | post_c484055_dispatchfast_generic | c484055 | 25094858 | 76026471 | 76923076.92 | 56037059.18 | 34641512.31 | | 2026-01-21T12:22:32.4341938Z | 20260121_202154 | post_d5fa6a1_setposition | d5fa6a1 | 27401987 | 76187915 | 76923076.92 | 55518543.19 | 33672905.88 | @@ -104,3 +110,4 @@ powershell -ExecutionPolicy Bypass -File Tools/RunPerf.ps1 -Bots 1000 -Frames 30 + From 0b529e2bc91382961c56c186b2d4d3873a612050 Mon Sep 17 00:00:00 2001 From: lcals Date: Thu, 22 Jan 2026 11:17:49 +0800 Subject: [PATCH 31/33] IL2CPP: TickMany direct CommandStream output --- .gitignore | 2 + Core/cpp/include/bridge/bridge.h | 18 ++- Core/cpp/src/api/bridge_api.cpp | 15 +-- Core/csharp/Bridge.Core/BridgeCore.cs | 104 +++--------------- Core/csharp/Bridge.Core/CommandStream.cs | 4 + .../Bridge.Core/Interop/BridgeNative.cs | 3 +- .../Runtime/Bridge.Core/BridgeCore.cs | 104 +++--------------- .../Runtime/Bridge.Core/CommandStream.cs | 4 + .../Bridge.Core/Interop/BridgeNative.cs | 11 +- 9 files changed, 65 insertions(+), 200 deletions(-) diff --git a/.gitignore b/.gitignore index b08f0c0..83f5b92 100644 --- a/.gitignore +++ b/.gitignore @@ -19,3 +19,5 @@ Tests/**/bin/ Tests/**/obj/ Tests/**/build/ Tests/unity/UserSettings + +puerts-master/ diff --git a/Core/cpp/include/bridge/bridge.h b/Core/cpp/include/bridge/bridge.h index 2edac4c..0866a37 100644 --- a/Core/cpp/include/bridge/bridge.h +++ b/Core/cpp/include/bridge/bridge.h @@ -170,6 +170,17 @@ typedef struct BridgeCmdCallHost uint32_t func_id; } BridgeCmdCallHost; +// Command stream view(Core -> Host): +// - 仅包含 ptr+len,指针由 Core 持有。 +// - 只保证在下一次 Tick(或 Destroy)前有效。 +typedef struct BridgeCommandStream +{ + const void* ptr; + uint32_t len; + // 预留字段(用于未来 ABI 扩展),必须为 0。 + uint32_t reserved0; +} BridgeCommandStream; + BRIDGE_API void BRIDGE_CALL BridgeCore_Tick(BridgeCore* core, float dt); // 组合调用:Tick + GetCommandStream(减少 Host 侧 P/Invoke 次数)。 @@ -183,14 +194,13 @@ BRIDGE_API BridgeResult BRIDGE_CALL BridgeCore_TickAndGetCommandStream( uint32_t* out_len); // 批量 Tick + 获取 command streams(机器人/压测用)。 -// - cores / out_ptrs / out_lens 均为长度为 count 的数组指针。 -// - 成功返回后:out_ptrs[i] / out_lens[i] 为 cores[i] 本帧的 stream。 +// - cores / out_streams 均为长度为 count 的数组指针。 +// - 成功返回后:out_streams[i] 为 cores[i] 本帧的 stream。 BRIDGE_API BridgeResult BRIDGE_CALL BridgeCore_TickManyAndGetCommandStreams( BridgeCore** cores, uint32_t count, float dt, - const void** out_ptrs, - uint32_t* out_lens); + BridgeCommandStream* out_streams); // 返回最近一次 BridgeCore_Tick 生成的 command stream(连续字节流)指针。 // 返回的内存由 Core 持有,只保证在下一次 BridgeCore_Tick(或 BridgeCore_Destroy)前有效。 diff --git a/Core/cpp/src/api/bridge_api.cpp b/Core/cpp/src/api/bridge_api.cpp index 7f1a47a..cbb1c7a 100644 --- a/Core/cpp/src/api/bridge_api.cpp +++ b/Core/cpp/src/api/bridge_api.cpp @@ -53,10 +53,9 @@ BridgeResult BRIDGE_CALL BridgeCore_TickManyAndGetCommandStreams( BridgeCore** cores, uint32_t count, float dt, - const void** out_ptrs, - uint32_t* out_lens) + BridgeCommandStream* out_streams) { - if (!cores || count == 0 || !out_ptrs || !out_lens) + if (!cores || count == 0 || !out_streams) { return BRIDGE_INVALID_ARGUMENT; } @@ -66,14 +65,16 @@ BridgeResult BRIDGE_CALL BridgeCore_TickManyAndGetCommandStreams( auto* core = cores[i]; if (!core) { - out_ptrs[i] = nullptr; - out_lens[i] = 0; + out_streams[i].ptr = nullptr; + out_streams[i].len = 0; + out_streams[i].reserved0 = 0; continue; } bridge::Tick(*core, dt); - out_ptrs[i] = core->commands.Data(); - out_lens[i] = core->commands.Size(); + out_streams[i].ptr = core->commands.Data(); + out_streams[i].len = core->commands.Size(); + out_streams[i].reserved0 = 0; } return BRIDGE_OK; } diff --git a/Core/csharp/Bridge.Core/BridgeCore.cs b/Core/csharp/Bridge.Core/BridgeCore.cs index 06a26be..2376eb0 100644 --- a/Core/csharp/Bridge.Core/BridgeCore.cs +++ b/Core/csharp/Bridge.Core/BridgeCore.cs @@ -10,8 +10,6 @@ public sealed class BridgeCore : IDisposable private const int StackAllocMaxCount = 1024; [ThreadStatic] private static IntPtr[]? s_tickManyCorePtrs; - [ThreadStatic] private static IntPtr[]? s_tickManyOutPtrs; - [ThreadStatic] private static uint[]? s_tickManyOutLens; private IntPtr _handle; @@ -69,7 +67,7 @@ public static void PrepareTickManyCache(int count) if (count < 0) throw new ArgumentOutOfRangeException(nameof(count)); - EnsureTickManyArrays(count); + EnsureTickManyCorePtrs(count); } public static unsafe void TickManyAndGetCommandStreams(BridgeCore[] cores, float dt, CommandStream[] streams) @@ -95,30 +93,18 @@ public static unsafe void TickManyAndGetCommandStreams(BridgeCore[] cores, float corePtrs[i] = core._handle; } - IntPtr* outPtrs = stackalloc IntPtr[count]; - uint* outLens = stackalloc uint[count]; - - var result = BridgeNative.BridgeCore_TickManyAndGetCommandStreams(corePtrs, (uint)count, dt, outPtrs, outLens); - if (result != BridgeResult.Ok) - throw new InvalidOperationException($"BridgeCore_TickManyAndGetCommandStreams failed: {result}"); - - fixed (CommandStream* dst = streams) + fixed (CommandStream* outStreams = streams) { - for (int i = 0; i < count; i++) - { - IntPtr ptr = outPtrs[i]; - uint len = outLens[i]; - dst[i] = (ptr == IntPtr.Zero || len == 0) ? default : new CommandStream(ptr, len); - } + var result = BridgeNative.BridgeCore_TickManyAndGetCommandStreams(corePtrs, (uint)count, dt, outStreams); + if (result != BridgeResult.Ok) + throw new InvalidOperationException($"BridgeCore_TickManyAndGetCommandStreams failed: {result}"); } } else { - EnsureTickManyArrays(count); + EnsureTickManyCorePtrs(count); IntPtr[] corePtrsManaged = s_tickManyCorePtrs!; - IntPtr[] outPtrsManaged = s_tickManyOutPtrs!; - uint[] outLensManaged = s_tickManyOutLens!; for (int i = 0; i < count; i++) { @@ -128,20 +114,11 @@ public static unsafe void TickManyAndGetCommandStreams(BridgeCore[] cores, float } fixed (IntPtr* corePtrs = corePtrsManaged) - fixed (IntPtr* outPtrs = outPtrsManaged) - fixed (uint* outLens = outLensManaged) - fixed (CommandStream* dst = streams) + fixed (CommandStream* outStreams = streams) { - var result = BridgeNative.BridgeCore_TickManyAndGetCommandStreams(corePtrs, (uint)count, dt, outPtrs, outLens); + var result = BridgeNative.BridgeCore_TickManyAndGetCommandStreams(corePtrs, (uint)count, dt, outStreams); if (result != BridgeResult.Ok) throw new InvalidOperationException($"BridgeCore_TickManyAndGetCommandStreams failed: {result}"); - - for (int i = 0; i < count; i++) - { - IntPtr ptr = outPtrs[i]; - uint len = outLens[i]; - dst[i] = (ptr == IntPtr.Zero || len == 0) ? default : new CommandStream(ptr, len); - } } } } @@ -159,72 +136,19 @@ public static unsafe void TickManyAndGetCommandStreams(IntPtr[] coreHandles, flo if (count == 0) return; - if (count <= StackAllocMaxCount) + fixed (IntPtr* corePtrs = coreHandles) + fixed (CommandStream* outStreams = streams) { - fixed (IntPtr* corePtrs = coreHandles) - { - IntPtr* outPtrs = stackalloc IntPtr[count]; - uint* outLens = stackalloc uint[count]; - - var result = BridgeNative.BridgeCore_TickManyAndGetCommandStreams(corePtrs, (uint)count, dt, outPtrs, outLens); - if (result != BridgeResult.Ok) - throw new InvalidOperationException($"BridgeCore_TickManyAndGetCommandStreams failed: {result}"); - - fixed (CommandStream* dst = streams) - { - for (int i = 0; i < count; i++) - { - IntPtr ptr = outPtrs[i]; - uint len = outLens[i]; - dst[i] = (ptr == IntPtr.Zero || len == 0) ? default : new CommandStream(ptr, len); - } - } - } - } - else - { - EnsureTickManyOutArrays(count); - - IntPtr[] outPtrsManaged = s_tickManyOutPtrs!; - uint[] outLensManaged = s_tickManyOutLens!; - - fixed (IntPtr* corePtrs = coreHandles) - fixed (IntPtr* outPtrs = outPtrsManaged) - fixed (uint* outLens = outLensManaged) - fixed (CommandStream* dst = streams) - { - var result = BridgeNative.BridgeCore_TickManyAndGetCommandStreams(corePtrs, (uint)count, dt, outPtrs, outLens); - if (result != BridgeResult.Ok) - throw new InvalidOperationException($"BridgeCore_TickManyAndGetCommandStreams failed: {result}"); - - for (int i = 0; i < count; i++) - { - IntPtr ptr = outPtrs[i]; - uint len = outLens[i]; - dst[i] = (ptr == IntPtr.Zero || len == 0) ? default : new CommandStream(ptr, len); - } - } + var result = BridgeNative.BridgeCore_TickManyAndGetCommandStreams(corePtrs, (uint)count, dt, outStreams); + if (result != BridgeResult.Ok) + throw new InvalidOperationException($"BridgeCore_TickManyAndGetCommandStreams failed: {result}"); } } - private static void EnsureTickManyArrays(int count) + private static void EnsureTickManyCorePtrs(int count) { s_tickManyCorePtrs ??= new IntPtr[count]; - s_tickManyOutPtrs ??= new IntPtr[count]; - s_tickManyOutLens ??= new uint[count]; - if (s_tickManyCorePtrs.Length < count) s_tickManyCorePtrs = new IntPtr[count]; - if (s_tickManyOutPtrs.Length < count) s_tickManyOutPtrs = new IntPtr[count]; - if (s_tickManyOutLens.Length < count) s_tickManyOutLens = new uint[count]; - } - - private static void EnsureTickManyOutArrays(int count) - { - s_tickManyOutPtrs ??= new IntPtr[count]; - s_tickManyOutLens ??= new uint[count]; - - if (s_tickManyOutPtrs.Length < count) s_tickManyOutPtrs = new IntPtr[count]; - if (s_tickManyOutLens.Length < count) s_tickManyOutLens = new uint[count]; } /// diff --git a/Core/csharp/Bridge.Core/CommandStream.cs b/Core/csharp/Bridge.Core/CommandStream.cs index cc6cdfe..36ba450 100644 --- a/Core/csharp/Bridge.Core/CommandStream.cs +++ b/Core/csharp/Bridge.Core/CommandStream.cs @@ -1,14 +1,17 @@ using System; +using System.Runtime.InteropServices; namespace Bridge.Core { /// /// 原生侧返回的 command stream(指针 + 长度)。 /// + [StructLayout(LayoutKind.Sequential)] public readonly struct CommandStream { public readonly IntPtr Ptr; public readonly uint Length; + private readonly uint _reserved0; public bool IsEmpty => Ptr == IntPtr.Zero || Length == 0; @@ -18,6 +21,7 @@ internal CommandStream(IntPtr ptr, uint length) { Ptr = ptr; Length = length; + _reserved0 = 0; } } } diff --git a/Core/csharp/Bridge.Core/Interop/BridgeNative.cs b/Core/csharp/Bridge.Core/Interop/BridgeNative.cs index b4b1fb9..ccebf42 100644 --- a/Core/csharp/Bridge.Core/Interop/BridgeNative.cs +++ b/Core/csharp/Bridge.Core/Interop/BridgeNative.cs @@ -31,8 +31,7 @@ internal static extern unsafe BridgeResult BridgeCore_TickManyAndGetCommandStrea IntPtr* cores, uint count, float dt, - IntPtr* outPtrs, - uint* outLens); + CommandStream* outStreams); [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl)] internal static extern BridgeResult BridgeCore_GetCommandStream( diff --git a/Packages/com.unitynativescripting.bridgecore/Runtime/Bridge.Core/BridgeCore.cs b/Packages/com.unitynativescripting.bridgecore/Runtime/Bridge.Core/BridgeCore.cs index 1c82fee..55e2a90 100644 --- a/Packages/com.unitynativescripting.bridgecore/Runtime/Bridge.Core/BridgeCore.cs +++ b/Packages/com.unitynativescripting.bridgecore/Runtime/Bridge.Core/BridgeCore.cs @@ -16,8 +16,6 @@ public sealed class BridgeCore : IDisposable #endif [ThreadStatic] private static IntPtr[]? s_tickManyCorePtrs; - [ThreadStatic] private static IntPtr[]? s_tickManyOutPtrs; - [ThreadStatic] private static uint[]? s_tickManyOutLens; private IntPtr _handle; @@ -75,7 +73,7 @@ public static void PrepareTickManyCache(int count) if (count < 0) throw new ArgumentOutOfRangeException(nameof(count)); - EnsureTickManyArrays(count); + EnsureTickManyCorePtrs(count); } public static unsafe void TickManyAndGetCommandStreams(BridgeCore[] cores, float dt, CommandStream[] streams) @@ -101,30 +99,18 @@ public static unsafe void TickManyAndGetCommandStreams(BridgeCore[] cores, float corePtrs[i] = core._handle; } - IntPtr* outPtrs = stackalloc IntPtr[count]; - uint* outLens = stackalloc uint[count]; - - var result = BridgeNative.BridgeCore_TickManyAndGetCommandStreams(corePtrs, (uint)count, dt, outPtrs, outLens); - if (result != BridgeResult.Ok) - throw new InvalidOperationException($"BridgeCore_TickManyAndGetCommandStreams failed: {result}"); - - fixed (CommandStream* dst = streams) + fixed (CommandStream* outStreams = streams) { - for (int i = 0; i < count; i++) - { - IntPtr ptr = outPtrs[i]; - uint len = outLens[i]; - dst[i] = (ptr == IntPtr.Zero || len == 0) ? default : new CommandStream(ptr, len); - } + var result = BridgeNative.BridgeCore_TickManyAndGetCommandStreams(corePtrs, (uint)count, dt, outStreams); + if (result != BridgeResult.Ok) + throw new InvalidOperationException($"BridgeCore_TickManyAndGetCommandStreams failed: {result}"); } } else { - EnsureTickManyArrays(count); + EnsureTickManyCorePtrs(count); IntPtr[] corePtrsManaged = s_tickManyCorePtrs!; - IntPtr[] outPtrsManaged = s_tickManyOutPtrs!; - uint[] outLensManaged = s_tickManyOutLens!; for (int i = 0; i < count; i++) { @@ -134,20 +120,11 @@ public static unsafe void TickManyAndGetCommandStreams(BridgeCore[] cores, float } fixed (IntPtr* corePtrs = corePtrsManaged) - fixed (IntPtr* outPtrs = outPtrsManaged) - fixed (uint* outLens = outLensManaged) - fixed (CommandStream* dst = streams) + fixed (CommandStream* outStreams = streams) { - var result = BridgeNative.BridgeCore_TickManyAndGetCommandStreams(corePtrs, (uint)count, dt, outPtrs, outLens); + var result = BridgeNative.BridgeCore_TickManyAndGetCommandStreams(corePtrs, (uint)count, dt, outStreams); if (result != BridgeResult.Ok) throw new InvalidOperationException($"BridgeCore_TickManyAndGetCommandStreams failed: {result}"); - - for (int i = 0; i < count; i++) - { - IntPtr ptr = outPtrs[i]; - uint len = outLens[i]; - dst[i] = (ptr == IntPtr.Zero || len == 0) ? default : new CommandStream(ptr, len); - } } } } @@ -165,72 +142,19 @@ public static unsafe void TickManyAndGetCommandStreams(IntPtr[] coreHandles, flo if (count == 0) return; - if (count <= StackAllocMaxCount) + fixed (IntPtr* corePtrs = coreHandles) + fixed (CommandStream* outStreams = streams) { - fixed (IntPtr* corePtrs = coreHandles) - { - IntPtr* outPtrs = stackalloc IntPtr[count]; - uint* outLens = stackalloc uint[count]; - - var result = BridgeNative.BridgeCore_TickManyAndGetCommandStreams(corePtrs, (uint)count, dt, outPtrs, outLens); - if (result != BridgeResult.Ok) - throw new InvalidOperationException($"BridgeCore_TickManyAndGetCommandStreams failed: {result}"); - - fixed (CommandStream* dst = streams) - { - for (int i = 0; i < count; i++) - { - IntPtr ptr = outPtrs[i]; - uint len = outLens[i]; - dst[i] = (ptr == IntPtr.Zero || len == 0) ? default : new CommandStream(ptr, len); - } - } - } - } - else - { - EnsureTickManyOutArrays(count); - - IntPtr[] outPtrsManaged = s_tickManyOutPtrs!; - uint[] outLensManaged = s_tickManyOutLens!; - - fixed (IntPtr* corePtrs = coreHandles) - fixed (IntPtr* outPtrs = outPtrsManaged) - fixed (uint* outLens = outLensManaged) - fixed (CommandStream* dst = streams) - { - var result = BridgeNative.BridgeCore_TickManyAndGetCommandStreams(corePtrs, (uint)count, dt, outPtrs, outLens); - if (result != BridgeResult.Ok) - throw new InvalidOperationException($"BridgeCore_TickManyAndGetCommandStreams failed: {result}"); - - for (int i = 0; i < count; i++) - { - IntPtr ptr = outPtrs[i]; - uint len = outLens[i]; - dst[i] = (ptr == IntPtr.Zero || len == 0) ? default : new CommandStream(ptr, len); - } - } + var result = BridgeNative.BridgeCore_TickManyAndGetCommandStreams(corePtrs, (uint)count, dt, outStreams); + if (result != BridgeResult.Ok) + throw new InvalidOperationException($"BridgeCore_TickManyAndGetCommandStreams failed: {result}"); } } - private static void EnsureTickManyArrays(int count) + private static void EnsureTickManyCorePtrs(int count) { s_tickManyCorePtrs ??= new IntPtr[count]; - s_tickManyOutPtrs ??= new IntPtr[count]; - s_tickManyOutLens ??= new uint[count]; - if (s_tickManyCorePtrs.Length < count) s_tickManyCorePtrs = new IntPtr[count]; - if (s_tickManyOutPtrs.Length < count) s_tickManyOutPtrs = new IntPtr[count]; - if (s_tickManyOutLens.Length < count) s_tickManyOutLens = new uint[count]; - } - - private static void EnsureTickManyOutArrays(int count) - { - s_tickManyOutPtrs ??= new IntPtr[count]; - s_tickManyOutLens ??= new uint[count]; - - if (s_tickManyOutPtrs.Length < count) s_tickManyOutPtrs = new IntPtr[count]; - if (s_tickManyOutLens.Length < count) s_tickManyOutLens = new uint[count]; } /// diff --git a/Packages/com.unitynativescripting.bridgecore/Runtime/Bridge.Core/CommandStream.cs b/Packages/com.unitynativescripting.bridgecore/Runtime/Bridge.Core/CommandStream.cs index cc6cdfe..36ba450 100644 --- a/Packages/com.unitynativescripting.bridgecore/Runtime/Bridge.Core/CommandStream.cs +++ b/Packages/com.unitynativescripting.bridgecore/Runtime/Bridge.Core/CommandStream.cs @@ -1,14 +1,17 @@ using System; +using System.Runtime.InteropServices; namespace Bridge.Core { /// /// 原生侧返回的 command stream(指针 + 长度)。 /// + [StructLayout(LayoutKind.Sequential)] public readonly struct CommandStream { public readonly IntPtr Ptr; public readonly uint Length; + private readonly uint _reserved0; public bool IsEmpty => Ptr == IntPtr.Zero || Length == 0; @@ -18,6 +21,7 @@ internal CommandStream(IntPtr ptr, uint length) { Ptr = ptr; Length = length; + _reserved0 = 0; } } } diff --git a/Packages/com.unitynativescripting.bridgecore/Runtime/Bridge.Core/Interop/BridgeNative.cs b/Packages/com.unitynativescripting.bridgecore/Runtime/Bridge.Core/Interop/BridgeNative.cs index ada1def..8783dc9 100644 --- a/Packages/com.unitynativescripting.bridgecore/Runtime/Bridge.Core/Interop/BridgeNative.cs +++ b/Packages/com.unitynativescripting.bridgecore/Runtime/Bridge.Core/Interop/BridgeNative.cs @@ -36,8 +36,7 @@ private unsafe delegate BridgeResult BridgeCore_TickManyAndGetCommandStreamsDele IntPtr* cores, uint count, float dt, - IntPtr* outPtrs, - uint* outLens); + CommandStream* outStreams); [UnmanagedFunctionPointer(CallingConvention.Cdecl)] private delegate BridgeResult BridgeCore_GetCommandStreamDelegate(IntPtr core, out IntPtr ptr, out uint len); @@ -120,11 +119,10 @@ internal static unsafe BridgeResult BridgeCore_TickManyAndGetCommandStreams( IntPtr* cores, uint count, float dt, - IntPtr* outPtrs, - uint* outLens) + CommandStream* outStreams) { EnsureBound(); - return s_tickManyAndGetCommandStreams(cores, count, dt, outPtrs, outLens); + return s_tickManyAndGetCommandStreams(cores, count, dt, outStreams); } internal static BridgeResult BridgeCore_GetCommandStream(IntPtr core, out IntPtr ptr, out uint len) @@ -170,8 +168,7 @@ internal static extern unsafe BridgeResult BridgeCore_TickManyAndGetCommandStrea IntPtr* cores, uint count, float dt, - IntPtr* outPtrs, - uint* outLens); + CommandStream* outStreams); [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl)] internal static extern BridgeResult BridgeCore_GetCommandStream( From 88517ccceea500e4ece9adcb01e07f3eb6623261 Mon Sep 17 00:00:00 2001 From: lcals Date: Thu, 22 Jan 2026 11:26:00 +0800 Subject: [PATCH 32/33] =?UTF-8?q?=E6=8F=90=E4=BA=A4=E6=80=A7=E8=83=BD?= =?UTF-8?q?=E8=AE=B0=E5=BD=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 393a3e3..91840c3 100644 --- a/README.md +++ b/README.md @@ -82,6 +82,7 @@ powershell -ExecutionPolicy Bypass -File Tools/RunPerf.ps1 -Bots 1000 -Frames 30 | tsUtc | runId | tag | git | robothost_null cmd/s | robot_runner cmd/s | robot_runner ticks/s | il2cpp_source 1k ticks/s | il2cpp_source 10k ticks/s | |---|---|---|---|---:|---:|---:|---:|---:| +| 2026-01-22T03:19:16.3595605Z | 20260122_111835 | tickmany_stream_direct_clean_r3 | 0b529e2 | 28172609 | 66324333 | 66666666.67 | 66351247.58 | 43464276.71 | | 2026-01-21T13:33:27.2531131Z | 20260121_213218 | post_4bfba43_shrink_header | 4bfba43 | 24956397 | 82791134 | 83333333.33 | 53676144.98 | 38640229.71 | | 2026-01-21T13:19:57.4007236Z | 20260121_211854 | probe_9219989_stable_window | 9219989 | 24159430 | 80006607 | 78947368.42 | 49798159.76 | 34168195.22 | | 2026-01-21T13:15:08.8643720Z | 20260121_211406 | post_912e0e5_unchecked_now | 326156a | 25574750 | 74101492 | 73170731.71 | 56039152.69 | 37078326.73 | @@ -111,3 +112,4 @@ powershell -ExecutionPolicy Bypass -File Tools/RunPerf.ps1 -Bots 1000 -Frames 30 + From 170abd81b5252f7d7b0f2a26d06a64139e97a3b7 Mon Sep 17 00:00:00 2001 From: lcals Date: Thu, 22 Jan 2026 12:20:42 +0800 Subject: [PATCH 33/33] docs: record TickMany IL2CPP perf notes --- Core/docs/PERF_NOTES.md | 23 +++++++++++++++++++++++ Core/docs/PERF_OPTIMIZATIONS.md | 30 ++++++++++++++++++++++++++++++ 2 files changed, 53 insertions(+) create mode 100644 Core/docs/PERF_NOTES.md diff --git a/Core/docs/PERF_NOTES.md b/Core/docs/PERF_NOTES.md new file mode 100644 index 0000000..710b23c --- /dev/null +++ b/Core/docs/PERF_NOTES.md @@ -0,0 +1,23 @@ +# 性能探索笔记(方便下次接着做) + +本文件用于记录“做过但未必有效/已撤回”的探索性尝试,避免下次重复走弯路。 + +> 已验证确定提升的改动请写到:`Core/docs/PERF_OPTIMIZATIONS.md` + +## 2026-01-22:仿 Puerts 的 IL2CPP InternalCall/vtable dispatch(未带来收益,已撤回) + +**目标** +- 把 `BridgeAllCommandDispatcher.DispatchFastUnchecked` 的 “解析 + 分发” 下沉到 native,通过 IL2CPP 内部 API(InternalCalls + vtable slot)直接调用 Host 的虚函数,期望减少 IL2CPP 生成代码的热点开销。 + +**实现思路(POC)** +- 在 native(源码插件)里注册一个 `InternalCall`: + - `Bridge.Core.Unity.Il2cppDispatch::DispatchFastUnchecked(IntPtr streamPtr, UInt32 streamLen, Object host)` +- 启动时做一次初始化: + - 找到 `Bridge.Bindings.BridgeAllHostApiBase`,用 `il2cpp_class_get_method_from_name` 取到各虚函数的 `slot`。 + - 分发时用 `host->klass->vtable[slot]` 取到 `VirtualInvokeData`,然后直接调用 `methodPtr`。 +- command 解析沿用现有 `BridgeCmdCallHost` 格式,payload struct 复用生成的 `Tests/cpp/generated/*.generated.h`(`HostFuncId` + `HostArgs_*`)。 + +**结论** +- 在当前测试场景(Unity IL2CPP Source,命令解析与 Host dispatch 已经是 IL2CPP 生成的 C++),这个方向几乎不赚,甚至可能因为额外的 InternalCall/初始化/不可内联等因素略亏。 +- 后续如要继续从 “Host dispatch” 榨性能,优先考虑减少“每帧/每 bot”的 managed 热点循环(例如把更大粒度的批处理下沉),而不是单纯把 dispatch 逻辑从 C# 迁到另一套 native dispatch。 + diff --git a/Core/docs/PERF_OPTIMIZATIONS.md b/Core/docs/PERF_OPTIMIZATIONS.md index 150d89b..eeba70c 100644 --- a/Core/docs/PERF_OPTIMIZATIONS.md +++ b/Core/docs/PERF_OPTIMIZATIONS.md @@ -42,6 +42,7 @@ pwsh -NoProfile -ExecutionPolicy Bypass -File Tools/RunPerf.ps1 -UnityVersion 60 **改动** - 在 `TickManyAndGetCommandStreams` 写回阶段,改为 `fixed (CommandStream* dst = streams)`,用 `dst[i] = ...` 直接写入。 +- 后续:`0b529e2` 进一步把 “写回阶段” 下沉到 native(直接写 `CommandStream[]`),避免 Host 侧组合/拷贝;见记录 7)。 **位置** - `Core/csharp/Bridge.Core/BridgeCore.cs` @@ -175,6 +176,35 @@ pwsh -NoProfile -ExecutionPolicy Bypass -File Tools/RunPerf.ps1 -UnityVersion 60 - `total_bytes`:10k*3000 从约 `1,200,000,000` 降到 `960,000,000`(-20%) - Unity IL2CPP Source:10k `ticks/s` 约 `34.17M` → `38.64M`(明显提升,见对应 runId) +### 7) TickMany:native 直接写入 `CommandStream[]`(去掉 out_ptr/out_len 组合;破坏性 ABI 变更) + +**引入** +- git:`0b529e2` +- 验证:Unity `6000.0.40f1` + - tag=`tickmany_stream_direct_clean_r3`;runId=`20260122_111835`(repeat=3) +- 对比:tag=`post_4bfba43_shrink_header`;runId=`20260121_213218`(repeat=3) + +**现象(IL2CPP 输出)** +- 旧的批量 Tick ABI 需要 Core 输出两段数组(`out_ptrs`/`out_lens`),Host 再把它们逐项组合成 `CommandStream[]`。 +- 在 IL2CPP 下这会生成额外的组合循环与数组访问路径(容易出现 `SetAt`/边界检查/struct 拷贝),在 1k/10k bots 下被放大。 + +**改动** +- C ABI 改为:`BridgeCore_TickManyAndGetCommandStreams(..., BridgeCommandStream* out_streams)`,由 native 直接填充 `{ptr,len}`。 +- C# 侧让 `CommandStream` 与 `BridgeCommandStream` 内存布局一致(新增 `_reserved0`),并把 `streams` 直接固定后传入 native(不再有 “out_ptr/out_len → streams” 的组合阶段)。 + +**位置** +- C ABI:`Core/cpp/include/bridge/bridge.h`、`Core/cpp/src/api/bridge_api.cpp` +- C# interop: + - `Core/csharp/Bridge.Core/CommandStream.cs` + - `Core/csharp/Bridge.Core/Interop/BridgeNative.cs` + - `Core/csharp/Bridge.Core/BridgeCore.cs` + - `Packages/com.unitynativescripting.bridgecore/Runtime/Bridge.Core/CommandStream.cs` + - `Packages/com.unitynativescripting.bridgecore/Runtime/Bridge.Core/Interop/BridgeNative.cs` + - `Packages/com.unitynativescripting.bridgecore/Runtime/Bridge.Core/BridgeCore.cs` + +**效果** +- Unity IL2CPP Source 的 `ticks/s`(1k/10k)有稳定提升(见 `README.md` 性能摘要表与对应 runId)。 + ## 优化流程建议(只在提升时记录/提交) 1. 做一次“小步”改动(只动一个热点点位)。