diff --git a/Source/Game/Game/Application/Application.cpp b/Source/Game/Game/Application/Application.cpp index be77db85..7c6505fc 100644 --- a/Source/Game/Game/Application/Application.cpp +++ b/Source/Game/Game/Application/Application.cpp @@ -227,6 +227,8 @@ bool Application::Init() ServiceLocator::SetTaskScheduler(_taskScheduler); _registries.gameRegistry = new entt::registry(); + _registries.eventIncomingRegistry = new entt::registry(); + _registries.eventOutgoingRegistry = new entt::registry(); ServiceLocator::SetEnttRegistries(&_registries); _inputManager = new InputManager(); @@ -451,6 +453,16 @@ bool Application::Tick(f32 deltaTime) } _ecsScheduler->Update(*_registries.gameRegistry, deltaTime); + + // Handle Double Buffered Event Swap + { + _registries.eventIncomingRegistry->clear(); + + entt::registry* temp = _registries.eventIncomingRegistry; + _registries.eventIncomingRegistry = _registries.eventOutgoingRegistry; + _registries.eventOutgoingRegistry = temp; + } + _animationSystem->Update(deltaTime); _editorHandler->Update(deltaTime); diff --git a/Source/Game/Game/Application/EnttRegistries.h b/Source/Game/Game/Application/EnttRegistries.h index 97860406..8351e88e 100644 --- a/Source/Game/Game/Application/EnttRegistries.h +++ b/Source/Game/Game/Application/EnttRegistries.h @@ -4,4 +4,6 @@ struct EnttRegistries { entt::registry* gameRegistry; + entt::registry* eventIncomingRegistry; + entt::registry* eventOutgoingRegistry; }; \ No newline at end of file diff --git a/Source/Game/Game/ECS/Components/Events.h b/Source/Game/Game/ECS/Components/Events.h new file mode 100644 index 00000000..2398931f --- /dev/null +++ b/Source/Game/Game/ECS/Components/Events.h @@ -0,0 +1,10 @@ +#pragma once +#include + +namespace ECS::Components +{ + struct MapLoadedEvent + { + u32 mapId; + }; +} \ No newline at end of file diff --git a/Source/Game/Game/ECS/Scheduler.h b/Source/Game/Game/ECS/Scheduler.h index 08354664..b51cce46 100644 --- a/Source/Game/Game/ECS/Scheduler.h +++ b/Source/Game/Game/ECS/Scheduler.h @@ -5,14 +5,14 @@ namespace ECS { - class Scheduler - { - public: - Scheduler(); + class Scheduler + { + public: + Scheduler(); - void Init(entt::registry & registry); - void Update(entt::registry& registry, f32 deltaTime); + void Init(entt::registry & registry); + void Update(entt::registry& registry, f32 deltaTime); - private: - }; + private: + }; } \ No newline at end of file diff --git a/Source/Game/Game/ECS/Systems/CharacterController.cpp b/Source/Game/Game/ECS/Systems/CharacterController.cpp index e3c6caf0..d7e85701 100644 --- a/Source/Game/Game/ECS/Systems/CharacterController.cpp +++ b/Source/Game/Game/ECS/Systems/CharacterController.cpp @@ -1,9 +1,9 @@ #include "CharacterController.h" #include "Game/Animation/AnimationSystem.h" - #include "Game/ECS/Components/AABB.h" #include "Game/ECS/Components/Camera.h" +#include "Game/ECS/Components/Events.h" #include "Game/ECS/Components/Model.h" #include "Game/ECS/Components/Name.h" #include "Game/ECS/Singletons/ActiveCamera.h" @@ -11,8 +11,9 @@ #include "Game/ECS/Singletons/FreeflyingCameraSettings.h" #include "Game/ECS/Singletons/JoltState.h" #include "Game/ECS/Singletons/OrbitalCameraSettings.h" +#include "Game/ECS/Util/EventUtil.h" #include "Game/ECS/Util/Transforms.h" - +#include "Game/Gameplay/MapLoader.h" #include "Game/Rendering/GameRenderer.h" #include "Game/Rendering/Debug/JoltDebugRenderer.h" #include "Game/Rendering/Model/ModelLoader.h" @@ -57,21 +58,7 @@ namespace ECS::Systems transformSystem.SetWorldPosition(characterSingleton.modelEntity, vec3(0.0f, 0.0f, 0.0f)); transformSystem.ParentEntityTo(characterSingleton.entity, characterSingleton.modelEntity); - ModelLoader* modelLoader = ServiceLocator::GetGameRenderer()->GetModelLoader(); - u32 modelHash = modelLoader->GetModelHashFromModelPath("character/human/female/humanfemale.complexmodel"); - modelLoader->LoadModelForEntity(characterSingleton.modelEntity, modelHash); - - JPH::BodyInterface& bodyInterface = joltState.physicsSystem.GetBodyInterface(); - - JPH::CapsuleShapeSettings shapeSetting(0.8f, 0.25f); - JPH::ShapeSettings::ShapeResult shapeResult = shapeSetting.Create(); - - JPH::CharacterVirtualSettings characterSettings; - characterSettings.mShape = shapeResult.Get(); - characterSettings.mBackFaceMode = JPH::EBackFaceMode::IgnoreBackFaces; - - characterSingleton.character = new JPH::CharacterVirtual(&characterSettings, JPH::RVec3(0.0f, 0.0f, 0.0f), JPH::Quat::sIdentity(), &joltState.physicsSystem); - characterSingleton.character->SetShapeOffset(JPH::Vec3(0.0f, 0.8f, 0.0f)); + InitCharacterController(registry); InputManager* inputManager = ServiceLocator::GetInputManager(); characterSingleton.keybindGroup = inputManager->CreateKeybindGroup("CharacterController", 100); @@ -188,6 +175,11 @@ namespace ECS::Systems entt::registry::context& ctx = registry.ctx(); auto& characterSingleton = ctx.get(); + Util::EventUtil::OnEvent([&](const Components::MapLoadedEvent& event) + { + InitCharacterController(registry); + }); + #ifdef JPH_DEBUG_RENDERER // TODO: Fix Jolt Primitives being erased in JoltDebugRenderer causing crash when changing map //Components::Transform& transform = registry.get(characterSingleton.modelEntity); @@ -525,18 +517,47 @@ namespace ECS::Systems } } - void CharacterController::ReInitCharacterModel(entt::registry& registry) + void CharacterController::InitCharacterController(entt::registry& registry) { entt::registry::context& ctx = registry.ctx(); auto& joltState = ctx.get(); auto& transformSystem = ctx.get(); + auto& activeCamera = ctx.get(); + auto& orbitalCameraSettings = ctx.get(); auto& characterSingleton = ctx.emplace(); ModelLoader* modelLoader = ServiceLocator::GetGameRenderer()->GetModelLoader(); u32 modelHash = modelLoader->GetModelHashFromModelPath("character/human/female/humanfemale.complexmodel"); modelLoader->LoadModelForEntity(characterSingleton.modelEntity, modelHash); - characterSingleton.character->SetPosition(JPH::Vec3(-1500.0f, 310.0f, 1250.0f)); + JPH::BodyInterface& bodyInterface = joltState.physicsSystem.GetBodyInterface(); + + JPH::CapsuleShapeSettings shapeSetting(0.8f, 0.25f); + JPH::ShapeSettings::ShapeResult shapeResult = shapeSetting.Create(); + + JPH::CharacterVirtualSettings characterSettings; + characterSettings.mShape = shapeResult.Get(); + characterSettings.mBackFaceMode = JPH::EBackFaceMode::IgnoreBackFaces; + + characterSingleton.character = new JPH::CharacterVirtual(&characterSettings, JPH::RVec3(0.0f, 0.0f, 0.0f), JPH::Quat::sIdentity(), &joltState.physicsSystem); + characterSingleton.character->SetShapeOffset(JPH::Vec3(0.0f, 0.8f, 0.0f)); + + MapLoader* mapLoader = ServiceLocator::GetGameRenderer()->GetMapLoader(); + + JPH::Vec3 newPosition = JPH::Vec3(-1500.0f, 310.0f, 1250.0f); + + if (mapLoader->GetCurrentMapID() == std::numeric_limits().max()) + { + newPosition = JPH::Vec3(0.0f, 0.0f, 0.0f); + } + + characterSingleton.character->SetPosition(newPosition); + transformSystem.SetWorldPosition(characterSingleton.entity, vec3(newPosition.GetX(), newPosition.GetY(), newPosition.GetZ())); + + if (activeCamera.entity == orbitalCameraSettings.entity) + { + transformSystem.ParentEntityTo(characterSingleton.entity, orbitalCameraSettings.entity); + } } } \ No newline at end of file diff --git a/Source/Game/Game/ECS/Systems/CharacterController.h b/Source/Game/Game/ECS/Systems/CharacterController.h index 8ecd65e5..7cc3655d 100644 --- a/Source/Game/Game/ECS/Systems/CharacterController.h +++ b/Source/Game/Game/ECS/Systems/CharacterController.h @@ -10,6 +10,6 @@ namespace ECS::Systems static void Init(entt::registry& registry); static void Update(entt::registry& registry, f32 deltaTime); - static void ReInitCharacterModel(entt::registry& registry); + static void InitCharacterController(entt::registry& registry); }; } \ No newline at end of file diff --git a/Source/Game/Game/ECS/Util/EventUtil.h b/Source/Game/Game/ECS/Util/EventUtil.h new file mode 100644 index 00000000..4c2b4481 --- /dev/null +++ b/Source/Game/Game/ECS/Util/EventUtil.h @@ -0,0 +1,38 @@ +#pragma once +#include "Game/Application/EnttRegistries.h" +#include "Game/Util/ServiceLocator.h" + +#include + +#include + +namespace ECS::Util +{ + namespace EventUtil + { + template + inline void PushEventTo(entt::registry& registry, Events&&... events) + { + entt::entity eventEntity = registry.create(); + (registry.emplace>(eventEntity, std::forward(events)), ...); + } + + template + inline void PushEvent(Events&&... events) + { + EnttRegistries* registries = ServiceLocator::GetEnttRegistries(); + entt::registry* eventRegistry = registries->eventOutgoingRegistry; + + PushEventTo(*eventRegistry, std::forward(events)...); + } + + template + inline void OnEvent(Handler&& handler) + { + EnttRegistries* registries = ServiceLocator::GetEnttRegistries(); + entt::registry* eventRegistry = registries->eventIncomingRegistry; + + eventRegistry->view().each(std::forward(handler)); + } + } +} \ No newline at end of file diff --git a/Source/Game/Game/Gameplay/MapLoader.cpp b/Source/Game/Game/Gameplay/MapLoader.cpp index 5add9e36..5ba422ff 100644 --- a/Source/Game/Game/Gameplay/MapLoader.cpp +++ b/Source/Game/Game/Gameplay/MapLoader.cpp @@ -2,8 +2,10 @@ #include "Game/Application/EnttRegistries.h" #include "Game/Editor/EditorHandler.h" #include "Game/Editor/Inspector.h" +#include "Game/ECS/Components/Events.h" #include "Game/ECS/Singletons/ClientDBCollection.h" #include "Game/ECS/Singletons/MapDB.h" +#include "Game/ECS/Util/EventUtil.h" #include "Game/Rendering/GameRenderer.h" #include "Game/Rendering/Debug/JoltDebugRenderer.h" #include "Game/Rendering/Terrain/TerrainLoader.h" @@ -39,6 +41,7 @@ void MapLoader::Update(f32 deltaTime) // Clear Map if (request.internalMapNameHash == std::numeric_limits().max()) { + _currentMapID = std::numeric_limits().max(); ClearRenderersForMap(); } else @@ -88,12 +91,16 @@ void MapLoader::Update(f32 deltaTime) { if (!_modelLoader->ContainsDiscoveredModel(mapHeader.placement.nameHash)) return; + + _currentMapID = mapID; ClearRenderersForMap(); _modelLoader->LoadPlacement(mapHeader.placement); } else { + _currentMapID = mapID; + TerrainLoader::LoadDesc loadDesc; loadDesc.loadType = TerrainLoader::LoadType::Full; loadDesc.mapName = internalMapName; @@ -129,4 +136,6 @@ void MapLoader::ClearRenderersForMap() Editor::EditorHandler* editorHandler = ServiceLocator::GetEditorHandler(); editorHandler->GetInspector()->ClearSelection(); + + ECS::Util::EventUtil::PushEvent(ECS::Components::MapLoadedEvent{ _currentMapID }); } diff --git a/Source/Game/Game/Gameplay/MapLoader.h b/Source/Game/Game/Gameplay/MapLoader.h index 471859bf..93498116 100644 --- a/Source/Game/Game/Gameplay/MapLoader.h +++ b/Source/Game/Game/Gameplay/MapLoader.h @@ -26,7 +26,7 @@ class MapLoader void UnloadMap(); void LoadMap(u32 mapHash); - const u32 GetCurrentMapIndex() { return _currentMapIndex; } + const u32 GetCurrentMapID() { return _currentMapID; } private: void ClearRenderersForMap(); @@ -36,6 +36,6 @@ class MapLoader ModelLoader* _modelLoader = nullptr; LiquidLoader* _liquidLoader = nullptr; - u32 _currentMapIndex = std::numeric_limits().max(); + u32 _currentMapID = std::numeric_limits().max(); moodycamel::ConcurrentQueue _requests; }; \ No newline at end of file diff --git a/Source/Game/Game/Rendering/Model/ModelLoader.cpp b/Source/Game/Game/Rendering/Model/ModelLoader.cpp index 2f29f7ee..6cea73f5 100644 --- a/Source/Game/Game/Rendering/Model/ModelLoader.cpp +++ b/Source/Game/Game/Rendering/Model/ModelLoader.cpp @@ -180,6 +180,8 @@ void ModelLoader::Clear() bodyInterface.RemoveBody(id); bodyInterface.DestroyBody(id); } + + _instanceIDToBodyID.clear(); } for (auto& pair : _nameHashToJoltShape) @@ -756,10 +758,12 @@ void ModelLoader::AddStaticInstance(entt::entity entityID, const LoadRequestInte // Create the actual rigid body JPH::Body* body = bodyInterface.CreateBody(bodySettings); // Note that if we run out of bodies this can return nullptr - - JPH::BodyID bodyID = body->GetID(); - bodyInterface.AddBody(bodyID, JPH::EActivation::Activate); - _instanceIDToBodyID[instanceID] = bodyID.GetIndexAndSequenceNumber(); + if (body) + { + JPH::BodyID bodyID = body->GetID(); + bodyInterface.AddBody(bodyID, JPH::EActivation::Activate); + _instanceIDToBodyID[instanceID] = bodyID.GetIndexAndSequenceNumber(); + } } } diff --git a/Source/Game/Game/Rendering/Terrain/TerrainLoader.cpp b/Source/Game/Game/Rendering/Terrain/TerrainLoader.cpp index 6dedb5a8..394e6554 100644 --- a/Source/Game/Game/Rendering/Terrain/TerrainLoader.cpp +++ b/Source/Game/Game/Rendering/Terrain/TerrainLoader.cpp @@ -2,8 +2,10 @@ #include "TerrainRenderer.h" #include "Game/Application/EnttRegistries.h" +#include "Game/ECS/Components/Events.h" #include "Game/ECS/Singletons/JoltState.h" #include "Game/ECS/Systems/CharacterController.h" +#include "Game/ECS/Util/EventUtil.h" #include "Game/Editor/EditorHandler.h" #include "Game/Editor/Inspector.h" #include "Game/Rendering/Debug/DebugRenderer.h" @@ -11,6 +13,7 @@ #include "Game/Rendering/GameRenderer.h" #include "Game/Rendering/Model/ModelLoader.h" #include "Game/Rendering/Liquid/LiquidLoader.h" +#include "Game/Gameplay/MapLoader.h" #include "Game/Util/JoltStream.h" #include "Game/Util/MapUtil.h" #include "Game/Util/ServiceLocator.h" @@ -402,7 +405,8 @@ void TerrainLoader::LoadFullMapRequest(const LoadRequestInternal& request) taskScheduler->AddTaskSetToPipe(&loadChunksTask); taskScheduler->WaitforTask(&loadChunksTask); - ECS::Systems::CharacterController::ReInitCharacterModel(*registry); + u32 mapID = ServiceLocator::GetGameRenderer()->GetMapLoader()->GetCurrentMapID(); + ECS::Util::EventUtil::PushEvent(ECS::Components::MapLoadedEvent{ mapID }); i32 physicsOptimizeBP = *CVarSystem::Get()->GetIntCVar(CVarCategory::Client | CVarCategory::Physics, "optimizeBP"_h); if (physicsEnabled && physicsOptimizeBP) diff --git a/Source/Game/Game/Scripting/LuaManager.h b/Source/Game/Game/Scripting/LuaManager.h index 2d28f2b8..3edf3706 100644 --- a/Source/Game/Game/Scripting/LuaManager.h +++ b/Source/Game/Game/Scripting/LuaManager.h @@ -36,7 +36,7 @@ namespace Scripting template bool SetGlobal(const std::string& name, T& value, bool canOverride) { - if (_globalTable.data.contains(name) && canOverride) + if (_globalTable.data.contains(name) && !canOverride) return false; _globalTable.data[name] = value;