Entity Creation and Destruction from scripts

- ScriptEngine: Allow destroying scripts during runtime
- Scripting:
    - Create new entities using Constructors
    - Added Destroy functions for Entities
    - Added SetScript/RemoveScript functions for Entities
    - Allow adding multiple components at once
    - Added Is-Method
- Mono Wrapper: Added Array-Functions
- WorldEnumerator: Fixed crash due to dangling list pointer after entity creation
- Scene:
    - Basic create Rigidbodies during runtime
    - Start of entity copying (For runtime use)
    - Added DestroyEntityDeferred
- SceneSerializer:
    - Added option to assign new IDs to entities
This commit is contained in:
Simon Lübeß
2023-09-15 23:22:27 +02:00
parent ff54eb738e
commit 754c149493
9 changed files with 470 additions and 62 deletions
+1 -1
View File
@@ -383,7 +383,7 @@ class ScriptClass : SharpClass
{
MonoObject* instance = Mono.mono_object_new(ScriptEngine.[Friend]s_AppDomain, _monoClass);
// Invoke empty constructor to fill fields
// Invoke empty constructor to initialize fields with default values specified in the script itself
Mono.mono_runtime_object_init(instance);
// Invoke constructor with UUID
+19 -1
View File
@@ -238,7 +238,7 @@ static class ScriptEngine
{
for (var entry in _entityScriptInstances)
{
entry.value.ReleaseRef();
entry.value?.ReleaseRef();
}
_entityScriptInstances.Clear();
@@ -257,6 +257,9 @@ static class ScriptEngine
script.Instance = new ScriptInstance(entityId, scriptClass);
script.Instance..ReleaseRef();
if (_entityScriptInstances.TryGetValue(entityId, let currentInstance))
currentInstance.ReleaseRef();
_entityScriptInstances[entityId] = script.Instance..AddRef();
script.Instance.Instantiate(entityId);
@@ -264,6 +267,21 @@ static class ScriptEngine
return true;
}
public static void DestroyInstance(Entity entity, ScriptComponent* script)
{
UUID entityId = entity.UUID;
if (script.Instance != null)
script.Instance = null;
script.ScriptClassName = null;
if (_entityScriptInstances.TryGetValue(entityId, let currentInstance))
currentInstance.ReleaseRef();
_entityScriptInstances[entityId] = null;
}
public static void CopyEditorFieldsToInstance(Entity entity, ScriptComponent* script)
{
Log.EngineLogger.AssertDebug(script.Instance != null);
+91
View File
@@ -8,6 +8,7 @@ using GlitchyEngine.World;
using GlitchyEngine.Core;
using System.Collections;
using Box2D;
using GlitchyEngine.Scripting;
namespace GlitchyEngine.Scripting;
@@ -146,7 +147,56 @@ static class ScriptGlue
#endregion Input
#region Scene/Entity stuff
[RegisterCall("ScriptGlue::Entity_Create")]
static void Entity_Create(MonoObject* scriptInstance, MonoString* monoEntityName, MonoArray* componentTypes, out UUID entityId)
{
char8* entityName = Mono.mono_string_to_utf8(monoEntityName);
Entity entity = ScriptEngine.Context.CreateEntity(StringView(entityName));
Mono.mono_free(entityName);
entityId = entity.UUID;
// TODO: Script instance
if (componentTypes != null)
{
Entity_AddComponents(entityId, componentTypes);
}
}
[RegisterCall("ScriptGlue::Entity_Destroy")]
static void Entity_Destroy(UUID entityId)
{
Entity entity = ScriptEngine.Context.GetEntityByID(entityId);
ScriptEngine.Context.DestroyEntityDeferred(entity);
}
[RegisterCall("ScriptGlue::Entity_CreateInstance")]
static void Entity_CreateInstance(UUID entityId, out UUID newEntityId)
{
Entity entity = ScriptEngine.Context.GetEntityByID(entityId);
Entity newEntity = ScriptEngine.Context.CreateInstance(entity);
newEntityId = newEntity.UUID;
}
[RegisterCall("ScriptGlue::Entity_AddComponents")]
static void Entity_AddComponents(UUID entityId, MonoArray* componentTypes)
{
if (componentTypes == null)
return;
uint length = Mono.mono_array_length(componentTypes);
for (uint i < length)
{
MonoReflectionType* reflectionType = Mono.mono_array_get<MonoReflectionType*>(componentTypes, i);
Entity_AddComponent(entityId, reflectionType);
}
}
[RegisterCall("ScriptGlue::Entity_AddComponent")]
static void Entity_AddComponent(UUID entityId, MonoReflectionType* componentType)
{
@@ -208,6 +258,47 @@ static class ScriptGlue
return ScriptEngine.GetManagedInstance(entityId);
}
[RegisterCall("ScriptGlue::Entity_SetScript")]
static MonoObject* Entity_SetScript(UUID entityId, MonoReflectionType* scriptType)
{
Entity entity = ScriptEngine.Context.GetEntityByID(entityId);
if (!entity.HasComponent<ScriptComponent>())
{
entity.AddComponent<ScriptComponent>();
}
if (entity.TryGetComponent<ScriptComponent>(let scriptComponent))
{
scriptComponent.Instance = null;
MonoType* type = Mono.mono_reflection_type_get_type(scriptType);
scriptComponent.ScriptClassName = StringView(Mono.mono_type_full_name(type));
// Initializes the created instance
// TODO: this returns false, if no script with ScriptClassName exists, we have to handle this case correctly I think.
ScriptEngine.InitializeInstance(entity, scriptComponent);
return scriptComponent.Instance.MonoInstance;
}
return null;
}
[RegisterCall("ScriptGlue::Entity_RemoveScript")]
static void Entity_RemoveScript(UUID entityId)
{
Entity entity = ScriptEngine.Context.GetEntityByID(entityId);
if (entity.TryGetComponent<ScriptComponent>(let scriptComponent))
{
ScriptEngine.DestroyInstance(entity, scriptComponent);
entity.RemoveComponent<ScriptComponent>();
}
}
#endregion
#region TransformComponent