#include "Scripting/Mono/MonoScriptRuntime.h" #include "Components/CameraComponent.h" #include "Components/GameObject.h" #include "Components/LightComponent.h" #include "Components/MeshFilterComponent.h" #include "Components/MeshRendererComponent.h" #include "Components/RigidbodyComponent.h" #include "Components/TransformComponent.h" #include "Debug/Logger.h" #include "Input/InputManager.h" #include "Physics/PhysicsWorld.h" #include "Rendering/Caches/DirectionalShadowSurfaceCache.h" #include "Rendering/Execution/CameraFramePlan.h" #include "Rendering/Execution/DirectionalShadowExecutionState.h" #include "Rendering/Execution/CameraFrameRenderGraphFrameData.h" #include "Rendering/Execution/Internal/CameraFrameGraph/SurfaceUtils.h" #include "Rendering/Graph/RenderGraph.h" #include "Rendering/Graph/RenderGraphRecordingContext.h" #include "Rendering/GraphicsSettingsState.h" #include "Rendering/Internal/RenderPipelineFactory.h" #include "Rendering/Passes/BuiltinFinalColorPass.h" #include "Rendering/Passes/BuiltinVectorFullscreenPass.h" #include "Rendering/Planning/FullscreenPassDesc.h" #include "Rendering/Planning/SceneRenderRequestPlanner.h" #include "Rendering/Pipelines/NativeSceneRecorder.h" #include "Rendering/Pipelines/ManagedScriptableRenderPipelineAsset.h" #include "Rendering/RenderPassGraphContract.h" #include "Rendering/RenderPipeline.h" #include "Rendering/RenderPipelineAsset.h" #include "Rendering/RenderPipelineStageGraphContract.h" #include "Resources/BuiltinResources.h" #include "Core/Asset/ResourceManager.h" #include "Scene/Scene.h" #include "Scripting/ScriptComponent.h" #include "Scripting/ScriptEngine.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace XCEngine { namespace Scripting { namespace { constexpr const char* kManagedRenderingNamespace = "XCEngine.Rendering"; struct MonoRootState { MonoDomain* rootDomain = nullptr; bool initialized = false; bool cleanupRegistered = false; }; enum class ManagedComponentKind { Unknown, Script, Transform, Rigidbody, Camera, Light, MeshFilter, MeshRenderer, }; struct ManagedComponentTypeInfo { ManagedComponentKind kind = ManagedComponentKind::Unknown; MonoClass* monoClass = nullptr; std::string assemblyName; std::string namespaceName; std::string className; }; MonoRootState& GetMonoRootState() { static MonoRootState state; return state; } Components::Scene*& GetInternalCallScene() { static Components::Scene* scene = nullptr; return scene; } float& GetInternalCallDeltaTime() { static float deltaTime = 0.0f; return deltaTime; } bool& GetInternalCallRegistrationState() { static bool registered = false; return registered; } struct ManagedScriptableRenderContextState { uint64_t handle = 0; Rendering::CameraFrameStage stage = Rendering::CameraFrameStage::MainScene; const Rendering::RenderPipelineStageRenderGraphContext* graphContext = nullptr; Rendering::Pipelines::NativeSceneRecorder* sceneRecorder = nullptr; struct RasterPassRecordRequest { Containers::String passName = {}; Rendering::FullscreenPassDesc passDesc = {}; Rendering::RenderGraphTextureHandle sourceColorTexture = {}; std::vector readTextures = {}; std::vector readDepthTextures = {}; std::vector textureBindings = {}; std::vector colorTargets = {}; Rendering::RenderGraphTextureHandle depthTarget = {}; }; uint64_t nextPendingRasterPassHandle = 1u; std::unordered_map pendingRasterPassRequests = {}; std::vector rasterPassRequests = {}; }; struct ManagedCameraRenderRequestContextState { uint64_t handle = 0; Rendering::CameraRenderRequest* request = nullptr; size_t renderedBaseCameraCount = 0u; size_t renderedRequestCount = 0u; Rendering::DirectionalShadowPlanningSettings directionalShadowPlanningSettings = {}; bool suppressDirectionalShadow = false; }; struct ManagedRenderSceneSetupContextState { uint64_t handle = 0; const Rendering::CameraFramePlan* plan = nullptr; Rendering::RenderSceneData* sceneData = nullptr; bool explicitlyConfigured = false; }; struct ManagedDirectionalShadowExecutionContextState { uint64_t handle = 0; const Rendering::CameraFramePlan* plan = nullptr; const Rendering::DirectionalShadowSurfaceAllocation* shadowAllocation = nullptr; Rendering::DirectionalShadowExecutionState* shadowState = nullptr; bool explicitlyConfigured = false; }; struct ManagedScriptableRenderPipelinePlanningContextState { uint64_t handle = 0; Rendering::CameraFramePlan* plan = nullptr; }; uint64_t& GetManagedScriptableRenderContextNextHandle() { static uint64_t nextHandle = 1; return nextHandle; } std::unordered_map& GetManagedScriptableRenderContextRegistry() { static std::unordered_map registry; return registry; } ManagedScriptableRenderContextState* FindManagedScriptableRenderContextState( uint64_t handle) { const auto it = GetManagedScriptableRenderContextRegistry().find(handle); return it != GetManagedScriptableRenderContextRegistry().end() ? it->second : nullptr; } ManagedScriptableRenderContextState::RasterPassRecordRequest* FindPendingManagedRasterPassRecordRequest( ManagedScriptableRenderContextState* state, uint64_t rasterPassHandle) { if (state == nullptr || rasterPassHandle == 0u) { return nullptr; } const auto it = state->pendingRasterPassRequests.find(rasterPassHandle); return it != state->pendingRasterPassRequests.end() ? &it->second : nullptr; } uint64_t RegisterManagedScriptableRenderContextState( ManagedScriptableRenderContextState& state) { uint64_t handle = GetManagedScriptableRenderContextNextHandle()++; if (handle == 0) { handle = GetManagedScriptableRenderContextNextHandle()++; } state.handle = handle; GetManagedScriptableRenderContextRegistry()[handle] = &state; return handle; } void UnregisterManagedScriptableRenderContextState(uint64_t handle) { if (handle == 0) { return; } GetManagedScriptableRenderContextRegistry().erase(handle); } const Rendering::RenderCameraData& ResolveManagedScriptableRenderContextCameraData( const ManagedScriptableRenderContextState* state) { if (state != nullptr && state->graphContext != nullptr) { return state->graphContext->sceneData.cameraData; } static const Rendering::RenderCameraData kDefaultCameraData = {}; return kDefaultCameraData; } const Rendering::RenderLightingData& ResolveManagedScriptableRenderContextLightingData( const ManagedScriptableRenderContextState* state) { if (state != nullptr && state->graphContext != nullptr) { return state->graphContext->sceneData.lighting; } static const Rendering::RenderLightingData kDefaultLightingData = {}; return kDefaultLightingData; } const Rendering::RenderEnvironmentData& ResolveManagedScriptableRenderContextEnvironmentData( const ManagedScriptableRenderContextState* state) { if (state != nullptr && state->graphContext != nullptr) { return state->graphContext->sceneData.environment; } static const Rendering::RenderEnvironmentData kDefaultEnvironmentData = {}; return kDefaultEnvironmentData; } const Rendering::ResolvedFinalColorPolicy& ResolveManagedScriptableRenderContextFinalColorPolicy( const ManagedScriptableRenderContextState* state) { if (state != nullptr && state->graphContext != nullptr) { return state->graphContext->finalColorPolicy; } static const Rendering::ResolvedFinalColorPolicy kDefaultFinalColorPolicy = {}; return kDefaultFinalColorPolicy; } Rendering::CameraFrameColorSource ResolveManagedScriptableRenderContextStageColorSource( const ManagedScriptableRenderContextState* state) { if (state != nullptr && state->graphContext != nullptr) { return state->graphContext->stageColorSource; } return Rendering::CameraFrameColorSource::ExplicitSurface; } bool ResolveManagedScriptableRenderContextUsesGraphManagedOutputColor( const ManagedScriptableRenderContextState* state) { return state != nullptr && state->graphContext != nullptr && state->graphContext->usesGraphManagedOutputColor; } int32_t EncodeManagedRenderGraphTextureHandle( Rendering::RenderGraphTextureHandle handle) { return handle.IsValid() ? static_cast(handle.index) : -1; } Rendering::RenderGraphTextureHandle DecodeManagedRenderGraphTextureHandle( int32_t handleValue) { Rendering::RenderGraphTextureHandle handle = {}; if (handleValue < 0) { return handle; } handle.index = static_cast(handleValue); return handle; } Rendering::RenderGraphTextureHandle ResolveManagedScriptableRenderContextSourceColorTexture( const ManagedScriptableRenderContextState* state) { if (state == nullptr || state->graphContext == nullptr) { return {}; } if (state->graphContext->sourceColorTexture.IsValid()) { return state->graphContext->sourceColorTexture; } const Rendering::CameraFrameRenderGraphResources* const resources = Rendering::TryGetCameraFrameRenderGraphResources( state->graphContext->blackboard); if (resources == nullptr) { return {}; } switch (state->stage) { case Rendering::CameraFrameStage::PostProcess: return resources->mainScene.color; case Rendering::CameraFrameStage::FinalOutput: return resources->postProcess.color.IsValid() ? resources->postProcess.color : resources->mainScene.color; default: return {}; } } Rendering::RenderGraphTextureHandle ResolveManagedPrimaryColorTarget( const std::vector& colorTargets) { const auto it = std::find_if( colorTargets.begin(), colorTargets.end(), [](Rendering::RenderGraphTextureHandle handle) { return handle.IsValid(); }); return it != colorTargets.end() ? *it : Rendering::RenderGraphTextureHandle{}; } Rendering::RenderGraphTextureHandle ResolveManagedScriptableRenderContextPrimaryColorTarget( const ManagedScriptableRenderContextState* state) { if (state == nullptr || state->graphContext == nullptr) { return {}; } return ResolveManagedPrimaryColorTarget( state->graphContext->colorTargets); } Rendering::RenderGraphTextureHandle ResolveManagedScriptableRenderContextDepthTarget( const ManagedScriptableRenderContextState* state) { return state != nullptr && state->graphContext != nullptr ? state->graphContext->depthTarget : Rendering::RenderGraphTextureHandle{}; } Rendering::RenderGraphTextureDesc BuildManagedFullscreenTransientDepthTextureDesc( const Rendering::RenderSurface& surface) { Rendering::RenderGraphTextureDesc desc = {}; desc.width = surface.GetWidth() > 0u ? surface.GetWidth() : surface.GetRenderAreaWidth(); desc.height = surface.GetHeight() > 0u ? surface.GetHeight() : surface.GetRenderAreaHeight(); desc.format = static_cast( RHI::Format::D24_UNorm_S8_UInt); desc.textureType = static_cast( RHI::TextureType::Texture2D); desc.sampleCount = 1u; desc.sampleQuality = 0u; return desc; } Rendering::RenderGraphRecordingSourceBinding BuildManagedScriptableRenderContextSourceBinding( const Rendering::RenderPipelineStageRenderGraphContext& context, Rendering::RenderGraphTextureHandle sourceColorTexture) { if (!sourceColorTexture.IsValid()) { return {}; } Rendering::RenderGraphRecordingSourceBinding binding = Rendering::MakeRenderGraphRecordingSourceBinding( context.sourceSurface, context.sourceColorView, context.sourceColorState, sourceColorTexture); const bool usesContextSource = context.sourceColorTexture.IsValid() && context.sourceColorTexture.index == sourceColorTexture.index; if (!usesContextSource) { binding.sourceColorView = nullptr; binding.sourceColorState = RHI::ResourceStates::PixelShaderResource; } if (binding.sourceSurface == nullptr) { binding.sourceSurface = &context.surfaceTemplate; } return binding; } bool RecordManagedFullscreenRasterPass( const Rendering::RenderPipelineStageRenderGraphContext& stageContext, Rendering::RenderPass& pass, Rendering::RenderGraphTextureHandle sourceColorTexture, std::vector colorTargets, std::vector additionalReadTextures, std::vector additionalReadDepthTextures, std::vector textureBindings, Rendering::RenderGraphTextureHandle depthTarget, const Containers::String& passName) { if (!Rendering::IsCameraFrameFullscreenSequenceStage(stageContext.stage) || !sourceColorTexture.IsValid() || !ResolveManagedPrimaryColorTarget(colorTargets).IsValid()) { return false; } const Rendering::RenderGraphRecordingContext baseContext = Rendering::BuildRenderGraphRecordingContext( stageContext); Rendering::RenderGraphRecordingContextBuildParams params = {}; if (!passName.Empty()) { params.passName = &passName; } params.overrideSourceBinding = true; params.sourceBinding = BuildManagedScriptableRenderContextSourceBinding( stageContext, sourceColorTexture); params.overrideColorTargets = true; params.colorTargets = std::move(colorTargets); params.overrideDepthTarget = true; params.depthTarget = depthTarget; const Rendering::RenderGraphRecordingContext recordingContext = Rendering::BuildRenderGraphRecordingContext( baseContext, std::move(params)); const Rendering::RenderPassRenderGraphContext renderGraphContext = Rendering::BuildRenderPassRenderGraphContext(recordingContext); Rendering::RenderPass* const passPtr = &pass; Rendering::RenderPassGraphIO io = Rendering::BuildSourceColorFullscreenRasterPassGraphIO(); io.writeDepth = depthTarget.IsValid(); return Rendering::RecordCallbackRasterRenderPass( renderGraphContext, io, [passPtr](const Rendering::RenderPassContext& passContext) { return passPtr != nullptr && passPtr->Execute(passContext); }, std::move(additionalReadTextures), std::move(additionalReadDepthTextures), std::move(textureBindings)); } bool RecordManagedFullscreenPassToTexture( const Rendering::RenderPipelineStageRenderGraphContext& stageContext, Rendering::RenderPass& pass, Rendering::RenderGraphTextureHandle sourceColorTexture, Rendering::RenderGraphTextureHandle outputColorTexture, const Containers::String& passName) { return RecordManagedFullscreenRasterPass( stageContext, pass, sourceColorTexture, { outputColorTexture }, {}, {}, {}, {}, passName); } const Rendering::DirectionalShadowRenderPlan& ResolveManagedScriptableRenderContextDirectionalShadowPlan( const ManagedScriptableRenderContextState* state) { if (state != nullptr && state->graphContext != nullptr) { return state->graphContext->directionalShadowPlan; } static const Rendering::DirectionalShadowRenderPlan kDefaultDirectionalShadowPlan = {}; return kDefaultDirectionalShadowPlan; } uint64_t& GetManagedCameraRenderRequestContextNextHandle() { static uint64_t nextHandle = 1; return nextHandle; } std::unordered_map& GetManagedCameraRenderRequestContextRegistry() { static std::unordered_map registry; return registry; } ManagedCameraRenderRequestContextState* FindManagedCameraRenderRequestContextState( uint64_t handle) { const auto it = GetManagedCameraRenderRequestContextRegistry().find(handle); return it != GetManagedCameraRenderRequestContextRegistry().end() ? it->second : nullptr; } uint64_t RegisterManagedCameraRenderRequestContextState( ManagedCameraRenderRequestContextState& state) { uint64_t handle = GetManagedCameraRenderRequestContextNextHandle()++; if (handle == 0) { handle = GetManagedCameraRenderRequestContextNextHandle()++; } state.handle = handle; GetManagedCameraRenderRequestContextRegistry()[handle] = &state; return handle; } void UnregisterManagedCameraRenderRequestContextState( uint64_t handle) { if (handle == 0) { return; } GetManagedCameraRenderRequestContextRegistry().erase(handle); } uint64_t& GetManagedRenderSceneSetupContextNextHandle() { static uint64_t nextHandle = 1; return nextHandle; } std::unordered_map& GetManagedRenderSceneSetupContextRegistry() { static std::unordered_map registry; return registry; } ManagedRenderSceneSetupContextState* FindManagedRenderSceneSetupContextState( uint64_t handle) { const auto it = GetManagedRenderSceneSetupContextRegistry().find(handle); return it != GetManagedRenderSceneSetupContextRegistry().end() ? it->second : nullptr; } uint64_t RegisterManagedRenderSceneSetupContextState( ManagedRenderSceneSetupContextState& state) { uint64_t handle = GetManagedRenderSceneSetupContextNextHandle()++; if (handle == 0) { handle = GetManagedRenderSceneSetupContextNextHandle()++; } state.handle = handle; GetManagedRenderSceneSetupContextRegistry()[handle] = &state; return handle; } void UnregisterManagedRenderSceneSetupContextState( uint64_t handle) { if (handle == 0) { return; } GetManagedRenderSceneSetupContextRegistry().erase(handle); } uint64_t& GetManagedDirectionalShadowExecutionContextNextHandle() { static uint64_t nextHandle = 1; return nextHandle; } std::unordered_map< uint64_t, ManagedDirectionalShadowExecutionContextState*>& GetManagedDirectionalShadowExecutionContextRegistry() { static std::unordered_map< uint64_t, ManagedDirectionalShadowExecutionContextState*> registry; return registry; } ManagedDirectionalShadowExecutionContextState* FindManagedDirectionalShadowExecutionContextState( uint64_t handle) { const auto it = GetManagedDirectionalShadowExecutionContextRegistry().find( handle); return it != GetManagedDirectionalShadowExecutionContextRegistry() .end() ? it->second : nullptr; } uint64_t RegisterManagedDirectionalShadowExecutionContextState( ManagedDirectionalShadowExecutionContextState& state) { uint64_t handle = GetManagedDirectionalShadowExecutionContextNextHandle()++; if (handle == 0) { handle = GetManagedDirectionalShadowExecutionContextNextHandle()++; } state.handle = handle; GetManagedDirectionalShadowExecutionContextRegistry()[handle] = &state; return handle; } void UnregisterManagedDirectionalShadowExecutionContextState( uint64_t handle) { if (handle == 0) { return; } GetManagedDirectionalShadowExecutionContextRegistry().erase( handle); } uint64_t& GetManagedScriptableRenderPipelinePlanningContextNextHandle() { static uint64_t nextHandle = 1; return nextHandle; } std::unordered_map& GetManagedScriptableRenderPipelinePlanningContextRegistry() { static std::unordered_map< uint64_t, ManagedScriptableRenderPipelinePlanningContextState*> registry; return registry; } ManagedScriptableRenderPipelinePlanningContextState* FindManagedScriptableRenderPipelinePlanningContextState( uint64_t handle) { const auto it = GetManagedScriptableRenderPipelinePlanningContextRegistry().find( handle); return it != GetManagedScriptableRenderPipelinePlanningContextRegistry().end() ? it->second : nullptr; } uint64_t RegisterManagedScriptableRenderPipelinePlanningContextState( ManagedScriptableRenderPipelinePlanningContextState& state) { uint64_t handle = GetManagedScriptableRenderPipelinePlanningContextNextHandle()++; if (handle == 0) { handle = GetManagedScriptableRenderPipelinePlanningContextNextHandle()++; } state.handle = handle; GetManagedScriptableRenderPipelinePlanningContextRegistry()[handle] = &state; return handle; } void UnregisterManagedScriptableRenderPipelinePlanningContextState( uint64_t handle) { if (handle == 0) { return; } GetManagedScriptableRenderPipelinePlanningContextRegistry().erase(handle); } bool TryResolveManagedCameraFrameStage( int32_t value, Rendering::CameraFrameStage& outStage) { switch (value) { case static_cast(Rendering::CameraFrameStage::PreScenePasses): outStage = Rendering::CameraFrameStage::PreScenePasses; return true; case static_cast(Rendering::CameraFrameStage::ShadowCaster): outStage = Rendering::CameraFrameStage::ShadowCaster; return true; case static_cast(Rendering::CameraFrameStage::DepthOnly): outStage = Rendering::CameraFrameStage::DepthOnly; return true; case static_cast(Rendering::CameraFrameStage::MainScene): outStage = Rendering::CameraFrameStage::MainScene; return true; case static_cast(Rendering::CameraFrameStage::PostProcess): outStage = Rendering::CameraFrameStage::PostProcess; return true; case static_cast(Rendering::CameraFrameStage::FinalOutput): outStage = Rendering::CameraFrameStage::FinalOutput; return true; case static_cast(Rendering::CameraFrameStage::ObjectId): outStage = Rendering::CameraFrameStage::ObjectId; return true; case static_cast(Rendering::CameraFrameStage::PostScenePasses): outStage = Rendering::CameraFrameStage::PostScenePasses; return true; case static_cast(Rendering::CameraFrameStage::OverlayPasses): outStage = Rendering::CameraFrameStage::OverlayPasses; return true; default: outStage = Rendering::CameraFrameStage::MainScene; return false; } } void CleanupMonoRootDomainAtExit() { MonoRootState& rootState = GetMonoRootState(); if (!rootState.rootDomain) { return; } mono_domain_set(rootState.rootDomain, true); mono_jit_cleanup(rootState.rootDomain); rootState.rootDomain = nullptr; rootState.initialized = false; GetInternalCallRegistrationState() = false; } std::string BuildFullClassName(const std::string& namespaceName, const std::string& className) { return namespaceName.empty() ? className : namespaceName + "." + className; } std::string BuildClassKey( const std::string& assemblyName, const std::string& namespaceName, const std::string& className) { return assemblyName + "|" + BuildFullClassName(namespaceName, className); } std::string SafeString(const char* value) { return value ? std::string(value) : std::string(); } std::string TrimAssemblyName(const std::string& assemblyName) { constexpr const char* kDllSuffix = ".dll"; if (assemblyName.size() >= 4u && assemblyName.substr(assemblyName.size() - 4u) == kDllSuffix) { return assemblyName.substr(0u, assemblyName.size() - 4u); } return assemblyName; } std::string TrimWhitespace(std::string value) { auto isWhitespace = [](unsigned char ch) { return std::isspace(ch) != 0; }; value.erase( value.begin(), std::find_if( value.begin(), value.end(), [&](char ch) { return !isWhitespace(static_cast(ch)); })); value.erase( std::find_if( value.rbegin(), value.rend(), [&](char ch) { return !isWhitespace(static_cast(ch)); }).base(), value.end()); return value; } bool NormalizeManagedAssemblyDescriptor( MonoScriptRuntime::ManagedAssemblyDescriptor& descriptor, const std::filesystem::path& assemblyDirectory, std::unordered_set& ioAssemblyNames, std::string* outError) { descriptor.name = TrimAssemblyName(TrimWhitespace(descriptor.name)); if (descriptor.name.empty() && !descriptor.path.empty()) { descriptor.name = TrimAssemblyName(descriptor.path.stem().string()); } if (descriptor.name.empty()) { if (outError != nullptr) { *outError = "Managed engine assembly name is empty."; } return false; } if (descriptor.path.empty() && !assemblyDirectory.empty()) { descriptor.path = assemblyDirectory / (descriptor.name + ".dll"); } if (!descriptor.path.empty()) { descriptor.path = descriptor.path.lexically_normal(); } if (!ioAssemblyNames.insert(descriptor.name).second) { if (outError != nullptr) { *outError = "Managed engine assembly name is duplicated: " + descriptor.name; } return false; } return true; } bool LoadManagedAssemblyManifest( const std::filesystem::path& assemblyDirectory, const std::filesystem::path& manifestPath, std::vector& outAssemblies, std::string* outError) { outAssemblies.clear(); std::error_code ec; if (manifestPath.empty() || !std::filesystem::exists(manifestPath, ec)) { return true; } std::ifstream input(manifestPath); if (!input.is_open()) { if (outError != nullptr) { *outError = "Failed to open managed engine assembly manifest: " + manifestPath.string(); } return false; } std::unordered_set assemblyNames; std::string line; size_t lineNumber = 0u; while (std::getline(input, line)) { ++lineNumber; const size_t commentStart = line.find('#'); if (commentStart != std::string::npos) { line.erase(commentStart); } line = TrimWhitespace(std::move(line)); if (line.empty()) { continue; } MonoScriptRuntime::ManagedAssemblyDescriptor descriptor; const size_t separator = line.find('='); if (separator == std::string::npos) { descriptor.name = line; } else { descriptor.name = line.substr(0u, separator); std::string relativePath = TrimWhitespace(line.substr(separator + 1u)); if (!relativePath.empty()) { descriptor.path = (assemblyDirectory / relativePath).lexically_normal(); } } if (!NormalizeManagedAssemblyDescriptor( descriptor, assemblyDirectory, assemblyNames, outError)) { if (outError != nullptr && !outError->empty()) { *outError += " Manifest: " + manifestPath.string() + " line " + std::to_string(lineNumber) + "."; } return false; } outAssemblies.push_back(std::move(descriptor)); } return true; } bool DiscoverManagedAssembliesByConvention( const MonoScriptRuntime::Settings& settings, std::vector& outAssemblies) { outAssemblies.clear(); std::error_code ec; if (settings.assemblyDirectory.empty() || !std::filesystem::exists(settings.assemblyDirectory, ec)) { return true; } const std::string coreAssemblyName = TrimAssemblyName(settings.coreAssemblyName); const std::string appAssemblyName = TrimAssemblyName(settings.appAssemblyName); std::unordered_set reservedNames = { coreAssemblyName, appAssemblyName, "mscorlib"}; for (std::filesystem::directory_iterator it( settings.assemblyDirectory, ec), end; it != end && !ec; it.increment(ec)) { if (ec || !it->is_regular_file(ec)) { continue; } const std::filesystem::path path = it->path(); if (path.extension() != ".dll") { continue; } const std::string assemblyName = TrimAssemblyName(path.stem().string()); if (assemblyName.rfind("XCEngine.", 0u) != 0u || reservedNames.contains(assemblyName)) { continue; } outAssemblies.push_back( MonoScriptRuntime::ManagedAssemblyDescriptor{ assemblyName, path.lexically_normal()}); } std::sort( outAssemblies.begin(), outAssemblies.end(), [](const MonoScriptRuntime::ManagedAssemblyDescriptor& lhs, const MonoScriptRuntime::ManagedAssemblyDescriptor& rhs) { return lhs.name < rhs.name; }); return true; } MonoScriptRuntime::ManagedAssemblyDescriptor BuildManagedAssemblyDescriptor( const std::string& assemblyName, const std::filesystem::path& assemblyPath) { return MonoScriptRuntime::ManagedAssemblyDescriptor{ assemblyName, assemblyPath}; } bool IsMonoClassOrSubclass(MonoClass* monoClass, MonoClass* potentialBaseClass) { if (!monoClass || !potentialBaseClass) { return false; } return monoClass == potentialBaseClass || mono_class_is_subclass_of(monoClass, potentialBaseClass, 0) != 0; } std::string MonoStringToUtf8(MonoString* stringObject) { if (!stringObject) { return std::string(); } char* utf8 = mono_string_to_utf8(stringObject); std::string result = utf8 ? std::string(utf8) : std::string(); if (utf8) { mono_free(utf8); } return result; } MonoScriptRuntime* GetActiveMonoScriptRuntime() { return dynamic_cast(ScriptEngine::Get().GetRuntime()); } void ClearManagedRenderPipelineSelection(MonoScriptRuntime* runtime) { const Rendering::Pipelines::ManagedRenderPipelineAssetDescriptor descriptor = Rendering::GetGraphicsSettingsState() .GetConfiguredRenderPipelineAssetDescriptor(); if (runtime != nullptr && descriptor.managedAssetHandle != 0u) { runtime->ReleaseExternalManagedObject(descriptor.managedAssetHandle); } Rendering::GetGraphicsSettingsState() .ClearConfiguredRenderPipelineAssetDescriptor(); } bool TryUnboxManagedBoolean(MonoObject* boxedValue, bool& outValue) { outValue = false; if (!boxedValue) { return false; } void* const rawValue = mono_object_unbox(boxedValue); if (!rawValue) { return false; } outValue = (*static_cast(rawValue)) != 0; return true; } bool TryUnboxManagedInt32(MonoObject* boxedValue, int32_t& outValue) { outValue = 0; if (!boxedValue) { return false; } void* const rawValue = mono_object_unbox(boxedValue); if (!rawValue) { return false; } outValue = *static_cast(rawValue); return true; } struct ManagedFinalColorSettingsData { uint8_t outputTransferMode = 0; uint8_t exposureMode = 0; uint16_t exposurePadding = 0; float exposureValue = 1.0f; uint8_t toneMappingMode = 0; uint8_t toneMappingPadding[3] = {}; XCEngine::Math::Vector4 finalColorScale = XCEngine::Math::Vector4::One(); }; static_assert( sizeof(ManagedFinalColorSettingsData) == sizeof(Rendering::FinalColorSettings), "Managed final color bridge layout must match native FinalColorSettings."); struct ManagedFinalColorOverrideSettingsData { uint8_t overrideOutputTransferMode = 0u; uint8_t outputTransferMode = 0u; uint8_t overrideExposureMode = 0u; uint8_t exposureMode = 0u; uint8_t overrideExposureValue = 0u; uint8_t exposureValuePadding[3] = {}; float exposureValue = 1.0f; uint8_t overrideToneMappingMode = 0u; uint8_t toneMappingMode = 0u; uint8_t overrideFinalColorScale = 0u; uint8_t finalColorScalePadding = 0u; XCEngine::Math::Vector4 finalColorScale = XCEngine::Math::Vector4::One(); }; static_assert( sizeof(ManagedFinalColorOverrideSettingsData) == sizeof(Rendering::FinalColorOverrideSettings), "Managed final color override bridge layout must match native FinalColorOverrideSettings."); struct ManagedRenderGraphTextureDescData { uint32_t width = 0u; uint32_t height = 0u; uint32_t format = 0u; uint32_t textureType = 0u; uint32_t sampleCount = 0u; uint32_t sampleQuality = 0u; }; static_assert( sizeof(ManagedRenderGraphTextureDescData) == sizeof(Rendering::RenderGraphTextureDesc), "Managed render graph texture desc bridge layout must match native RenderGraphTextureDesc."); struct ManagedDirectionalShadowSamplingSettingsData { float receiverDepthBias = 0.0010f; float normalBiasScale = 2.0f; float shadowStrength = 0.85f; }; static_assert( sizeof(ManagedDirectionalShadowSamplingSettingsData) == sizeof(Rendering::DirectionalShadowSamplingSettings), "Managed directional shadow sampling bridge layout must match native DirectionalShadowSamplingSettings."); struct ManagedDirectionalShadowCasterBiasSettingsData { float depthBiasFactor = 2.5f; int32_t depthBiasUnits = 4; }; static_assert( sizeof(ManagedDirectionalShadowCasterBiasSettingsData) == sizeof(Rendering::DirectionalShadowCasterBiasSettings), "Managed directional shadow caster bias bridge layout must match native DirectionalShadowCasterBiasSettings."); struct ManagedDirectionalShadowPlanningSettingsData { uint32_t mapDimension = 2048u; float minFocusDistance = 5.0f; float maxFocusDistance = 32.0f; float perspectiveFocusFactor = 1.0f; float orthographicFocusFactor = 2.0f; float minDepthRange = 20.0f; float boundsPadding = 0.5f; float minDepthPadding = 2.0f; ManagedDirectionalShadowSamplingSettingsData sampling = {}; ManagedDirectionalShadowCasterBiasSettingsData casterBias = {}; }; static_assert( sizeof(ManagedDirectionalShadowPlanningSettingsData) == sizeof(Rendering::DirectionalShadowPlanningSettings), "Managed directional shadow planning bridge layout must match native DirectionalShadowPlanningSettings."); struct ManagedFilteringSettingsData { int32_t renderQueueMin = std::numeric_limits::lowest(); int32_t renderQueueMax = std::numeric_limits::max(); uint32_t renderLayerMask = std::numeric_limits::max(); uint8_t requireShadowCasting = 0u; uint8_t requireRenderObjectId = 0u; }; static_assert( sizeof(ManagedFilteringSettingsData) == sizeof(Rendering::FilteringSettings), "Managed filtering settings bridge layout must match native FilteringSettings."); struct ManagedSortingSettingsData { uint32_t sortMode = 0u; }; static_assert( sizeof(ManagedSortingSettingsData) == sizeof(Rendering::SortingSettings), "Managed sorting settings bridge layout must match native SortingSettings."); struct ManagedRendererListDescData { uint32_t type = 0u; ManagedFilteringSettingsData filtering = {}; ManagedSortingSettingsData sorting = {}; }; static_assert( sizeof(ManagedRendererListDescData) == sizeof(Rendering::RendererListDesc), "Managed renderer list desc bridge layout must match native RendererListDesc."); struct ManagedDepthStateData { uint8_t writeEnabled = 1u; uint8_t compareFunction = static_cast(Resources::MaterialComparisonFunc::Less); }; static_assert( sizeof(ManagedDepthStateData) == sizeof(Rendering::DepthState), "Managed depth state bridge layout must match native DepthState."); struct ManagedStencilFaceStateData { uint8_t failOperation = static_cast(Resources::MaterialStencilOp::Keep); uint8_t passOperation = static_cast(Resources::MaterialStencilOp::Keep); uint8_t depthFailOperation = static_cast(Resources::MaterialStencilOp::Keep); uint8_t compareFunction = static_cast(Resources::MaterialComparisonFunc::Always); }; static_assert( sizeof(ManagedStencilFaceStateData) == sizeof(Rendering::StencilFaceState), "Managed stencil face state bridge layout must match native StencilFaceState."); struct ManagedStencilStateData { uint8_t enabled = 0u; uint8_t readMask = 0xFFu; uint8_t writeMask = 0xFFu; ManagedStencilFaceStateData frontFace = {}; ManagedStencilFaceStateData backFace = {}; }; static_assert( sizeof(ManagedStencilStateData) == sizeof(Rendering::StencilState), "Managed stencil state bridge layout must match native StencilState."); struct ManagedRenderStateBlockData { uint32_t mask = 0u; ManagedDepthStateData depthState = {}; ManagedStencilStateData stencilState = {}; uint8_t stencilReference = 0u; }; static_assert( sizeof(ManagedRenderStateBlockData) == sizeof(Rendering::RenderStateBlock), "Managed render state block bridge layout must match native RenderStateBlock."); Rendering::FinalColorOutputTransferMode ResolveManagedFinalColorOutputTransferMode( uint8_t value) { switch (value) { case 1: return Rendering::FinalColorOutputTransferMode::LinearToSRGB; default: return Rendering::FinalColorOutputTransferMode::Disabled; } } Rendering::FinalColorExposureMode ResolveManagedFinalColorExposureMode( uint8_t value) { switch (value) { case 1: return Rendering::FinalColorExposureMode::Fixed; default: return Rendering::FinalColorExposureMode::Disabled; } } Rendering::FinalColorToneMappingMode ResolveManagedFinalColorToneMappingMode( uint8_t value) { switch (value) { case 1: return Rendering::FinalColorToneMappingMode::Neutral; case 2: return Rendering::FinalColorToneMappingMode::ACES; default: return Rendering::FinalColorToneMappingMode::Disabled; } } Resources::MaterialComparisonFunc ResolveManagedMaterialComparisonFunc( uint8_t value) { switch (value) { case static_cast(Resources::MaterialComparisonFunc::Never): return Resources::MaterialComparisonFunc::Never; case static_cast(Resources::MaterialComparisonFunc::Equal): return Resources::MaterialComparisonFunc::Equal; case static_cast(Resources::MaterialComparisonFunc::LessEqual): return Resources::MaterialComparisonFunc::LessEqual; case static_cast(Resources::MaterialComparisonFunc::Greater): return Resources::MaterialComparisonFunc::Greater; case static_cast(Resources::MaterialComparisonFunc::NotEqual): return Resources::MaterialComparisonFunc::NotEqual; case static_cast(Resources::MaterialComparisonFunc::GreaterEqual): return Resources::MaterialComparisonFunc::GreaterEqual; case static_cast(Resources::MaterialComparisonFunc::Always): return Resources::MaterialComparisonFunc::Always; case static_cast(Resources::MaterialComparisonFunc::Less): default: return Resources::MaterialComparisonFunc::Less; } } Resources::MaterialStencilOp ResolveManagedMaterialStencilOp( uint8_t value) { switch (value) { case static_cast(Resources::MaterialStencilOp::Zero): return Resources::MaterialStencilOp::Zero; case static_cast(Resources::MaterialStencilOp::Replace): return Resources::MaterialStencilOp::Replace; case static_cast(Resources::MaterialStencilOp::IncrSat): return Resources::MaterialStencilOp::IncrSat; case static_cast(Resources::MaterialStencilOp::DecrSat): return Resources::MaterialStencilOp::DecrSat; case static_cast(Resources::MaterialStencilOp::Invert): return Resources::MaterialStencilOp::Invert; case static_cast(Resources::MaterialStencilOp::IncrWrap): return Resources::MaterialStencilOp::IncrWrap; case static_cast(Resources::MaterialStencilOp::DecrWrap): return Resources::MaterialStencilOp::DecrWrap; case static_cast(Resources::MaterialStencilOp::Keep): default: return Resources::MaterialStencilOp::Keep; } } Rendering::RenderStateMask ResolveManagedRenderStateMask( uint32_t value) { const uint32_t knownMask = Rendering::ToRenderStateMaskBits(Rendering::RenderStateMask::Depth) | Rendering::ToRenderStateMaskBits(Rendering::RenderStateMask::Stencil); return static_cast( value & knownMask); } Rendering::DepthState BuildManagedDepthState( const ManagedDepthStateData& depthStateData) { Rendering::DepthState depthState = {}; depthState.writeEnabled = depthStateData.writeEnabled != 0u; depthState.compareFunction = ResolveManagedMaterialComparisonFunc( depthStateData.compareFunction); return depthState; } Rendering::StencilFaceState BuildManagedStencilFaceState( const ManagedStencilFaceStateData& stencilFaceData) { Rendering::StencilFaceState stencilFaceState = {}; stencilFaceState.failOp = ResolveManagedMaterialStencilOp( stencilFaceData.failOperation); stencilFaceState.passOp = ResolveManagedMaterialStencilOp( stencilFaceData.passOperation); stencilFaceState.depthFailOp = ResolveManagedMaterialStencilOp( stencilFaceData.depthFailOperation); stencilFaceState.compareFunction = ResolveManagedMaterialComparisonFunc( stencilFaceData.compareFunction); return stencilFaceState; } Rendering::StencilState BuildManagedStencilState( const ManagedStencilStateData& stencilStateData) { Rendering::StencilState stencilState = {}; stencilState.enabled = stencilStateData.enabled != 0u; stencilState.readMask = stencilStateData.readMask; stencilState.writeMask = stencilStateData.writeMask; stencilState.frontFace = BuildManagedStencilFaceState( stencilStateData.frontFace); stencilState.backFace = BuildManagedStencilFaceState( stencilStateData.backFace); return stencilState; } Rendering::RenderStateBlock BuildManagedRenderStateBlock( const ManagedRenderStateBlockData& renderStateBlockData) { Rendering::RenderStateBlock renderStateBlock = {}; renderStateBlock.mask = ResolveManagedRenderStateMask( renderStateBlockData.mask); renderStateBlock.depthState = BuildManagedDepthState( renderStateBlockData.depthState); renderStateBlock.stencilState = BuildManagedStencilState( renderStateBlockData.stencilState); renderStateBlock.stencilReference = renderStateBlockData.stencilReference; return renderStateBlock; } bool TryUnboxManagedFinalColorSettings( MonoObject* boxedValue, Rendering::FinalColorSettings& outSettings) { outSettings = {}; outSettings.exposureValue = 1.0f; outSettings.finalColorScale = XCEngine::Math::Vector4::One(); if (!boxedValue) { return false; } void* const rawValue = mono_object_unbox(boxedValue); if (!rawValue) { return false; } const auto* const managedSettings = static_cast(rawValue); outSettings.outputTransferMode = ResolveManagedFinalColorOutputTransferMode( managedSettings->outputTransferMode); outSettings.exposureMode = ResolveManagedFinalColorExposureMode( managedSettings->exposureMode); outSettings.exposureValue = managedSettings->exposureValue; outSettings.toneMappingMode = ResolveManagedFinalColorToneMappingMode( managedSettings->toneMappingMode); outSettings.finalColorScale = managedSettings->finalColorScale; return true; } Rendering::FinalColorSettings BuildManagedFinalColorSettings( const ManagedFinalColorSettingsData& managedSettings) { Rendering::FinalColorSettings settings = {}; settings.exposureValue = 1.0f; settings.finalColorScale = XCEngine::Math::Vector4::One(); settings.outputTransferMode = ResolveManagedFinalColorOutputTransferMode( managedSettings.outputTransferMode); settings.exposureMode = ResolveManagedFinalColorExposureMode( managedSettings.exposureMode); settings.exposureValue = managedSettings.exposureValue; settings.toneMappingMode = ResolveManagedFinalColorToneMappingMode( managedSettings.toneMappingMode); settings.finalColorScale = managedSettings.finalColorScale; return settings; } ManagedFinalColorOverrideSettingsData BuildManagedFinalColorOverrideSettings( const Rendering::FinalColorOverrideSettings& nativeSettings) { ManagedFinalColorOverrideSettingsData managedSettings = {}; managedSettings.overrideOutputTransferMode = nativeSettings.overrideOutputTransferMode ? 1u : 0u; managedSettings.outputTransferMode = static_cast(nativeSettings.outputTransferMode); managedSettings.overrideExposureMode = nativeSettings.overrideExposureMode ? 1u : 0u; managedSettings.exposureMode = static_cast(nativeSettings.exposureMode); managedSettings.overrideExposureValue = nativeSettings.overrideExposureValue ? 1u : 0u; managedSettings.exposureValue = nativeSettings.exposureValue; managedSettings.overrideToneMappingMode = nativeSettings.overrideToneMappingMode ? 1u : 0u; managedSettings.toneMappingMode = static_cast(nativeSettings.toneMappingMode); managedSettings.overrideFinalColorScale = nativeSettings.overrideFinalColorScale ? 1u : 0u; managedSettings.finalColorScale = nativeSettings.finalColorScale; return managedSettings; } bool SupportsManagedRenderPipelineStageGraphRecording( Rendering::CameraFrameStage stage) { return Rendering::SupportsCameraFramePipelineGraphRecording(stage) || Rendering::IsCameraFrameFullscreenSequenceStage(stage) || Rendering::IsCameraFrameScenePassRequestStage(stage); } bool SupportsManagedScriptableRenderContextSceneRecordingStage( Rendering::CameraFrameStage stage) { return stage == Rendering::CameraFrameStage::MainScene || Rendering::IsCameraFrameScenePassRequestStage(stage); } Rendering::RenderPass* ConfigureManagedFullscreenPass( std::vector>& passPool, size_t passIndex, const Rendering::FullscreenPassDesc& passDesc) { while (passPool.size() <= passIndex) { passPool.push_back(nullptr); } std::unique_ptr& passSlot = passPool[passIndex]; switch (passDesc.type) { case Rendering::FullscreenPassType::ColorScale: { Rendering::Passes::BuiltinVectorFullscreenPass* fullscreenPass = dynamic_cast( passSlot.get()); if (fullscreenPass == nullptr) { passSlot = std::make_unique(); fullscreenPass = static_cast( passSlot.get()); } fullscreenPass->SetShaderPath( Resources::GetBuiltinColorScalePostProcessShaderPath()); fullscreenPass->SetPreferredPassName("ColorScale"); fullscreenPass->SetVectorPayload(passDesc.colorScale.scale); return fullscreenPass; } case Rendering::FullscreenPassType::ShaderVector: { Rendering::Passes::BuiltinVectorFullscreenPass* fullscreenPass = dynamic_cast( passSlot.get()); if (fullscreenPass == nullptr) { passSlot = std::make_unique(); fullscreenPass = static_cast( passSlot.get()); } fullscreenPass->SetShaderPath(passDesc.shaderVector.shaderPath); fullscreenPass->SetPreferredPassName(passDesc.shaderVector.passName); fullscreenPass->SetVectorPayload(passDesc.shaderVector.vectorPayload); return fullscreenPass; } case Rendering::FullscreenPassType::FinalColor: { Rendering::Passes::BuiltinFinalColorPass* finalColorPass = dynamic_cast( passSlot.get()); if (finalColorPass == nullptr) { passSlot = std::make_unique(); finalColorPass = static_cast( passSlot.get()); } finalColorPass->SetShaderPath( Resources::GetBuiltinFinalColorShaderPath()); finalColorPass->SetSettings(passDesc.finalColor.settings); return finalColorPass; } default: return nullptr; } } } // namespace class MonoManagedRenderPipelineAssetRuntime final : public Rendering::Pipelines::ManagedRenderPipelineAssetRuntime , public std::enable_shared_from_this { public: MonoManagedRenderPipelineAssetRuntime( MonoScriptRuntime* runtime, std::weak_ptr runtimeLifetime, Rendering::Pipelines::ManagedRenderPipelineAssetDescriptor descriptor) : m_runtime(runtime) , m_runtimeLifetime(std::move(runtimeLifetime)) , m_descriptor(std::move(descriptor)) { } ~MonoManagedRenderPipelineAssetRuntime() override { ReleaseManagedAsset(); } std::unique_ptr CreateStageRecorder() const override; void ConfigureCameraRenderRequest( Rendering::CameraRenderRequest& request, size_t renderedBaseCameraCount, size_t renderedRequestCount, const Rendering::DirectionalShadowPlanningSettings& directionalShadowSettings) const override; void ConfigureCameraFramePlan( Rendering::CameraFramePlan& plan) const override; bool ConfigureRenderSceneSetup( const Rendering::CameraFramePlan& plan, Rendering::RenderSceneData& sceneData) const override; bool ConfigureDirectionalShadowExecutionState( const Rendering::CameraFramePlan& plan, const Rendering::DirectionalShadowSurfaceAllocation& shadowAllocation, Rendering::DirectionalShadowExecutionState& shadowState) const override; bool TryGetDefaultFinalColorSettings( Rendering::FinalColorSettings& settings) const override; std::shared_ptr GetSharedPipelineBackendAsset() const override; MonoScriptRuntime* GetRuntime() const { return m_runtime; } bool IsRuntimeAlive() const { return m_runtime != nullptr && !m_runtimeLifetime.expired() && m_runtime->m_initialized; } bool AcquireManagedPipelineHandle(uint32_t& outPipelineHandle) const; private: bool EnsureManagedAsset() const; bool SyncManagedAssetRuntimeState() const; bool TryGetManagedRuntimeResourceVersion(int32_t& outVersion) const; void ReleaseManagedPipeline() const; void ReleaseManagedAsset() const; MonoObject* GetManagedAssetObject() const; MonoMethod* ResolveDisposePipelineMethod(MonoObject* pipelineObject) const; MonoMethod* ResolveCreatePipelineMethod(MonoObject* assetObject) const; MonoMethod* ResolveConfigureCameraRenderRequestMethod( MonoObject* assetObject) const; MonoMethod* ResolveConfigureCameraFramePlanMethod( MonoObject* assetObject) const; MonoMethod* ResolveGetDefaultFinalColorSettingsMethod( MonoObject* assetObject) const; MonoMethod* ResolveGetRuntimeResourceVersionMethod( MonoObject* assetObject) const; MonoMethod* ResolveConfigureRenderSceneSetupMethod( MonoObject* assetObject) const; MonoMethod* ResolveConfigureDirectionalShadowExecutionStateMethod( MonoObject* assetObject) const; MonoMethod* ResolveReleaseRuntimeResourcesMethod( MonoObject* assetObject) const; MonoScriptRuntime* m_runtime = nullptr; std::weak_ptr m_runtimeLifetime; Rendering::Pipelines::ManagedRenderPipelineAssetDescriptor m_descriptor; mutable uint32_t m_assetHandle = 0; mutable MonoMethod* m_disposePipelineMethod = nullptr; mutable MonoMethod* m_createPipelineMethod = nullptr; mutable MonoMethod* m_configureCameraRenderRequestMethod = nullptr; mutable MonoMethod* m_configureCameraFramePlanMethod = nullptr; mutable MonoMethod* m_getDefaultFinalColorSettingsMethod = nullptr; mutable MonoMethod* m_getRuntimeResourceVersionMethod = nullptr; mutable MonoMethod* m_configureRenderSceneSetupMethod = nullptr; mutable MonoMethod* m_configureDirectionalShadowExecutionStateMethod = nullptr; mutable MonoMethod* m_releaseRuntimeResourcesMethod = nullptr; mutable bool m_ownsManagedAssetHandle = false; mutable bool m_assetCreationAttempted = false; mutable bool m_runtimeResourceVersionResolved = false; mutable int32_t m_runtimeResourceVersion = 0; mutable uint32_t m_pipelineHandle = 0; mutable bool m_pipelineCreationAttempted = false; mutable bool m_sharedPipelineBackendAssetResolved = false; mutable std::shared_ptr m_sharedPipelineBackendAsset = nullptr; }; class MonoManagedRenderPipelineStageRecorder final : public Rendering::RenderPipelineStageRecorder { public: explicit MonoManagedRenderPipelineStageRecorder( std::shared_ptr assetRuntime) : m_assetRuntime(std::move(assetRuntime)) , m_runtime( m_assetRuntime != nullptr ? m_assetRuntime->GetRuntime() : nullptr) { } ~MonoManagedRenderPipelineStageRecorder() override { Shutdown(); } bool Initialize(const Rendering::RenderContext&) override { return GetManagedPipelineObject() != nullptr; } void Shutdown() override { for (std::unique_ptr& pass : m_fullscreenPassPool) { if (pass != nullptr) { pass->Shutdown(); } } m_fullscreenPassPool.clear(); if (m_ownedSceneDrawBackend != nullptr) { m_ownedSceneDrawBackend->Shutdown(); } m_ownedSharedPipelineBackendAsset.reset(); m_supportsStageContextualMethod = nullptr; m_supportsStageMethod = nullptr; m_recordStageMethod = nullptr; m_resolvedPipelineHandle = 0; m_boundSceneDrawBackend = nullptr; } void SetPipelineBackend( Rendering::RenderPipelineBackend* pipelineBackend) override { m_boundSceneDrawBackend = dynamic_cast(pipelineBackend); } bool SupportsStageRenderGraph(Rendering::CameraFrameStage stage) const override { return SupportsStageRenderGraph( Rendering::RenderPipelineStageSupportContext{ stage, -1 }); } bool SupportsStageRenderGraph( const Rendering::RenderPipelineStageSupportContext& context) const override { if (!SupportsManagedRenderPipelineStageGraphRecording(context.stage) || !IsRuntimeAlive()) { return false; } MonoObject* const pipelineObject = GetManagedPipelineObject(); if (!pipelineObject) { return false; } MonoMethod* const contextualMethod = ResolveSupportsStageContextualMethod( pipelineObject); if (contextualMethod != nullptr) { int32_t managedStage = static_cast(context.stage); int32_t rendererIndex = context.rendererIndex; void* args[2] = { &managedStage, &rendererIndex }; MonoObject* result = nullptr; if (!m_runtime->InvokeManagedMethod( pipelineObject, contextualMethod, args, &result)) { return false; } bool supportsStage = false; return TryUnboxManagedBoolean( result, supportsStage) && supportsStage; } return SupportsStageRenderGraphFallback( pipelineObject, context.stage); } private: bool SupportsStageRenderGraphFallback( MonoObject* pipelineObject, Rendering::CameraFrameStage stage) const { if (!SupportsManagedRenderPipelineStageGraphRecording(stage) || !IsRuntimeAlive()) { return false; } MonoMethod* const method = ResolveSupportsStageMethod(pipelineObject); if (!pipelineObject || !method) { return false; } int32_t managedStage = static_cast(stage); void* args[1] = { &managedStage }; MonoObject* result = nullptr; if (!m_runtime->InvokeManagedMethod( pipelineObject, method, args, &result)) { return false; } bool supportsStage = false; return TryUnboxManagedBoolean(result, supportsStage) && supportsStage; } public: bool RecordStageRenderGraph( const Rendering::RenderPipelineStageRenderGraphContext& context) override { if (!IsRuntimeAlive()) { return false; } MonoObject* const pipelineObject = GetManagedPipelineObject(); MonoMethod* const method = ResolveRecordStageMethod(pipelineObject); if (!pipelineObject || !method) { return false; } ManagedScriptableRenderContextState managedContextState = {}; managedContextState.stage = context.stage; managedContextState.graphContext = &context; Rendering::SceneDrawBackend* const sceneDrawBackend = ResolveSceneDrawBackend(); if (sceneDrawBackend == nullptr) { return false; } Rendering::Pipelines::NativeSceneRecorder sceneRecorder( *sceneDrawBackend, context); managedContextState.sceneRecorder = &sceneRecorder; const uint64_t managedContextHandle = RegisterManagedScriptableRenderContextState(managedContextState); MonoObject* const managedContextObject = m_runtime->CreateManagedScriptableRenderContext(managedContextHandle); if (managedContextObject == nullptr) { UnregisterManagedScriptableRenderContextState(managedContextHandle); return false; } void* args[1] = { managedContextObject }; MonoObject* result = nullptr; const bool invokeSucceeded = m_runtime->InvokeManagedMethod( pipelineObject, method, args, &result); UnregisterManagedScriptableRenderContextState(managedContextHandle); if (!invokeSucceeded) { return false; } bool recorded = false; if (!(TryUnboxManagedBoolean(result, recorded) && recorded)) { return false; } return FlushManagedRasterPasses( context, managedContextState); } private: bool IsRuntimeAlive() const { return m_assetRuntime != nullptr && m_assetRuntime->IsRuntimeAlive() && m_runtime != nullptr; } MonoObject* GetManagedPipelineObject() const { if (!IsRuntimeAlive()) { return nullptr; } uint32_t pipelineHandle = 0; if (!m_assetRuntime->AcquireManagedPipelineHandle(pipelineHandle) || pipelineHandle == 0) { return nullptr; } if (pipelineHandle != m_resolvedPipelineHandle) { m_supportsStageContextualMethod = nullptr; m_supportsStageMethod = nullptr; m_recordStageMethod = nullptr; m_resolvedPipelineHandle = pipelineHandle; } return m_runtime->GetManagedObject(pipelineHandle); } MonoMethod* ResolveSupportsStageContextualMethod( MonoObject* pipelineObject) const { if (m_supportsStageContextualMethod == nullptr) { m_supportsStageContextualMethod = m_runtime->ResolveManagedMethod( pipelineObject, "SupportsStageRenderGraphContextual", 2); } return m_supportsStageContextualMethod; } MonoMethod* ResolveSupportsStageMethod(MonoObject* pipelineObject) const { if (m_supportsStageMethod == nullptr) { m_supportsStageMethod = m_runtime->ResolveManagedMethod( pipelineObject, "SupportsStageRenderGraph", 1); } return m_supportsStageMethod; } MonoMethod* ResolveRecordStageMethod(MonoObject* pipelineObject) const { if (m_recordStageMethod == nullptr) { m_recordStageMethod = m_runtime->ResolveManagedMethod( pipelineObject, "RecordStageRenderGraph", 1); } return m_recordStageMethod; } bool FlushManagedRasterPasses( const Rendering::RenderPipelineStageRenderGraphContext& context, const ManagedScriptableRenderContextState& managedContextState) { if (managedContextState.rasterPassRequests.empty()) { return true; } if (!Rendering::IsCameraFrameFullscreenSequenceStage(context.stage)) { return false; } Rendering::RenderGraphTextureHandle currentSourceColor = ResolveManagedScriptableRenderContextSourceColorTexture( &managedContextState); const Rendering::RenderGraphTextureHandle finalOutputColor = ResolveManagedScriptableRenderContextPrimaryColorTarget( &managedContextState); if (!currentSourceColor.IsValid() || !finalOutputColor.IsValid()) { return false; } for (size_t passIndex = 0u; passIndex < managedContextState.rasterPassRequests.size(); ++passIndex) { const ManagedScriptableRenderContextState::RasterPassRecordRequest& request = managedContextState.rasterPassRequests[passIndex]; Rendering::RenderPass* const pass = ConfigureManagedFullscreenPass( m_fullscreenPassPool, passIndex, request.passDesc); if (pass == nullptr) { return false; } const Containers::String resolvedPassName = !request.passName.Empty() ? request.passName : managedContextState.rasterPassRequests.size() == 1u ? context.passName : Rendering::BuildRenderGraphSequencePassName( context.passName, passIndex); const Rendering::RenderGraphTextureHandle resolvedSourceColor = request.sourceColorTexture.IsValid() ? request.sourceColorTexture : currentSourceColor; std::vector resolvedColorTargets = request.colorTargets; if (!ResolveManagedPrimaryColorTarget(resolvedColorTargets) .IsValid()) { const bool isLastPass = passIndex + 1u == managedContextState.rasterPassRequests.size(); const Rendering::RenderGraphTextureHandle resolvedOutputColor = isLastPass ? finalOutputColor : context.graphBuilder.CreateTransientTexture( resolvedPassName + ".Color", Rendering::BuildFullscreenTransientTextureDesc( context.surfaceTemplate)); resolvedColorTargets = { resolvedOutputColor }; } if (!RecordManagedFullscreenRasterPass( context, *pass, resolvedSourceColor, resolvedColorTargets, request.readTextures, request.readDepthTextures, request.textureBindings, request.depthTarget, resolvedPassName)) { return false; } currentSourceColor = ResolveManagedPrimaryColorTarget( resolvedColorTargets); } return true; } Rendering::SceneDrawBackend* ResolveSceneDrawBackend() { if (m_boundSceneDrawBackend != nullptr) { return m_boundSceneDrawBackend; } const std::shared_ptr sharedPipelineBackendAsset = m_assetRuntime != nullptr ? m_assetRuntime->GetSharedPipelineBackendAsset() : nullptr; if (sharedPipelineBackendAsset == nullptr) { return nullptr; } if (m_ownedSceneDrawBackend == nullptr || sharedPipelineBackendAsset != m_ownedSharedPipelineBackendAsset) { if (m_ownedSceneDrawBackend != nullptr) { m_ownedSceneDrawBackend->Shutdown(); } m_ownedSceneDrawBackend = Rendering::Internal::CreateSceneDrawBackendFromAsset( sharedPipelineBackendAsset); m_ownedSharedPipelineBackendAsset = sharedPipelineBackendAsset; } return m_ownedSceneDrawBackend.get(); } std::shared_ptr m_assetRuntime; MonoScriptRuntime* m_runtime = nullptr; mutable MonoMethod* m_supportsStageContextualMethod = nullptr; mutable MonoMethod* m_supportsStageMethod = nullptr; mutable MonoMethod* m_recordStageMethod = nullptr; mutable uint32_t m_resolvedPipelineHandle = 0; std::vector> m_fullscreenPassPool = {}; Rendering::SceneDrawBackend* m_boundSceneDrawBackend = nullptr; std::shared_ptr m_ownedSharedPipelineBackendAsset = nullptr; std::unique_ptr m_ownedSceneDrawBackend = nullptr; }; std::unique_ptr MonoManagedRenderPipelineAssetRuntime::CreateStageRecorder() const { if (!IsRuntimeAlive() || !m_descriptor.IsValid()) { return nullptr; } return std::make_unique( shared_from_this()); } void MonoManagedRenderPipelineAssetRuntime::ConfigureCameraRenderRequest( Rendering::CameraRenderRequest& request, size_t renderedBaseCameraCount, size_t renderedRequestCount, const Rendering::DirectionalShadowPlanningSettings& directionalShadowSettings) const { if (!EnsureManagedAsset()) { request.directionalShadow = {}; Rendering::ApplyDefaultRenderPipelineAssetCameraRenderRequestPolicy( request, renderedBaseCameraCount, renderedRequestCount, directionalShadowSettings); return; } MonoObject* const assetObject = GetManagedAssetObject(); MonoMethod* const method = ResolveConfigureCameraRenderRequestMethod(assetObject); if (assetObject == nullptr || method == nullptr) { request.directionalShadow = {}; Rendering::ApplyDefaultRenderPipelineAssetCameraRenderRequestPolicy( request, renderedBaseCameraCount, renderedRequestCount, directionalShadowSettings); return; } ManagedCameraRenderRequestContextState requestContextState = {}; requestContextState.request = &request; requestContextState.renderedBaseCameraCount = renderedBaseCameraCount; requestContextState.renderedRequestCount = renderedRequestCount; requestContextState.directionalShadowPlanningSettings = directionalShadowSettings; const uint64_t requestContextHandle = RegisterManagedCameraRenderRequestContextState( requestContextState); MonoObject* const requestContextObject = m_runtime->CreateManagedCameraRenderRequestContext( requestContextHandle); if (requestContextObject == nullptr) { UnregisterManagedCameraRenderRequestContextState( requestContextHandle); request.directionalShadow = {}; Rendering::ApplyDefaultRenderPipelineAssetCameraRenderRequestPolicy( request, renderedBaseCameraCount, renderedRequestCount, directionalShadowSettings); return; } void* args[1] = { requestContextObject }; m_runtime->InvokeManagedMethod( assetObject, method, args, nullptr); request.directionalShadow = {}; if (requestContextState.suppressDirectionalShadow) { } else { Rendering::ApplyDefaultRenderPipelineAssetCameraRenderRequestPolicy( request, renderedBaseCameraCount, renderedRequestCount, requestContextState.directionalShadowPlanningSettings); } UnregisterManagedCameraRenderRequestContextState( requestContextHandle); } void MonoManagedRenderPipelineAssetRuntime::ConfigureCameraFramePlan( Rendering::CameraFramePlan& plan) const { if (!EnsureManagedAsset()) { return; } MonoObject* const assetObject = GetManagedAssetObject(); MonoMethod* const method = ResolveConfigureCameraFramePlanMethod(assetObject); if (assetObject == nullptr || method == nullptr) { return; } ManagedScriptableRenderPipelinePlanningContextState planningContextState = {}; planningContextState.plan = &plan; const uint64_t planningContextHandle = RegisterManagedScriptableRenderPipelinePlanningContextState( planningContextState); MonoObject* const planningContextObject = m_runtime->CreateManagedScriptableRenderPipelinePlanningContext( planningContextHandle); if (planningContextObject == nullptr) { UnregisterManagedScriptableRenderPipelinePlanningContextState( planningContextHandle); return; } void* args[1] = { planningContextObject }; m_runtime->InvokeManagedMethod( assetObject, method, args, nullptr); UnregisterManagedScriptableRenderPipelinePlanningContextState( planningContextHandle); } bool MonoManagedRenderPipelineAssetRuntime::ConfigureRenderSceneSetup( const Rendering::CameraFramePlan& plan, Rendering::RenderSceneData& sceneData) const { if (!EnsureManagedAsset()) { return false; } MonoObject* const assetObject = GetManagedAssetObject(); MonoMethod* const method = ResolveConfigureRenderSceneSetupMethod(assetObject); if (assetObject == nullptr || method == nullptr) { return false; } ManagedRenderSceneSetupContextState setupContextState = {}; setupContextState.plan = &plan; setupContextState.sceneData = &sceneData; const uint64_t setupContextHandle = RegisterManagedRenderSceneSetupContextState( setupContextState); MonoObject* const setupContextObject = m_runtime->CreateManagedRenderSceneSetupContext( setupContextHandle); if (setupContextObject == nullptr) { UnregisterManagedRenderSceneSetupContextState( setupContextHandle); return false; } void* args[1] = { setupContextObject }; m_runtime->InvokeManagedMethod( assetObject, method, args, nullptr); UnregisterManagedRenderSceneSetupContextState( setupContextHandle); return setupContextState.explicitlyConfigured; } bool MonoManagedRenderPipelineAssetRuntime:: ConfigureDirectionalShadowExecutionState( const Rendering::CameraFramePlan& plan, const Rendering::DirectionalShadowSurfaceAllocation& shadowAllocation, Rendering::DirectionalShadowExecutionState& shadowState) const { if (!EnsureManagedAsset()) { return false; } MonoObject* const assetObject = GetManagedAssetObject(); MonoMethod* const method = ResolveConfigureDirectionalShadowExecutionStateMethod( assetObject); if (assetObject == nullptr || method == nullptr) { return false; } ManagedDirectionalShadowExecutionContextState executionState = {}; executionState.plan = &plan; executionState.shadowAllocation = &shadowAllocation; executionState.shadowState = &shadowState; const uint64_t executionContextHandle = RegisterManagedDirectionalShadowExecutionContextState( executionState); MonoObject* const executionContextObject = m_runtime->CreateManagedDirectionalShadowExecutionContext( executionContextHandle); if (executionContextObject == nullptr) { UnregisterManagedDirectionalShadowExecutionContextState( executionContextHandle); return false; } void* args[1] = { executionContextObject }; m_runtime->InvokeManagedMethod( assetObject, method, args, nullptr); UnregisterManagedDirectionalShadowExecutionContextState( executionContextHandle); return executionState.explicitlyConfigured; } bool MonoManagedRenderPipelineAssetRuntime::TryGetDefaultFinalColorSettings( Rendering::FinalColorSettings& settings) const { settings = {}; settings.exposureValue = 1.0f; settings.finalColorScale = XCEngine::Math::Vector4::One(); if (!EnsureManagedAsset()) { return false; } MonoObject* const assetObject = GetManagedAssetObject(); MonoMethod* const method = ResolveGetDefaultFinalColorSettingsMethod(assetObject); if (assetObject == nullptr || method == nullptr) { return false; } MonoObject* managedSettings = nullptr; if (!m_runtime->InvokeManagedMethod( assetObject, method, nullptr, &managedSettings)) { return false; } return TryUnboxManagedFinalColorSettings( managedSettings, settings); } std::shared_ptr MonoManagedRenderPipelineAssetRuntime::GetSharedPipelineBackendAsset() const { if (!SyncManagedAssetRuntimeState()) { return nullptr; } if (m_sharedPipelineBackendAssetResolved) { return m_sharedPipelineBackendAsset; } if (GetManagedAssetObject() == nullptr) { return nullptr; } m_sharedPipelineBackendAssetResolved = true; m_sharedPipelineBackendAsset = Rendering::Internal::CreateDefaultPipelineBackendAsset(); return m_sharedPipelineBackendAsset; } bool MonoManagedRenderPipelineAssetRuntime::AcquireManagedPipelineHandle( uint32_t& outPipelineHandle) const { if (!SyncManagedAssetRuntimeState()) { outPipelineHandle = 0; return false; } if (m_pipelineHandle != 0) { outPipelineHandle = m_pipelineHandle; return true; } if (m_pipelineCreationAttempted) { outPipelineHandle = 0; return false; } m_pipelineCreationAttempted = true; MonoObject* const assetObject = GetManagedAssetObject(); MonoMethod* const createPipelineMethod = ResolveCreatePipelineMethod(assetObject); if (assetObject == nullptr || createPipelineMethod == nullptr) { outPipelineHandle = 0; return false; } MonoObject* pipelineObject = nullptr; if (!m_runtime->InvokeManagedMethod( assetObject, createPipelineMethod, nullptr, &pipelineObject) || pipelineObject == nullptr) { outPipelineHandle = 0; return false; } if (!IsMonoClassOrSubclass( mono_object_get_class(pipelineObject), m_runtime->m_scriptableRenderPipelineClass)) { m_runtime->SetError( "Managed render pipeline asset returned a non-ScriptableRenderPipeline instance: " + m_descriptor.GetFullName() + "."); outPipelineHandle = 0; return false; } m_pipelineHandle = m_runtime->RetainExternalManagedObject(pipelineObject); outPipelineHandle = m_pipelineHandle; return m_pipelineHandle != 0; } bool MonoManagedRenderPipelineAssetRuntime::EnsureManagedAsset() const { if (m_assetHandle != 0) { return true; } if (m_assetCreationAttempted || !IsRuntimeAlive() || !m_descriptor.IsValid()) { return false; } m_assetCreationAttempted = true; if (m_descriptor.HasManagedAssetHandle()) { MonoObject* const assetObject = m_runtime->GetExternalManagedObject( m_descriptor.managedAssetHandle); MonoClass* const assetClass = assetObject != nullptr ? mono_object_get_class(assetObject) : nullptr; if (assetClass == nullptr) { m_runtime->SetError( "Managed render pipeline asset handle is no longer valid: " + m_descriptor.GetFullName() + "."); return false; } if (!IsMonoClassOrSubclass( assetClass, m_runtime->m_scriptableRenderPipelineAssetClass)) { m_runtime->SetError( "Managed render pipeline asset must derive from ScriptableRenderPipelineAsset: " + m_descriptor.GetFullName() + "."); return false; } m_assetHandle = m_descriptor.managedAssetHandle; m_ownsManagedAssetHandle = false; return true; } MonoClass* assetClass = nullptr; if (!m_runtime->ResolveManagedClass( m_descriptor.assemblyName, m_descriptor.namespaceName, m_descriptor.className, assetClass) || assetClass == nullptr) { return false; } if (!IsMonoClassOrSubclass( assetClass, m_runtime->m_scriptableRenderPipelineAssetClass)) { m_runtime->SetError( "Managed render pipeline asset must derive from ScriptableRenderPipelineAsset: " + m_descriptor.GetFullName() + "."); return false; } m_ownsManagedAssetHandle = m_runtime->CreateExternalManagedObject(assetClass, m_assetHandle) && m_assetHandle != 0; return m_ownsManagedAssetHandle; } bool MonoManagedRenderPipelineAssetRuntime::SyncManagedAssetRuntimeState() const { if (!EnsureManagedAsset()) { return false; } int32_t runtimeResourceVersion = 0; if (!TryGetManagedRuntimeResourceVersion(runtimeResourceVersion)) { return false; } if (!m_runtimeResourceVersionResolved) { m_runtimeResourceVersion = runtimeResourceVersion; m_runtimeResourceVersionResolved = true; return true; } if (runtimeResourceVersion == m_runtimeResourceVersion) { return true; } ReleaseManagedPipeline(); m_sharedPipelineBackendAsset.reset(); m_sharedPipelineBackendAssetResolved = false; m_runtimeResourceVersion = runtimeResourceVersion; return true; } bool MonoManagedRenderPipelineAssetRuntime::TryGetManagedRuntimeResourceVersion( int32_t& outVersion) const { outVersion = 0; if (!EnsureManagedAsset()) { return false; } MonoObject* const assetObject = GetManagedAssetObject(); MonoMethod* const method = ResolveGetRuntimeResourceVersionMethod(assetObject); if (assetObject == nullptr || method == nullptr) { return false; } MonoObject* managedVersion = nullptr; if (!m_runtime->InvokeManagedMethod( assetObject, method, nullptr, &managedVersion)) { return false; } return TryUnboxManagedInt32(managedVersion, outVersion); } void MonoManagedRenderPipelineAssetRuntime::ReleaseManagedPipeline() const { m_pipelineCreationAttempted = false; m_disposePipelineMethod = nullptr; if (!IsRuntimeAlive()) { m_pipelineHandle = 0; return; } if (m_pipelineHandle != 0) { MonoObject* const pipelineObject = m_runtime->GetManagedObject(m_pipelineHandle); MonoMethod* const disposeMethod = ResolveDisposePipelineMethod(pipelineObject); if (pipelineObject != nullptr && disposeMethod != nullptr) { m_runtime->InvokeManagedMethod( pipelineObject, disposeMethod, nullptr, nullptr); } m_runtime->DestroyExternalManagedObject(m_pipelineHandle); m_pipelineHandle = 0; } } void MonoManagedRenderPipelineAssetRuntime::ReleaseManagedAsset() const { ReleaseManagedPipeline(); m_releaseRuntimeResourcesMethod = nullptr; m_createPipelineMethod = nullptr; m_configureCameraRenderRequestMethod = nullptr; m_configureCameraFramePlanMethod = nullptr; m_getDefaultFinalColorSettingsMethod = nullptr; m_getRuntimeResourceVersionMethod = nullptr; m_configureRenderSceneSetupMethod = nullptr; m_configureDirectionalShadowExecutionStateMethod = nullptr; m_sharedPipelineBackendAsset.reset(); m_sharedPipelineBackendAssetResolved = false; m_runtimeResourceVersionResolved = false; m_runtimeResourceVersion = 0; const bool ownsManagedAssetHandle = m_ownsManagedAssetHandle; m_ownsManagedAssetHandle = false; m_assetCreationAttempted = false; if (!IsRuntimeAlive()) { m_assetHandle = 0; return; } MonoObject* const assetObject = GetManagedAssetObject(); MonoMethod* const releaseRuntimeResourcesMethod = ResolveReleaseRuntimeResourcesMethod(assetObject); if (assetObject != nullptr && releaseRuntimeResourcesMethod != nullptr) { m_runtime->InvokeManagedMethod( assetObject, releaseRuntimeResourcesMethod, nullptr, nullptr); } if (m_assetHandle != 0 && ownsManagedAssetHandle) { m_runtime->DestroyExternalManagedObject(m_assetHandle); } m_assetHandle = 0; } MonoObject* MonoManagedRenderPipelineAssetRuntime::GetManagedAssetObject() const { return m_assetHandle != 0 ? m_runtime->GetManagedObject(m_assetHandle) : nullptr; } MonoMethod* MonoManagedRenderPipelineAssetRuntime::ResolveDisposePipelineMethod( MonoObject* pipelineObject) const { if (m_disposePipelineMethod == nullptr) { m_disposePipelineMethod = m_runtime->ResolveManagedMethod( pipelineObject, "DisposeInstance", 0); } return m_disposePipelineMethod; } MonoMethod* MonoManagedRenderPipelineAssetRuntime::ResolveCreatePipelineMethod( MonoObject* assetObject) const { if (m_createPipelineMethod == nullptr) { m_createPipelineMethod = m_runtime->ResolveManagedMethod( assetObject, "CreatePipeline", 0); } return m_createPipelineMethod; } MonoMethod* MonoManagedRenderPipelineAssetRuntime::ResolveConfigureCameraRenderRequestMethod( MonoObject* assetObject) const { if (m_configureCameraRenderRequestMethod == nullptr) { m_configureCameraRenderRequestMethod = m_runtime->ResolveManagedMethod( assetObject, "ConfigureCameraRenderRequest", 1); } return m_configureCameraRenderRequestMethod; } MonoMethod* MonoManagedRenderPipelineAssetRuntime::ResolveConfigureCameraFramePlanMethod( MonoObject* assetObject) const { if (m_configureCameraFramePlanMethod == nullptr) { m_configureCameraFramePlanMethod = m_runtime->ResolveManagedMethod( assetObject, "ConfigureCameraFramePlanInstance", 1); } return m_configureCameraFramePlanMethod; } MonoMethod* MonoManagedRenderPipelineAssetRuntime::ResolveGetDefaultFinalColorSettingsMethod( MonoObject* assetObject) const { if (m_getDefaultFinalColorSettingsMethod == nullptr) { m_getDefaultFinalColorSettingsMethod = m_runtime->ResolveManagedMethod( assetObject, "GetDefaultFinalColorSettings", 0); } return m_getDefaultFinalColorSettingsMethod; } MonoMethod* MonoManagedRenderPipelineAssetRuntime::ResolveGetRuntimeResourceVersionMethod( MonoObject* assetObject) const { if (m_getRuntimeResourceVersionMethod == nullptr) { m_getRuntimeResourceVersionMethod = m_runtime->ResolveManagedMethod( assetObject, "GetRuntimeResourceVersionInstance", 0); } return m_getRuntimeResourceVersionMethod; } MonoMethod* MonoManagedRenderPipelineAssetRuntime:: ResolveConfigureRenderSceneSetupMethod( MonoObject* assetObject) const { if (m_configureRenderSceneSetupMethod == nullptr) { m_configureRenderSceneSetupMethod = m_runtime->ResolveManagedMethod( assetObject, "ConfigureRenderSceneSetupInstance", 1); } return m_configureRenderSceneSetupMethod; } MonoMethod* MonoManagedRenderPipelineAssetRuntime:: ResolveConfigureDirectionalShadowExecutionStateMethod( MonoObject* assetObject) const { if (m_configureDirectionalShadowExecutionStateMethod == nullptr) { m_configureDirectionalShadowExecutionStateMethod = m_runtime->ResolveManagedMethod( assetObject, "ConfigureDirectionalShadowExecutionStateInstance", 1); } return m_configureDirectionalShadowExecutionStateMethod; } MonoMethod* MonoManagedRenderPipelineAssetRuntime::ResolveReleaseRuntimeResourcesMethod( MonoObject* assetObject) const { if (m_releaseRuntimeResourcesMethod == nullptr) { m_releaseRuntimeResourcesMethod = m_runtime->ResolveManagedMethod( assetObject, "ReleaseRuntimeResourcesInstance", 0); } return m_releaseRuntimeResourcesMethod; } class MonoManagedRenderPipelineBridge final : public Rendering::Pipelines::ManagedRenderPipelineBridge { public: MonoManagedRenderPipelineBridge( MonoScriptRuntime* runtime, std::weak_ptr runtimeLifetime) : m_runtime(runtime) , m_runtimeLifetime(std::move(runtimeLifetime)) { } std::shared_ptr CreateAssetRuntime( const Rendering::Pipelines::ManagedRenderPipelineAssetDescriptor& descriptor) const override { if (!IsRuntimeAlive() || !descriptor.IsValid()) { return nullptr; } return std::make_shared( m_runtime, m_runtimeLifetime, descriptor); } private: bool IsRuntimeAlive() const { return m_runtime != nullptr && !m_runtimeLifetime.expired() && m_runtime->m_initialized; } MonoScriptRuntime* m_runtime = nullptr; std::weak_ptr m_runtimeLifetime; }; namespace { ManagedComponentTypeInfo ResolveManagedComponentTypeInfo(MonoClass* monoClass) { ManagedComponentTypeInfo typeInfo; if (!monoClass) { return typeInfo; } typeInfo.monoClass = monoClass; typeInfo.namespaceName = SafeString(mono_class_get_namespace(monoClass)); typeInfo.className = SafeString(mono_class_get_name(monoClass)); if (typeInfo.namespaceName == "XCEngine" && typeInfo.className == "Transform") { typeInfo.kind = ManagedComponentKind::Transform; return typeInfo; } if (typeInfo.namespaceName == "XCEngine" && typeInfo.className == "Rigidbody") { typeInfo.kind = ManagedComponentKind::Rigidbody; return typeInfo; } if (typeInfo.namespaceName == "XCEngine" && typeInfo.className == "Camera") { typeInfo.kind = ManagedComponentKind::Camera; return typeInfo; } if (typeInfo.namespaceName == "XCEngine" && typeInfo.className == "Light") { typeInfo.kind = ManagedComponentKind::Light; return typeInfo; } if (typeInfo.namespaceName == "XCEngine" && typeInfo.className == "MeshFilter") { typeInfo.kind = ManagedComponentKind::MeshFilter; return typeInfo; } if (typeInfo.namespaceName == "XCEngine" && typeInfo.className == "MeshRenderer") { typeInfo.kind = ManagedComponentKind::MeshRenderer; return typeInfo; } MonoScriptRuntime* runtime = GetActiveMonoScriptRuntime(); if (runtime && runtime->IsClassAvailable( runtime->GetSettings().appAssemblyName, typeInfo.namespaceName, typeInfo.className)) { typeInfo.kind = ManagedComponentKind::Script; typeInfo.assemblyName = runtime->GetSettings().appAssemblyName; } return typeInfo; } ManagedComponentTypeInfo ResolveManagedComponentTypeInfo(MonoReflectionType* reflectionType) { if (!reflectionType) { return {}; } MonoType* monoType = mono_reflection_type_get_type(reflectionType); if (!monoType) { return {}; } return ResolveManagedComponentTypeInfo(mono_class_from_mono_type(monoType)); } Components::GameObject* FindGameObjectByUUIDRecursive(Components::GameObject* gameObject, uint64_t uuid) { if (!gameObject) { return nullptr; } if (gameObject->GetUUID() == uuid) { return gameObject; } for (Components::GameObject* child : gameObject->GetChildren()) { if (Components::GameObject* found = FindGameObjectByUUIDRecursive(child, uuid)) { return found; } } return nullptr; } ScriptComponent* FindScriptComponentByUUIDRecursive(Components::GameObject* gameObject, uint64_t scriptComponentUUID) { if (!gameObject || scriptComponentUUID == 0) { return nullptr; } for (ScriptComponent* component : gameObject->GetComponents()) { if (component && component->GetScriptComponentUUID() == scriptComponentUUID) { return component; } } for (Components::GameObject* child : gameObject->GetChildren()) { if (ScriptComponent* found = FindScriptComponentByUUIDRecursive(child, scriptComponentUUID)) { return found; } } return nullptr; } Components::GameObject* FindGameObjectByUUID(uint64_t uuid) { Components::Scene* scene = GetInternalCallScene(); if (!scene || uuid == 0) { return nullptr; } for (Components::GameObject* root : scene->GetRootGameObjects()) { if (Components::GameObject* found = FindGameObjectByUUIDRecursive(root, uuid)) { return found; } } return nullptr; } ScriptComponent* FindScriptComponentByUUID(uint64_t scriptComponentUUID) { Components::Scene* scene = GetInternalCallScene(); if (!scene || scriptComponentUUID == 0) { return nullptr; } for (Components::GameObject* root : scene->GetRootGameObjects()) { if (ScriptComponent* found = FindScriptComponentByUUIDRecursive(root, scriptComponentUUID)) { return found; } } return nullptr; } Components::Component* FindNativeComponent(Components::GameObject* gameObject, ManagedComponentKind componentKind) { if (!gameObject) { return nullptr; } switch (componentKind) { case ManagedComponentKind::Transform: return gameObject->GetTransform(); case ManagedComponentKind::Rigidbody: return gameObject->GetComponent(); case ManagedComponentKind::Camera: return gameObject->GetComponent(); case ManagedComponentKind::Light: return gameObject->GetComponent(); case ManagedComponentKind::MeshFilter: return gameObject->GetComponent(); case ManagedComponentKind::MeshRenderer: return gameObject->GetComponent(); case ManagedComponentKind::Script: case ManagedComponentKind::Unknown: return nullptr; } return nullptr; } bool HasNativeComponent(Components::GameObject* gameObject, ManagedComponentKind componentKind) { return FindNativeComponent(gameObject, componentKind) != nullptr; } bool IsMatchingScriptComponent(const ScriptComponent* component, const ManagedComponentTypeInfo& typeInfo) { return component && component->HasScriptClass() && typeInfo.kind == ManagedComponentKind::Script && component->GetAssemblyName() == typeInfo.assemblyName && component->GetNamespaceName() == typeInfo.namespaceName && component->GetClassName() == typeInfo.className; } Components::Component* AddOrGetNativeComponent(Components::GameObject* gameObject, ManagedComponentKind componentKind) { if (!gameObject) { return nullptr; } switch (componentKind) { case ManagedComponentKind::Transform: return gameObject->GetTransform(); case ManagedComponentKind::Rigidbody: return gameObject->GetComponent() ? static_cast(gameObject->GetComponent()) : static_cast(gameObject->AddComponent()); case ManagedComponentKind::Camera: return gameObject->GetComponent() ? static_cast(gameObject->GetComponent()) : static_cast(gameObject->AddComponent()); case ManagedComponentKind::Light: return gameObject->GetComponent() ? static_cast(gameObject->GetComponent()) : static_cast(gameObject->AddComponent()); case ManagedComponentKind::MeshFilter: return gameObject->GetComponent() ? static_cast(gameObject->GetComponent()) : static_cast(gameObject->AddComponent()); case ManagedComponentKind::MeshRenderer: return gameObject->GetComponent() ? static_cast(gameObject->GetComponent()) : static_cast(gameObject->AddComponent()); case ManagedComponentKind::Script: case ManagedComponentKind::Unknown: return nullptr; } return nullptr; } ScriptComponent* FindMatchingScriptComponent( Components::GameObject* gameObject, const ManagedComponentTypeInfo& typeInfo) { if (!gameObject || typeInfo.kind != ManagedComponentKind::Script) { return nullptr; } for (ScriptComponent* component : gameObject->GetComponents()) { if (IsMatchingScriptComponent(component, typeInfo)) { return component; } } return nullptr; } ScriptComponent* FindMatchingScriptComponentInChildren( Components::GameObject* gameObject, const ManagedComponentTypeInfo& typeInfo) { if (!gameObject) { return nullptr; } if (ScriptComponent* component = FindMatchingScriptComponent(gameObject, typeInfo)) { return component; } for (Components::GameObject* child : gameObject->GetChildren()) { if (ScriptComponent* component = FindMatchingScriptComponentInChildren(child, typeInfo)) { return component; } } return nullptr; } ScriptComponent* FindMatchingScriptComponentInParent( Components::GameObject* gameObject, const ManagedComponentTypeInfo& typeInfo) { while (gameObject) { if (ScriptComponent* component = FindMatchingScriptComponent(gameObject, typeInfo)) { return component; } gameObject = gameObject->GetParent(); } return nullptr; } Components::Component* FindNativeComponentInChildren( Components::GameObject* gameObject, ManagedComponentKind componentKind) { if (!gameObject) { return nullptr; } if (Components::Component* component = FindNativeComponent(gameObject, componentKind)) { return component; } for (Components::GameObject* child : gameObject->GetChildren()) { if (Components::Component* component = FindNativeComponentInChildren(child, componentKind)) { return component; } } return nullptr; } Components::Component* FindNativeComponentInParent( Components::GameObject* gameObject, ManagedComponentKind componentKind) { while (gameObject) { if (Components::Component* component = FindNativeComponent(gameObject, componentKind)) { return component; } gameObject = gameObject->GetParent(); } return nullptr; } bool DestroyNativeComponentInstance(Components::GameObject* gameObject, Components::Component* component) { if (!gameObject || !component || component == gameObject->GetTransform()) { return false; } if (component->IsEnabled() && gameObject->IsActiveInHierarchy()) { component->OnDisable(); } component->OnDestroy(); return gameObject->RemoveComponent(component); } Components::CameraComponent* FindCameraComponent(uint64_t gameObjectUUID) { Components::GameObject* gameObject = FindGameObjectByUUID(gameObjectUUID); return gameObject ? gameObject->GetComponent() : nullptr; } Components::LightComponent* FindLightComponent(uint64_t gameObjectUUID) { Components::GameObject* gameObject = FindGameObjectByUUID(gameObjectUUID); return gameObject ? gameObject->GetComponent() : nullptr; } Components::MeshFilterComponent* FindMeshFilterComponent(uint64_t gameObjectUUID) { Components::GameObject* gameObject = FindGameObjectByUUID(gameObjectUUID); return gameObject ? gameObject->GetComponent() : nullptr; } Components::MeshRendererComponent* FindMeshRendererComponent(uint64_t gameObjectUUID) { Components::GameObject* gameObject = FindGameObjectByUUID(gameObjectUUID); return gameObject ? gameObject->GetComponent() : nullptr; } Components::RigidbodyComponent* FindRigidbodyComponent(uint64_t gameObjectUUID) { Components::GameObject* gameObject = FindGameObjectByUUID(gameObjectUUID); return gameObject ? gameObject->GetComponent() : nullptr; } Components::Space ResolveManagedSpace(int32_t value) { return value == static_cast(Components::Space::World) ? Components::Space::World : Components::Space::Self; } Physics::PhysicsBodyType ResolveManagedPhysicsBodyType(int32_t value) { switch (value) { case static_cast(Physics::PhysicsBodyType::Static): return Physics::PhysicsBodyType::Static; case static_cast(Physics::PhysicsBodyType::Kinematic): return Physics::PhysicsBodyType::Kinematic; case static_cast(Physics::PhysicsBodyType::Dynamic): default: return Physics::PhysicsBodyType::Dynamic; } } Physics::PhysicsForceMode ResolveManagedForceMode(int32_t value) { switch (value) { case static_cast(Physics::PhysicsForceMode::Acceleration): return Physics::PhysicsForceMode::Acceleration; case static_cast(Physics::PhysicsForceMode::Impulse): return Physics::PhysicsForceMode::Impulse; case static_cast(Physics::PhysicsForceMode::VelocityChange): return Physics::PhysicsForceMode::VelocityChange; case static_cast(Physics::PhysicsForceMode::Force): default: return Physics::PhysicsForceMode::Force; } } Physics::PhysicsWorld* FindRuntimePhysicsWorld() { return ScriptEngine::Get().GetRuntimePhysicsWorld(); } MonoArray* CreateManagedComponentArray(MonoClass* componentClass, const std::vector& components) { if (!componentClass) { return nullptr; } MonoDomain* domain = mono_domain_get(); if (!domain) { return nullptr; } MonoArray* array = mono_array_new(domain, componentClass, static_cast(components.size())); if (!array) { return nullptr; } for (uintptr_t index = 0; index < components.size(); ++index) { mono_array_setref(array, index, components[index]); } return array; } void LogManagedMessage( XCEngine::Debug::LogLevel level, MonoString* message, MonoString* file, int32_t line, MonoString* member) { const std::string messageText = MonoStringToUtf8(message); const std::string fileText = MonoStringToUtf8(file); const std::string memberText = MonoStringToUtf8(member); XCEngine::Debug::Logger::Get().Log( level, XCEngine::Debug::LogCategory::Scripting, XCEngine::Containers::String(messageText.c_str()), fileText.c_str(), line, memberText.c_str()); } void InternalCall_Debug_Log(MonoString* message, MonoString* file, int32_t line, MonoString* member) { LogManagedMessage(XCEngine::Debug::LogLevel::Info, message, file, line, member); } void InternalCall_Debug_LogWarning(MonoString* message, MonoString* file, int32_t line, MonoString* member) { LogManagedMessage(XCEngine::Debug::LogLevel::Warning, message, file, line, member); } void InternalCall_Debug_LogError(MonoString* message, MonoString* file, int32_t line, MonoString* member) { LogManagedMessage(XCEngine::Debug::LogLevel::Error, message, file, line, member); } float InternalCall_Time_GetDeltaTime() { return GetInternalCallDeltaTime(); } float InternalCall_Time_GetFixedDeltaTime() { return ScriptEngine::Get().GetRuntimeFixedDeltaTime(); } mono_bool InternalCall_Input_GetKey(int32_t keyCode) { return XCEngine::Input::InputManager::Get().IsKeyDown( static_cast(keyCode)) ? 1 : 0; } mono_bool InternalCall_Input_GetKeyDown(int32_t keyCode) { return XCEngine::Input::InputManager::Get().IsKeyPressed( static_cast(keyCode)) ? 1 : 0; } mono_bool InternalCall_Input_GetKeyUp(int32_t keyCode) { return XCEngine::Input::InputManager::Get().IsKeyReleased( static_cast(keyCode)) ? 1 : 0; } mono_bool InternalCall_Input_GetMouseButton(int32_t button) { return XCEngine::Input::InputManager::Get().IsMouseButtonDown( static_cast(button)) ? 1 : 0; } mono_bool InternalCall_Input_GetMouseButtonDown(int32_t button) { return XCEngine::Input::InputManager::Get().IsMouseButtonClicked( static_cast(button)) ? 1 : 0; } mono_bool InternalCall_Input_GetMouseButtonUp(int32_t button) { return XCEngine::Input::InputManager::Get().IsMouseButtonReleased( static_cast(button)) ? 1 : 0; } mono_bool InternalCall_Input_GetButton(MonoString* buttonName) { return XCEngine::Input::InputManager::Get().GetButton( XCEngine::Containers::String(MonoStringToUtf8(buttonName).c_str())) ? 1 : 0; } mono_bool InternalCall_Input_GetButtonDown(MonoString* buttonName) { return XCEngine::Input::InputManager::Get().GetButtonDown( XCEngine::Containers::String(MonoStringToUtf8(buttonName).c_str())) ? 1 : 0; } mono_bool InternalCall_Input_GetButtonUp(MonoString* buttonName) { return XCEngine::Input::InputManager::Get().GetButtonUp( XCEngine::Containers::String(MonoStringToUtf8(buttonName).c_str())) ? 1 : 0; } float InternalCall_Input_GetAxis(MonoString* axisName) { return XCEngine::Input::InputManager::Get().GetAxis( XCEngine::Containers::String(MonoStringToUtf8(axisName).c_str())); } float InternalCall_Input_GetAxisRaw(MonoString* axisName) { return XCEngine::Input::InputManager::Get().GetAxisRaw( XCEngine::Containers::String(MonoStringToUtf8(axisName).c_str())); } mono_bool InternalCall_Input_GetAnyKey() { return XCEngine::Input::InputManager::Get().IsAnyKeyDown() ? 1 : 0; } mono_bool InternalCall_Input_GetAnyKeyDown() { return XCEngine::Input::InputManager::Get().IsAnyKeyPressed() ? 1 : 0; } void InternalCall_Input_GetMousePosition(XCEngine::Math::Vector3* outPosition) { if (!outPosition) { return; } const XCEngine::Math::Vector2 position = XCEngine::Input::InputManager::Get().GetMousePosition(); *outPosition = XCEngine::Math::Vector3(position.x, position.y, 0.0f); } void InternalCall_Input_GetMouseScrollDelta(XCEngine::Math::Vector2* outDelta) { if (!outDelta) { return; } *outDelta = XCEngine::Math::Vector2( 0.0f, XCEngine::Input::InputManager::Get().GetMouseScrollDelta()); } MonoString* InternalCall_GameObject_GetName(uint64_t gameObjectUUID) { Components::GameObject* gameObject = FindGameObjectByUUID(gameObjectUUID); return mono_string_new( mono_domain_get(), gameObject ? gameObject->GetName().c_str() : ""); } void InternalCall_GameObject_SetName(uint64_t gameObjectUUID, MonoString* name) { Components::GameObject* gameObject = FindGameObjectByUUID(gameObjectUUID); if (!gameObject) { return; } gameObject->SetName(MonoStringToUtf8(name)); } MonoString* InternalCall_GameObject_GetTag(uint64_t gameObjectUUID) { Components::GameObject* gameObject = FindGameObjectByUUID(gameObjectUUID); return mono_string_new( mono_domain_get(), gameObject ? gameObject->GetTag().c_str() : ""); } void InternalCall_GameObject_SetTag(uint64_t gameObjectUUID, MonoString* tag) { Components::GameObject* gameObject = FindGameObjectByUUID(gameObjectUUID); if (!gameObject) { return; } gameObject->SetTag(MonoStringToUtf8(tag)); } mono_bool InternalCall_GameObject_CompareTag(uint64_t gameObjectUUID, MonoString* tag) { Components::GameObject* gameObject = FindGameObjectByUUID(gameObjectUUID); return (gameObject && gameObject->CompareTag(MonoStringToUtf8(tag))) ? 1 : 0; } int32_t InternalCall_GameObject_GetLayer(uint64_t gameObjectUUID) { Components::GameObject* gameObject = FindGameObjectByUUID(gameObjectUUID); return gameObject ? static_cast(gameObject->GetLayer()) : 0; } void InternalCall_GameObject_SetLayer(uint64_t gameObjectUUID, int32_t layer) { Components::GameObject* gameObject = FindGameObjectByUUID(gameObjectUUID); if (!gameObject) { return; } gameObject->SetLayer(static_cast(std::clamp(layer, 0, 31))); } mono_bool InternalCall_GameObject_GetActiveSelf(uint64_t gameObjectUUID) { Components::GameObject* gameObject = FindGameObjectByUUID(gameObjectUUID); return (gameObject && gameObject->IsActive()) ? 1 : 0; } mono_bool InternalCall_GameObject_GetActiveInHierarchy(uint64_t gameObjectUUID) { Components::GameObject* gameObject = FindGameObjectByUUID(gameObjectUUID); return (gameObject && gameObject->IsActiveInHierarchy()) ? 1 : 0; } void InternalCall_GameObject_SetActive(uint64_t gameObjectUUID, mono_bool active) { Components::GameObject* gameObject = FindGameObjectByUUID(gameObjectUUID); if (!gameObject) { return; } gameObject->SetActive(active != 0); } mono_bool InternalCall_GameObject_HasComponent(uint64_t gameObjectUUID, MonoReflectionType* componentType) { Components::GameObject* gameObject = FindGameObjectByUUID(gameObjectUUID); const ManagedComponentTypeInfo typeInfo = ResolveManagedComponentTypeInfo(componentType); if (typeInfo.kind == ManagedComponentKind::Script) { return FindMatchingScriptComponent(gameObject, typeInfo) ? 1 : 0; } return HasNativeComponent(gameObject, typeInfo.kind) ? 1 : 0; } MonoObject* InternalCall_GameObject_GetComponent(uint64_t gameObjectUUID, MonoReflectionType* componentType) { Components::GameObject* gameObject = FindGameObjectByUUID(gameObjectUUID); if (!gameObject) { return nullptr; } MonoScriptRuntime* runtime = GetActiveMonoScriptRuntime(); if (!runtime) { return nullptr; } const ManagedComponentTypeInfo typeInfo = ResolveManagedComponentTypeInfo(componentType); if (typeInfo.kind == ManagedComponentKind::Script) { ScriptComponent* component = FindMatchingScriptComponent(gameObject, typeInfo); if (!component) { return nullptr; } if (!runtime->HasManagedInstance(component)) { ScriptEngine::Get().OnScriptComponentEnabled(component); } return runtime->GetManagedInstanceObject(component); } if (!HasNativeComponent(gameObject, typeInfo.kind) || !typeInfo.monoClass) { return nullptr; } return runtime->CreateManagedComponentWrapper(typeInfo.monoClass, gameObjectUUID); } MonoArray* InternalCall_GameObject_GetComponents(uint64_t gameObjectUUID, MonoReflectionType* componentType) { Components::GameObject* gameObject = FindGameObjectByUUID(gameObjectUUID); if (!gameObject) { return nullptr; } MonoScriptRuntime* runtime = GetActiveMonoScriptRuntime(); if (!runtime) { return nullptr; } const ManagedComponentTypeInfo typeInfo = ResolveManagedComponentTypeInfo(componentType); if (!typeInfo.monoClass) { return nullptr; } std::vector managedComponents; auto appendNativeComponents = [&](const auto& nativeComponents) { for (const auto* component : nativeComponents) { if (!component || !component->GetGameObject()) { continue; } if (MonoObject* managedObject = runtime->CreateManagedComponentWrapper(typeInfo.monoClass, component->GetGameObject()->GetUUID())) { managedComponents.push_back(managedObject); } } }; switch (typeInfo.kind) { case ManagedComponentKind::Script: for (ScriptComponent* component : gameObject->GetComponents()) { if (!IsMatchingScriptComponent(component, typeInfo)) { continue; } if (!runtime->HasManagedInstance(component)) { ScriptEngine::Get().OnScriptComponentEnabled(component); } if (MonoObject* managedObject = runtime->GetManagedInstanceObject(component)) { managedComponents.push_back(managedObject); } } break; case ManagedComponentKind::Transform: appendNativeComponents(gameObject->GetComponents()); break; case ManagedComponentKind::Rigidbody: appendNativeComponents(gameObject->GetComponents()); break; case ManagedComponentKind::Camera: appendNativeComponents(gameObject->GetComponents()); break; case ManagedComponentKind::Light: appendNativeComponents(gameObject->GetComponents()); break; case ManagedComponentKind::MeshFilter: appendNativeComponents(gameObject->GetComponents()); break; case ManagedComponentKind::MeshRenderer: appendNativeComponents(gameObject->GetComponents()); break; case ManagedComponentKind::Unknown: return nullptr; } return CreateManagedComponentArray(typeInfo.monoClass, managedComponents); } MonoObject* InternalCall_GameObject_GetComponentInChildren(uint64_t gameObjectUUID, MonoReflectionType* componentType) { Components::GameObject* gameObject = FindGameObjectByUUID(gameObjectUUID); if (!gameObject) { return nullptr; } MonoScriptRuntime* runtime = GetActiveMonoScriptRuntime(); if (!runtime) { return nullptr; } const ManagedComponentTypeInfo typeInfo = ResolveManagedComponentTypeInfo(componentType); if (typeInfo.kind == ManagedComponentKind::Script) { ScriptComponent* component = FindMatchingScriptComponentInChildren(gameObject, typeInfo); if (!component) { return nullptr; } if (!runtime->HasManagedInstance(component)) { ScriptEngine::Get().OnScriptComponentEnabled(component); } return runtime->GetManagedInstanceObject(component); } Components::Component* component = FindNativeComponentInChildren(gameObject, typeInfo.kind); if (!component || !typeInfo.monoClass) { return nullptr; } return runtime->CreateManagedComponentWrapper(typeInfo.monoClass, component->GetGameObject()->GetUUID()); } MonoObject* InternalCall_GameObject_GetComponentInParent(uint64_t gameObjectUUID, MonoReflectionType* componentType) { Components::GameObject* gameObject = FindGameObjectByUUID(gameObjectUUID); if (!gameObject) { return nullptr; } MonoScriptRuntime* runtime = GetActiveMonoScriptRuntime(); if (!runtime) { return nullptr; } const ManagedComponentTypeInfo typeInfo = ResolveManagedComponentTypeInfo(componentType); if (typeInfo.kind == ManagedComponentKind::Script) { ScriptComponent* component = FindMatchingScriptComponentInParent(gameObject, typeInfo); if (!component) { return nullptr; } if (!runtime->HasManagedInstance(component)) { ScriptEngine::Get().OnScriptComponentEnabled(component); } return runtime->GetManagedInstanceObject(component); } Components::Component* component = FindNativeComponentInParent(gameObject, typeInfo.kind); if (!component || !typeInfo.monoClass) { return nullptr; } return runtime->CreateManagedComponentWrapper(typeInfo.monoClass, component->GetGameObject()->GetUUID()); } MonoObject* InternalCall_GameObject_AddComponent(uint64_t gameObjectUUID, MonoReflectionType* componentType) { Components::GameObject* gameObject = FindGameObjectByUUID(gameObjectUUID); if (!gameObject) { return nullptr; } MonoScriptRuntime* runtime = GetActiveMonoScriptRuntime(); if (!runtime) { return nullptr; } const ManagedComponentTypeInfo typeInfo = ResolveManagedComponentTypeInfo(componentType); if (typeInfo.kind == ManagedComponentKind::Script) { ScriptComponent* component = gameObject->AddComponent(); component->SetScriptClass(typeInfo.assemblyName, typeInfo.namespaceName, typeInfo.className); return runtime->GetManagedInstanceObject(component); } if (!AddOrGetNativeComponent(gameObject, typeInfo.kind) || !typeInfo.monoClass) { return nullptr; } return runtime->CreateManagedComponentWrapper(typeInfo.monoClass, gameObjectUUID); } uint64_t InternalCall_GameObject_Find(MonoString* name) { Components::Scene* scene = GetInternalCallScene(); if (!scene) { return 0; } Components::GameObject* gameObject = scene->Find(MonoStringToUtf8(name)); return gameObject ? gameObject->GetUUID() : 0; } uint64_t InternalCall_GameObject_Create(MonoString* name, uint64_t parentGameObjectUUID) { Components::Scene* scene = GetInternalCallScene(); if (!scene) { return 0; } Components::GameObject* parent = nullptr; if (parentGameObjectUUID != 0) { parent = FindGameObjectByUUID(parentGameObjectUUID); if (!parent || parent->GetScene() != scene) { return 0; } } std::string objectName = MonoStringToUtf8(name); if (objectName.empty()) { objectName = "GameObject"; } Components::GameObject* created = scene->CreateGameObject(objectName, parent); return created ? created->GetUUID() : 0; } void InternalCall_GameObject_Destroy(uint64_t gameObjectUUID) { Components::Scene* scene = GetInternalCallScene(); Components::GameObject* gameObject = FindGameObjectByUUID(gameObjectUUID); if (!scene || !gameObject || gameObject->GetScene() != scene) { return; } scene->DestroyGameObject(gameObject); } void InternalCall_Object_Destroy(MonoObject* object) { MonoScriptRuntime* runtime = GetActiveMonoScriptRuntime(); if (!runtime || !object) { return; } runtime->DestroyManagedObject(object); } mono_bool InternalCall_Behaviour_GetEnabled(uint64_t scriptComponentUUID) { ScriptComponent* component = FindScriptComponentByUUID(scriptComponentUUID); return (component && component->IsEnabled()) ? 1 : 0; } void InternalCall_Behaviour_SetEnabled(uint64_t scriptComponentUUID, mono_bool enabled) { ScriptComponent* component = FindScriptComponentByUUID(scriptComponentUUID); if (!component) { return; } component->SetEnabled(enabled != 0); } void InternalCall_Transform_GetLocalPosition(uint64_t gameObjectUUID, XCEngine::Math::Vector3* outPosition) { if (!outPosition) { return; } Components::GameObject* gameObject = FindGameObjectByUUID(gameObjectUUID); if (!gameObject || !gameObject->GetTransform()) { *outPosition = XCEngine::Math::Vector3::Zero(); return; } *outPosition = gameObject->GetTransform()->GetLocalPosition(); } void InternalCall_Transform_SetLocalPosition(uint64_t gameObjectUUID, XCEngine::Math::Vector3* position) { if (!position) { return; } Components::GameObject* gameObject = FindGameObjectByUUID(gameObjectUUID); if (!gameObject || !gameObject->GetTransform()) { return; } gameObject->GetTransform()->SetLocalPosition(*position); } void InternalCall_Transform_GetLocalRotation(uint64_t gameObjectUUID, XCEngine::Math::Quaternion* outRotation) { if (!outRotation) { return; } Components::GameObject* gameObject = FindGameObjectByUUID(gameObjectUUID); if (!gameObject || !gameObject->GetTransform()) { *outRotation = XCEngine::Math::Quaternion::Identity(); return; } *outRotation = gameObject->GetTransform()->GetLocalRotation(); } void InternalCall_Transform_SetLocalRotation(uint64_t gameObjectUUID, XCEngine::Math::Quaternion* rotation) { if (!rotation) { return; } Components::GameObject* gameObject = FindGameObjectByUUID(gameObjectUUID); if (!gameObject || !gameObject->GetTransform()) { return; } gameObject->GetTransform()->SetLocalRotation(*rotation); } void InternalCall_Transform_GetLocalScale(uint64_t gameObjectUUID, XCEngine::Math::Vector3* outScale) { if (!outScale) { return; } Components::GameObject* gameObject = FindGameObjectByUUID(gameObjectUUID); if (!gameObject || !gameObject->GetTransform()) { *outScale = XCEngine::Math::Vector3::One(); return; } *outScale = gameObject->GetTransform()->GetLocalScale(); } void InternalCall_Transform_SetLocalScale(uint64_t gameObjectUUID, XCEngine::Math::Vector3* scale) { if (!scale) { return; } Components::GameObject* gameObject = FindGameObjectByUUID(gameObjectUUID); if (!gameObject || !gameObject->GetTransform()) { return; } gameObject->GetTransform()->SetLocalScale(*scale); } void InternalCall_Transform_GetLocalEulerAngles(uint64_t gameObjectUUID, XCEngine::Math::Vector3* outEulerAngles) { if (!outEulerAngles) { return; } Components::GameObject* gameObject = FindGameObjectByUUID(gameObjectUUID); if (!gameObject || !gameObject->GetTransform()) { *outEulerAngles = XCEngine::Math::Vector3::Zero(); return; } *outEulerAngles = gameObject->GetTransform()->GetLocalEulerAngles(); } void InternalCall_Transform_SetLocalEulerAngles(uint64_t gameObjectUUID, XCEngine::Math::Vector3* eulerAngles) { if (!eulerAngles) { return; } Components::GameObject* gameObject = FindGameObjectByUUID(gameObjectUUID); if (!gameObject || !gameObject->GetTransform()) { return; } gameObject->GetTransform()->SetLocalEulerAngles(*eulerAngles); } void InternalCall_Transform_GetPosition(uint64_t gameObjectUUID, XCEngine::Math::Vector3* outPosition) { if (!outPosition) { return; } Components::GameObject* gameObject = FindGameObjectByUUID(gameObjectUUID); if (!gameObject || !gameObject->GetTransform()) { *outPosition = XCEngine::Math::Vector3::Zero(); return; } *outPosition = gameObject->GetTransform()->GetPosition(); } void InternalCall_Transform_SetPosition(uint64_t gameObjectUUID, XCEngine::Math::Vector3* position) { if (!position) { return; } Components::GameObject* gameObject = FindGameObjectByUUID(gameObjectUUID); if (!gameObject || !gameObject->GetTransform()) { return; } gameObject->GetTransform()->SetPosition(*position); } void InternalCall_Transform_GetRotation(uint64_t gameObjectUUID, XCEngine::Math::Quaternion* outRotation) { if (!outRotation) { return; } Components::GameObject* gameObject = FindGameObjectByUUID(gameObjectUUID); if (!gameObject || !gameObject->GetTransform()) { *outRotation = XCEngine::Math::Quaternion::Identity(); return; } *outRotation = gameObject->GetTransform()->GetRotation(); } void InternalCall_Transform_SetRotation(uint64_t gameObjectUUID, XCEngine::Math::Quaternion* rotation) { if (!rotation) { return; } Components::GameObject* gameObject = FindGameObjectByUUID(gameObjectUUID); if (!gameObject || !gameObject->GetTransform()) { return; } gameObject->GetTransform()->SetRotation(*rotation); } void InternalCall_Transform_GetScale(uint64_t gameObjectUUID, XCEngine::Math::Vector3* outScale) { if (!outScale) { return; } Components::GameObject* gameObject = FindGameObjectByUUID(gameObjectUUID); if (!gameObject || !gameObject->GetTransform()) { *outScale = XCEngine::Math::Vector3::One(); return; } *outScale = gameObject->GetTransform()->GetScale(); } void InternalCall_Transform_SetScale(uint64_t gameObjectUUID, XCEngine::Math::Vector3* scale) { if (!scale) { return; } Components::GameObject* gameObject = FindGameObjectByUUID(gameObjectUUID); if (!gameObject || !gameObject->GetTransform()) { return; } gameObject->GetTransform()->SetScale(*scale); } void InternalCall_Transform_GetForward(uint64_t gameObjectUUID, XCEngine::Math::Vector3* outForward) { if (!outForward) { return; } Components::GameObject* gameObject = FindGameObjectByUUID(gameObjectUUID); if (!gameObject || !gameObject->GetTransform()) { *outForward = XCEngine::Math::Vector3::Forward(); return; } *outForward = gameObject->GetTransform()->GetForward(); } void InternalCall_Transform_GetRight(uint64_t gameObjectUUID, XCEngine::Math::Vector3* outRight) { if (!outRight) { return; } Components::GameObject* gameObject = FindGameObjectByUUID(gameObjectUUID); if (!gameObject || !gameObject->GetTransform()) { *outRight = XCEngine::Math::Vector3::Right(); return; } *outRight = gameObject->GetTransform()->GetRight(); } void InternalCall_Transform_GetUp(uint64_t gameObjectUUID, XCEngine::Math::Vector3* outUp) { if (!outUp) { return; } Components::GameObject* gameObject = FindGameObjectByUUID(gameObjectUUID); if (!gameObject || !gameObject->GetTransform()) { *outUp = XCEngine::Math::Vector3::Up(); return; } *outUp = gameObject->GetTransform()->GetUp(); } void InternalCall_Transform_Translate(uint64_t gameObjectUUID, XCEngine::Math::Vector3* translation, int32_t relativeTo) { if (!translation) { return; } Components::GameObject* gameObject = FindGameObjectByUUID(gameObjectUUID); if (!gameObject || !gameObject->GetTransform()) { return; } gameObject->GetTransform()->Translate(*translation, ResolveManagedSpace(relativeTo)); } void InternalCall_Transform_Rotate(uint64_t gameObjectUUID, XCEngine::Math::Vector3* eulers, int32_t relativeTo) { if (!eulers) { return; } Components::GameObject* gameObject = FindGameObjectByUUID(gameObjectUUID); if (!gameObject || !gameObject->GetTransform()) { return; } gameObject->GetTransform()->Rotate(*eulers, ResolveManagedSpace(relativeTo)); } void InternalCall_Transform_RotateAxisAngle( uint64_t gameObjectUUID, XCEngine::Math::Vector3* axis, float angle, int32_t relativeTo) { if (!axis) { return; } Components::GameObject* gameObject = FindGameObjectByUUID(gameObjectUUID); if (!gameObject || !gameObject->GetTransform()) { return; } gameObject->GetTransform()->Rotate(*axis, angle, ResolveManagedSpace(relativeTo)); } void InternalCall_Transform_LookAt(uint64_t gameObjectUUID, XCEngine::Math::Vector3* target) { if (!target) { return; } Components::GameObject* gameObject = FindGameObjectByUUID(gameObjectUUID); if (!gameObject || !gameObject->GetTransform()) { return; } gameObject->GetTransform()->LookAt(*target); } void InternalCall_Transform_LookAtWithUp( uint64_t gameObjectUUID, XCEngine::Math::Vector3* target, XCEngine::Math::Vector3* up) { if (!target || !up) { return; } Components::GameObject* gameObject = FindGameObjectByUUID(gameObjectUUID); if (!gameObject || !gameObject->GetTransform()) { return; } gameObject->GetTransform()->LookAt(*target, *up); } void InternalCall_Transform_TransformPoint(uint64_t gameObjectUUID, XCEngine::Math::Vector3* point, XCEngine::Math::Vector3* outPoint) { if (!point || !outPoint) { return; } Components::GameObject* gameObject = FindGameObjectByUUID(gameObjectUUID); if (!gameObject || !gameObject->GetTransform()) { *outPoint = *point; return; } *outPoint = gameObject->GetTransform()->TransformPoint(*point); } void InternalCall_Transform_InverseTransformPoint(uint64_t gameObjectUUID, XCEngine::Math::Vector3* point, XCEngine::Math::Vector3* outPoint) { if (!point || !outPoint) { return; } Components::GameObject* gameObject = FindGameObjectByUUID(gameObjectUUID); if (!gameObject || !gameObject->GetTransform()) { *outPoint = *point; return; } *outPoint = gameObject->GetTransform()->InverseTransformPoint(*point); } void InternalCall_Transform_TransformDirection(uint64_t gameObjectUUID, XCEngine::Math::Vector3* direction, XCEngine::Math::Vector3* outDirection) { if (!direction || !outDirection) { return; } Components::GameObject* gameObject = FindGameObjectByUUID(gameObjectUUID); if (!gameObject || !gameObject->GetTransform()) { *outDirection = *direction; return; } *outDirection = gameObject->GetTransform()->TransformDirection(*direction); } void InternalCall_Transform_InverseTransformDirection(uint64_t gameObjectUUID, XCEngine::Math::Vector3* direction, XCEngine::Math::Vector3* outDirection) { if (!direction || !outDirection) { return; } Components::GameObject* gameObject = FindGameObjectByUUID(gameObjectUUID); if (!gameObject || !gameObject->GetTransform()) { *outDirection = *direction; return; } *outDirection = gameObject->GetTransform()->InverseTransformDirection(*direction); } uint64_t InternalCall_Transform_GetParent(uint64_t gameObjectUUID) { Components::GameObject* gameObject = FindGameObjectByUUID(gameObjectUUID); if (!gameObject || !gameObject->GetParent()) { return 0; } return gameObject->GetParent()->GetUUID(); } void InternalCall_Transform_SetParent(uint64_t gameObjectUUID, uint64_t parentGameObjectUUID, mono_bool worldPositionStays) { Components::GameObject* gameObject = FindGameObjectByUUID(gameObjectUUID); if (!gameObject) { return; } Components::GameObject* parent = parentGameObjectUUID != 0 ? FindGameObjectByUUID(parentGameObjectUUID) : nullptr; gameObject->SetParent(parent, worldPositionStays != 0); } int32_t InternalCall_Transform_GetChildCount(uint64_t gameObjectUUID) { Components::GameObject* gameObject = FindGameObjectByUUID(gameObjectUUID); return gameObject ? static_cast(gameObject->GetChildCount()) : 0; } uint64_t InternalCall_Transform_GetChild(uint64_t gameObjectUUID, int32_t index) { Components::GameObject* gameObject = FindGameObjectByUUID(gameObjectUUID); if (!gameObject || index < 0) { return 0; } Components::GameObject* child = gameObject->GetChild(static_cast(index)); return child ? child->GetUUID() : 0; } float InternalCall_Camera_GetFieldOfView(uint64_t gameObjectUUID) { Components::CameraComponent* component = FindCameraComponent(gameObjectUUID); return component ? component->GetFieldOfView() : 0.0f; } void InternalCall_Camera_SetFieldOfView(uint64_t gameObjectUUID, float value) { Components::CameraComponent* component = FindCameraComponent(gameObjectUUID); if (!component) { return; } component->SetFieldOfView(value); } float InternalCall_Camera_GetNearClipPlane(uint64_t gameObjectUUID) { Components::CameraComponent* component = FindCameraComponent(gameObjectUUID); return component ? component->GetNearClipPlane() : 0.0f; } void InternalCall_Camera_SetNearClipPlane(uint64_t gameObjectUUID, float value) { Components::CameraComponent* component = FindCameraComponent(gameObjectUUID); if (!component) { return; } component->SetNearClipPlane(value); } float InternalCall_Camera_GetFarClipPlane(uint64_t gameObjectUUID) { Components::CameraComponent* component = FindCameraComponent(gameObjectUUID); return component ? component->GetFarClipPlane() : 0.0f; } void InternalCall_Camera_SetFarClipPlane(uint64_t gameObjectUUID, float value) { Components::CameraComponent* component = FindCameraComponent(gameObjectUUID); if (!component) { return; } component->SetFarClipPlane(value); } float InternalCall_Camera_GetDepth(uint64_t gameObjectUUID) { Components::CameraComponent* component = FindCameraComponent(gameObjectUUID); return component ? component->GetDepth() : 0.0f; } void InternalCall_Camera_SetDepth(uint64_t gameObjectUUID, float value) { Components::CameraComponent* component = FindCameraComponent(gameObjectUUID); if (!component) { return; } component->SetDepth(value); } mono_bool InternalCall_Camera_GetPrimary(uint64_t gameObjectUUID) { Components::CameraComponent* component = FindCameraComponent(gameObjectUUID); return (component && component->IsPrimary()) ? 1 : 0; } void InternalCall_Camera_SetPrimary(uint64_t gameObjectUUID, mono_bool value) { Components::CameraComponent* component = FindCameraComponent(gameObjectUUID); if (!component) { return; } component->SetPrimary(value != 0); } int32_t InternalCall_Camera_GetClearMode(uint64_t gameObjectUUID) { Components::CameraComponent* component = FindCameraComponent(gameObjectUUID); return component != nullptr ? static_cast(component->GetClearMode()) : 0; } void InternalCall_Camera_SetClearMode(uint64_t gameObjectUUID, int32_t value) { Components::CameraComponent* component = FindCameraComponent(gameObjectUUID); if (!component) { return; } component->SetClearMode( static_cast(value)); } int32_t InternalCall_Camera_GetStackType(uint64_t gameObjectUUID) { Components::CameraComponent* component = FindCameraComponent(gameObjectUUID); return component != nullptr ? static_cast(component->GetStackType()) : 0; } void InternalCall_Camera_SetStackType(uint64_t gameObjectUUID, int32_t value) { Components::CameraComponent* component = FindCameraComponent(gameObjectUUID); if (!component) { return; } component->SetStackType( static_cast(value)); } int32_t InternalCall_Camera_GetProjectionType(uint64_t gameObjectUUID) { Components::CameraComponent* component = FindCameraComponent(gameObjectUUID); return component != nullptr ? static_cast(component->GetProjectionType()) : 0; } mono_bool InternalCall_Camera_GetSkyboxEnabled(uint64_t gameObjectUUID) { Components::CameraComponent* component = FindCameraComponent(gameObjectUUID); return (component && component->IsSkyboxEnabled()) ? 1 : 0; } mono_bool InternalCall_Camera_GetHasSkyboxMaterial(uint64_t gameObjectUUID) { Components::CameraComponent* component = FindCameraComponent(gameObjectUUID); return (component && component->GetSkyboxMaterial() != nullptr) ? 1 : 0; } mono_bool InternalCall_Camera_GetHasFinalColorOverrides( uint64_t gameObjectUUID) { Components::CameraComponent* component = FindCameraComponent(gameObjectUUID); return (component && component->GetFinalColorOverrides().HasOverrides()) ? 1 : 0; } void InternalCall_Camera_GetFinalColorOverrideSettings( uint64_t gameObjectUUID, ManagedFinalColorOverrideSettingsData* outSettings) { if (outSettings == nullptr) { return; } Components::CameraComponent* component = FindCameraComponent(gameObjectUUID); const Rendering::FinalColorOverrideSettings sourceSettings = component != nullptr ? component->GetFinalColorOverrides() : Rendering::FinalColorOverrideSettings{}; *outSettings = BuildManagedFinalColorOverrideSettings( sourceSettings); } void InternalCall_Camera_GetSkyboxTopColor( uint64_t gameObjectUUID, XCEngine::Math::Color* outColor) { if (outColor == nullptr) { return; } Components::CameraComponent* component = FindCameraComponent(gameObjectUUID); *outColor = component != nullptr ? component->GetSkyboxTopColor() : XCEngine::Math::Color(); } void InternalCall_Camera_GetSkyboxHorizonColor( uint64_t gameObjectUUID, XCEngine::Math::Color* outColor) { if (outColor == nullptr) { return; } Components::CameraComponent* component = FindCameraComponent(gameObjectUUID); *outColor = component != nullptr ? component->GetSkyboxHorizonColor() : XCEngine::Math::Color(); } void InternalCall_Camera_GetSkyboxBottomColor( uint64_t gameObjectUUID, XCEngine::Math::Color* outColor) { if (outColor == nullptr) { return; } Components::CameraComponent* component = FindCameraComponent(gameObjectUUID); *outColor = component != nullptr ? component->GetSkyboxBottomColor() : XCEngine::Math::Color(); } float InternalCall_Light_GetIntensity(uint64_t gameObjectUUID) { Components::LightComponent* component = FindLightComponent(gameObjectUUID); return component ? component->GetIntensity() : 0.0f; } void InternalCall_Light_SetIntensity(uint64_t gameObjectUUID, float value) { Components::LightComponent* component = FindLightComponent(gameObjectUUID); if (!component) { return; } component->SetIntensity(value); } float InternalCall_Light_GetRange(uint64_t gameObjectUUID) { Components::LightComponent* component = FindLightComponent(gameObjectUUID); return component ? component->GetRange() : 0.0f; } void InternalCall_Light_SetRange(uint64_t gameObjectUUID, float value) { Components::LightComponent* component = FindLightComponent(gameObjectUUID); if (!component) { return; } component->SetRange(value); } float InternalCall_Light_GetSpotAngle(uint64_t gameObjectUUID) { Components::LightComponent* component = FindLightComponent(gameObjectUUID); return component ? component->GetSpotAngle() : 0.0f; } void InternalCall_Light_SetSpotAngle(uint64_t gameObjectUUID, float value) { Components::LightComponent* component = FindLightComponent(gameObjectUUID); if (!component) { return; } component->SetSpotAngle(value); } mono_bool InternalCall_Light_GetCastsShadows(uint64_t gameObjectUUID) { Components::LightComponent* component = FindLightComponent(gameObjectUUID); return (component && component->GetCastsShadows()) ? 1 : 0; } void InternalCall_Light_SetCastsShadows(uint64_t gameObjectUUID, mono_bool value) { Components::LightComponent* component = FindLightComponent(gameObjectUUID); if (!component) { return; } component->SetCastsShadows(value != 0); } MonoString* InternalCall_MeshFilter_GetMeshPath(uint64_t gameObjectUUID) { Components::MeshFilterComponent* component = FindMeshFilterComponent(gameObjectUUID); return mono_string_new( mono_domain_get(), component ? component->GetMeshPath().c_str() : ""); } void InternalCall_MeshFilter_SetMeshPath(uint64_t gameObjectUUID, MonoString* path) { Components::MeshFilterComponent* component = FindMeshFilterComponent(gameObjectUUID); if (!component) { return; } component->SetMeshPath(MonoStringToUtf8(path)); } int32_t InternalCall_MeshRenderer_GetMaterialCount(uint64_t gameObjectUUID) { Components::MeshRendererComponent* component = FindMeshRendererComponent(gameObjectUUID); return component ? static_cast(component->GetMaterialCount()) : 0; } MonoString* InternalCall_MeshRenderer_GetMaterialPath(uint64_t gameObjectUUID, int32_t index) { Components::MeshRendererComponent* component = FindMeshRendererComponent(gameObjectUUID); const std::string path = (component && index >= 0) ? component->GetMaterialPath(static_cast(index)) : std::string(); return mono_string_new(mono_domain_get(), path.c_str()); } void InternalCall_MeshRenderer_SetMaterialPath(uint64_t gameObjectUUID, int32_t index, MonoString* path) { Components::MeshRendererComponent* component = FindMeshRendererComponent(gameObjectUUID); if (!component || index < 0) { return; } component->SetMaterialPath(static_cast(index), MonoStringToUtf8(path)); } void InternalCall_MeshRenderer_ClearMaterials(uint64_t gameObjectUUID) { Components::MeshRendererComponent* component = FindMeshRendererComponent(gameObjectUUID); if (!component) { return; } component->ClearMaterials(); } mono_bool InternalCall_MeshRenderer_GetCastShadows(uint64_t gameObjectUUID) { Components::MeshRendererComponent* component = FindMeshRendererComponent(gameObjectUUID); return (component && component->GetCastShadows()) ? 1 : 0; } void InternalCall_MeshRenderer_SetCastShadows(uint64_t gameObjectUUID, mono_bool value) { Components::MeshRendererComponent* component = FindMeshRendererComponent(gameObjectUUID); if (!component) { return; } component->SetCastShadows(value != 0); } mono_bool InternalCall_MeshRenderer_GetReceiveShadows(uint64_t gameObjectUUID) { Components::MeshRendererComponent* component = FindMeshRendererComponent(gameObjectUUID); return (component && component->GetReceiveShadows()) ? 1 : 0; } void InternalCall_MeshRenderer_SetReceiveShadows(uint64_t gameObjectUUID, mono_bool value) { Components::MeshRendererComponent* component = FindMeshRendererComponent(gameObjectUUID); if (!component) { return; } component->SetReceiveShadows(value != 0); } int32_t InternalCall_MeshRenderer_GetRenderLayer(uint64_t gameObjectUUID) { Components::MeshRendererComponent* component = FindMeshRendererComponent(gameObjectUUID); return component ? static_cast(component->GetRenderLayer()) : 0; } void InternalCall_MeshRenderer_SetRenderLayer(uint64_t gameObjectUUID, int32_t value) { Components::MeshRendererComponent* component = FindMeshRendererComponent(gameObjectUUID); if (!component) { return; } component->SetRenderLayer(static_cast(std::max(value, 0))); } int32_t InternalCall_Rigidbody_GetBodyType(uint64_t gameObjectUUID) { Components::RigidbodyComponent* component = FindRigidbodyComponent(gameObjectUUID); return component ? static_cast(component->GetBodyType()) : static_cast(Physics::PhysicsBodyType::Dynamic); } void InternalCall_Rigidbody_SetBodyType(uint64_t gameObjectUUID, int32_t value) { Components::RigidbodyComponent* component = FindRigidbodyComponent(gameObjectUUID); if (!component) { return; } component->SetBodyType(ResolveManagedPhysicsBodyType(value)); } float InternalCall_Rigidbody_GetMass(uint64_t gameObjectUUID) { Components::RigidbodyComponent* component = FindRigidbodyComponent(gameObjectUUID); return component ? component->GetMass() : 1.0f; } void InternalCall_Rigidbody_SetMass(uint64_t gameObjectUUID, float value) { Components::RigidbodyComponent* component = FindRigidbodyComponent(gameObjectUUID); if (!component) { return; } component->SetMass(value); } float InternalCall_Rigidbody_GetLinearDamping(uint64_t gameObjectUUID) { Components::RigidbodyComponent* component = FindRigidbodyComponent(gameObjectUUID); return component ? component->GetLinearDamping() : 0.0f; } void InternalCall_Rigidbody_SetLinearDamping(uint64_t gameObjectUUID, float value) { Components::RigidbodyComponent* component = FindRigidbodyComponent(gameObjectUUID); if (!component) { return; } component->SetLinearDamping(value); } float InternalCall_Rigidbody_GetAngularDamping(uint64_t gameObjectUUID) { Components::RigidbodyComponent* component = FindRigidbodyComponent(gameObjectUUID); return component ? component->GetAngularDamping() : 0.05f; } void InternalCall_Rigidbody_SetAngularDamping(uint64_t gameObjectUUID, float value) { Components::RigidbodyComponent* component = FindRigidbodyComponent(gameObjectUUID); if (!component) { return; } component->SetAngularDamping(value); } void InternalCall_Rigidbody_GetLinearVelocity(uint64_t gameObjectUUID, XCEngine::Math::Vector3* outVelocity) { if (!outVelocity) { return; } Components::RigidbodyComponent* component = FindRigidbodyComponent(gameObjectUUID); *outVelocity = component ? component->GetLinearVelocity() : XCEngine::Math::Vector3::Zero(); } void InternalCall_Rigidbody_SetLinearVelocity(uint64_t gameObjectUUID, XCEngine::Math::Vector3* velocity) { Components::RigidbodyComponent* component = FindRigidbodyComponent(gameObjectUUID); if (!component || !velocity) { return; } component->SetLinearVelocity(*velocity); } void InternalCall_Rigidbody_GetAngularVelocity(uint64_t gameObjectUUID, XCEngine::Math::Vector3* outVelocity) { if (!outVelocity) { return; } Components::RigidbodyComponent* component = FindRigidbodyComponent(gameObjectUUID); *outVelocity = component ? component->GetAngularVelocity() : XCEngine::Math::Vector3::Zero(); } void InternalCall_Rigidbody_SetAngularVelocity(uint64_t gameObjectUUID, XCEngine::Math::Vector3* velocity) { Components::RigidbodyComponent* component = FindRigidbodyComponent(gameObjectUUID); if (!component || !velocity) { return; } component->SetAngularVelocity(*velocity); } mono_bool InternalCall_Rigidbody_GetUseGravity(uint64_t gameObjectUUID) { Components::RigidbodyComponent* component = FindRigidbodyComponent(gameObjectUUID); return (component && component->GetUseGravity()) ? 1 : 0; } void InternalCall_Rigidbody_SetUseGravity(uint64_t gameObjectUUID, mono_bool value) { Components::RigidbodyComponent* component = FindRigidbodyComponent(gameObjectUUID); if (!component) { return; } component->SetUseGravity(value != 0); } mono_bool InternalCall_Rigidbody_GetEnableCCD(uint64_t gameObjectUUID) { Components::RigidbodyComponent* component = FindRigidbodyComponent(gameObjectUUID); return (component && component->GetEnableCCD()) ? 1 : 0; } void InternalCall_Rigidbody_SetEnableCCD(uint64_t gameObjectUUID, mono_bool value) { Components::RigidbodyComponent* component = FindRigidbodyComponent(gameObjectUUID); if (!component) { return; } component->SetEnableCCD(value != 0); } void InternalCall_Rigidbody_AddForce(uint64_t gameObjectUUID, XCEngine::Math::Vector3* force, int32_t forceMode) { Components::RigidbodyComponent* component = FindRigidbodyComponent(gameObjectUUID); if (!component || !force) { return; } component->AddForce(*force, ResolveManagedForceMode(forceMode)); } void InternalCall_Rigidbody_ClearForces(uint64_t gameObjectUUID) { Components::RigidbodyComponent* component = FindRigidbodyComponent(gameObjectUUID); if (!component) { return; } component->ClearForces(); } mono_bool InternalCall_Physics_Raycast( XCEngine::Math::Vector3* origin, XCEngine::Math::Vector3* direction, float maxDistance, uint64_t* outHitGameObjectUUID, XCEngine::Math::Vector3* outHitPoint, XCEngine::Math::Vector3* outHitNormal, float* outHitDistance, int32_t* outHitIsTrigger) { if (outHitGameObjectUUID) { *outHitGameObjectUUID = 0; } if (outHitPoint) { *outHitPoint = XCEngine::Math::Vector3::Zero(); } if (outHitNormal) { *outHitNormal = XCEngine::Math::Vector3::Zero(); } if (outHitDistance) { *outHitDistance = 0.0f; } if (outHitIsTrigger) { *outHitIsTrigger = 0; } Physics::PhysicsWorld* physicsWorld = FindRuntimePhysicsWorld(); if (!physicsWorld || !origin || !direction) { return 0; } Physics::RaycastHit hit; if (!physicsWorld->Raycast(*origin, *direction, maxDistance, hit)) { return 0; } if (outHitGameObjectUUID) { *outHitGameObjectUUID = hit.gameObject ? hit.gameObject->GetUUID() : 0; } if (outHitPoint) { *outHitPoint = hit.point; } if (outHitNormal) { *outHitNormal = hit.normal; } if (outHitDistance) { *outHitDistance = hit.distance; } if (outHitIsTrigger) { *outHitIsTrigger = hit.isTrigger ? 1 : 0; } return 1; } void InternalCall_Rendering_SetRenderPipelineAsset(MonoObject* assetObject) { MonoScriptRuntime* const runtime = GetActiveMonoScriptRuntime(); const Rendering::Pipelines::ManagedRenderPipelineAssetDescriptor currentDescriptor = Rendering::GetGraphicsSettingsState() .GetConfiguredRenderPipelineAssetDescriptor(); if (assetObject == nullptr) { ClearManagedRenderPipelineSelection(runtime); return; } MonoClass* const monoClass = mono_object_get_class(assetObject); if (monoClass == nullptr) { return; } if (runtime != nullptr && !runtime->IsScriptableRenderPipelineAssetObject(assetObject)) { return; } MonoImage* image = mono_class_get_image(monoClass); Rendering::Pipelines::ManagedRenderPipelineAssetDescriptor descriptor = {}; descriptor.assemblyName = TrimAssemblyName(SafeString(image != nullptr ? mono_image_get_name(image) : nullptr)); descriptor.namespaceName = SafeString(mono_class_get_namespace(monoClass)); descriptor.className = SafeString(mono_class_get_name(monoClass)); descriptor.managedAssetHandle = runtime != nullptr ? runtime->RetainExternalManagedObjectReference(assetObject) : 0u; if (!descriptor.IsValid() || descriptor.managedAssetHandle == 0u) { if (runtime != nullptr && descriptor.managedAssetHandle != 0u) { runtime->ReleaseExternalManagedObject( descriptor.managedAssetHandle); } return; } if (runtime != nullptr && currentDescriptor.managedAssetHandle != 0u && currentDescriptor.managedAssetHandle != descriptor.managedAssetHandle) { runtime->ReleaseExternalManagedObject( currentDescriptor.managedAssetHandle); } Rendering::GetGraphicsSettingsState() .SetConfiguredRenderPipelineAssetDescriptor(descriptor); } MonoObject* InternalCall_Rendering_GetRenderPipelineAsset() { MonoScriptRuntime* const runtime = GetActiveMonoScriptRuntime(); if (runtime == nullptr) { return nullptr; } Rendering::Pipelines::ManagedRenderPipelineAssetDescriptor descriptor = Rendering::GetGraphicsSettingsState() .GetConfiguredRenderPipelineAssetDescriptor(); if (!descriptor.IsValid()) { return nullptr; } if (descriptor.managedAssetHandle == 0u) { if (!runtime->TryEnsureManagedRenderPipelineAssetHandle(descriptor)) { return nullptr; } Rendering::GetGraphicsSettingsState() .SetConfiguredRenderPipelineAssetDescriptor(descriptor); } return runtime->GetExternalManagedObject( descriptor.managedAssetHandle); } int32_t InternalCall_Rendering_ScriptableRenderContext_GetStage( uint64_t nativeHandle) { const ManagedScriptableRenderContextState* const state = FindManagedScriptableRenderContextState(nativeHandle); return state != nullptr ? static_cast(state->stage) : static_cast(Rendering::CameraFrameStage::MainScene); } int32_t InternalCall_Rendering_ScriptableRenderContext_GetRendererIndex( uint64_t nativeHandle) { const ManagedScriptableRenderContextState* const state = FindManagedScriptableRenderContextState(nativeHandle); return state != nullptr && state->graphContext != nullptr ? state->graphContext->rendererIndex : -1; } int32_t InternalCall_Rendering_ScriptableRenderContext_GetSourceColorTextureHandle( uint64_t nativeHandle) { const ManagedScriptableRenderContextState* const state = FindManagedScriptableRenderContextState(nativeHandle); return EncodeManagedRenderGraphTextureHandle( ResolveManagedScriptableRenderContextSourceColorTexture( state)); } int32_t InternalCall_Rendering_ScriptableRenderContext_GetPrimaryColorTargetHandle( uint64_t nativeHandle) { const ManagedScriptableRenderContextState* const state = FindManagedScriptableRenderContextState(nativeHandle); return EncodeManagedRenderGraphTextureHandle( ResolveManagedScriptableRenderContextPrimaryColorTarget( state)); } int32_t InternalCall_Rendering_ScriptableRenderContext_GetDepthTargetHandle( uint64_t nativeHandle) { const ManagedScriptableRenderContextState* const state = FindManagedScriptableRenderContextState(nativeHandle); return EncodeManagedRenderGraphTextureHandle( ResolveManagedScriptableRenderContextDepthTarget( state)); } int32_t InternalCall_Rendering_ScriptableRenderContext_CreateTransientTexture( uint64_t nativeHandle, MonoString* name, ManagedRenderGraphTextureDescData* descData) { ManagedScriptableRenderContextState* const state = FindManagedScriptableRenderContextState(nativeHandle); if (state == nullptr || state->graphContext == nullptr || descData == nullptr) { return -1; } const auto* const desc = reinterpret_cast( descData); if (!desc->IsValid()) { return -1; } const Rendering::RenderGraphTextureHandle handle = state->graphContext->graphBuilder.CreateTransientTexture( Containers::String(MonoStringToUtf8(name).c_str()), *desc); return EncodeManagedRenderGraphTextureHandle(handle); } int32_t InternalCall_Rendering_ScriptableRenderContext_CreateFullscreenTransientColorTexture( uint64_t nativeHandle, MonoString* name) { ManagedScriptableRenderContextState* const state = FindManagedScriptableRenderContextState(nativeHandle); if (state == nullptr || state->graphContext == nullptr) { return -1; } const Rendering::RenderGraphTextureHandle handle = state->graphContext->graphBuilder.CreateTransientTexture( Containers::String(MonoStringToUtf8(name).c_str()), Rendering::BuildFullscreenTransientTextureDesc( state->graphContext->surfaceTemplate)); return EncodeManagedRenderGraphTextureHandle(handle); } int32_t InternalCall_Rendering_ScriptableRenderContext_CreateFullscreenTransientDepthTexture( uint64_t nativeHandle, MonoString* name) { ManagedScriptableRenderContextState* const state = FindManagedScriptableRenderContextState(nativeHandle); if (state == nullptr || state->graphContext == nullptr) { return -1; } const Rendering::RenderGraphTextureHandle handle = state->graphContext->graphBuilder.CreateTransientTexture( Containers::String(MonoStringToUtf8(name).c_str()), BuildManagedFullscreenTransientDepthTextureDesc( state->graphContext->surfaceTemplate)); return EncodeManagedRenderGraphTextureHandle(handle); } uint64_t InternalCall_Rendering_ScriptableRenderContext_BeginRasterPass( uint64_t nativeHandle, MonoString* passName) { ManagedScriptableRenderContextState* const state = FindManagedScriptableRenderContextState(nativeHandle); if (state == nullptr || state->graphContext == nullptr || !Rendering::IsCameraFrameFullscreenSequenceStage(state->stage)) { return 0u; } const Containers::String passNameString( MonoStringToUtf8(passName).c_str()); if (passNameString.Empty()) { return 0u; } uint64_t rasterPassHandle = state->nextPendingRasterPassHandle++; if (rasterPassHandle == 0u) { rasterPassHandle = state->nextPendingRasterPassHandle++; } ManagedScriptableRenderContextState::RasterPassRecordRequest request = {}; request.passName = passNameString; state->pendingRasterPassRequests[rasterPassHandle] = std::move(request); return rasterPassHandle; } mono_bool InternalCall_Rendering_ScriptableRenderContext_SetRasterPassSourceColorTexture( uint64_t nativeHandle, uint64_t rasterPassHandle, int32_t sourceTextureHandle) { ManagedScriptableRenderContextState* const state = FindManagedScriptableRenderContextState(nativeHandle); ManagedScriptableRenderContextState::RasterPassRecordRequest* const request = FindPendingManagedRasterPassRecordRequest( state, rasterPassHandle); if (request == nullptr) { return 0; } const Rendering::RenderGraphTextureHandle sourceColorTexture = DecodeManagedRenderGraphTextureHandle( sourceTextureHandle); if (!sourceColorTexture.IsValid()) { return 0; } request->sourceColorTexture = sourceColorTexture; return 1; } mono_bool InternalCall_Rendering_ScriptableRenderContext_AddRasterPassReadTexture( uint64_t nativeHandle, uint64_t rasterPassHandle, int32_t textureHandle) { ManagedScriptableRenderContextState* const state = FindManagedScriptableRenderContextState(nativeHandle); ManagedScriptableRenderContextState::RasterPassRecordRequest* const request = FindPendingManagedRasterPassRecordRequest( state, rasterPassHandle); if (request == nullptr) { return 0; } const Rendering::RenderGraphTextureHandle readTexture = DecodeManagedRenderGraphTextureHandle( textureHandle); if (!readTexture.IsValid()) { return 0; } request->readTextures.push_back(readTexture); return 1; } mono_bool InternalCall_Rendering_ScriptableRenderContext_AddRasterPassReadDepthTexture( uint64_t nativeHandle, uint64_t rasterPassHandle, int32_t textureHandle) { ManagedScriptableRenderContextState* const state = FindManagedScriptableRenderContextState(nativeHandle); ManagedScriptableRenderContextState::RasterPassRecordRequest* const request = FindPendingManagedRasterPassRecordRequest( state, rasterPassHandle); if (request == nullptr) { return 0; } const Rendering::RenderGraphTextureHandle readDepthTexture = DecodeManagedRenderGraphTextureHandle( textureHandle); if (!readDepthTexture.IsValid()) { return 0; } request->readDepthTextures.push_back(readDepthTexture); return 1; } mono_bool InternalCall_Rendering_ScriptableRenderContext_AddRasterPassTextureBinding( uint64_t nativeHandle, uint64_t rasterPassHandle, MonoString* shaderResourceName, int32_t textureHandle, mono_bool isDepth) { ManagedScriptableRenderContextState* const state = FindManagedScriptableRenderContextState(nativeHandle); ManagedScriptableRenderContextState::RasterPassRecordRequest* const request = FindPendingManagedRasterPassRecordRequest( state, rasterPassHandle); if (request == nullptr) { return 0; } const Containers::String shaderResourceNameString( MonoStringToUtf8(shaderResourceName).c_str()); if (shaderResourceNameString.Empty()) { return 0; } const Rendering::RenderGraphTextureHandle texture = DecodeManagedRenderGraphTextureHandle( textureHandle); if (!texture.IsValid()) { return 0; } Rendering::RenderPassGraphTextureBindingRequest bindingRequest = {}; bindingRequest.resourceName = shaderResourceNameString; bindingRequest.texture = texture; bindingRequest.aspect = isDepth != 0 ? Rendering::RenderGraphTextureAspect::Depth : Rendering::RenderGraphTextureAspect::Color; auto existingBinding = std::find_if( request->textureBindings.begin(), request->textureBindings.end(), [&shaderResourceNameString]( const Rendering::RenderPassGraphTextureBindingRequest& existingRequest) { return existingRequest.resourceName == shaderResourceNameString; }); if (existingBinding != request->textureBindings.end()) { *existingBinding = std::move(bindingRequest); } else { request->textureBindings.push_back( std::move(bindingRequest)); } return 1; } mono_bool InternalCall_Rendering_ScriptableRenderContext_SetRasterPassColorAttachment( uint64_t nativeHandle, uint64_t rasterPassHandle, int32_t colorAttachmentIndex, int32_t textureHandle) { ManagedScriptableRenderContextState* const state = FindManagedScriptableRenderContextState(nativeHandle); ManagedScriptableRenderContextState::RasterPassRecordRequest* const request = FindPendingManagedRasterPassRecordRequest( state, rasterPassHandle); if (request == nullptr || colorAttachmentIndex < 0) { return 0; } const Rendering::RenderGraphTextureHandle colorAttachment = DecodeManagedRenderGraphTextureHandle( textureHandle); if (!colorAttachment.IsValid()) { return 0; } if (request->colorTargets.size() <= static_cast(colorAttachmentIndex)) { request->colorTargets.resize( static_cast(colorAttachmentIndex) + 1u); } request->colorTargets[static_cast(colorAttachmentIndex)] = colorAttachment; return 1; } mono_bool InternalCall_Rendering_ScriptableRenderContext_SetRasterPassDepthAttachment( uint64_t nativeHandle, uint64_t rasterPassHandle, int32_t textureHandle) { ManagedScriptableRenderContextState* const state = FindManagedScriptableRenderContextState(nativeHandle); ManagedScriptableRenderContextState::RasterPassRecordRequest* const request = FindPendingManagedRasterPassRecordRequest( state, rasterPassHandle); if (request == nullptr) { return 0; } const Rendering::RenderGraphTextureHandle depthAttachment = DecodeManagedRenderGraphTextureHandle( textureHandle); if (!depthAttachment.IsValid()) { return 0; } request->depthTarget = depthAttachment; return 1; } mono_bool InternalCall_Rendering_ScriptableRenderContext_SetRasterPassColorScaleFullscreenExecution( uint64_t nativeHandle, uint64_t rasterPassHandle, XCEngine::Math::Vector4* vectorPayload) { ManagedScriptableRenderContextState* const state = FindManagedScriptableRenderContextState(nativeHandle); ManagedScriptableRenderContextState::RasterPassRecordRequest* const request = FindPendingManagedRasterPassRecordRequest( state, rasterPassHandle); if (request == nullptr || vectorPayload == nullptr) { return 0; } request->passDesc = Rendering::FullscreenPassDesc::MakeColorScale( *vectorPayload); return 1; } mono_bool InternalCall_Rendering_ScriptableRenderContext_SetRasterPassShaderVectorFullscreenExecution( uint64_t nativeHandle, uint64_t rasterPassHandle, MonoString* shaderPath, MonoString* shaderPassName, XCEngine::Math::Vector4* vectorPayload) { ManagedScriptableRenderContextState* const state = FindManagedScriptableRenderContextState(nativeHandle); ManagedScriptableRenderContextState::RasterPassRecordRequest* const request = FindPendingManagedRasterPassRecordRequest( state, rasterPassHandle); if (request == nullptr || vectorPayload == nullptr) { return 0; } const Containers::String shaderPathString( MonoStringToUtf8(shaderPath).c_str()); if (shaderPathString.Empty()) { return 0; } request->passDesc = Rendering::FullscreenPassDesc::MakeShaderVector( shaderPathString, *vectorPayload, Containers::String(MonoStringToUtf8(shaderPassName).c_str())); return request->passDesc.IsValid() ? 1 : 0; } mono_bool InternalCall_Rendering_ScriptableRenderContext_SetRasterPassFinalColorFullscreenExecution( uint64_t nativeHandle, uint64_t rasterPassHandle, ManagedFinalColorSettingsData* settingsData) { ManagedScriptableRenderContextState* const state = FindManagedScriptableRenderContextState(nativeHandle); ManagedScriptableRenderContextState::RasterPassRecordRequest* const request = FindPendingManagedRasterPassRecordRequest( state, rasterPassHandle); if (request == nullptr || settingsData == nullptr) { return 0; } request->passDesc = Rendering::FullscreenPassDesc::MakeFinalColor( BuildManagedFinalColorSettings( *settingsData)); return request->passDesc.IsValid() ? 1 : 0; } mono_bool InternalCall_Rendering_ScriptableRenderContext_CommitRasterPass( uint64_t nativeHandle, uint64_t rasterPassHandle) { ManagedScriptableRenderContextState* const state = FindManagedScriptableRenderContextState(nativeHandle); if (state == nullptr || state->graphContext == nullptr || !Rendering::IsCameraFrameFullscreenSequenceStage(state->stage)) { return 0; } auto it = state->pendingRasterPassRequests.find( rasterPassHandle); if (it == state->pendingRasterPassRequests.end()) { return 0; } ManagedScriptableRenderContextState::RasterPassRecordRequest request = std::move(it->second); state->pendingRasterPassRequests.erase(it); if (!request.passDesc.IsValid() || !ResolveManagedPrimaryColorTarget(request.colorTargets) .IsValid()) { return 0; } state->rasterPassRequests.push_back(std::move(request)); return 1; } int32_t InternalCall_Rendering_ScriptableRenderContext_GetStageColorSource( uint64_t nativeHandle) { const ManagedScriptableRenderContextState* const state = FindManagedScriptableRenderContextState(nativeHandle); return static_cast( ResolveManagedScriptableRenderContextStageColorSource(state)); } mono_bool InternalCall_Rendering_ScriptableRenderContext_GetStageUsesGraphManagedOutputColor( uint64_t nativeHandle) { const ManagedScriptableRenderContextState* const state = FindManagedScriptableRenderContextState(nativeHandle); return ResolveManagedScriptableRenderContextUsesGraphManagedOutputColor( state) ? 1 : 0; } mono_bool InternalCall_Rendering_ScriptableRenderContext_GetMainDirectionalShadowEnabled( uint64_t nativeHandle) { const ManagedScriptableRenderContextState* const state = FindManagedScriptableRenderContextState(nativeHandle); return ResolveManagedScriptableRenderContextDirectionalShadowPlan(state) .enabled ? 1 : 0; } void InternalCall_Rendering_ScriptableRenderContext_GetMainDirectionalShadowViewProjection( uint64_t nativeHandle, XCEngine::Math::Matrix4x4* outViewProjection) { const ManagedScriptableRenderContextState* const state = FindManagedScriptableRenderContextState(nativeHandle); *outViewProjection = ResolveManagedScriptableRenderContextDirectionalShadowPlan(state) .cameraData.viewProjection; } float InternalCall_Rendering_ScriptableRenderContext_GetMainDirectionalShadowOrthographicHalfExtent( uint64_t nativeHandle) { const ManagedScriptableRenderContextState* const state = FindManagedScriptableRenderContextState(nativeHandle); return ResolveManagedScriptableRenderContextDirectionalShadowPlan(state) .orthographicHalfExtent; } float InternalCall_Rendering_ScriptableRenderContext_GetMainDirectionalShadowNearClipPlane( uint64_t nativeHandle) { const ManagedScriptableRenderContextState* const state = FindManagedScriptableRenderContextState(nativeHandle); return ResolveManagedScriptableRenderContextDirectionalShadowPlan(state) .nearClipPlane; } float InternalCall_Rendering_ScriptableRenderContext_GetMainDirectionalShadowFarClipPlane( uint64_t nativeHandle) { const ManagedScriptableRenderContextState* const state = FindManagedScriptableRenderContextState(nativeHandle); return ResolveManagedScriptableRenderContextDirectionalShadowPlan(state) .farClipPlane; } int32_t InternalCall_Rendering_ScriptableRenderContext_GetMainDirectionalShadowMapWidth( uint64_t nativeHandle) { const ManagedScriptableRenderContextState* const state = FindManagedScriptableRenderContextState(nativeHandle); return static_cast( ResolveManagedScriptableRenderContextDirectionalShadowPlan(state) .mapWidth); } int32_t InternalCall_Rendering_ScriptableRenderContext_GetMainDirectionalShadowMapHeight( uint64_t nativeHandle) { const ManagedScriptableRenderContextState* const state = FindManagedScriptableRenderContextState(nativeHandle); return static_cast( ResolveManagedScriptableRenderContextDirectionalShadowPlan(state) .mapHeight); } float InternalCall_Rendering_ScriptableRenderContext_GetMainDirectionalShadowWorldTexelSize( uint64_t nativeHandle) { const ManagedScriptableRenderContextState* const state = FindManagedScriptableRenderContextState(nativeHandle); return ResolveManagedScriptableRenderContextDirectionalShadowPlan(state) .texelWorldSize; } float InternalCall_Rendering_ScriptableRenderContext_GetMainDirectionalShadowReceiverDepthBias( uint64_t nativeHandle) { const ManagedScriptableRenderContextState* const state = FindManagedScriptableRenderContextState(nativeHandle); return ResolveManagedScriptableRenderContextDirectionalShadowPlan(state) .sampling.receiverDepthBias; } float InternalCall_Rendering_ScriptableRenderContext_GetMainDirectionalShadowNormalBiasScale( uint64_t nativeHandle) { const ManagedScriptableRenderContextState* const state = FindManagedScriptableRenderContextState(nativeHandle); return ResolveManagedScriptableRenderContextDirectionalShadowPlan(state) .sampling.normalBiasScale; } float InternalCall_Rendering_ScriptableRenderContext_GetMainDirectionalShadowStrength( uint64_t nativeHandle) { const ManagedScriptableRenderContextState* const state = FindManagedScriptableRenderContextState(nativeHandle); return ResolveManagedScriptableRenderContextDirectionalShadowPlan(state) .sampling.shadowStrength; } float InternalCall_Rendering_ScriptableRenderContext_GetMainDirectionalShadowDepthBiasFactor( uint64_t nativeHandle) { const ManagedScriptableRenderContextState* const state = FindManagedScriptableRenderContextState(nativeHandle); return ResolveManagedScriptableRenderContextDirectionalShadowPlan(state) .casterBias.depthBiasFactor; } int32_t InternalCall_Rendering_ScriptableRenderContext_GetMainDirectionalShadowDepthBiasUnits( uint64_t nativeHandle) { const ManagedScriptableRenderContextState* const state = FindManagedScriptableRenderContextState(nativeHandle); return ResolveManagedScriptableRenderContextDirectionalShadowPlan(state) .casterBias.depthBiasUnits; } void InternalCall_Rendering_ScriptableRenderContext_GetCameraView( uint64_t nativeHandle, XCEngine::Math::Matrix4x4* outView) { if (outView == nullptr) { return; } const ManagedScriptableRenderContextState* const state = FindManagedScriptableRenderContextState(nativeHandle); *outView = ResolveManagedScriptableRenderContextCameraData(state).view; } void InternalCall_Rendering_ScriptableRenderContext_GetCameraProjection( uint64_t nativeHandle, XCEngine::Math::Matrix4x4* outProjection) { if (outProjection == nullptr) { return; } const ManagedScriptableRenderContextState* const state = FindManagedScriptableRenderContextState(nativeHandle); *outProjection = ResolveManagedScriptableRenderContextCameraData(state).projection; } void InternalCall_Rendering_ScriptableRenderContext_GetCameraViewProjection( uint64_t nativeHandle, XCEngine::Math::Matrix4x4* outViewProjection) { if (outViewProjection == nullptr) { return; } const ManagedScriptableRenderContextState* const state = FindManagedScriptableRenderContextState(nativeHandle); *outViewProjection = ResolveManagedScriptableRenderContextCameraData(state).viewProjection; } void InternalCall_Rendering_ScriptableRenderContext_GetCameraWorldPosition( uint64_t nativeHandle, XCEngine::Math::Vector3* outWorldPosition) { if (outWorldPosition == nullptr) { return; } const ManagedScriptableRenderContextState* const state = FindManagedScriptableRenderContextState(nativeHandle); *outWorldPosition = ResolveManagedScriptableRenderContextCameraData(state).worldPosition; } void InternalCall_Rendering_ScriptableRenderContext_GetCameraWorldRight( uint64_t nativeHandle, XCEngine::Math::Vector3* outWorldRight) { if (outWorldRight == nullptr) { return; } const ManagedScriptableRenderContextState* const state = FindManagedScriptableRenderContextState(nativeHandle); *outWorldRight = ResolveManagedScriptableRenderContextCameraData(state).worldRight; } void InternalCall_Rendering_ScriptableRenderContext_GetCameraWorldUp( uint64_t nativeHandle, XCEngine::Math::Vector3* outWorldUp) { if (outWorldUp == nullptr) { return; } const ManagedScriptableRenderContextState* const state = FindManagedScriptableRenderContextState(nativeHandle); *outWorldUp = ResolveManagedScriptableRenderContextCameraData(state).worldUp; } void InternalCall_Rendering_ScriptableRenderContext_GetCameraWorldForward( uint64_t nativeHandle, XCEngine::Math::Vector3* outWorldForward) { if (outWorldForward == nullptr) { return; } const ManagedScriptableRenderContextState* const state = FindManagedScriptableRenderContextState(nativeHandle); *outWorldForward = ResolveManagedScriptableRenderContextCameraData(state).worldForward; } void InternalCall_Rendering_ScriptableRenderContext_GetCameraClearColor( uint64_t nativeHandle, XCEngine::Math::Color* outClearColor) { if (outClearColor == nullptr) { return; } const ManagedScriptableRenderContextState* const state = FindManagedScriptableRenderContextState(nativeHandle); *outClearColor = ResolveManagedScriptableRenderContextCameraData(state).clearColor; } int32_t InternalCall_Rendering_ScriptableRenderContext_GetCameraClearFlags( uint64_t nativeHandle) { const ManagedScriptableRenderContextState* const state = FindManagedScriptableRenderContextState(nativeHandle); return static_cast( ResolveManagedScriptableRenderContextCameraData(state).clearFlags); } mono_bool InternalCall_Rendering_ScriptableRenderContext_GetCameraPerspectiveProjection( uint64_t nativeHandle) { const ManagedScriptableRenderContextState* const state = FindManagedScriptableRenderContextState(nativeHandle); return ResolveManagedScriptableRenderContextCameraData(state) .perspectiveProjection ? 1 : 0; } float InternalCall_Rendering_ScriptableRenderContext_GetCameraVerticalFovRadians( uint64_t nativeHandle) { const ManagedScriptableRenderContextState* const state = FindManagedScriptableRenderContextState(nativeHandle); return ResolveManagedScriptableRenderContextCameraData(state) .verticalFovRadians; } float InternalCall_Rendering_ScriptableRenderContext_GetCameraOrthographicSize( uint64_t nativeHandle) { const ManagedScriptableRenderContextState* const state = FindManagedScriptableRenderContextState(nativeHandle); return ResolveManagedScriptableRenderContextCameraData(state) .orthographicSize; } float InternalCall_Rendering_ScriptableRenderContext_GetCameraAspectRatio( uint64_t nativeHandle) { const ManagedScriptableRenderContextState* const state = FindManagedScriptableRenderContextState(nativeHandle); return ResolveManagedScriptableRenderContextCameraData(state) .aspectRatio; } float InternalCall_Rendering_ScriptableRenderContext_GetCameraNearClipPlane( uint64_t nativeHandle) { const ManagedScriptableRenderContextState* const state = FindManagedScriptableRenderContextState(nativeHandle); return ResolveManagedScriptableRenderContextCameraData(state) .nearClipPlane; } float InternalCall_Rendering_ScriptableRenderContext_GetCameraFarClipPlane( uint64_t nativeHandle) { const ManagedScriptableRenderContextState* const state = FindManagedScriptableRenderContextState(nativeHandle); return ResolveManagedScriptableRenderContextCameraData(state) .farClipPlane; } int32_t InternalCall_Rendering_ScriptableRenderContext_GetCameraViewportWidth( uint64_t nativeHandle) { const ManagedScriptableRenderContextState* const state = FindManagedScriptableRenderContextState(nativeHandle); return static_cast( ResolveManagedScriptableRenderContextCameraData(state).viewportWidth); } int32_t InternalCall_Rendering_ScriptableRenderContext_GetCameraViewportHeight( uint64_t nativeHandle) { const ManagedScriptableRenderContextState* const state = FindManagedScriptableRenderContextState(nativeHandle); return static_cast( ResolveManagedScriptableRenderContextCameraData(state).viewportHeight); } mono_bool InternalCall_Rendering_ScriptableRenderContext_GetMainDirectionalLightEnabled( uint64_t nativeHandle) { const ManagedScriptableRenderContextState* const state = FindManagedScriptableRenderContextState(nativeHandle); return ResolveManagedScriptableRenderContextLightingData(state) .mainDirectionalLight.enabled ? 1 : 0; } mono_bool InternalCall_Rendering_ScriptableRenderContext_GetMainDirectionalLightCastsShadows( uint64_t nativeHandle) { const ManagedScriptableRenderContextState* const state = FindManagedScriptableRenderContextState(nativeHandle); return ResolveManagedScriptableRenderContextLightingData(state) .mainDirectionalLight.castsShadows ? 1 : 0; } void InternalCall_Rendering_ScriptableRenderContext_GetMainDirectionalLightDirection( uint64_t nativeHandle, XCEngine::Math::Vector3* outDirection) { if (outDirection == nullptr) { return; } const ManagedScriptableRenderContextState* const state = FindManagedScriptableRenderContextState(nativeHandle); *outDirection = ResolveManagedScriptableRenderContextLightingData(state) .mainDirectionalLight.direction; } void InternalCall_Rendering_ScriptableRenderContext_GetMainDirectionalLightColor( uint64_t nativeHandle, XCEngine::Math::Color* outColor) { if (outColor == nullptr) { return; } const ManagedScriptableRenderContextState* const state = FindManagedScriptableRenderContextState(nativeHandle); *outColor = ResolveManagedScriptableRenderContextLightingData(state) .mainDirectionalLight.color; } float InternalCall_Rendering_ScriptableRenderContext_GetMainDirectionalLightIntensity( uint64_t nativeHandle) { const ManagedScriptableRenderContextState* const state = FindManagedScriptableRenderContextState(nativeHandle); return ResolveManagedScriptableRenderContextLightingData(state) .mainDirectionalLight.intensity; } mono_bool InternalCall_Rendering_ScriptableRenderContext_GetHasMainDirectionalShadow( uint64_t nativeHandle) { const ManagedScriptableRenderContextState* const state = FindManagedScriptableRenderContextState(nativeHandle); return ResolveManagedScriptableRenderContextLightingData(state) .HasMainDirectionalShadow() ? 1 : 0; } int32_t InternalCall_Rendering_ScriptableRenderContext_GetAdditionalLightCount( uint64_t nativeHandle) { const ManagedScriptableRenderContextState* const state = FindManagedScriptableRenderContextState(nativeHandle); return static_cast( ResolveManagedScriptableRenderContextLightingData(state) .additionalLightCount); } int32_t InternalCall_Rendering_ScriptableRenderContext_GetEnvironmentMode( uint64_t nativeHandle) { const ManagedScriptableRenderContextState* const state = FindManagedScriptableRenderContextState(nativeHandle); return static_cast( ResolveManagedScriptableRenderContextEnvironmentData(state).mode); } void InternalCall_Rendering_ScriptableRenderContext_GetEnvironmentSkyboxTopColor( uint64_t nativeHandle, XCEngine::Math::Color* outColor) { if (outColor == nullptr) { return; } const ManagedScriptableRenderContextState* const state = FindManagedScriptableRenderContextState(nativeHandle); *outColor = ResolveManagedScriptableRenderContextEnvironmentData(state) .skybox.topColor; } void InternalCall_Rendering_ScriptableRenderContext_GetEnvironmentSkyboxHorizonColor( uint64_t nativeHandle, XCEngine::Math::Color* outColor) { if (outColor == nullptr) { return; } const ManagedScriptableRenderContextState* const state = FindManagedScriptableRenderContextState(nativeHandle); *outColor = ResolveManagedScriptableRenderContextEnvironmentData(state) .skybox.horizonColor; } void InternalCall_Rendering_ScriptableRenderContext_GetEnvironmentSkyboxBottomColor( uint64_t nativeHandle, XCEngine::Math::Color* outColor) { if (outColor == nullptr) { return; } const ManagedScriptableRenderContextState* const state = FindManagedScriptableRenderContextState(nativeHandle); *outColor = ResolveManagedScriptableRenderContextEnvironmentData(state) .skybox.bottomColor; } int32_t InternalCall_Rendering_ScriptableRenderContext_GetFinalColorOutputTransferMode( uint64_t nativeHandle) { const ManagedScriptableRenderContextState* const state = FindManagedScriptableRenderContextState(nativeHandle); return static_cast( ResolveManagedScriptableRenderContextFinalColorPolicy(state) .outputTransferMode); } int32_t InternalCall_Rendering_ScriptableRenderContext_GetFinalColorExposureMode( uint64_t nativeHandle) { const ManagedScriptableRenderContextState* const state = FindManagedScriptableRenderContextState(nativeHandle); return static_cast( ResolveManagedScriptableRenderContextFinalColorPolicy(state) .exposureMode); } float InternalCall_Rendering_ScriptableRenderContext_GetFinalColorExposureValue( uint64_t nativeHandle) { const ManagedScriptableRenderContextState* const state = FindManagedScriptableRenderContextState(nativeHandle); return ResolveManagedScriptableRenderContextFinalColorPolicy(state) .exposureValue; } int32_t InternalCall_Rendering_ScriptableRenderContext_GetFinalColorToneMappingMode( uint64_t nativeHandle) { const ManagedScriptableRenderContextState* const state = FindManagedScriptableRenderContextState(nativeHandle); return static_cast( ResolveManagedScriptableRenderContextFinalColorPolicy(state) .toneMappingMode); } void InternalCall_Rendering_ScriptableRenderContext_GetFinalColorScale( uint64_t nativeHandle, XCEngine::Math::Vector4* outScale) { if (outScale == nullptr) { return; } const ManagedScriptableRenderContextState* const state = FindManagedScriptableRenderContextState(nativeHandle); *outScale = ResolveManagedScriptableRenderContextFinalColorPolicy(state) .finalColorScale; } mono_bool InternalCall_Rendering_ScriptableRenderContext_GetFinalColorHasPipelineDefaults( uint64_t nativeHandle) { const ManagedScriptableRenderContextState* const state = FindManagedScriptableRenderContextState(nativeHandle); return ResolveManagedScriptableRenderContextFinalColorPolicy(state) .hasPipelineDefaults ? 1 : 0; } mono_bool InternalCall_Rendering_ScriptableRenderContext_GetFinalColorHasCameraOverrides( uint64_t nativeHandle) { const ManagedScriptableRenderContextState* const state = FindManagedScriptableRenderContextState(nativeHandle); return ResolveManagedScriptableRenderContextFinalColorPolicy(state) .hasCameraOverrides ? 1 : 0; } mono_bool InternalCall_Rendering_ScriptableRenderContext_RecordScenePhase( uint64_t nativeHandle, int32_t scenePhase) { ManagedScriptableRenderContextState* const state = FindManagedScriptableRenderContextState(nativeHandle); if (state == nullptr || state->graphContext == nullptr || state->sceneRecorder == nullptr || !SupportsManagedScriptableRenderContextSceneRecordingStage( state->stage)) { return 0; } return state->sceneRecorder->RecordScenePhase( static_cast(scenePhase)) ? 1 : 0; } mono_bool InternalCall_Rendering_ScriptableRenderContext_RecordSceneInjectionPoint( uint64_t nativeHandle, int32_t injectionPoint) { ManagedScriptableRenderContextState* const state = FindManagedScriptableRenderContextState(nativeHandle); if (state == nullptr || state->graphContext == nullptr || state->sceneRecorder == nullptr || state->stage != Rendering::CameraFrameStage::MainScene) { return 0; } return state->sceneRecorder->RecordInjectionPoint( static_cast(injectionPoint)) ? 1 : 0; } mono_bool InternalCall_Rendering_ScriptableRenderContext_RecordNativeSceneFeaturePass( uint64_t nativeHandle, int32_t featurePassId) { ManagedScriptableRenderContextState* const state = FindManagedScriptableRenderContextState(nativeHandle); if (state == nullptr || state->graphContext == nullptr || state->sceneRecorder == nullptr || state->stage != Rendering::CameraFrameStage::MainScene) { return 0; } const Rendering::NativeSceneFeaturePassId resolvedFeaturePassId = static_cast( featurePassId); if (resolvedFeaturePassId == Rendering::NativeSceneFeaturePassId::Invalid) { return 0; } return state->sceneRecorder->RecordFeaturePass( resolvedFeaturePassId) ? 1 : 0; } mono_bool InternalCall_Rendering_ScriptableRenderContext_DrawRenderersByDesc( uint64_t nativeHandle, int32_t scenePhase, ManagedRendererListDescData* rendererListDescData, MonoString* overrideMaterialPath, MonoString* shaderPassName, ManagedRenderStateBlockData* renderStateBlockData) { ManagedScriptableRenderContextState* const state = FindManagedScriptableRenderContextState(nativeHandle); if (state == nullptr || state->graphContext == nullptr || state->sceneRecorder == nullptr || !SupportsManagedScriptableRenderContextSceneRecordingStage( state->stage) || rendererListDescData == nullptr) { return 0; } Rendering::DrawSettings drawSettings = {}; drawSettings.scenePhase = static_cast(scenePhase); drawSettings.rendererListDesc = *reinterpret_cast( rendererListDescData); const std::string overrideMaterialPathUtf8 = MonoStringToUtf8(overrideMaterialPath); if (!overrideMaterialPathUtf8.empty()) { drawSettings.overrideMaterial = Resources::ResourceManager::Get().Load( overrideMaterialPathUtf8.c_str()); if (!drawSettings.overrideMaterial.IsValid()) { Debug::Logger::Get().Error( Debug::LogCategory::Rendering, (Containers::String( "ScriptableRenderContext DrawRenderers failed to load override material: ") + Containers::String(overrideMaterialPathUtf8.c_str())) .CStr()); return 0; } } const std::string shaderPassNameUtf8 = MonoStringToUtf8(shaderPassName); if (!shaderPassNameUtf8.empty()) { drawSettings.shaderPassName = Containers::String(shaderPassNameUtf8.c_str()); } if (renderStateBlockData != nullptr) { drawSettings.renderStateBlock = BuildManagedRenderStateBlock( *renderStateBlockData); } return state->sceneRecorder->RecordSceneDrawSettings( drawSettings) ? 1 : 0; } int32_t InternalCall_Rendering_CameraRenderRequestContext_GetRenderedBaseCameraCount( uint64_t nativeHandle) { const ManagedCameraRenderRequestContextState* const state = FindManagedCameraRenderRequestContextState(nativeHandle); return state != nullptr ? static_cast(state->renderedBaseCameraCount) : 0; } int32_t InternalCall_Rendering_CameraRenderRequestContext_GetRenderedRequestCount( uint64_t nativeHandle) { const ManagedCameraRenderRequestContextState* const state = FindManagedCameraRenderRequestContextState(nativeHandle); return state != nullptr ? static_cast(state->renderedRequestCount) : 0; } uint64_t InternalCall_Rendering_CameraRenderRequestContext_GetCameraGameObjectUUID( uint64_t nativeHandle) { const ManagedCameraRenderRequestContextState* const state = FindManagedCameraRenderRequestContextState(nativeHandle); if (state == nullptr || state->request == nullptr || state->request->camera == nullptr || state->request->camera->GetGameObject() == nullptr) { return 0u; } return state->request->camera->GetGameObject()->GetUUID(); } int32_t InternalCall_Rendering_CameraRenderRequestContext_GetRendererIndex( uint64_t nativeHandle) { const ManagedCameraRenderRequestContextState* const state = FindManagedCameraRenderRequestContextState(nativeHandle); return state != nullptr && state->request != nullptr ? state->request->rendererIndex : -1; } void InternalCall_Rendering_CameraRenderRequestContext_SetRendererIndex( uint64_t nativeHandle, int32_t rendererIndex) { ManagedCameraRenderRequestContextState* const state = FindManagedCameraRenderRequestContextState(nativeHandle); if (state == nullptr || state->request == nullptr) { return; } state->request->rendererIndex = rendererIndex; } mono_bool InternalCall_Rendering_CameraRenderRequestContext_GetHasDirectionalShadow( uint64_t nativeHandle) { const ManagedCameraRenderRequestContextState* const state = FindManagedCameraRenderRequestContextState(nativeHandle); return state != nullptr && state->request != nullptr && state->request->directionalShadow.IsValid() ? 1 : 0; } void InternalCall_Rendering_CameraRenderRequestContext_GetDirectionalShadowPlanningSettings( uint64_t nativeHandle, ManagedDirectionalShadowPlanningSettingsData* outSettings) { const ManagedCameraRenderRequestContextState* const state = FindManagedCameraRenderRequestContextState(nativeHandle); if (outSettings == nullptr) { return; } const Rendering::DirectionalShadowPlanningSettings sourceSettings = state != nullptr ? state->directionalShadowPlanningSettings : Rendering::DirectionalShadowPlanningSettings(); *outSettings = *reinterpret_cast( &sourceSettings); } void InternalCall_Rendering_CameraRenderRequestContext_SetDirectionalShadowPlanningSettings( uint64_t nativeHandle, ManagedDirectionalShadowPlanningSettingsData* settings) { ManagedCameraRenderRequestContextState* const state = FindManagedCameraRenderRequestContextState(nativeHandle); if (state == nullptr || settings == nullptr) { return; } state->directionalShadowPlanningSettings = *reinterpret_cast( settings); } void InternalCall_Rendering_CameraRenderRequestContext_ClearDirectionalShadow( uint64_t nativeHandle) { ManagedCameraRenderRequestContextState* const state = FindManagedCameraRenderRequestContextState(nativeHandle); if (state == nullptr || state->request == nullptr) { return; } state->request->directionalShadow = {}; state->suppressDirectionalShadow = true; } int32_t InternalCall_Rendering_CameraRenderRequestContext_GetClearFlags( uint64_t nativeHandle) { const ManagedCameraRenderRequestContextState* const state = FindManagedCameraRenderRequestContextState(nativeHandle); return state != nullptr && state->request != nullptr ? static_cast(state->request->clearFlags) : static_cast(Rendering::RenderClearFlags::All); } void InternalCall_Rendering_CameraRenderRequestContext_SetClearFlags( uint64_t nativeHandle, int32_t clearFlags) { ManagedCameraRenderRequestContextState* const state = FindManagedCameraRenderRequestContextState(nativeHandle); if (state == nullptr || state->request == nullptr) { return; } state->request->clearFlags = static_cast(clearFlags); } void InternalCall_Rendering_CameraRenderRequestContext_SetResolvedFinalColorPolicy( uint64_t nativeHandle, ManagedFinalColorSettingsData* settings, mono_bool hasPipelineDefaults, mono_bool hasCameraOverrides) { ManagedCameraRenderRequestContextState* const state = FindManagedCameraRenderRequestContextState(nativeHandle); if (state == nullptr || state->request == nullptr || settings == nullptr) { return; } const Rendering::FinalColorSettings resolvedSettings = BuildManagedFinalColorSettings(*settings); Rendering::ResolvedFinalColorPolicy resolvedPolicy = {}; resolvedPolicy.outputTransferMode = resolvedSettings.outputTransferMode; resolvedPolicy.exposureMode = resolvedSettings.exposureMode; resolvedPolicy.exposureValue = resolvedSettings.exposureValue; resolvedPolicy.toneMappingMode = resolvedSettings.toneMappingMode; resolvedPolicy.finalColorScale = resolvedSettings.finalColorScale; resolvedPolicy.hasPipelineDefaults = hasPipelineDefaults != 0; resolvedPolicy.hasCameraOverrides = hasCameraOverrides != 0; state->request->finalColorPolicy = resolvedPolicy; } void InternalCall_Rendering_CameraRenderRequestContext_ClearFinalColorPolicy( uint64_t nativeHandle) { ManagedCameraRenderRequestContextState* const state = FindManagedCameraRenderRequestContextState(nativeHandle); if (state == nullptr || state->request == nullptr) { return; } state->request->finalColorPolicy = {}; } int32_t InternalCall_Rendering_RenderSceneSetupContext_GetRendererIndex( uint64_t nativeHandle) { const ManagedRenderSceneSetupContextState* const state = FindManagedRenderSceneSetupContextState(nativeHandle); return state != nullptr && state->plan != nullptr ? state->plan->request.rendererIndex : -1; } uint64_t InternalCall_Rendering_RenderSceneSetupContext_GetCameraGameObjectUUID( uint64_t nativeHandle) { const ManagedRenderSceneSetupContextState* const state = FindManagedRenderSceneSetupContextState(nativeHandle); if (state == nullptr || state->plan == nullptr || state->plan->request.camera == nullptr || state->plan->request.camera->GetGameObject() == nullptr) { return 0u; } return state->plan->request.camera->GetGameObject()->GetUUID(); } mono_bool InternalCall_Rendering_RenderSceneSetupContext_GetIsConfigured( uint64_t nativeHandle) { const ManagedRenderSceneSetupContextState* const state = FindManagedRenderSceneSetupContextState(nativeHandle); return state != nullptr && state->explicitlyConfigured ? 1 : 0; } int32_t InternalCall_Rendering_RenderSceneSetupContext_GetClearFlags( uint64_t nativeHandle) { const ManagedRenderSceneSetupContextState* const state = FindManagedRenderSceneSetupContextState(nativeHandle); return state != nullptr && state->plan != nullptr ? static_cast(state->plan->request.clearFlags) : 0; } mono_bool InternalCall_Rendering_RenderSceneSetupContext_GetHasMainSceneDepthAttachment( uint64_t nativeHandle) { const ManagedRenderSceneSetupContextState* const state = FindManagedRenderSceneSetupContextState(nativeHandle); return state != nullptr && state->plan != nullptr && state->plan->GetMainSceneSurface().GetDepthAttachment() != nullptr ? 1 : 0; } mono_bool InternalCall_Rendering_RenderSceneSetupContext_GetHasMainDirectionalShadow( uint64_t nativeHandle) { const ManagedRenderSceneSetupContextState* const state = FindManagedRenderSceneSetupContextState(nativeHandle); return state != nullptr && state->sceneData != nullptr && state->sceneData->lighting.HasMainDirectionalShadow() ? 1 : 0; } void InternalCall_Rendering_RenderSceneSetupContext_SetEnvironmentNone( uint64_t nativeHandle) { ManagedRenderSceneSetupContextState* const state = FindManagedRenderSceneSetupContextState(nativeHandle); if (state == nullptr || state->sceneData == nullptr) { return; } state->sceneData->environment = {}; state->explicitlyConfigured = true; } mono_bool InternalCall_Rendering_RenderSceneSetupContext_UseCameraSkyboxMaterial( uint64_t nativeHandle) { ManagedRenderSceneSetupContextState* const state = FindManagedRenderSceneSetupContextState(nativeHandle); if (state == nullptr || state->plan == nullptr || state->sceneData == nullptr || state->plan->request.camera == nullptr) { return 0; } const Resources::Material* skyboxMaterial = state->plan->request.camera->GetSkyboxMaterial(); if (skyboxMaterial == nullptr) { return 0; } state->sceneData->environment = {}; state->sceneData->environment.mode = Rendering::RenderEnvironmentMode::MaterialSkybox; state->sceneData->environment.materialSkybox.material = skyboxMaterial; state->explicitlyConfigured = true; return 1; } void InternalCall_Rendering_RenderSceneSetupContext_SetProceduralSkybox( uint64_t nativeHandle, XCEngine::Math::Color* topColor, XCEngine::Math::Color* horizonColor, XCEngine::Math::Color* bottomColor) { ManagedRenderSceneSetupContextState* const state = FindManagedRenderSceneSetupContextState(nativeHandle); if (state == nullptr || state->sceneData == nullptr) { return; } state->sceneData->environment = {}; state->sceneData->environment.mode = Rendering::RenderEnvironmentMode::ProceduralSkybox; state->sceneData->environment.skybox.topColor = topColor != nullptr ? *topColor : XCEngine::Math::Color(); state->sceneData->environment.skybox.horizonColor = horizonColor != nullptr ? *horizonColor : XCEngine::Math::Color(); state->sceneData->environment.skybox.bottomColor = bottomColor != nullptr ? *bottomColor : XCEngine::Math::Color(); state->explicitlyConfigured = true; } void InternalCall_Rendering_RenderSceneSetupContext_ClearGlobalShaderKeywords( uint64_t nativeHandle) { ManagedRenderSceneSetupContextState* const state = FindManagedRenderSceneSetupContextState(nativeHandle); if (state == nullptr || state->sceneData == nullptr) { return; } state->sceneData->globalShaderKeywords = {}; state->explicitlyConfigured = true; } void InternalCall_Rendering_RenderSceneSetupContext_SetGlobalShaderKeyword( uint64_t nativeHandle, MonoString* keyword, mono_bool enabled) { ManagedRenderSceneSetupContextState* const state = FindManagedRenderSceneSetupContextState(nativeHandle); if (state == nullptr || state->sceneData == nullptr) { return; } const XCEngine::Containers::String normalizedKeyword = Resources::NormalizeShaderKeywordToken( XCEngine::Containers::String( MonoStringToUtf8(keyword).c_str())); if (normalizedKeyword.Empty()) { state->explicitlyConfigured = true; return; } Resources::ShaderKeywordSet& keywordSet = state->sceneData->globalShaderKeywords; bool foundKeyword = false; size_t foundIndex = 0; for (size_t keywordIndex = 0; keywordIndex < keywordSet.enabledKeywords.Size(); ++keywordIndex) { if (keywordSet.enabledKeywords[keywordIndex] == normalizedKeyword) { foundKeyword = true; foundIndex = keywordIndex; break; } } if (enabled != 0) { if (!foundKeyword) { keywordSet.enabledKeywords.PushBack(normalizedKeyword); } } else if (foundKeyword) { const size_t lastIndex = keywordSet.enabledKeywords.Size() - 1; if (foundIndex != lastIndex) { keywordSet.enabledKeywords[foundIndex] = keywordSet.enabledKeywords[lastIndex]; } keywordSet.enabledKeywords.PopBack(); } Resources::NormalizeShaderKeywordSetInPlace(keywordSet); state->explicitlyConfigured = true; } mono_bool InternalCall_Rendering_DirectionalShadowExecutionContext_GetHasPlannedMainDirectionalShadow( uint64_t nativeHandle) { const ManagedDirectionalShadowExecutionContextState* const state = FindManagedDirectionalShadowExecutionContextState( nativeHandle); return state != nullptr && state->plan != nullptr && state->plan->directionalShadow.IsValid() ? 1 : 0; } int32_t InternalCall_Rendering_DirectionalShadowExecutionContext_GetRendererIndex( uint64_t nativeHandle) { const ManagedDirectionalShadowExecutionContextState* const state = FindManagedDirectionalShadowExecutionContextState( nativeHandle); return state != nullptr && state->plan != nullptr ? state->plan->request.rendererIndex : -1; } mono_bool InternalCall_Rendering_DirectionalShadowExecutionContext_GetIsConfigured( uint64_t nativeHandle) { const ManagedDirectionalShadowExecutionContextState* const state = FindManagedDirectionalShadowExecutionContextState( nativeHandle); return state != nullptr && state->explicitlyConfigured ? 1 : 0; } mono_bool InternalCall_Rendering_DirectionalShadowExecutionContext_UseDefaultMainDirectionalShadowExecution( uint64_t nativeHandle) { ManagedDirectionalShadowExecutionContextState* const state = FindManagedDirectionalShadowExecutionContextState( nativeHandle); if (state == nullptr || state->plan == nullptr || state->shadowAllocation == nullptr || state->shadowState == nullptr) { return 0; } Rendering::ApplyDefaultRenderPipelineDirectionalShadowExecutionPolicy( *state->plan, *state->shadowAllocation, *state->shadowState); state->explicitlyConfigured = true; return state->shadowState->shadowCasterRequest.IsValid() && state->shadowState->shadowData.IsValid() ? 1 : 0; } void InternalCall_Rendering_DirectionalShadowExecutionContext_ClearDirectionalShadowExecution( uint64_t nativeHandle) { ManagedDirectionalShadowExecutionContextState* const state = FindManagedDirectionalShadowExecutionContextState( nativeHandle); if (state == nullptr || state->shadowState == nullptr) { return; } *state->shadowState = {}; state->explicitlyConfigured = true; } int32_t InternalCall_Rendering_ScriptableRenderPipelinePlanningContext_GetRendererIndex( uint64_t nativeHandle) { const ManagedScriptableRenderPipelinePlanningContextState* const state = FindManagedScriptableRenderPipelinePlanningContextState(nativeHandle); return state != nullptr && state->plan != nullptr ? state->plan->request.rendererIndex : -1; } mono_bool InternalCall_Rendering_ScriptableRenderPipelinePlanningContext_IsStageRequested( uint64_t nativeHandle, int32_t stage) { const ManagedScriptableRenderPipelinePlanningContextState* const state = FindManagedScriptableRenderPipelinePlanningContextState(nativeHandle); if (state == nullptr || state->plan == nullptr) { return 0; } Rendering::CameraFrameStage resolvedStage = Rendering::CameraFrameStage::MainScene; if (!TryResolveManagedCameraFrameStage(stage, resolvedStage)) { return 0; } return state->plan->HasFrameStage(resolvedStage) ? 1 : 0; } int32_t InternalCall_Rendering_ScriptableRenderPipelinePlanningContext_GetStageColorSource( uint64_t nativeHandle, int32_t stage) { const ManagedScriptableRenderPipelinePlanningContextState* const state = FindManagedScriptableRenderPipelinePlanningContextState(nativeHandle); if (state == nullptr || state->plan == nullptr) { return static_cast( Rendering::CameraFrameColorSource::ExplicitSurface); } Rendering::CameraFrameStage resolvedStage = Rendering::CameraFrameStage::MainScene; if (!TryResolveManagedCameraFrameStage(stage, resolvedStage)) { return static_cast( Rendering::CameraFrameColorSource::ExplicitSurface); } return static_cast( state->plan->ResolveStageColorSource(resolvedStage)); } mono_bool InternalCall_Rendering_ScriptableRenderPipelinePlanningContext_GetStageUsesGraphManagedOutputColor( uint64_t nativeHandle, int32_t stage) { const ManagedScriptableRenderPipelinePlanningContextState* const state = FindManagedScriptableRenderPipelinePlanningContextState(nativeHandle); if (state == nullptr || state->plan == nullptr) { return 0; } Rendering::CameraFrameStage resolvedStage = Rendering::CameraFrameStage::MainScene; if (!TryResolveManagedCameraFrameStage(stage, resolvedStage)) { return 0; } return state->plan->UsesGraphManagedOutputColor(resolvedStage) ? 1 : 0; } mono_bool InternalCall_Rendering_ScriptableRenderPipelinePlanningContext_RequestFullscreenStage( uint64_t nativeHandle, int32_t stage, int32_t source, mono_bool usesGraphManagedOutputColor) { ManagedScriptableRenderPipelinePlanningContextState* const state = FindManagedScriptableRenderPipelinePlanningContextState(nativeHandle); if (state == nullptr || state->plan == nullptr) { return 0; } Rendering::CameraFrameStage resolvedStage = Rendering::CameraFrameStage::MainScene; if (!TryResolveManagedCameraFrameStage(stage, resolvedStage)) { return 0; } const Rendering::CameraFrameColorSource resolvedSource = static_cast(source); return state->plan->RequestFullscreenStage( resolvedStage, resolvedSource, usesGraphManagedOutputColor != 0, true) ? 1 : 0; } void InternalCall_Rendering_ScriptableRenderPipelinePlanningContext_ClearFullscreenStage( uint64_t nativeHandle, int32_t stage) { ManagedScriptableRenderPipelinePlanningContextState* const state = FindManagedScriptableRenderPipelinePlanningContextState(nativeHandle); if (state == nullptr || state->plan == nullptr) { return; } Rendering::CameraFrameStage resolvedStage = Rendering::CameraFrameStage::MainScene; if (!TryResolveManagedCameraFrameStage(stage, resolvedStage)) { return; } state->plan->ClearFullscreenStage(resolvedStage, true); } mono_bool InternalCall_Rendering_ScriptableRenderPipelinePlanningContext_RequestShadowCasterStage( uint64_t nativeHandle) { ManagedScriptableRenderPipelinePlanningContextState* const state = FindManagedScriptableRenderPipelinePlanningContextState(nativeHandle); return state != nullptr && state->plan != nullptr && state->plan->RequestShadowCasterStage(true) ? 1 : 0; } void InternalCall_Rendering_ScriptableRenderPipelinePlanningContext_ClearShadowCasterStage( uint64_t nativeHandle) { ManagedScriptableRenderPipelinePlanningContextState* const state = FindManagedScriptableRenderPipelinePlanningContextState(nativeHandle); if (state == nullptr || state->plan == nullptr) { return; } state->plan->ClearShadowCasterStage(true); } mono_bool InternalCall_Rendering_ScriptableRenderPipelinePlanningContext_GetHasExplicitShadowCasterStageConfiguration( uint64_t nativeHandle) { const ManagedScriptableRenderPipelinePlanningContextState* const state = FindManagedScriptableRenderPipelinePlanningContextState(nativeHandle); return state != nullptr && state->plan != nullptr && state->plan->HasExplicitShadowCasterStageConfiguration() ? 1 : 0; } mono_bool InternalCall_Rendering_ScriptableRenderPipelinePlanningContext_RequestDepthOnlyStage( uint64_t nativeHandle) { ManagedScriptableRenderPipelinePlanningContextState* const state = FindManagedScriptableRenderPipelinePlanningContextState(nativeHandle); return state != nullptr && state->plan != nullptr && state->plan->RequestDepthOnlyStage(true) ? 1 : 0; } mono_bool InternalCall_Rendering_ScriptableRenderPipelinePlanningContext_RequestCameraDepthOnlyStage( uint64_t nativeHandle) { ManagedScriptableRenderPipelinePlanningContextState* const state = FindManagedScriptableRenderPipelinePlanningContextState(nativeHandle); if (state == nullptr || state->plan == nullptr) { return 0; } Rendering::DepthOnlyRenderRequest& depthOnlyRequest = state->plan->request.depthOnly; depthOnlyRequest = {}; depthOnlyRequest.surface = Rendering::CameraFramePlan::BuildCameraDepthOnlySurfaceTemplate( state->plan->request.surface); depthOnlyRequest.clearFlags = Rendering::RenderClearFlags::Depth; if (!depthOnlyRequest.IsValid()) { depthOnlyRequest = {}; state->plan->ClearDepthOnlyStage(true); return 0; } return state->plan->RequestDepthOnlyStage(true) ? 1 : 0; } void InternalCall_Rendering_ScriptableRenderPipelinePlanningContext_ClearDepthOnlyStage( uint64_t nativeHandle) { ManagedScriptableRenderPipelinePlanningContextState* const state = FindManagedScriptableRenderPipelinePlanningContextState(nativeHandle); if (state == nullptr || state->plan == nullptr) { return; } state->plan->ClearDepthOnlyStage(true); } mono_bool InternalCall_Rendering_ScriptableRenderPipelinePlanningContext_GetHasExplicitDepthOnlyStageConfiguration( uint64_t nativeHandle) { const ManagedScriptableRenderPipelinePlanningContextState* const state = FindManagedScriptableRenderPipelinePlanningContextState(nativeHandle); return state != nullptr && state->plan != nullptr && state->plan->HasExplicitDepthOnlyStageConfiguration() ? 1 : 0; } mono_bool InternalCall_Rendering_ScriptableRenderPipelinePlanningContext_GetHasFinalColorProcessing( uint64_t nativeHandle) { const ManagedScriptableRenderPipelinePlanningContextState* const state = FindManagedScriptableRenderPipelinePlanningContextState(nativeHandle); return state != nullptr && state->plan != nullptr && state->plan->finalColorPolicy.RequiresProcessing() ? 1 : 0; } void RegisterInternalCalls() { if (GetInternalCallRegistrationState()) { return; } mono_add_internal_call("XCEngine.InternalCalls::Debug_Log", reinterpret_cast(&InternalCall_Debug_Log)); mono_add_internal_call("XCEngine.InternalCalls::Debug_LogWarning", reinterpret_cast(&InternalCall_Debug_LogWarning)); mono_add_internal_call("XCEngine.InternalCalls::Debug_LogError", reinterpret_cast(&InternalCall_Debug_LogError)); mono_add_internal_call("XCEngine.InternalCalls::Time_GetDeltaTime", reinterpret_cast(&InternalCall_Time_GetDeltaTime)); mono_add_internal_call("XCEngine.InternalCalls::Time_GetFixedDeltaTime", reinterpret_cast(&InternalCall_Time_GetFixedDeltaTime)); mono_add_internal_call("XCEngine.InternalCalls::Input_GetKey", reinterpret_cast(&InternalCall_Input_GetKey)); mono_add_internal_call("XCEngine.InternalCalls::Input_GetKeyDown", reinterpret_cast(&InternalCall_Input_GetKeyDown)); mono_add_internal_call("XCEngine.InternalCalls::Input_GetKeyUp", reinterpret_cast(&InternalCall_Input_GetKeyUp)); mono_add_internal_call("XCEngine.InternalCalls::Input_GetMouseButton", reinterpret_cast(&InternalCall_Input_GetMouseButton)); mono_add_internal_call("XCEngine.InternalCalls::Input_GetMouseButtonDown", reinterpret_cast(&InternalCall_Input_GetMouseButtonDown)); mono_add_internal_call("XCEngine.InternalCalls::Input_GetMouseButtonUp", reinterpret_cast(&InternalCall_Input_GetMouseButtonUp)); mono_add_internal_call("XCEngine.InternalCalls::Input_GetButton", reinterpret_cast(&InternalCall_Input_GetButton)); mono_add_internal_call("XCEngine.InternalCalls::Input_GetButtonDown", reinterpret_cast(&InternalCall_Input_GetButtonDown)); mono_add_internal_call("XCEngine.InternalCalls::Input_GetButtonUp", reinterpret_cast(&InternalCall_Input_GetButtonUp)); mono_add_internal_call("XCEngine.InternalCalls::Input_GetAxis", reinterpret_cast(&InternalCall_Input_GetAxis)); mono_add_internal_call("XCEngine.InternalCalls::Input_GetAxisRaw", reinterpret_cast(&InternalCall_Input_GetAxisRaw)); mono_add_internal_call("XCEngine.InternalCalls::Input_GetAnyKey", reinterpret_cast(&InternalCall_Input_GetAnyKey)); mono_add_internal_call("XCEngine.InternalCalls::Input_GetAnyKeyDown", reinterpret_cast(&InternalCall_Input_GetAnyKeyDown)); mono_add_internal_call("XCEngine.InternalCalls::Input_GetMousePosition", reinterpret_cast(&InternalCall_Input_GetMousePosition)); mono_add_internal_call("XCEngine.InternalCalls::Input_GetMouseScrollDelta", reinterpret_cast(&InternalCall_Input_GetMouseScrollDelta)); mono_add_internal_call("XCEngine.InternalCalls::GameObject_GetName", reinterpret_cast(&InternalCall_GameObject_GetName)); mono_add_internal_call("XCEngine.InternalCalls::GameObject_SetName", reinterpret_cast(&InternalCall_GameObject_SetName)); mono_add_internal_call("XCEngine.InternalCalls::GameObject_GetTag", reinterpret_cast(&InternalCall_GameObject_GetTag)); mono_add_internal_call("XCEngine.InternalCalls::GameObject_SetTag", reinterpret_cast(&InternalCall_GameObject_SetTag)); mono_add_internal_call("XCEngine.InternalCalls::GameObject_CompareTag", reinterpret_cast(&InternalCall_GameObject_CompareTag)); mono_add_internal_call("XCEngine.InternalCalls::GameObject_GetLayer", reinterpret_cast(&InternalCall_GameObject_GetLayer)); mono_add_internal_call("XCEngine.InternalCalls::GameObject_SetLayer", reinterpret_cast(&InternalCall_GameObject_SetLayer)); mono_add_internal_call("XCEngine.InternalCalls::GameObject_GetActiveSelf", reinterpret_cast(&InternalCall_GameObject_GetActiveSelf)); mono_add_internal_call("XCEngine.InternalCalls::GameObject_GetActiveInHierarchy", reinterpret_cast(&InternalCall_GameObject_GetActiveInHierarchy)); mono_add_internal_call("XCEngine.InternalCalls::GameObject_SetActive", reinterpret_cast(&InternalCall_GameObject_SetActive)); mono_add_internal_call("XCEngine.InternalCalls::GameObject_HasComponent", reinterpret_cast(&InternalCall_GameObject_HasComponent)); mono_add_internal_call("XCEngine.InternalCalls::GameObject_GetComponent", reinterpret_cast(&InternalCall_GameObject_GetComponent)); mono_add_internal_call("XCEngine.InternalCalls::GameObject_GetComponents", reinterpret_cast(&InternalCall_GameObject_GetComponents)); mono_add_internal_call("XCEngine.InternalCalls::GameObject_GetComponentInChildren", reinterpret_cast(&InternalCall_GameObject_GetComponentInChildren)); mono_add_internal_call("XCEngine.InternalCalls::GameObject_GetComponentInParent", reinterpret_cast(&InternalCall_GameObject_GetComponentInParent)); mono_add_internal_call("XCEngine.InternalCalls::GameObject_AddComponent", reinterpret_cast(&InternalCall_GameObject_AddComponent)); mono_add_internal_call("XCEngine.InternalCalls::GameObject_Find", reinterpret_cast(&InternalCall_GameObject_Find)); mono_add_internal_call("XCEngine.InternalCalls::GameObject_Create", reinterpret_cast(&InternalCall_GameObject_Create)); mono_add_internal_call("XCEngine.InternalCalls::GameObject_Destroy", reinterpret_cast(&InternalCall_GameObject_Destroy)); mono_add_internal_call("XCEngine.InternalCalls::Object_Destroy", reinterpret_cast(&InternalCall_Object_Destroy)); mono_add_internal_call("XCEngine.InternalCalls::Behaviour_GetEnabled", reinterpret_cast(&InternalCall_Behaviour_GetEnabled)); mono_add_internal_call("XCEngine.InternalCalls::Behaviour_SetEnabled", reinterpret_cast(&InternalCall_Behaviour_SetEnabled)); mono_add_internal_call("XCEngine.InternalCalls::Transform_GetLocalPosition", reinterpret_cast(&InternalCall_Transform_GetLocalPosition)); mono_add_internal_call("XCEngine.InternalCalls::Transform_SetLocalPosition", reinterpret_cast(&InternalCall_Transform_SetLocalPosition)); mono_add_internal_call("XCEngine.InternalCalls::Transform_GetLocalRotation", reinterpret_cast(&InternalCall_Transform_GetLocalRotation)); mono_add_internal_call("XCEngine.InternalCalls::Transform_SetLocalRotation", reinterpret_cast(&InternalCall_Transform_SetLocalRotation)); mono_add_internal_call("XCEngine.InternalCalls::Transform_GetLocalScale", reinterpret_cast(&InternalCall_Transform_GetLocalScale)); mono_add_internal_call("XCEngine.InternalCalls::Transform_SetLocalScale", reinterpret_cast(&InternalCall_Transform_SetLocalScale)); mono_add_internal_call("XCEngine.InternalCalls::Transform_GetLocalEulerAngles", reinterpret_cast(&InternalCall_Transform_GetLocalEulerAngles)); mono_add_internal_call("XCEngine.InternalCalls::Transform_SetLocalEulerAngles", reinterpret_cast(&InternalCall_Transform_SetLocalEulerAngles)); mono_add_internal_call("XCEngine.InternalCalls::Transform_GetPosition", reinterpret_cast(&InternalCall_Transform_GetPosition)); mono_add_internal_call("XCEngine.InternalCalls::Transform_SetPosition", reinterpret_cast(&InternalCall_Transform_SetPosition)); mono_add_internal_call("XCEngine.InternalCalls::Transform_GetRotation", reinterpret_cast(&InternalCall_Transform_GetRotation)); mono_add_internal_call("XCEngine.InternalCalls::Transform_SetRotation", reinterpret_cast(&InternalCall_Transform_SetRotation)); mono_add_internal_call("XCEngine.InternalCalls::Transform_GetScale", reinterpret_cast(&InternalCall_Transform_GetScale)); mono_add_internal_call("XCEngine.InternalCalls::Transform_SetScale", reinterpret_cast(&InternalCall_Transform_SetScale)); mono_add_internal_call("XCEngine.InternalCalls::Transform_GetForward", reinterpret_cast(&InternalCall_Transform_GetForward)); mono_add_internal_call("XCEngine.InternalCalls::Transform_GetRight", reinterpret_cast(&InternalCall_Transform_GetRight)); mono_add_internal_call("XCEngine.InternalCalls::Transform_GetUp", reinterpret_cast(&InternalCall_Transform_GetUp)); mono_add_internal_call("XCEngine.InternalCalls::Transform_Translate", reinterpret_cast(&InternalCall_Transform_Translate)); mono_add_internal_call("XCEngine.InternalCalls::Transform_Rotate", reinterpret_cast(&InternalCall_Transform_Rotate)); mono_add_internal_call("XCEngine.InternalCalls::Transform_RotateAxisAngle", reinterpret_cast(&InternalCall_Transform_RotateAxisAngle)); mono_add_internal_call("XCEngine.InternalCalls::Transform_LookAt", reinterpret_cast(&InternalCall_Transform_LookAt)); mono_add_internal_call("XCEngine.InternalCalls::Transform_LookAtWithUp", reinterpret_cast(&InternalCall_Transform_LookAtWithUp)); mono_add_internal_call("XCEngine.InternalCalls::Transform_TransformPoint", reinterpret_cast(&InternalCall_Transform_TransformPoint)); mono_add_internal_call("XCEngine.InternalCalls::Transform_InverseTransformPoint", reinterpret_cast(&InternalCall_Transform_InverseTransformPoint)); mono_add_internal_call("XCEngine.InternalCalls::Transform_TransformDirection", reinterpret_cast(&InternalCall_Transform_TransformDirection)); mono_add_internal_call("XCEngine.InternalCalls::Transform_InverseTransformDirection", reinterpret_cast(&InternalCall_Transform_InverseTransformDirection)); mono_add_internal_call("XCEngine.InternalCalls::Transform_GetParent", reinterpret_cast(&InternalCall_Transform_GetParent)); mono_add_internal_call("XCEngine.InternalCalls::Transform_SetParent", reinterpret_cast(&InternalCall_Transform_SetParent)); mono_add_internal_call("XCEngine.InternalCalls::Transform_GetChildCount", reinterpret_cast(&InternalCall_Transform_GetChildCount)); mono_add_internal_call("XCEngine.InternalCalls::Transform_GetChild", reinterpret_cast(&InternalCall_Transform_GetChild)); mono_add_internal_call("XCEngine.InternalCalls::Camera_GetFieldOfView", reinterpret_cast(&InternalCall_Camera_GetFieldOfView)); mono_add_internal_call("XCEngine.InternalCalls::Camera_SetFieldOfView", reinterpret_cast(&InternalCall_Camera_SetFieldOfView)); mono_add_internal_call("XCEngine.InternalCalls::Camera_GetNearClipPlane", reinterpret_cast(&InternalCall_Camera_GetNearClipPlane)); mono_add_internal_call("XCEngine.InternalCalls::Camera_SetNearClipPlane", reinterpret_cast(&InternalCall_Camera_SetNearClipPlane)); mono_add_internal_call("XCEngine.InternalCalls::Camera_GetFarClipPlane", reinterpret_cast(&InternalCall_Camera_GetFarClipPlane)); mono_add_internal_call("XCEngine.InternalCalls::Camera_SetFarClipPlane", reinterpret_cast(&InternalCall_Camera_SetFarClipPlane)); mono_add_internal_call("XCEngine.InternalCalls::Camera_GetDepth", reinterpret_cast(&InternalCall_Camera_GetDepth)); mono_add_internal_call("XCEngine.InternalCalls::Camera_SetDepth", reinterpret_cast(&InternalCall_Camera_SetDepth)); mono_add_internal_call("XCEngine.InternalCalls::Camera_GetPrimary", reinterpret_cast(&InternalCall_Camera_GetPrimary)); mono_add_internal_call("XCEngine.InternalCalls::Camera_SetPrimary", reinterpret_cast(&InternalCall_Camera_SetPrimary)); mono_add_internal_call("XCEngine.InternalCalls::Camera_GetClearMode", reinterpret_cast(&InternalCall_Camera_GetClearMode)); mono_add_internal_call("XCEngine.InternalCalls::Camera_SetClearMode", reinterpret_cast(&InternalCall_Camera_SetClearMode)); mono_add_internal_call("XCEngine.InternalCalls::Camera_GetStackType", reinterpret_cast(&InternalCall_Camera_GetStackType)); mono_add_internal_call("XCEngine.InternalCalls::Camera_SetStackType", reinterpret_cast(&InternalCall_Camera_SetStackType)); mono_add_internal_call("XCEngine.InternalCalls::Camera_GetProjectionType", reinterpret_cast(&InternalCall_Camera_GetProjectionType)); mono_add_internal_call("XCEngine.InternalCalls::Camera_GetSkyboxEnabled", reinterpret_cast(&InternalCall_Camera_GetSkyboxEnabled)); mono_add_internal_call("XCEngine.InternalCalls::Camera_GetHasSkyboxMaterial", reinterpret_cast(&InternalCall_Camera_GetHasSkyboxMaterial)); mono_add_internal_call("XCEngine.InternalCalls::Camera_GetHasFinalColorOverrides", reinterpret_cast(&InternalCall_Camera_GetHasFinalColorOverrides)); mono_add_internal_call("XCEngine.InternalCalls::Camera_GetFinalColorOverrideSettings", reinterpret_cast(&InternalCall_Camera_GetFinalColorOverrideSettings)); mono_add_internal_call("XCEngine.InternalCalls::Camera_GetSkyboxTopColor", reinterpret_cast(&InternalCall_Camera_GetSkyboxTopColor)); mono_add_internal_call("XCEngine.InternalCalls::Camera_GetSkyboxHorizonColor", reinterpret_cast(&InternalCall_Camera_GetSkyboxHorizonColor)); mono_add_internal_call("XCEngine.InternalCalls::Camera_GetSkyboxBottomColor", reinterpret_cast(&InternalCall_Camera_GetSkyboxBottomColor)); mono_add_internal_call("XCEngine.InternalCalls::Light_GetIntensity", reinterpret_cast(&InternalCall_Light_GetIntensity)); mono_add_internal_call("XCEngine.InternalCalls::Light_SetIntensity", reinterpret_cast(&InternalCall_Light_SetIntensity)); mono_add_internal_call("XCEngine.InternalCalls::Light_GetRange", reinterpret_cast(&InternalCall_Light_GetRange)); mono_add_internal_call("XCEngine.InternalCalls::Light_SetRange", reinterpret_cast(&InternalCall_Light_SetRange)); mono_add_internal_call("XCEngine.InternalCalls::Light_GetSpotAngle", reinterpret_cast(&InternalCall_Light_GetSpotAngle)); mono_add_internal_call("XCEngine.InternalCalls::Light_SetSpotAngle", reinterpret_cast(&InternalCall_Light_SetSpotAngle)); mono_add_internal_call("XCEngine.InternalCalls::Light_GetCastsShadows", reinterpret_cast(&InternalCall_Light_GetCastsShadows)); mono_add_internal_call("XCEngine.InternalCalls::Light_SetCastsShadows", reinterpret_cast(&InternalCall_Light_SetCastsShadows)); mono_add_internal_call("XCEngine.InternalCalls::MeshFilter_GetMeshPath", reinterpret_cast(&InternalCall_MeshFilter_GetMeshPath)); mono_add_internal_call("XCEngine.InternalCalls::MeshFilter_SetMeshPath", reinterpret_cast(&InternalCall_MeshFilter_SetMeshPath)); mono_add_internal_call("XCEngine.InternalCalls::MeshRenderer_GetMaterialCount", reinterpret_cast(&InternalCall_MeshRenderer_GetMaterialCount)); mono_add_internal_call("XCEngine.InternalCalls::MeshRenderer_GetMaterialPath", reinterpret_cast(&InternalCall_MeshRenderer_GetMaterialPath)); mono_add_internal_call("XCEngine.InternalCalls::MeshRenderer_SetMaterialPath", reinterpret_cast(&InternalCall_MeshRenderer_SetMaterialPath)); mono_add_internal_call("XCEngine.InternalCalls::MeshRenderer_ClearMaterials", reinterpret_cast(&InternalCall_MeshRenderer_ClearMaterials)); mono_add_internal_call("XCEngine.InternalCalls::MeshRenderer_GetCastShadows", reinterpret_cast(&InternalCall_MeshRenderer_GetCastShadows)); mono_add_internal_call("XCEngine.InternalCalls::MeshRenderer_SetCastShadows", reinterpret_cast(&InternalCall_MeshRenderer_SetCastShadows)); mono_add_internal_call("XCEngine.InternalCalls::MeshRenderer_GetReceiveShadows", reinterpret_cast(&InternalCall_MeshRenderer_GetReceiveShadows)); mono_add_internal_call("XCEngine.InternalCalls::MeshRenderer_SetReceiveShadows", reinterpret_cast(&InternalCall_MeshRenderer_SetReceiveShadows)); mono_add_internal_call("XCEngine.InternalCalls::MeshRenderer_GetRenderLayer", reinterpret_cast(&InternalCall_MeshRenderer_GetRenderLayer)); mono_add_internal_call("XCEngine.InternalCalls::MeshRenderer_SetRenderLayer", reinterpret_cast(&InternalCall_MeshRenderer_SetRenderLayer)); mono_add_internal_call("XCEngine.InternalCalls::Rigidbody_GetBodyType", reinterpret_cast(&InternalCall_Rigidbody_GetBodyType)); mono_add_internal_call("XCEngine.InternalCalls::Rigidbody_SetBodyType", reinterpret_cast(&InternalCall_Rigidbody_SetBodyType)); mono_add_internal_call("XCEngine.InternalCalls::Rigidbody_GetMass", reinterpret_cast(&InternalCall_Rigidbody_GetMass)); mono_add_internal_call("XCEngine.InternalCalls::Rigidbody_SetMass", reinterpret_cast(&InternalCall_Rigidbody_SetMass)); mono_add_internal_call("XCEngine.InternalCalls::Rigidbody_GetLinearDamping", reinterpret_cast(&InternalCall_Rigidbody_GetLinearDamping)); mono_add_internal_call("XCEngine.InternalCalls::Rigidbody_SetLinearDamping", reinterpret_cast(&InternalCall_Rigidbody_SetLinearDamping)); mono_add_internal_call("XCEngine.InternalCalls::Rigidbody_GetAngularDamping", reinterpret_cast(&InternalCall_Rigidbody_GetAngularDamping)); mono_add_internal_call("XCEngine.InternalCalls::Rigidbody_SetAngularDamping", reinterpret_cast(&InternalCall_Rigidbody_SetAngularDamping)); mono_add_internal_call("XCEngine.InternalCalls::Rigidbody_GetLinearVelocity", reinterpret_cast(&InternalCall_Rigidbody_GetLinearVelocity)); mono_add_internal_call("XCEngine.InternalCalls::Rigidbody_SetLinearVelocity", reinterpret_cast(&InternalCall_Rigidbody_SetLinearVelocity)); mono_add_internal_call("XCEngine.InternalCalls::Rigidbody_GetAngularVelocity", reinterpret_cast(&InternalCall_Rigidbody_GetAngularVelocity)); mono_add_internal_call("XCEngine.InternalCalls::Rigidbody_SetAngularVelocity", reinterpret_cast(&InternalCall_Rigidbody_SetAngularVelocity)); mono_add_internal_call("XCEngine.InternalCalls::Rigidbody_GetUseGravity", reinterpret_cast(&InternalCall_Rigidbody_GetUseGravity)); mono_add_internal_call("XCEngine.InternalCalls::Rigidbody_SetUseGravity", reinterpret_cast(&InternalCall_Rigidbody_SetUseGravity)); mono_add_internal_call("XCEngine.InternalCalls::Rigidbody_GetEnableCCD", reinterpret_cast(&InternalCall_Rigidbody_GetEnableCCD)); mono_add_internal_call("XCEngine.InternalCalls::Rigidbody_SetEnableCCD", reinterpret_cast(&InternalCall_Rigidbody_SetEnableCCD)); mono_add_internal_call("XCEngine.InternalCalls::Rigidbody_AddForce", reinterpret_cast(&InternalCall_Rigidbody_AddForce)); mono_add_internal_call("XCEngine.InternalCalls::Rigidbody_ClearForces", reinterpret_cast(&InternalCall_Rigidbody_ClearForces)); mono_add_internal_call("XCEngine.InternalCalls::Physics_Raycast", reinterpret_cast(&InternalCall_Physics_Raycast)); mono_add_internal_call("XCEngine.InternalCalls::Rendering_SetRenderPipelineAsset", reinterpret_cast(&InternalCall_Rendering_SetRenderPipelineAsset)); mono_add_internal_call("XCEngine.InternalCalls::Rendering_GetRenderPipelineAsset", reinterpret_cast(&InternalCall_Rendering_GetRenderPipelineAsset)); mono_add_internal_call("XCEngine.InternalCalls::Rendering_ScriptableRenderContext_GetStage", reinterpret_cast(&InternalCall_Rendering_ScriptableRenderContext_GetStage)); mono_add_internal_call("XCEngine.InternalCalls::Rendering_ScriptableRenderContext_GetRendererIndex", reinterpret_cast(&InternalCall_Rendering_ScriptableRenderContext_GetRendererIndex)); mono_add_internal_call("XCEngine.InternalCalls::Rendering_ScriptableRenderContext_GetSourceColorTextureHandle", reinterpret_cast(&InternalCall_Rendering_ScriptableRenderContext_GetSourceColorTextureHandle)); mono_add_internal_call("XCEngine.InternalCalls::Rendering_ScriptableRenderContext_GetPrimaryColorTargetHandle", reinterpret_cast(&InternalCall_Rendering_ScriptableRenderContext_GetPrimaryColorTargetHandle)); mono_add_internal_call("XCEngine.InternalCalls::Rendering_ScriptableRenderContext_GetDepthTargetHandle", reinterpret_cast(&InternalCall_Rendering_ScriptableRenderContext_GetDepthTargetHandle)); mono_add_internal_call("XCEngine.InternalCalls::Rendering_ScriptableRenderContext_CreateTransientTexture", reinterpret_cast(&InternalCall_Rendering_ScriptableRenderContext_CreateTransientTexture)); mono_add_internal_call("XCEngine.InternalCalls::Rendering_ScriptableRenderContext_CreateFullscreenTransientColorTexture", reinterpret_cast(&InternalCall_Rendering_ScriptableRenderContext_CreateFullscreenTransientColorTexture)); mono_add_internal_call("XCEngine.InternalCalls::Rendering_ScriptableRenderContext_CreateFullscreenTransientDepthTexture", reinterpret_cast(&InternalCall_Rendering_ScriptableRenderContext_CreateFullscreenTransientDepthTexture)); mono_add_internal_call("XCEngine.InternalCalls::Rendering_ScriptableRenderContext_BeginRasterPass", reinterpret_cast(&InternalCall_Rendering_ScriptableRenderContext_BeginRasterPass)); mono_add_internal_call("XCEngine.InternalCalls::Rendering_ScriptableRenderContext_SetRasterPassSourceColorTexture", reinterpret_cast(&InternalCall_Rendering_ScriptableRenderContext_SetRasterPassSourceColorTexture)); mono_add_internal_call("XCEngine.InternalCalls::Rendering_ScriptableRenderContext_AddRasterPassReadTexture", reinterpret_cast(&InternalCall_Rendering_ScriptableRenderContext_AddRasterPassReadTexture)); mono_add_internal_call("XCEngine.InternalCalls::Rendering_ScriptableRenderContext_AddRasterPassReadDepthTexture", reinterpret_cast(&InternalCall_Rendering_ScriptableRenderContext_AddRasterPassReadDepthTexture)); mono_add_internal_call("XCEngine.InternalCalls::Rendering_ScriptableRenderContext_AddRasterPassTextureBinding", reinterpret_cast(&InternalCall_Rendering_ScriptableRenderContext_AddRasterPassTextureBinding)); mono_add_internal_call("XCEngine.InternalCalls::Rendering_ScriptableRenderContext_SetRasterPassColorAttachment", reinterpret_cast(&InternalCall_Rendering_ScriptableRenderContext_SetRasterPassColorAttachment)); mono_add_internal_call("XCEngine.InternalCalls::Rendering_ScriptableRenderContext_SetRasterPassDepthAttachment", reinterpret_cast(&InternalCall_Rendering_ScriptableRenderContext_SetRasterPassDepthAttachment)); mono_add_internal_call("XCEngine.InternalCalls::Rendering_ScriptableRenderContext_SetRasterPassColorScaleFullscreenExecution", reinterpret_cast(&InternalCall_Rendering_ScriptableRenderContext_SetRasterPassColorScaleFullscreenExecution)); mono_add_internal_call("XCEngine.InternalCalls::Rendering_ScriptableRenderContext_SetRasterPassShaderVectorFullscreenExecution", reinterpret_cast(&InternalCall_Rendering_ScriptableRenderContext_SetRasterPassShaderVectorFullscreenExecution)); mono_add_internal_call("XCEngine.InternalCalls::Rendering_ScriptableRenderContext_SetRasterPassFinalColorFullscreenExecution", reinterpret_cast(&InternalCall_Rendering_ScriptableRenderContext_SetRasterPassFinalColorFullscreenExecution)); mono_add_internal_call("XCEngine.InternalCalls::Rendering_ScriptableRenderContext_CommitRasterPass", reinterpret_cast(&InternalCall_Rendering_ScriptableRenderContext_CommitRasterPass)); mono_add_internal_call("XCEngine.InternalCalls::Rendering_ScriptableRenderContext_GetStageColorSource", reinterpret_cast(&InternalCall_Rendering_ScriptableRenderContext_GetStageColorSource)); mono_add_internal_call("XCEngine.InternalCalls::Rendering_ScriptableRenderContext_GetStageUsesGraphManagedOutputColor", reinterpret_cast(&InternalCall_Rendering_ScriptableRenderContext_GetStageUsesGraphManagedOutputColor)); mono_add_internal_call("XCEngine.InternalCalls::Rendering_ScriptableRenderContext_GetMainDirectionalShadowEnabled", reinterpret_cast(&InternalCall_Rendering_ScriptableRenderContext_GetMainDirectionalShadowEnabled)); mono_add_internal_call("XCEngine.InternalCalls::Rendering_ScriptableRenderContext_GetMainDirectionalShadowViewProjection", reinterpret_cast(&InternalCall_Rendering_ScriptableRenderContext_GetMainDirectionalShadowViewProjection)); mono_add_internal_call("XCEngine.InternalCalls::Rendering_ScriptableRenderContext_GetMainDirectionalShadowOrthographicHalfExtent", reinterpret_cast(&InternalCall_Rendering_ScriptableRenderContext_GetMainDirectionalShadowOrthographicHalfExtent)); mono_add_internal_call("XCEngine.InternalCalls::Rendering_ScriptableRenderContext_GetMainDirectionalShadowNearClipPlane", reinterpret_cast(&InternalCall_Rendering_ScriptableRenderContext_GetMainDirectionalShadowNearClipPlane)); mono_add_internal_call("XCEngine.InternalCalls::Rendering_ScriptableRenderContext_GetMainDirectionalShadowFarClipPlane", reinterpret_cast(&InternalCall_Rendering_ScriptableRenderContext_GetMainDirectionalShadowFarClipPlane)); mono_add_internal_call("XCEngine.InternalCalls::Rendering_ScriptableRenderContext_GetMainDirectionalShadowMapWidth", reinterpret_cast(&InternalCall_Rendering_ScriptableRenderContext_GetMainDirectionalShadowMapWidth)); mono_add_internal_call("XCEngine.InternalCalls::Rendering_ScriptableRenderContext_GetMainDirectionalShadowMapHeight", reinterpret_cast(&InternalCall_Rendering_ScriptableRenderContext_GetMainDirectionalShadowMapHeight)); mono_add_internal_call("XCEngine.InternalCalls::Rendering_ScriptableRenderContext_GetMainDirectionalShadowWorldTexelSize", reinterpret_cast(&InternalCall_Rendering_ScriptableRenderContext_GetMainDirectionalShadowWorldTexelSize)); mono_add_internal_call("XCEngine.InternalCalls::Rendering_ScriptableRenderContext_GetMainDirectionalShadowReceiverDepthBias", reinterpret_cast(&InternalCall_Rendering_ScriptableRenderContext_GetMainDirectionalShadowReceiverDepthBias)); mono_add_internal_call("XCEngine.InternalCalls::Rendering_ScriptableRenderContext_GetMainDirectionalShadowNormalBiasScale", reinterpret_cast(&InternalCall_Rendering_ScriptableRenderContext_GetMainDirectionalShadowNormalBiasScale)); mono_add_internal_call("XCEngine.InternalCalls::Rendering_ScriptableRenderContext_GetMainDirectionalShadowStrength", reinterpret_cast(&InternalCall_Rendering_ScriptableRenderContext_GetMainDirectionalShadowStrength)); mono_add_internal_call("XCEngine.InternalCalls::Rendering_ScriptableRenderContext_GetMainDirectionalShadowDepthBiasFactor", reinterpret_cast(&InternalCall_Rendering_ScriptableRenderContext_GetMainDirectionalShadowDepthBiasFactor)); mono_add_internal_call("XCEngine.InternalCalls::Rendering_ScriptableRenderContext_GetMainDirectionalShadowDepthBiasUnits", reinterpret_cast(&InternalCall_Rendering_ScriptableRenderContext_GetMainDirectionalShadowDepthBiasUnits)); mono_add_internal_call("XCEngine.InternalCalls::Rendering_ScriptableRenderContext_GetCameraView", reinterpret_cast(&InternalCall_Rendering_ScriptableRenderContext_GetCameraView)); mono_add_internal_call("XCEngine.InternalCalls::Rendering_ScriptableRenderContext_GetCameraProjection", reinterpret_cast(&InternalCall_Rendering_ScriptableRenderContext_GetCameraProjection)); mono_add_internal_call("XCEngine.InternalCalls::Rendering_ScriptableRenderContext_GetCameraViewProjection", reinterpret_cast(&InternalCall_Rendering_ScriptableRenderContext_GetCameraViewProjection)); mono_add_internal_call("XCEngine.InternalCalls::Rendering_ScriptableRenderContext_GetCameraWorldPosition", reinterpret_cast(&InternalCall_Rendering_ScriptableRenderContext_GetCameraWorldPosition)); mono_add_internal_call("XCEngine.InternalCalls::Rendering_ScriptableRenderContext_GetCameraWorldRight", reinterpret_cast(&InternalCall_Rendering_ScriptableRenderContext_GetCameraWorldRight)); mono_add_internal_call("XCEngine.InternalCalls::Rendering_ScriptableRenderContext_GetCameraWorldUp", reinterpret_cast(&InternalCall_Rendering_ScriptableRenderContext_GetCameraWorldUp)); mono_add_internal_call("XCEngine.InternalCalls::Rendering_ScriptableRenderContext_GetCameraWorldForward", reinterpret_cast(&InternalCall_Rendering_ScriptableRenderContext_GetCameraWorldForward)); mono_add_internal_call("XCEngine.InternalCalls::Rendering_ScriptableRenderContext_GetCameraClearColor", reinterpret_cast(&InternalCall_Rendering_ScriptableRenderContext_GetCameraClearColor)); mono_add_internal_call("XCEngine.InternalCalls::Rendering_ScriptableRenderContext_GetCameraClearFlags", reinterpret_cast(&InternalCall_Rendering_ScriptableRenderContext_GetCameraClearFlags)); mono_add_internal_call("XCEngine.InternalCalls::Rendering_ScriptableRenderContext_GetCameraPerspectiveProjection", reinterpret_cast(&InternalCall_Rendering_ScriptableRenderContext_GetCameraPerspectiveProjection)); mono_add_internal_call("XCEngine.InternalCalls::Rendering_ScriptableRenderContext_GetCameraVerticalFovRadians", reinterpret_cast(&InternalCall_Rendering_ScriptableRenderContext_GetCameraVerticalFovRadians)); mono_add_internal_call("XCEngine.InternalCalls::Rendering_ScriptableRenderContext_GetCameraOrthographicSize", reinterpret_cast(&InternalCall_Rendering_ScriptableRenderContext_GetCameraOrthographicSize)); mono_add_internal_call("XCEngine.InternalCalls::Rendering_ScriptableRenderContext_GetCameraAspectRatio", reinterpret_cast(&InternalCall_Rendering_ScriptableRenderContext_GetCameraAspectRatio)); mono_add_internal_call("XCEngine.InternalCalls::Rendering_ScriptableRenderContext_GetCameraNearClipPlane", reinterpret_cast(&InternalCall_Rendering_ScriptableRenderContext_GetCameraNearClipPlane)); mono_add_internal_call("XCEngine.InternalCalls::Rendering_ScriptableRenderContext_GetCameraFarClipPlane", reinterpret_cast(&InternalCall_Rendering_ScriptableRenderContext_GetCameraFarClipPlane)); mono_add_internal_call("XCEngine.InternalCalls::Rendering_ScriptableRenderContext_GetCameraViewportWidth", reinterpret_cast(&InternalCall_Rendering_ScriptableRenderContext_GetCameraViewportWidth)); mono_add_internal_call("XCEngine.InternalCalls::Rendering_ScriptableRenderContext_GetCameraViewportHeight", reinterpret_cast(&InternalCall_Rendering_ScriptableRenderContext_GetCameraViewportHeight)); mono_add_internal_call("XCEngine.InternalCalls::Rendering_ScriptableRenderContext_GetMainDirectionalLightEnabled", reinterpret_cast(&InternalCall_Rendering_ScriptableRenderContext_GetMainDirectionalLightEnabled)); mono_add_internal_call("XCEngine.InternalCalls::Rendering_ScriptableRenderContext_GetMainDirectionalLightCastsShadows", reinterpret_cast(&InternalCall_Rendering_ScriptableRenderContext_GetMainDirectionalLightCastsShadows)); mono_add_internal_call("XCEngine.InternalCalls::Rendering_ScriptableRenderContext_GetMainDirectionalLightDirection", reinterpret_cast(&InternalCall_Rendering_ScriptableRenderContext_GetMainDirectionalLightDirection)); mono_add_internal_call("XCEngine.InternalCalls::Rendering_ScriptableRenderContext_GetMainDirectionalLightColor", reinterpret_cast(&InternalCall_Rendering_ScriptableRenderContext_GetMainDirectionalLightColor)); mono_add_internal_call("XCEngine.InternalCalls::Rendering_ScriptableRenderContext_GetMainDirectionalLightIntensity", reinterpret_cast(&InternalCall_Rendering_ScriptableRenderContext_GetMainDirectionalLightIntensity)); mono_add_internal_call("XCEngine.InternalCalls::Rendering_ScriptableRenderContext_GetHasMainDirectionalShadow", reinterpret_cast(&InternalCall_Rendering_ScriptableRenderContext_GetHasMainDirectionalShadow)); mono_add_internal_call("XCEngine.InternalCalls::Rendering_ScriptableRenderContext_GetAdditionalLightCount", reinterpret_cast(&InternalCall_Rendering_ScriptableRenderContext_GetAdditionalLightCount)); mono_add_internal_call("XCEngine.InternalCalls::Rendering_ScriptableRenderContext_GetEnvironmentMode", reinterpret_cast(&InternalCall_Rendering_ScriptableRenderContext_GetEnvironmentMode)); mono_add_internal_call("XCEngine.InternalCalls::Rendering_ScriptableRenderContext_GetEnvironmentSkyboxTopColor", reinterpret_cast(&InternalCall_Rendering_ScriptableRenderContext_GetEnvironmentSkyboxTopColor)); mono_add_internal_call("XCEngine.InternalCalls::Rendering_ScriptableRenderContext_GetEnvironmentSkyboxHorizonColor", reinterpret_cast(&InternalCall_Rendering_ScriptableRenderContext_GetEnvironmentSkyboxHorizonColor)); mono_add_internal_call("XCEngine.InternalCalls::Rendering_ScriptableRenderContext_GetEnvironmentSkyboxBottomColor", reinterpret_cast(&InternalCall_Rendering_ScriptableRenderContext_GetEnvironmentSkyboxBottomColor)); mono_add_internal_call("XCEngine.InternalCalls::Rendering_ScriptableRenderContext_GetFinalColorOutputTransferMode", reinterpret_cast(&InternalCall_Rendering_ScriptableRenderContext_GetFinalColorOutputTransferMode)); mono_add_internal_call("XCEngine.InternalCalls::Rendering_ScriptableRenderContext_GetFinalColorExposureMode", reinterpret_cast(&InternalCall_Rendering_ScriptableRenderContext_GetFinalColorExposureMode)); mono_add_internal_call("XCEngine.InternalCalls::Rendering_ScriptableRenderContext_GetFinalColorExposureValue", reinterpret_cast(&InternalCall_Rendering_ScriptableRenderContext_GetFinalColorExposureValue)); mono_add_internal_call("XCEngine.InternalCalls::Rendering_ScriptableRenderContext_GetFinalColorToneMappingMode", reinterpret_cast(&InternalCall_Rendering_ScriptableRenderContext_GetFinalColorToneMappingMode)); mono_add_internal_call("XCEngine.InternalCalls::Rendering_ScriptableRenderContext_GetFinalColorScale", reinterpret_cast(&InternalCall_Rendering_ScriptableRenderContext_GetFinalColorScale)); mono_add_internal_call("XCEngine.InternalCalls::Rendering_ScriptableRenderContext_GetFinalColorHasPipelineDefaults", reinterpret_cast(&InternalCall_Rendering_ScriptableRenderContext_GetFinalColorHasPipelineDefaults)); mono_add_internal_call("XCEngine.InternalCalls::Rendering_ScriptableRenderContext_GetFinalColorHasCameraOverrides", reinterpret_cast(&InternalCall_Rendering_ScriptableRenderContext_GetFinalColorHasCameraOverrides)); mono_add_internal_call("XCEngine.InternalCalls::Rendering_ScriptableRenderContext_RecordScenePhase", reinterpret_cast(&InternalCall_Rendering_ScriptableRenderContext_RecordScenePhase)); mono_add_internal_call("XCEngine.InternalCalls::Rendering_ScriptableRenderContext_DrawRenderersByDesc", reinterpret_cast(&InternalCall_Rendering_ScriptableRenderContext_DrawRenderersByDesc)); mono_add_internal_call("XCEngine.InternalCalls::Rendering_ScriptableRenderContext_RecordSceneInjectionPoint", reinterpret_cast(&InternalCall_Rendering_ScriptableRenderContext_RecordSceneInjectionPoint)); mono_add_internal_call("XCEngine.InternalCalls::Rendering_ScriptableRenderContext_RecordNativeSceneFeaturePass", reinterpret_cast(&InternalCall_Rendering_ScriptableRenderContext_RecordNativeSceneFeaturePass)); mono_add_internal_call("XCEngine.InternalCalls::Rendering_ScriptableRenderPipelinePlanningContext_GetRendererIndex", reinterpret_cast(&InternalCall_Rendering_ScriptableRenderPipelinePlanningContext_GetRendererIndex)); mono_add_internal_call("XCEngine.InternalCalls::Rendering_ScriptableRenderPipelinePlanningContext_IsStageRequested", reinterpret_cast(&InternalCall_Rendering_ScriptableRenderPipelinePlanningContext_IsStageRequested)); mono_add_internal_call("XCEngine.InternalCalls::Rendering_ScriptableRenderPipelinePlanningContext_GetStageColorSource", reinterpret_cast(&InternalCall_Rendering_ScriptableRenderPipelinePlanningContext_GetStageColorSource)); mono_add_internal_call("XCEngine.InternalCalls::Rendering_ScriptableRenderPipelinePlanningContext_GetStageUsesGraphManagedOutputColor", reinterpret_cast(&InternalCall_Rendering_ScriptableRenderPipelinePlanningContext_GetStageUsesGraphManagedOutputColor)); mono_add_internal_call("XCEngine.InternalCalls::Rendering_ScriptableRenderPipelinePlanningContext_RequestFullscreenStage", reinterpret_cast(&InternalCall_Rendering_ScriptableRenderPipelinePlanningContext_RequestFullscreenStage)); mono_add_internal_call("XCEngine.InternalCalls::Rendering_ScriptableRenderPipelinePlanningContext_ClearFullscreenStage", reinterpret_cast(&InternalCall_Rendering_ScriptableRenderPipelinePlanningContext_ClearFullscreenStage)); mono_add_internal_call("XCEngine.InternalCalls::Rendering_ScriptableRenderPipelinePlanningContext_RequestShadowCasterStage", reinterpret_cast(&InternalCall_Rendering_ScriptableRenderPipelinePlanningContext_RequestShadowCasterStage)); mono_add_internal_call("XCEngine.InternalCalls::Rendering_ScriptableRenderPipelinePlanningContext_ClearShadowCasterStage", reinterpret_cast(&InternalCall_Rendering_ScriptableRenderPipelinePlanningContext_ClearShadowCasterStage)); mono_add_internal_call("XCEngine.InternalCalls::Rendering_ScriptableRenderPipelinePlanningContext_GetHasExplicitShadowCasterStageConfiguration", reinterpret_cast(&InternalCall_Rendering_ScriptableRenderPipelinePlanningContext_GetHasExplicitShadowCasterStageConfiguration)); mono_add_internal_call("XCEngine.InternalCalls::Rendering_ScriptableRenderPipelinePlanningContext_RequestDepthOnlyStage", reinterpret_cast(&InternalCall_Rendering_ScriptableRenderPipelinePlanningContext_RequestDepthOnlyStage)); mono_add_internal_call("XCEngine.InternalCalls::Rendering_ScriptableRenderPipelinePlanningContext_RequestCameraDepthOnlyStage", reinterpret_cast(&InternalCall_Rendering_ScriptableRenderPipelinePlanningContext_RequestCameraDepthOnlyStage)); mono_add_internal_call("XCEngine.InternalCalls::Rendering_ScriptableRenderPipelinePlanningContext_ClearDepthOnlyStage", reinterpret_cast(&InternalCall_Rendering_ScriptableRenderPipelinePlanningContext_ClearDepthOnlyStage)); mono_add_internal_call("XCEngine.InternalCalls::Rendering_ScriptableRenderPipelinePlanningContext_GetHasExplicitDepthOnlyStageConfiguration", reinterpret_cast(&InternalCall_Rendering_ScriptableRenderPipelinePlanningContext_GetHasExplicitDepthOnlyStageConfiguration)); mono_add_internal_call("XCEngine.InternalCalls::Rendering_ScriptableRenderPipelinePlanningContext_GetHasFinalColorProcessing", reinterpret_cast(&InternalCall_Rendering_ScriptableRenderPipelinePlanningContext_GetHasFinalColorProcessing)); mono_add_internal_call("XCEngine.InternalCalls::Rendering_CameraRenderRequestContext_GetRenderedBaseCameraCount", reinterpret_cast(&InternalCall_Rendering_CameraRenderRequestContext_GetRenderedBaseCameraCount)); mono_add_internal_call("XCEngine.InternalCalls::Rendering_CameraRenderRequestContext_GetRenderedRequestCount", reinterpret_cast(&InternalCall_Rendering_CameraRenderRequestContext_GetRenderedRequestCount)); mono_add_internal_call("XCEngine.InternalCalls::Rendering_CameraRenderRequestContext_GetCameraGameObjectUUID", reinterpret_cast(&InternalCall_Rendering_CameraRenderRequestContext_GetCameraGameObjectUUID)); mono_add_internal_call("XCEngine.InternalCalls::Rendering_CameraRenderRequestContext_GetRendererIndex", reinterpret_cast(&InternalCall_Rendering_CameraRenderRequestContext_GetRendererIndex)); mono_add_internal_call("XCEngine.InternalCalls::Rendering_CameraRenderRequestContext_SetRendererIndex", reinterpret_cast(&InternalCall_Rendering_CameraRenderRequestContext_SetRendererIndex)); mono_add_internal_call("XCEngine.InternalCalls::Rendering_CameraRenderRequestContext_GetHasDirectionalShadow", reinterpret_cast(&InternalCall_Rendering_CameraRenderRequestContext_GetHasDirectionalShadow)); mono_add_internal_call("XCEngine.InternalCalls::Rendering_CameraRenderRequestContext_GetDirectionalShadowPlanningSettings", reinterpret_cast(&InternalCall_Rendering_CameraRenderRequestContext_GetDirectionalShadowPlanningSettings)); mono_add_internal_call("XCEngine.InternalCalls::Rendering_CameraRenderRequestContext_SetDirectionalShadowPlanningSettings", reinterpret_cast(&InternalCall_Rendering_CameraRenderRequestContext_SetDirectionalShadowPlanningSettings)); mono_add_internal_call("XCEngine.InternalCalls::Rendering_CameraRenderRequestContext_ClearDirectionalShadow", reinterpret_cast(&InternalCall_Rendering_CameraRenderRequestContext_ClearDirectionalShadow)); mono_add_internal_call("XCEngine.InternalCalls::Rendering_CameraRenderRequestContext_GetClearFlags", reinterpret_cast(&InternalCall_Rendering_CameraRenderRequestContext_GetClearFlags)); mono_add_internal_call("XCEngine.InternalCalls::Rendering_CameraRenderRequestContext_SetClearFlags", reinterpret_cast(&InternalCall_Rendering_CameraRenderRequestContext_SetClearFlags)); mono_add_internal_call("XCEngine.InternalCalls::Rendering_CameraRenderRequestContext_SetResolvedFinalColorPolicy", reinterpret_cast(&InternalCall_Rendering_CameraRenderRequestContext_SetResolvedFinalColorPolicy)); mono_add_internal_call("XCEngine.InternalCalls::Rendering_CameraRenderRequestContext_ClearFinalColorPolicy", reinterpret_cast(&InternalCall_Rendering_CameraRenderRequestContext_ClearFinalColorPolicy)); mono_add_internal_call("XCEngine.InternalCalls::Rendering_RenderSceneSetupContext_GetRendererIndex", reinterpret_cast(&InternalCall_Rendering_RenderSceneSetupContext_GetRendererIndex)); mono_add_internal_call("XCEngine.InternalCalls::Rendering_RenderSceneSetupContext_GetCameraGameObjectUUID", reinterpret_cast(&InternalCall_Rendering_RenderSceneSetupContext_GetCameraGameObjectUUID)); mono_add_internal_call("XCEngine.InternalCalls::Rendering_RenderSceneSetupContext_GetIsConfigured", reinterpret_cast(&InternalCall_Rendering_RenderSceneSetupContext_GetIsConfigured)); mono_add_internal_call("XCEngine.InternalCalls::Rendering_RenderSceneSetupContext_GetClearFlags", reinterpret_cast(&InternalCall_Rendering_RenderSceneSetupContext_GetClearFlags)); mono_add_internal_call("XCEngine.InternalCalls::Rendering_RenderSceneSetupContext_GetHasMainSceneDepthAttachment", reinterpret_cast(&InternalCall_Rendering_RenderSceneSetupContext_GetHasMainSceneDepthAttachment)); mono_add_internal_call("XCEngine.InternalCalls::Rendering_RenderSceneSetupContext_GetHasMainDirectionalShadow", reinterpret_cast(&InternalCall_Rendering_RenderSceneSetupContext_GetHasMainDirectionalShadow)); mono_add_internal_call("XCEngine.InternalCalls::Rendering_RenderSceneSetupContext_SetEnvironmentNone", reinterpret_cast(&InternalCall_Rendering_RenderSceneSetupContext_SetEnvironmentNone)); mono_add_internal_call("XCEngine.InternalCalls::Rendering_RenderSceneSetupContext_UseCameraSkyboxMaterial", reinterpret_cast(&InternalCall_Rendering_RenderSceneSetupContext_UseCameraSkyboxMaterial)); mono_add_internal_call("XCEngine.InternalCalls::Rendering_RenderSceneSetupContext_SetProceduralSkybox", reinterpret_cast(&InternalCall_Rendering_RenderSceneSetupContext_SetProceduralSkybox)); mono_add_internal_call("XCEngine.InternalCalls::Rendering_RenderSceneSetupContext_ClearGlobalShaderKeywords", reinterpret_cast(&InternalCall_Rendering_RenderSceneSetupContext_ClearGlobalShaderKeywords)); mono_add_internal_call("XCEngine.InternalCalls::Rendering_RenderSceneSetupContext_SetGlobalShaderKeyword", reinterpret_cast(&InternalCall_Rendering_RenderSceneSetupContext_SetGlobalShaderKeyword)); mono_add_internal_call("XCEngine.InternalCalls::Rendering_DirectionalShadowExecutionContext_GetHasPlannedMainDirectionalShadow", reinterpret_cast(&InternalCall_Rendering_DirectionalShadowExecutionContext_GetHasPlannedMainDirectionalShadow)); mono_add_internal_call("XCEngine.InternalCalls::Rendering_DirectionalShadowExecutionContext_GetRendererIndex", reinterpret_cast(&InternalCall_Rendering_DirectionalShadowExecutionContext_GetRendererIndex)); mono_add_internal_call("XCEngine.InternalCalls::Rendering_DirectionalShadowExecutionContext_GetIsConfigured", reinterpret_cast(&InternalCall_Rendering_DirectionalShadowExecutionContext_GetIsConfigured)); mono_add_internal_call("XCEngine.InternalCalls::Rendering_DirectionalShadowExecutionContext_UseDefaultMainDirectionalShadowExecution", reinterpret_cast(&InternalCall_Rendering_DirectionalShadowExecutionContext_UseDefaultMainDirectionalShadowExecution)); mono_add_internal_call("XCEngine.InternalCalls::Rendering_DirectionalShadowExecutionContext_ClearDirectionalShadowExecution", reinterpret_cast(&InternalCall_Rendering_DirectionalShadowExecutionContext_ClearDirectionalShadowExecution)); GetInternalCallRegistrationState() = true; } } // namespace MonoScriptRuntime::MonoScriptRuntime(Settings settings) : m_settings(std::move(settings)) { ResolveSettings(); } MonoScriptRuntime::~MonoScriptRuntime() { Shutdown(); } bool MonoScriptRuntime::Initialize() { m_lastError.clear(); if (!ResolveSettings()) { return false; } if (m_initialized) { return true; } if (!InitializeRootDomain()) { return false; } if (!CreateAppDomain()) { return false; } if (!LoadAssemblies()) { DestroyAppDomain(); return false; } if (!DiscoverScriptClasses()) { DestroyAppDomain(); return false; } m_runtimeLifetimeToken = std::make_shared(0); m_initialized = true; Rendering::Pipelines::SetManagedRenderPipelineBridge( std::make_shared( this, m_runtimeLifetimeToken)); return true; } void MonoScriptRuntime::Shutdown() { Rendering::Pipelines::ClearManagedRenderPipelineBridge(); ClearManagedRenderPipelineSelection(this); GetManagedScriptableRenderContextRegistry().clear(); GetManagedScriptableRenderContextNextHandle() = 1; GetManagedCameraRenderRequestContextRegistry().clear(); GetManagedCameraRenderRequestContextNextHandle() = 1; GetManagedRenderSceneSetupContextRegistry().clear(); GetManagedRenderSceneSetupContextNextHandle() = 1; GetManagedDirectionalShadowExecutionContextRegistry().clear(); GetManagedDirectionalShadowExecutionContextNextHandle() = 1; GetManagedScriptableRenderPipelinePlanningContextRegistry().clear(); GetManagedScriptableRenderPipelinePlanningContextNextHandle() = 1; ClearManagedInstances(); ClearExternalManagedObjects(); ClearClassCache(); m_coreAssembly = nullptr; m_appAssembly = nullptr; m_coreImage = nullptr; m_appImage = nullptr; m_loadedManagedAssemblies.clear(); m_componentClass = nullptr; m_behaviourClass = nullptr; m_gameObjectClass = nullptr; m_monoBehaviourClass = nullptr; m_scriptableRenderPipelineAssetClass = nullptr; m_scriptableRenderPipelineClass = nullptr; m_scriptableRenderContextClass = nullptr; m_cameraRenderRequestContextClass = nullptr; m_renderSceneSetupContextClass = nullptr; m_directionalShadowExecutionContextClass = nullptr; m_scriptableRenderPipelinePlanningContextClass = nullptr; m_serializeFieldAttributeClass = nullptr; m_gameObjectConstructor = nullptr; m_scriptableRenderContextConstructor = nullptr; m_cameraRenderRequestContextConstructor = nullptr; m_renderSceneSetupContextConstructor = nullptr; m_directionalShadowExecutionContextConstructor = nullptr; m_scriptableRenderPipelinePlanningContextConstructor = nullptr; m_managedGameObjectUUIDField = nullptr; m_gameObjectUUIDField = nullptr; m_scriptComponentUUIDField = nullptr; DestroyAppDomain(); m_activeScene = nullptr; GetInternalCallScene() = nullptr; GetInternalCallDeltaTime() = 0.0f; m_runtimeLifetimeToken.reset(); m_initialized = false; } bool MonoScriptRuntime::IsClassAvailable( const std::string& assemblyName, const std::string& namespaceName, const std::string& className) const { return FindClassMetadata(assemblyName, namespaceName, className) != nullptr; } bool MonoScriptRuntime::TryGetAvailableScriptClasses( std::vector& outClasses) const { outClasses.clear(); if (!m_initialized) { return false; } outClasses.reserve(m_classes.size()); for (const auto& [key, metadata] : m_classes) { (void)key; outClasses.push_back( ScriptClassDescriptor{ metadata.assemblyName, metadata.namespaceName, metadata.className }); } std::sort( outClasses.begin(), outClasses.end(), [](const ScriptClassDescriptor& lhs, const ScriptClassDescriptor& rhs) { if (lhs.assemblyName != rhs.assemblyName) { return lhs.assemblyName < rhs.assemblyName; } if (lhs.namespaceName != rhs.namespaceName) { return lhs.namespaceName < rhs.namespaceName; } return lhs.className < rhs.className; }); return true; } bool MonoScriptRuntime::TryGetAvailableRenderPipelineAssetClasses( std::vector& outClasses) const { outClasses.clear(); if (!m_initialized) { return false; } outClasses = m_renderPipelineAssetClasses; std::sort( outClasses.begin(), outClasses.end(), [](const ScriptClassDescriptor& lhs, const ScriptClassDescriptor& rhs) { if (lhs.assemblyName != rhs.assemblyName) { return lhs.assemblyName < rhs.assemblyName; } if (lhs.namespaceName != rhs.namespaceName) { return lhs.namespaceName < rhs.namespaceName; } return lhs.className < rhs.className; }); return true; } std::vector MonoScriptRuntime::GetScriptClassNames(const std::string& assemblyName) const { std::vector classes; if (!TryGetAvailableScriptClasses(classes)) { return {}; } std::vector classNames; classNames.reserve(classes.size()); for (const ScriptClassDescriptor& descriptor : classes) { if (!assemblyName.empty() && descriptor.assemblyName != assemblyName) { continue; } classNames.push_back(descriptor.GetFullName()); } return classNames; } bool MonoScriptRuntime::TryGetClassFieldMetadata( const std::string& assemblyName, const std::string& namespaceName, const std::string& className, std::vector& outFields) const { outFields.clear(); const ClassMetadata* metadata = FindClassMetadata(assemblyName, namespaceName, className); if (!metadata) { return false; } outFields.reserve(metadata->fields.size()); for (const auto& [fieldName, fieldMetadata] : metadata->fields) { outFields.push_back(ScriptFieldMetadata{fieldName, fieldMetadata.type}); } std::sort( outFields.begin(), outFields.end(), [](const ScriptFieldMetadata& lhs, const ScriptFieldMetadata& rhs) { return lhs.name < rhs.name; }); return true; } bool MonoScriptRuntime::TryGetClassFieldDefaultValues( const std::string& assemblyName, const std::string& namespaceName, const std::string& className, std::vector& outFields) const { outFields.clear(); const ClassMetadata* metadata = FindClassMetadata(assemblyName, namespaceName, className); if (!metadata) { return false; } SetCurrentDomain(); MonoObject* instance = mono_object_new(m_appDomain, metadata->monoClass); if (!instance) { return false; } mono_runtime_object_init(instance); outFields.reserve(metadata->fields.size()); for (const auto& [fieldName, fieldMetadata] : metadata->fields) { ScriptFieldValue value; if (!TryReadFieldValue(instance, fieldMetadata, value)) { outFields.clear(); return false; } outFields.push_back(ScriptFieldDefaultValue{fieldName, fieldMetadata.type, value}); } std::sort( outFields.begin(), outFields.end(), [](const ScriptFieldDefaultValue& lhs, const ScriptFieldDefaultValue& rhs) { return lhs.fieldName < rhs.fieldName; }); return true; } bool MonoScriptRuntime::HasManagedInstance(const ScriptComponent* component) const { const InstanceData* instanceData = FindInstance(component); return instanceData != nullptr && GetManagedObject(*instanceData) != nullptr; } MonoObject* MonoScriptRuntime::GetManagedInstanceObject(const ScriptComponent* component) const { const InstanceData* instanceData = FindInstance(component); return instanceData ? GetManagedObject(*instanceData) : nullptr; } bool MonoScriptRuntime::TryGetFieldValue( const ScriptComponent* component, const std::string& fieldName, ScriptFieldValue& outValue) const { const InstanceData* instanceData = FindInstance(component); if (!instanceData || !instanceData->classMetadata) { return false; } const auto fieldIt = instanceData->classMetadata->fields.find(fieldName); if (fieldIt == instanceData->classMetadata->fields.end()) { return false; } MonoObject* instance = GetManagedObject(*instanceData); if (!instance) { return false; } return TryReadFieldValue(instance, fieldIt->second, outValue); } void MonoScriptRuntime::OnRuntimeStart(Components::Scene* scene) { m_activeScene = nullptr; GetInternalCallDeltaTime() = 0.0f; if (Initialize()) { m_activeScene = scene; GetInternalCallScene() = scene; } } void MonoScriptRuntime::OnRuntimeStop(Components::Scene* scene) { if (scene != nullptr) { ClearManagedRenderPipelineSelection(this); } ClearManagedInstances(); m_activeScene = nullptr; GetInternalCallScene() = nullptr; GetInternalCallDeltaTime() = 0.0f; } bool MonoScriptRuntime::TrySetManagedFieldValue( const ScriptRuntimeContext& context, const std::string& fieldName, const ScriptFieldValue& value) { const InstanceData* instanceData = FindInstance(context); if (!instanceData || !instanceData->classMetadata) { return false; } const auto metadataIt = instanceData->classMetadata->fields.find(fieldName); if (metadataIt == instanceData->classMetadata->fields.end()) { return false; } if (!IsScriptFieldValueCompatible(metadataIt->second.type, value)) { return false; } MonoObject* instance = GetManagedObject(*instanceData); if (!instance) { return false; } return TrySetFieldValue(instance, metadataIt->second, value); } bool MonoScriptRuntime::TryGetManagedFieldValue( const ScriptRuntimeContext& context, const std::string& fieldName, ScriptFieldValue& outValue) const { const InstanceData* instanceData = FindInstance(context); if (!instanceData || !instanceData->classMetadata) { return false; } const auto metadataIt = instanceData->classMetadata->fields.find(fieldName); if (metadataIt == instanceData->classMetadata->fields.end()) { return false; } MonoObject* instance = GetManagedObject(*instanceData); if (!instance) { return false; } return TryReadFieldValue(instance, metadataIt->second, outValue); } void MonoScriptRuntime::SyncManagedFieldsToStorage(const ScriptRuntimeContext& context) { if (!context.component) { return; } const InstanceData* instanceData = FindInstance(context); if (!instanceData || !instanceData->classMetadata) { return; } MonoObject* instance = GetManagedObject(*instanceData); if (!instance) { return; } ScriptFieldStorage& fieldStorage = context.component->GetFieldStorage(); const std::vector fieldNames = fieldStorage.GetFieldNames(); for (const std::string& fieldName : fieldNames) { StoredScriptField* storedField = fieldStorage.FindField(fieldName); if (!storedField) { continue; } const auto metadataIt = instanceData->classMetadata->fields.find(fieldName); if (metadataIt == instanceData->classMetadata->fields.end() || storedField->type != metadataIt->second.type) { continue; } ScriptFieldValue value; if (!TryReadFieldValue(instance, metadataIt->second, value)) { continue; } fieldStorage.SetFieldValue(fieldName, storedField->type, value); } } bool MonoScriptRuntime::CreateScriptInstance(const ScriptRuntimeContext& context) { if (!context.component) { SetError("Cannot create a managed script instance without a ScriptComponent."); return false; } if (FindInstance(context)) { return true; } if (!Initialize()) { return false; } const std::string assemblyName = context.component->GetAssemblyName().empty() ? m_settings.appAssemblyName : context.component->GetAssemblyName(); const ClassMetadata* classMetadata = FindClassMetadata( assemblyName, context.component->GetNamespaceName(), context.component->GetClassName()); if (!classMetadata) { SetError("Managed script class was not found: " + assemblyName + "|" + context.component->GetFullClassName()); return false; } SetCurrentDomain(); MonoObject* instance = mono_object_new(m_appDomain, classMetadata->monoClass); if (!instance) { SetError("Mono failed to allocate a managed object for " + classMetadata->fullName + "."); return false; } mono_runtime_object_init(instance); if (!ApplyContextFields(context, instance) || !ApplyStoredFields(context, *classMetadata, instance)) { return false; } const uint32_t gcHandle = mono_gchandle_new(instance, false); const InstanceKey key{context.gameObjectUUID, context.scriptComponentUUID}; m_instances[key] = InstanceData{classMetadata, gcHandle}; return true; } void MonoScriptRuntime::DestroyScriptInstance(const ScriptRuntimeContext& context) { InstanceData* instanceData = FindInstance(context); if (!instanceData) { return; } if (instanceData->gcHandle != 0) { mono_gchandle_free(instanceData->gcHandle); } m_instances.erase(InstanceKey{context.gameObjectUUID, context.scriptComponentUUID}); } void MonoScriptRuntime::InvokeMethod( const ScriptRuntimeContext& context, ScriptLifecycleMethod method, float deltaTime) { const InstanceData* instanceData = FindInstance(context); if (!instanceData || !instanceData->classMetadata) { return; } MonoMethod* managedMethod = instanceData->classMetadata->lifecycleMethods[static_cast(method)]; if (!managedMethod) { return; } MonoObject* instance = GetManagedObject(*instanceData); if (!instance) { return; } const float previousDeltaTime = GetInternalCallDeltaTime(); GetInternalCallDeltaTime() = deltaTime; InvokeManagedMethod(instance, managedMethod, nullptr); GetInternalCallDeltaTime() = previousDeltaTime; } void MonoScriptRuntime::InvokePhysicsMessage( const ScriptRuntimeContext& context, ScriptPhysicsMessage message, Components::GameObject* other) { const InstanceData* instanceData = FindInstance(context); if (!instanceData || !instanceData->classMetadata) { return; } const PhysicsMessageMethods& methods = instanceData->classMetadata->physicsMessageMethods[static_cast(message)]; MonoMethod* managedMethod = methods.withGameObject ? methods.withGameObject : methods.withoutArgs; if (!managedMethod) { return; } MonoObject* instance = GetManagedObject(*instanceData); if (!instance) { return; } if (methods.withGameObject) { MonoObject* managedOther = other ? CreateManagedGameObject(other->GetUUID()) : nullptr; if (other && !managedOther) { return; } void* args[1]; args[0] = managedOther; InvokeManagedMethod(instance, managedMethod, args); return; } InvokeManagedMethod(instance, managedMethod, nullptr); } size_t MonoScriptRuntime::InstanceKeyHasher::operator()(const InstanceKey& key) const { const size_t h1 = std::hash{}(key.gameObjectUUID); const size_t h2 = std::hash{}(key.scriptComponentUUID); return h1 ^ (h2 + 0x9e3779b97f4a7c15ULL + (h1 << 6) + (h1 >> 2)); } std::filesystem::path MonoScriptRuntime::GetEngineAssemblyManifestPath( const std::filesystem::path& assemblyDirectory) { return assemblyDirectory / EngineAssemblyManifestFileName; } bool MonoScriptRuntime::DiscoverEngineAssemblies( Settings& ioSettings, std::string* outError) { if (!ioSettings.engineAssemblies.empty()) { std::unordered_set assemblyNames; for (ManagedAssemblyDescriptor& assembly : ioSettings.engineAssemblies) { if (!NormalizeManagedAssemblyDescriptor( assembly, ioSettings.assemblyDirectory, assemblyNames, outError)) { return false; } } return true; } if (ioSettings.assemblyDirectory.empty()) { return true; } std::vector discoveredAssemblies; const std::filesystem::path manifestPath = GetEngineAssemblyManifestPath(ioSettings.assemblyDirectory); if (!LoadManagedAssemblyManifest( ioSettings.assemblyDirectory, manifestPath, discoveredAssemblies, outError)) { return false; } if (discoveredAssemblies.empty() && !DiscoverManagedAssembliesByConvention( ioSettings, discoveredAssemblies)) { if (outError != nullptr) { *outError = "Failed to discover managed engine assemblies in " + ioSettings.assemblyDirectory.string(); } return false; } ioSettings.engineAssemblies = std::move(discoveredAssemblies); return true; } bool MonoScriptRuntime::ResolveSettings() { if (!m_settings.coreAssemblyPath.empty() && m_settings.assemblyDirectory.empty()) { m_settings.assemblyDirectory = m_settings.coreAssemblyPath.parent_path(); } if (!m_settings.appAssemblyPath.empty() && m_settings.assemblyDirectory.empty()) { m_settings.assemblyDirectory = m_settings.appAssemblyPath.parent_path(); } if (m_settings.coreAssemblyPath.empty() && !m_settings.assemblyDirectory.empty()) { m_settings.coreAssemblyPath = m_settings.assemblyDirectory / (m_settings.coreAssemblyName + ".dll"); } if (m_settings.appAssemblyPath.empty() && !m_settings.assemblyDirectory.empty()) { m_settings.appAssemblyPath = m_settings.assemblyDirectory / (m_settings.appAssemblyName + ".dll"); } if (m_settings.corlibDirectory.empty()) { if (!m_settings.assemblyDirectory.empty()) { m_settings.corlibDirectory = m_settings.assemblyDirectory; } else if (!m_settings.coreAssemblyPath.empty()) { m_settings.corlibDirectory = m_settings.coreAssemblyPath.parent_path(); } } std::string discoveryError; if (!DiscoverEngineAssemblies(m_settings, &discoveryError)) { SetError(discoveryError); return false; } return true; } bool MonoScriptRuntime::InitializeRootDomain() { MonoRootState& rootState = GetMonoRootState(); if (rootState.initialized) { return true; } if (!m_settings.corlibDirectory.empty()) { const std::string corlibDirectory = m_settings.corlibDirectory.string(); mono_set_assemblies_path(corlibDirectory.c_str()); } mono_config_parse(nullptr); rootState.rootDomain = mono_jit_init_version("XCEngineRootDomain", "v4.0.30319"); if (!rootState.rootDomain) { SetError("Failed to initialize the Mono root domain."); return false; } mono_domain_set(rootState.rootDomain, true); RegisterInternalCalls(); rootState.initialized = true; if (!rootState.cleanupRegistered) { std::atexit(&CleanupMonoRootDomainAtExit); rootState.cleanupRegistered = true; } return true; } bool MonoScriptRuntime::CreateAppDomain() { if (m_appDomain) { return true; } MonoRootState& rootState = GetMonoRootState(); if (!rootState.rootDomain) { SetError("Mono root domain is not initialized."); return false; } mono_domain_set(rootState.rootDomain, true); m_appDomain = mono_domain_create_appdomain(const_cast("XCEngineScriptDomain"), nullptr); if (!m_appDomain) { SetError("Failed to create the Mono app domain."); return false; } mono_domain_set(m_appDomain, true); return true; } void MonoScriptRuntime::DestroyAppDomain() { if (!m_appDomain) { return; } MonoRootState& rootState = GetMonoRootState(); if (rootState.rootDomain) { mono_domain_set(rootState.rootDomain, true); } mono_domain_unload(m_appDomain); m_appDomain = nullptr; if (rootState.rootDomain) { mono_domain_set(rootState.rootDomain, true); } } void MonoScriptRuntime::SetCurrentDomain() const { if (m_appDomain) { mono_domain_set(m_appDomain, true); } } bool MonoScriptRuntime::LoadAssemblies() { if (m_settings.coreAssemblyPath.empty() || m_settings.appAssemblyPath.empty()) { SetError("Managed assembly paths are not configured."); return false; } SetCurrentDomain(); m_loadedManagedAssemblies.clear(); if (!LoadAssemblyImage( BuildManagedAssemblyDescriptor( m_settings.coreAssemblyName, m_settings.coreAssemblyPath), "script core", m_coreAssembly, m_coreImage)) { return false; } for (const ManagedAssemblyDescriptor& assembly : m_settings.engineAssemblies) { MonoAssembly* loadedAssembly = nullptr; MonoImage* loadedImage = nullptr; if (!LoadAssemblyImage( assembly, "engine", loadedAssembly, loadedImage)) { return false; } } if (!LoadAssemblyImage( BuildManagedAssemblyDescriptor( m_settings.appAssemblyName, m_settings.appAssemblyPath), "game scripts", m_appAssembly, m_appImage)) { return false; } return true; } bool MonoScriptRuntime::LoadAssemblyImage( const ManagedAssemblyDescriptor& descriptor, const char* roleLabel, MonoAssembly*& outAssembly, MonoImage*& outImage) { outAssembly = nullptr; outImage = nullptr; if (descriptor.name.empty() || descriptor.path.empty()) { SetError( "Managed " + std::string(roleLabel) + " assembly descriptor is incomplete."); return false; } if (!std::filesystem::exists(descriptor.path)) { SetError( "Managed " + std::string(roleLabel) + " assembly does not exist: " + descriptor.path.string()); return false; } if (m_loadedManagedAssemblies.contains(descriptor.name)) { SetError( "Managed assembly name is loaded more than once: " + descriptor.name); return false; } outAssembly = mono_domain_assembly_open( m_appDomain, descriptor.path.string().c_str()); if (!outAssembly) { SetError( "Failed to load managed " + std::string(roleLabel) + " assembly: " + descriptor.path.string()); return false; } outImage = mono_assembly_get_image(outAssembly); if (!outImage) { SetError( "Failed to access the managed " + std::string(roleLabel) + " image: " + descriptor.path.string()); return false; } m_loadedManagedAssemblies.emplace( descriptor.name, LoadedManagedAssemblyData{outAssembly, outImage}); return true; } bool MonoScriptRuntime::DiscoverScriptClasses() { ClearClassCache(); m_componentClass = mono_class_from_name( m_coreImage, m_settings.baseNamespace.c_str(), "Component"); if (!m_componentClass) { SetError("Failed to locate the managed Component base type."); return false; } m_behaviourClass = mono_class_from_name( m_coreImage, m_settings.baseNamespace.c_str(), "Behaviour"); if (!m_behaviourClass) { SetError("Failed to locate the managed Behaviour base type."); return false; } m_gameObjectClass = mono_class_from_name( m_coreImage, m_settings.baseNamespace.c_str(), "GameObject"); if (!m_gameObjectClass) { SetError("Failed to locate the managed GameObject wrapper type."); return false; } m_gameObjectConstructor = mono_class_get_method_from_name(m_gameObjectClass, ".ctor", 1); m_managedGameObjectUUIDField = mono_class_get_field_from_name(m_gameObjectClass, "m_uuid"); if (!m_gameObjectConstructor || !m_managedGameObjectUUIDField) { SetError("Failed to locate the managed GameObject constructor or UUID field."); return false; } m_monoBehaviourClass = mono_class_from_name( m_coreImage, m_settings.baseNamespace.c_str(), m_settings.baseClassName.c_str()); if (!m_monoBehaviourClass) { SetError("Failed to locate the managed base type " + BuildFullClassName(m_settings.baseNamespace, m_settings.baseClassName) + "."); return false; } m_scriptableRenderPipelineAssetClass = mono_class_from_name( m_coreImage, kManagedRenderingNamespace, "ScriptableRenderPipelineAsset"); if (!m_scriptableRenderPipelineAssetClass) { SetError("Failed to locate the managed ScriptableRenderPipelineAsset base type."); return false; } m_scriptableRenderPipelineClass = mono_class_from_name( m_coreImage, kManagedRenderingNamespace, "ScriptableRenderPipeline"); if (!m_scriptableRenderPipelineClass) { SetError("Failed to locate the managed ScriptableRenderPipeline base type."); return false; } m_scriptableRenderContextClass = mono_class_from_name( m_coreImage, kManagedRenderingNamespace, "ScriptableRenderContext"); if (!m_scriptableRenderContextClass) { SetError("Failed to locate the managed ScriptableRenderContext type."); return false; } m_scriptableRenderContextConstructor = mono_class_get_method_from_name( m_scriptableRenderContextClass, ".ctor", 1); if (!m_scriptableRenderContextConstructor) { SetError( "Failed to locate the managed ScriptableRenderContext constructor."); return false; } m_cameraRenderRequestContextClass = mono_class_from_name( m_coreImage, kManagedRenderingNamespace, "CameraRenderRequestContext"); if (!m_cameraRenderRequestContextClass) { SetError( "Failed to locate the managed CameraRenderRequestContext type."); return false; } m_cameraRenderRequestContextConstructor = mono_class_get_method_from_name( m_cameraRenderRequestContextClass, ".ctor", 1); if (!m_cameraRenderRequestContextConstructor) { SetError( "Failed to locate the managed CameraRenderRequestContext constructor."); return false; } m_renderSceneSetupContextClass = mono_class_from_name( m_coreImage, kManagedRenderingNamespace, "RenderSceneSetupContext"); if (!m_renderSceneSetupContextClass) { SetError( "Failed to locate the managed RenderSceneSetupContext type."); return false; } m_renderSceneSetupContextConstructor = mono_class_get_method_from_name( m_renderSceneSetupContextClass, ".ctor", 1); if (!m_renderSceneSetupContextConstructor) { SetError( "Failed to locate the managed RenderSceneSetupContext constructor."); return false; } m_directionalShadowExecutionContextClass = mono_class_from_name( m_coreImage, kManagedRenderingNamespace, "DirectionalShadowExecutionContext"); if (!m_directionalShadowExecutionContextClass) { SetError( "Failed to locate the managed DirectionalShadowExecutionContext type."); return false; } m_directionalShadowExecutionContextConstructor = mono_class_get_method_from_name( m_directionalShadowExecutionContextClass, ".ctor", 1); if (!m_directionalShadowExecutionContextConstructor) { SetError( "Failed to locate the managed DirectionalShadowExecutionContext constructor."); return false; } m_scriptableRenderPipelinePlanningContextClass = mono_class_from_name( m_coreImage, kManagedRenderingNamespace, "ScriptableRenderPipelinePlanningContext"); if (!m_scriptableRenderPipelinePlanningContextClass) { SetError( "Failed to locate the managed ScriptableRenderPipelinePlanningContext type."); return false; } m_scriptableRenderPipelinePlanningContextConstructor = mono_class_get_method_from_name( m_scriptableRenderPipelinePlanningContextClass, ".ctor", 1); if (!m_scriptableRenderPipelinePlanningContextConstructor) { SetError( "Failed to locate the managed ScriptableRenderPipelinePlanningContext constructor."); return false; } m_serializeFieldAttributeClass = mono_class_from_name( m_coreImage, m_settings.baseNamespace.c_str(), "SerializeField"); if (!m_serializeFieldAttributeClass) { SetError("Failed to locate the managed SerializeField attribute type."); return false; } m_gameObjectUUIDField = mono_class_get_field_from_name(m_componentClass, "m_gameObjectUUID"); m_scriptComponentUUIDField = mono_class_get_field_from_name(m_behaviourClass, "m_scriptComponentUUID"); if (!m_gameObjectUUIDField || !m_scriptComponentUUIDField) { SetError("Failed to locate the managed context fields for Component/Behaviour."); return false; } DiscoverScriptClassesInImage(m_settings.appAssemblyName, m_appImage); DiscoverRenderPipelineAssetClassesInImage( m_settings.coreAssemblyName, m_coreImage); for (const ManagedAssemblyDescriptor& assembly : m_settings.engineAssemblies) { DiscoverRenderPipelineAssetClassesInImage( assembly.name, FindLoadedAssemblyImage(assembly.name)); } DiscoverRenderPipelineAssetClassesInImage( m_settings.appAssemblyName, m_appImage); return true; } void MonoScriptRuntime::DiscoverScriptClassesInImage(const std::string& assemblyName, MonoImage* image) { if (!image) { return; } const int typeCount = mono_image_get_table_rows(image, MONO_TABLE_TYPEDEF); for (int index = 1; index <= typeCount; ++index) { const uint32_t typeToken = mono_metadata_make_token(MONO_TABLE_TYPEDEF, index); MonoClass* monoClass = mono_class_get(image, typeToken); if (!monoClass || !IsMonoBehaviourSubclass(monoClass)) { continue; } if ((mono_class_get_flags(monoClass) & MONO_TYPE_ATTR_ABSTRACT) != 0) { continue; } ClassMetadata metadata; metadata.assemblyName = assemblyName; metadata.namespaceName = SafeString(mono_class_get_namespace(monoClass)); metadata.className = SafeString(mono_class_get_name(monoClass)); metadata.fullName = BuildFullClassName(metadata.namespaceName, metadata.className); metadata.monoClass = monoClass; for (size_t methodIndex = 0; methodIndex < LifecycleMethodCount; ++methodIndex) { metadata.lifecycleMethods[methodIndex] = mono_class_get_method_from_name( monoClass, ToLifecycleMethodName(static_cast(methodIndex)), 0); } for (size_t methodIndex = 0; methodIndex < PhysicsMessageCount; ++methodIndex) { PhysicsMessageMethods& methods = metadata.physicsMessageMethods[methodIndex]; methods.withGameObject = mono_class_get_method_from_name( monoClass, ToPhysicsMessageMethodName(static_cast(methodIndex)), 1); methods.withoutArgs = mono_class_get_method_from_name( monoClass, ToPhysicsMessageMethodName(static_cast(methodIndex)), 0); } void* fieldIterator = nullptr; while (MonoClassField* field = mono_class_get_fields(monoClass, &fieldIterator)) { const uint32_t fieldFlags = mono_field_get_flags(field); if ((fieldFlags & MONO_FIELD_ATTR_STATIC) != 0 || (fieldFlags & MONO_FIELD_ATTR_LITERAL) != 0 || (fieldFlags & MONO_FIELD_ATTR_INIT_ONLY) != 0) { continue; } const bool isPublicField = (fieldFlags & MONO_FIELD_ATTR_PUBLIC) != 0; if (!isPublicField && !HasSerializeFieldAttribute(field)) { continue; } FieldMetadata fieldMetadata = BuildFieldMetadata(field); if (fieldMetadata.type == ScriptFieldType::None) { continue; } metadata.fields.emplace(mono_field_get_name(field), std::move(fieldMetadata)); } m_classes.emplace( BuildClassKey(metadata.assemblyName, metadata.namespaceName, metadata.className), std::move(metadata)); } } void MonoScriptRuntime::DiscoverRenderPipelineAssetClassesInImage( const std::string& assemblyName, MonoImage* image) { if (!image || m_scriptableRenderPipelineAssetClass == nullptr) { return; } const int typeCount = mono_image_get_table_rows(image, MONO_TABLE_TYPEDEF); for (int index = 1; index <= typeCount; ++index) { const uint32_t typeToken = mono_metadata_make_token(MONO_TABLE_TYPEDEF, index); MonoClass* monoClass = mono_class_get(image, typeToken); if (monoClass == nullptr || monoClass == m_scriptableRenderPipelineAssetClass || !IsMonoClassOrSubclass( monoClass, m_scriptableRenderPipelineAssetClass)) { continue; } if ((mono_class_get_flags(monoClass) & MONO_TYPE_ATTR_ABSTRACT) != 0) { continue; } const ScriptClassDescriptor descriptor{ assemblyName, SafeString(mono_class_get_namespace(monoClass)), SafeString(mono_class_get_name(monoClass))}; if (std::find( m_renderPipelineAssetClasses.begin(), m_renderPipelineAssetClasses.end(), descriptor) == m_renderPipelineAssetClasses.end()) { m_renderPipelineAssetClasses.push_back(descriptor); } } } bool MonoScriptRuntime::IsMonoBehaviourSubclass(MonoClass* monoClass) const { if (!monoClass || !m_monoBehaviourClass || monoClass == m_monoBehaviourClass) { return false; } MonoClass* current = monoClass; while (current) { if (current == m_monoBehaviourClass) { return true; } current = mono_class_get_parent(current); } return false; } bool MonoScriptRuntime::IsSupportedComponentFieldClass(MonoClass* monoClass) const { if (!IsMonoClassOrSubclass(monoClass, m_componentClass)) { return false; } if (monoClass == m_componentClass || monoClass == m_behaviourClass || monoClass == m_monoBehaviourClass) { return false; } if (IsScriptComponentFieldClass(monoClass)) { return true; } const std::string namespaceName = SafeString(mono_class_get_namespace(monoClass)); const std::string className = SafeString(mono_class_get_name(monoClass)); if (namespaceName != m_settings.baseNamespace) { return false; } return className == "Transform" || className == "Rigidbody" || className == "Camera" || className == "Light" || className == "MeshFilter" || className == "MeshRenderer"; } bool MonoScriptRuntime::IsScriptComponentFieldClass(MonoClass* monoClass) const { if (!monoClass || monoClass == m_monoBehaviourClass) { return false; } return IsMonoClassOrSubclass(monoClass, m_monoBehaviourClass); } bool MonoScriptRuntime::HasSerializeFieldAttribute(MonoClassField* field) const { if (!field || !m_serializeFieldAttributeClass) { return false; } MonoClass* ownerClass = mono_field_get_parent(field); if (!ownerClass) { return false; } MonoCustomAttrInfo* attributes = mono_custom_attrs_from_field(ownerClass, field); if (!attributes) { return false; } const mono_bool hasAttribute = mono_custom_attrs_has_attr(attributes, m_serializeFieldAttributeClass); mono_custom_attrs_free(attributes); return hasAttribute != 0; } MonoScriptRuntime::FieldMetadata MonoScriptRuntime::BuildFieldMetadata(MonoClassField* field) const { FieldMetadata metadata; metadata.field = field; if (!field) { return metadata; } MonoType* monoType = mono_field_get_type(field); if (!monoType) { return metadata; } switch (mono_type_get_type(monoType)) { case MONO_TYPE_R4: metadata.type = ScriptFieldType::Float; return metadata; case MONO_TYPE_R8: metadata.type = ScriptFieldType::Double; return metadata; case MONO_TYPE_BOOLEAN: metadata.type = ScriptFieldType::Bool; return metadata; case MONO_TYPE_I4: metadata.type = ScriptFieldType::Int32; return metadata; case MONO_TYPE_U8: metadata.type = ScriptFieldType::UInt64; return metadata; case MONO_TYPE_STRING: metadata.type = ScriptFieldType::String; return metadata; case MONO_TYPE_CLASS: { MonoClass* referenceClass = mono_class_from_mono_type(monoType); if (!referenceClass) { return metadata; } const std::string namespaceName = SafeString(mono_class_get_namespace(referenceClass)); const std::string className = SafeString(mono_class_get_name(referenceClass)); if (namespaceName == m_settings.baseNamespace && className == "GameObject") { metadata.type = ScriptFieldType::GameObject; return metadata; } if (IsSupportedComponentFieldClass(referenceClass)) { metadata.type = ScriptFieldType::Component; metadata.componentClass = referenceClass; } return metadata; } case MONO_TYPE_VALUETYPE: { MonoClass* valueTypeClass = mono_class_from_mono_type(monoType); if (!valueTypeClass) { return metadata; } if (mono_class_is_enum(valueTypeClass) != 0) { MonoType* underlyingType = mono_class_enum_basetype(valueTypeClass); if (!underlyingType) { return metadata; } switch (mono_type_get_type(underlyingType)) { case MONO_TYPE_I1: case MONO_TYPE_U1: case MONO_TYPE_I2: case MONO_TYPE_U2: case MONO_TYPE_I4: case MONO_TYPE_U4: metadata.type = ScriptFieldType::Int32; metadata.isEnum = true; metadata.enumUnderlyingType = static_cast(mono_type_get_type(underlyingType)); return metadata; default: return metadata; } } const std::string namespaceName = SafeString(mono_class_get_namespace(valueTypeClass)); const std::string className = SafeString(mono_class_get_name(valueTypeClass)); if (namespaceName != m_settings.baseNamespace) { return metadata; } if (className == "Vector2") { metadata.type = ScriptFieldType::Vector2; return metadata; } if (className == "Vector3") { metadata.type = ScriptFieldType::Vector3; return metadata; } if (className == "Vector4") { metadata.type = ScriptFieldType::Vector4; return metadata; } return metadata; } default: return metadata; } } const char* MonoScriptRuntime::ToLifecycleMethodName(ScriptLifecycleMethod method) { switch (method) { case ScriptLifecycleMethod::Awake: return "Awake"; case ScriptLifecycleMethod::OnEnable: return "OnEnable"; case ScriptLifecycleMethod::Start: return "Start"; case ScriptLifecycleMethod::FixedUpdate: return "FixedUpdate"; case ScriptLifecycleMethod::Update: return "Update"; case ScriptLifecycleMethod::LateUpdate: return "LateUpdate"; case ScriptLifecycleMethod::OnDisable: return "OnDisable"; case ScriptLifecycleMethod::OnDestroy: return "OnDestroy"; } return ""; } const char* MonoScriptRuntime::ToPhysicsMessageMethodName(ScriptPhysicsMessage message) { switch (message) { case ScriptPhysicsMessage::CollisionEnter: return "OnCollisionEnter"; case ScriptPhysicsMessage::CollisionStay: return "OnCollisionStay"; case ScriptPhysicsMessage::CollisionExit: return "OnCollisionExit"; case ScriptPhysicsMessage::TriggerEnter: return "OnTriggerEnter"; case ScriptPhysicsMessage::TriggerStay: return "OnTriggerStay"; case ScriptPhysicsMessage::TriggerExit: return "OnTriggerExit"; } return ""; } const MonoScriptRuntime::ClassMetadata* MonoScriptRuntime::FindClassMetadata( const std::string& assemblyName, const std::string& namespaceName, const std::string& className) const { const auto it = m_classes.find(BuildClassKey(assemblyName, namespaceName, className)); return it != m_classes.end() ? &it->second : nullptr; } bool MonoScriptRuntime::ResolveManagedClass( const std::string& assemblyName, const std::string& namespaceName, const std::string& className, MonoClass*& outClass) const { outClass = nullptr; if (!m_initialized || assemblyName.empty() || className.empty()) { return false; } MonoImage* image = FindLoadedAssemblyImage(assemblyName); if (!image) { return false; } SetCurrentDomain(); outClass = mono_class_from_name( image, namespaceName.c_str(), className.c_str()); return outClass != nullptr; } bool MonoScriptRuntime::CreateExternalManagedObject( const std::string& assemblyName, const std::string& namespaceName, const std::string& className, uint32_t& outHandle) { outHandle = 0; MonoClass* monoClass = nullptr; if (!ResolveManagedClass( assemblyName, namespaceName, className, monoClass)) { SetError( "Managed class was not found: " + assemblyName + "|" + BuildFullClassName(namespaceName, className)); return false; } return CreateExternalManagedObject(monoClass, outHandle); } bool MonoScriptRuntime::CreateExternalManagedObject( MonoClass* monoClass, uint32_t& outHandle) { outHandle = 0; if (!m_initialized || !monoClass) { return false; } SetCurrentDomain(); MonoObject* const instance = mono_object_new(m_appDomain, monoClass); if (!instance) { SetError( "Mono failed to allocate a managed object for " + BuildFullClassName( SafeString(mono_class_get_namespace(monoClass)), SafeString(mono_class_get_name(monoClass))) + "."); return false; } mono_runtime_object_init(instance); outHandle = RetainExternalManagedObject(instance); return outHandle != 0; } uint32_t MonoScriptRuntime::RetainExternalManagedObject(MonoObject* instance) { if (!m_initialized || !instance) { return 0; } SetCurrentDomain(); const uint32_t gcHandle = mono_gchandle_new(instance, false); if (gcHandle == 0) { return 0; } m_externalManagedObjects[gcHandle] = ExternalManagedObjectData{ mono_object_get_class(instance), gcHandle }; return gcHandle; } MonoObject* MonoScriptRuntime::GetExternalManagedObject(uint32_t gcHandle) const { return GetManagedObject(gcHandle); } uint32_t MonoScriptRuntime::RetainExternalManagedObjectReference( MonoObject* managedObject) { return RetainExternalManagedObject(managedObject); } void MonoScriptRuntime::ReleaseExternalManagedObject(uint32_t gcHandle) { DestroyExternalManagedObject(gcHandle); } bool MonoScriptRuntime::IsScriptableRenderPipelineAssetObject( MonoObject* managedObject) const { return managedObject != nullptr && m_scriptableRenderPipelineAssetClass != nullptr && IsMonoClassOrSubclass( mono_object_get_class(managedObject), m_scriptableRenderPipelineAssetClass); } bool MonoScriptRuntime::TryEnsureManagedRenderPipelineAssetHandle( Rendering::Pipelines::ManagedRenderPipelineAssetDescriptor& ioDescriptor) { if (!m_initialized || !ioDescriptor.IsValid()) { return false; } if (ioDescriptor.managedAssetHandle != 0u) { MonoObject* const assetObject = GetExternalManagedObject(ioDescriptor.managedAssetHandle); if (IsScriptableRenderPipelineAssetObject(assetObject)) { return true; } ioDescriptor.managedAssetHandle = 0u; } MonoClass* assetClass = nullptr; if (!ResolveManagedClass( ioDescriptor.assemblyName, ioDescriptor.namespaceName, ioDescriptor.className, assetClass) || assetClass == nullptr) { return false; } if (!IsMonoClassOrSubclass( assetClass, m_scriptableRenderPipelineAssetClass)) { SetError( "Managed render pipeline asset must derive from ScriptableRenderPipelineAsset: " + ioDescriptor.GetFullName() + "."); return false; } return CreateExternalManagedObject(assetClass, ioDescriptor.managedAssetHandle) && ioDescriptor.managedAssetHandle != 0u; } void MonoScriptRuntime::DestroyExternalManagedObject(uint32_t gcHandle) { if (gcHandle == 0) { return; } const auto it = m_externalManagedObjects.find(gcHandle); if (it == m_externalManagedObjects.end()) { return; } SetCurrentDomain(); mono_gchandle_free(gcHandle); m_externalManagedObjects.erase(it); } MonoObject* MonoScriptRuntime::CreateManagedScriptableRenderContext( uint64_t nativeHandle) { if (!m_initialized || nativeHandle == 0 || m_scriptableRenderContextClass == nullptr || m_scriptableRenderContextConstructor == nullptr) { return nullptr; } SetCurrentDomain(); MonoObject* const contextObject = mono_object_new(m_appDomain, m_scriptableRenderContextClass); if (contextObject == nullptr) { SetError( "Mono failed to allocate a managed ScriptableRenderContext."); return nullptr; } void* args[1]; uint64_t nativeHandleArgument = nativeHandle; args[0] = &nativeHandleArgument; MonoObject* exception = nullptr; mono_runtime_invoke( m_scriptableRenderContextConstructor, contextObject, args, &exception); if (exception != nullptr) { RecordException(exception); return nullptr; } return contextObject; } MonoObject* MonoScriptRuntime::CreateManagedCameraRenderRequestContext( uint64_t nativeHandle) { if (!m_initialized || nativeHandle == 0 || m_cameraRenderRequestContextClass == nullptr || m_cameraRenderRequestContextConstructor == nullptr) { return nullptr; } SetCurrentDomain(); MonoObject* const contextObject = mono_object_new( m_appDomain, m_cameraRenderRequestContextClass); if (contextObject == nullptr) { SetError( "Mono failed to allocate a managed CameraRenderRequestContext."); return nullptr; } void* args[1]; uint64_t nativeHandleArgument = nativeHandle; args[0] = &nativeHandleArgument; MonoObject* exception = nullptr; mono_runtime_invoke( m_cameraRenderRequestContextConstructor, contextObject, args, &exception); if (exception != nullptr) { RecordException(exception); return nullptr; } return contextObject; } MonoObject* MonoScriptRuntime::CreateManagedRenderSceneSetupContext( uint64_t nativeHandle) { if (!m_initialized || nativeHandle == 0 || m_renderSceneSetupContextClass == nullptr || m_renderSceneSetupContextConstructor == nullptr) { return nullptr; } SetCurrentDomain(); MonoObject* const contextObject = mono_object_new( m_appDomain, m_renderSceneSetupContextClass); if (contextObject == nullptr) { SetError( "Mono failed to allocate a managed RenderSceneSetupContext."); return nullptr; } void* args[1]; uint64_t nativeHandleArgument = nativeHandle; args[0] = &nativeHandleArgument; MonoObject* exception = nullptr; mono_runtime_invoke( m_renderSceneSetupContextConstructor, contextObject, args, &exception); if (exception != nullptr) { RecordException(exception); return nullptr; } return contextObject; } MonoObject* MonoScriptRuntime::CreateManagedDirectionalShadowExecutionContext( uint64_t nativeHandle) { if (!m_initialized || nativeHandle == 0 || m_directionalShadowExecutionContextClass == nullptr || m_directionalShadowExecutionContextConstructor == nullptr) { return nullptr; } SetCurrentDomain(); MonoObject* const contextObject = mono_object_new( m_appDomain, m_directionalShadowExecutionContextClass); if (contextObject == nullptr) { SetError( "Mono failed to allocate a managed DirectionalShadowExecutionContext."); return nullptr; } void* args[1]; uint64_t nativeHandleArgument = nativeHandle; args[0] = &nativeHandleArgument; MonoObject* exception = nullptr; mono_runtime_invoke( m_directionalShadowExecutionContextConstructor, contextObject, args, &exception); if (exception != nullptr) { RecordException(exception); return nullptr; } return contextObject; } MonoObject* MonoScriptRuntime::CreateManagedScriptableRenderPipelinePlanningContext( uint64_t nativeHandle) { if (!m_initialized || nativeHandle == 0 || m_scriptableRenderPipelinePlanningContextClass == nullptr || m_scriptableRenderPipelinePlanningContextConstructor == nullptr) { return nullptr; } SetCurrentDomain(); MonoObject* const contextObject = mono_object_new( m_appDomain, m_scriptableRenderPipelinePlanningContextClass); if (contextObject == nullptr) { SetError( "Mono failed to allocate a managed ScriptableRenderPipelinePlanningContext."); return nullptr; } void* args[1]; uint64_t nativeHandleArgument = nativeHandle; args[0] = &nativeHandleArgument; MonoObject* exception = nullptr; mono_runtime_invoke( m_scriptableRenderPipelinePlanningContextConstructor, contextObject, args, &exception); if (exception != nullptr) { RecordException(exception); return nullptr; } return contextObject; } MonoScriptRuntime::InstanceData* MonoScriptRuntime::FindInstance(const ScriptRuntimeContext& context) { const auto it = m_instances.find(InstanceKey{context.gameObjectUUID, context.scriptComponentUUID}); return it != m_instances.end() ? &it->second : nullptr; } const MonoScriptRuntime::InstanceData* MonoScriptRuntime::FindInstance(const ScriptRuntimeContext& context) const { const auto it = m_instances.find(InstanceKey{context.gameObjectUUID, context.scriptComponentUUID}); return it != m_instances.end() ? &it->second : nullptr; } const MonoScriptRuntime::InstanceData* MonoScriptRuntime::FindInstance(const ScriptComponent* component) const { if (!component || !component->GetGameObject()) { return nullptr; } const auto it = m_instances.find(InstanceKey{ component->GetGameObject()->GetUUID(), component->GetScriptComponentUUID() }); return it != m_instances.end() ? &it->second : nullptr; } MonoObject* MonoScriptRuntime::GetManagedObject(const InstanceData& instanceData) const { if (instanceData.gcHandle == 0) { return nullptr; } SetCurrentDomain(); return mono_gchandle_get_target(instanceData.gcHandle); } MonoObject* MonoScriptRuntime::GetManagedObject(uint32_t gcHandle) const { if (gcHandle == 0 || m_externalManagedObjects.find(gcHandle) == m_externalManagedObjects.end()) { return nullptr; } SetCurrentDomain(); return mono_gchandle_get_target(gcHandle); } MonoMethod* MonoScriptRuntime::ResolveManagedMethod( MonoClass* monoClass, const char* methodName, int parameterCount) const { if (!monoClass || !methodName) { return nullptr; } SetCurrentDomain(); for (MonoClass* currentClass = monoClass; currentClass != nullptr; currentClass = mono_class_get_parent(currentClass)) { if (MonoMethod* const method = mono_class_get_method_from_name( currentClass, methodName, parameterCount); method != nullptr) { return method; } } return nullptr; } MonoMethod* MonoScriptRuntime::ResolveManagedMethod( MonoObject* instance, const char* methodName, int parameterCount) const { return instance != nullptr ? ResolveManagedMethod( mono_object_get_class(instance), methodName, parameterCount) : nullptr; } bool MonoScriptRuntime::ApplyContextFields(const ScriptRuntimeContext& context, MonoObject* instance) { if (!instance) { return false; } SetCurrentDomain(); if (m_gameObjectUUIDField) { uint64_t gameObjectUUID = context.gameObjectUUID; mono_field_set_value(instance, m_gameObjectUUIDField, &gameObjectUUID); } if (m_scriptComponentUUIDField) { uint64_t scriptComponentUUID = context.scriptComponentUUID; mono_field_set_value(instance, m_scriptComponentUUIDField, &scriptComponentUUID); } return true; } bool MonoScriptRuntime::ApplyStoredFields( const ScriptRuntimeContext& context, const ClassMetadata& metadata, MonoObject* instance) { if (!context.component || !instance) { return false; } const ScriptFieldStorage& fieldStorage = context.component->GetFieldStorage(); for (const std::string& fieldName : fieldStorage.GetFieldNames()) { const StoredScriptField* storedField = fieldStorage.FindField(fieldName); if (!storedField) { continue; } const auto metadataIt = metadata.fields.find(fieldName); if (metadataIt == metadata.fields.end() || storedField->type != metadataIt->second.type) { continue; } if (!TrySetFieldValue(instance, metadataIt->second, storedField->value)) { return false; } } return true; } MonoObject* MonoScriptRuntime::CreateManagedComponentWrapper(MonoClass* componentClass, uint64_t gameObjectUUID) { if (!m_initialized || !componentClass || gameObjectUUID == 0) { return nullptr; } SetCurrentDomain(); MonoMethod* constructor = mono_class_get_method_from_name(componentClass, ".ctor", 1); if (!constructor) { return nullptr; } MonoObject* managedObject = mono_object_new(m_appDomain, componentClass); if (!managedObject) { return nullptr; } void* args[1]; uint64_t uuidArgument = gameObjectUUID; args[0] = &uuidArgument; MonoObject* exception = nullptr; mono_runtime_invoke(constructor, managedObject, args, &exception); if (exception) { RecordException(exception); return nullptr; } return managedObject; } MonoObject* MonoScriptRuntime::CreateManagedGameObject(uint64_t gameObjectUUID) { if (gameObjectUUID == 0 || !m_gameObjectClass || !m_gameObjectConstructor) { return nullptr; } SetCurrentDomain(); MonoObject* managedObject = mono_object_new(m_appDomain, m_gameObjectClass); if (!managedObject) { return nullptr; } void* args[1]; uint64_t uuidArgument = gameObjectUUID; args[0] = &uuidArgument; MonoObject* exception = nullptr; mono_runtime_invoke(m_gameObjectConstructor, managedObject, args, &exception); if (exception) { RecordException(exception); return nullptr; } return managedObject; } bool MonoScriptRuntime::TryExtractComponentReference( MonoObject* managedObject, ComponentReference& outReference) const { outReference = ComponentReference{}; if (!managedObject) { return true; } if (!m_componentClass || !m_gameObjectUUIDField) { return false; } SetCurrentDomain(); MonoClass* monoClass = mono_object_get_class(managedObject); if (!IsMonoClassOrSubclass(monoClass, m_componentClass)) { return false; } uint64_t gameObjectUUID = 0; mono_field_get_value(managedObject, m_gameObjectUUIDField, &gameObjectUUID); if (gameObjectUUID == 0) { return false; } uint64_t scriptComponentUUID = 0; if (m_scriptComponentUUIDField && IsMonoClassOrSubclass(monoClass, m_behaviourClass)) { mono_field_get_value(managedObject, m_scriptComponentUUIDField, &scriptComponentUUID); } outReference = ComponentReference{gameObjectUUID, scriptComponentUUID}; return true; } bool MonoScriptRuntime::DestroyManagedObject(MonoObject* managedObject) { if (!m_initialized || !managedObject) { return false; } SetCurrentDomain(); MonoClass* monoClass = mono_object_get_class(managedObject); if (!monoClass) { return false; } if (monoClass == m_gameObjectClass) { uint64_t gameObjectUUID = 0; mono_field_get_value(managedObject, m_managedGameObjectUUIDField, &gameObjectUUID); Components::Scene* scene = GetInternalCallScene(); Components::GameObject* gameObject = FindGameObjectByUUID(gameObjectUUID); if (!scene || !gameObject || gameObject->GetScene() != scene) { return false; } scene->DestroyGameObject(gameObject); return true; } if (monoClass != m_componentClass && !mono_class_is_subclass_of(monoClass, m_componentClass, false)) { return false; } uint64_t gameObjectUUID = 0; mono_field_get_value(managedObject, m_gameObjectUUIDField, &gameObjectUUID); Components::GameObject* gameObject = FindGameObjectByUUID(gameObjectUUID); if (!gameObject) { return false; } if (monoClass == m_behaviourClass || mono_class_is_subclass_of(monoClass, m_behaviourClass, false)) { uint64_t scriptComponentUUID = 0; mono_field_get_value(managedObject, m_scriptComponentUUIDField, &scriptComponentUUID); if (scriptComponentUUID != 0) { ScriptComponent* component = FindScriptComponentByUUID(scriptComponentUUID); return DestroyNativeComponentInstance(gameObject, component); } } const ManagedComponentTypeInfo typeInfo = ResolveManagedComponentTypeInfo(monoClass); switch (typeInfo.kind) { case ManagedComponentKind::Rigidbody: return DestroyNativeComponentInstance(gameObject, gameObject->GetComponent()); case ManagedComponentKind::Camera: return DestroyNativeComponentInstance(gameObject, gameObject->GetComponent()); case ManagedComponentKind::Light: return DestroyNativeComponentInstance(gameObject, gameObject->GetComponent()); case ManagedComponentKind::MeshFilter: return DestroyNativeComponentInstance(gameObject, gameObject->GetComponent()); case ManagedComponentKind::MeshRenderer: return DestroyNativeComponentInstance(gameObject, gameObject->GetComponent()); case ManagedComponentKind::Transform: case ManagedComponentKind::Script: case ManagedComponentKind::Unknown: return false; } return false; } bool MonoScriptRuntime::TryExtractGameObjectReference( MonoObject* managedObject, GameObjectReference& outReference) const { outReference = GameObjectReference{}; if (!managedObject) { return true; } if (!m_gameObjectClass || !m_managedGameObjectUUIDField) { return false; } if (mono_object_get_class(managedObject) != m_gameObjectClass) { return false; } uint64_t gameObjectUUID = 0; mono_field_get_value(managedObject, m_managedGameObjectUUIDField, &gameObjectUUID); outReference = GameObjectReference{gameObjectUUID}; return true; } bool MonoScriptRuntime::TrySetFieldValue( MonoObject* instance, const FieldMetadata& fieldMetadata, const ScriptFieldValue& value) { if (!instance || !fieldMetadata.field) { return false; } SetCurrentDomain(); if (fieldMetadata.isEnum) { if (!std::holds_alternative(value)) { return false; } const int32_t storedValue = std::get(value); switch (fieldMetadata.enumUnderlyingType) { case MONO_TYPE_I1: { if (storedValue < std::numeric_limits::min() || storedValue > std::numeric_limits::max()) { return false; } int8_t nativeValue = static_cast(storedValue); mono_field_set_value(instance, fieldMetadata.field, &nativeValue); return true; } case MONO_TYPE_U1: { if (storedValue < 0 || storedValue > std::numeric_limits::max()) { return false; } uint8_t nativeValue = static_cast(storedValue); mono_field_set_value(instance, fieldMetadata.field, &nativeValue); return true; } case MONO_TYPE_I2: { if (storedValue < std::numeric_limits::min() || storedValue > std::numeric_limits::max()) { return false; } int16_t nativeValue = static_cast(storedValue); mono_field_set_value(instance, fieldMetadata.field, &nativeValue); return true; } case MONO_TYPE_U2: { if (storedValue < 0 || storedValue > std::numeric_limits::max()) { return false; } uint16_t nativeValue = static_cast(storedValue); mono_field_set_value(instance, fieldMetadata.field, &nativeValue); return true; } case MONO_TYPE_I4: { int32_t nativeValue = storedValue; mono_field_set_value(instance, fieldMetadata.field, &nativeValue); return true; } case MONO_TYPE_U4: { if (storedValue < 0) { return false; } uint32_t nativeValue = static_cast(storedValue); mono_field_set_value(instance, fieldMetadata.field, &nativeValue); return true; } default: return false; } } switch (fieldMetadata.type) { case ScriptFieldType::Float: { float nativeValue = std::get(value); mono_field_set_value(instance, fieldMetadata.field, &nativeValue); return true; } case ScriptFieldType::Double: { double nativeValue = std::get(value); mono_field_set_value(instance, fieldMetadata.field, &nativeValue); return true; } case ScriptFieldType::Bool: { mono_bool nativeValue = std::get(value) ? 1 : 0; mono_field_set_value(instance, fieldMetadata.field, &nativeValue); return true; } case ScriptFieldType::Int32: { int32_t nativeValue = std::get(value); mono_field_set_value(instance, fieldMetadata.field, &nativeValue); return true; } case ScriptFieldType::UInt64: { uint64_t nativeValue = std::get(value); mono_field_set_value(instance, fieldMetadata.field, &nativeValue); return true; } case ScriptFieldType::String: { MonoString* managedString = mono_string_new(m_appDomain, std::get(value).c_str()); mono_field_set_value(instance, fieldMetadata.field, managedString); return true; } case ScriptFieldType::Vector2: { Math::Vector2 nativeValue = std::get(value); mono_field_set_value(instance, fieldMetadata.field, &nativeValue); return true; } case ScriptFieldType::Vector3: { Math::Vector3 nativeValue = std::get(value); mono_field_set_value(instance, fieldMetadata.field, &nativeValue); return true; } case ScriptFieldType::Vector4: { Math::Vector4 nativeValue = std::get(value); mono_field_set_value(instance, fieldMetadata.field, &nativeValue); return true; } case ScriptFieldType::GameObject: { const GameObjectReference reference = std::get(value); MonoObject* managedGameObject = CreateManagedGameObject(reference.gameObjectUUID); if (reference.gameObjectUUID != 0 && !managedGameObject) { return false; } mono_field_set_value(instance, fieldMetadata.field, managedGameObject); return true; } case ScriptFieldType::Component: { const ComponentReference reference = std::get(value); if (reference.gameObjectUUID == 0 && reference.scriptComponentUUID == 0) { mono_field_set_value(instance, fieldMetadata.field, nullptr); return true; } if (!fieldMetadata.componentClass) { return false; } MonoObject* managedComponent = nullptr; if (IsScriptComponentFieldClass(fieldMetadata.componentClass)) { if (reference.gameObjectUUID == 0 || reference.scriptComponentUUID == 0) { return false; } ScriptComponent* component = FindScriptComponentByUUID(reference.scriptComponentUUID); if (!component || !component->GetGameObject() || component->GetGameObject()->GetUUID() != reference.gameObjectUUID || component->GetAssemblyName() != m_settings.appAssemblyName || component->GetNamespaceName() != SafeString(mono_class_get_namespace(fieldMetadata.componentClass)) || component->GetClassName() != SafeString(mono_class_get_name(fieldMetadata.componentClass))) { return false; } if (!HasManagedInstance(component)) { ScriptEngine::Get().OnScriptComponentEnabled(component); } managedComponent = GetManagedInstanceObject(component); if (!managedComponent) { return false; } } else { if (reference.gameObjectUUID == 0 || reference.scriptComponentUUID != 0) { return false; } Components::GameObject* targetObject = FindGameObjectByUUID(reference.gameObjectUUID); if (!targetObject) { return false; } const std::string namespaceName = SafeString(mono_class_get_namespace(fieldMetadata.componentClass)); const std::string className = SafeString(mono_class_get_name(fieldMetadata.componentClass)); if (namespaceName != m_settings.baseNamespace) { return false; } bool hasComponent = false; if (className == "Transform") { hasComponent = targetObject->GetTransform() != nullptr; } else if (className == "Rigidbody") { hasComponent = targetObject->GetComponent() != nullptr; } else if (className == "Camera") { hasComponent = targetObject->GetComponent() != nullptr; } else if (className == "Light") { hasComponent = targetObject->GetComponent() != nullptr; } else if (className == "MeshFilter") { hasComponent = targetObject->GetComponent() != nullptr; } else if (className == "MeshRenderer") { hasComponent = targetObject->GetComponent() != nullptr; } else { return false; } if (!hasComponent) { return false; } managedComponent = CreateManagedComponentWrapper(fieldMetadata.componentClass, reference.gameObjectUUID); if (!managedComponent) { return false; } } mono_field_set_value(instance, fieldMetadata.field, managedComponent); return true; } case ScriptFieldType::None: return false; } return false; } bool MonoScriptRuntime::TryReadFieldValue( MonoObject* instance, const FieldMetadata& fieldMetadata, ScriptFieldValue& outValue) const { if (!instance || !fieldMetadata.field) { return false; } if (fieldMetadata.isEnum) { switch (fieldMetadata.enumUnderlyingType) { case MONO_TYPE_I1: { int8_t nativeValue = 0; mono_field_get_value(instance, fieldMetadata.field, &nativeValue); outValue = static_cast(nativeValue); return true; } case MONO_TYPE_U1: { uint8_t nativeValue = 0; mono_field_get_value(instance, fieldMetadata.field, &nativeValue); outValue = static_cast(nativeValue); return true; } case MONO_TYPE_I2: { int16_t nativeValue = 0; mono_field_get_value(instance, fieldMetadata.field, &nativeValue); outValue = static_cast(nativeValue); return true; } case MONO_TYPE_U2: { uint16_t nativeValue = 0; mono_field_get_value(instance, fieldMetadata.field, &nativeValue); outValue = static_cast(nativeValue); return true; } case MONO_TYPE_I4: { int32_t nativeValue = 0; mono_field_get_value(instance, fieldMetadata.field, &nativeValue); outValue = nativeValue; return true; } case MONO_TYPE_U4: { uint32_t nativeValue = 0; mono_field_get_value(instance, fieldMetadata.field, &nativeValue); if (nativeValue > static_cast(std::numeric_limits::max())) { return false; } outValue = static_cast(nativeValue); return true; } default: return false; } } switch (fieldMetadata.type) { case ScriptFieldType::Float: { float nativeValue = 0.0f; mono_field_get_value(instance, fieldMetadata.field, &nativeValue); outValue = nativeValue; return true; } case ScriptFieldType::Double: { double nativeValue = 0.0; mono_field_get_value(instance, fieldMetadata.field, &nativeValue); outValue = nativeValue; return true; } case ScriptFieldType::Bool: { mono_bool nativeValue = 0; mono_field_get_value(instance, fieldMetadata.field, &nativeValue); outValue = (nativeValue != 0); return true; } case ScriptFieldType::Int32: { int32_t nativeValue = 0; mono_field_get_value(instance, fieldMetadata.field, &nativeValue); outValue = nativeValue; return true; } case ScriptFieldType::UInt64: { uint64_t nativeValue = 0; mono_field_get_value(instance, fieldMetadata.field, &nativeValue); outValue = nativeValue; return true; } case ScriptFieldType::String: { MonoObject* managedObject = mono_field_get_value_object(m_appDomain, fieldMetadata.field, instance); if (!managedObject) { outValue = std::string(); return true; } MonoString* managedString = reinterpret_cast(managedObject); char* utf8 = mono_string_to_utf8(managedString); outValue = utf8 ? std::string(utf8) : std::string(); if (utf8) { mono_free(utf8); } return true; } case ScriptFieldType::Vector2: { Math::Vector2 nativeValue; mono_field_get_value(instance, fieldMetadata.field, &nativeValue); outValue = nativeValue; return true; } case ScriptFieldType::Vector3: { Math::Vector3 nativeValue; mono_field_get_value(instance, fieldMetadata.field, &nativeValue); outValue = nativeValue; return true; } case ScriptFieldType::Vector4: { Math::Vector4 nativeValue; mono_field_get_value(instance, fieldMetadata.field, &nativeValue); outValue = nativeValue; return true; } case ScriptFieldType::GameObject: { MonoObject* managedObject = mono_field_get_value_object(m_appDomain, fieldMetadata.field, instance); GameObjectReference reference; if (!TryExtractGameObjectReference(managedObject, reference)) { return false; } outValue = reference; return true; } case ScriptFieldType::Component: { MonoObject* managedObject = mono_field_get_value_object(m_appDomain, fieldMetadata.field, instance); ComponentReference reference; if (!TryExtractComponentReference(managedObject, reference)) { return false; } outValue = reference; return true; } case ScriptFieldType::None: return false; } return false; } void MonoScriptRuntime::ClearManagedInstances() { for (auto& [key, instanceData] : m_instances) { (void)key; if (instanceData.gcHandle != 0) { mono_gchandle_free(instanceData.gcHandle); } } m_instances.clear(); } void MonoScriptRuntime::ClearExternalManagedObjects() { for (auto& [gcHandle, objectData] : m_externalManagedObjects) { (void)objectData; if (gcHandle != 0) { mono_gchandle_free(gcHandle); } } m_externalManagedObjects.clear(); } void MonoScriptRuntime::ClearClassCache() { m_classes.clear(); m_renderPipelineAssetClasses.clear(); } MonoImage* MonoScriptRuntime::FindLoadedAssemblyImage( const std::string& assemblyName) const { const auto it = m_loadedManagedAssemblies.find(assemblyName); return it != m_loadedManagedAssemblies.end() ? it->second.image : nullptr; } bool MonoScriptRuntime::InvokeManagedMethod( MonoObject* instance, MonoMethod* method, void** args, MonoObject** outReturnValue) { if (!instance || !method) { if (outReturnValue) { *outReturnValue = nullptr; } return false; } SetCurrentDomain(); MonoObject* exception = nullptr; MonoObject* returnValue = mono_runtime_invoke(method, instance, args, &exception); if (exception) { if (outReturnValue) { *outReturnValue = nullptr; } RecordException(exception); return false; } if (outReturnValue) { *outReturnValue = returnValue; } return true; } void MonoScriptRuntime::RecordException(MonoObject* exception) { m_lastError = "Managed exception"; if (!exception) { return; } MonoObject* secondaryException = nullptr; MonoString* exceptionString = mono_object_to_string(exception, &secondaryException); if (!exceptionString || secondaryException) { return; } char* utf8 = mono_string_to_utf8(exceptionString); if (!utf8) { return; } m_lastError = utf8; mono_free(utf8); } void MonoScriptRuntime::SetError(const std::string& error) { m_lastError = error; } } // namespace Scripting } // namespace XCEngine