diff --git a/GlitchyEditor/src/EditorLayer.bf b/GlitchyEditor/src/EditorLayer.bf index a48bf90..e180351 100644 --- a/GlitchyEditor/src/EditorLayer.bf +++ b/GlitchyEditor/src/EditorLayer.bf @@ -864,6 +864,8 @@ namespace GlitchyEditor /// Starts the play mode for the current scene private void OnScenePlay() { + // TODO: Dictionary scriptData = _editorScene.SerializeScripts(); + _editor.SceneViewportWindow.EditorMode = false; _sceneState = .Play; @@ -871,9 +873,9 @@ namespace GlitchyEditor { _editorScene.CopyTo(runtimeScene, true); - runtimeScene.OnRuntimeStart(); + SetActiveScene(runtimeScene, startRuntime: true, startSimulation: true); - SetReference!(_activeScene, runtimeScene); + // TODO: runtimeScene.DeserializeScripts(scriptData); } _editor.CurrentScene = _activeScene; @@ -882,6 +884,27 @@ namespace GlitchyEditor 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 private void OnSceneSimulate() { @@ -892,9 +915,7 @@ namespace GlitchyEditor { _editorScene.CopyTo(simulationScene, false); - simulationScene.OnSimulationStart(); - - SetReference!(_activeScene, simulationScene); + SetActiveScene(simulationScene, startRuntime: false, startSimulation: true); } _editor.CurrentScene = _activeScene; @@ -930,12 +951,9 @@ namespace GlitchyEditor /// Stops the simulation or game and returns to edit mode. private void OnSceneStop() { - if (_sceneState == .Play) - _activeScene.OnRuntimeStop(); - else if (_sceneState == .Simulate) - _activeScene.OnSimulationStop(); + SetActiveScene(_editorScene, startRuntime: true, startSimulation: false); - SetReference!(_activeScene, _editorScene); + // TODO: _editorScene.DeserializeScripts(scriptData); _editor.SceneViewportWindow.EditorMode = true; _sceneState = .Edit; @@ -985,9 +1003,19 @@ namespace GlitchyEditor /// Sets the current editor scene private void SetEditorScene(Scene scene) { + if (_editorScene != null) + { + _editorScene.StopRuntime(); + } + SetReference!(_editorScene, scene); _editor.CurrentScene = _editorScene; SetReference!(_activeScene, _editorScene); + + if (_editorScene != null) + { + _editorScene.StartRuntime(); + } } /// Creates a new default scene. diff --git a/GlitchyEngine/src/Scripting/ScriptEngine.bf b/GlitchyEngine/src/Scripting/ScriptEngine.bf index 9167503..11f3c19 100644 --- a/GlitchyEngine/src/Scripting/ScriptEngine.bf +++ b/GlitchyEngine/src/Scripting/ScriptEngine.bf @@ -83,7 +83,12 @@ static class ScriptEngine public static Dictionary EntityClasses => _entityScripts; public static Dictionary 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 _entityFields = new .() ~ { @@ -246,20 +251,38 @@ static class ScriptEngine 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(); + script.Instance = null; } _entityScriptInstances.Clear(); - SetContext(null); + Context = null; } public static bool InitializeInstance(Entity entity, ScriptComponent* script) diff --git a/GlitchyEngine/src/World/Scene.bf b/GlitchyEngine/src/World/Scene.bf index 316cd4d..3a97832 100644 --- a/GlitchyEngine/src/World/Scene.bf +++ b/GlitchyEngine/src/World/Scene.bf @@ -104,8 +104,11 @@ namespace GlitchyEngine.World /// Copies all entities with their components to the given target-scene. /// @param target The scene that the entities are copied to. - /// @param initializeScripts If true script instances will be initialized. - public void CopyTo(Scene target, bool initializeScripts) + /// @param copyScripts If true script components will be copied. + /// 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 for (let sourceHandle in _ecsWorld.Enumerate()) @@ -124,47 +127,25 @@ namespace GlitchyEngine.World CopyComponents(this, target); CopyComponents(this, target); CopyComponents(this, target); - CopyComponents(this, target); CopyComponents(this, target); CopyComponents(this, target); CopyComponents(this, target); - if (initializeScripts) + if (copyScripts) { - // Set context, so that constructors can correctly reference the scene - ScriptEngine.SetContext(target); - - //CopyComponents(this, target); - - // Copy ScriptComponents... needs extra handling for the script instances - for (let (sourceHandle, sourceComponent) in _ecsWorld.Enumerate()) + for (let (sourceHandle, sourceScript) in _ecsWorld.Enumerate()) { - Entity sourceEntity = .(sourceHandle, this); + Entity sourceEntity = .(sourceHandle, target); Entity targetEntity = target.GetEntityByID(sourceEntity.UUID); - ScriptComponent* targetComponent = targetEntity.AddComponent(); - - targetComponent.ScriptClassName = sourceComponent.ScriptClassName; + ScriptComponent* targetScript = targetEntity.AddComponent(); - // 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()) - { - Entity entity = .(handle, this); - - if (script.Instance != null) - ScriptEngine.CopyEditorFieldsToInstance(entity, script); + targetScript.ScriptClassName = sourceScript.ScriptClassName; } } - + // Copy transforms... needs special handling for the Parent<->Child relations for (let (sourceHandle, sourceTransform) in _ecsWorld.Enumerate()) { @@ -221,21 +202,36 @@ namespace GlitchyEngine.World } } - public void OnRuntimeStart() + public void Start(bool simulation, bool runtime) { - OnSimulationStart(); - SetupPhysicsCallbacks(); - ScriptEngine.SetContext(this); + if (simulation) + StartSimulation(); + + } - public void OnRuntimeStop() + public void StartRuntime() { - OnSimulationStop(); - ScriptEngine.OnRuntimeStop(); + ScriptEngine.StartRuntime(this); + + // Initialize ScriptComponents + for (let (handle, scriptComponent) in _ecsWorld.Enumerate()) + { + 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); draw.drawPolygonCallback = (vertices, vertexCount, color, userData) => @@ -289,6 +285,8 @@ namespace GlitchyEngine.World World.SetDebugDrawFlags(_physicsWorld2D, .e_shapeBit); InitPhysics2D(); + + SetupPhysicsCallbacks(); } private void SetupPhysicsCallbacks() @@ -590,10 +588,15 @@ namespace GlitchyEngine.World polygonCollider.RuntimeFixture = fixture; } - public void OnSimulationStop() + public void StopSimulation() { + if (_physicsWorld2D == null) + return; + Box2D.World.Delete(_physicsWorld2D); _physicsWorld2D = null; + + // TODO: Get rid of all references to colliders, etc. in physics components. } public enum UpdateMode