Much more stable and simplified subsystem architecture

This commit is contained in:
WiggleWizard
2024-09-18 21:20:14 +01:00
parent 510b577f49
commit 066b2998ac
15 changed files with 183 additions and 66 deletions

View File

@@ -14,14 +14,13 @@
#include "src/Threading/JobSystem.h"
#include "src/Core/RegisterCoreTypes.h"
#include "src/Modules/Modules.h"
#include "src/Subsystems/EngineSubsystemScriptable.h"
#include <GLFW/glfw3.h>
#include <imgui/imgui_impl_glfw.h>
#include <imgui/imgui_impl_opengl3.h>
#include <Tracy.hpp>
#include "src/Subsystems/EngineSubsystemScript.h"
#include "src/Subsystems/TickableEngineSubsystem.h"
namespace Nuake
@@ -97,20 +96,27 @@ namespace Nuake
}
}
float scaledTimeStep = timeStep * timeScale;
// Tick all subsystems
for (auto subsystem : tickableSubsystems)
if (Engine::IsPlayMode())
{
if (subsystem != nullptr)
for (auto subsystem : subsystems)
{
subsystem->Tick();
if (subsystem == nullptr)
continue;
if (subsystem->CanEverTick())
{
subsystem->Tick(scaledTimeStep);
}
}
}
// Dont update if no scene is loaded.
if (currentWindow->GetScene())
{
float scaledTimeStep = timeStep * timeScale;
currentWindow->Update(scaledTimeStep);
// Play mode update all the entities, Editor does not.
@@ -136,12 +142,14 @@ namespace Nuake
void Engine::EnterPlayMode()
{
SetGameState(GameState::Loading);
lastFrameTime = (float)glfwGetTime(); // Reset timestep timer.
// Dont trigger init if already in player mode.
if (GetGameState() == GameState::Playing)
if (GetGameState() == GameState::Playing || GetGameState() == GameState::Loading)
{
Logger::Log("Cannot enter play mode if is already in play mode.", "engine", WARNING);
Logger::Log("Cannot enter play mode if is already in play mode or is loading.", "engine", WARNING);
return;
}
@@ -155,6 +163,9 @@ namespace Nuake
{
Logger::Log("Cannot enter play mode. Scene OnInit failed", "engine", CRITICAL);
GetCurrentScene()->OnExit();
// Precautionary measure
SetGameState(GameState::Stopped);
}
}
@@ -231,7 +242,7 @@ namespace Nuake
return currentProject;
}
Ref<EngineSubsystemScript> Engine::GetScriptedSubsystem(const std::string& subsystemName)
Ref<EngineSubsystemScriptable> Engine::GetScriptedSubsystem(const std::string& subsystemName)
{
if (scriptedSubsystemMap.contains(subsystemName))
{
@@ -240,18 +251,32 @@ namespace Nuake
return nullptr;
}
Ref<EngineSubsystemScriptable> Engine::GetScriptedSubsystem(const int subsystemId)
{
if (subsystemId >= subsystems.size())
{
return nullptr;
}
return std::reinterpret_pointer_cast<EngineSubsystemScriptable>(subsystems[subsystemId]);
}
void Engine::InitializeCoreSubsystems()
{
}
void Engine::OnScriptingEngineGameAssemblyLoaded()
{
if (!Engine::IsPlayMode() && Engine::GetGameState() != GameState::Loading)
{
return;
}
subsystems.clear();
scriptedSubsystemMap.clear();
auto& gameAssembly = ScriptingEngineNet::Get().GetGameAssembly();
auto scriptTypeEngineSubsystem = gameAssembly.GetType("Nuake.Net.EngineSubsystem");
const Coral::ManagedAssembly& gameAssembly = ScriptingEngineNet::Get().GetGameAssembly();
const auto scriptTypeEngineSubsystem = gameAssembly.GetType("Nuake.Net.EngineSubsystem");
const auto& types = gameAssembly.GetTypes();
for (const auto& type : types)
@@ -263,10 +288,13 @@ namespace Nuake
Logger::Log("Creating Scripted Subsystem " + typeName);
Coral::ManagedObject scriptedSubsystem = type->CreateInstance();
Ref<EngineSubsystemScript> subsystemScript = CreateRef<EngineSubsystemScript>(scriptedSubsystem);
scriptedSubsystem.SetPropertyValue("EngineSubsystemID", subsystems.size());
Ref<EngineSubsystemScriptable> subsystemScript = CreateRef<EngineSubsystemScriptable>(scriptedSubsystem);
subsystems.push_back(subsystemScript);
scriptedSubsystemMap[typeName] = subsystemScript;
subsystemScript->Initialize();
}
}
}

