diff --git a/include/Engine/Core/EntityFile.h b/include/Engine/Core/EntityFile.h index 538e9047..fae39c51 100644 --- a/include/Engine/Core/EntityFile.h +++ b/include/Engine/Core/EntityFile.h @@ -1,164 +1,21 @@ #ifndef EntityFile_h__ #define EntityFile_h__ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include "World.h" +#include "EntityXMLFile.h" +#include "EntityXMLFilePreprocessor.h" +#include "EntityXMLFileParser.h" +#include "EntityWrapper.h" -#include "../GLM.h" -#include "Util/XercesString.h" -#include "ResourceManager.h" -#include "Entity.h" -#include "ComponentInfo.h" - -class EntityFileHandler -{ - friend class EntityFileSAXHandler; -public: - // @param EntityID The entity found - // @param EntityID The parent of the entity - typedef std::function OnStartEntityCallback; - void SetStartEntityCallback(OnStartEntityCallback c) { m_OnStartEntityCallback = c; } - // @param EntityID The entity the component corresponds to - // @param std::string Type name of the component - typedef std::function OnStartComponentCallback; - void SetStartComponentCallback(OnStartComponentCallback c) { m_OnStartComponentCallback = c; } - // @param EntityID Entity - // @param std::string Component name - // @param std::string Field name - // @param std::map Field attribute names and values - typedef std::function&)> OnStartFieldCallback; - void SetStartFieldCallback(OnStartFieldCallback c) { m_OnStartFieldCallback = c; } - // @param EntityID Entity - // @param std::string Component name - // @param std::string Field name - // @param char* Field data - typedef std::function OnStartFieldDataCallback; - void SetStartFieldDataCallback(OnStartFieldDataCallback c) { m_OnStartFieldDataCallback = c; } - -private: - OnStartEntityCallback m_OnStartEntityCallback = nullptr; - OnStartComponentCallback m_OnStartComponentCallback = nullptr; - OnStartFieldCallback m_OnStartFieldCallback = nullptr; - OnStartFieldDataCallback m_OnStartFieldDataCallback = nullptr; -}; - -class EntityFileSAXHandler : public xercesc::DefaultHandler +class EntityFile : private World, public Resource { public: - enum class State - { - Unknown, - Entity, - Component, - ComponentField - }; + EntityFile(std::string path); - EntityFileSAXHandler(const EntityFileHandler* handler, xercesc::SAX2XMLReader* reader); - - void startElement(const XMLCh* const _uri, const XMLCh* const _localName, const XMLCh* const _qname, const xercesc::Attributes& attrs) override; - void characters(const XMLCh* const chars, const XMLSize_t length) override; - void endElement(const XMLCh* const _uri, const XMLCh* const _localName, const XMLCh* const _qname) override; - - void warning(const xercesc::SAXParseException& e); - void error(const xercesc::SAXParseException& e); - void fatalError(const xercesc::SAXParseException& e); + EntityWrapper MergeInto(World* other); private: - const EntityFileHandler* m_Handler; - xercesc::XMLGrammarPool* m_GrammarPool; - xercesc::SAX2XMLReader* m_Reader; - //State m_CurrentScope = State::Unknown; - std::stack m_StateStack; - unsigned int m_NextEntityID = 0; - std::stack m_EntityStack; - std::string m_CurrentComponent; - std::string m_CurrentField; - std::map m_CurrentAttributes; - - void onStartEntity(const xercesc::Attributes& attrs); - void onEndEntity(); - void onStartEntityRef(const xercesc::Attributes& attrs); - void onStartComponent(const std::string& name); - void onEndComponent(const std::string& name); - void onStartComponentField(const std::string& field, const xercesc::Attributes& attrs); - void onEndComponentField(const std::string& field); - void onFieldData(char* data); -}; - -class EntityFileXMLErrorHandler : public xercesc::ErrorHandler -{ -public: - void warning(const xercesc::SAXParseException& e) override - { - reportParseException("Warning", e); - } - void error(const xercesc::SAXParseException& e) override - { - reportParseException("Error", e); - } - void fatalError(const xercesc::SAXParseException& e) override - { - reportParseException("FATAL ERROR", e); - } - void resetErrors() override { } - -private: - void reportParseException(std::string type, const xercesc::SAXParseException& e) - { - char* message = xercesc::XMLString::transcode(e.getMessage()); - char* systemID = xercesc::XMLString::transcode(e.getSystemId()); - std::cerr << systemID << ":" << e.getLineNumber() << ":" << e.getColumnNumber() << std::endl; - std::cerr << type << ": " << message << std::endl; - xercesc::XMLString::release(&systemID); - xercesc::XMLString::release(&message); - } -}; - -class EntityFile : public Resource -{ - friend class ResourceManager; - friend class EntityFileSAXHandler; -private: - EntityFile(boost::filesystem::path path); - ~EntityFile(); - -public: - static unsigned int GetTypeStride(std::string typeName); - static void WriteAttributeData(char* outData, const ComponentInfo::Field_t& field, const std::map& attributes); - static void WriteValueData(char* outData, const ComponentInfo::Field_t& field, const char* valueData); - - xercesc::XMLGrammarPool* GrammarPool() const { return m_GrammarPool; } - - void Parse(const EntityFileHandler* handler) const; - -private: - boost::filesystem::path m_FilePath; - xercesc::XMLGrammarPool* m_GrammarPool; - xercesc::SAX2XMLReader* m_SAX2XMLReader; - //std::map m_ComponentInfo; - //std::vector m_EntityReferences; - - static void setReaderFeatures(xercesc::SAX2XMLReader* reader); + EntityID m_RootEntity = EntityID_Invalid; }; #endif \ No newline at end of file diff --git a/include/Engine/Core/EntityXMLFile.h b/include/Engine/Core/EntityXMLFile.h new file mode 100644 index 00000000..6f24154d --- /dev/null +++ b/include/Engine/Core/EntityXMLFile.h @@ -0,0 +1,164 @@ +#ifndef EntityXMLFile_h__ +#define EntityXMLFile_h__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../GLM.h" +#include "Util/XercesString.h" +#include "ResourceManager.h" +#include "Entity.h" +#include "ComponentInfo.h" + +class EntityFileHandler +{ + friend class EntityFileSAXHandler; +public: + // @param EntityID The entity found + // @param EntityID The parent of the entity + typedef std::function OnStartEntityCallback; + void SetStartEntityCallback(OnStartEntityCallback c) { m_OnStartEntityCallback = c; } + // @param EntityID The entity the component corresponds to + // @param std::string Type name of the component + typedef std::function OnStartComponentCallback; + void SetStartComponentCallback(OnStartComponentCallback c) { m_OnStartComponentCallback = c; } + // @param EntityID Entity + // @param std::string Component name + // @param std::string Field name + // @param std::map Field attribute names and values + typedef std::function&)> OnStartFieldCallback; + void SetStartFieldCallback(OnStartFieldCallback c) { m_OnStartFieldCallback = c; } + // @param EntityID Entity + // @param std::string Component name + // @param std::string Field name + // @param char* Field data + typedef std::function OnStartFieldDataCallback; + void SetStartFieldDataCallback(OnStartFieldDataCallback c) { m_OnStartFieldDataCallback = c; } + +private: + OnStartEntityCallback m_OnStartEntityCallback = nullptr; + OnStartComponentCallback m_OnStartComponentCallback = nullptr; + OnStartFieldCallback m_OnStartFieldCallback = nullptr; + OnStartFieldDataCallback m_OnStartFieldDataCallback = nullptr; +}; + +class EntityFileSAXHandler : public xercesc::DefaultHandler +{ +public: + enum class State + { + Unknown, + Entity, + Component, + ComponentField + }; + + EntityFileSAXHandler(const EntityFileHandler* handler, xercesc::SAX2XMLReader* reader); + + void startElement(const XMLCh* const _uri, const XMLCh* const _localName, const XMLCh* const _qname, const xercesc::Attributes& attrs) override; + void characters(const XMLCh* const chars, const XMLSize_t length) override; + void endElement(const XMLCh* const _uri, const XMLCh* const _localName, const XMLCh* const _qname) override; + + void warning(const xercesc::SAXParseException& e); + void error(const xercesc::SAXParseException& e); + void fatalError(const xercesc::SAXParseException& e); + +private: + const EntityFileHandler* m_Handler; + xercesc::XMLGrammarPool* m_GrammarPool; + xercesc::SAX2XMLReader* m_Reader; + //State m_CurrentScope = State::Unknown; + std::stack m_StateStack; + unsigned int m_NextEntityID = 0; + std::stack m_EntityStack; + std::string m_CurrentComponent; + std::string m_CurrentField; + std::map m_CurrentAttributes; + + void onStartEntity(const xercesc::Attributes& attrs); + void onEndEntity(); + void onStartEntityRef(const xercesc::Attributes& attrs); + void onStartComponent(const std::string& name); + void onEndComponent(const std::string& name); + void onStartComponentField(const std::string& field, const xercesc::Attributes& attrs); + void onEndComponentField(const std::string& field); + void onFieldData(char* data); +}; + +class EntityFileXMLErrorHandler : public xercesc::ErrorHandler +{ +public: + void warning(const xercesc::SAXParseException& e) override + { + reportParseException("Warning", e); + } + void error(const xercesc::SAXParseException& e) override + { + reportParseException("Error", e); + } + void fatalError(const xercesc::SAXParseException& e) override + { + reportParseException("FATAL ERROR", e); + } + void resetErrors() override { } + +private: + void reportParseException(std::string type, const xercesc::SAXParseException& e) + { + char* message = xercesc::XMLString::transcode(e.getMessage()); + char* systemID = xercesc::XMLString::transcode(e.getSystemId()); + std::cerr << systemID << ":" << e.getLineNumber() << ":" << e.getColumnNumber() << std::endl; + std::cerr << type << ": " << message << std::endl; + xercesc::XMLString::release(&systemID); + xercesc::XMLString::release(&message); + } +}; + +class EntityXMLFile : public Resource +{ + friend class ResourceManager; + friend class EntityFileSAXHandler; +private: + EntityXMLFile(boost::filesystem::path path); + ~EntityXMLFile(); + +public: + static unsigned int GetTypeStride(std::string typeName); + static void WriteAttributeData(char* outData, const ComponentInfo::Field_t& field, const std::map& attributes); + static void WriteValueData(char* outData, const ComponentInfo::Field_t& field, const char* valueData); + + xercesc::XMLGrammarPool* GrammarPool() const { return m_GrammarPool; } + + void Parse(const EntityFileHandler* handler) const; + +private: + boost::filesystem::path m_FilePath; + xercesc::XMLGrammarPool* m_GrammarPool; + xercesc::SAX2XMLReader* m_SAX2XMLReader; + //std::map m_ComponentInfo; + //std::vector m_EntityReferences; + + static void setReaderFeatures(xercesc::SAX2XMLReader* reader); +}; + +#endif \ No newline at end of file diff --git a/include/Engine/Core/EntityFileParser.h b/include/Engine/Core/EntityXMLFileParser.h similarity index 78% rename from include/Engine/Core/EntityFileParser.h rename to include/Engine/Core/EntityXMLFileParser.h index b4eee5b2..4bc2fab9 100644 --- a/include/Engine/Core/EntityFileParser.h +++ b/include/Engine/Core/EntityXMLFileParser.h @@ -1,18 +1,19 @@ -#ifndef EntityFileParser_h__ -#define EntityFileParser_h__ +#ifndef EntityXMLFileParser_h__ +#define EntityXMLFileParser_h__ -#include "EntityFile.h" +#include "EntityXMLFile.h" #include "World.h" -class EntityFileParser +class EntityXMLFileParser { + friend class EntityFile; public: - EntityFileParser(const EntityFile* entityFile); - - EntityID MergeEntities(World* world, EntityID baseParent = EntityID_Invalid); + EntityXMLFileParser(const EntityXMLFile* entityFile); private: - const EntityFile* m_EntityFile; + EntityID MergeEntities(World* world, EntityID baseParent = EntityID_Invalid); + + const EntityXMLFile* m_EntityFile; EntityFileHandler m_Handler; World* m_World = nullptr; EntityID m_FirstEntity = EntityID_Invalid; diff --git a/include/Engine/Core/EntityFilePreprocessor.h b/include/Engine/Core/EntityXMLFilePreprocessor.h similarity index 80% rename from include/Engine/Core/EntityFilePreprocessor.h rename to include/Engine/Core/EntityXMLFilePreprocessor.h index b46bd383..4f969291 100644 --- a/include/Engine/Core/EntityFilePreprocessor.h +++ b/include/Engine/Core/EntityXMLFilePreprocessor.h @@ -1,5 +1,5 @@ -#ifndef EntityFilePreprocessor_h__ -#define EntityFilePreprocessor_h__ +#ifndef EntityXMLFilePreprocessor_h__ +#define EntityXMLFilePreprocessor_h__ #include #include @@ -17,17 +17,18 @@ #include "Util/XercesString.h" #include "ResourceManager.h" #include "World.h" -#include "EntityFile.h" +#include "EntityXMLFile.h" -class EntityFilePreprocessor +class EntityXMLFilePreprocessor { + friend class EntityFile; public: - EntityFilePreprocessor(const EntityFile* entityFile); - - void RegisterComponents(World* world); + EntityXMLFilePreprocessor(const EntityXMLFile* entityFile); private: - const EntityFile* m_EntityFile; + void RegisterComponents(World* world); + + const EntityXMLFile* m_EntityFile; std::map m_ComponentCounts; std::map m_ComponentInfo; diff --git a/include/Engine/Core/EntityFileWriter.h b/include/Engine/Core/EntityXMLFileWriter.h similarity index 87% rename from include/Engine/Core/EntityFileWriter.h rename to include/Engine/Core/EntityXMLFileWriter.h index b75bc145..da073a73 100644 --- a/include/Engine/Core/EntityFileWriter.h +++ b/include/Engine/Core/EntityXMLFileWriter.h @@ -1,5 +1,5 @@ -#ifndef EntityFileWriter_h__ -#define EntityFileWriter_h__ +#ifndef EntityXMLFileWriter_h__ +#define EntityXMLFileWriter_h__ #include #include @@ -8,13 +8,13 @@ #include #include "Util/XercesString.h" -#include "EntityFile.h" +#include "EntityXMLFile.h" #include "World.h" -class EntityFileWriter +class EntityXMLFileWriter { public: - EntityFileWriter(boost::filesystem::path file) + EntityXMLFileWriter(boost::filesystem::path file) : m_FilePath(file) { using namespace xercesc; diff --git a/include/Engine/Core/MemoryPool.h b/include/Engine/Core/MemoryPool.h index 053e75aa..da4af84e 100644 --- a/include/Engine/Core/MemoryPool.h +++ b/include/Engine/Core/MemoryPool.h @@ -118,9 +118,6 @@ public: else { m_ExtraMemory.push_back((char*)malloc(m_Stride)); //We should preferably not enter here to avoid performance issues. Set more numMaxElements in constructor instead. - if (!DisableMemoryPool::Value) { - LOG_DEBUG("Allocated slots exceed Pool size, extra memory allocated dynamically. Pool size: %u, dynamic size: %u.", m_NumSlots, m_ExtraMemory.size()); - } return m_ExtraMemory.back(); } } diff --git a/include/Engine/Core/World.h b/include/Engine/Core/World.h index c9f738ce..9ae38021 100644 --- a/include/Engine/Core/World.h +++ b/include/Engine/Core/World.h @@ -6,6 +6,7 @@ #include "ObjectPool.h" #include "ComponentPool.h" #include "EventBroker.h" +struct EntityWrapper; class World { @@ -18,13 +19,13 @@ public: World(const World& other); // Create empty entity - EntityID CreateEntity(EntityID parent = 0); + EntityID CreateEntity(EntityID parent = EntityID_Invalid); // Delete entity and all components within void DeleteEntity(EntityID entity); // Check if an entity exists bool ValidEntity(EntityID entity) const; // Register a component type and allocate space for it - void RegisterComponent(ComponentInfo& ci); + void RegisterComponent(const ComponentInfo& ci); // Attach a component to an entity and fill it with default values ComponentWrapper AttachComponent(EntityID entity, const std::string& componentType); // Check if an entity has a component @@ -49,6 +50,12 @@ public: void SetName(EntityID entity, const std::string& name); // Get the textual name of an entity std::string GetName(EntityID entity) const; + // Get the first entity in the world with the name. + EntityWrapper GetFirstEntityByName(const std::string& name); + + // Merge another world into this one + // Returns a map that maps entities from the other world to their copies in this one + std::unordered_map Merge(const World* other); private: EventBroker* m_EventBroker = nullptr; diff --git a/include/Engine/Editor/EditorSystem.h b/include/Engine/Editor/EditorSystem.h index 06ee53b6..655ac9b9 100644 --- a/include/Engine/Editor/EditorSystem.h +++ b/include/Engine/Editor/EditorSystem.h @@ -5,9 +5,8 @@ #include "../Core/World.h" #include "../Core/SystemPipeline.h" #include "../Core/ResourceManager.h" -#include "../Core/EntityFilePreprocessor.h" -#include "../Core/EntityFileParser.h" -#include "../Core/EntityFileWriter.h" +#include "../Core/EntityFile.h" +#include "../Core/EntityXMLFileWriter.h" #include "../Core/EMousePress.h" #include "../Input/EInputCommand.h" #include "EditorGUI.h" diff --git a/include/Engine/Input/FirstPersonInputController.h b/include/Engine/Input/FirstPersonInputController.h index 28795a7f..1cf4b828 100644 --- a/include/Engine/Input/FirstPersonInputController.h +++ b/include/Engine/Input/FirstPersonInputController.h @@ -27,7 +27,7 @@ public: virtual bool OnCommand(const Events::InputCommand& e) override; virtual void Reset(); - void AssaultDashCheck(double dt, bool isJumping, double assaultDashCoolDownMaxTimer, double& assaultDashCoolDownTimer); + void AssaultDashCheck(double dt, bool isJumping, double assaultDashCoolDownMaxTimer, double& assaultDashCoolDownTimer, EntityID playerID); bool SniperSprintingCheck(); virtual bool AssaultDashDoubleTapped() const { return m_AssaultDashDoubleTapped; } virtual bool PlayerIsDashing() const { return m_PlayerIsDashing; } @@ -42,6 +42,7 @@ protected: bool m_Crouching = false; //assault dash membervariables - needed to calculate the doubletap- and dashlogic double m_AssaultDashDoubleTapDeltaTime = 0.0; + double m_DashEffectResetTimer = 0.0; //i will let m_AssaultDashDoubleTapSensitivityTimer stay hardcoded, its not really a gamevariable (more an inputvariable), //and its very unlikely that someone wants to change that value const float m_AssaultDashDoubleTapSensitivityTimer = 0.25f; @@ -52,7 +53,7 @@ protected: bool m_ShiftDashing = false; bool m_ValidDoubleTap = false; - //specialabilitys + //specialabilities bool m_MovementKeyDown = false; bool m_SpecialAbilityKeyDown = false; int m_NumberOfMovementKeysDown = 0; @@ -191,12 +192,19 @@ bool FirstPersonInputController::OnLockMouse(const Events::LockMou } template -void FirstPersonInputController::AssaultDashCheck(double dt, bool isJumping, double assaultDashCoolDownMaxTimer, double& assaultDashCoolDownTimer) { +void FirstPersonInputController::AssaultDashCheck(double dt, bool isJumping, double assaultDashCoolDownMaxTimer, double& assaultDashCoolDownTimer, EntityID playerID) { m_AssaultDashDoubleTapDeltaTime += dt; + m_DashEffectResetTimer += dt; assaultDashCoolDownTimer -= dt; //cooldown = assaultDashCoolDownMaxTimer sec, pretend the dash lasts 0.25 sec (for friction to do its work) if (assaultDashCoolDownTimer > (assaultDashCoolDownMaxTimer - 0.25f)) { m_PlayerIsDashing = true; + if (m_DashEffectResetTimer > 0.05) { + Events::DashAbility e; + e.Player = playerID; + m_EventBroker->Publish(e); + m_DashEffectResetTimer = 0.0; + } } else { m_PlayerIsDashing = false; } @@ -208,6 +216,9 @@ void FirstPersonInputController::AssaultDashCheck(double dt, bool assaultDashCoolDownTimer = assaultDashCoolDownMaxTimer; m_AssaultDashDoubleTapped = true; m_AssaultDashDoubleTapDeltaTime = 0.f; + Events::DashAbility e; + e.Player = playerID; + m_EventBroker->Publish(e); return; } @@ -238,6 +249,7 @@ void FirstPersonInputController::AssaultDashCheck(double dt, bool assaultDashCoolDownTimer = assaultDashCoolDownMaxTimer; Events::DashAbility e; + e.Player = playerID; m_EventBroker->Publish(e); } diff --git a/include/Engine/Network/Client.h b/include/Engine/Network/Client.h index c407f7f8..4ee071d2 100644 --- a/include/Engine/Network/Client.h +++ b/include/Engine/Network/Client.h @@ -28,6 +28,7 @@ #include "Core/EPlayerSpawned.h" #include "Core/EAmmoPickup.h" #include "Network/ESearchForServers.h" +#include "../Game/Events/EDashAbility.h" struct ServerInfo { @@ -107,6 +108,7 @@ private: void parsePlayerDamage(Packet& packet); void parseComponentDeletion(Packet& packet); void parseDoubleJump(Packet& packet); + void parseDashEffect(Packet& packet); void parseAmmoPickup(Packet& packet); void InterpolateFields(Packet& packet, const ComponentInfo & componentInfo, const EntityID & entityID, const std::string & componentType); void parseSnapshot(Packet& packet); @@ -135,6 +137,9 @@ private: EventRelay< Client, Events::SearchForServers> m_ESearchForServers; EventRelay m_EDoubleJump; bool OnDoubleJump(Events::DoubleJump & e); + EventRelay m_EDashAbility; + bool OnDashAbility(const Events::DashAbility& e); + bool OnSearchForServers(const Events::SearchForServers& e); UDPClient m_ServerlistRequest; std::vector m_Serverlist; diff --git a/include/Engine/Network/MessageType.h b/include/Engine/Network/MessageType.h index bf773618..c34f584e 100644 --- a/include/Engine/Network/MessageType.h +++ b/include/Engine/Network/MessageType.h @@ -20,6 +20,7 @@ enum class MessageType ComponentDeleted, PlayerTransform, OnDoubleJump, + OnDashEffect, ServerlistRequest, AmmoPickup, Invalid diff --git a/include/Engine/Network/Server.h b/include/Engine/Network/Server.h index 3c956ed9..7bcefc65 100644 --- a/include/Engine/Network/Server.h +++ b/include/Engine/Network/Server.h @@ -83,6 +83,7 @@ private: void parseClientPing(); void parsePing(); bool parseDoubleJump(Packet& packet); + void parseDashEffect(Packet& packet); void parseUDPConnect(Packet& packet); void parseTCPConnect(Packet& packet); void parseDisconnect(); diff --git a/include/Game/Events/EDashAbility.h b/include/Game/Events/EDashAbility.h index 62a2b935..c5078fab 100644 --- a/include/Game/Events/EDashAbility.h +++ b/include/Game/Events/EDashAbility.h @@ -2,11 +2,15 @@ #define Events_DashAbility_h__ #include "Core/Event.h" +#include "Core/EntityWrapper.h" namespace Events { -struct DashAbility : public Event { }; +struct DashAbility : public Event +{ + EntityID Player; +}; } diff --git a/include/Game/Game.h b/include/Game/Game.h index 06fd4703..4d173b48 100644 --- a/include/Game/Game.h +++ b/include/Game/Game.h @@ -13,13 +13,13 @@ #include "Input/KeyboardInputHandler.h" #include "Input/MouseInputHandler.h" #include "Core/EKeyDown.h" -#include "Core/EntityFilePreprocessor.h" +#include "Core/EntityXMLFilePreprocessor.h" #include "Core/SystemPipeline.h" #include "Systems/ExplosionEffectSystem.h" #include "Editor/EditorSystem.h" -#include "Core/EntityFile.h" +#include "Core/EntityXMLFile.h" #include "Rendering/RenderSystem.h" -#include "Core/EntityFileParser.h" +#include "Core/EntityXMLFileParser.h" #include "Core/Octree.h" #include "Rendering/Font.h" #include "Systems/InterpolationSystem.h" diff --git a/include/Game/Systems/AbilityCooldownHUDSystem.h b/include/Game/Systems/AbilityCooldownHUDSystem.h new file mode 100644 index 00000000..610b4dc2 --- /dev/null +++ b/include/Game/Systems/AbilityCooldownHUDSystem.h @@ -0,0 +1,17 @@ +#ifndef AbilityCooldownHUDSystem_h__ +#define AbilityCooldownHUDSystem_h__ + +#include "../../Engine/Core/System.h" +#include "../../Engine/GLM.h" + +class AbilityCooldownHUDSystem : public ImpureSystem +{ +public: + AbilityCooldownHUDSystem(SystemParams params) + : System(params) + { } + + virtual void Update(double dt) override; +}; + +#endif \ No newline at end of file diff --git a/include/Game/Systems/AmmoPickupSystem.h b/include/Game/Systems/AmmoPickupSystem.h index 7917e765..70c5630f 100644 --- a/include/Game/Systems/AmmoPickupSystem.h +++ b/include/Game/Systems/AmmoPickupSystem.h @@ -4,7 +4,7 @@ #include "Core/System.h" #include "Core/Transform.h" #include "Core/ResourceManager.h" -#include "Core/EntityFileParser.h" +#include "Core/EntityFile.h" #include "Core/EPickupSpawned.h" #include "Core/EAmmoPickup.h" #include "Engine/Collision/ETrigger.h" diff --git a/include/Game/Systems/BoostIconsHUDSystem.h b/include/Game/Systems/BoostIconsHUDSystem.h new file mode 100644 index 00000000..d8de777d --- /dev/null +++ b/include/Game/Systems/BoostIconsHUDSystem.h @@ -0,0 +1,19 @@ +#ifndef BoostIconsHUDSystem_h__ +#define BoostIconsHUDSystem_h__ + +#include "../../Engine/Core/System.h" +#include "../../Engine/GLM.h" + +class BoostIconsHUDSystem : public PureSystem +{ +public: + BoostIconsHUDSystem(SystemParams params) + : System(params) + , PureSystem("BoostIconsHUD") + { } + + virtual void UpdateComponent(EntityWrapper& entity, ComponentWrapper& capturePoint, double dt) override; + +}; + +#endif \ No newline at end of file diff --git a/include/Game/Systems/BoostSystem.h b/include/Game/Systems/BoostSystem.h index f82707ab..f02e9472 100644 --- a/include/Game/Systems/BoostSystem.h +++ b/include/Game/Systems/BoostSystem.h @@ -3,7 +3,7 @@ #include "Core/System.h" #include "Core/ResourceManager.h" -#include "Core/EntityFileParser.h" +#include "Core/EntityFile.h" #include "Core/EPlayerDamage.h" #include "Common.h" diff --git a/include/Game/Systems/DamageIndicatorSystem.h b/include/Game/Systems/DamageIndicatorSystem.h index ae9ba195..9c88ba78 100644 --- a/include/Game/Systems/DamageIndicatorSystem.h +++ b/include/Game/Systems/DamageIndicatorSystem.h @@ -4,7 +4,7 @@ #include "Core/System.h" #include "Core/Transform.h" #include "Core/ResourceManager.h" -#include "Core/EntityFileParser.h" +#include "Core/EntityFile.h" #include "Core/EPlayerDamage.h" #include "Common.h" #include diff --git a/include/Game/Systems/FloatingEffectSystem.h b/include/Game/Systems/FloatingEffectSystem.h new file mode 100644 index 00000000..56931001 --- /dev/null +++ b/include/Game/Systems/FloatingEffectSystem.h @@ -0,0 +1,19 @@ +#include "Common.h" +#include "Core/System.h" + +class FloatingEffectSystem : public PureSystem +{ +public: + FloatingEffectSystem(SystemParams params) + : System(params) + , PureSystem("FloatingEffect") + { } + + virtual void UpdateComponent(EntityWrapper& entity, ComponentWrapper& component, double dt) override + { + ComponentWrapper& transform = m_World->GetComponent(component.EntityID, "Transform"); + (double&)component["Time"] += dt; + (glm::vec3&)transform["Position"] = (float)(double)component["Amplitude"] * glm::sin((glm::two_pi() / (float)(double)component["Period"]) * (float)(double)component["Time"]) * (glm::vec3)component["Axis"]; + + } +}; \ No newline at end of file diff --git a/include/Game/Systems/PickupSpawnSystem.h b/include/Game/Systems/PickupSpawnSystem.h index be99141c..b72b8b25 100644 --- a/include/Game/Systems/PickupSpawnSystem.h +++ b/include/Game/Systems/PickupSpawnSystem.h @@ -4,7 +4,7 @@ #include "Core/System.h" #include "Core/Transform.h" #include "Core/ResourceManager.h" -#include "Core/EntityFileParser.h" +#include "Core/EntityFile.h" #include "Core/EPickupSpawned.h" #include "Core/EPlayerHealthPickup.h" #include "Engine/Collision/ETrigger.h" diff --git a/include/Game/Systems/PlayerDeathSystem.h b/include/Game/Systems/PlayerDeathSystem.h index 112c202e..e4f96114 100644 --- a/include/Game/Systems/PlayerDeathSystem.h +++ b/include/Game/Systems/PlayerDeathSystem.h @@ -6,11 +6,9 @@ #include "GLM.h" #include "Rendering/ESetCamera.h" #include "Core/ConfigFile.h" - #include "Core/EntityFile.h" -#include "Core/EntityFileParser.h" - #include "Core/EPlayerDeath.h" +#include "Core/EEntityDeleted.h" class PlayerDeathSystem : public ImpureSystem { @@ -20,8 +18,12 @@ public: virtual void Update(double dt) override; private: + EntityWrapper m_LocalPlayerDeathEffect; + EventRelay m_OnPlayerDeath; bool OnPlayerDeath(Events::PlayerDeath& e); + EventRelay m_EEntityDeleted; + bool OnEntityDeleted(Events::EntityDeleted& e); void createDeathEffect(EntityWrapper player); diff --git a/include/Game/Systems/PlayerMovementSystem.h b/include/Game/Systems/PlayerMovementSystem.h index 92aa1915..bf7b4718 100644 --- a/include/Game/Systems/PlayerMovementSystem.h +++ b/include/Game/Systems/PlayerMovementSystem.h @@ -6,9 +6,7 @@ #include #include "Events/EDoubleJump.h" #include "../Engine/Sound/EPlaySoundOnEntity.h" - #include "Core/EntityFile.h" -#include "Core/EntityFileParser.h" class PlayerMovementSystem : public ImpureSystem { @@ -41,6 +39,8 @@ private: bool OnPlayerSpawned(Events::PlayerSpawned& e); EventRelay m_EDoubleJump; bool PlayerMovementSystem::OnDoubleJump(Events::DoubleJump & e); + EventRelay m_EDashAbility; + bool PlayerMovementSystem::OnDashAbility(Events::DashAbility & e); void updateMovementControllers(double dt); void updateVelocity(EntityWrapper player, double dt); diff --git a/include/Game/Systems/SpawnerSystem.h b/include/Game/Systems/SpawnerSystem.h index e4a44738..f36f7259 100644 --- a/include/Game/Systems/SpawnerSystem.h +++ b/include/Game/Systems/SpawnerSystem.h @@ -7,8 +7,7 @@ #include "Core/System.h" #include "Events/ESpawnerSpawn.h" #include "Core/Transform.h" -#include "Core/ResourceManager.h" -#include "Core/EntityFileParser.h" +#include "Core/EntityFile.h" class SpawnerSystem : public System { diff --git a/include/Game/Systems/Weapon/WeaponSystem.h b/include/Game/Systems/Weapon/WeaponSystem.h index b8278bc4..f6543ffb 100644 --- a/include/Game/Systems/Weapon/WeaponSystem.h +++ b/include/Game/Systems/Weapon/WeaponSystem.h @@ -9,8 +9,8 @@ #include "Core/EShoot.h" #include "Core/EPlayerSpawned.h" #include "Input/EInputCommand.h" -#include "Core/EntityFile.h" -#include "Core/EntityFileParser.h" +#include "Core/EntityXMLFile.h" +#include "Core/EntityXMLFileParser.h" #include "Core/Octree.h" #include "Collision/EntityAABB.h" #include "Systems/SpawnerSystem.h" diff --git a/resources/DefaultConfig.ini b/resources/DefaultConfig.ini index e99e3437..8917e3e1 100644 --- a/resources/DefaultConfig.ini +++ b/resources/DefaultConfig.ini @@ -4,7 +4,7 @@ LoadMap= ; if true -> Pool allocation is not used when calling Allocate/Free, just use regular dynamic allocation. ; if false -> Use pool allocation. DisableMemoryPool=false -RespawnTime = 8.0 +RespawnTime = -1.0 EditorEnabled=false OutOfBodyExperience=false diff --git a/resources/Schema/Components.xsd b/resources/Schema/Components.xsd index a75de84e..004a11a7 100644 --- a/resources/Schema/Components.xsd +++ b/resources/Schema/Components.xsd @@ -51,9 +51,12 @@ + + + \ No newline at end of file diff --git a/resources/Schema/Components/AbilityCooldownHUD.xml b/resources/Schema/Components/AbilityCooldownHUD.xml new file mode 100644 index 00000000..8f91bbc3 --- /dev/null +++ b/resources/Schema/Components/AbilityCooldownHUD.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/resources/Schema/Components/AbilityCooldownHUD.xsd b/resources/Schema/Components/AbilityCooldownHUD.xsd new file mode 100644 index 00000000..5bfb01a8 --- /dev/null +++ b/resources/Schema/Components/AbilityCooldownHUD.xsd @@ -0,0 +1,9 @@ + + + + + + HUD element for tracking ability cooldown. If it has a sprite and fill component it will fill the sprite with chosen color depending on the cooldown.\n A child with text component named "Cooldown" + + + \ No newline at end of file diff --git a/resources/Schema/Components/BoostIconsHUD.xml b/resources/Schema/Components/BoostIconsHUD.xml new file mode 100644 index 00000000..e25d9611 --- /dev/null +++ b/resources/Schema/Components/BoostIconsHUD.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/Schema/Components/BoostIconsHUD.xsd b/resources/Schema/Components/BoostIconsHUD.xsd new file mode 100644 index 00000000..c5fe2e5d --- /dev/null +++ b/resources/Schema/Components/BoostIconsHUD.xsd @@ -0,0 +1,10 @@ + + + + + + + Origin for the 3 boost states. Create 3 children with Sprite and Fill components, name them "Sprint", "Defender", "Assault" + + + \ No newline at end of file diff --git a/resources/Schema/Components/FloatingEffect.xml b/resources/Schema/Components/FloatingEffect.xml new file mode 100644 index 00000000..f1fd237a --- /dev/null +++ b/resources/Schema/Components/FloatingEffect.xml @@ -0,0 +1,8 @@ + + + 1 + 1 + + + + \ No newline at end of file diff --git a/resources/Schema/Components/FloatingEffect.xsd b/resources/Schema/Components/FloatingEffect.xsd new file mode 100644 index 00000000..a71006f5 --- /dev/null +++ b/resources/Schema/Components/FloatingEffect.xsd @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/resources/Schema/Components/Text.xml b/resources/Schema/Components/Text.xml index d38d3961..cda29b86 100644 --- a/resources/Schema/Components/Text.xml +++ b/resources/Schema/Components/Text.xml @@ -1,7 +1,7 @@ - + Fonts/DroidSans.ttf,64 true
diff --git a/resources/Schema/Entities/DashEffect.xml b/resources/Schema/Entities/DashEffect.xml new file mode 100644 index 00000000..9dfdc14c --- /dev/null +++ b/resources/Schema/Entities/DashEffect.xml @@ -0,0 +1,18 @@ + + + + + + + 0.5 + + + + 0 + 0.5 + + + + + + diff --git a/resources/Schema/Entities/NewMap2version2.xml b/resources/Schema/Entities/NewMap2version2.xml index fcb81666..8089073f 100644 --- a/resources/Schema/Entities/NewMap2version2.xml +++ b/resources/Schema/Entities/NewMap2version2.xml @@ -804,11 +804,11 @@ - + 2 - + @@ -825,7 +825,7 @@ - + @@ -851,11 +851,11 @@ - + 2 - + @@ -872,7 +872,7 @@ - + @@ -898,11 +898,11 @@ - + 2 - + @@ -919,7 +919,7 @@ - + @@ -945,11 +945,11 @@ - + 2 - + @@ -966,7 +966,7 @@ - + @@ -992,11 +992,11 @@ - + 2 - + @@ -1013,7 +1013,7 @@ - + @@ -1039,11 +1039,11 @@ - + 2 - + @@ -1060,7 +1060,7 @@ - + @@ -1086,11 +1086,11 @@ - + 2 - + @@ -1107,7 +1107,7 @@ - + @@ -2242,7 +2242,7 @@ Models/Props/Stones/AssaultHolder.mesh - + @@ -2355,11 +2355,11 @@ - + 2 - + @@ -2376,7 +2376,7 @@ - + @@ -2402,11 +2402,11 @@ - + 2 - + @@ -2423,7 +2423,7 @@ - + @@ -2904,11 +2904,11 @@ - + 2 - + @@ -2925,7 +2925,7 @@ - + @@ -2951,11 +2951,11 @@ - + 2 - + @@ -2972,7 +2972,7 @@ - + @@ -2998,11 +2998,11 @@ - + 2 - + @@ -3019,7 +3019,7 @@ - + @@ -3045,11 +3045,11 @@ - + 2 - + @@ -3066,7 +3066,7 @@ - + @@ -3092,11 +3092,11 @@ - + 2 - + @@ -3113,7 +3113,7 @@ - + @@ -3139,11 +3139,11 @@ - + 2 - + @@ -3160,7 +3160,7 @@ - + @@ -3186,11 +3186,11 @@ - + 2 - + @@ -3207,7 +3207,7 @@ - + diff --git a/resources/Schema/Entities/NewMap2version3NEW.xml b/resources/Schema/Entities/NewMap2version3NEW.xml index 5b224de3..61e7b740 100644 --- a/resources/Schema/Entities/NewMap2version3NEW.xml +++ b/resources/Schema/Entities/NewMap2version3NEW.xml @@ -802,8 +802,13 @@ + + + + 2 + - + @@ -821,7 +826,7 @@ - + @@ -844,8 +849,13 @@ + + + + 2 + - + @@ -863,7 +873,7 @@ - + @@ -886,8 +896,13 @@ + + + + 2 + - + @@ -905,7 +920,7 @@ - + @@ -928,8 +943,13 @@ + + + + 2 + - + @@ -947,7 +967,7 @@ - + @@ -970,8 +990,13 @@ + + + + 2 + - + @@ -989,7 +1014,7 @@ - + @@ -1012,8 +1037,13 @@ + + + + 2 + - + @@ -1031,7 +1061,7 @@ - + @@ -1054,8 +1084,13 @@ + + + + 2 + - + @@ -1073,7 +1108,7 @@ - + @@ -2318,8 +2353,13 @@ + + + + 2 + - + @@ -2337,7 +2377,7 @@ - + @@ -2360,8 +2400,13 @@ + + + + 2 + - + @@ -2379,7 +2424,7 @@ - + @@ -2857,8 +2902,13 @@ + + + + 2 + - + @@ -2876,7 +2926,7 @@ - + @@ -2899,8 +2949,13 @@ + + + + 2 + - + @@ -2918,7 +2973,7 @@ - + @@ -2941,8 +2996,13 @@ + + + + 2 + - + @@ -2960,7 +3020,7 @@ - + @@ -2983,8 +3043,13 @@ + + + + 2 + - + @@ -3002,7 +3067,7 @@ - + @@ -3025,8 +3090,13 @@ + + + + 2 + - + @@ -3044,7 +3114,7 @@ - + @@ -3067,8 +3137,13 @@ + + + + 2 + - + @@ -3086,7 +3161,7 @@ - + @@ -3109,8 +3184,13 @@ + + + + 2 + - + @@ -3128,7 +3208,7 @@ - + @@ -4222,7 +4302,7 @@ - -15 + -15 4 @@ -4444,7 +4524,7 @@ - 1 + 0.40000000596046448 diff --git a/resources/Schema/Entities/NewMapWSpectatorCam.xml b/resources/Schema/Entities/NewMapWSpectatorCam.xml new file mode 100644 index 00000000..bf1b4c2b --- /dev/null +++ b/resources/Schema/Entities/NewMapWSpectatorCam.xml @@ -0,0 +1,5532 @@ + + + + + + 0.0 + 15 + + + + + + + + + + + + + + + Models/Props/Ground.mesh + + + + + + + + + Models/Props/Highground1.mesh + + + + + + + + + + Models/Props/Highground2.mesh + + + + + + + + + + Models/Props/Highground1.mesh + + + + + + + + + + + + Models/Props/Highground2.mesh + + + + + + + + + + + + Models/Props/Highground3.mesh + + + + + + + + + + Models/Props/Highground4.mesh + + + + + + + + + + Models/Props/Highground5.mesh + + + + + + + + + + + Models/Props/Highground6.mesh + + + + + + + + + + Models/Props/Walls/SciFiWallTop.mesh + + + + + + + + + Models/Props/Walls/SciFiWallBig.mesh + + + + + + + + + + Models/Props/Walls/SciFiWallMedium.mesh + + + + + + + + + + Models/Props/Walls/SciFiWallSmall1.mesh + + + + + + + + + + Models/Props/Walls/SciFiWallSmall2.mesh + + + + + + + + + + Models/Props/Walls/SciFiWallBig.mesh + + + + + + + + + + + + Models/Props/Walls/SciFiWallMedium.mesh + + + + + + + + + + + + Models/Props/Walls/SciFiWallSmall3.mesh + + + + + + + + + + Models/Props/Walls/SciFiWallSmall4.mesh + + + + + + + + + + + + + + + + + + + + + + Models/Props/Pillars/SciFiPillar1Blue.mesh + + + + + + + + + + + + + Models/Props/Pillars/SciFiPillar1Red.mesh + + + + + + + + + + + + + Models/Props/Pillars/StonePillar.mesh + + + + + + + + + + + + Models/Props/Pillars/StonePillar.mesh + + + + + + + + + + + + + Models/Props/Pillars/SciFiPillar2Red.mesh + + + + + + + + + + + + + Models/Props/Pillars/SciFiPillar3Blue.mesh + + + + + + + + + + + + + + Models/Props/Pillars/SciFiPillar1Blue.mesh + + + + + + + + + + + + + + Models/Props/Pillars/SciFiPillar1Red.mesh + + + + + + + + + + + + + + Models/Props/Pillars/SciFiPillar3Red.mesh + + + + + + + + + + + + + + Models/Props/Pillars/StonePillar.mesh + + + + + + + + + + + + Models/Props/Pillars/StonePillar.mesh + + + + + + + + + + + + + Models/Props/Pillars/StonePillar.mesh + + + + + + + + + + + + + Models/Props/Pillars/SciFiPillar2Blue.mesh + + + + + + + + + + + + + Models/Props/Pillars/SciFiPillar2Red.mesh + + + + + + + + + + + + + Models/Props/Pillars/StonePillar.mesh + + + + + + + + + + + Models/Props/Pillars/StonePillar.mesh + + + + + + + + + + + + + + + Models/Props/Pillars/SciFiPillar2Blue.mesh + + + + + + + + + + + + + + Models/Props/Pillars/SciFiPillar2Blue.mesh + + + + + + + + + + + + + + Models/Props/Pillars/SciFiPillar2Blue.mesh + + + + + + + + + + + + + + Models/Props/Pillars/SciFiPillar2Blue.mesh + + + + + + + + + + + + + Models/Props/Pillars/StonePillar.mesh + + + + + + + + + + + + + Models/Props/Pillars/SciFiPillar2Red.mesh + + + + + + + + + + + + + + Models/Props/Pillars/SciFiPillar2Red.mesh + + + + + + + + + + + + + Models/Props/Pillars/SciFiPillar2Red.mesh + + + + + + + + + + + + + + Models/Props/Pillars/StonePillar.mesh + + + + + + + + + + + + + Models/Props/Pillars/SciFiPillar2Red.mesh + + + + + + + + + + + + + + + + + + + + Models/Props/Walls/BigWallBlue.mesh + + + + + + + + + + + Models/Props/Walls/BigWallBlue.mesh + + + + + + + + + + + + + + + Models/Props/Walls/BigWallBlue.mesh + + + + + + + + + + + Models/Props/Walls/BigWallBlue.mesh + + + + + + + + + + + + + + Models/Props/Walls/BigWallRed.mesh + + + + + + + + + + + + Models/Props/Walls/BigWallRed.mesh + + + + + + + + + + + + + + + Models/Props/Walls/BigWallRed.mesh + + + + + + + + + + + + Models/Props/Walls/BigWallRed.mesh + + + + + + + + + + + + + + + Models/Props/Walls/BigWallRed.mesh + + + + + + + + + + + + Models/Props/Walls/BigWallRed.mesh + + + + + + + + + + + + + + Models/Props/Walls/BigWallRed.mesh + + + + + + + + + + + + + + + + Models/Props/Walls/BigWallBlue.mesh + + + + + + + + + + + + Models/Props/Walls/BigWallBlue.mesh + + + + + + + + + + + + + Models/Props/Walls/BigWallBlue.mesh + + + + + + + + + + + + + + + Models/Props/Walls/MediumWall3.mesh + + + + + + + + + + + + Models/Props/Walls/MediumWall3.mesh + + + + + + + + + + + + + + Models/Props/Walls/SmallWall3.mesh + + + + + + + + + + + + + Models/Props/Walls/SmallWall3.mesh + + + + + + + + + + + + Models/Props/Walls/SmallWall3.mesh + + + + + + + + + + + + + + Models/Props/Walls/SmallWall2.mesh + + + + + + + + + + + + + Models/Props/Walls/SmallWall4.mesh + + + + + + + + + + + + Models/Props/Walls/SmallWall3.mesh + + + + + + + + + + + + Models/Props/Walls/SmallWall2.mesh + + + + + + + + + + + + + Models/Props/Walls/SmallWall2.mesh + + + + + + + + + + + + + Models/Props/Walls/SmallWall2.mesh + + + + + + + + + + + + + Models/Props/Walls/MediumWall2.mesh + + + + + + + + + + + + Models/Props/Walls/MediumWall2.mesh + + + + + + + + + + + + + + Models/Props/Walls/MediumWall1.mesh + + + + + + + + + + + + Models/Props/Walls/MediumWall1.mesh + + + + + + + + + + + + + + Models/Props/Walls/MediumWall1.mesh + + + + + + + + + + + + Models/Props/Walls/MediumWall1.mesh + + + + + + + + + + + + Models/Props/Walls/MediumWall1.mesh + + + + + + + + + + + + + + Models/Props/Walls/BigWallRed.mesh + + + + + + + + + + + Models/Props/Walls/BigWallRed.mesh + + + + + + + + + + + + Models/Props/Walls/BigWallRed.mesh + + + + + + + + + + + Models/Props/Walls/BigWallRed.mesh + + + + + + + + + + + + + + + + Models/Props/Walls/BigWallRed.mesh + + + + + + + + + + + + + Models/Props/Walls/BigWallRed.mesh + + + + + + + + + + + + + + Models/Props/Walls/BigWallBlue.mesh + + + + + + + + + + + Models/Props/Walls/BigWallBlue.mesh + + + + + + + + + + + + Models/Props/Walls/BigWallBlue.mesh + + + + + + + + + + + + Models/Props/Walls/BigWallBlue.mesh + + + + + + + + + + + + + + Models/Props/Walls/BigWallBlue.mesh + + + + + + + + + + + + Models/Props/Walls/SmallWall3.mesh + + + + + + + + + + + + Models/Props/Walls/SmallWall3.mesh + + + + + + + + + + + + + Models/Props/Walls/SmallWall4.mesh + + + + + + + + + + + + + + Models/Props/Walls/SmallWall4.mesh + + + + + + + + + + + + Models/Props/Walls/SmallWall2.mesh + + + + + + + + + + + + + + Models/Props/Walls/SmallWall2.mesh + + + + + + + + + + + + + Models/Props/Walls/BigWallBlue.mesh + + + + + + + + + + + + Models/Props/Walls/BigWallBlue.mesh + + + + + + + + + + + Models/Props/Walls/BigWallBlue.mesh + + + + + + + + + + + + + + + Models/Props/Walls/SmallWall2.mesh + + + + + + + + + + + + + + Models/Props/Walls/SmallWall2.mesh + + + + + + + + + + + Models/Props/Walls/BigWallBlue.mesh + + + + + + + + + + + Models/Props/Walls/BigWallBlue.mesh + + + + + + + + + + + + + + + + Models/Props/Walls/BigWallBlue.mesh + + + + + + + + + + + Models/Props/Walls/BigWallBlue.mesh + + + + + + + + + + + + Models/Props/Walls/BigWallBlue.mesh + + + + + + + + + + + + Models/Props/Walls/BigWallBlue.mesh + + + + + + + + + + + + + + Models/Props/Walls/BigWallBlue.mesh + + + + + + + + + + + + Models/Props/Walls/BigWallBlue.mesh + + + + + + + + + + + + + + + Models/Props/Walls/MediumWall3.mesh + + + + + + + + + + + + + Models/Props/Walls/BigWallRed.mesh + + + + + + + + + + + Models/Props/Walls/BigWallRed.mesh + + + + + + + + + + + + Models/Props/Walls/BigWallRed.mesh + + + + + + + + + + + + + + Models/Props/Walls/BigWallRed.mesh + + + + + + + + + + + + Models/Props/Walls/BigWallRed.mesh + + + + + + + + + + + + + + Models/Props/Walls/BigWallRed.mesh + + + + + + + + + + + + Models/Props/Walls/BigWallRed.mesh + + + + + + + + + + + + Models/Props/Walls/SmallWall2.mesh + + + + + + + + + + + + Models/Props/Walls/BigWallRed.mesh + + + + + + + + + + + + + + Models/Props/Walls/SmallWall3.mesh + + + + + + + + + + + + Models/Props/Walls/SpecialWall1.mesh + + + + + + + + + + + + + + Models/Props/Flora/SpecialRoot.mesh + + + + + + + + + + + + + + Models/Props/Walls/MediumWall1.mesh + + + + + + + + + + + + + Models/Props/Walls/MediumWall1.mesh + + + + + + + + + + + + + Models/Props/Walls/MediumWall1.mesh + + + + + + + + + + + + Models/Props/Walls/MediumWall3.mesh + + + + + + + + + + + + + Models/Props/Walls/MediumWall1.mesh + + + + + + + + + + + + Models/Props/Walls/MediumWall1.mesh + + + + + + + + + + + + + + Models/Props/Walls/SmallWall2.mesh + + + + + + + + + + + + + Models/Props/Walls/SmallWall2.mesh + + + + + + + + + + + + Models/Props/Walls/SmallWall2.mesh + + + + + + + + + + + + Models/Props/Walls/MediumWall3.mesh + + + + + + + + + + + + Models/Props/Walls/MediumWall2.mesh + + + + + + + + + + + Models/Props/Walls/MediumWall2.mesh + + + + + + + + + + + + + Models/Props/Walls/SmallWall3.mesh + + + + + + + + + + + + Models/Props/Walls/SmallWall4.mesh + + + + + + + + + + + + + + + + Models/Props/Walls/MediumWall3.mesh + + + + + + + + + + + + + Models/Props/Walls/MediumWall2.mesh + + + + + + + + + + + + + Models/Props/Walls/SpecialWall1.mesh + + + + + + + + + + + + + + Models/Props/Walls/MediumWall1.mesh + + + + + + + + + + + + + Models/Props/Walls/SpecialWall1.mesh + + + + + + + + + + + + Models/Props/Walls/SpecialWall1.mesh + + + + + + + + + + + + + Models/Props/Walls/SpecialWall1.mesh + + + + + + + + + + + + + Models/Props/Walls/SpecialWall1.mesh + + + + + + + + + + + + + Models/Props/Walls/SpecialWall1.mesh + + + + + + + + + + + + + + Models/Props/Walls/SpecialWall1.mesh + + + + + + + + + + + + + + + + + + + + + Models/Props/Bridges/WoodenBridge.mesh + + + + + + + + + + + + + + Models/Props/Bridges/WoodenBridge.mesh + + + + + + + + + + + + + + Models/Props/Bridges/WoodenBridge.mesh + + + + + + + + + + + + + Models/Props/Bridges/SciFiBridge1Red.mesh + + + + + + + + + + + + + Models/Props/Bridges/SciFiBridgeDefense.mesh + + + + + + + + + + + + Models/Props/Bridges/SciFiBridgeDefense.mesh + + + + + + + + + + + Models/Props/Bridges/SciFiBridgeDefense.mesh + + + + + + + + + + + Models/Props/Bridges/SciFiBridgeDefense.mesh + + + + + + + + + + + + + + + + + + Models/Props/Bridges/SciFiBridgeDefense.mesh + + + + + + + + + + + + Models/Props/Bridges/SciFiBridgeDefense.mesh + + + + + + + + + + + Models/Props/Bridges/SciFiBridgeDefense.mesh + + + + + + + + + + + Models/Props/Bridges/SciFiBridgeDefense.mesh + + + + + + + + + + + + + + + + + + + + Models/Props/Bridges/SciFiBridge1Blue.mesh + + + + + + + + + + + + + Models/Props/Bridges/SciFiBridgeDefense.mesh + + + + + + + + + + + + Models/Props/Bridges/SciFiBridgeDefense.mesh + + + + + + + + + + + Models/Props/Bridges/SciFiBridgeDefense.mesh + + + + + + + + + + + + Models/Props/Bridges/SciFiBridgeDefense.mesh + + + + + + + + + + + + + + + + + + Models/Props/Bridges/SciFiBridgeDefense.mesh + + + + + + + + + + + + Models/Props/Bridges/SciFiBridgeDefense.mesh + + + + + + + + + + + Models/Props/Bridges/SciFiBridgeDefense.mesh + + + + + + + + + + + Models/Props/Bridges/SciFiBridgeDefense.mesh + + + + + + + + + + + + + + + + + + + + Models/Props/Pillars/SciFiBridgePillar1.mesh + + + + + + + + + + + + + + Models/Props/Bridges/SciFiBridge1Blue.mesh + + + + + + + + + + + + + Models/Props/Bridges/SciFiBridge1Blue.mesh + + + + + + + + + + + + + Models/Props/Pillars/SciFiBridgePillar1.mesh + + + + + + + + + + + + + + Models/Props/Bridges/SciFiBridge1Red.mesh + + + + + + + + + + + + + Models/Props/Bridges/SciFiBridge1Red.mesh + + + + + + + + + + + + + Models/Props/Bridges/WoodenBridge.mesh + + + + + + + + + + + + + + + + + + + + + Models/Props/Pillars/SciFiBridgePillar1.mesh + + + + + + + + + + + + + + Models/Props/Pillars/SciFiBridgePillar1.mesh + + + + + + + + + + + + + + Models/Props/Walls/MediumWall2.mesh + + + + + + + + + + + Models/Props/Walls/MediumWall2.mesh + + + + + + + + + + + + + + + Models/Props/Walls/MediumWall3.mesh + + + + + + + + + + + Models/Props/Walls/MediumWall3.mesh + + + + + + + + + + + + + + Models/Props/Pillars/SciFiBridgePillar1.mesh + + + + + + + + + + + + Models/Core/UnitCube.mesh + + + + + + + + + + + + + + + Models/Props/Walls/MediumWall1.mesh + + + + + + + + + + + + Models/Props/Walls/MediumWall1.mesh + + + + + + + + + + + + Models/Props/Walls/MediumWall1.mesh + + + + + + + + + + + + + + Models/Props/Walls/MediumWall1.mesh + + + + + + + + + + + Models/Props/Walls/MediumWall1.mesh + + + + + + + + + + + + + + Models/Core/UnitCube.mesh + + + + + + + + + + + + + Models/Core/UnitCube.mesh + + + + + + + + + + + + + + Models/Core/UnitPlane.mesh + + true + + + + + + + + + + + + + Models/Core/UnitPlane.mesh + + true + + + + + + + + + + + + + + Models/Core/UnitCube.mesh + + + + + + + + + + + + + Models/Core/UnitCube.mesh + + + + + + + + + + + + + + + + Models/Props/Pillars/SciFiBridgePillar1.mesh + + + + + + + + + + + + + + Models/Props/Pillars/SciFiBridgePillar1.mesh + + + + + + + + + + + + + + + + + + + + Models/Props/Flora/AliveBush.mesh + true + + + + + + + + + + + + Models/Props/Flora/AliveBush.mesh + true + + + + + + + + + + Models/Props/Flora/AliveBush.mesh + true + + + + + + + + + + + Models/Props/Flora/AliveBush.mesh + true + + + + + + + + + + + Models/Props/Flora/AliveBush.mesh + true + + + + + + + + + + + Models/Props/Flora/AliveBush.mesh + true + + + + + + + + + + + Models/Props/Flora/AliveBush.mesh + true + + + + + + + + + + + + + + + Models/Props/Flora/TreeLog.mesh + + + + + + + + + + + + + Models/Props/Flora/AliveBush.mesh + true + + + + + + + + + + Models/Props/Flora/AliveBush.mesh + true + + + + + + + + + + + + + Models/Props/Flora/AliveBush.mesh + true + + + + + + + + + + Models/Props/Flora/AliveBush.mesh + true + + + + + + + + + + + Models/Props/Flora/AliveBush.mesh + true + + + + + + + + + + + Models/Props/Flora/AliveBush.mesh + true + + + + + + + + + + + + + Models/Props/Flora/AliveBush.mesh + true + + + + + + + + + + Models/Props/Flora/AliveBush.mesh + true + + + + + + + + + + + + Models/Props/Flora/AliveBush.mesh + true + + + + + + + + + + + + + + Models/Props/Flora/SpecialRoot.mesh + + + + + + + + + + + + Models/Props/Flora/AliveBush.mesh + true + + + + + + + + + + Models/Props/Flora/AliveBush.mesh + true + + + + + + + + + + + Models/Props/Flora/AliveBush.mesh + true + + + + + + + + + + + Models/Props/Flora/AliveBush.mesh + true + + + + + + + + + + + Models/Props/Flora/AliveBush.mesh + true + + + + + + + + + + + Models/Props/Flora/AliveBush.mesh + true + + + + + + + + + + + + + Models/Props/Flora/AliveBush.mesh + true + + + + + + + + + + Models/Props/Flora/AliveBush.mesh + true + + + + + + + + + + + Models/Props/Flora/AliveBush.mesh + true + + + + + + + + + + + Models/Props/Flora/AliveBush.mesh + true + + + + + + + + + + + + + Models/Props/Flora/AliveBush.mesh + true + + + + + + + + + + + + + Models/Props/Flora/AliveBush.mesh + true + + + + + + + + + + + + + Models/Props/Flora/AliveBush.mesh + true + + + + + + + + + + + Models/Props/Flora/AliveBush.mesh + true + + + + + + + + + + + + + + + Models/Props/Flora/AliveBush.mesh + true + + + + + + + + + + + + + Models/Props/Flora/AliveBush.mesh + true + + + + + + + + + + + + + + Models/Props/Flora/SpecialRoot.mesh + + + + + + + + + + + + + Models/Props/Flora/AliveBush.mesh + true + + + + + + + + + + + + + Models/Props/Flora/AliveBush.mesh + true + + + + + + + + + + + + + Models/Props/Flora/AliveBush.mesh + true + + + + + + + + + + + + Models/Props/Flora/AliveBush.mesh + true + + + + + + + + + + + + + + Models/Props/Flora/AliveBush.mesh + true + + + + + + + + + + + + + + Models/Props/Flora/AliveBush.mesh + true + + + + + + + + + + + + + + Models/Props/Flora/AliveBush.mesh + true + + + + + + + + + + + + + + Models/Props/Flora/SpecialRoot.mesh + + + + + + + + + + + + + + + + + + + + + Models/Props/Stones/BigStone.mesh + + + + + + + + + + + + + Models/Props/Stones/MediumStone2.mesh + + + + + + + + + + + + + + Models/Props/Stones/BigStone.mesh + + + + + + + + + + + + + Models/Props/Stones/BigStone.mesh + + + + + + + + + + + + + + Models/Props/Stones/BigStone.mesh + + + + + + + + + + + + Models/Props/Stones/BigStone.mesh + + + + + + + + + + + + + Models/Props/Stones/BigStone.mesh + + + + + + + + + + + + + + + + Models/Props/Stones/BigStone.mesh + + + + + + + + + + + + + Models/Props/Stones/MediumStone1.mesh + + + + + + + + + + + + + + Models/Props/Stones/SmallStone1.mesh + + + + + + + + + + + + + + Models/Props/Stones/BigStone.mesh + + + + + + + + + + + + Models/Props/Stones/MediumStone1.mesh + + + + + + + + + + + + + Models/Props/Stones/MediumStone1.mesh + + + + + + + + + + + + + + + Models/Props/Stones/MediumStone1.mesh + + + + + + + + + + + + + + Models/Props/Stones/BigStone.mesh + + + + + + + + + + + + Models/Props/Stones/BigStone.mesh + + + + + + + + + + + + + Models/Props/Stones/BigStone.mesh + + + + + + + + + + + + + Models/Props/Stones/BigStone.mesh + + + + + + + + + + + + + Models/Props/Stones/MediumStone2.mesh + + + + + + + + + + + + + + Models/Props/Stones/BigStone.mesh + + + + + + + + + + + + Models/Props/Stones/BigStone.mesh + + + + + + + + + + + + + + + + + Models/Props/Stones/BigStone.mesh + + + + + + + + + + + Models/Props/Stones/BigStone.mesh + + + + + + + + + + + + + Models/Props/Stones/BigStone.mesh + + + + + + + + + + + + + Models/Props/Stones/BigStone.mesh + + + + + + + + + + + + + Models/Props/Stones/SmallStone1.mesh + + + + + + + + + + + + + + Models/Props/Stones/BigStone.mesh + + + + + + + + + + + + + + + Models/Props/Stones/BigStone.mesh + + + + + + + + + + + + Models/Props/Stones/BigStone.mesh + + + + + + + + + + + + + + + + Models/Props/Stones/BigStone.mesh + + + + + + + + + + + + + Models/Props/Stones/BigStone.mesh + + + + + + + + + + + + + Models/Props/Stones/BigStone.mesh + + + + + + + + + + + + + Models/Props/Stones/BigStone.mesh + + + + + + + + + + + + Models/Props/Stones/SmallStone2.mesh + + + + + + + + + + + + + + Models/Props/Stones/MediumStone2.mesh + + + + + + + + + + + + + Models/Props/Stones/ShinyStoneCrystalRed.mesh + + + + + + + + + + + + + + Models/Props/Stones/ShinyStoneCrystalRed.mesh + + + + + + + + + + + + + + Models/Props/Stones/ShinyStoneCrystalRed.mesh + + + + + + + + + + + + + + Models/Props/Walls/MediumWall1.mesh + + + + + + + + + + + + Models/Props/Stones/BigStone.mesh + + + + + + + + + + + + + Models/Props/Stones/SmallStone1.mesh + + + + + + + + + + + + + + Models/Props/Stones/MediumStone2.mesh + + + + + + + + + + + + + Models/Props/Stones/MediumStone2.mesh + + + + + + + + + + + + + Models/Props/Stones/SmallStone2.mesh + + + + + + + + + + + + + Models/Props/Stones/MediumStone2.mesh + + + + + + + + + + + + Models/Props/Stones/MediumStone2.mesh + + + + + + + + + + + + + + Models/Props/Stones/SmallStone1.mesh + + + + + + + + + + + + + + Models/Props/Stones/MediumStone2.mesh + + + + + + + + + + + + + + Models/Props/Stones/SmallStone1.mesh + + + + + + + + + + + + + Models/Props/Stones/SmallStone2.mesh + + + + + + + + + + + + + + Models/Props/Stones/SmallStone1.mesh + + + + + + + + + + + + + + Models/Props/Stones/MediumStone1.mesh + + + + + + + + + + + + + + + + + + + Models/Props/Stones/SmallStone1.mesh + + + + + + + + + + + + + Models/Props/Stones/SmallStone2.mesh + + + + + + + + + + + + + + Models/Props/Stones/MediumStone2.mesh + + + + + + + + + + + + + Models/Props/Stones/SmallStone1.mesh + + + + + + + + + + + + + + + Models/Props/Stones/SmallStone1.mesh + + + + + + + + + + + + + + Models/Props/Stones/SmallStone1.mesh + + + + + + + + + + + + + + + + Models/Props/Stones/SmallStone2.mesh + + + + + + + + + + + + + + Models/Props/Stones/SmallStone1.mesh + + + + + + + + + + + + + Models/Props/Stones/SmallStone2.mesh + + + + + + + + + + + + + + Models/Props/Stones/MediumStone2.mesh + + + + + + + + + + + + + + Models/Props/Stones/BigStone.mesh + + + + + + + + + + + + + Models/Props/Stones/MediumStone2.mesh + + + + + + + + + + + + Models/Props/Stones/MediumStone2.mesh + + + + + + + + + + + + + Models/Props/Stones/SmallStone1.mesh + + + + + + + + + + + + + + + + Models/Props/Stones/SmallStone2.mesh + + + + + + + + + + + + + + Models/Props/Stones/MediumStone2.mesh + + + + + + + + + + + + + + Models/Props/Stones/MediumStone1.mesh + + + + + + + + + + + + + + Models/Props/Stones/MediumStone2.mesh + + + + + + + + + + + + + Models/Props/Stones/BigStone.mesh + + + + + + + + + + + + + Models/Props/Stones/SmallStone2.mesh + + + + + + + + + + + + + + Models/Props/Stones/MediumStone2.mesh + + + + + + + + + + + + + + + + + + + + + Models/Props/PickUps/PickUpHolder.mesh + + + + + + + + + + + + + + Models/Props/PickUps/PickUpHolder.mesh + + + + + + + + + + + + + + Models/Props/PickUps/PickUpHolder.mesh + + + + + + + + + + + + + + Models/Props/PickUps/PickUpHolder.mesh + + + + + + + + + + + + + + + + + + + + + + + + Models/Props/PickUps/PickUpHolder.mesh + + + + + + + + + + + + + + Models/Props/PickUps/PickUpHolder.mesh + + + + + + + + + + + + + Models/Props/PickUps/PickUpHolder.mesh + + + + + + + + + + + + + + Models/Props/PickUps/PickUpHolder.mesh + + + + + + + + + + + + + + Models/Props/PickUps/PickUpHolder.mesh + + + + + + + + + + + + + + + + + + + + + Models/Props/Stones/AssaultHolder.mesh + + + + + + + + + + + + Models/Props/Stones/AssaultHolder.mesh + + + + + + + + + + + + + + + Models/Props/Stones/AssaultHolder.mesh + + + + + + + + + + + + Models/Props/Stones/AssaultHolder.mesh + + + + + + + + + + + + + + + Models/Props/Stones/AssaultHolder.mesh + + + + + + + + + + + + Models/Props/Stones/AssaultHolder.mesh + + + + + + + + + + + + Models/Props/Stones/AssaultHolder.mesh + + + + + + + + + + + + Models/Props/Stones/AssaultHolder.mesh + + + + + + + + + + + + + + + + + + + Models/Props/Stones/AssaultHolder.mesh + + + + + + + + + + + + + + Models/Props/Stones/AssaultHolder.mesh + + + + + + + + + + + + + + Models/Props/Stones/AssaultHolder.mesh + + + + + + + + + + + + + + Models/Props/Stones/AssaultHolder.mesh + + + + + + + + + + + + + + + + + + + + + Models/Props/SciFiHolder1.mesh + + + + + + + + + + + + + Models/Props/SciFiHolder1.mesh + + + + + + + + + + + + + Models/Props/SciFiHolder1.mesh + + + + + + + + + + + + + Models/Props/SciFiHolder1.mesh + + + + + + + + + + + + + Models/Props/SciFiHolder1.mesh + + + + + + + + + + + + + Models/Props/SciFiHolder1.mesh + + + + + + + + + + + + + Models/Props/SciFiHolder1.mesh + + + + + + + + + + + + + Models/Props/SciFiHolder1.mesh + + + + + + + + + + + + + + + + + + + + Models/Props/Stones/ShinyStoneCrystalRed.mesh + + + + + + + + + + + + + Models/Props/Stones/ShinyStoneCrystalRed.mesh + + + + + + + + + + + + + + Models/Props/Stones/ShinyStoneCrystalRed.mesh + + + + + + + + + + + + + Models/Props/Stones/ShinyStoneCrystalBlue.mesh + + + + + + + + + + + + + + Models/Props/Stones/ShinyStoneCrystalBlue.mesh + + + + + + + + + + + + + + Models/Props/Stones/ShinyStoneCrystalBlue.mesh + + + + + + + + + + + + + + Models/Props/Stones/ShinyStoneCrystalBlue.mesh + + + + + + + + + + + + + + Models/Props/Stones/ShinyStoneCrystalBlue.mesh + + + + + + + + + + + + + Models/Props/Stones/ShinyStoneCrystalRed.mesh + + + + + + + + + + + + + + Models/Props/Stones/ShinyStoneCrystalRed.mesh + + + + + + + + + + + + + + Models/Props/Stones/ShinyStoneCrystalBlue.mesh + + + + + + + + + + + + + + Models/Props/Stones/ShinyStoneCrystalBlue.mesh + + + + + + + + + + + + + + Models/Props/Stones/ShinyStoneCrystalRed.mesh + + + + + + + + + + + + + + Models/Props/Stones/ShinyStoneCrystalRed.mesh + + + + + + + + + + + + + Models/Props/Stones/ShinyStoneCrystalBlue.mesh + + + + + + + + + + + + + + Models/Props/Stones/ShinyStoneCrystalBlue.mesh + + + + + + + + + + + + + + Models/Props/Stones/ShinyStoneCrystalRed.mesh + + + + + + + + + + + + + + + + + + + + + + + Models/Props/CapturePoint/CapturePointBlue.mesh + + + + + + + + + + + + + 4 + + + Models/Core/UnitCylinder.mesh + + true + + + + + + + + + + + + + + + + + + + + + Models/Props/CapturePoint/CapturePointNeutral.mesh + + + + + + + + + + 3 + + + Models/Core/UnitCylinder.mesh + + true + + + + + + + + + + + + + + + + + Models/Props/CapturePoint/CapturePointNeutral.mesh + + + + + + + + + + 2 + + + Models/Core/UnitCylinder.mesh + + true + + + + + + + + + + + + + + + + + Models/Props/CapturePoint/CapturePointNeutral.mesh + + + + + + + + + + 1.5498908015879351 + 1 + + + Models/Core/UnitCylinder.mesh + + true + + + + + + + + + + + + + + + + + Models/Props/CapturePoint/CapturePointRed.mesh + + + + + + + + + + + + + + + Models/Core/UnitCylinder.mesh + + true + + + + + + + + + + + + + + + + + + + + + + + + + + + 1 + + + + + + + + + 10 + + + + + + + + + + 10 + + + + + + + + + + + + + 10 + + + + + + + + + + + 10 + + + + + + + + + + + 10 + + + + + + + + + + + 1 + + + + + + + + + + + + + + Schema/Entities/PlayerRed.xml + + + + + + + + + + + + + + + + Models/Characters/Assault/AssaultTPose.mesh + false + + + + + + + + + + + + Models/Characters/Assault/AssaultTPose.mesh + false + + + + + + + + + + + + Models/Characters/Assault/AssaultTPose.mesh + false + + + + + + + + + + + + Models/Characters/Assault/AssaultTPose.mesh + false + + + + + + + + + + + + + + Schema/Entities/Player.xml + + + + + + + + + + + + + + + + Models/Characters/Assault/AssaultTPose.mesh + false + + + + + + + + + + + + Models/Characters/Assault/AssaultTPose.mesh + false + + + + + + + + + + + + Models/Characters/Assault/AssaultTPose.mesh + false + + + + + + + + + + + + Models/Characters/Assault/AssaultTPose.mesh + false + + + + + + + + + + + + + + + + + + + 0.10000000149011612 + + + + Models/Props/PickUps/HealthPickUp.mesh + + + + + + + + + + + + + + + 0.10000000149011612 + + + + Models/Props/PickUps/AmmoPickUp.mesh + + + + + + + + + + + + + + + 0.10000000149011612 + + + + Models/Props/PickUps/HealthPickUp.mesh + + + + + + + + + + + + + + + 0.10000000149011612 + + + + Models/Props/PickUps/HealthPickUp.mesh + + + + + + + + + + + + + + + 0.10000000149011612 + + + + Models/Props/PickUps/AmmoPickUp.mesh + + + + + + + + + + + + + + + 0.10000000149011612 + + + + Models/Props/PickUps/HealthPickUp.mesh + + + + + + + + + + + + + + + 0.10000000149011612 + + + + Models/Props/PickUps/AmmoPickUp.mesh + + + + + + + + + + + + + + + 0.10000000149011612 + + + + Models/Props/PickUps/AmmoPickUp.mesh + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Fonts/DroidSans.ttf,64 + + + + + + + + + + + + + + + + + + + + + Textures/Core/UnitHexagon.png + + + + + + + + + + + + 2 + + + + + + Textures/Core/UnitHexagon_Rotated.png + + + + + + + + + + + + + + + + Textures/Core/UnitHexagon.png + + + + + + + + + + + + 3 + + + + + + Textures/Core/UnitHexagon_Rotated.png + + + + + + + + + + + + + + + + Textures/Core/UnitHexagon.png + + + + + + + + + + + + 4 + + + + + + Textures/Core/UnitHexagon_Rotated.png + + + + + + + + + + + + + + + + Textures/Core/UnitHexagon.png + + + + + + + + + + + + 1 + + + 0.59265931447347009 + + + + Textures/Core/UnitHexagon_Rotated.png + + + + + + + + + + + + + + + + Textures/Core/UnitHexagon.png + + + + + + + + + + + + + + + + Textures/Core/UnitHexagon_Rotated.png + + + + + + + + + + + + + + + + + + + + + diff --git a/resources/Schema/Entities/Player.xml b/resources/Schema/Entities/Player.xml index 28ace561..34692605 100644 --- a/resources/Schema/Entities/Player.xml +++ b/resources/Schema/Entities/Player.xml @@ -100,12 +100,12 @@ 1 - 100/100 Fonts/DroidSans.ttf,64 + @@ -132,7 +132,70 @@ - + + + + + + + + + + + + + + Textures/Core/White.png + false + + + + + + + + + + + + + + + + + Textures/Core/White.png + false + + + + + + + + + + + + + + + + + Textures/Core/White.png + false + + + + + + + + + + + + + @@ -196,7 +259,6 @@ 3 - 0.80222018197612788 @@ -231,6 +293,7 @@ 4 + 1 @@ -286,7 +349,7 @@ Textures/Core/UnitHexagon.png - + @@ -297,7 +360,8 @@ - + 1 + Textures/Core/UnitHexagon_Rotated.png @@ -306,7 +370,7 @@ - + @@ -369,6 +433,25 @@ + + + + + Models/Widgets/Arrows/Arrow5.mesh + + + + + + + + + + + + + + diff --git a/resources/Schema/Entities/SpectatorCamera.xml b/resources/Schema/Entities/SpectatorCamera.xml new file mode 100644 index 00000000..5c3dc514 --- /dev/null +++ b/resources/Schema/Entities/SpectatorCamera.xml @@ -0,0 +1,219 @@ + + + + + + + + + + + + + + + + + + + + + + Time to respawn: 0 + Fonts/DroidSans.ttf,64 + + + + + + + + + + + + + + + + + + + + + + + + Textures/Core/UnitHexagon.png + + + + + + + + + + + + 2 + + + + + + Textures/Core/UnitHexagon_Rotated.png + + + + + + + + + + + + + + + + Textures/Core/UnitHexagon.png + + + + + + + + + + + + 3 + + + + + + Textures/Core/UnitHexagon_Rotated.png + + + + + + + + + + + + + + + + Textures/Core/UnitHexagon.png + + + + + + + + + + + + 4 + + + + + + Textures/Core/UnitHexagon_Rotated.png + + + + + + + + + + + + + + + + Textures/Core/UnitHexagon.png + + + + + + + + + + + + 1 + + + 0.59265931447347009 + + + + Textures/Core/UnitHexagon_Rotated.png + + + + + + + + + + + + + + + + Textures/Core/UnitHexagon.png + + + + + + + + + + + + + + + + Textures/Core/UnitHexagon_Rotated.png + + + + + + + + + + + + + + + + + + + diff --git a/resources/Schema/Types/Entity.xsd b/resources/Schema/Types/Entity.xsd index 61d8e520..1d8ea8f3 100644 --- a/resources/Schema/Types/Entity.xsd +++ b/resources/Schema/Types/Entity.xsd @@ -51,8 +51,17 @@ + + + + + + + + + diff --git a/resources/Shaders/ForwardPlusSplatMapRGBShieldCheck.frag.glsl b/resources/Shaders/ForwardPlusSplatMapRGBShieldCheck.frag.glsl index fa3af6ac..d61726fe 100644 --- a/resources/Shaders/ForwardPlusSplatMapRGBShieldCheck.frag.glsl +++ b/resources/Shaders/ForwardPlusSplatMapRGBShieldCheck.frag.glsl @@ -40,7 +40,6 @@ layout (binding = 10) uniform sampler2D SpecularMapTexture3; layout (binding = 11) uniform sampler2D GlowMapTexture1; layout (binding = 12) uniform sampler2D GlowMapTexture2; layout (binding = 13) uniform sampler2D GlowMapTexture3; -layout (binding = 13) uniform sampler2D GlowMapTexture3; layout (binding = 31) uniform samplerCube ShieldBuffer; #define TILE_SIZE 16 diff --git a/src/Engine/Core/EntityFile.cpp b/src/Engine/Core/EntityFile.cpp index 3987b092..997b9c46 100644 --- a/src/Engine/Core/EntityFile.cpp +++ b/src/Engine/Core/EntityFile.cpp @@ -1,291 +1,25 @@ #include "Core/EntityFile.h" -EntityFile::EntityFile(boost::filesystem::path path) - : m_FilePath(path) +EntityFile::EntityFile(std::string path) { - using namespace xercesc; - XMLPlatformUtils::Initialize(); - m_GrammarPool = new XMLGrammarPoolImpl(); - m_SAX2XMLReader = XMLReaderFactory::createXMLReader(XMLPlatformUtils::fgMemoryManager, m_GrammarPool); -} + EntityXMLFile* xml = ResourceManager::Load(path); -EntityFile::~EntityFile() -{ - delete m_SAX2XMLReader; - delete m_GrammarPool; - xercesc::XMLPlatformUtils::Terminate(); -} + EntityXMLFilePreprocessor preprocessor(xml); + preprocessor.RegisterComponents(this); -void EntityFile::Parse(const EntityFileHandler* handler) const -{ - using namespace xercesc; + EntityXMLFileParser parser(xml); + m_RootEntity = parser.MergeEntities(this); - EntityFileSAXHandler saxHandler(handler, m_SAX2XMLReader); - setReaderFeatures(m_SAX2XMLReader); - m_SAX2XMLReader->setContentHandler(&saxHandler); - m_SAX2XMLReader->setErrorHandler(&saxHandler); - m_SAX2XMLReader->setDeclarationHandler(&saxHandler); - m_SAX2XMLReader->parse(m_FilePath.string().c_str()); -} - -void EntityFile::setReaderFeatures(xercesc::SAX2XMLReader* reader) -{ - using namespace xercesc; - reader->setFeature(XMLUni::fgXercesCacheGrammarFromParse, true); - reader->setFeature(XMLUni::fgXercesUseCachedGrammarInParse, true); - reader->setFeature(XMLUni::fgSAX2CoreValidation, true); - reader->setFeature(XMLUni::fgSAX2CoreNameSpaces, true); - reader->setFeature(XMLUni::fgXercesSchema, true); - reader->setFeature(XMLUni::fgXercesSchemaFullChecking, true); - reader->setFeature(XMLUni::fgXercesCalculateSrcOfs, true); - reader->setFeature(XMLUni::fgXercesIdentityConstraintChecking, true); -} - -unsigned int EntityFile::GetTypeStride(std::string typeName) -{ - std::map typeStrides{ - { "bool", sizeof(bool) }, - { "int", sizeof(int) }, - { "float", sizeof(float) }, - { "double", sizeof(double) }, - { "string", sizeof(std::string) }, - { "enum", sizeof(ComponentInfo::EnumType) }, - { "Vector", sizeof(glm::vec3) }, - { "Quaternion", sizeof(glm::quat) }, - { "Color", sizeof(glm::vec4) } - }; - - auto it = typeStrides.find(typeName); - return (it != typeStrides.end()) ? it->second : 0; -} - -void EntityFile::WriteAttributeData(char* outData, const ComponentInfo::Field_t& field, const std::map& attributes) -{ - if (field.Type == "Vector") { - glm::vec3 vec; - vec.x = boost::lexical_cast(attributes.at("X")); - vec.y = boost::lexical_cast(attributes.at("Y")); - vec.z = boost::lexical_cast(attributes.at("Z")); - memcpy(outData, reinterpret_cast(&vec), field.Stride); - } else if (field.Type == "Color") { - glm::vec4 vec; - vec.r = boost::lexical_cast(attributes.at("R")); - vec.g = boost::lexical_cast(attributes.at("G")); - vec.b = boost::lexical_cast(attributes.at("B")); - vec.a = boost::lexical_cast(attributes.at("A")); - memcpy(outData, reinterpret_cast(&vec), field.Stride); - } else if (field.Type == "Quaternion") { - glm::quat q; - q.x = boost::lexical_cast(attributes.at("X")); - q.y = boost::lexical_cast(attributes.at("Y")); - q.z = boost::lexical_cast(attributes.at("Z")); - q.w = boost::lexical_cast(attributes.at("W")); - memcpy(outData, reinterpret_cast(&q), field.Stride); - } else if (!attributes.empty()) { - LOG_WARNING("%i attributes not handled by any type conversion!", attributes.size()); - } -} - -void EntityFile::WriteValueData(char* outData, const ComponentInfo::Field_t& field, const char* valueData) -{ - // Catch and ignore casting errors so whitespace around string enums won't mess anything up - try { - if (field.Type == "int") { - int value = boost::lexical_cast(valueData); - memcpy(outData, reinterpret_cast(&value), field.Stride); - } else if (field.Type == "enum") { - ComponentInfo::EnumType value = boost::lexical_cast(valueData); - memcpy(outData, reinterpret_cast(&value), field.Stride); - } else if (field.Type == "float") { - float value = boost::lexical_cast(valueData); - memcpy(outData, reinterpret_cast(&value), field.Stride); - } else if (field.Type == "double") { - double value = boost::lexical_cast(valueData); - memcpy(outData, reinterpret_cast(&value), field.Stride); - } else if (field.Type == "bool") { - bool value = (valueData[0] == 't'); // Lazy bool evaluation - memcpy(outData, reinterpret_cast(&value), field.Stride); - } else if (field.Type == "string") { - new (outData) std::string(valueData); - } else { - LOG_WARNING("Unknown value data type: %s", field.Type.c_str()); - } - } catch (const boost::bad_lexical_cast&) { } -} - -EntityFileSAXHandler::EntityFileSAXHandler(const EntityFileHandler* handler, xercesc::SAX2XMLReader* reader) - : m_Handler(handler) - , m_Reader(reader) -{ - // 0 is imaginary base parent - m_EntityStack.push(0); - m_StateStack.push(State::Unknown); -} - -void EntityFileSAXHandler::startElement(const XMLCh* const _uri, const XMLCh* const _localName, const XMLCh* const _qname, const xercesc::Attributes& attrs) -{ - std::string name = XS::ToString(_localName); - - if (m_StateStack.top() == State::Unknown || m_StateStack.top() == State::Entity) { - if (name == "Entity") { - m_StateStack.push(State::Entity); - onStartEntity(attrs); - return; - } - if (name == "EntityRef") { - onStartEntityRef(attrs); - return; - } + if (m_RootEntity == EntityID_Invalid) { + ResourceManager::Release("EntityXMLFile", path); + throw Resource::FailedLoadingException("Failed to merge entities; root entity is invalid"); } - std::string uri = XS::ToString(_uri); - if (m_StateStack.top() == State::Entity) { - if (uri == "components") { - m_StateStack.push(State::Component); - onStartComponent(name); - return; - } - } - - if (m_StateStack.top() == State::Component) { - m_StateStack.push(State::ComponentField); - onStartComponentField(name, attrs); - return; - } + ResourceManager::Release("EntityXMLFile", path); } -void EntityFileSAXHandler::endElement(const XMLCh* const _uri, const XMLCh* const _localName, const XMLCh* const _qname) +EntityWrapper EntityFile::MergeInto(World* other) { - std::string name = XS::ToString(_localName); - if (m_StateStack.top() == State::Entity) { - if (name == "Entity") { - m_StateStack.pop(); - onEndEntity(); - return; - } - } - - std::string uri = XS::ToString(_uri); - if (m_StateStack.top() == State::Component) { - //if (uri == "components") { - m_StateStack.pop(); - onEndComponent(name); - return; - //} - } - - if (m_StateStack.top() == State::ComponentField && name == m_CurrentField) { - m_StateStack.pop(); - onEndComponentField(name); - return; - } -} - -void EntityFileSAXHandler::characters(const XMLCh* const chars, const XMLSize_t length) -{ - if (m_StateStack.top() == State::ComponentField) { - char* transcoded = xercesc::XMLString::transcode(chars); - onFieldData(transcoded); - } -} - -void EntityFileSAXHandler::fatalError(const xercesc::SAXParseException& e) -{ - std::string message = XS::ToString(e.getMessage()); - std::string systemId = XS::ToString(e.getSystemId()); - XMLFileLoc line = e.getLineNumber(); - XMLFileLoc column = e.getColumnNumber(); - LOG_ERROR("SAXParseException\n\tLocation: %s:%i:%i\n\tFatal Error: %s", systemId.c_str(), line, column, message.c_str()); -} - -void EntityFileSAXHandler::error(const xercesc::SAXParseException& e) -{ - std::string message = XS::ToString(e.getMessage()); - std::string systemId = XS::ToString(e.getSystemId()); - XMLFileLoc line = e.getLineNumber(); - XMLFileLoc column = e.getColumnNumber(); - LOG_ERROR("SAXParseException\n\tLocation: %s:%i:%i\n\tError: %s", systemId.c_str(), line, column, message.c_str()); -} - -void EntityFileSAXHandler::warning(const xercesc::SAXParseException& e) -{ - std::string message = XS::ToString(e.getMessage()); - std::string systemId = XS::ToString(e.getSystemId()); - XMLFileLoc line = e.getLineNumber(); - XMLFileLoc column = e.getColumnNumber(); - LOG_ERROR("SAXParseException\n\tLocation: %s:%i:%i\n\tWarning: %s", systemId.c_str(), line, column, message.c_str()); -} - -void EntityFileSAXHandler::onStartEntity(const xercesc::Attributes& attrs) -{ - EntityID parent = m_EntityStack.top(); - - if (m_Handler->m_OnStartEntityCallback) { - std::string name; - auto xName = attrs.getValue(XS::ToXMLCh("name")); - if (xName != nullptr) { - name = XS::ToString(xName); - } - m_Handler->m_OnStartEntityCallback(m_NextEntityID, parent, name); - } - - m_EntityStack.push(m_NextEntityID); - m_NextEntityID++; -} - -void EntityFileSAXHandler::onEndEntity() -{ - m_EntityStack.pop(); -} - -void EntityFileSAXHandler::onStartEntityRef(const xercesc::Attributes& attrs) -{ - std::string path = XS::ToString(attrs.getValue(XS::ToXMLCh("file"))); - - xercesc::SAX2XMLReader* reader = xercesc::XMLReaderFactory::createXMLReader(); - EntityFile::setReaderFeatures(reader); - reader->setContentHandler(this); - reader->setErrorHandler(this); - reader->parse(path.c_str()); - delete reader; -} - -void EntityFileSAXHandler::onStartComponentField(const std::string& field, const xercesc::Attributes& attrs) -{ - //LOG_DEBUG(" Field: %s", field.c_str()); - m_CurrentField = field; - m_CurrentAttributes.clear(); - for (int i = 0; i < attrs.getLength(); i++) { - auto name = attrs.getQName(i); - auto value = attrs.getValue(name); - //LOG_DEBUG(" %s = %s", (char*)XS::ToString(name), (char*)XS::ToString(value)); - m_CurrentAttributes[XS::ToString(name).operator std::string()] = XS::ToString(value).operator std::string(); - } - - if (m_Handler->m_OnStartFieldCallback) { - m_Handler->m_OnStartFieldCallback(m_EntityStack.top(), m_CurrentComponent, field, m_CurrentAttributes); - } -} - -void EntityFileSAXHandler::onEndComponent(const std::string& name) { } - -void EntityFileSAXHandler::onStartComponent(const std::string& name) -{ - //LOG_DEBUG(" Component: %s", name.c_str()); - m_CurrentComponent = name; - if (m_Handler->m_OnStartComponentCallback) { - m_Handler->m_OnStartComponentCallback(m_EntityStack.top(), name); - } -} - -void EntityFileSAXHandler::onEndComponentField(const std::string& field) { } - -void EntityFileSAXHandler::onFieldData(char* data) -{ - //LOG_DEBUG(" Data: %s", data); - if (m_Handler->m_OnStartFieldDataCallback) { - m_Handler->m_OnStartFieldDataCallback(m_EntityStack.top(), m_CurrentComponent, m_CurrentField, data); - } - - xercesc::XMLString::release(&data); -} + auto mapping = other->Merge(this); + return EntityWrapper(other, mapping.at(m_RootEntity)); +} \ No newline at end of file diff --git a/src/Engine/Core/EntityFileParser.cpp b/src/Engine/Core/EntityFileParser.cpp deleted file mode 100644 index 23c0c4c4..00000000 --- a/src/Engine/Core/EntityFileParser.cpp +++ /dev/null @@ -1,74 +0,0 @@ -#include "Core/EntityFileParser.h" - -EntityFileParser::EntityFileParser(const EntityFile* entityFile) - : m_EntityFile(entityFile) -{ - m_Handler.SetStartEntityCallback(std::bind(&EntityFileParser::onStartEntity, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3)); - m_Handler.SetStartComponentCallback(std::bind(&EntityFileParser::onStartComponent, this, std::placeholders::_1, std::placeholders::_2)); - m_Handler.SetStartFieldCallback(std::bind(&EntityFileParser::onStartComponentField, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4)); - m_Handler.SetStartFieldDataCallback(std::bind(&EntityFileParser::onFieldData, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4)); -} - -EntityID EntityFileParser::MergeEntities(World* world, EntityID baseParent /*= EntityID_Invalid */) -{ - m_World = world; - m_EntityIDMapper[0] = baseParent; - m_EntityFile->Parse(&m_Handler); - return m_FirstEntity; -} - -void EntityFileParser::onStartEntity(EntityID entity, EntityID parent, const std::string& name) -{ - EntityID realParent = m_EntityIDMapper.at(parent); - EntityID realEntity = m_World->CreateEntity(realParent); - if (m_FirstEntity == EntityID_Invalid) { - m_FirstEntity = realEntity; - } - if (!name.empty()) { - m_World->SetName(realEntity, name); - } - m_EntityIDMapper[entity] = realEntity; - //LOG_DEBUG("Created entity #%i (%i) with parent %i (%i)", entity, realEntity, parent, realParent); -} - -void EntityFileParser::onStartComponent(EntityID entity, const std::string& component) -{ - EntityID realEntity = m_EntityIDMapper.at(entity); - m_World->AttachComponent(realEntity, component); - //LOG_DEBUG("Attached component of type \"%s\" to entity #%i (%i)", component.c_str(), entity, realEntity); -} - -void EntityFileParser::onStartComponentField(EntityID entity, const std::string& componentType, const std::string& fieldName, const std::map& attributes) -{ - EntityID realEntity = m_EntityIDMapper.at(entity); - ComponentWrapper component = m_World->GetComponent(realEntity, componentType); - auto fieldIt = component.Info.Fields.find(fieldName); - if (fieldIt == component.Info.Fields.end()) { - LOG_ERROR("Tried to set unknown field \"%s\" of component type \"%s\"! Ignoring.", fieldName.c_str(), componentType.c_str()); - return; - } - auto& field = fieldIt->second; - - //LOG_DEBUG("Field \"%s\" type \"%s\"", fieldName.c_str(), field.Type.c_str()); - //LOG_DEBUG("Attributes:"); - //for (auto& kv : attributes) { - // LOG_DEBUG("\t%s = %s", kv.first.c_str(), kv.second.c_str()); - //} - - char* data = component.Data + field.Offset; - EntityFile::WriteAttributeData(data, field, attributes); -} - -void EntityFileParser::onFieldData(EntityID entity, const std::string& componentType, const std::string& fieldName, const char* fieldData) -{ - EntityID realEntity = m_EntityIDMapper.at(entity); - ComponentWrapper component = m_World->GetComponent(realEntity, componentType); - auto fieldIt = component.Info.Fields.find(fieldName); - if (fieldIt == component.Info.Fields.end()) { - return; - } - auto& field = fieldIt->second; - - char* data = component.Data + field.Offset; - EntityFile::WriteValueData(data, field, fieldData); -} diff --git a/src/Engine/Core/EntityXMLFile.cpp b/src/Engine/Core/EntityXMLFile.cpp new file mode 100644 index 00000000..b32d952d --- /dev/null +++ b/src/Engine/Core/EntityXMLFile.cpp @@ -0,0 +1,291 @@ +#include "Core/EntityXMLFile.h" + +EntityXMLFile::EntityXMLFile(boost::filesystem::path path) + : m_FilePath(path) +{ + using namespace xercesc; + XMLPlatformUtils::Initialize(); + m_GrammarPool = new XMLGrammarPoolImpl(); + m_SAX2XMLReader = XMLReaderFactory::createXMLReader(XMLPlatformUtils::fgMemoryManager, m_GrammarPool); +} + +EntityXMLFile::~EntityXMLFile() +{ + delete m_SAX2XMLReader; + delete m_GrammarPool; + xercesc::XMLPlatformUtils::Terminate(); +} + +void EntityXMLFile::Parse(const EntityFileHandler* handler) const +{ + using namespace xercesc; + + EntityFileSAXHandler saxHandler(handler, m_SAX2XMLReader); + setReaderFeatures(m_SAX2XMLReader); + m_SAX2XMLReader->setContentHandler(&saxHandler); + m_SAX2XMLReader->setErrorHandler(&saxHandler); + m_SAX2XMLReader->setDeclarationHandler(&saxHandler); + m_SAX2XMLReader->parse(m_FilePath.string().c_str()); +} + +void EntityXMLFile::setReaderFeatures(xercesc::SAX2XMLReader* reader) +{ + using namespace xercesc; + reader->setFeature(XMLUni::fgXercesCacheGrammarFromParse, true); + reader->setFeature(XMLUni::fgXercesUseCachedGrammarInParse, true); + reader->setFeature(XMLUni::fgSAX2CoreValidation, true); + reader->setFeature(XMLUni::fgSAX2CoreNameSpaces, true); + reader->setFeature(XMLUni::fgXercesSchema, true); + reader->setFeature(XMLUni::fgXercesSchemaFullChecking, true); + reader->setFeature(XMLUni::fgXercesCalculateSrcOfs, true); + reader->setFeature(XMLUni::fgXercesIdentityConstraintChecking, true); +} + +unsigned int EntityXMLFile::GetTypeStride(std::string typeName) +{ + std::map typeStrides{ + { "bool", sizeof(bool) }, + { "int", sizeof(int) }, + { "float", sizeof(float) }, + { "double", sizeof(double) }, + { "string", sizeof(std::string) }, + { "enum", sizeof(ComponentInfo::EnumType) }, + { "Vector", sizeof(glm::vec3) }, + { "Quaternion", sizeof(glm::quat) }, + { "Color", sizeof(glm::vec4) } + }; + + auto it = typeStrides.find(typeName); + return (it != typeStrides.end()) ? it->second : 0; +} + +void EntityXMLFile::WriteAttributeData(char* outData, const ComponentInfo::Field_t& field, const std::map& attributes) +{ + if (field.Type == "Vector") { + glm::vec3 vec; + vec.x = boost::lexical_cast(attributes.at("X")); + vec.y = boost::lexical_cast(attributes.at("Y")); + vec.z = boost::lexical_cast(attributes.at("Z")); + memcpy(outData, reinterpret_cast(&vec), field.Stride); + } else if (field.Type == "Color") { + glm::vec4 vec; + vec.r = boost::lexical_cast(attributes.at("R")); + vec.g = boost::lexical_cast(attributes.at("G")); + vec.b = boost::lexical_cast(attributes.at("B")); + vec.a = boost::lexical_cast(attributes.at("A")); + memcpy(outData, reinterpret_cast(&vec), field.Stride); + } else if (field.Type == "Quaternion") { + glm::quat q; + q.x = boost::lexical_cast(attributes.at("X")); + q.y = boost::lexical_cast(attributes.at("Y")); + q.z = boost::lexical_cast(attributes.at("Z")); + q.w = boost::lexical_cast(attributes.at("W")); + memcpy(outData, reinterpret_cast(&q), field.Stride); + } else if (!attributes.empty()) { + LOG_WARNING("%i attributes not handled by any type conversion!", attributes.size()); + } +} + +void EntityXMLFile::WriteValueData(char* outData, const ComponentInfo::Field_t& field, const char* valueData) +{ + // Catch and ignore casting errors so whitespace around string enums won't mess anything up + try { + if (field.Type == "int") { + int value = boost::lexical_cast(valueData); + memcpy(outData, reinterpret_cast(&value), field.Stride); + } else if (field.Type == "enum") { + ComponentInfo::EnumType value = boost::lexical_cast(valueData); + memcpy(outData, reinterpret_cast(&value), field.Stride); + } else if (field.Type == "float") { + float value = boost::lexical_cast(valueData); + memcpy(outData, reinterpret_cast(&value), field.Stride); + } else if (field.Type == "double") { + double value = boost::lexical_cast(valueData); + memcpy(outData, reinterpret_cast(&value), field.Stride); + } else if (field.Type == "bool") { + bool value = (valueData[0] == 't'); // Lazy bool evaluation + memcpy(outData, reinterpret_cast(&value), field.Stride); + } else if (field.Type == "string") { + new (outData) std::string(valueData); + } else { + LOG_WARNING("Unknown value data type: %s", field.Type.c_str()); + } + } catch (const boost::bad_lexical_cast&) { } +} + +EntityFileSAXHandler::EntityFileSAXHandler(const EntityFileHandler* handler, xercesc::SAX2XMLReader* reader) + : m_Handler(handler) + , m_Reader(reader) +{ + // 0 is imaginary base parent + m_EntityStack.push(0); + m_StateStack.push(State::Unknown); +} + +void EntityFileSAXHandler::startElement(const XMLCh* const _uri, const XMLCh* const _localName, const XMLCh* const _qname, const xercesc::Attributes& attrs) +{ + std::string name = XS::ToString(_localName); + + if (m_StateStack.top() == State::Unknown || m_StateStack.top() == State::Entity) { + if (name == "Entity") { + m_StateStack.push(State::Entity); + onStartEntity(attrs); + return; + } + if (name == "EntityRef") { + onStartEntityRef(attrs); + return; + } + } + + std::string uri = XS::ToString(_uri); + if (m_StateStack.top() == State::Entity) { + if (uri == "components") { + m_StateStack.push(State::Component); + onStartComponent(name); + return; + } + } + + if (m_StateStack.top() == State::Component) { + m_StateStack.push(State::ComponentField); + onStartComponentField(name, attrs); + return; + } +} + +void EntityFileSAXHandler::endElement(const XMLCh* const _uri, const XMLCh* const _localName, const XMLCh* const _qname) +{ + std::string name = XS::ToString(_localName); + if (m_StateStack.top() == State::Entity) { + if (name == "Entity") { + m_StateStack.pop(); + onEndEntity(); + return; + } + } + + std::string uri = XS::ToString(_uri); + if (m_StateStack.top() == State::Component) { + //if (uri == "components") { + m_StateStack.pop(); + onEndComponent(name); + return; + //} + } + + if (m_StateStack.top() == State::ComponentField && name == m_CurrentField) { + m_StateStack.pop(); + onEndComponentField(name); + return; + } +} + +void EntityFileSAXHandler::characters(const XMLCh* const chars, const XMLSize_t length) +{ + if (m_StateStack.top() == State::ComponentField) { + char* transcoded = xercesc::XMLString::transcode(chars); + onFieldData(transcoded); + } +} + +void EntityFileSAXHandler::fatalError(const xercesc::SAXParseException& e) +{ + std::string message = XS::ToString(e.getMessage()); + std::string systemId = XS::ToString(e.getSystemId()); + XMLFileLoc line = e.getLineNumber(); + XMLFileLoc column = e.getColumnNumber(); + LOG_ERROR("SAXParseException\n\tLocation: %s:%i:%i\n\tFatal Error: %s", systemId.c_str(), line, column, message.c_str()); +} + +void EntityFileSAXHandler::error(const xercesc::SAXParseException& e) +{ + std::string message = XS::ToString(e.getMessage()); + std::string systemId = XS::ToString(e.getSystemId()); + XMLFileLoc line = e.getLineNumber(); + XMLFileLoc column = e.getColumnNumber(); + LOG_ERROR("SAXParseException\n\tLocation: %s:%i:%i\n\tError: %s", systemId.c_str(), line, column, message.c_str()); +} + +void EntityFileSAXHandler::warning(const xercesc::SAXParseException& e) +{ + std::string message = XS::ToString(e.getMessage()); + std::string systemId = XS::ToString(e.getSystemId()); + XMLFileLoc line = e.getLineNumber(); + XMLFileLoc column = e.getColumnNumber(); + LOG_ERROR("SAXParseException\n\tLocation: %s:%i:%i\n\tWarning: %s", systemId.c_str(), line, column, message.c_str()); +} + +void EntityFileSAXHandler::onStartEntity(const xercesc::Attributes& attrs) +{ + EntityID parent = m_EntityStack.top(); + + if (m_Handler->m_OnStartEntityCallback) { + std::string name; + auto xName = attrs.getValue(XS::ToXMLCh("name")); + if (xName != nullptr) { + name = XS::ToString(xName); + } + m_Handler->m_OnStartEntityCallback(m_NextEntityID, parent, name); + } + + m_EntityStack.push(m_NextEntityID); + m_NextEntityID++; +} + +void EntityFileSAXHandler::onEndEntity() +{ + m_EntityStack.pop(); +} + +void EntityFileSAXHandler::onStartEntityRef(const xercesc::Attributes& attrs) +{ + std::string path = XS::ToString(attrs.getValue(XS::ToXMLCh("file"))); + + xercesc::SAX2XMLReader* reader = xercesc::XMLReaderFactory::createXMLReader(); + EntityXMLFile::setReaderFeatures(reader); + reader->setContentHandler(this); + reader->setErrorHandler(this); + reader->parse(path.c_str()); + delete reader; +} + +void EntityFileSAXHandler::onStartComponentField(const std::string& field, const xercesc::Attributes& attrs) +{ + //LOG_DEBUG(" Field: %s", field.c_str()); + m_CurrentField = field; + m_CurrentAttributes.clear(); + for (int i = 0; i < attrs.getLength(); i++) { + auto name = attrs.getQName(i); + auto value = attrs.getValue(name); + //LOG_DEBUG(" %s = %s", (char*)XS::ToString(name), (char*)XS::ToString(value)); + m_CurrentAttributes[XS::ToString(name).operator std::string()] = XS::ToString(value).operator std::string(); + } + + if (m_Handler->m_OnStartFieldCallback) { + m_Handler->m_OnStartFieldCallback(m_EntityStack.top(), m_CurrentComponent, field, m_CurrentAttributes); + } +} + +void EntityFileSAXHandler::onEndComponent(const std::string& name) { } + +void EntityFileSAXHandler::onStartComponent(const std::string& name) +{ + //LOG_DEBUG(" Component: %s", name.c_str()); + m_CurrentComponent = name; + if (m_Handler->m_OnStartComponentCallback) { + m_Handler->m_OnStartComponentCallback(m_EntityStack.top(), name); + } +} + +void EntityFileSAXHandler::onEndComponentField(const std::string& field) { } + +void EntityFileSAXHandler::onFieldData(char* data) +{ + //LOG_DEBUG(" Data: %s", data); + if (m_Handler->m_OnStartFieldDataCallback) { + m_Handler->m_OnStartFieldDataCallback(m_EntityStack.top(), m_CurrentComponent, m_CurrentField, data); + } + + xercesc::XMLString::release(&data); +} diff --git a/src/Engine/Core/EntityXMLFileParser.cpp b/src/Engine/Core/EntityXMLFileParser.cpp new file mode 100644 index 00000000..9c79775c --- /dev/null +++ b/src/Engine/Core/EntityXMLFileParser.cpp @@ -0,0 +1,84 @@ +#include "Core/EntityXMLFileParser.h" + +EntityXMLFileParser::EntityXMLFileParser(const EntityXMLFile* entityFile) + : m_EntityFile(entityFile) +{ + m_Handler.SetStartEntityCallback(std::bind(&EntityXMLFileParser::onStartEntity, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3)); + m_Handler.SetStartComponentCallback(std::bind(&EntityXMLFileParser::onStartComponent, this, std::placeholders::_1, std::placeholders::_2)); + m_Handler.SetStartFieldCallback(std::bind(&EntityXMLFileParser::onStartComponentField, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4)); + m_Handler.SetStartFieldDataCallback(std::bind(&EntityXMLFileParser::onFieldData, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4)); +} + +EntityID EntityXMLFileParser::MergeEntities(World* world, EntityID baseParent /*= EntityID_Invalid */) +{ + m_World = world; + m_EntityIDMapper[0] = baseParent; + m_EntityFile->Parse(&m_Handler); + return m_FirstEntity; +} + +void EntityXMLFileParser::onStartEntity(EntityID entity, EntityID parent, const std::string& name) +{ + EntityID realParent = m_EntityIDMapper.at(parent); + EntityID realEntity = m_World->CreateEntity(realParent); + if (m_FirstEntity == EntityID_Invalid) { + m_FirstEntity = realEntity; + } + if (!name.empty()) { + m_World->SetName(realEntity, name); + } + m_EntityIDMapper[entity] = realEntity; + //LOG_DEBUG("Created entity #%i (%i) with parent %i (%i)", entity, realEntity, parent, realParent); +} + +void EntityXMLFileParser::onStartComponent(EntityID entity, const std::string& component) +{ + if (m_World->GetComponentPools().count(component) != 0) { + EntityID realEntity = m_EntityIDMapper.at(entity); + m_World->AttachComponent(realEntity, component); + } else { + LOG_ERROR("Tried to attach unregistered component \"%s\"! to entity #%i. Ignoring.", component.c_str(), entity); + } + //LOG_DEBUG("Attached component of type \"%s\" to entity #%i (%i)", component.c_str(), entity, realEntity); +} + +void EntityXMLFileParser::onStartComponentField(EntityID entity, const std::string& componentType, const std::string& fieldName, const std::map& attributes) +{ + if (m_World->GetComponentPools().count(componentType) == 0) { + return; + } + EntityID realEntity = m_EntityIDMapper.at(entity); + ComponentWrapper component = m_World->GetComponent(realEntity, componentType); + auto fieldIt = component.Info.Fields.find(fieldName); + if (fieldIt == component.Info.Fields.end()) { + LOG_ERROR("Tried to set unknown field \"%s\" of component type \"%s\"! Ignoring.", fieldName.c_str(), componentType.c_str()); + return; + } + auto& field = fieldIt->second; + + //LOG_DEBUG("Field \"%s\" type \"%s\"", fieldName.c_str(), field.Type.c_str()); + //LOG_DEBUG("Attributes:"); + //for (auto& kv : attributes) { + // LOG_DEBUG("\t%s = %s", kv.first.c_str(), kv.second.c_str()); + //} + + char* data = component.Data + field.Offset; + EntityXMLFile::WriteAttributeData(data, field, attributes); +} + +void EntityXMLFileParser::onFieldData(EntityID entity, const std::string& componentType, const std::string& fieldName, const char* fieldData) +{ + if (m_World->GetComponentPools().count(componentType) == 0) { + return; + } + EntityID realEntity = m_EntityIDMapper.at(entity); + ComponentWrapper component = m_World->GetComponent(realEntity, componentType); + auto fieldIt = component.Info.Fields.find(fieldName); + if (fieldIt == component.Info.Fields.end()) { + return; + } + auto& field = fieldIt->second; + + char* data = component.Data + field.Offset; + EntityXMLFile::WriteValueData(data, field, fieldData); +} diff --git a/src/Engine/Core/EntityFilePreprocessor.cpp b/src/Engine/Core/EntityXMLFilePreprocessor.cpp similarity index 93% rename from src/Engine/Core/EntityFilePreprocessor.cpp rename to src/Engine/Core/EntityXMLFilePreprocessor.cpp index 592daedb..9695509d 100644 --- a/src/Engine/Core/EntityFilePreprocessor.cpp +++ b/src/Engine/Core/EntityXMLFilePreprocessor.cpp @@ -1,10 +1,10 @@ -#include "Core/EntityFilePreprocessor.h" +#include "Core/EntityXMLFilePreprocessor.h" -EntityFilePreprocessor::EntityFilePreprocessor(const EntityFile* entityFile) +EntityXMLFilePreprocessor::EntityXMLFilePreprocessor(const EntityXMLFile* entityFile) : m_EntityFile(entityFile) { EntityFileHandler handler; - handler.SetStartComponentCallback(std::bind(&EntityFilePreprocessor::onStartComponent, this, std::placeholders::_1, std::placeholders::_2)); + handler.SetStartComponentCallback(std::bind(&EntityXMLFilePreprocessor::onStartComponent, this, std::placeholders::_1, std::placeholders::_2)); m_EntityFile->Parse(&handler); //LOG_DEBUG("___ COMPONENT DEFINITIONS ___"); @@ -28,20 +28,20 @@ EntityFilePreprocessor::EntityFilePreprocessor(const EntityFile* entityFile) parseDefaults(); } -void EntityFilePreprocessor::RegisterComponents(World* world) +void EntityXMLFilePreprocessor::RegisterComponents(World* world) { for (auto& kv : m_ComponentInfo) { world->RegisterComponent(kv.second); } } -void EntityFilePreprocessor::onStartComponent(EntityID entity, std::string type) +void EntityXMLFilePreprocessor::onStartComponent(EntityID entity, std::string type) { //LOG_DEBUG("Component: %s", type.c_str()); m_ComponentCounts[type]++; } -void EntityFilePreprocessor::parseComponentInfo() +void EntityXMLFilePreprocessor::parseComponentInfo() { using namespace xercesc; EntityFileXMLErrorHandler errorHandler; @@ -141,9 +141,9 @@ void EntityFilePreprocessor::parseComponentInfo() std::string baseType = XS::ToString(elementDeclaration->getTypeDefinition()->getBaseType()->getName()); std::string effectiveType = type; - unsigned int stride = EntityFile::GetTypeStride(type); + unsigned int stride = EntityXMLFile::GetTypeStride(type); if (stride == 0) { - stride = EntityFile::GetTypeStride(baseType); + stride = EntityXMLFile::GetTypeStride(baseType); if (stride == 0) { LOG_WARNING("Field \"%s\" in component \"%s\" uses unexpected field type \"%s\" with base type \"%s\". Skipping.", name.c_str(), compInfo.Name.c_str(), type.c_str(), baseType.c_str()); continue; @@ -196,7 +196,7 @@ void EntityFilePreprocessor::parseComponentInfo() } } -void EntityFilePreprocessor::parseDefaults() +void EntityXMLFilePreprocessor::parseDefaults() { using namespace xercesc; @@ -261,7 +261,7 @@ void EntityFilePreprocessor::parseDefaults() auto attribItem = attributeMap->item(i); attributes[XS::ToString(attribItem->getNodeName())] = XS::ToString(attribItem->getNodeValue()); } - EntityFile::WriteAttributeData(data, field, attributes); + EntityXMLFile::WriteAttributeData(data, field, attributes); } auto childNode = fieldElement->getFirstChild(); @@ -278,14 +278,14 @@ void EntityFilePreprocessor::parseDefaults() // Handle potential field values if (childNode->getNodeType() == DOMNode::TEXT_NODE) { char* cstrValue = XMLString::transcode(childNode->getNodeValue()); - EntityFile::WriteValueData(data, field, cstrValue); + EntityXMLFile::WriteValueData(data, field, cstrValue); XMLString::release(&cstrValue); } } } } -std::string EntityFilePreprocessor::parseAnnotationXML(const XMLCh* xml) +std::string EntityXMLFilePreprocessor::parseAnnotationXML(const XMLCh* xml) { using namespace xercesc; diff --git a/src/Engine/Core/EntityFileWriter.cpp b/src/Engine/Core/EntityXMLFileWriter.cpp similarity index 94% rename from src/Engine/Core/EntityFileWriter.cpp rename to src/Engine/Core/EntityXMLFileWriter.cpp index 06a3c4ca..a98d3fbd 100644 --- a/src/Engine/Core/EntityFileWriter.cpp +++ b/src/Engine/Core/EntityXMLFileWriter.cpp @@ -1,13 +1,13 @@ -#include "Core/EntityFileWriter.h" +#include "Core/EntityXMLFileWriter.h" #define X(str) XS::ToXMLCh(str) -void EntityFileWriter::WriteWorld(World* world) +void EntityXMLFileWriter::WriteWorld(World* world) { WriteEntity(world, 0); } -void EntityFileWriter::WriteEntity(World* world, EntityID entity) +void EntityXMLFileWriter::WriteEntity(World* world, EntityID entity) { using namespace xercesc; DOMDocument* doc = m_DOMImplementation->createDocument(nullptr, X("Entity"), nullptr); @@ -41,7 +41,7 @@ void EntityFileWriter::WriteEntity(World* world, EntityID entity) doc->release(); } -void EntityFileWriter::appendEntityChildren(xercesc::DOMElement* parentElement, const World* world, EntityID entity) +void EntityXMLFileWriter::appendEntityChildren(xercesc::DOMElement* parentElement, const World* world, EntityID entity) { using namespace xercesc; DOMDocument* doc = parentElement->getOwnerDocument(); @@ -67,7 +67,7 @@ void EntityFileWriter::appendEntityChildren(xercesc::DOMElement* parentElement, } } -void EntityFileWriter::appentEntityComponents(xercesc::DOMElement* parentElement, const World* world, EntityID entity) +void EntityXMLFileWriter::appentEntityComponents(xercesc::DOMElement* parentElement, const World* world, EntityID entity) { using namespace xercesc; DOMDocument* doc = parentElement->getOwnerDocument(); diff --git a/src/Engine/Core/Util/Logging.cpp b/src/Engine/Core/Util/Logging.cpp index c7612fd8..63a6f380 100644 --- a/src/Engine/Core/Util/Logging.cpp +++ b/src/Engine/Core/Util/Logging.cpp @@ -33,8 +33,8 @@ void _LOG(_LOG_LEVEL logLevel, const char* file, const char* func, unsigned int va_end(args); if (logLevel == LOG_LEVEL_ERROR) { - //std::cerr << file << ":" << line << " " << func << std::endl; - //std::cerr << _LOG_LEVEL_PREFIX[logLevel] << message << std::endl; + std::cerr << file << ":" << line << " " << func << std::endl; + std::cerr << _LOG_LEVEL_PREFIX[logLevel] << message << std::endl; } else { std::cout << _LOG_LEVEL_PREFIX[logLevel] << message << std::endl; } diff --git a/src/Engine/Core/World.cpp b/src/Engine/Core/World.cpp index 9b323ff4..0952a53b 100644 --- a/src/Engine/Core/World.cpp +++ b/src/Engine/Core/World.cpp @@ -1,6 +1,7 @@ #include "Core/World.h" #include "Core/EEntityDeleted.h" #include "Core/EComponentDeleted.h" +#include "Core/EntityWrapper.h" World::~World() { @@ -44,7 +45,7 @@ bool World::ValidEntity(EntityID entity) const return m_EntityParents.find(entity) != m_EntityParents.end(); } -void World::RegisterComponent(ComponentInfo& ci) +void World::RegisterComponent(const ComponentInfo& ci) { if (m_ComponentPools.find(ci.Name) == m_ComponentPools.end()) { m_ComponentPools[ci.Name] = new ComponentPool(ci); @@ -151,6 +152,62 @@ std::string World::GetName(EntityID entity) const } } +EntityWrapper World::GetFirstEntityByName(const std::string& name) +{ + auto itPair = GetDirectChildren(EntityID_Invalid); + for (auto it = itPair.first; it != itPair.second; it++) { + EntityID childEntityID = it->second; + EntityWrapper childEntity(this, childEntityID); + if (!childEntity.Valid()) { + continue; + } + EntityWrapper entityWithName = childEntity.Name() == name ? childEntity : childEntity.FirstChildByName(name); + if (entityWithName.Valid()) { + return entityWithName; + } + } + return EntityWrapper::Invalid; +} + +std::unordered_map World::Merge(const World* other) +{ + std::unordered_map oldToNew; + + // Create new entities + for (auto& kv : other->m_EntityParents) { + EntityID entity = kv.first; + + EntityID newEntity = CreateEntity(); + SetName(newEntity, other->GetName(entity)); + oldToNew[entity] = newEntity; + } + // Fix relationships + for (auto& kv : other->m_EntityParents) { + EntityID entity = kv.first; + EntityID parent = kv.second; + if (parent != EntityID_Invalid) { + SetParent(oldToNew.at(entity), oldToNew.at(parent)); + } + } + + // Transfer components + for (auto& kv : other->m_ComponentPools) { + auto& componentType = kv.first; + ComponentPool* pool = kv.second; + // Register pool if it's not present in world + if (m_ComponentPools.count(componentType) == 0) { + RegisterComponent(pool->ComponentInfo()); + } + // Copy components + for (auto component : *pool) { + ComponentWrapper newComponent = AttachComponent(oldToNew.at(component.EntityID), componentType); + component.Copy(newComponent); + } + } + + return oldToNew; +} + EntityID World::generateEntityID() { // TODO: Make EntityID generation smarter diff --git a/src/Engine/Editor/EditorSystem.cpp b/src/Engine/Editor/EditorSystem.cpp index 4bee1427..62ddba88 100644 --- a/src/Engine/Editor/EditorSystem.cpp +++ b/src/Engine/Editor/EditorSystem.cpp @@ -2,6 +2,7 @@ #include "Core/UniformScaleSystem.h" #include "Editor/EditorRenderSystem.h" #include "Editor/EditorWidgetSystem.h" +#include "Core/EntityFile.h" EditorSystem::EditorSystem(SystemParams params, IRenderer* renderer, RenderFrame* renderFrame) : System(params) @@ -129,7 +130,7 @@ void EditorSystem::OnEntitySelected(EntityWrapper entity) void EditorSystem::OnEntitySave(EntityWrapper entity, boost::filesystem::path filePath) { - EntityFileWriter writer(filePath); + EntityXMLFileWriter writer(filePath); writer.WriteEntity(entity.World, entity.ID); } @@ -260,12 +261,11 @@ EntityWrapper EditorSystem::importEntity(EntityWrapper parent, boost::filesystem try { auto entityFile = ResourceManager::Load(filePath.string()); - EntityFilePreprocessor fpp(entityFile); - fpp.RegisterComponents(parent.World); - EntityFileParser fp(entityFile); - EntityID newEntity = fp.MergeEntities(parent.World, parent.ID); - return EntityWrapper(parent.World, newEntity); - } catch (const std::exception&) { + EntityWrapper newEntity = entityFile->MergeInto(parent.World); + parent.World->SetParent(newEntity.ID, parent.ID); + return newEntity; + } catch (const std::exception& e) { + LOG_ERROR("Failed to import entity \"%s\": \"%s\"", filePath.string().c_str(), e.what()); return EntityWrapper::Invalid; } } diff --git a/src/Engine/Network/Client.cpp b/src/Engine/Network/Client.cpp index aa87f6ff..d666e550 100644 --- a/src/Engine/Network/Client.cpp +++ b/src/Engine/Network/Client.cpp @@ -33,6 +33,7 @@ void Client::Connect(std::string address, int port) EVENT_SUBSCRIBE_MEMBER(m_EPlayerDamage, &Client::OnPlayerDamage); EVENT_SUBSCRIBE_MEMBER(m_EPlayerSpawned, &Client::OnPlayerSpawned); EVENT_SUBSCRIBE_MEMBER(m_EDoubleJump, &Client::OnDoubleJump); + EVENT_SUBSCRIBE_MEMBER(m_EDashAbility, &Client::OnDashAbility); EVENT_SUBSCRIBE_MEMBER(m_ESearchForServers, &Client::OnSearchForServers); auto config = ResourceManager::Load("Config.ini"); m_Address = address; @@ -143,6 +144,9 @@ void Client::parseMessageType(Packet& packet) case MessageType::OnDoubleJump: parseDoubleJump(packet); break; + case MessageType::OnDashEffect: + parseDashEffect(packet); + break; case MessageType::AmmoPickup: parseAmmoPickup(packet); break; @@ -262,7 +266,7 @@ void Client::parseEntityDeletion(Packet & packet) if (m_ServerIDToClientID.find(entityToDelete) != m_ServerIDToClientID.end()) { EntityID localEntity = m_ServerIDToClientID.at(entityToDelete); if (m_World->ValidEntity(localEntity)) { - if (m_World->HasComponent(localEntity,"Player")) { + if (m_World->HasComponent(localEntity, "Player")) { Events::PlayerDeath e; e.Player = EntityWrapper(m_World, localEntity); m_EventBroker->Publish(e); @@ -297,8 +301,22 @@ void Client::parseDoubleJump(Packet & packet) } } + +void Client::parseDashEffect(Packet& packet) +{ + EntityID serverID = packet.ReadPrimitive(); + if (!serverClientMapsHasEntity(serverID)) { + return; + } + Events::DashAbility e; + e.Player = m_ServerIDToClientID.at(serverID); + if (e.Player != m_LocalPlayer.ID) { + m_EventBroker->Publish(e); + } +} + void Client::parseAmmoPickup(Packet & packet) -{ +{ Events::AmmoPickup e; e.AmmoGain = packet.ReadPrimitive(); e.Player = m_LocalPlayer; @@ -388,7 +406,7 @@ void Client::parseSnapshot(Packet& packet) if (m_SnapshotFilter != nullptr) { shouldApply = m_SnapshotFilter->FilterComponent(localEntity, newComponent); } - if (shouldApply) { + if (shouldApply) { ComponentWrapper currentComponent = m_World->GetComponent(localEntityID, componentType); memcpy(currentComponent.Data, newComponent.Data, componentInfo.Stride); } @@ -518,6 +536,18 @@ bool Client::OnPlayerSpawned(const Events::PlayerSpawned& e) return true; } + +bool Client::OnDashAbility(const Events::DashAbility& e) +{ + if (!clientServerMapsHasEntity(e.Player) || e.Player != m_LocalPlayer.ID) { + return false; + } + Packet packet(MessageType::OnDashEffect); + packet.WritePrimitive(m_ClientIDToServerID.at(e.Player)); + m_Reliable.Send(packet); + return true; +} + bool Client::OnSearchForServers(const Events::SearchForServers& e) { m_SearchingForServers = true; diff --git a/src/Engine/Network/Server.cpp b/src/Engine/Network/Server.cpp index 08b72304..68c00fbe 100644 --- a/src/Engine/Network/Server.cpp +++ b/src/Engine/Network/Server.cpp @@ -141,6 +141,9 @@ void Server::parseMessageType(Packet& packet) case MessageType::OnDoubleJump: parseDoubleJump(packet); break; + case MessageType::OnDashEffect: + parseDashEffect(packet); + break; default: break; } @@ -555,6 +558,11 @@ bool Server::parseDoubleJump(Packet & packet) return true; } +void Server::parseDashEffect(Packet& packet) +{ + reliableBroadcast(packet); +} + void Server::parseOnInputCommand(Packet& packet) { PlayerID player = -1; diff --git a/src/Engine/Rendering/FrameBuffer.cpp b/src/Engine/Rendering/FrameBuffer.cpp index 9ba0d2d8..da438e7a 100644 --- a/src/Engine/Rendering/FrameBuffer.cpp +++ b/src/Engine/Rendering/FrameBuffer.cpp @@ -70,7 +70,7 @@ void FrameBuffer::Generate() } GLERROR("3"); - GLenum* bufferTextures = &attachments[0]; + GLenum* bufferTextures = attachments.data(); glDrawBuffers(attachments.size(), bufferTextures); if (GLERROR("GLBufferAttachement error")) { printf(": AttachmentSize %i", attachments.size()); diff --git a/src/Game/Game.cpp b/src/Game/Game.cpp index 8c6e653e..ab4b9652 100644 --- a/src/Game/Game.cpp +++ b/src/Game/Game.cpp @@ -10,7 +10,9 @@ #include "Systems/SpawnerSystem.h" #include "Systems/PlayerSpawnSystem.h" #include "Systems/PlayerDeathSystem.h" -#include "Core/EntityFileWriter.h" +#include "Systems/FloatingEffectSystem.h" +#include "Core/EntityFile.h" +#include "Core/EntityXMLFileWriter.h" #include "Game/Systems/CapturePointSystem.h" #include "Game/Systems/CapturePointHUDSystem.h" #include "Game/Systems/PickupSpawnSystem.h" @@ -25,9 +27,11 @@ #include "Rendering/AnimationSystem.h" #include "Network/MultiplayerSnapshotFilter.h" #include "Game/Systems/AmmunitionHUDSystem.h" +#include "Game/Systems/AbilityCooldownHUDSystem.h" #include "Game/Systems/CapturePointArrowHUDSystem.h" #include "Game/Systems/KillFeedSystem.h" #include "Game/Systems/BoostSystem.h" +#include "Game/Systems/BoostIconsHUDSystem.h" #include "GUI/ButtonSystem.h" #include "GUI/MainMenuSystem.h" @@ -44,6 +48,7 @@ Game::Game(int argc, char* argv[]) ResourceManager::RegisterType("Png"); ResourceManager::RegisterType("ShaderProgram"); ResourceManager::RegisterType("EntityFile"); + ResourceManager::RegisterType("EntityXMLFile"); ResourceManager::RegisterType("FontFile"); m_Config = ResourceManager::Load("Config.ini"); @@ -80,10 +85,7 @@ Game::Game(int argc, char* argv[]) std::string mapToLoad = m_Config->Get("Debug.LoadMap", ""); if (!mapToLoad.empty()) { auto file = ResourceManager::Load(mapToLoad); - EntityFilePreprocessor fpp(file); - fpp.RegisterComponents(m_World); - EntityFileParser fp(file); - fp.MergeEntities(m_World); + file->MergeInto(m_World); } // Create the sound manager @@ -120,6 +122,7 @@ Game::Game(int argc, char* argv[]) ++updateOrderLevel; m_SystemPipeline->AddSystem(updateOrderLevel); m_SystemPipeline->AddSystem(updateOrderLevel); + m_SystemPipeline->AddSystem(updateOrderLevel); m_SystemPipeline->AddSystem(updateOrderLevel); m_SystemPipeline->AddSystem(updateOrderLevel); m_SystemPipeline->AddSystem(updateOrderLevel); @@ -133,6 +136,7 @@ Game::Game(int argc, char* argv[]) m_SystemPipeline->AddSystem(updateOrderLevel); m_SystemPipeline->AddSystem(updateOrderLevel); m_SystemPipeline->AddSystem(updateOrderLevel); + m_SystemPipeline->AddSystem(updateOrderLevel); m_SystemPipeline->AddSystem(updateOrderLevel); m_SystemPipeline->AddSystem(updateOrderLevel); m_SystemPipeline->AddSystem(updateOrderLevel); @@ -146,6 +150,7 @@ Game::Game(int argc, char* argv[]) m_SystemPipeline->AddSystem(updateOrderLevel); m_SystemPipeline->AddSystem(updateOrderLevel, m_Renderer); m_SystemPipeline->AddSystem(updateOrderLevel, m_Renderer); + m_SystemPipeline->AddSystem(updateOrderLevel); // Populate Octree with collidables ++updateOrderLevel; m_SystemPipeline->AddSystem(updateOrderLevel, m_OctreeCollision, "Collidable"); diff --git a/src/Game/Systems/AbilityCooldownHUDSystem.cpp b/src/Game/Systems/AbilityCooldownHUDSystem.cpp new file mode 100644 index 00000000..44180a62 --- /dev/null +++ b/src/Game/Systems/AbilityCooldownHUDSystem.cpp @@ -0,0 +1,30 @@ +#include "Game/Systems/AbilityCooldownHUDSystem.h" + +void AbilityCooldownHUDSystem::Update(double dt) +{ + //HUD element for tracking cooldown on the parent entity with Dashability TODO: Make sure it support other abilities when they are made. + + auto abilityHUDs = m_World->GetComponents("AbilityCooldownHUD"); + if (abilityHUDs == nullptr) + return; + + for (auto& abilityHUDC : *abilityHUDs) { + EntityWrapper entity = EntityWrapper(m_World, abilityHUDC.EntityID); + EntityWrapper abilityEntity = entity.FirstParentWithComponent("DashAbility"); + if (!abilityEntity.Valid()) + return; + EntityWrapper cooldownTextEntity = entity.FirstChildByName("Cooldown"); + if(cooldownTextEntity.Valid()) { + if(cooldownTextEntity.HasComponent("Text")) + { + double maxAbilityCD = (double)abilityEntity["DashAbility"]["CoolDownMaxTimer"]; + double currentAbilityCD = (double)abilityEntity["DashAbility"]["CoolDownTimer"]; + currentAbilityCD = currentAbilityCD >= 0.0 ? currentAbilityCD : 0.0; + std::string t = (std::string&)cooldownTextEntity["Text"]["Content"] = std::to_string(currentAbilityCD).substr(0, 3); + if(entity.HasComponent("Fill")) { + entity["Fill"]["Percentage"] = currentAbilityCD/maxAbilityCD; //TODO: current time needs to be in the component. + } + } + } + } +} diff --git a/src/Game/Systems/AmmoPickupSystem.cpp b/src/Game/Systems/AmmoPickupSystem.cpp index 74d86f70..062efe94 100644 --- a/src/Game/Systems/AmmoPickupSystem.cpp +++ b/src/Game/Systems/AmmoPickupSystem.cpp @@ -21,16 +21,15 @@ void AmmoPickupSystem::Update(double dt) somePickup.DecreaseThisRespawnTimer -= dt; if (somePickup.DecreaseThisRespawnTimer < 0.0) { auto entityFile = ResourceManager::Load("Schema/Entities/AmmoPickup.xml"); - EntityFileParser parser(entityFile); - EntityID ammoPickupID = parser.MergeEntities(m_World); + EntityWrapper ammoPickup = entityFile->MergeInto(m_World); //let the world know a pickup has spawned Events::PickupSpawned ePickupSpawned; - ePickupSpawned.Pickup = EntityWrapper(m_World, ammoPickupID); + ePickupSpawned.Pickup = ammoPickup; m_EventBroker->Publish(ePickupSpawned); //copy values from the old entity to the new entity - auto& newAmmoPickupEntity = EntityWrapper(m_World, ammoPickupID); + auto& newAmmoPickupEntity = ammoPickup; newAmmoPickupEntity["Transform"]["Position"] = somePickup.Pos; newAmmoPickupEntity["AmmoPickup"]["AmmoGain"] = somePickup.AmmoGain; newAmmoPickupEntity["AmmoPickup"]["RespawnTimer"] = somePickup.RespawnTimer; diff --git a/src/Game/Systems/BoostIconsHUDSystem.cpp b/src/Game/Systems/BoostIconsHUDSystem.cpp new file mode 100644 index 00000000..f83278ff --- /dev/null +++ b/src/Game/Systems/BoostIconsHUDSystem.cpp @@ -0,0 +1,42 @@ +#include "Game/Systems/BoostIconsHUDSystem.h" + +void BoostIconsHUDSystem::UpdateComponent(EntityWrapper& entity, ComponentWrapper& capturePoint, double dt) +{ + EntityWrapper assaultEntity = entity.FirstChildByName("Assault"); + EntityWrapper defenderEntity = entity.FirstChildByName("Defender"); + EntityWrapper sniperEntity = entity.FirstChildByName("Sniper"); + + if(assaultEntity.Valid()) { + if (assaultEntity.HasComponent("Fill")) { + EntityWrapper parentWithAssaultBoost = assaultEntity.FirstParentWithComponent("BoostAssault"); + if (parentWithAssaultBoost.Valid()) { + (double&)assaultEntity["Fill"]["Percentage"] = 1.0; + } else { + (double&)assaultEntity["Fill"]["Percentage"] = 0.0; + } + } + } + + if (defenderEntity.Valid()) { + if (defenderEntity.HasComponent("Fill")) { + EntityWrapper parentWithAssaultBoost = defenderEntity.FirstParentWithComponent("BoostDefender"); + if (parentWithAssaultBoost.Valid()) { + (double&)defenderEntity["Fill"]["Percentage"] = 1.0; + } else { + (double&)defenderEntity["Fill"]["Percentage"] = 0.0; + } + } + } + + if (sniperEntity.Valid()) { + if (sniperEntity.HasComponent("Fill")) { + EntityWrapper parentWithAssaultBoost = sniperEntity.FirstParentWithComponent("BoostSniper"); + if (parentWithAssaultBoost.Valid()) { + (double&)sniperEntity["Fill"]["Percentage"] = 1.0; + } else { + (double&)sniperEntity["Fill"]["Percentage"] = 0.0; + } + } + } +} + diff --git a/src/Game/Systems/BoostSystem.cpp b/src/Game/Systems/BoostSystem.cpp index 9e4d6968..c79576e4 100644 --- a/src/Game/Systems/BoostSystem.cpp +++ b/src/Game/Systems/BoostSystem.cpp @@ -39,10 +39,9 @@ bool BoostSystem::OnPlayerDamage(Events::PlayerDamage& e) } //load boost XML file, set it entity parented with the victim player auto entityFile = ResourceManager::Load(classXML); - EntityFileParser parser(entityFile); - EntityID boostAssaultEntity = parser.MergeEntities(m_World); - m_World->SetName(boostAssaultEntity, className); - m_World->SetParent(boostAssaultEntity, e.Victim.ID); + EntityWrapper boostAssaultEntity = entityFile->MergeInto(m_World); + m_World->SetName(boostAssaultEntity.ID, className); + m_World->SetParent(boostAssaultEntity.ID, e.Victim.ID); return true; } diff --git a/src/Game/Systems/DamageIndicatorSystem.cpp b/src/Game/Systems/DamageIndicatorSystem.cpp index ca26052d..e68f741d 100644 --- a/src/Game/Systems/DamageIndicatorSystem.cpp +++ b/src/Game/Systems/DamageIndicatorSystem.cpp @@ -9,7 +9,7 @@ DamageIndicatorSystem::DamageIndicatorSystem(SystemParams params) //load texture to cache auto texture = CommonFunctions::LoadTexture("Textures/DamageIndicator.png", false); - auto entityFile = ResourceManager::Load("Schema/Entities/DamageIndicator.xml"); + auto entityFile = ResourceManager::Load("Schema/Entities/DamageIndicator.xml"); } void DamageIndicatorSystem::Update(double dt) { @@ -50,15 +50,13 @@ bool DamageIndicatorSystem::OnPlayerDamage(Events::PlayerDamage& e) //load & set the "2d" sprite auto entityFile = ResourceManager::Load("Schema/Entities/DamageIndicator.xml"); - EntityFileParser parser(entityFile); - EntityID spriteID = parser.MergeEntities(m_World); - m_World->SetParent(spriteID, m_CurrentCamera); - auto spriteWrapper = EntityWrapper(m_World, spriteID); + EntityWrapper sprite = entityFile->MergeInto(m_World); + m_World->SetParent(sprite.ID, m_CurrentCamera); //simply set the rotation z-wise to the angleBetweenVectors - spriteWrapper["Transform"]["Orientation"] = glm::vec3(0, 0, angleBetweenVectors); + sprite["Transform"]["Orientation"] = glm::vec3(0, 0, angleBetweenVectors); if (!IsServer) { - updateDamageIndicatorVector.emplace_back(spriteWrapper, inflictorPos); + updateDamageIndicatorVector.emplace_back(sprite, inflictorPos); } return true; @@ -127,8 +125,8 @@ glm::vec3 DamageIndicatorSystem::DamageIndicatorTest(EntityWrapper player) { auto inflictorPos = glm::vec3(currentPos.x + testVar*6.0f, currentPos.y, currentPos.z + testVar2*6.0f); //load the explosioneffect XML - auto deathEffect = ResourceManager::Load("Schema/Entities/PlayerDeathExplosionWithCamera.xml"); - EntityFileParser parser(deathEffect); + auto deathEffect = ResourceManager::Load("Schema/Entities/PlayerDeathExplosionWithCamera.xml"); + EntityXMLFileParser parser(deathEffect); EntityID deathEffectID = parser.MergeEntities(m_World); EntityWrapper deathEffectEW = EntityWrapper(m_World, deathEffectID); diff --git a/src/Game/Systems/PickupSpawnSystem.cpp b/src/Game/Systems/PickupSpawnSystem.cpp index 79e7d66b..99da931f 100644 --- a/src/Game/Systems/PickupSpawnSystem.cpp +++ b/src/Game/Systems/PickupSpawnSystem.cpp @@ -19,16 +19,15 @@ void PickupSpawnSystem::Update(double dt) if (somePickup.DecreaseThisRespawnTimer < 0.0) { //spawn the new healthPickup auto entityFile = ResourceManager::Load("Schema/Entities/HealthPickup.xml"); - EntityFileParser parser(entityFile); - EntityID healthPickupID = parser.MergeEntities(m_World); + EntityWrapper healthPickup = entityFile->MergeInto(m_World); //let the world know a pickup has spawned (graphics effects, etc) Events::PickupSpawned ePickupSpawned; - ePickupSpawned.Pickup = EntityWrapper(m_World, healthPickupID); + ePickupSpawned.Pickup = healthPickup; m_EventBroker->Publish(ePickupSpawned); //copy values from the old entity to the new entity - auto& newHealthPickupEntity = EntityWrapper(m_World, healthPickupID); + auto& newHealthPickupEntity = healthPickup; newHealthPickupEntity["Transform"]["Position"] = somePickup.Pos; newHealthPickupEntity["HealthPickup"]["HealthGain"] = somePickup.HealthGain; newHealthPickupEntity["HealthPickup"]["RespawnTimer"] = somePickup.RespawnTimer; diff --git a/src/Game/Systems/PlayerDeathSystem.cpp b/src/Game/Systems/PlayerDeathSystem.cpp index 844d2ed1..cbf0927f 100644 --- a/src/Game/Systems/PlayerDeathSystem.cpp +++ b/src/Game/Systems/PlayerDeathSystem.cpp @@ -4,6 +4,7 @@ PlayerDeathSystem::PlayerDeathSystem(SystemParams params) : System(params) { EVENT_SUBSCRIBE_MEMBER(m_OnPlayerDeath, &PlayerDeathSystem::OnPlayerDeath); + EVENT_SUBSCRIBE_MEMBER(m_EEntityDeleted, &PlayerDeathSystem::OnEntityDeleted); } void PlayerDeathSystem::Update(double dt) @@ -27,10 +28,8 @@ bool PlayerDeathSystem::OnPlayerDeath(Events::PlayerDeath& e) void PlayerDeathSystem::createDeathEffect(EntityWrapper player) { //load the explosioneffect XML - auto deathEffect = ResourceManager::Load("Schema/Entities/PlayerDeathExplosionWithCamera.xml"); - EntityFileParser parser(deathEffect); - EntityID deathEffectID = parser.MergeEntities(m_World); - EntityWrapper deathEffectEW = EntityWrapper(m_World, deathEffectID); + auto entityFile = ResourceManager::Load("Schema/Entities/PlayerDeathExplosionWithCamera.xml"); + EntityWrapper deathEffectEW = entityFile->MergeInto(m_World); //components that we need from player auto playerModel = player.FirstChildByName("PlayerModel"); @@ -59,9 +58,28 @@ void PlayerDeathSystem::createDeathEffect(EntityWrapper player) //camera (with lifetime) behind the player if (player == LocalPlayer) { + m_LocalPlayerDeathEffect = deathEffectEW; auto cam = deathEffectEW.FirstChildByName("Camera"); Events::SetCamera eSetCamera; eSetCamera.CameraEntity = cam; m_EventBroker->Publish(eSetCamera); } } + +bool PlayerDeathSystem::OnEntityDeleted(Events::EntityDeleted& e) +{ + // We only care about when the local players death effect is removed. + if (m_LocalPlayerDeathEffect.ID != e.DeletedEntity) { + return false; + } + + // Look for the spectator camera entity in the level. + EntityWrapper spectatorCam = m_World->GetFirstEntityByName("SpectatorCamera"); + if (!spectatorCam.Valid() || !spectatorCam.HasComponent("Camera") || LocalPlayer.Valid()) { + return false; + } + Events::SetCamera eSetCamera; + eSetCamera.CameraEntity = spectatorCam; + m_EventBroker->Publish(eSetCamera); + return true; +} diff --git a/src/Game/Systems/PlayerMovementSystem.cpp b/src/Game/Systems/PlayerMovementSystem.cpp index 8bcf092f..46f01afe 100644 --- a/src/Game/Systems/PlayerMovementSystem.cpp +++ b/src/Game/Systems/PlayerMovementSystem.cpp @@ -5,6 +5,7 @@ PlayerMovementSystem::PlayerMovementSystem(SystemParams params) { EVENT_SUBSCRIBE_MEMBER(m_EPlayerSpawned, &PlayerMovementSystem::OnPlayerSpawned); EVENT_SUBSCRIBE_MEMBER(m_EDoubleJump, &PlayerMovementSystem::OnDoubleJump); + EVENT_SUBSCRIBE_MEMBER(m_EDashAbility, &PlayerMovementSystem::OnDashAbility); } PlayerMovementSystem::~PlayerMovementSystem() @@ -79,7 +80,7 @@ void PlayerMovementSystem::updateMovementControllers(double dt) ComponentWrapper cPhysics = player["Physics"]; //Assault Dash Check if (player.HasComponent("DashAbility")) { - controller->AssaultDashCheck(dt, ((glm::vec3)cPhysics["Velocity"]).y != 0.0f, player["DashAbility"]["CoolDownMaxTimer"], player["DashAbility"]["CoolDownTimer"]); + controller->AssaultDashCheck(dt, ((glm::vec3)cPhysics["Velocity"]).y != 0.0f, player["DashAbility"]["CoolDownMaxTimer"], player["DashAbility"]["CoolDownTimer"], player.ID); } wishDirection = controller->Movement() * glm::inverse(glm::quat(ori)); //this makes sure you can only dash in the 4 directions: forw,backw,left,right @@ -323,11 +324,11 @@ bool PlayerMovementSystem::OnPlayerSpawned(Events::PlayerSpawned& e) bool PlayerMovementSystem::OnDoubleJump(Events::DoubleJump & e) { // If entity does not exist, exit - if (!EntityWrapper(m_World, e.entityID).Valid()) { + if (!EntityWrapper(m_World, e.entityID).Valid()) { return false; } // If entity IsLocalPlayer, exit - if (e.entityID == m_LocalPlayer.ID) { + if (e.entityID == m_LocalPlayer.ID) { return false; } spawnHexagon(EntityWrapper(m_World, e.entityID)); @@ -335,11 +336,33 @@ bool PlayerMovementSystem::OnDoubleJump(Events::DoubleJump & e) } void PlayerMovementSystem::spawnHexagon(EntityWrapper target) -{ +{ //put a hexagon at the entitys... feet? - auto hexagonEffect = ResourceManager::Load("Schema/Entities/DoubleJumpHexagon.xml"); - EntityFileParser parser(hexagonEffect); - EntityID hexagonEffectID = parser.MergeEntities(m_World); - EntityWrapper hexagonEW = EntityWrapper(m_World, hexagonEffectID); + auto entityFile = ResourceManager::Load("Schema/Entities/DoubleJumpHexagon.xml"); + EntityWrapper hexagonEW = entityFile->MergeInto(m_World); hexagonEW["Transform"]["Position"] = (glm::vec3)target["Transform"]["Position"]; -} \ No newline at end of file +} + +bool PlayerMovementSystem::OnDashAbility(Events::DashAbility & e) +{ + EntityWrapper player(m_World, e.Player); + if (!player.Valid() || !IsClient || player.ID == LocalPlayer.ID) { + return false; + } + + auto entityFile = ResourceManager::Load("Schema/Entities/DashEffect.xml"); + EntityWrapper dashEffect = entityFile->MergeInto(m_World); + auto playerModel = player.FirstChildByName("PlayerModel"); + auto playerEntityModel = playerModel["Model"]; + auto playerEntityAnimation = playerModel["Animation"]; + playerEntityModel.Copy(dashEffect["Model"]); + playerEntityAnimation.Copy(dashEffect["Animation"]); + dashEffect["ExplosionEffect"]["EndColor"] = (glm::vec4)playerEntityModel["Color"]; + ((glm::vec4&)dashEffect["ExplosionEffect"]["EndColor"]).w = 0.f; + dashEffect["Animation"]["Speed1"] = 0.0; + dashEffect["Animation"]["Speed2"] = 0.0; + dashEffect["Animation"]["Speed3"] = 0.0; + dashEffect["Transform"]["Position"] = (glm::vec3)player["Transform"]["Position"]; + dashEffect["Transform"]["Orientation"] = (glm::vec3)player["Transform"]["Orientation"]; + return true; +} diff --git a/src/Game/Systems/PlayerSpawnSystem.cpp b/src/Game/Systems/PlayerSpawnSystem.cpp index e03a1778..fbda849d 100644 --- a/src/Game/Systems/PlayerSpawnSystem.cpp +++ b/src/Game/Systems/PlayerSpawnSystem.cpp @@ -10,7 +10,7 @@ PlayerSpawnSystem::PlayerSpawnSystem(SystemParams params) ConfigFile* config = ResourceManager::Load("Config.ini"); m_NetworkEnabled = config->Get("Networking.StartNetwork", false); m_ForcedRespawnTime = config->Get("Debug.RespawnTime", -1.0f); - m_DbgConfigForceRespawn = m_ForcedRespawnTime > 0; + m_DbgConfigForceRespawn = m_ForcedRespawnTime > 0 && IsServer; } void PlayerSpawnSystem::Update(double dt) @@ -26,7 +26,21 @@ void PlayerSpawnSystem::Update(double dt) // Increase timer. double& timer = (double&)modeComponent["RespawnTime"]; timer += dt; - double maxRespawnTime = m_DbgConfigForceRespawn ? m_ForcedRespawnTime : (double)modeComponent["MaxRespawnTime"]; + if (m_DbgConfigForceRespawn) { + (double&)modeComponent["MaxRespawnTime"] = m_ForcedRespawnTime; + } + double maxRespawnTime = (double)modeComponent["MaxRespawnTime"]; + EntityWrapper spectatorCam = m_World->GetFirstEntityByName("SpectatorCamera"); + if (spectatorCam.Valid()) { + EntityWrapper HUD = spectatorCam.FirstChildByName("SpectatorHUD"); + if (HUD.Valid()) { + EntityWrapper respawnTimer = spectatorCam.FirstChildByName("RespawnTimer"); + if (respawnTimer.Valid()) { + //Update respawn time in the HUD element. + respawnTimer["Text"]["Content"] = std::to_string(1 + (int)(maxRespawnTime - timer)); + } + } + } if (timer < maxRespawnTime) { return; } @@ -54,7 +68,14 @@ void PlayerSpawnSystem::Update(double dt) // If the spawner has a team affiliation, check it if (spawner.HasComponent("Team")) { - if ((int)spawner["Team"]["Team"] != req.Team) { + auto cSpawnerTeam = spawner["Team"]; + if ((int)cSpawnerTeam["Team"] != req.Team) { + // Increase num spawned players if someone picks spectator, since it is valid to pick spectator + // but don't spawn anything, goto next spawnrequest. + if (req.Team == (int)cSpawnerTeam["Team"].Enum("Spectator")) { + ++numSpawnedPlayers; + break; + } continue; } } @@ -75,9 +96,9 @@ void PlayerSpawnSystem::Update(double dt) } } if (numSpawnedPlayers != (int)m_SpawnRequests.size()) { - LOG_DEBUG("%i players were supposed to be spawned, but %i was spawned.", (int)m_SpawnRequests.size(), numSpawnedPlayers); + LOG_DEBUG("%i players were supposed to be spawned or set as spectator, but only %i was handled.", (int)m_SpawnRequests.size(), numSpawnedPlayers); } else { - LOG_DEBUG("%i players were spawned.", numSpawnedPlayers); + LOG_DEBUG("%i players were spawned or set as spectator.", numSpawnedPlayers); } m_SpawnRequests.clear(); } @@ -88,24 +109,29 @@ bool PlayerSpawnSystem::OnInputCommand(Events::InputCommand& e) return false; } + if (e.Value == 0) { + return false; + } + + // A dead client should be able to swap to the spectator camera. + if (IsClient && !LocalPlayer.Valid()) { + // Set the spectator camera as active, if it exists. + // Find the camera. + EntityWrapper spectatorCam = m_World->GetFirstEntityByName("SpectatorCamera"); + if (spectatorCam.Valid() && spectatorCam.HasComponent("Camera")) { + Events::SetCamera eSetCamera; + eSetCamera.CameraEntity = spectatorCam; + m_EventBroker->Publish(eSetCamera); + } + } + // Team picks should be processed ONLY server-side! // Don't make a spawn request if we're the client. if (!IsServer && m_NetworkEnabled) { return false; } - if (e.Value == 0) { - return false; - } - - //TODO: Spectating? - //Right now, return if someone picks spectator. - //1 signifies spectator here, could not get Playerteam component since it may be invalid or without team comp. - if ((ComponentInfo::EnumType)e.Value == 1) { - return false; - } - - //Check if the player already requested spawn. + // Check if the player already requested spawn. auto iter = m_SpawnRequests.begin(); for (; iter != m_SpawnRequests.end(); ++iter) { if (iter->PlayerID == e.PlayerID) { @@ -114,11 +140,11 @@ bool PlayerSpawnSystem::OnInputCommand(Events::InputCommand& e) } if (iter != m_SpawnRequests.end()) { - //If player is in queue to spawn, then change their team affiliation in the request. + // If player is in queue to spawn, then change their team affiliation in the request. iter->Team = (ComponentInfo::EnumType)e.Value; } else if (m_PlayerEntities.count(e.PlayerID) == 0 || !m_PlayerEntities[e.PlayerID].Valid()) { - //If player is not in queue to spawn, then create a spawn request, - //but only if they are spectating and/or just connected. + // If player is not in queue to spawn, then create a spawn request, + // but only if they are spectating and/or just connected. SpawnRequest req; req.PlayerID = e.PlayerID; req.Team = (ComponentInfo::EnumType)e.Value; diff --git a/src/Game/Systems/SpawnerSystem.cpp b/src/Game/Systems/SpawnerSystem.cpp index 6500460f..282c958b 100644 --- a/src/Game/Systems/SpawnerSystem.cpp +++ b/src/Game/Systems/SpawnerSystem.cpp @@ -17,15 +17,17 @@ EntityWrapper SpawnerSystem::Spawn(EntityWrapper spawner, EntityWrapper parent / // Load the entity file and parse it const std::string& entityFilePath = spawner["Spawner"]["EntityFile"]; - auto entityFile = ResourceManager::Load(entityFilePath); - if (entityFile == nullptr) { + EntityWrapper spawnedEntity; + try { + auto entityFile = ResourceManager::Load(entityFilePath); + spawnedEntity = entityFile->MergeInto(world); + world->SetParent(spawnedEntity.ID, parent.ID); + } catch (const Resource::FailedLoadingException& e) { return EntityWrapper::Invalid; } - EntityFileParser parser(entityFile); - EntityWrapper spawnedEntity(world, parser.MergeEntities(world, parent.ID)); - //If the spawned entity is collideable, then we must not spawn it where it collides with something that - //has a dontCollideComponent attached. + // If the spawned entity is collidable, then we must not spawn it where it collides with something that + // has a dontCollideComponent attached. bool spawnOnCollidable = dontCollideComponent.empty() || !spawnedEntity.HasComponent("Collidable"); if (!spawnOnCollidable) { boost::optional optBox = Collision::EntityAbsoluteAABB(spawnedEntity); diff --git a/src/Tests/CapturePointTest.cpp b/src/Tests/CapturePointTest.cpp index 8a9baf40..8fb7869c 100644 --- a/src/Tests/CapturePointTest.cpp +++ b/src/Tests/CapturePointTest.cpp @@ -7,7 +7,7 @@ using boost::unit_test_framework::test_case; #include "Collision/TriggerSystem.h" #include "Collision/CollisionSystem.h" -#include "Core/EntityFileWriter.h" +#include "Core/EntityXMLFileWriter.h" #include "Game/Systems/CapturePointSystem.h" BOOST_AUTO_TEST_SUITE(CapturePointTestSuite) @@ -82,7 +82,7 @@ bool CapturePointTest::CapturePoint_Game_Loop_OneHundredTimes() { CapturePointTest::CapturePointTest(int runTestNumber) { ResourceManager::RegisterType("ConfigFile"); - ResourceManager::RegisterType("EntityFile"); + ResourceManager::RegisterType("EntityFile"); m_Config = ResourceManager::Load("Config.ini"); LOG_LEVEL = static_cast<_LOG_LEVEL>(m_Config->Get("Debug.LogLevel", 1)); @@ -99,10 +99,10 @@ CapturePointTest::CapturePointTest(int runTestNumber) m_SystemPipeline->AddSystem(1); //must register components (Components.xsd), else you cant create entities. Easiest done by loading a test xsd file - auto file = ResourceManager::Load("Schema/Entities/TeamTest.xml"); - EntityFilePreprocessor fpp(file); + auto file = ResourceManager::Load("Schema/Entities/TeamTest.xml"); + EntityXMLFilePreprocessor fpp(file); fpp.RegisterComponents(m_World); - EntityFileParser fp(file); + EntityXMLFileParser fp(file); fp.MergeEntities(m_World); EntityID playerID = m_World->CreateEntity(); diff --git a/src/Tests/CapturePointTest.h b/src/Tests/CapturePointTest.h index 54bdc55c..1046f714 100644 --- a/src/Tests/CapturePointTest.h +++ b/src/Tests/CapturePointTest.h @@ -9,12 +9,12 @@ #include "Input/KeyboardInputHandler.h" #include "Input/MouseInputHandler.h" #include "Core/EKeyDown.h" -#include "Core/EntityFile.h" +#include "Core/EntityXMLFile.h" #include "Core/SystemPipeline.h" -#include "Core/EntityFilePreprocessor.h" -#include "Core/EntityFileParser.h" -#include "Core/EntityFileWriter.h" +#include "Core/EntityXMLFilePreprocessor.h" +#include "Core/EntityXMLFileParser.h" +#include "Core/EntityXMLFileWriter.h" #include "Engine/Collision/ETrigger.h" diff --git a/src/Tests/HealthSystemTest.cpp b/src/Tests/HealthSystemTest.cpp index bf2650a3..0a8758ae 100644 --- a/src/Tests/HealthSystemTest.cpp +++ b/src/Tests/HealthSystemTest.cpp @@ -30,7 +30,7 @@ BOOST_AUTO_TEST_SUITE_END() GameHealthSystemTest::GameHealthSystemTest() { ResourceManager::RegisterType("ConfigFile"); - ResourceManager::RegisterType("EntityFile"); + ResourceManager::RegisterType("EntityFile"); m_Config = ResourceManager::Load("Config.ini"); LOG_LEVEL = static_cast<_LOG_LEVEL>(m_Config->Get("Debug.LogLevel", 1)); @@ -41,10 +41,10 @@ GameHealthSystemTest::GameHealthSystemTest() // Create a world m_World = new World(); - auto file = ResourceManager::Load("Schema/Entities/TeamTest.xml"); - EntityFilePreprocessor fpp(file); + auto file = ResourceManager::Load("Schema/Entities/TeamTest.xml"); + EntityXMLFilePreprocessor fpp(file); fpp.RegisterComponents(m_World); - EntityFileParser fp(file); + EntityXMLFileParser fp(file); fp.MergeEntities(m_World); // Create system pipeline diff --git a/src/Tests/HealthSystemTest.h b/src/Tests/HealthSystemTest.h index 275558d2..787a2d0e 100644 --- a/src/Tests/HealthSystemTest.h +++ b/src/Tests/HealthSystemTest.h @@ -11,7 +11,7 @@ #include "Input/KeyboardInputHandler.h" #include "Input/MouseInputHandler.h" #include "Core/EKeyDown.h" -#include "Core/EntityFile.h" +#include "Core/EntityXMLFile.h" #include "Core/SystemPipeline.h" #include "Editor/EditorSystem.h" diff --git a/src/Tests/PickupSpawnTest.cpp b/src/Tests/PickupSpawnTest.cpp index 4acd897e..0af72883 100644 --- a/src/Tests/PickupSpawnTest.cpp +++ b/src/Tests/PickupSpawnTest.cpp @@ -30,7 +30,7 @@ BOOST_AUTO_TEST_SUITE_END() PickupSpawnTest::PickupSpawnTest(int runTestNumber) { ResourceManager::RegisterType("ConfigFile"); - ResourceManager::RegisterType("EntityFile"); + ResourceManager::RegisterType("EntityFile"); m_Config = ResourceManager::Load("Config.ini"); LOG_LEVEL = static_cast<_LOG_LEVEL>(m_Config->Get("Debug.LogLevel", 1)); @@ -44,10 +44,10 @@ PickupSpawnTest::PickupSpawnTest(int runTestNumber) m_SystemPipeline->AddSystem(1); //must register components (Components.xsd), else you cant create entities. Easiest done by loading a test xsd file - auto file = ResourceManager::Load("Schema/Entities/HealthPickup.xml"); - EntityFilePreprocessor fpp(file); + auto file = ResourceManager::Load("Schema/Entities/HealthPickup.xml"); + EntityXMLFilePreprocessor fpp(file); fpp.RegisterComponents(m_World); - EntityFileParser fp(file); + EntityXMLFileParser fp(file); //connect the healthpickup to the world m_HealthPickupID = fp.MergeEntities(m_World); diff --git a/src/Tests/PickupSpawnTest.h b/src/Tests/PickupSpawnTest.h index b9d5483a..372b07cd 100644 --- a/src/Tests/PickupSpawnTest.h +++ b/src/Tests/PickupSpawnTest.h @@ -9,12 +9,12 @@ #include "Input/KeyboardInputHandler.h" #include "Input/MouseInputHandler.h" #include "Core/EKeyDown.h" -#include "Core/EntityFile.h" +#include "Core/EntityXMLFile.h" #include "Core/SystemPipeline.h" -#include "Core/EntityFilePreprocessor.h" -#include "Core/EntityFileParser.h" -#include "Core/EntityFileWriter.h" +#include "Core/EntityXMLFilePreprocessor.h" +#include "Core/EntityXMLFileParser.h" +#include "Core/EntityXMLFileWriter.h" #include "Engine/Collision/ETrigger.h" @@ -29,7 +29,7 @@ //#include #include "Collision/TriggerSystem.h" #include "Collision/CollisionSystem.h" -#include "Core/EntityFileWriter.h" +#include "Core/EntityXMLFileWriter.h" #include "Game/Systems/HealthSystem.h" #include "Game/Systems/PickupSpawnSystem.h"