Start and Stop script runtime for editor scene

This commit is contained in:
Simon Lübeß
2023-12-03 14:06:40 +01:00
parent aaa48158c3
commit 1238a43896
3 changed files with 110 additions and 56 deletions
+38 -10
View File
@@ -864,6 +864,8 @@ namespace GlitchyEditor
/// Starts the play mode for the current scene /// Starts the play mode for the current scene
private void OnScenePlay() private void OnScenePlay()
{ {
// TODO: Dictionary<UUID, ScriptData> scriptData = _editorScene.SerializeScripts();
_editor.SceneViewportWindow.EditorMode = false; _editor.SceneViewportWindow.EditorMode = false;
_sceneState = .Play; _sceneState = .Play;
@@ -871,9 +873,9 @@ namespace GlitchyEditor
{ {
_editorScene.CopyTo(runtimeScene, true); _editorScene.CopyTo(runtimeScene, true);
runtimeScene.OnRuntimeStart(); SetActiveScene(runtimeScene, startRuntime: true, startSimulation: true);
SetReference!(_activeScene, runtimeScene); // TODO: runtimeScene.DeserializeScripts(scriptData);
} }
_editor.CurrentScene = _activeScene; _editor.CurrentScene = _activeScene;
@@ -882,6 +884,27 @@ namespace GlitchyEditor
SwitchToPlayWindow(); SwitchToPlayWindow();
} }
/// Activates the given scene.
/// @param scene The scene to be activated.
/// @param startRuntime If set to true, the script runtime will be initialized for the given scene.
/// @param startSimulation If set to true, the physics simulation will be initialized for the given scene.
private void SetActiveScene(Scene scene, bool startRuntime, bool startSimulation)
{
_activeScene?.StopRuntime();
_activeScene?.StopSimulation();
if (scene != null)
{
if (startRuntime)
scene.StartRuntime();
if (startSimulation)
scene.StartSimulation();
}
SetReference!(_activeScene, scene);
}
/// Starts the physics simulation mode for the current scene /// Starts the physics simulation mode for the current scene
private void OnSceneSimulate() private void OnSceneSimulate()
{ {
@@ -892,9 +915,7 @@ namespace GlitchyEditor
{ {
_editorScene.CopyTo(simulationScene, false); _editorScene.CopyTo(simulationScene, false);
simulationScene.OnSimulationStart(); SetActiveScene(simulationScene, startRuntime: false, startSimulation: true);
SetReference!(_activeScene, simulationScene);
} }
_editor.CurrentScene = _activeScene; _editor.CurrentScene = _activeScene;
@@ -930,12 +951,9 @@ namespace GlitchyEditor
/// Stops the simulation or game and returns to edit mode. /// Stops the simulation or game and returns to edit mode.
private void OnSceneStop() private void OnSceneStop()
{ {
if (_sceneState == .Play) SetActiveScene(_editorScene, startRuntime: true, startSimulation: false);
_activeScene.OnRuntimeStop();
else if (_sceneState == .Simulate)
_activeScene.OnSimulationStop();
SetReference!(_activeScene, _editorScene); // TODO: _editorScene.DeserializeScripts(scriptData);
_editor.SceneViewportWindow.EditorMode = true; _editor.SceneViewportWindow.EditorMode = true;
_sceneState = .Edit; _sceneState = .Edit;
@@ -985,9 +1003,19 @@ namespace GlitchyEditor
/// Sets the current editor scene /// Sets the current editor scene
private void SetEditorScene(Scene scene) private void SetEditorScene(Scene scene)
{ {
if (_editorScene != null)
{
_editorScene.StopRuntime();
}
SetReference!(_editorScene, scene); SetReference!(_editorScene, scene);
_editor.CurrentScene = _editorScene; _editor.CurrentScene = _editorScene;
SetReference!(_activeScene, _editorScene); SetReference!(_activeScene, _editorScene);
if (_editorScene != null)
{
_editorScene.StartRuntime();
}
} }
/// Creates a new default scene. /// Creates a new default scene.
+30 -7
View File
@@ -83,7 +83,12 @@ static class ScriptEngine
public static Dictionary<StringView, ScriptClass> EntityClasses => _entityScripts; public static Dictionary<StringView, ScriptClass> EntityClasses => _entityScripts;
public static Dictionary<StringView, ScriptClass> ComponentClasses => _componentClasses; public static Dictionary<StringView, ScriptClass> ComponentClasses => _componentClasses;
public static Scene Context => s_Context; /// Gets or sets the current scene context for the runtime.
public static Scene Context
{
get => s_Context;
private set => SetReference!(s_Context, value);
}
private static Dictionary<UUID, ScriptFieldMap> _entityFields = new .() ~ private static Dictionary<UUID, ScriptFieldMap> _entityFields = new .() ~
{ {
@@ -246,20 +251,38 @@ static class ScriptEngine
InitAssemblyWatcher(); InitAssemblyWatcher();
} }
public static void SetContext(Scene scene) /// Starts the script runtime and sets the context scene.
public static void StartRuntime(Scene context)
{ {
SetReference!(s_Context, scene); /// At the moment only set the context.
Debug.Assert(s_Context == null, "StartRuntime was called twice without StopRuntime in between!");
Context = context;
} }
public static void OnRuntimeStop() /// Stopts the script runtime and disposes of all script instances.
public static void StopRuntime()
{ {
for (var entry in _entityScriptInstances) if (Context == null)
{ {
entry.value?.ReleaseRef(); // There should be nothing to do, if we have no context
Debug.Assert(_entityScriptInstances.Count == 0, "There are script instances but no context scene.");
return;
}
for (let (id, instance) in _entityScriptInstances)
{
instance?.ReleaseRef();
Entity entity = Context.GetEntityByID(id);
// Remove Instance from script
ScriptComponent* script = entity.GetComponent<ScriptComponent>();
script.Instance = null;
} }
_entityScriptInstances.Clear(); _entityScriptInstances.Clear();
SetContext(null); Context = null;
} }
public static bool InitializeInstance(Entity entity, ScriptComponent* script) public static bool InitializeInstance(Entity entity, ScriptComponent* script)
+41 -38
View File
@@ -104,8 +104,11 @@ namespace GlitchyEngine.World
/// Copies all entities with their components to the given target-scene. /// Copies all entities with their components to the given target-scene.
/// @param target The scene that the entities are copied to. /// @param target The scene that the entities are copied to.
/// @param initializeScripts If true script instances will be initialized. /// @param copyScripts If true script components will be copied.
public void CopyTo(Scene target, bool initializeScripts) /// This is for simulation mode, where the script-components won't be executing, thus we don't copy them.
/// TODO: But in reality we still might want to have scripts, because the user might want to run some code, just not OnCreate/OnUpdate?
/// TODO: Honestly, I'm not quite sure what simulation mode is actually good for. Maybe we better just remove it?
public void CopyTo(Scene target, bool copyScripts)
{ {
// Copy entities // Copy entities
for (let sourceHandle in _ecsWorld.Enumerate()) for (let sourceHandle in _ecsWorld.Enumerate())
@@ -125,43 +128,21 @@ namespace GlitchyEngine.World
CopyComponents<CameraComponent>(this, target); CopyComponents<CameraComponent>(this, target);
CopyComponents<LightComponent>(this, target); CopyComponents<LightComponent>(this, target);
CopyComponents<Rigidbody2DComponent>(this, target); CopyComponents<Rigidbody2DComponent>(this, target);
CopyComponents<BoxCollider2DComponent>(this, target); CopyComponents<BoxCollider2DComponent>(this, target);
CopyComponents<CircleCollider2DComponent>(this, target); CopyComponents<CircleCollider2DComponent>(this, target);
CopyComponents<PolygonCollider2DComponent>(this, target); CopyComponents<PolygonCollider2DComponent>(this, target);
if (initializeScripts) if (copyScripts)
{ {
// Set context, so that constructors can correctly reference the scene for (let (sourceHandle, sourceScript) in _ecsWorld.Enumerate<ScriptComponent>())
ScriptEngine.SetContext(target);
//CopyComponents<NativeScriptComponent>(this, target);
// Copy ScriptComponents... needs extra handling for the script instances
for (let (sourceHandle, sourceComponent) in _ecsWorld.Enumerate<ScriptComponent>())
{ {
Entity sourceEntity = .(sourceHandle, this); Entity sourceEntity = .(sourceHandle, target);
Entity targetEntity = target.GetEntityByID(sourceEntity.UUID); Entity targetEntity = target.GetEntityByID(sourceEntity.UUID);
ScriptComponent* targetComponent = targetEntity.AddComponent<ScriptComponent>(); ScriptComponent* targetScript = targetEntity.AddComponent<ScriptComponent>();
targetComponent.ScriptClassName = sourceComponent.ScriptClassName; targetScript.ScriptClassName = sourceScript.ScriptClassName;
// 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(targetEntity, targetComponent);
}
// Copy values to entities.
// We do this in a separate loop because we might reference other entities.
// If we did it in a single loop these entities might not exist yet.
for (let (handle, script) in target._ecsWorld.Enumerate<ScriptComponent>())
{
Entity entity = .(handle, this);
if (script.Instance != null)
ScriptEngine.CopyEditorFieldsToInstance(entity, script);
} }
} }
@@ -221,21 +202,36 @@ namespace GlitchyEngine.World
} }
} }
public void OnRuntimeStart() public void Start(bool simulation, bool runtime)
{ {
OnSimulationStart(); if (simulation)
SetupPhysicsCallbacks(); StartSimulation();
ScriptEngine.SetContext(this);
} }
public void OnRuntimeStop() public void StartRuntime()
{ {
OnSimulationStop(); ScriptEngine.StartRuntime(this);
ScriptEngine.OnRuntimeStop();
// Initialize ScriptComponents
for (let (handle, scriptComponent) in _ecsWorld.Enumerate<ScriptComponent>())
{
Entity entity = .(handle, this);
// TODO: this returns false, if no script with ScriptClassName exists, we have to handle this case correctly
ScriptEngine.InitializeInstance(entity, scriptComponent);
}
} }
public void OnSimulationStart() public void StopRuntime()
{ {
ScriptEngine.StopRuntime();
}
public void StartSimulation()
{
// TODO: Add Setting for the user to define whether Physics will be initialized or not?
_physicsWorld2D = World.Create(_gravity2D); _physicsWorld2D = World.Create(_gravity2D);
draw.drawPolygonCallback = (vertices, vertexCount, color, userData) => draw.drawPolygonCallback = (vertices, vertexCount, color, userData) =>
@@ -289,6 +285,8 @@ namespace GlitchyEngine.World
World.SetDebugDrawFlags(_physicsWorld2D, .e_shapeBit); World.SetDebugDrawFlags(_physicsWorld2D, .e_shapeBit);
InitPhysics2D(); InitPhysics2D();
SetupPhysicsCallbacks();
} }
private void SetupPhysicsCallbacks() private void SetupPhysicsCallbacks()
@@ -590,10 +588,15 @@ namespace GlitchyEngine.World
polygonCollider.RuntimeFixture = fixture; polygonCollider.RuntimeFixture = fixture;
} }
public void OnSimulationStop() public void StopSimulation()
{ {
if (_physicsWorld2D == null)
return;
Box2D.World.Delete(_physicsWorld2D); Box2D.World.Delete(_physicsWorld2D);
_physicsWorld2D = null; _physicsWorld2D = null;
// TODO: Get rid of all references to colliders, etc. in physics components.
} }
public enum UpdateMode public enum UpdateMode