View File

@@ -10,11 +10,11 @@ namespace Nuake
class Project;
class Scene;
class EngineSubsystem;
class TickableEngineSubsystem;
class EngineSubsystemScript;
class EngineSubsystemScriptable;
enum GameState
{
Loading,
Playing,
Paused,
Stopped
@@ -54,7 +54,8 @@ namespace Nuake
static bool LoadProject(Ref<Project> project);
static Ref<Project> GetProject();
static Ref<EngineSubsystemScript> GetScriptedSubsystem(const std::string& subsystemName);
static Ref<EngineSubsystemScriptable> GetScriptedSubsystem(const std::string& subsystemName);
static Ref<EngineSubsystemScriptable> GetScriptedSubsystem(const int subsystemId);
protected:
static void InitializeCoreSubsystems();
@@ -67,9 +68,7 @@ namespace Nuake
static std::string queuedScene;
static inline std::vector<Ref<EngineSubsystem>> subsystems;
static inline std::vector<Ref<TickableEngineSubsystem>> tickableSubsystems;
static inline std::unordered_map<std::string, Ref<EngineSubsystemScript>> scriptedSubsystemMap;
static inline std::unordered_map<std::string, Ref<EngineSubsystemScriptable>> scriptedSubsystemMap;
static GameState gameState;

View File

@@ -9,7 +9,7 @@
#include <Coral/ManagedObject.hpp>
#include <Coral/Array.hpp>
#include "Coral/Type.hpp"
#include "src/Subsystems/EngineSubsystemScript.h"
#include "..\..\Subsystems\EngineSubsystemScriptable.h"
namespace Nuake {
@@ -119,7 +119,7 @@ namespace Nuake {
Coral::ManagedObject GetEngineSubsystemByName(Coral::String subsystemName)
{
const Ref<EngineSubsystemScript> scriptedSubsystem = Engine::GetScriptedSubsystem(subsystemName);
const Ref<EngineSubsystemScriptable> scriptedSubsystem = Engine::GetScriptedSubsystem(subsystemName);
if (scriptedSubsystem == nullptr)
{
return {};

View File

@@ -0,0 +1,37 @@
#include "EngineSubsystemNetAPI.h"
#include "Engine.h"
#include "src/Subsystems/EngineSubsystemScriptable.h"
namespace Nuake
{
void SetCanTick(int subsystemId, bool tick)
{
auto subsystem = Engine::GetScriptedSubsystem(subsystemId);
if (subsystem == nullptr)
{
Logger::Log("Subsystem isn't a valid scripted subsystem", "EngineSubsystemNetAPI", WARNING);
return;
}
subsystem->SetCanTick(tick);
}
bool GetCanTick(int subsystemId)
{
auto subsystem = Engine::GetScriptedSubsystem(subsystemId);
if (subsystem == nullptr)
{
Logger::Log("Subsystem isn't a valid scripted subsystem", "EngineSubsystemNetAPI", WARNING);
return false;
}
return subsystem->CanEverTick();
}
void EngineSubsystemNetAPI::RegisterMethods()
{
RegisterMethod("EngineSubsystem.SetCanTickIcall", &SetCanTick);
RegisterMethod("EngineSubsystem.GetCanTickIcall", &GetCanTick);
}
}

View File

@@ -0,0 +1,14 @@
#pragma once
#include "NetAPIModule.h"
namespace Nuake
{
class EngineSubsystemNetAPI : public Nuake::NetAPIModule
{
public:
virtual const std::string GetModuleName() const override { return "EngineSubsystem"; }
virtual void RegisterMethods() override;
};
}

View File

@@ -8,6 +8,7 @@
#include "src/Scene/Components/NetScriptComponent.h"
#include "NetModules/EngineNetAPI.h"
#include "NetModules/EngineSubsystemNetAPI.h"
#include "NetModules/InputNetAPI.h"
#include "NetModules/SceneNetAPI.h"
#include "NetModules/UINetAPI.h"
@@ -53,6 +54,7 @@ namespace Nuake
modules =
{
CreateRef<EngineNetAPI>(),
CreateRef<EngineSubsystemNetAPI>(),
CreateRef<InputNetAPI>(),
CreateRef<SceneNetAPI>(),
CreateRef<UINetAPI>()

View File

@@ -1 +1,11 @@
#include "EngineSubsystem.h"
void Nuake::EngineSubsystem::SetCanTick(bool canTick)
{
canEverTick = canTick;
}
bool Nuake::EngineSubsystem::CanEverTick() const
{
return canEverTick;
}

View File

@@ -9,6 +9,13 @@ namespace Nuake
class EngineSubsystem
{
public:
void SetCanTick(bool canTick);
bool CanEverTick() const;
virtual void Initialize() {}
virtual void Tick(float deltaTime) {}
private:
bool canEverTick = true;
};
}

View File

@@ -1,18 +0,0 @@
#include "EngineSubsystemScript.h"
namespace Nuake
{
EngineSubsystemScript::EngineSubsystemScript(const Coral::ManagedObject& object)
: cSharpObjectInstance(object)
{
}
Coral::ManagedObject& EngineSubsystemScript::GetManagedObjectInstance()
{
return cSharpObjectInstance;
}
}

View File

@@ -0,0 +1,35 @@
#include "EngineSubsystemScriptable.h"
namespace Nuake
{
EngineSubsystemScriptable::EngineSubsystemScriptable(const Coral::ManagedObject& object)
: cSharpObjectInstance(object)
{
}
Coral::ManagedObject& EngineSubsystemScriptable::GetManagedObjectInstance()
{
return cSharpObjectInstance;
}
void EngineSubsystemScriptable::Initialize()
{
if (!cSharpObjectInstance.IsValid())
return;
cSharpObjectInstance.InvokeMethod("Initialize");
}
void EngineSubsystemScriptable::Tick(float deltaTime)
{
if (!cSharpObjectInstance.IsValid())
return;
cSharpObjectInstance.InvokeMethod("OnTick", deltaTime);
}
}

View File

@@ -1,20 +1,24 @@
#pragma once
#include "EngineSubsystem.h"
#include "Coral/ManagedObject.hpp"
#include <Coral/ManagedObject.hpp>
/**
* Essentially just a wrapper for C# subsystems
*/
namespace Nuake
{
class EngineSubsystemScript : public EngineSubsystem
class EngineSubsystemScriptable : public EngineSubsystem
{
public:
EngineSubsystemScript(const Coral::ManagedObject& object);
EngineSubsystemScriptable(const Coral::ManagedObject& object);
Coral::ManagedObject& GetManagedObjectInstance();
virtual void Initialize() override;
virtual void Tick(float deltaTime) override;
private:
Coral::ManagedObject cSharpObjectInstance;
};

View File

@@ -1 +0,0 @@
#include "TickableEngineSubsystem.h"

View File

@@ -1,13 +0,0 @@
#pragma once
#include "EngineSubsystem.h"
namespace Nuake
{
class TickableEngineSubsystem : public EngineSubsystem
{
public:
virtual void Tick() {}
};
}

View File

@@ -1,6 +1,25 @@
namespace Nuake.Net;
public class EngineSubsystem
namespace Nuake.Net
{
public class EngineSubsystem
{
internal static unsafe delegate*<int, bool, void> SetCanTickIcall;
internal static unsafe delegate*<int, bool> GetCanTickIcall;
}
public int EngineSubsystemID { get; protected set; }
public bool CanTick
{
set
{
unsafe { SetCanTickIcall(EngineSubsystemID, value); }
}
get
{
unsafe { return GetCanTickIcall(EngineSubsystemID); }
}
}
public virtual void Initialize() {}
public virtual void OnTick(float deltaTime) {}
}
}

View File

@@ -1,6 +0,0 @@
namespace Nuake.Net;
public class EngineTickableSubsystem
{
}