diff --git a/Editor/src/Windows/EditorInterface.cpp b/Editor/src/Windows/EditorInterface.cpp index 961c5ecf..e5be80d9 100644 --- a/Editor/src/Windows/EditorInterface.cpp +++ b/Editor/src/Windows/EditorInterface.cpp @@ -118,7 +118,7 @@ namespace Nuake { using namespace Nuake::StaticResources; ImGui::LoadIniSettingsFromMemory((const char*)StaticResources::Resources_default_layout_ini); - ScriptingContext::Get().Initialize(); + //ScriptingContext::Get().Initialize(); } void EditorInterface::Init() @@ -511,6 +511,7 @@ namespace Nuake { { playButtonPressed = ImGui::Button(ICON_FA_PLAY, ImVec2(30, 30)) || Input::IsKeyPressed(Key::F5); tooltip = "Build & Play (F5)"; + } if (playButtonPressed) @@ -527,6 +528,7 @@ namespace Nuake { { this->SceneSnapshot = Engine::GetCurrentScene()->Copy(); + std::string statusMessage = ICON_FA_HAMMER + std::string(" Building .Net solution..."); SetStatusMessage(statusMessage); @@ -553,6 +555,8 @@ namespace Nuake { } else { + Engine::GetProject()->ExportEntitiesToTrenchbroom(); + SetStatusMessage("Entering play mode..."); PushCommand(SetGameState(GameState::Playing)); diff --git a/Nuake/Engine.cpp b/Nuake/Engine.cpp index e165c7fc..f21e8e73 100644 --- a/Nuake/Engine.cpp +++ b/Nuake/Engine.cpp @@ -169,6 +169,7 @@ namespace Nuake } FileSystem::SetRootDirectory(FileSystem::GetParentPath(project->FullPath)); + ScriptingEngineNet::Get().Initialize(); ScriptingEngineNet::Get().LoadProjectAssembly(project); return true; diff --git a/Nuake/src/Audio/AudioManager.cpp b/Nuake/src/Audio/AudioManager.cpp index 862319bc..914ca01c 100644 --- a/Nuake/src/Audio/AudioManager.cpp +++ b/Nuake/src/Audio/AudioManager.cpp @@ -153,7 +153,7 @@ namespace Nuake { void AudioManager::LoadWavAudio(const std::string& filePath) { - const bool STREAMING = true; + const bool STREAMING = false; if (STREAMING) { Ref wavStream = CreateRef(); diff --git a/Nuake/src/Physics/DynamicWorld.cpp b/Nuake/src/Physics/DynamicWorld.cpp index 2b4e9766..cddeedd8 100644 --- a/Nuake/src/Physics/DynamicWorld.cpp +++ b/Nuake/src/Physics/DynamicWorld.cpp @@ -494,8 +494,20 @@ namespace Nuake { std::string name = entity.GetComponent().Name; - _JoltBodyInterface->SetPositionAndRotation(bodyId, newPosition, newRotation, JPH::EActivation::DontActivate); - //_JoltBodyInterface->MoveKinematic(bodyId, newPosition, newRotation, 0.0f); + JPH::EMotionType bodyType = _JoltBodyInterface->GetMotionType(bodyId); + switch (bodyType) + { + case JPH::EMotionType::Kinematic: + { + _JoltBodyInterface->MoveKinematic(bodyId, newPosition, newRotation, 0.0f); + break; + } + case JPH::EMotionType::Static: + { + _JoltBodyInterface->SetPositionAndRotation(bodyId, newPosition, newRotation, JPH::EActivation::DontActivate); + break; + } + } } } } @@ -864,7 +876,7 @@ namespace Nuake _CollisionCallbacks.push_back(std::move(data)); } - const std::vector& DynamicWorld::GetCollisionsData() + const std::vector DynamicWorld::GetCollisionsData() { std::scoped_lock lock(_CollisionCallbackMutex); return _CollisionCallbacks; diff --git a/Nuake/src/Physics/DynamicWorld.h b/Nuake/src/Physics/DynamicWorld.h index faf8e2d9..f8436836 100644 --- a/Nuake/src/Physics/DynamicWorld.h +++ b/Nuake/src/Physics/DynamicWorld.h @@ -91,7 +91,7 @@ namespace Nuake void ClearCollisionData(); void RegisterCollisionCallback(const CollisionData& data); - const std::vector& GetCollisionsData(); + const std::vector GetCollisionsData(); private: JPH::Ref GetJoltShape(const Ref shape); void SyncEntitiesTranforms(); diff --git a/Nuake/src/Physics/PhysicsManager.cpp b/Nuake/src/Physics/PhysicsManager.cpp index 718fb8e4..db271d68 100644 --- a/Nuake/src/Physics/PhysicsManager.cpp +++ b/Nuake/src/Physics/PhysicsManager.cpp @@ -57,7 +57,7 @@ namespace Nuake return m_World->CastShape(from, to, shape); } - const std::vector& PhysicsManager::GetCollisions() + const std::vector PhysicsManager::GetCollisions() { return m_World->GetCollisionsData(); } diff --git a/Nuake/src/Physics/PhysicsManager.h b/Nuake/src/Physics/PhysicsManager.h index 8f98a954..901a6b86 100644 --- a/Nuake/src/Physics/PhysicsManager.h +++ b/Nuake/src/Physics/PhysicsManager.h @@ -53,7 +53,7 @@ namespace Nuake std::vector Raycast(const Vector3& from, const Vector3& to); std::vector Shapecast(const Vector3& from, const Vector3& to, const Ref& shape); - const std::vector& GetCollisions(); + const std::vector GetCollisions(); void RegisterBody(Ref rb); void RegisterGhostBody(Ref rb); diff --git a/Nuake/src/Physics/Rigibody.h b/Nuake/src/Physics/Rigibody.h index 3e1be3c9..8800836a 100644 --- a/Nuake/src/Physics/Rigibody.h +++ b/Nuake/src/Physics/Rigibody.h @@ -20,6 +20,7 @@ namespace Nuake Quat _rotation; Entity _entity; + bool _ForceKinematic = false; bool _isTrigger = false; bool m_LockXAxis = false; bool m_LockYAxis = false; @@ -29,7 +30,7 @@ namespace Nuake RigidBody(); RigidBody(Vector3 position, Entity handle); - RigidBody(float mass, Vector3 position, Quat rotation, Matrix4 transform, Ref shape, Entity entity, Vector3 initialVel = Vector3(0, 0, 0)); + RigidBody(float mass, Vector3 position, Quat rotation, Matrix4 transform, Ref shape, Entity entity, Vector3 initialVel = Vector3(0, 0, 0), bool forceKinematic = false); void UpdateTransform(); @@ -43,6 +44,7 @@ namespace Nuake void SetLockXAxis(bool lock) { m_LockXAxis = lock; } void SetLockYAxis(bool lock) { m_LockYAxis = lock; } void SetLockZAxis(bool lock) { m_LockZAxis = lock; } + bool GetForceKinematic() const { return _ForceKinematic; } void SetEntityID(Entity ent); Vector3 GetPosition() const { return _position; } diff --git a/Nuake/src/Physics/Rigidbody.cpp b/Nuake/src/Physics/Rigidbody.cpp index 0ffd9d35..4f47c3aa 100644 --- a/Nuake/src/Physics/Rigidbody.cpp +++ b/Nuake/src/Physics/Rigidbody.cpp @@ -20,12 +20,13 @@ namespace Nuake } - RigidBody::RigidBody(float mass, Vector3 position, Quat rotation, Matrix4 transform, Ref shape, Entity entity, Vector3 initialVel) : + RigidBody::RigidBody(float mass, Vector3 position, Quat rotation, Matrix4 transform, Ref shape, Entity entity, Vector3 initialVel, bool forceKinematic) : _position(position), _collisionShape(shape), _mass(mass), _entity(entity), - _rotation(rotation) + _rotation(rotation), + _ForceKinematic(forceKinematic) { } diff --git a/Nuake/src/Rendering/SceneRenderer.cpp b/Nuake/src/Rendering/SceneRenderer.cpp index 3c4b2659..0ecb9b33 100644 --- a/Nuake/src/Rendering/SceneRenderer.cpp +++ b/Nuake/src/Rendering/SceneRenderer.cpp @@ -75,6 +75,9 @@ namespace Nuake mCapsuleGizmo = CreateRef(); mCapsuleGizmo->CreateMesh(); + + mDebugLines = std::vector(); + mDebugShapes = std::vector(); } void SceneRenderer::Cleanup() @@ -84,24 +87,30 @@ namespace Nuake void SceneRenderer::Update(const Timestep time, bool isEditorUpdate) { // Delete debug shapes that are dead - std::erase_if(mDebugLines, [](const DebugLine& line) + if (mDebugLines.size() > 0) { - return line.Life < 0.0f; - }); + std::erase_if(mDebugLines, [](const DebugLine& line) + { + return line.Life < 0.0f; + }); - std::erase_if(mDebugShapes, [](const DebugShape& shape) - { - return shape.Life < 0.0f; - }); - - for (auto& line : mDebugLines) - { - line.Life -= time; + for (auto& line : mDebugLines) + { + line.Life -= time; + } } - for (auto& shape : mDebugShapes) + if (mDebugShapes.size() > 0) { - shape.Life -= time; + std::erase_if(mDebugShapes, [](const DebugShape& shape) + { + return shape.Life < 0.0f; + }); + + for (auto& shape : mDebugShapes) + { + shape.Life -= time; + } } } @@ -527,10 +536,7 @@ namespace Nuake if (model.IsTransparent || !visibility.Visible) continue; - for (Ref& m : model.Meshes) - { - Renderer::SubmitMesh(m, transform.GetGlobalTransform()); - } + } Renderer::Flush(shader, true); @@ -620,10 +626,7 @@ namespace Nuake if (model.IsTransparent || !visibility.Visible) continue; - for (Ref& m : model.Meshes) - { - Renderer::SubmitMesh(m, transform.GetGlobalTransform()); - } + } Renderer::Flush(shader, true); @@ -795,10 +798,7 @@ namespace Nuake if (model.IsTransparent || !visibility.Visible) continue; - for (auto& b : model.Meshes) - { - Renderer::SubmitMesh(b, transform.GetGlobalTransform(), (uint32_t)e); - } + } glEnable(GL_DEPTH_TEST); glDisable(GL_CULL_FACE); diff --git a/Nuake/src/Resource/FGD/FGDClass.h b/Nuake/src/Resource/FGD/FGDClass.h index 77e8a4c0..477b957d 100644 --- a/Nuake/src/Resource/FGD/FGDClass.h +++ b/Nuake/src/Resource/FGD/FGDClass.h @@ -76,6 +76,7 @@ namespace Nuake { std::string Name; std::string Description; std::string Prefab; + std::string Script; std::vector Properties; FGDBaseEntity BaseClass; diff --git a/Nuake/src/Resource/Project.cpp b/Nuake/src/Resource/Project.cpp index 0fa37e28..7039effe 100644 --- a/Nuake/src/Resource/Project.cpp +++ b/Nuake/src/Resource/Project.cpp @@ -1,11 +1,15 @@ #include "Project.h" -#include "../Core/FileSystem.h" +#include "src/Core/FileSystem.h" +#include "Engine.h" +#include "src/Core/Logger.h" +#include "src/Audio/AudioManager.h" +#include "src/Scripting/ScriptingEngineNet.h" + #include + #include #include -#include "../Core/Logger.h" -#include "Engine.h" -#include + namespace Nuake { @@ -104,6 +108,73 @@ namespace Nuake return project; } + void Project::ExportEntitiesToTrenchbroom() + { + Ref file = EntityDefinitionsFile; + + file->BrushEntities.clear(); + for (auto& [name, type] : ScriptingEngineNet::Get().GetBrushEntities()) + { + FGDBrushEntity brushEntity = FGDBrushEntity(name); + brushEntity.Script = name; + brushEntity.Description = type.Description; + brushEntity.IsTrigger = type.isTrigger; + for (auto& t : type.exposedVars) + { + ClassProperty classProp; + classProp.name = t.Name; + classProp.type = ClassPropertyType::String; + if (t.Type == ExposedVarTypes::String && t.Value.has_value()) + { + classProp.value = std::any_cast(t.Value); + } + else if (t.Type == ExposedVarTypes::Int) + { + classProp.value = std::to_string(std::any_cast(t.Value)); + } + else + { + classProp.value = ""; + } + brushEntity.Properties.push_back(classProp); + } + + file->BrushEntities.push_back(brushEntity); + } + + file->PointEntities.clear(); + for (auto& [name, type] : ScriptingEngineNet::Get().GetPointEntities()) + { + FGDPointEntity pointEntity = FGDPointEntity(name); + pointEntity.Script = name; + pointEntity.Description = type.Description; + for (auto& t : type.exposedVars) + { + ClassProperty classProp; + classProp.name = t.Name; + classProp.type = ClassPropertyType::String; + if (t.Type == ExposedVarTypes::String && t.Value.has_value()) + { + classProp.value = std::any_cast(t.Value); + } + else if (t.Type == ExposedVarTypes::Int) + { + classProp.value = std::to_string(std::any_cast(t.Value)); + } + else + { + classProp.value = ""; + } + + pointEntity.Properties.push_back(classProp); + } + + file->PointEntities.push_back(pointEntity); + } + + file->Export(); + } + json Project::Serialize() { BEGIN_SERIALIZE(); diff --git a/Nuake/src/Resource/Project.h b/Nuake/src/Resource/Project.h index 0be770d1..3bf66efe 100644 --- a/Nuake/src/Resource/Project.h +++ b/Nuake/src/Resource/Project.h @@ -59,6 +59,8 @@ namespace Nuake static Ref New(); static Ref Load(std::string& path); + void ExportEntitiesToTrenchbroom(); + json Serialize() override; bool Deserialize(const json& j) override; }; diff --git a/Nuake/src/Scene/Components/BSPBrushComponent.h b/Nuake/src/Scene/Components/BSPBrushComponent.h index 47ad28b2..7c5ba3b0 100644 --- a/Nuake/src/Scene/Components/BSPBrushComponent.h +++ b/Nuake/src/Scene/Components/BSPBrushComponent.h @@ -10,7 +10,7 @@ namespace Nuake { class BSPBrushComponent { public: - std::vector> Meshes; + //std::vector> Meshes; std::vector> Hulls; std::vector> Materials; @@ -27,7 +27,7 @@ namespace Nuake { BSPBrushComponent() { - Meshes = std::vector>(); + //Meshes = std::vector>(); Materials = std::vector>(); Rigidbody = std::vector>(); Hulls = std::vector>(); diff --git a/Nuake/src/Scene/Systems/PhysicsSystem.cpp b/Nuake/src/Scene/Systems/PhysicsSystem.cpp index 400843b0..6de93c66 100644 --- a/Nuake/src/Scene/Systems/PhysicsSystem.cpp +++ b/Nuake/src/Scene/Systems/PhysicsSystem.cpp @@ -131,8 +131,7 @@ namespace Nuake const Quat& startRotation = transformComponent.GetGlobalRotation(); const auto collisionShape = CreateRef(hull); - - auto rigidBody = CreateRef(0.0f, startPosition, startRotation, startTransform, collisionShape, entity); + auto rigidBody = CreateRef(0.0f, startPosition, startRotation, startTransform, collisionShape, entity, Vector3{ 0, 0, 0 }, brushComponent.IsFunc); brushComponent.Rigidbody.push_back(rigidBody); rigidBody->SetIsTrigger(brushComponent.IsTrigger); PhysicsManager::Get().RegisterBody(rigidBody); diff --git a/Nuake/src/Scene/Systems/QuakeMapBuilder.cpp b/Nuake/src/Scene/Systems/QuakeMapBuilder.cpp index 8fb21cb8..bd62a8a6 100644 --- a/Nuake/src/Scene/Systems/QuakeMapBuilder.cpp +++ b/Nuake/src/Scene/Systems/QuakeMapBuilder.cpp @@ -40,392 +40,6 @@ namespace Nuake { Ref DefaultMaterial; - void QuakeMapBuilder::CreateTrigger(brush* brush, brush_geometry* brush_inst, - Scene* scene, Entity& parent, - const std::string& target, const std::string& targetname) - { - std::vector vertices; - std::vector indices; - - Entity brushEntity = scene->CreateEntity("Trigger"); - TransformComponent& transformComponent = brushEntity.GetComponent(); - TriggerZone& trigger = brushEntity.AddComponent(); - trigger.target = target; - - parent.AddChild(brushEntity); - - transformComponent.SetGlobalPosition(Vector3(brush->center.y * (1.0f / 64), - brush->center.z * ScaleFactor * (1.0f / 64), - brush->center.x * ScaleFactor * (1.0f / 64))); - - BSPBrushComponent& bsp = brushEntity.AddComponent(); - bsp.IsSolid = false; - bsp.target = target; - int indexOffset = 0; - for (int f = 0; f < brush->face_count; ++f) - { - face* face = &brush->faces[f]; - - face_geometry* face_geo_inst = &brush_inst->faces[f]; - - for (int i = 0; i < face_geo_inst->vertex_count; ++i) - { - face_vertex vertex = face_geo_inst->vertices[i]; - - Vector3 vertexPos = Vector3( - (vertex.vertex.y - brush->center.y) * ScaleFactor * (1.0f / 64), - (vertex.vertex.z - brush->center.z) * ScaleFactor * (1.0f / 64), - (vertex.vertex.x - brush->center.x) * ScaleFactor * (1.0f / 64) - ); - - Vector3 vertexNormal = Vector3(vertex.normal.y, vertex.normal.z, vertex.normal.x); - Vector3 vertexTangent = Vector3(vertex.tangent.y, vertex.tangent.z, vertex.tangent.x); - - vertices.push_back(Vertex{ - vertexPos, - Vector2(0,0), - vertexNormal, - vertexTangent, - glm::vec3(0.0, 1.0, 0.0) - }); - } - - for (int i = 0; i < (face_geo_inst->vertex_count - 2) * 3; ++i) - { - unsigned int index = face_geo_inst->indices[i]; - indices.push_back((unsigned int)indexOffset + index); - } - - indexOffset += face_geo_inst->vertex_count; - } - - Ref mesh = CreateRef(); - mesh->AddSurface(vertices, indices); - bsp.Meshes.push_back(mesh); - } - - void QuakeMapBuilder::CreateBrush(brush* brush, brush_geometry* brush_inst, - Scene* scene, Entity& parent, - const std::string& target, const std::string& targetname) - { - std::vector vertices; - std::vector indices; - Entity brushEntity = scene->CreateEntity(targetname); - TransformComponent& transformComponent = brushEntity.GetComponent(); - BSPBrushComponent& bsp = brushEntity.AddComponent(); - - parent.AddChild(brushEntity); - - transformComponent.SetGlobalPosition(Vector3( - brush->center.y * ScaleFactor * (1.0f / 64), - brush->center.z * ScaleFactor * (1.0f / 64), - brush->center.x * ScaleFactor * (1.0f / 64))); - - int index_offset = 0; - int lastTextureID = -1; - std::string lastTexturePath = ""; - for (int f = 0; f < brush->face_count; ++f) - { - face* face = &brush->faces[f]; - texture_data* texture = &textures[face->texture_idx]; - - bool textureIsEmpty = std::string(texture->name) == "__TB_empty" || std::string(texture->name).empty(); - if (textureIsEmpty) - { - texture->height = 1; - texture->width = 1; - continue; - } - else - { - if (FileSystem::FileExists("textures/" + std::string(texture->name) + ".material")) - { - - } - else - { - std::string path = FileSystem::Root + "textures/" + std::string(texture->name) + ".png"; - auto tex = TextureManager::Get()->GetTexture(path); - - texture->height = tex->GetHeight(); - texture->width = tex->GetWidth(); - } - } - - face_geometry* face_geo_inst = &brush_inst->faces[f]; - - for (int i = 0; i < face_geo_inst->vertex_count; ++i) - { - face_vertex vertex = face_geo_inst->vertices[i]; - vertex_uv vertex_uv = get_valve_uv(vertex.vertex, face, texture->width, texture->height); - - Vector3 vertexPos = Vector3( - (vertex.vertex.y - brush->center.y) * ScaleFactor * (1.0f / 64), - (vertex.vertex.z - brush->center.z) * ScaleFactor * (1.0f / 64), - (vertex.vertex.x - brush->center.x) * ScaleFactor * (1.0f / 64) - ); - - Vector2 vertexUV = Vector2(vertex_uv.u, vertex_uv.v); - Vector3 vertexNormal = Vector3(vertex.normal.y, vertex.normal.z, vertex.normal.x); - Vector3 vertexTangent = Vector3(vertex.tangent.y, vertex.tangent.z, vertex.tangent.x); - - vertices.push_back(Vertex{ - vertexPos, - vertexUV, - vertexNormal, - vertexTangent, - glm::vec3(0.0, 1.0, 0.0) - }); - } - - for (int i = 0; i < (face_geo_inst->vertex_count - 2) * 3; ++i) - { - unsigned int index = face_geo_inst->indices[i]; - indices.push_back(index_offset + (unsigned int)index); - } - - if (lastTextureID != face->texture_idx) - { - lastTexturePath = FileSystem::Root + "textures/" + std::string(texture->name) + ".png"; - - Ref mesh = CreateRef(); - mesh->AddSurface(vertices, indices); - - if (const std::string materialPath = "textures/" + std::string(texture->name) + ".material"; - FileSystem::FileExists(materialPath)) - { - Ref material = ResourceLoader::LoadMaterial(materialPath); - mesh->SetMaterial(material); - } - else if (std::string(texture->name) != "__TB_empty") - { - Ref material = MaterialManager::Get()->GetMaterial(lastTexturePath); - mesh->SetMaterial(material); - } - - bsp.Meshes.push_back(mesh); - - index_offset = 0; - vertices.clear(); - indices.clear(); - lastTextureID = face->texture_idx; - } - else - { - index_offset += (face_geo_inst->vertex_count); - } - } - - if (vertices.size() > 0) - { - Ref mesh = CreateRef(); - mesh->AddSurface(vertices, indices); - - Ref material = MaterialManager::Get()->GetMaterial(lastTexturePath); - mesh->SetMaterial(material); - - bsp.Meshes.push_back(mesh); - } - } - - void QuakeMapBuilder::CreateFuncBrush(brush* brush, brush_geometry* brush_inst, - Scene* scene, Entity& parent, - const std::string& target, const std::string& targetname, FGDBrushEntity fgdBrush, std::map props) - { - std::vector vertices; - std::vector indices; - - std::string name = fgdBrush.Name; - if (targetname != "") - name = targetname; - - Entity brushEntity = scene->CreateEntity(name); - - TransformComponent& transformComponent = brushEntity.GetComponent(); - BSPBrushComponent& bsp = brushEntity.AddComponent(); - - std::map> m_Materials; - - bsp.IsSolid = !fgdBrush.IsTrigger; - bsp.IsTransparent = !fgdBrush.Visible; - bsp.IsFunc = true; - bsp.IsTrigger = fgdBrush.IsTrigger; - if (fgdBrush.Script != "") - { - NetScriptComponent& netScript = brushEntity.AddComponent(); - netScript.ScriptPath = fgdBrush.Script; - - ScriptingEngineNet::Get().UpdateEntityWithExposedVar(brushEntity); - for (auto& ev : netScript.ExposedVar) - { - if (props.find(ev.Name) != props.end()) - { - if (ev.Type == NetScriptExposedVarType::String) - { - ev.Value = props[ev.Name]; - ev.DefaultValue = ev.Value; - } - } - } - } - - bsp.target = target; - bsp.TargetName = targetname; - - parent.AddChild(brushEntity); - - transformComponent.SetLocalPosition(Vector3( - brush->center.y * ScaleFactor * (1.0f / 64), - brush->center.z * ScaleFactor * (1.0f / 64), - brush->center.x * ScaleFactor * (1.0f / 64))); - - int index_offset = 0; - int lastTextureID = -1; - std::string lastTexturePath = ""; - std::vector pointsInBrush; - for (int f = 0; f < brush->face_count; ++f) - { - face* face = &brush->faces[f]; - texture_data* texture = &textures[face->texture_idx]; - if (std::string(texture->name) == "__TB_empty") - { - texture->height = 1; - texture->width = 1; - } - else - { - std::string path = FileSystem::Root + std::string(texture->name) + ".png"; - auto tex = TextureManager::Get()->GetTexture(path); - texture->height = tex->GetHeight(); - texture->width = tex->GetWidth(); - } - - Ref currentMaterial; - if (std::string(texture->name) != "__TB_empty") - { - std::string path = FileSystem::Root + "Textures/" + std::string(texture->name) + ".png"; - - if (const std::string materialPath = "Materials/" + std::string(texture->name) + ".material"; - FileSystem::FileExists(materialPath)) - { - Ref material = ResourceLoader::LoadMaterial(materialPath); - m_Materials[path] = material; - } - else - { - if (m_Materials.find(path) == m_Materials.end()) - { - m_Materials[path] = MaterialManager::Get()->GetMaterial(path); - } - } - - currentMaterial = m_Materials[path]; - texture->height = currentMaterial->m_Albedo->GetHeight(); - texture->width = currentMaterial->m_Albedo->GetWidth(); - } - else - { - continue; - - currentMaterial = MaterialManager::Get()->GetMaterial("resources/Textures/default/Default.png"); - texture->height = texture->width = 1; - } - - face_geometry* face_geo_inst = &brush_inst->faces[f]; - - for (int i = 0; i < face_geo_inst->vertex_count; ++i) - { - face_vertex vertex = face_geo_inst->vertices[i]; - vertex_uv vertex_uv = get_valve_uv(vertex.vertex, face, texture->width, texture->height); - - Vector3 vertexPos = Vector3( - (vertex.vertex.y - brush->center.y) * ScaleFactor * (1.0f / 64), - (vertex.vertex.z - brush->center.z) * ScaleFactor * (1.0f / 64), - (vertex.vertex.x - brush->center.x) * ScaleFactor * (1.0f / 64) - ); - - - pointsInBrush.push_back(vertexPos); - Vector2 vertexUV = Vector2(vertex_uv.u, vertex_uv.v); - Vector3 vertexNormal = Vector3(vertex.normal.y, vertex.normal.z, vertex.normal.x); - Vector3 vertexTangent = Vector3(vertex.tangent.y, vertex.tangent.z, vertex.tangent.x); - - vertices.push_back(Vertex - { - vertexPos, - vertexUV, - vertexNormal, - vertexTangent, - glm::vec3(0.0, 1.0, 0.0) - } - ); - } - - for (int i = 0; i < (face_geo_inst->vertex_count - 2) * 3; ++i) - { - unsigned int index = face_geo_inst->indices[i]; - indices.push_back(index_offset + (unsigned int)index); - } - - if (!bsp.IsTrigger) - { - if (lastTextureID != face->texture_idx) - { - lastTexturePath = FileSystem::Root + "textures/" + std::string(texture->name) + ".png"; - Ref mesh = CreateRef(); - mesh->AddSurface(vertices, indices); - - if (std::string(texture->name) != "__TB_empty") - { - mesh->SetMaterial(currentMaterial); - } - - bsp.Meshes.push_back(mesh); - - index_offset = 0; - vertices.clear(); - indices.clear(); - lastTextureID = face->texture_idx; - } - else - { - index_offset += (face_geo_inst->vertex_count); - } - } - else - { - index_offset += (face_geo_inst->vertex_count); - } - } - bsp.Hulls.push_back(std::move(pointsInBrush)); - - if (bsp.IsTrigger) - { - Ref mesh = CreateRef(); - mesh->AddSurface(vertices, indices); - - bsp.Meshes.push_back(mesh); - vertices.clear(); - } - - if (vertices.size() > 0) - { - Ref mesh = CreateRef(); - mesh->AddSurface(vertices, indices); - - Ref material = MaterialManager::Get()->GetMaterial(lastTexturePath); - mesh->SetMaterial(material); - bsp.Meshes.push_back(mesh); - - ModelComponent& modelComponent = brushEntity.AddComponent(); - - Ref model = CreateRef(); - model->AddMesh(mesh); - modelComponent.ModelResource = model; - } - - } - void QuakeMapBuilder::BuildQuakeMap(Entity& ent, bool Collisions) { if (!ent.HasComponent()) @@ -454,6 +68,7 @@ namespace Nuake { DefaultMaterial = MaterialManager::Get()->GetMaterial("default"); Entity worldspawnEntity = { (entt::entity)-1, m_Scene }; + Entity currentNonWorldEntity; std::map pointEntities = std::map(); for (uint32_t e = 0; e < (uint32_t)entity_count; ++e) { @@ -537,41 +152,248 @@ namespace Nuake { if (!isWorldSpawn) { + currentNonWorldEntity = m_Scene->CreateEntity(properties["classname"]); + ent.AddChild(currentNonWorldEntity); + + auto& transformComponent = currentNonWorldEntity.GetComponent(); + transformComponent.SetLocalPosition({entity_inst->center.y / 64.0f, entity_inst->center.z / 64.0f, entity_inst->center.x / 64.0f }); + auto& bsp = currentNonWorldEntity.AddComponent(); + if (isPointEntity) { - if (pointEntities.find(pointEntity->Name) == pointEntities.end()) + std::string name = pointEntity->Name; + if (targetname != "") { - Entity pointEntityParent = Engine::GetCurrentScene()->CreateEntity(pointEntity->Name); - pointEntities[pointEntity->Name] = pointEntityParent; - ent.AddChild(pointEntityParent); + name = targetname; } - Entity newPrefab = Engine::GetCurrentScene()->CreateEntity(pointEntity->Name); + bsp.target = target; + bsp.TargetName = targetname; - pointEntities[pointEntity->Name].AddChild(newPrefab); - - auto& prefabComponent = newPrefab.AddComponent(); - prefabComponent.SetPrefab(Prefab::New(pointEntity->Prefab)); - newPrefab.GetComponent().SetLocalPosition(brushLocalPosition); - - for (auto& e : prefabComponent.PrefabInstance->Entities) + if (properties.find("origin") != properties.end()) { - if (!e.GetComponent().HasParent) + auto splits = String::Split(properties["origin"], ' '); + if (splits.size() == 3) { - newPrefab.AddChild(e); + int x = atoi(splits[0].c_str()); + int y = atoi(splits[1].c_str()); + int z = atoi(splits[2].c_str()); + + Vector3 pointPosition = { y / 64.0f, z / 64.0f, x / 64.0f }; + transformComponent.SetLocalPosition(pointPosition); + } + } + + if (pointEntity->Script != "") + { + NetScriptComponent& netScript = currentNonWorldEntity.AddComponent(); + netScript.ScriptPath = pointEntity->Script; + + ScriptingEngineNet::Get().UpdateEntityWithExposedVar(currentNonWorldEntity); + for (auto& ev : netScript.ExposedVar) + { + if (properties.find(ev.Name) != properties.end()) + { + if (ev.Type == NetScriptExposedVarType::String) + { + ev.Value = properties[ev.Name]; + ev.DefaultValue = ev.Value; + } + } + } + } + else + { + Entity newPrefab = Engine::GetCurrentScene()->CreateEntity(pointEntity->Name); + pointEntities[pointEntity->Name].AddChild(newPrefab); + + auto& prefabComponent = newPrefab.AddComponent(); + prefabComponent.SetPrefab(Prefab::New(pointEntity->Prefab)); + newPrefab.GetComponent().SetLocalPosition(brushLocalPosition); + + for (auto& e : prefabComponent.PrefabInstance->Entities) + { + if (!e.GetComponent().HasParent) + { + newPrefab.AddChild(e); + } } } } - - for (int b = 0; b < entity_inst->brush_count; ++b) + else { - brush* brush_inst = &entity_inst->brushes[b]; - brush_geometry* brush_geo_inst = &entity_geo_inst->brushes[b]; + std::string name = fgdBrush->Name; + if (targetname != "") + { + name = targetname; + } - if (isEntity) - CreateFuncBrush(brush_inst, brush_geo_inst, m_Scene, worldspawnEntity, target, targetname, *fgdBrush, properties); - //else - // CreateBrush(brush_inst, brush_geo_inst, m_Scene, newEntity, target, targetname); + bsp.IsSolid = !fgdBrush->IsTrigger; + bsp.IsTransparent = !fgdBrush->Visible; + bsp.IsFunc = true; + bsp.IsTrigger = fgdBrush->IsTrigger; + bsp.target = target; + bsp.TargetName = targetname; + + if (fgdBrush->Script != "") + { + NetScriptComponent& netScript = currentNonWorldEntity.AddComponent(); + netScript.ScriptPath = fgdBrush->Script; + + ScriptingEngineNet::Get().UpdateEntityWithExposedVar(currentNonWorldEntity); + for (auto& ev : netScript.ExposedVar) + { + if (properties.find(ev.Name) != properties.end()) + { + if (ev.Type == NetScriptExposedVarType::String) + { + ev.Value = properties[ev.Name]; + ev.DefaultValue = ev.Value; + } + } + } + } + + std::map> m_Materials; + std::map, std::vector> m_StaticWorld; + for (int b = 0; b < entity_inst->brush_count; ++b) + { + brush* brush_inst = &entity_inst->brushes[b]; + brush_geometry* brush_geo_inst = &entity_geo_inst->brushes[b]; + std::vector pointsInBrush; + if (isEntity) + { + std::vector vertices; + std::vector indices; + + int index_offset = 0; + int lastTextureID = -1; + std::string lastTexturePath = ""; + for (int f = 0; f < brush_inst->face_count; ++f) + { + face* face = &brush_inst->faces[f]; + texture_data* texture = &textures[face->texture_idx]; + Ref currentMaterial; + if (std::string(texture->name) != "__TB_empty") + { + std::string path = FileSystem::Root + "Textures/" + std::string(texture->name) + ".png"; + + if (const std::string materialPath = "Materials/" + std::string(texture->name) + ".material"; + FileSystem::FileExists(materialPath)) + { + Ref material = ResourceLoader::LoadMaterial(materialPath); + m_Materials[path] = material; + } + else + { + if (m_Materials.find(path) == m_Materials.end()) + { + m_Materials[path] = MaterialManager::Get()->GetMaterial(path); + } + } + + currentMaterial = m_Materials[path]; + texture->height = currentMaterial->m_Albedo->GetHeight(); + texture->width = currentMaterial->m_Albedo->GetWidth(); + } + else + { + continue; + + currentMaterial = MaterialManager::Get()->GetMaterial("resources/Textures/default/Default.png"); + texture->height = texture->width = 1; + } + + face_geometry* face_geo_inst = &brush_geo_inst->faces[f]; + std::vector vertices; + std::vector indices; + for (int i = 0; i < face_geo_inst->vertex_count; ++i) + { + face_vertex vertex = face_geo_inst->vertices[i]; + vertex_uv vertex_uv; + + if (face->is_valve_uv) + vertex_uv = get_valve_uv(vertex.vertex, face, texture->width, texture->height); + else + vertex_uv = get_standard_uv(vertex.vertex, face, texture->width, texture->height); + + Vector3 vertexPos = Vector3( + (vertex.vertex.y - entity_inst->center.y) * quakeMapC.ScaleFactor, + (vertex.vertex.z - entity_inst->center.z) * quakeMapC.ScaleFactor, + (vertex.vertex.x - entity_inst->center.x) * quakeMapC.ScaleFactor + ); + + // We need to push the hull points because the batching + // will create 1 model per material, this prevents us from + // having 1 collision shape per brush(convex). + pointsInBrush.push_back(vertexPos * (1.0f / 64.0f)); + + Vector2 vertexUV = Vector2(vertex_uv.u, 1.0 - vertex_uv.v); + Vector3 vertexNormal = Vector3(vertex.normal.y, vertex.normal.z, vertex.normal.x); + Vector3 vertexTangent = Vector3(vertex.tangent.y, vertex.tangent.z, vertex.tangent.x); + Vector3 vertexBitangent = glm::cross(vertexNormal, vertexTangent) * (float)vertex.tangent.w; + + vertices.push_back(Vertex{ + vertexPos * (1.0f / 64.0f), + vertexUV, + vertexNormal, + vertexTangent, + vertexBitangent + }); + } + + for (int i = 0; i < (face_geo_inst->vertex_count - 2) * 3; i += 3) + { + uint32_t i1 = face_geo_inst->indices[i]; + uint32_t i2 = face_geo_inst->indices[i + 1]; + uint32_t i3 = face_geo_inst->indices[i + 2]; + indices.push_back(i3); + indices.push_back(i2); + indices.push_back(i1); + } + + m_StaticWorld[currentMaterial].push_back({ vertices, indices }); + + vertices.clear(); + indices.clear(); + } + + bsp.Hulls.push_back(std::move(pointsInBrush)); + } + + //else + // CreateBrush(brush_inst, brush_geo_inst, m_Scene, newEntity, target, targetname); + } + + // Batching process + Ref model = CreateRef(); + for (auto& mat : m_StaticWorld) + { + std::vector batchedVertices; + std::vector batchedIndices; + uint32_t indexOffset = 0; + for (auto& pm : mat.second) + { + for (auto& vert : pm.Vertices) + batchedVertices.push_back(vert); + + for (auto& index : pm.Indices) + batchedIndices.push_back(indexOffset + index); + + indexOffset += static_cast(pm.Vertices.size()); + } + + Ref mesh = CreateRef(); + mesh->AddSurface(batchedVertices, batchedIndices); + mesh->SetMaterial(mat.first); + model->AddMesh(mesh); + } + + if (!bsp.IsTrigger) + { + ModelComponent& modelComponent = currentNonWorldEntity.AddComponent(); + modelComponent.ModelResource = model; + } } } else diff --git a/Nuake/src/Scripting/NetModules/SceneNetAPI.cpp b/Nuake/src/Scripting/NetModules/SceneNetAPI.cpp index 748e25bc..ac355b84 100644 --- a/Nuake/src/Scripting/NetModules/SceneNetAPI.cpp +++ b/Nuake/src/Scripting/NetModules/SceneNetAPI.cpp @@ -234,6 +234,7 @@ namespace Nuake { for (auto e : brushView) { BSPBrushComponent& brushComponent = brushView.get(e); + auto targets = brushComponent.Targets; if (brushComponent.TargetName == target) { Entity entity = { (entt::entity)(e), scene.get() }; @@ -345,6 +346,29 @@ namespace Nuake { } } + float CameraGetFOV(int entityId) + { + Entity entity = { (entt::entity)(entityId), Engine::GetCurrentScene().get() }; + + if (entity.IsValid() && entity.HasComponent()) + { + auto& component = entity.GetComponent(); + return component.CameraInstance->Fov; + } + } + + void CameraSetFOV(int entityId, float fov) + { + float safeFov = glm::clamp(fov, 1.0f, 180.0f); + Entity entity = { (entt::entity)(entityId), Engine::GetCurrentScene().get() }; + + if (entity.IsValid() && entity.HasComponent()) + { + auto& component = entity.GetComponent(); + component.CameraInstance->Fov = safeFov; + } + } + void MoveAndSlide(int entityId, float vx, float vy, float vz) { Entity entity = { (entt::entity)(entityId), Engine::GetCurrentScene().get() }; @@ -432,6 +456,30 @@ namespace Nuake { return {}; } + bool AudioEmitterGetIsPlaying(int entityId) + { + Entity entity = Entity((entt::entity)(entityId), Engine::GetCurrentScene().get()); + + if (entity.IsValid() && entity.HasComponent()) + { + auto& audioEmitter = entity.GetComponent(); + return audioEmitter.IsPlaying; + } + + return false; + } + + void AudioEmitterSetIsPlaying(int entityId, Coral::Bool32 isPlaying) + { + Entity entity = Entity((entt::entity)(entityId), Engine::GetCurrentScene().get()); + + if (entity.IsValid() && entity.HasComponent()) + { + auto& audioEmitter = entity.GetComponent(); + audioEmitter.IsPlaying = isPlaying; + } + } + void Nuake::SceneNetAPI::RegisterMethods() { // Entity @@ -443,6 +491,7 @@ namespace Nuake { RegisterMethod("Entity.EntityIsValidIcall", &EntityIsValid); RegisterMethod("Entity.EntityGetTargetsIcall", &EntityGetTargets); RegisterMethod("Entity.EntityGetTargetIcall", &EntityGetTarget); + // Prefab RegisterMethod("Prefab.PrefabInstanceIcall", &PrefabInstance); @@ -465,6 +514,8 @@ namespace Nuake { // Camera RegisterMethod("CameraComponent.GetDirectionIcall", &CameraGetDirection); + RegisterMethod("CameraComponent.GetCameraFOVIcall", &CameraGetFOV); + RegisterMethod("CameraComponent.SetCameraFOVIcall", &CameraSetFOV); // Character Controller RegisterMethod("CharacterControllerComponent.MoveAndSlideIcall", &MoveAndSlide); @@ -475,6 +526,10 @@ namespace Nuake { // Navigation Mesh RegisterMethod("NavMeshVolumeComponent.FindPathIcall", &NavMeshComponentFindPath); + + // Audio Emitter + RegisterMethod("AudioEmitterComponent.GetIsPlayingIcall", &AudioEmitterGetIsPlaying); + RegisterMethod("AudioEmitterComponent.SetIsPlayingIcall", &AudioEmitterSetIsPlaying); } } diff --git a/Nuake/src/Scripting/ScriptingEngineNet.cpp b/Nuake/src/Scripting/ScriptingEngineNet.cpp index 5c4f0b09..9d85285f 100644 --- a/Nuake/src/Scripting/ScriptingEngineNet.cpp +++ b/Nuake/src/Scripting/ScriptingEngineNet.cpp @@ -95,26 +95,38 @@ namespace Nuake { auto lineCharNums = String::Split(numbersString[0], ','); - int lineNum = std::stoi(lineCharNums[0]); - int charNum = std::stoi(lineCharNums[1]); - - // error message - std::string errMesg = ""; - int i = 0; - for (auto s : String::Split(line, ':')) + if (lineCharNums.size() == 1) { - if (i >= 3) - { - errMesg += s; - } - i++; + CompilationError compilationError; + compilationError.message = ""; + compilationError.file = filePath; + compilationError.line = 0; + errors.push_back(compilationError); } + else + { + int lineNum = std::stoi(lineCharNums[0]); + int charNum = std::stoi(lineCharNums[1]); - CompilationError compilationError; - compilationError.message = errMesg; - compilationError.file = filePath; - compilationError.line = lineNum; - errors.push_back(compilationError); + // error message + std::string errMesg = ""; + int i = 0; + for (auto s : String::Split(line, ':')) + { + if (i >= 3) + { + errMesg += s; + } + i++; + } + + CompilationError compilationError; + compilationError.message = errMesg; + compilationError.file = filePath; + compilationError.line = lineNum; + errors.push_back(compilationError); + } + } } @@ -173,6 +185,7 @@ namespace Nuake } Coral::GC::Collect(); + Coral::GC::WaitForPendingFinalizers(); GetHostInstance()->UnloadAssemblyLoadContext(m_LoadContext); @@ -298,23 +311,33 @@ namespace Nuake m_PrefabType = m_GameAssembly.GetType("Nuake.Net.Prefab"); auto& exposedFieldAttributeType = m_GameAssembly.GetType("Nuake.Net.ExposedAttribute"); auto& brushScriptAttributeType = m_GameAssembly.GetType("Nuake.Net.BrushScript"); + auto& pointScriptAttributeType = m_GameAssembly.GetType("Nuake.Net.PointScript"); for (auto& type : m_GameAssembly.GetTypes()) { + // Brush bool isBrushScript = false; std::string brushDescription; bool isTrigger = false; + + // Point + bool isPointScript = false; + std::string pointDescription; + for (auto& attribute : type->GetAttributes()) { - if (attribute.GetType() != brushScriptAttributeType) + if (attribute.GetType() == brushScriptAttributeType) { - continue; + brushDescription = attribute.GetFieldValue("Description"); + isTrigger = attribute.GetFieldValue("IsTrigger"); + isBrushScript = true; } - brushDescription = attribute.GetFieldValue("Description"); - isTrigger = attribute.GetFieldValue("IsTrigger"); - - isBrushScript = true; + if (attribute.GetType() == pointScriptAttributeType) + { + pointDescription = attribute.GetFieldValue("Description"); + isPointScript = true; + } } const std::string baseTypeName = std::string(type->GetBaseType().GetFullName()); @@ -395,6 +418,11 @@ namespace Nuake m_BrushEntityTypes[shortenedTypeName] = gameScriptObject; } + if (isPointScript) + { + gameScriptObject.Description = pointDescription; + m_PointEntityTypes[shortenedTypeName] = gameScriptObject; + } m_GameEntityTypes[shortenedTypeName] = gameScriptObject; } } diff --git a/Nuake/src/Scripting/ScriptingEngineNet.h b/Nuake/src/Scripting/ScriptingEngineNet.h index 4841c07b..40a06430 100644 --- a/Nuake/src/Scripting/ScriptingEngineNet.h +++ b/Nuake/src/Scripting/ScriptingEngineNet.h @@ -50,6 +50,7 @@ namespace Nuake { bool isTrigger = false; std::string Description = ""; + AABB aabb = AABB({0, 0, 0}, { 1, 1, 1 }); }; struct CompilationError @@ -86,6 +87,7 @@ namespace Nuake { // This is a map that contains all the instances of entity scripts. std::unordered_map m_GameEntityTypes; std::unordered_map m_BrushEntityTypes; + std::unordered_map m_PointEntityTypes; std::unordered_map m_EntityToManagedObjects; ScriptingEngineNet(); @@ -126,6 +128,7 @@ namespace Nuake { Coral::ManagedAssembly GetNuakeAssembly() const { return m_NuakeAssembly; } std::unordered_map GetBrushEntities() const { return m_BrushEntityTypes; } + std::unordered_map GetPointEntities() const { return m_PointEntityTypes; } private: std::string GenerateGUID(); }; diff --git a/NuakeNet/src/Components.cs b/NuakeNet/src/Components.cs index 0773908c..c4a6bfea 100644 --- a/NuakeNet/src/Components.cs +++ b/NuakeNet/src/Components.cs @@ -157,13 +157,25 @@ namespace Nuake.Net public class CameraComponent : IComponent { internal static unsafe delegate*> GetDirectionIcall; + internal static unsafe delegate* SetCameraFOVIcall; + internal static unsafe delegate* GetCameraFOVIcall; public CameraComponent(int entityId) { EntityID = entityId; } - public float FOV { get; set; } + public float FOV + { + get + { + unsafe { return GetCameraFOVIcall(EntityID); } + } + set + { + unsafe { SetCameraFOVIcall(EntityID, value); } + } + } public Vector3 Direction { @@ -181,6 +193,9 @@ namespace Nuake.Net public class AudioEmitterComponent : IComponent { + internal static unsafe delegate* GetIsPlayingIcall; + internal static unsafe delegate* SetIsPlayingIcall; + public AudioEmitterComponent(int entityId) { EntityID = entityId; @@ -190,7 +205,11 @@ namespace Nuake.Net public bool Loop { get; set; } public bool Spatialized { get; set; } - public bool Playing { get; set; } + public bool Playing + { + get { unsafe { return GetIsPlayingIcall(EntityID); } } + set { unsafe { SetIsPlayingIcall(EntityID, value); } } + } } public class ModelComponent : IComponent diff --git a/NuakeNet/src/main.cs b/NuakeNet/src/main.cs index f90fcd0b..6845519a 100644 --- a/NuakeNet/src/main.cs +++ b/NuakeNet/src/main.cs @@ -30,6 +30,23 @@ namespace Nuake.Net } } + public struct AABB + { + public Vector3 A; + public Vector3 B; + + public AABB(Vector3 a, Vector3 b) + { + A = a; + B = b; + } + + public AABB(float ax, float ay, float az, float bx, float by, float bz) + { + A = new Vector3(ax, ay, az); + B = new Vector3(bx, by, bz); + } + } [AttributeUsage(AttributeTargets.Field)] public sealed class ExposedAttribute : Attribute @@ -53,12 +70,30 @@ namespace Nuake.Net public sealed class PointScript : Attribute { public string Description = ""; - public bool IsTrigger = false; + public Vector3 AABBA; + public Vector2 AABBB; + + public List AABBData = new(); + public List ColorData = new(); + + public Color Color + { + get { return Color; } + set + { + ColorData.Add(value.R); + ColorData.Add(value.G); + ColorData.Add(value.B); + } + } + + string Model; + float ModelScale = 1.0f; + string Sprite; public PointScript(string description = "") { Description = description; - IsTrigger = isTrigger; } }