feat(physics): dispatch PhysX simulation events to scene scripts

This commit is contained in:
2026-04-15 13:36:39 +08:00
parent 077786e4c7
commit 51aea47c83
20 changed files with 955 additions and 7 deletions

View File

@@ -2097,10 +2097,46 @@ void MonoScriptRuntime::InvokeMethod(
const float previousDeltaTime = GetInternalCallDeltaTime();
GetInternalCallDeltaTime() = deltaTime;
InvokeManagedMethod(instance, managedMethod);
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<size_t>(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<uint64_t>{}(key.gameObjectUUID);
const size_t h2 = std::hash<uint64_t>{}(key.scriptComponentUUID);
@@ -2346,6 +2382,18 @@ void MonoScriptRuntime::DiscoverScriptClassesInImage(const std::string& assembly
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<ScriptPhysicsMessage>(methodIndex)),
1);
methods.withoutArgs = mono_class_get_method_from_name(
monoClass,
ToPhysicsMessageMethodName(static_cast<ScriptPhysicsMessage>(methodIndex)),
0);
}
void* fieldIterator = nullptr;
while (MonoClassField* field = mono_class_get_fields(monoClass, &fieldIterator)) {
const uint32_t fieldFlags = mono_field_get_flags(field);
@@ -2564,6 +2612,19 @@ const char* MonoScriptRuntime::ToLifecycleMethodName(ScriptLifecycleMethod metho
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,
@@ -3207,7 +3268,7 @@ void MonoScriptRuntime::ClearClassCache() {
m_classes.clear();
}
bool MonoScriptRuntime::InvokeManagedMethod(MonoObject* instance, MonoMethod* method) {
bool MonoScriptRuntime::InvokeManagedMethod(MonoObject* instance, MonoMethod* method, void** args) {
if (!instance || !method) {
return false;
}
@@ -3215,7 +3276,7 @@ bool MonoScriptRuntime::InvokeManagedMethod(MonoObject* instance, MonoMethod* me
SetCurrentDomain();
MonoObject* exception = nullptr;
mono_runtime_invoke(method, instance, nullptr, &exception);
mono_runtime_invoke(method, instance, args, &exception);
if (exception) {
RecordException(exception);
return false;

View File

@@ -82,5 +82,14 @@ void NullScriptRuntime::InvokeMethod(
(void)deltaTime;
}
void NullScriptRuntime::InvokePhysicsMessage(
const ScriptRuntimeContext& context,
ScriptPhysicsMessage message,
Components::GameObject* other) {
(void)context;
(void)message;
(void)other;
}
} // namespace Scripting
} // namespace XCEngine

View File

@@ -258,6 +258,28 @@ void ScriptEngine::OnLateUpdate(float deltaTime) {
}
}
void ScriptEngine::DispatchPhysicsMessage(
Components::GameObject* gameObject,
ScriptPhysicsMessage message,
Components::GameObject* other) {
if (!m_runtimeRunning || !gameObject) {
return;
}
for (ScriptComponent* component : gameObject->GetComponents<ScriptComponent>()) {
if (!component) {
continue;
}
ScriptInstanceState* state = FindState(component);
if (!state || !ShouldScriptRun(*state) || !EnsureScriptReady(*state, true) || !state->enabled) {
continue;
}
InvokePhysicsMessage(*state, message, other);
}
}
void ScriptEngine::OnScriptComponentEnabled(ScriptComponent* component) {
if (!m_runtimeRunning || !component) {
return;
@@ -887,6 +909,14 @@ void ScriptEngine::InvokeLifecycleMethod(ScriptInstanceState& state, ScriptLifec
m_runtime->SyncManagedFieldsToStorage(state.context);
}
void ScriptEngine::InvokePhysicsMessage(
ScriptInstanceState& state,
ScriptPhysicsMessage message,
Components::GameObject* other) {
m_runtime->InvokePhysicsMessage(state.context, message, other);
m_runtime->SyncManagedFieldsToStorage(state.context);
}
void ScriptEngine::StopTrackingScript(ScriptInstanceState& state, bool runtimeStopping) {
if (state.enabled) {
InvokeLifecycleMethod(state, ScriptLifecycleMethod::OnDisable);