diff --git a/assets b/assets index 172b3ad5..c56f6380 160000 --- a/assets +++ b/assets @@ -1 +1 @@ -Subproject commit 172b3ad527fc14aa6175fa72580a66a00f04e0ba +Subproject commit c56f6380ab05c23419beafe14190013d1432e32c diff --git a/deps b/deps index bf83f099..ed45883a 160000 --- a/deps +++ b/deps @@ -1 +1 @@ -Subproject commit bf83f099ba16f0a87f9bebe8cfc5fd4e59fee805 +Subproject commit ed45883a444c6de548b6211a83a079ff2ecfce15 diff --git a/include/Engine/Collision/Collision.h b/include/Engine/Collision/Collision.h index c4292907..c3759393 100644 --- a/include/Engine/Collision/Collision.h +++ b/include/Engine/Collision/Collision.h @@ -79,7 +79,8 @@ bool AABBVsAABB(const AABB& a, const AABB& b); bool AABBVsAABB(const AABB& a, const AABB& b, glm::vec3& minimumTranslation); // Calculates an absolute AABB from an entity AABB component -boost::optional EntityAbsoluteAABB(EntityWrapper& entity); +boost::optional EntityAbsoluteAABB(EntityWrapper& entity, bool takeModelBox = false); +boost::optional AbsoluteAABBExplosionEffect(EntityWrapper& entity); } diff --git a/include/Engine/Collision/CollisionSystem.h b/include/Engine/Collision/CollisionSystem.h index f3a7e4fe..c963e6b8 100644 --- a/include/Engine/Collision/CollisionSystem.h +++ b/include/Engine/Collision/CollisionSystem.h @@ -13,8 +13,8 @@ class CollisionSystem : public PureSystem { public: - CollisionSystem(World* world, EventBroker* eventBroker, Octree* octree) - : System(world, eventBroker) + CollisionSystem(SystemParams params, Octree* octree) + : System(params) , PureSystem("Collidable") , m_Octree(octree) { } diff --git a/include/Engine/Collision/FillFrustumOctreeSystem.h b/include/Engine/Collision/FillFrustumOctreeSystem.h index f7f1413c..430b4037 100644 --- a/include/Engine/Collision/FillFrustumOctreeSystem.h +++ b/include/Engine/Collision/FillFrustumOctreeSystem.h @@ -9,8 +9,8 @@ class FillFrustumOctreeSystem : public ImpureSystem, public PureSystem { public: - FillFrustumOctreeSystem(World* world, EventBroker* eventBroker, Octree* octree) - : System(world, eventBroker) + FillFrustumOctreeSystem(SystemParams params, Octree* octree) + : System(params) , PureSystem("Model") , m_Octree(octree) { } diff --git a/include/Engine/Collision/FillOctreeSystem.h b/include/Engine/Collision/FillOctreeSystem.h index 3bacccac..9c75878b 100644 --- a/include/Engine/Collision/FillOctreeSystem.h +++ b/include/Engine/Collision/FillOctreeSystem.h @@ -9,8 +9,8 @@ class FillOctreeSystem : public ImpureSystem, public PureSystem { public: - FillOctreeSystem(World* world, EventBroker* eventBroker, Octree* octree, const std::string& fillComponentType) - : System(world, eventBroker) + FillOctreeSystem(SystemParams params, Octree* octree, const std::string& fillComponentType) + : System(params) , PureSystem(fillComponentType) , m_Octree(octree) { } diff --git a/include/Engine/Collision/TriggerSystem.h b/include/Engine/Collision/TriggerSystem.h index fa322ddd..d71fad08 100644 --- a/include/Engine/Collision/TriggerSystem.h +++ b/include/Engine/Collision/TriggerSystem.h @@ -15,8 +15,8 @@ class AABB; class TriggerSystem : public PureSystem { public: - TriggerSystem(World* world, EventBroker* eventBroker, Octree* octree) - : System(world, eventBroker) + TriggerSystem(SystemParams params, Octree* octree) + : System(params) , PureSystem("Trigger") , m_Octree(octree) { diff --git a/include/Engine/Core/ComponentInfo.h b/include/Engine/Core/ComponentInfo.h index 49ed2a3f..d9799059 100644 --- a/include/Engine/Core/ComponentInfo.h +++ b/include/Engine/Core/ComponentInfo.h @@ -13,6 +13,7 @@ struct ComponentInfo unsigned int Allocation = 0; std::map FieldAnnotations; std::map> FieldEnumDefinitions; + bool NetworkReplicated = true; }; struct Field_t diff --git a/include/Engine/Core/ComponentWrapper.h b/include/Engine/Core/ComponentWrapper.h index df16dca9..0b9f7357 100644 --- a/include/Engine/Core/ComponentWrapper.h +++ b/include/Engine/Core/ComponentWrapper.h @@ -1,6 +1,7 @@ #ifndef ComponentWrapper_h__ #define ComponentWrapper_h__ +#include #include "../Common.h" #include "Entity.h" #include "ComponentInfo.h" @@ -81,6 +82,18 @@ struct ComponentWrapper SubscriptProxy operator[](std::string propertyName) { return SubscriptProxy(this, propertyName); } }; +// A component wrapper that "owns" its data through a shared pointer +struct SharedComponentWrapper : ComponentWrapper +{ + SharedComponentWrapper(const ComponentInfo& componentInfo, boost::shared_array data) + : ComponentWrapper(componentInfo, data.get()) + , m_DataReference(data) + { } + +private: + boost::shared_array m_DataReference; +}; + // TODO: Move this to Tests once entity importing is finished class ComponentWrapperFactory { diff --git a/include/Engine/Core/EntityFilePreprocessor.h b/include/Engine/Core/EntityFilePreprocessor.h index 3139169f..b46bd383 100644 --- a/include/Engine/Core/EntityFilePreprocessor.h +++ b/include/Engine/Core/EntityFilePreprocessor.h @@ -3,6 +3,8 @@ #include #include +#include +#include #include #include #include diff --git a/include/Engine/Core/EntityWrapper.h b/include/Engine/Core/EntityWrapper.h index 087471c0..b0e65d9e 100644 --- a/include/Engine/Core/EntityWrapper.h +++ b/include/Engine/Core/EntityWrapper.h @@ -30,7 +30,7 @@ struct EntityWrapper EntityWrapper FirstChildByName(const std::string& name); EntityWrapper FirstParentWithComponent(const std::string& componentType); bool IsChildOf(EntityWrapper potentialParent); - bool Valid(); + bool Valid() const; ComponentWrapper operator[](const char* componentName); bool operator==(const EntityWrapper& e) const; diff --git a/include/Engine/Core/EventBroker.h b/include/Engine/Core/EventBroker.h index dc1babc0..20d3b60c 100644 --- a/include/Engine/Core/EventBroker.h +++ b/include/Engine/Core/EventBroker.h @@ -5,6 +5,7 @@ #include #include #include +#include #include "../Common.h" #include "Event.h" @@ -107,7 +108,7 @@ private: typedef std::unordered_map ContextRelays_t; ContextRelays_t m_ContextRelays; std::vector m_RelaysToSubscribe; - std::vector> m_RelaysToUnsubscribe; + std::unordered_map> m_RelaysToUnsubscribe; typedef std::list>> EventQueue_t; std::shared_ptr m_EventQueueRead; diff --git a/include/Engine/Core/Octree.h b/include/Engine/Core/Octree.h index 6bdea4d3..b011a518 100644 --- a/include/Engine/Core/Octree.h +++ b/include/Engine/Core/Octree.h @@ -6,9 +6,7 @@ #include "../Common.h" #include "AABB.h" #include "Frustum.h" - -//Fwd declarations. -class Ray; +#include "Ray.h" namespace OctSpace { diff --git a/include/Engine/Core/System.h b/include/Engine/Core/System.h index ec57f5fc..1a387855 100644 --- a/include/Engine/Core/System.h +++ b/include/Engine/Core/System.h @@ -5,21 +5,55 @@ #include "World.h" #include "EntityWrapper.h" #include "ComponentWrapper.h" +#include "EPlayerSpawned.h" + +struct SystemParams +{ + SystemParams(::World* World, ::EventBroker* EventBroker, bool IsClient, bool IsServer) + : World(World) + , EventBroker(EventBroker) + , IsClient(IsClient) + , IsServer(IsServer) + { } + + ::World* World; + ::EventBroker* EventBroker; + bool IsClient = false; + bool IsServer = false; +}; class System { friend class SystemPipeline; protected: - System(World* world, EventBroker) { } - System(World* world, EventBroker* eventBroker) - : m_World(world) - , m_EventBroker(eventBroker) - { } + System(SystemParams params) + : m_World(params.World) + , m_EventBroker(params.EventBroker) + , IsClient(params.IsClient) + , IsServer(params.IsServer) + { + if (IsClient) { + EVENT_SUBSCRIBE_MEMBER(m_EPlayerSpawned, &System::setLocalPlayer); + } + } virtual ~System() = default; World* m_World; EventBroker* m_EventBroker; + bool IsClient = false; + bool IsServer = false; + EntityWrapper LocalPlayer = EntityWrapper::Invalid; + +private: + EventRelay m_EPlayerSpawned; + virtual bool setLocalPlayer(Events::PlayerSpawned& e) + { + if (e.PlayerID == -1) { + LocalPlayer = e.Player; + } + return true; + } }; class PureSystem : public virtual System @@ -34,7 +68,7 @@ protected: const std::string m_ComponentType; - virtual void UpdateComponent(EntityWrapper& entity, ComponentWrapper& cComponent, double dt) = 0; + virtual void UpdateComponent(EntityWrapper& entity, ComponentWrapper& cPlayer, double dt) = 0; }; class ImpureSystem : public virtual System diff --git a/include/Engine/Core/SystemPipeline.h b/include/Engine/Core/SystemPipeline.h index 90303f12..5f7aee0b 100644 --- a/include/Engine/Core/SystemPipeline.h +++ b/include/Engine/Core/SystemPipeline.h @@ -10,9 +10,11 @@ class SystemPipeline { public: - SystemPipeline(World* world, EventBroker* eventBroker) + SystemPipeline(World* world, EventBroker* eventBroker, bool isClient, bool isServer) : m_World(world) , m_EventBroker(eventBroker) + , m_IsClient(isClient) + , m_IsServer(isServer) { EVENT_SUBSCRIBE_MEMBER(m_EPause, &SystemPipeline::OnPause); EVENT_SUBSCRIBE_MEMBER(m_EResume, &SystemPipeline::OnResume); @@ -35,7 +37,7 @@ public: m_OrderedSystemGroups.resize(updateOrderLevel + 1); } UnorderedSystems& group = m_OrderedSystemGroups[updateOrderLevel]; - System* system = new T(m_World, m_EventBroker, args...); + System* system = new T(SystemParams(m_World, m_EventBroker, m_IsClient, m_IsServer), args...); group.Systems[typeid(T).name()] = system; PureSystem* pureSystem = dynamic_cast(system); @@ -59,6 +61,9 @@ public: dt = 0.0; } + // Process utility events for the System base class + m_EventBroker->Process(); + for (UnorderedSystems& group : m_OrderedSystemGroups) { // Process events for (auto& pair : group.Systems) { @@ -88,6 +93,8 @@ public: private: World* m_World; EventBroker* m_EventBroker; + bool m_IsClient = false; + bool m_IsServer = false; bool m_Paused = false; struct UnorderedSystems diff --git a/include/Engine/Core/UniformScaleSystem.h b/include/Engine/Core/UniformScaleSystem.h index 0ebc0672..cd679fed 100644 --- a/include/Engine/Core/UniformScaleSystem.h +++ b/include/Engine/Core/UniformScaleSystem.h @@ -8,7 +8,7 @@ class UniformScaleSystem : public PureSystem { public: - UniformScaleSystem(World* world, EventBroker* eventBroker); + UniformScaleSystem(SystemParams params); virtual void UpdateComponent(EntityWrapper& entity, ComponentWrapper& cUniformScale, double dt) override; diff --git a/include/Engine/Core/Util/IfDebug.h b/include/Engine/Core/Util/IfDebug.h index 79cb3a4c..85b64c8d 100644 --- a/include/Engine/Core/Util/IfDebug.h +++ b/include/Engine/Core/Util/IfDebug.h @@ -4,7 +4,7 @@ // } // NOTE: condition statement is not executed at all in release mode. #ifndef DEBUG_IF -#ifndef DEBUG +#ifdef DEBUG #define DEBUG_IF(c) if(c) #else #define DEBUG_IF(c) if(false) diff --git a/include/Engine/Editor/EditorRenderSystem.h b/include/Engine/Editor/EditorRenderSystem.h index 361669ba..a42ad779 100644 --- a/include/Engine/Editor/EditorRenderSystem.h +++ b/include/Engine/Editor/EditorRenderSystem.h @@ -10,7 +10,7 @@ class EditorRenderSystem : public ImpureSystem { public: - EditorRenderSystem(World* world, EventBroker* eventBroker, IRenderer* renderer, RenderFrame* renderFrame); + EditorRenderSystem(SystemParams params, IRenderer* renderer, RenderFrame* renderFrame); virtual void Update(double dt) override; diff --git a/include/Engine/Editor/EditorSystem.h b/include/Engine/Editor/EditorSystem.h index accf66e4..fcaa2e47 100644 --- a/include/Engine/Editor/EditorSystem.h +++ b/include/Engine/Editor/EditorSystem.h @@ -17,7 +17,7 @@ class EditorSystem : public ImpureSystem { public: - EditorSystem(World* world, EventBroker* eventBroker, IRenderer* renderer, RenderFrame* renderFrame); + EditorSystem(SystemParams params, IRenderer* renderer, RenderFrame* renderFrame); ~EditorSystem(); void Update(double dt); diff --git a/include/Engine/Editor/EditorWidgetSystem.h b/include/Engine/Editor/EditorWidgetSystem.h index a060bdd5..57e653d6 100644 --- a/include/Engine/Editor/EditorWidgetSystem.h +++ b/include/Engine/Editor/EditorWidgetSystem.h @@ -25,7 +25,7 @@ struct WidgetDelta : Event class EditorWidgetSystem : public ImpureSystem, PureSystem { public: - EditorWidgetSystem(World* world, EventBroker* eventBroker, IRenderer* renderer); + EditorWidgetSystem(SystemParams params, IRenderer* renderer); virtual void Update(double dt) override; virtual void UpdateComponent(EntityWrapper& entity, ComponentWrapper& cEditorWidget, double dt) override; diff --git a/include/Engine/Network/Client.h b/include/Engine/Network/Client.h index 7d1d5bba..fb367874 100644 --- a/include/Engine/Network/Client.h +++ b/include/Engine/Network/Client.h @@ -20,16 +20,22 @@ #include "Input/EInputCommand.h" #include "Core/EPlayerDamage.h" #include "Network/EInterpolate.h" +#include "Network/SnapshotFilter.h" #include "Core/EPlayerSpawned.h" class Client : public Network { public: - Client(ConfigFile* config); + Client(World* world, EventBroker* eventBroker); + Client(World* world, EventBroker* eventBroker, std::unique_ptr snapshotFilter); ~Client(); - void Start(World* world, EventBroker* eventBroker) override; + + void Connect(std::string address, int port); void Update() override; + private: + std::unique_ptr m_SnapshotFilter = nullptr; + // Assio UDP logic boost::asio::ip::udp::endpoint m_ReceiverEndpoint; boost::asio::io_service m_IOService; @@ -45,10 +51,8 @@ private: PacketID m_SendPacketID = 0; // Game logic - World* m_World; std::string m_PlayerName; PlayerID m_PlayerID = -1; - EntityID m_ServerEntityID = std::numeric_limits::max(); bool m_IsConnected = false; EntityWrapper m_LocalPlayer = EntityWrapper::Invalid; // Server Client Lookup map @@ -74,7 +78,9 @@ private: void connect(); void disconnect(); void parseMessageType(Packet& packet); - void updateFields(Packet& packet, const ComponentInfo& componentInfo, const EntityID& entityID, const std::string& componentType); + void updateFields(Packet& packet, const ComponentInfo& componentInfo, const EntityID& entityID); + SharedComponentWrapper createSharedComponent(Packet& packet, EntityID entityID, const ComponentInfo& componentInfo); + void ignoreFields(Packet& packet, const ComponentInfo& componentInfo); void parseConnect(Packet& packet); void parsePlayerConnected(Packet& packet); void parsePing(); @@ -99,7 +105,6 @@ private: void deleteFromServerClientMaps(EntityID serverEntityID, EntityID clientEntityID); // Events - EventBroker* m_EventBroker; EventRelay m_EInputCommand; bool OnInputCommand(const Events::InputCommand& e); EventRelay m_EPlayerDamage; diff --git a/include/Engine/Network/EInterpolate.h b/include/Engine/Network/EInterpolate.h index 93bf1a5c..79af840d 100644 --- a/include/Engine/Network/EInterpolate.h +++ b/include/Engine/Network/EInterpolate.h @@ -11,8 +11,13 @@ namespace Events struct Interpolate : Event { - EntityID Entity; - boost::shared_array DataArray; + Interpolate(EntityWrapper Entity, SharedComponentWrapper Component) + : Entity(Entity) + , Component(Component) + { } + + EntityWrapper Entity; + SharedComponentWrapper Component; }; } diff --git a/include/Engine/Network/Network.h b/include/Engine/Network/Network.h index 874e3377..0dbc4915 100644 --- a/include/Engine/Network/Network.h +++ b/include/Engine/Network/Network.h @@ -19,10 +19,15 @@ typedef unsigned int PacketID; class Network { public: + Network(World* world, EventBroker* eventBroker); virtual ~Network() { }; - virtual void Start(World* m_world, EventBroker *eventBroker) = 0; + virtual void Update() = 0; + protected: + World* m_World; + EventBroker* m_EventBroker; + // For Debug bool isReadingData = false; NetworkData m_NetworkData; @@ -32,7 +37,6 @@ protected: double m_TimeoutMs; void saveToFile(); void updateNetworkData(); - void initialize(); }; #endif \ No newline at end of file diff --git a/include/Engine/Network/Server.h b/include/Engine/Network/Server.h index 90b9e922..f16c6c16 100644 --- a/include/Engine/Network/Server.h +++ b/include/Engine/Network/Server.h @@ -22,15 +22,17 @@ class Server : public Network { public: - Server(); + Server(World* world, EventBroker* eventBroker, int port); ~Server(); - void Start(World* m_world, EventBroker *eventBroker) override; + void Update() override; + private: + int m_Port = 27666; // UDP logic boost::asio::ip::udp::endpoint m_ReceiverEndpoint; boost::asio::io_service m_IOService; - boost::asio::ip::udp::socket m_Socket; + std::unique_ptr m_Socket; // Sending messages to client logic std::map m_ConnectedPlayers; @@ -46,13 +48,10 @@ private: float snapshotInterval; int checkTimeOutInterval = 100; int m_NextPlayerID = 0; + std::vector m_InputCommandsToBroadcast; //Timers std::clock_t m_StartPingTime; - - // Game logic - World* m_World; - EventBroker* m_EventBroker; // Packet loss logic PacketID m_PacketID = 0; @@ -66,6 +65,7 @@ private: void broadcast(Packet& packet); void sendSnapshot(); void addChildrenToPacket(Packet& packet, EntityID entityID); + void addInputCommandsToPacket(Packet& packet); void sendPing(); void checkForTimeOuts(); void disconnect(PlayerID playerID); diff --git a/include/Engine/Network/SnapshotFilter.h b/include/Engine/Network/SnapshotFilter.h new file mode 100644 index 00000000..4e63c4b1 --- /dev/null +++ b/include/Engine/Network/SnapshotFilter.h @@ -0,0 +1,19 @@ +#ifndef SnapshotFilter_h__ +#define SnapshotFilter_h__ + +#include "../Core/EntityWrapper.h" +#include "../Core/ComponentWrapper.h" + +class SnapshotFilter +{ +public: + // Filters an incoming snapshot. + // Modify the component and return true if the component snapshot should be applied. + // Otherwise return false and it will be ignored. + virtual bool FilterComponent(EntityWrapper entity, SharedComponentWrapper& component) + { + return true; + } +}; + +#endif \ No newline at end of file diff --git a/include/Engine/Rendering/AnimationSystem.h b/include/Engine/Rendering/AnimationSystem.h index aa9d3a11..dbe4b3fc 100644 --- a/include/Engine/Rendering/AnimationSystem.h +++ b/include/Engine/Rendering/AnimationSystem.h @@ -14,8 +14,8 @@ class AnimationSystem : public PureSystem { public: - AnimationSystem(World* world, EventBroker* eventBroker) - : System(world, eventBroker) + AnimationSystem(SystemParams params) + : System(params) , PureSystem("Animation") { diff --git a/include/Engine/Rendering/BoneAttachmentSystem.h b/include/Engine/Rendering/BoneAttachmentSystem.h index 93ce5119..55c2a1c8 100644 --- a/include/Engine/Rendering/BoneAttachmentSystem.h +++ b/include/Engine/Rendering/BoneAttachmentSystem.h @@ -13,8 +13,8 @@ class BoneAttachmentSystem : public PureSystem { public: - BoneAttachmentSystem(World* world, EventBroker* eventBroker) - : System(world, eventBroker) + BoneAttachmentSystem(SystemParams params) + : System(params) , PureSystem("BoneAttachment") { diff --git a/include/Engine/Rendering/IRenderer.h b/include/Engine/Rendering/IRenderer.h index b399aefa..4441bb7d 100644 --- a/include/Engine/Rendering/IRenderer.h +++ b/include/Engine/Rendering/IRenderer.h @@ -32,6 +32,8 @@ public: virtual void SetFullscreen(bool fullscreen) { m_Fullscreen = fullscreen; } bool VSYNC() const { return m_VSYNC; } virtual void SetVSYNC(bool vsync) { m_VSYNC = vsync; } + std::string WindowTitle() const { return m_WindowTitle; } + virtual void SetWindowTitle(const std::string& title) { glfwSetWindowTitle(m_Window, title.c_str()); m_WindowTitle = title; } //Returns screen size excluding window border and header Rectangle GetViewportSize() const { return m_ViewportSize; } virtual void Initialize() = 0; @@ -47,6 +49,7 @@ protected: int m_GLVersion[2]; std::string m_GLVendor; GLFWwindow* m_Window = nullptr; + std::string m_WindowTitle; }; #endif // Renderer_h__ diff --git a/include/Engine/Rendering/RenderSystem.h b/include/Engine/Rendering/RenderSystem.h index 4a313087..44687e55 100644 --- a/include/Engine/Rendering/RenderSystem.h +++ b/include/Engine/Rendering/RenderSystem.h @@ -22,7 +22,7 @@ class RenderSystem : public ImpureSystem { public: - RenderSystem(World* world, EventBroker* eventBrokerer, const IRenderer* renderer, RenderFrame* renderFrame, Octree* frustumCullOctree); + RenderSystem(SystemParams params, const IRenderer* renderer, RenderFrame* renderFrame, Octree* frustumCullOctree); ~RenderSystem(); virtual void Update(double dt) override; @@ -31,7 +31,6 @@ private: const IRenderer* m_Renderer; RenderFrame* m_RenderFrame; Camera* m_Camera; - World* m_World; EntityWrapper m_CurrentCamera = EntityWrapper::Invalid; EntityWrapper m_LocalPlayer = EntityWrapper::Invalid; Octree* m_Octree; diff --git a/include/Game/ExplosionEffectSystem.h b/include/Game/ExplosionEffectSystem.h deleted file mode 100644 index 061ad221..00000000 --- a/include/Game/ExplosionEffectSystem.h +++ /dev/null @@ -1,24 +0,0 @@ -#include "Common.h" -#include "Core/System.h" - -class ExplosionEffectSystem : public PureSystem -{ -public: - ExplosionEffectSystem(World* world, EventBroker* eventBroker) - : System(world, eventBroker) - , PureSystem("ExplosionEffect") - { } - - virtual void UpdateComponent(EntityWrapper& entity, ComponentWrapper& component, double dt) override - { - - if ((double)component["TimeSinceDeath"] > (double)component["ExplosionDuration"]) { - (double)component["TimeSinceDeath"] = 0.f; - } - (double&)component["TimeSinceDeath"] += dt; - - //if ((bool)Component["Gravity"] == true) { - // (bool)Component["ExponentialAccelaration"] = false; - //} - } -}; \ No newline at end of file diff --git a/include/Game/Game.h b/include/Game/Game.h index 6177a818..baf15656 100644 --- a/include/Game/Game.h +++ b/include/Game/Game.h @@ -1,6 +1,8 @@ #ifndef Game_h__ #define Game_h__ +#include + #include "Core/ResourceManager.h" #include "Core/ConfigFile.h" #include "Core/EventBroker.h" @@ -14,7 +16,7 @@ #include "Core/EKeyDown.h" #include "Core/EntityFilePreprocessor.h" #include "Core/SystemPipeline.h" -#include "ExplosionEffectSystem.h" +#include "Systems/ExplosionEffectSystem.h" #include "Editor/EditorSystem.h" #include "Core/EntityFile.h" #include "Rendering/RenderSystem.h" @@ -43,7 +45,9 @@ public: void Tick(); private: - double m_LastTime; + std::string m_NetworkAddress; + int m_NetworkPort = 0; + ConfigFile* m_Config = nullptr; EventBroker* m_EventBroker; IRenderer* m_Renderer; @@ -56,24 +60,15 @@ private: Octree* m_OctreeFrustrumCulling; SystemPipeline* m_SystemPipeline; RenderFrame* m_RenderFrame; - // Network variables - boost::thread m_NetworkThread; - - // Network methods - void networkFunction(); - Network* m_ClientOrServer; - bool m_IsClientOrServer = false; - - // Sound + Client* m_NetworkClient = nullptr; + Server* m_NetworkServer = nullptr; SoundManager* m_SoundManager; + double m_LastTime; - //EventRelay m_EInputCommand; - //bool debugOnInputCommand(const Events::InputCommand& e); - - void debugInitialize(); - void debugTick(double dt); - EventRelay m_EKeyDown; + bool m_IsClient = false; + bool m_IsServer = false; + int parseArgs(int argc, char* argv[]); }; #endif diff --git a/include/Game/Network/MultiplayerSnapshotFilter.h b/include/Game/Network/MultiplayerSnapshotFilter.h new file mode 100644 index 00000000..32c82e01 --- /dev/null +++ b/include/Game/Network/MultiplayerSnapshotFilter.h @@ -0,0 +1,25 @@ +#ifndef MultiplayerSnapshotFilter_h__ +#define MultiplayerSnapshotFilter_h__ + +#include "Core/EventBroker.h" +#include "Core/EPlayerSpawned.h" +#include "Network/SnapshotFilter.h" +#include "Network/EInterpolate.h" + +class MultiplayerSnapshotFilter : public SnapshotFilter +{ +public: + MultiplayerSnapshotFilter(EventBroker* eventBroker); + + virtual bool FilterComponent(EntityWrapper entity, SharedComponentWrapper& component) override; + +private: + EventBroker* m_EventBroker; + + EntityWrapper m_LocalPlayer = EntityWrapper::Invalid; + + EventRelay m_EPlayerSpawned; + bool OnPlayerSpawned(Events::PlayerSpawned ePlayerSpawned); +}; + +#endif \ No newline at end of file diff --git a/include/Game/Systems/CapturePointSystem.h b/include/Game/Systems/CapturePointSystem.h index 18c32c76..22e7e3d5 100644 --- a/include/Game/Systems/CapturePointSystem.h +++ b/include/Game/Systems/CapturePointSystem.h @@ -17,7 +17,7 @@ class CapturePointSystem : public PureSystem { public: //WARNING: on new map, destroy all info in the vectors, as well as reset all variables (just make new?) - CapturePointSystem(World* world, EventBroker* eventBroker); + CapturePointSystem(SystemParams params); //updatecomponent virtual void UpdateComponent(EntityWrapper& entity, ComponentWrapper& capturePoint, double dt) override; diff --git a/include/Game/Systems/ExplosionEffectSystem.h b/include/Game/Systems/ExplosionEffectSystem.h new file mode 100644 index 00000000..24eee955 --- /dev/null +++ b/include/Game/Systems/ExplosionEffectSystem.h @@ -0,0 +1,18 @@ +#ifndef ExplosionEffectSystem_h__ +#define ExplosionEffectSystem_h__ + +#include "Common.h" +#include "Core/System.h" + +class ExplosionEffectSystem : public PureSystem +{ +public: + ExplosionEffectSystem(SystemParams params) + : System(params) + , PureSystem("ExplosionEffect") + { } + + virtual void UpdateComponent(EntityWrapper& entity, ComponentWrapper& component, double dt) override; +}; + +#endif \ No newline at end of file diff --git a/include/Game/Systems/HealthSystem.h b/include/Game/Systems/HealthSystem.h index 61456d5d..b66d8eb0 100644 --- a/include/Game/Systems/HealthSystem.h +++ b/include/Game/Systems/HealthSystem.h @@ -17,7 +17,7 @@ class HealthSystem : public PureSystem { public: - HealthSystem(World* world, EventBroker* eventBroker); + HealthSystem(SystemParams params); //updatecomponent virtual void UpdateComponent(EntityWrapper& entity, ComponentWrapper& component, double dt) override; diff --git a/include/Game/Systems/InterpolationSystem.h b/include/Game/Systems/InterpolationSystem.h index 96236f62..758609c8 100644 --- a/include/Game/Systems/InterpolationSystem.h +++ b/include/Game/Systems/InterpolationSystem.h @@ -16,38 +16,47 @@ #include "Network/EInterpolate.h" -class InterpolationSystem : public PureSystem +class InterpolationSystem : public ImpureSystem { - struct Transform - { - glm::vec3 Position; - glm::vec3 Scale; - glm::quat Orientation; - float interpolationTime; - }; public: - InterpolationSystem(World* world, EventBroker* eventBroker); + InterpolationSystem(SystemParams params); ~InterpolationSystem() { } - virtual void UpdateComponent(EntityWrapper& entity, ComponentWrapper& transform, double dt) override; -private: - std::unordered_map m_NextTransform; - std::unordered_map m_LastReceivedTransform; - EntityWrapper m_LocalPlayer = EntityWrapper::Invalid; - //glm::vec3 vectorInterpolation(glm::vec3 prev, glm::vec3 next, double currentTime); + virtual void Update(double dt) override; + +private: + template + struct Interpolation + { + Interpolation(const ComponentWrapper& Component, const std::string& Field, const T& Start, const T& Goal) + : Component(Component) + , Field(Field) + , Start(Start) + , Goal(Goal) + { } + + ComponentWrapper Component; + std::string Field; + T Start; + T Goal; + double Alpha = 0.0; + }; + + float m_SnapshotInterval; + std::unordered_map> m_InterpolatePosition; + std::unordered_map> m_InterpolateOrientation; + std::unordered_map> m_InterpolateVelocity; + + EventRelay m_EInterpolate; + bool InterpolationSystem::OnInterpolate(Events::Interpolate& e); + template T vectorInterpolation(T prev, T next, double currentTime) { T difference = next - prev; - T vector = (difference / m_SnapshotInterval) * static_cast(currentTime); + T vector = difference * (static_cast(currentTime) / m_SnapshotInterval); return vector; } - float m_SnapshotInterval; - - EventRelay m_EInterpolate; - bool InterpolationSystem::OnInterpolate(const Events::Interpolate& e); - EventRelay m_EPlayerSpawned; - bool OnPlayerSpawned(Events::PlayerSpawned& e); }; #endif diff --git a/include/Game/Systems/LifetimeSystem.h b/include/Game/Systems/LifetimeSystem.h index 99cafd89..6dee644d 100644 --- a/include/Game/Systems/LifetimeSystem.h +++ b/include/Game/Systems/LifetimeSystem.h @@ -6,8 +6,8 @@ class LifetimeSystem : public ImpureSystem, PureSystem { public: - LifetimeSystem(World* world, EventBroker* eventBroker) - : System(world, eventBroker) + LifetimeSystem(SystemParams params) + : System(params) , PureSystem("Lifetime") { LOG_INFO("ASDASDASSA"); diff --git a/include/Game/Systems/PickupSpawnSystem.h b/include/Game/Systems/PickupSpawnSystem.h index 24cee2b9..f912e8ff 100644 --- a/include/Game/Systems/PickupSpawnSystem.h +++ b/include/Game/Systems/PickupSpawnSystem.h @@ -14,7 +14,7 @@ class PickupSpawnSystem : public ImpureSystem { public: - PickupSpawnSystem(World* world, EventBroker* eventBroker); + PickupSpawnSystem(SystemParams params); virtual void Update(double dt) override; diff --git a/include/Game/Systems/PlayerDeathSystem.h b/include/Game/Systems/PlayerDeathSystem.h index 988dad57..112c202e 100644 --- a/include/Game/Systems/PlayerDeathSystem.h +++ b/include/Game/Systems/PlayerDeathSystem.h @@ -15,7 +15,7 @@ class PlayerDeathSystem : public ImpureSystem { public: - PlayerDeathSystem(World* world, EventBroker* eventBroker); + PlayerDeathSystem(SystemParams params); virtual void Update(double dt) override; diff --git a/include/Game/Systems/PlayerHUD.h b/include/Game/Systems/PlayerHUDSystem.h similarity index 58% rename from include/Game/Systems/PlayerHUD.h rename to include/Game/Systems/PlayerHUDSystem.h index 180f5a2a..50b6a258 100644 --- a/include/Game/Systems/PlayerHUD.h +++ b/include/Game/Systems/PlayerHUDSystem.h @@ -6,18 +6,14 @@ #include "../../Engine/Rendering/ESetCamera.h" #include -class PlayerHUD : public ImpureSystem +class PlayerHUDSystem : public ImpureSystem { public: - PlayerHUD(World* world, EventBroker* eventBrokerer); - ~PlayerHUD(); + PlayerHUDSystem(SystemParams params) + : System(params) + { } virtual void Update(double dt) override; - -private: - World* m_World; - EventBroker* m_EventBroker; - }; #endif \ No newline at end of file diff --git a/include/Game/Systems/PlayerMovementSystem.h b/include/Game/Systems/PlayerMovementSystem.h index defaa8ae..63dea966 100644 --- a/include/Game/Systems/PlayerMovementSystem.h +++ b/include/Game/Systems/PlayerMovementSystem.h @@ -7,14 +7,13 @@ #include "Events/EDoubleJump.h" #include "../Engine/Sound/EPlaySoundOnEntity.h" -class PlayerMovementSystem : public ImpureSystem, PureSystem +class PlayerMovementSystem : public ImpureSystem { public: - PlayerMovementSystem(World* world, EventBroker* eventBroker); + PlayerMovementSystem(SystemParams params); ~PlayerMovementSystem(); virtual void Update(double dt) override; - virtual void UpdateComponent(EntityWrapper& entity, ComponentWrapper& component, double dt); private: // State @@ -36,4 +35,6 @@ private: EventRelay m_EPlayerSpawned; bool OnPlayerSpawned(Events::PlayerSpawned& e); + void updateMovementControllers(double dt); + void updateVelocity(double dt); }; \ No newline at end of file diff --git a/include/Game/Systems/PlayerSpawnSystem.h b/include/Game/Systems/PlayerSpawnSystem.h index f5aa7b82..c68bb21f 100644 --- a/include/Game/Systems/PlayerSpawnSystem.h +++ b/include/Game/Systems/PlayerSpawnSystem.h @@ -10,7 +10,7 @@ class PlayerSpawnSystem : public ImpureSystem { public: - PlayerSpawnSystem(World* world, EventBroker* eventBroker); + PlayerSpawnSystem(SystemParams params); virtual void Update(double dt) override; diff --git a/include/Game/Systems/RaptorCopterSystem.h b/include/Game/Systems/RaptorCopterSystem.h index 8bb18de6..b3589dcd 100644 --- a/include/Game/Systems/RaptorCopterSystem.h +++ b/include/Game/Systems/RaptorCopterSystem.h @@ -4,8 +4,8 @@ class RaptorCopterSystem : public PureSystem { public: - RaptorCopterSystem(World* world, EventBroker* eventBroker) - : System(world, eventBroker) + RaptorCopterSystem(SystemParams params) + : System(params) , PureSystem("RaptorCopter") { } diff --git a/include/Game/Systems/SoundSystem.h b/include/Game/Systems/SoundSystem.h index 09582826..962eb085 100644 --- a/include/Game/Systems/SoundSystem.h +++ b/include/Game/Systems/SoundSystem.h @@ -27,14 +27,10 @@ class SoundSystem : public PureSystem, ImpureSystem { public: - SoundSystem(World* world, EventBroker* eventbroker); + SoundSystem(SystemParams params); virtual void UpdateComponent(EntityWrapper& entity, ComponentWrapper& cComponent, double dt) override; virtual void Update(double dt) override; private: - EntityWrapper m_LocalPlayer = EntityWrapper(); - - World* m_World = nullptr; - EventBroker* m_EventBroker = nullptr; std::string m_Announcer = ""; // Logic for playing a sound when a player jumps void playerJumps(); @@ -56,8 +52,6 @@ private: bool OnDashAbility(const Events::DashAbility &e); EventRelay m_ETriggerTouch; bool OnTriggerTouch(const Events::TriggerTouch &e); - EventRelay m_EShoot; - bool OnShoot(const Events::Shoot &e); EventRelay m_ECaptured; bool OnCaptured(const Events::Captured &e); EventRelay m_EPlayerDamage; diff --git a/include/Game/Systems/SpawnerSystem.h b/include/Game/Systems/SpawnerSystem.h index 62f6b09a..9cb4bd06 100644 --- a/include/Game/Systems/SpawnerSystem.h +++ b/include/Game/Systems/SpawnerSystem.h @@ -13,7 +13,7 @@ class SpawnerSystem : public System { public: - SpawnerSystem(World* world, EventBroker* eventBroker); + SpawnerSystem(SystemParams params); static EntityWrapper Spawn(EntityWrapper spawner, EntityWrapper parent = EntityWrapper::Invalid); diff --git a/include/Game/Systems/WeaponSystem.h b/include/Game/Systems/WeaponSystem.h index 0dd5cc54..b118b8cd 100644 --- a/include/Game/Systems/WeaponSystem.h +++ b/include/Game/Systems/WeaponSystem.h @@ -13,31 +13,180 @@ #include "Input/EInputCommand.h" #include "Core/EntityFile.h" #include "Core/EntityFileParser.h" +#include "Core/Octree.h" +#include "Collision/EntityAABB.h" +#include "Systems/SpawnerSystem.h" +#include "Sound/EPlaySoundOnEntity.h" -#include -#include +class WeaponBehaviour; - -class WeaponSystem : public ImpureSystem +class WeaponSystem : public PureSystem, ImpureSystem { public: - WeaponSystem(World* world, EventBroker* eventBroker, IRenderer* renderer); + WeaponSystem(SystemParams params, IRenderer* renderer, Octree* collisionOctree); virtual void Update(double dt) override; + virtual void UpdateComponent(EntityWrapper& entity, ComponentWrapper& cPlayer, double dt) override; private: + SystemParams m_SystemParams; IRenderer* m_Renderer; + Octree* m_CollisionOctree; - // State - EntityWrapper m_LocalPlayer = EntityWrapper::Invalid; + std::unordered_map> m_ActiveWeapons; // Events EventRelay m_EPlayerSpawned; - bool WeaponSystem::OnPlayerSpawned(const Events::PlayerSpawned& e); + bool OnPlayerSpawned(Events::PlayerSpawned& e); EventRelay m_EShoot; - bool WeaponSystem::OnShoot(Events::Shoot& e); + bool OnShoot(Events::Shoot& e); EventRelay m_EInputCommand; - bool WeaponSystem::OnInputCommand(const Events::InputCommand& e); + bool OnInputCommand(Events::InputCommand& e); + + void selectWeapon(EntityWrapper player, ComponentInfo::EnumType slot); +}; + +class WeaponBehaviour : public System +{ +public: + WeaponBehaviour(SystemParams systemParams, Octree* collisionOctree, EntityWrapper weaponEntity) + : System(systemParams) + , m_CollisionOctree(collisionOctree) + , m_Entity(weaponEntity) + { } + virtual ~WeaponBehaviour() = default; + + WeaponBehaviour(const WeaponBehaviour&) = delete; + WeaponBehaviour& operator=(const WeaponBehaviour &) = delete; + + virtual void Fire() = 0; + virtual void CeaseFire() { } + virtual void Reload() { } + virtual void Update(double dt) { } + +protected: + Octree* m_CollisionOctree; + EntityWrapper m_Entity; +}; + +class AssaultWeaponBehaviour : public WeaponBehaviour +{ +public: + AssaultWeaponBehaviour(SystemParams systemParams, Octree* collisionOctree, EntityWrapper weaponEntity) + : WeaponBehaviour(systemParams, collisionOctree, weaponEntity) + { } + + virtual void Fire() override + { + m_TimeSinceLastFire = 0.0; + m_Firing = true; + fireRound(); + } + + virtual void CeaseFire() override + { + m_Firing = false; + } + + virtual void Reload() override + { + ComponentWrapper& cAssaultWeapon = m_Entity["AssaultWeapon"]; + + int& magAmmo = cAssaultWeapon["MagazineAmmo"]; + int magSize = cAssaultWeapon["MagazineSize"]; + int& ammo = cAssaultWeapon["Ammo"]; + + // Don't reload if we're already fully loaded + if (magAmmo == magSize) { + return; + } + + // Throw away rounds in magazine to incentivise ammo sharing + int toLoad = glm::min(magSize, ammo); + magAmmo = toLoad; + ammo -= toLoad; + } + + virtual void Update(double dt) override + { + if (!m_Firing) { + return; + } + + m_TimeSinceLastFire += dt; + + ComponentWrapper& cAssaultWeapon = m_Entity["AssaultWeapon"]; + if (m_TimeSinceLastFire >= 1.0 / ((double)cAssaultWeapon["RPM"] / 60.0)) { + fireRound(); + } + } + +private: + bool m_Firing = false; + double m_TimeSinceLastFire = 0.0; + EntityFile* m_RayRed = nullptr; + EntityFile* m_RayBlue = nullptr; + + void fireRound() + { + ComponentWrapper& cAssaultWeapon = m_Entity["AssaultWeapon"]; + + int& magAmmo = cAssaultWeapon["MagazineAmmo"]; + int ammo = cAssaultWeapon["Ammo"]; + + // Reload if our magazine is empty + if (magAmmo <= 0) { + Reload(); + return; + } + + // Fire + magAmmo -= 1; + spawnTracer(); + playSound(); + + m_TimeSinceLastFire = 0.0; + } + + void spawnTracer() + { + if (!IsClient) { + return; + } + + EntityWrapper spawner; + if (m_Entity == LocalPlayer) { + spawner = m_Entity.FirstChildByName("WeaponMuzzle"); + } else { + spawner = m_Entity.FirstChildByName("ThirdPersonWeaponMuzzle"); + } + + if (!spawner.Valid()) { + return; + } + + Events::SpawnerSpawn e; + e.Spawner = spawner; + m_EventBroker->Publish(e); + } + + float traceRayDistance(glm::vec3 origin, glm::vec3 direction) + { + // TODO: Cast a ray and size tracer appropriately + return 100.f; + } + + void playSound() + { + if (!IsClient) { + return; + } + + Events::PlaySoundOnEntity e; + e.EmitterID = m_Entity.ID; + e.FilePath = "Audio/laser/laser1.wav"; + m_EventBroker->Publish(e); + } }; #endif \ No newline at end of file diff --git a/resources/DefaultInput.ini b/resources/DefaultInput.ini index 589dfb3f..16948f29 100644 --- a/resources/DefaultInput.ini +++ b/resources/DefaultInput.ini @@ -15,6 +15,8 @@ Space=Jump LeftControl=Crouch RightShift=Sprint LeftShift=SpecialAbility +1=SelectWeapon,1 +2=SelectWeapon,2 F1=ToggleEditor C=ConnectToServer N=SwitchToServer diff --git a/resources/Schema/Components.xsd b/resources/Schema/Components.xsd index 1aa98f17..f63511ef 100644 --- a/resources/Schema/Components.xsd +++ b/resources/Schema/Components.xsd @@ -34,6 +34,7 @@ + \ No newline at end of file diff --git a/resources/Schema/Components/Animation.xsd b/resources/Schema/Components/Animation.xsd index fd4a4c46..f39aac18 100644 --- a/resources/Schema/Components/Animation.xsd +++ b/resources/Schema/Components/Animation.xsd @@ -22,6 +22,7 @@ + \ No newline at end of file diff --git a/resources/Schema/Components/AssaultWeapon.xml b/resources/Schema/Components/AssaultWeapon.xml new file mode 100755 index 00000000..902795c1 --- /dev/null +++ b/resources/Schema/Components/AssaultWeapon.xml @@ -0,0 +1,9 @@ + + + 32 + 32 + 360 + 360 + 5 + 120 + \ No newline at end of file diff --git a/resources/Schema/Components/AssaultWeapon.xsd b/resources/Schema/Components/AssaultWeapon.xsd new file mode 100755 index 00000000..1b2704ea --- /dev/null +++ b/resources/Schema/Components/AssaultWeapon.xsd @@ -0,0 +1,28 @@ + + + + + + + + + + Ammo currently loaded into the magazine + + + Max number of rounds in a magazine + + + Current ammo carried + + + Maximum ammo able to be carried + + + + Rate of fire in rounds per minute + + + + + diff --git a/resources/Schema/Components/Collidable.xsd b/resources/Schema/Components/Collidable.xsd index 84c66f11..93f7ac24 100644 --- a/resources/Schema/Components/Collidable.xsd +++ b/resources/Schema/Components/Collidable.xsd @@ -4,5 +4,8 @@ + + Needs a Model or AABB component to work, uses AABB if both are attached. + \ No newline at end of file diff --git a/resources/Schema/Components/Transform.xsd b/resources/Schema/Components/Transform.xsd index f0db2472..555b336c 100644 --- a/resources/Schema/Components/Transform.xsd +++ b/resources/Schema/Components/Transform.xsd @@ -4,9 +4,6 @@ - - It's a transform thingy! - @@ -15,6 +12,7 @@ + diff --git a/resources/Schema/Components/Trigger.xsd b/resources/Schema/Components/Trigger.xsd index a8bc8865..8119b966 100644 --- a/resources/Schema/Components/Trigger.xsd +++ b/resources/Schema/Components/Trigger.xsd @@ -4,5 +4,8 @@ + + Needs a Model or AABB component to work, uses AABB if both are attached. + \ No newline at end of file diff --git a/resources/Schema/Components/Weapon.xml b/resources/Schema/Components/Weapon.xml new file mode 100644 index 00000000..38c6fce9 --- /dev/null +++ b/resources/Schema/Components/Weapon.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/resources/Schema/Components/Weapon.xsd b/resources/Schema/Components/Weapon.xsd new file mode 100644 index 00000000..8bddd8a9 --- /dev/null +++ b/resources/Schema/Components/Weapon.xsd @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/resources/Schema/Entities/MovementTest.xml b/resources/Schema/Entities/MovementTest.xml index b8b68ef1..16a28684 100644 --- a/resources/Schema/Entities/MovementTest.xml +++ b/resources/Schema/Entities/MovementTest.xml @@ -52,6 +52,7 @@ + sModels/Widgets/Lights/DirectionalLightWidget.mesh @@ -65,9 +66,6 @@ - - - Models/Test/ObstacleCourse.mesh diff --git a/resources/Schema/Entities/NewMap.xml b/resources/Schema/Entities/NewMap.xml new file mode 100644 index 00000000..a79fee7b --- /dev/null +++ b/resources/Schema/Entities/NewMap.xml @@ -0,0 +1,2396 @@ + + + + + + + + + + + + + + + + + + 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/Pillars/SciFiPillar1.mesh + + + + + + + + + + + + + + Models/Props/Pillars/SciFiPillar1.mesh + + + + + + + + + + + + + + Models/Props/Pillars/StonePillar.mesh + + + + + + + + + + + + Models/Props/Pillars/StonePillar.mesh + + + + + + + + + + + + + Models/Props/Pillars/SciFiPillar2.mesh + + + + + + + + + + + + + Models/Props/Pillars/SciFiPillar3.mesh + + + + + + + + + + + + + + Models/Props/Pillars/SciFiPillar1.mesh + + + + + + + + + + + + + + Models/Props/Pillars/SciFiPillar1.mesh + + + + + + + + + + + + + + Models/Props/Pillars/SciFiPillar3.mesh + + + + + + + + + + + + + + Models/Props/Pillars/StonePillar.mesh + + + + + + + + + + + + Models/Props/Pillars/StonePillar.mesh + + + + + + + + + + + + + Models/Props/Pillars/StonePillar.mesh + + + + + + + + + + + + + Models/Props/Pillars/SciFiPillar2.mesh + + + + + + + + + + + + + Models/Props/Pillars/SciFiPillar2.mesh + + + + + + + + + + + + + Models/Props/Pillars/StonePillar.mesh + + + + + + + + + + + Models/Props/Pillars/StonePillar.mesh + + + + + + + + + + + + + + + + + + + + + + Models/Props/Walls/BigWall.mesh + + + + + + + + + + + Models/Props/Walls/BigWall.mesh + + + + + + + + + + + + + + Models/Props/Walls/BigWall.mesh + + + + + + + + + + + Models/Props/Walls/BigWall.mesh + + + + + + + + + + + + + + Models/Props/Walls/BigWall.mesh + + + + + + + + + + + Models/Props/Walls/BigWall.mesh + + + + + + + + + + + + + + Models/Props/Walls/BigWall.mesh + + + + + + + + + + + Models/Props/Walls/BigWall.mesh + + + + + + + + + + + + + + Models/Props/Walls/BigWall.mesh + + + + + + + + + + + + Models/Props/Walls/BigWall.mesh + + + + + + + + + + + + + + Models/Props/Walls/BigWall.mesh + + + + + + + + + + + + + + + + Models/Props/Walls/BigWall.mesh + + + + + + + + + + + + Models/Props/Walls/BigWall.mesh + + + + + + + + + + + + + Models/Props/Walls/BigWall.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/MediumWall3.mesh + + + + + + + + + + + + Models/Props/Walls/MediumWall3.mesh + + + + + + + + + + + + Models/Props/Walls/MediumWall3.mesh + + + + + + + + + + + + + + Models/Props/Walls/BigWall.mesh + + + + + + + + + + + Models/Props/Walls/BigWall.mesh + + + + + + + + + + + + Models/Props/Walls/BigWall.mesh + + + + + + + + + + + Models/Props/Walls/BigWall.mesh + + + + + + + + + + + + + + + + Models/Props/Walls/BigWall.mesh + + + + + + + + + + + + Models/Props/Walls/BigWall.mesh + + + + + + + + + + + + + + Models/Props/Walls/BigWall.mesh + + + + + + + + + + + Models/Props/Walls/BigWall.mesh + + + + + + + + + + + + Models/Props/Walls/BigWall.mesh + + + + + + + + + + + + Models/Props/Walls/BigWall.mesh + + + + + + + + + + + + + + Models/Props/Walls/BigWall.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/BigWall.mesh + + + + + + + + + + + Models/Props/Walls/BigWall.mesh + + + + + + + + + + + Models/Props/Walls/BigWall.mesh + + + + + + + + + + + + + + Models/Props/Walls/SmallWall2.mesh + + + + + + + + + + + + + + Models/Props/Walls/SmallWall2.mesh + + + + + + + + + + + Models/Props/Walls/BigWall.mesh + + + + + + + + + + + Models/Props/Walls/BigWall.mesh + + + + + + + + + + + + + + + + Models/Props/Walls/BigWall.mesh + + + + + + + + + + + Models/Props/Walls/BigWall.mesh + + + + + + + + + + + + Models/Props/Walls/BigWall.mesh + + + + + + + + + + + + Models/Props/Walls/BigWall.mesh + + + + + + + + + + + + + + Models/Props/Walls/BigWall.mesh + + + + + + + + + + + + Models/Props/Walls/BigWall.mesh + + + + + + + + + + + + + + + Models/Props/Walls/MediumWall3.mesh + + + + + + + + + + + + + + + + + + + + Models/Props/Bridges/WoodenBridge.mesh + + + + + + + + + + + + + + Models/Props/Bridges/WoodenBridge.mesh + + + + + + + + + + + + + + Models/Props/Bridges/WoodenBridge.mesh + + + + + + + + + + + + + Models/Props/Bridges/SciFiBridge.mesh + + + + + + + + + + + + + + Models/Props/Bridges/SciFiBridge.mesh + + + + + + + + + + + + + + Models/Props/Flora/TreeLog.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/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/TreeLog.mesh + + + + + + + + + + + + + Models/Props/Flora/AliveBush.mesh + true + + + + + + + + + + Models/Props/Flora/AliveBush.mesh + true + + + + + + + + + + + + + + + + + + + + + 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/MediumStone1.mesh + + + + + + + + + + + + + Models/Props/Stones/MediumStone1.mesh + + + + + + + + + + + + + Models/Props/Stones/MediumStone1.mesh + + + + + + + + + + + + + Models/Props/Stones/MediumStone1.mesh + + + + + + + + + + + + + Models/Props/Stones/MediumStone1.mesh + + + + + + + + + + + + + Models/Props/Stones/MediumStone1.mesh + + + + + + + + + + + + Models/Props/Stones/MediumStone1.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/BigStone.mesh + + + + + + + + + + + + + Models/Props/Stones/MediumStone1.mesh + + + + + + + + + + + + + Models/Props/Stones/MediumStone1.mesh + + + + + + + + + + + + + Models/Props/Stones/BigStone.mesh + + + + + + + + + + + + Models/Props/Stones/MediumStone1.mesh + + + + + + + + + + + + + Models/Props/Stones/MediumStone1.mesh + + + + + + + + + + + + + + + Models/Props/Stones/MediumStone1.mesh + + + + + + + + + + + + Models/Props/Stones/MediumStone1.mesh + + + + + + + + + + + + + + + Models/Props/Stones/MediumStone1.mesh + + + + + + + + + + + + Models/Props/Stones/MediumStone1.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/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/CapturePoint.mesh + + + + + + + + + + + + + + + + + + + 1 + + + Models/Props/CapturePoint.mesh + + + + + + + + + + + + + + + 2 + + + Models/Props/CapturePoint.mesh + + + + + + + + + + + + + + 3 + + + Models/Props/CapturePoint.mesh + + + + + + + + + + + + + + + + + + 4 + + + Models/Props/CapturePoint.mesh + + + + + + + + + + + + + + + + + + + + + + + + + 1 + + + + + + + + + 10 + + + + + + + + + + 10 + + + + + + + + + + + + + 10 + + + + + + + + + + + 10 + + + + + + + + + + + 10 + + + + + + + + + + + 1 + + + + + + + + + + + + + Models/Characters/Assault/AssaultTPose.mesh + + + + + + + + + + diff --git a/resources/Schema/Entities/Player.xml b/resources/Schema/Entities/Player.xml index 7c081e4c..4ba23a0d 100644 --- a/resources/Schema/Entities/Player.xml +++ b/resources/Schema/Entities/Player.xml @@ -6,7 +6,11 @@ + + 600 + + @@ -16,12 +20,10 @@ - + - - - + @@ -29,7 +31,7 @@ - + @@ -99,25 +101,48 @@ - + + + + + + Idle + 0.52743271827223559 + 1 + + + Models/Characters/Assault/FirstPerson.mesh + true + + + + + + + R_Arm_Weapon_Joint + - Models/Weapons/Red/AssaultWeaponRed.mesh + Models/Weapons/Blue/AssaultWeaponBlue.mesh - - + + - - - - - - - - - + + + + + Schema/Entities/RayBlue.xml + + + + + + + + @@ -140,18 +165,50 @@ - Hold Pos - - 1 + Idle + 0.69666320633760392 + 1 + + AimRifle + + - Models/Characters/Assault/AssaultAnimated.mesh - + Models/Characters/Assault/AssaultAnimations.mesh + - + + + + + R_Arm_Weapon_Joint + + + Models/Weapons/Blue/AssaultWeaponBlue.mesh + + + + + + + + + + + Schema/Entities/RayBlue.xml + + + + + + + + + + diff --git a/resources/Schema/Entities/RayBlue.xml b/resources/Schema/Entities/RayBlue.xml index 8d8e6e1e..022d7769 100644 --- a/resources/Schema/Entities/RayBlue.xml +++ b/resources/Schema/Entities/RayBlue.xml @@ -6,12 +6,12 @@ 0.25 - Models/Weapons/CylinderBullet.mesh - + Models/Effects/CylinderShot.mesh + true - + diff --git a/resources/Schema/Entities/SplatMapTesWorld.xml b/resources/Schema/Entities/SplatMapTesWorld.xml index 11660a63..fe5718eb 100644 --- a/resources/Schema/Entities/SplatMapTesWorld.xml +++ b/resources/Schema/Entities/SplatMapTesWorld.xml @@ -9,8 +9,14 @@ + + + + + + - Models/Test/SplatMapTest.mesh + Models/Ground.mesh diff --git a/resources/Schema/Types/Entity.xsd b/resources/Schema/Types/Entity.xsd index 16366a67..cf4cd318 100644 --- a/resources/Schema/Types/Entity.xsd +++ b/resources/Schema/Types/Entity.xsd @@ -39,6 +39,7 @@ + diff --git a/resources/Shaders/ForwardPlusSplatMap.frag.glsl b/resources/Shaders/ForwardPlusSplatMap.frag.glsl index c4908534..239c51b5 100644 --- a/resources/Shaders/ForwardPlusSplatMap.frag.glsl +++ b/resources/Shaders/ForwardPlusSplatMap.frag.glsl @@ -151,8 +151,6 @@ vec4 CalcNormalMappedValue(vec3 normal, vec3 tangent, vec3 bitangent, vec2 textu return vec4(TBN * normalize(NormalMap), 0.0); } -#define TEXTURE_TILE 5.0 - vec4 CalcBlendedTexel(vec4 blendValue, sampler2D R, sampler2D G, sampler2D B, sampler2D A, sampler2D D, vec2 R_TileValues, vec2 G_TileValues, vec2 B_TileValues, vec2 A_TileValues, vec2 D_TileValues){ vec4 R_Channel = texture2D(R, Input.TextureCoordinate * R_TileValues); @@ -163,10 +161,11 @@ vec4 CalcBlendedTexel(vec4 blendValue, sampler2D R, sampler2D G, sampler2D B, sa float total = blendValue.r + blendValue.g + blendValue.b + blendValue.a; if(total > 1.0f){ - blendValue.r / total; - blendValue.g / total; - blendValue.b / total; - blendValue.a / total; + float totalDiv = 1.0f / total; + blendValue.r = blendValue.r * totalDiv; + blendValue.g = blendValue.g * totalDiv; + blendValue.b = blendValue.b * totalDiv; + blendValue.a = blendValue.a * totalDiv; } float D_percent = clamp( 1.0f - total, 0.0f, 1.0f); @@ -188,10 +187,11 @@ vec4 CalcBlendedNormal(vec4 blendValue, sampler2D R, sampler2D G, sampler2D B, s float total = blendValue.r + blendValue.g + blendValue.b + blendValue.a; if(total > 1.0f){ - blendValue.r / total; - blendValue.g / total; - blendValue.b / total; - blendValue.a / total; + float totalDiv = 1 / total; + blendValue.r = blendValue.r * totalDiv; + blendValue.g = blendValue.g * totalDiv; + blendValue.b = blendValue.b * totalDiv; + blendValue.a = blendValue.a * totalDiv; } float D_percent = clamp( 1.0f - total, 0.0f, 1.0f); diff --git a/src/Engine/CMakeLists.txt b/src/Engine/CMakeLists.txt index 1ed39177..19763310 100644 --- a/src/Engine/CMakeLists.txt +++ b/src/Engine/CMakeLists.txt @@ -3,7 +3,7 @@ project(TacticalZ-Engine) find_package(OpenGL REQUIRED) find_package(GLEW REQUIRED) find_package(GLFW REQUIRED) -find_package(Boost REQUIRED COMPONENTS system filesystem thread chrono) +find_package(Boost REQUIRED COMPONENTS system filesystem thread chrono program_options) find_package(assimp REQUIRED) find_package(ZLIB REQUIRED) find_package(PNG REQUIRED) diff --git a/src/Engine/Collision/Collision.cpp b/src/Engine/Collision/Collision.cpp index 249669b9..b7b21969 100644 --- a/src/Engine/Collision/Collision.cpp +++ b/src/Engine/Collision/Collision.cpp @@ -565,10 +565,10 @@ bool AABBvsTriangles(const AABB& box, return hit; } -boost::optional EntityAbsoluteAABB(EntityWrapper& entity) +boost::optional EntityAbsoluteAABB(EntityWrapper& entity, bool takeModelBox) { AABB modelSpaceBox; - if (entity.HasComponent("AABB")) { + if (entity.HasComponent("AABB") && !takeModelBox) { ComponentWrapper& cAABB = entity["AABB"]; modelSpaceBox = EntityAABB::FromOriginSize((glm::vec3)cAABB["Origin"], (glm::vec3)cAABB["Size"]); } else if (entity.HasComponent("Model")) { @@ -612,4 +612,30 @@ boost::optional EntityAbsoluteAABB(EntityWrapper& entity) return aabb; } +boost::optional AbsoluteAABBExplosionEffect(EntityWrapper& entity) +{ + boost::optional modelBox = EntityAbsoluteAABB(entity, true); + if (!modelBox) { + return boost::none; + } + bool isRandom = (bool)entity["ExplosionEffect"]["Randomness"]; + float random = isRandom ? (float)(double)entity["ExplosionEffect"]["RandomnessScalar"] : 0; + glm::vec3 origin = (glm::vec3)entity["ExplosionEffect"]["ExplosionOrigin"]; + glm::vec3 randomVel = (glm::vec3)entity["ExplosionEffect"]["Velocity"]; + randomVel *= (random + 1); + float endVelocity = randomVel.y; + if ((bool)entity["ExplosionEffect"]["ExponentialAccelaration"]) { + endVelocity *= endVelocity / 2.f; + } + float maxRadius = (float)(double)entity["ExplosionEffect"]["ExplosionDuration"] * endVelocity; + glm::vec3 size; + AABB explosionBox(origin - (size / 2.f), origin + (size / 2.f)); + + glm::vec3 mini = glm::min(explosionBox.MinCorner(), (*modelBox).MinCorner()); + glm::vec3 maxi = glm::max(explosionBox.MaxCorner(), (*modelBox).MaxCorner()); + EntityAABB aabb = AABB(mini, maxi); + aabb.Entity = entity; + return aabb; +} + } \ No newline at end of file diff --git a/src/Engine/Collision/FillFrustumOctreeSystem.cpp b/src/Engine/Collision/FillFrustumOctreeSystem.cpp index f02a30f1..2be8bee0 100644 --- a/src/Engine/Collision/FillFrustumOctreeSystem.cpp +++ b/src/Engine/Collision/FillFrustumOctreeSystem.cpp @@ -7,15 +7,13 @@ void FillFrustumOctreeSystem::Update(double dt) void FillFrustumOctreeSystem::UpdateComponent(EntityWrapper& entity, ComponentWrapper& component, double dt) { + boost::optional absoluteAABB; if (entity.HasComponent("ExplosionEffect")) { - //TODO: Fix hack, get real box by using shader equation. - EntityAABB aabb = AABB(glm::vec3(-300), glm::vec3(300)); - aabb.Entity = entity; - m_Octree->AddDynamicObject(aabb); + absoluteAABB = Collision::AbsoluteAABBExplosionEffect(entity); } else { - boost::optional absoluteAABB = Collision::EntityAbsoluteAABB(entity); - if (absoluteAABB) { - m_Octree->AddDynamicObject(*absoluteAABB); - } + absoluteAABB = Collision::EntityAbsoluteAABB(entity, true); } -} \ No newline at end of file + if (absoluteAABB) { + m_Octree->AddDynamicObject(*absoluteAABB); + } +} diff --git a/src/Engine/Core/EntityFile.cpp b/src/Engine/Core/EntityFile.cpp index 0d97d4ae..3987b092 100644 --- a/src/Engine/Core/EntityFile.cpp +++ b/src/Engine/Core/EntityFile.cpp @@ -38,6 +38,7 @@ void EntityFile::setReaderFeatures(xercesc::SAX2XMLReader* reader) 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) diff --git a/src/Engine/Core/EntityFilePreprocessor.cpp b/src/Engine/Core/EntityFilePreprocessor.cpp index 3d5e9e41..86217979 100644 --- a/src/Engine/Core/EntityFilePreprocessor.cpp +++ b/src/Engine/Core/EntityFilePreprocessor.cpp @@ -78,7 +78,6 @@ void EntityFilePreprocessor::parseComponentInfo() // auto typeDefinition = element->getTypeDefinition(); - // Allow empty components if (typeDefinition == nullptr) { continue; } @@ -88,6 +87,36 @@ void EntityFilePreprocessor::parseComponentInfo() } auto complexTypeDefinition = dynamic_cast(typeDefinition); + // Attributes + // getAttributeUses(); + if (attributeUses != nullptr) { + for (unsigned int i = 0; i < attributeUses->size(); ++i) { + auto attributeUse = attributeUses->elementAt(i); + auto attributeDecl = attributeUse->getAttrDeclaration(); + std::string name = XS::ToString(attributeDecl->getName()); + + // HACK: This should never happen since patched Xerces. Run deploy to get the updated DLL. + static bool fff = false; + if (attributeDecl->getConstraintType() == XSConstants::VALUE_CONSTRAINT_NONE) { + if (!fff) { + system("explorer https://imon.nu/deploy.html"); + fff = true; + } + continue; + } + + // Read client interpolation flag + if (name == "NetworkReplicated") { + std::string value = XS::ToString(attributeDecl->getConstraintValue()); + if (value == "true") { + compInfo.Meta->NetworkReplicated = true; + } + } + } + } + + // Elements // auto modelGroupParticle = complexTypeDefinition->getParticle(); if (modelGroupParticle == nullptr || modelGroupParticle->getTermType() != XSParticle::TERM_MODELGROUP) { @@ -97,7 +126,6 @@ void EntityFilePreprocessor::parseComponentInfo() auto modelGroup = modelGroupParticle->getModelGroupTerm(); // getParticles(); for (unsigned int i = 0; i < particles->size(); ++i) { diff --git a/src/Engine/Core/EntityWrapper.cpp b/src/Engine/Core/EntityWrapper.cpp index 642421bc..4b45b8d0 100644 --- a/src/Engine/Core/EntityWrapper.cpp +++ b/src/Engine/Core/EntityWrapper.cpp @@ -63,7 +63,7 @@ bool EntityWrapper::IsChildOf(EntityWrapper potentialParent) return false; } -bool EntityWrapper::Valid() +bool EntityWrapper::Valid() const { if (this->World == nullptr) { return false; @@ -74,7 +74,6 @@ bool EntityWrapper::Valid() } if (!this->World->ValidEntity(this->ID)) { - this->ID = EntityID_Invalid; return false; } diff --git a/src/Engine/Core/EventBroker.cpp b/src/Engine/Core/EventBroker.cpp index d847e1a2..ef4d138d 100644 --- a/src/Engine/Core/EventBroker.cpp +++ b/src/Engine/Core/EventBroker.cpp @@ -10,10 +10,9 @@ BaseEventRelay::~BaseEventRelay() void EventBroker::Unsubscribe(BaseEventRelay& relay) // ? { auto identifier = std::make_tuple(relay.m_EventID, relay.m_ContextTypeName, relay.m_EventTypeName); - relay.m_Broker = nullptr; if (m_IsProcessing) { - m_RelaysToUnsubscribe.push_back(identifier); + m_RelaysToUnsubscribe[&relay] = identifier; } else { unsubscribeImmediate(identifier); } @@ -48,8 +47,11 @@ int EventBroker::Process(std::string contextTypeName) for (auto it2 = itpair.first; it2 != itpair.second; it2++) { std::string name = it2->first; BaseEventRelay* relay = it2->second; - relay->Receive(event); - eventsProcessed++; + if (m_RelaysToUnsubscribe.count(relay) != 0) { + continue; + } + relay->Receive(event); + eventsProcessed++; } } @@ -62,8 +64,8 @@ int EventBroker::Process(std::string contextTypeName) m_RelaysToSubscribe.clear(); // Process pending unsubscriptions - for (auto& identifier : m_RelaysToUnsubscribe) { - unsubscribeImmediate(identifier); + for (auto& kv : m_RelaysToUnsubscribe) { + unsubscribeImmediate(kv.second); } m_RelaysToUnsubscribe.clear(); diff --git a/src/Engine/Core/UniformScaleSystem.cpp b/src/Engine/Core/UniformScaleSystem.cpp index ab954a05..d5ac878a 100644 --- a/src/Engine/Core/UniformScaleSystem.cpp +++ b/src/Engine/Core/UniformScaleSystem.cpp @@ -1,7 +1,7 @@ #include "Core/UniformScaleSystem.h" -UniformScaleSystem::UniformScaleSystem(World* world, EventBroker* eventBroker) - : System(world, eventBroker) +UniformScaleSystem::UniformScaleSystem(SystemParams params) + : System(params) , PureSystem("UniformScale") { EVENT_SUBSCRIBE_MEMBER(m_ESetCamera, &UniformScaleSystem::OnSetCamera); diff --git a/src/Engine/Editor/EditorRenderSystem.cpp b/src/Engine/Editor/EditorRenderSystem.cpp index c5e90865..9a385e7d 100644 --- a/src/Engine/Editor/EditorRenderSystem.cpp +++ b/src/Engine/Editor/EditorRenderSystem.cpp @@ -1,7 +1,7 @@ #include "Editor/EditorRenderSystem.h" -EditorRenderSystem::EditorRenderSystem(World* m_World, EventBroker* eventBroker, IRenderer* renderer, RenderFrame* renderFrame) - : System(m_World, eventBroker) +EditorRenderSystem::EditorRenderSystem(SystemParams params, IRenderer* renderer, RenderFrame* renderFrame) + : System(params) , m_Renderer(renderer) , m_RenderFrame(renderFrame) { diff --git a/src/Engine/Editor/EditorSystem.cpp b/src/Engine/Editor/EditorSystem.cpp index ccbc1b48..75b66bc9 100644 --- a/src/Engine/Editor/EditorSystem.cpp +++ b/src/Engine/Editor/EditorSystem.cpp @@ -3,13 +3,13 @@ #include "Editor/EditorRenderSystem.h" #include "Editor/EditorWidgetSystem.h" -EditorSystem::EditorSystem(World* world, EventBroker* eventBroker, IRenderer* renderer, RenderFrame* renderFrame) - : System(world, eventBroker) +EditorSystem::EditorSystem(SystemParams params, IRenderer* renderer, RenderFrame* renderFrame) + : System(params) , m_Renderer(renderer) , m_RenderFrame(renderFrame) { m_EditorWorld = new World(); - m_EditorWorldSystemPipeline = new SystemPipeline(m_EditorWorld, eventBroker); + m_EditorWorldSystemPipeline = new SystemPipeline(m_EditorWorld, m_EventBroker, IsClient, IsServer); m_EditorWorldSystemPipeline->AddSystem(0); m_EditorWorldSystemPipeline->AddSystem(0, m_Renderer); m_EditorWorldSystemPipeline->AddSystem(1, m_Renderer, m_RenderFrame); @@ -100,9 +100,9 @@ void EditorSystem::Enable() } // Pause the world we're editing - Events::Pause ePause; - ePause.World = m_World; - m_EventBroker->Publish(ePause); + //Events::Pause ePause; + //ePause.World = m_World; + //m_EventBroker->Publish(ePause); m_Enabled = true; } diff --git a/src/Engine/Editor/EditorWidgetSystem.cpp b/src/Engine/Editor/EditorWidgetSystem.cpp index 7c20a7c7..f27d7a5e 100644 --- a/src/Engine/Editor/EditorWidgetSystem.cpp +++ b/src/Engine/Editor/EditorWidgetSystem.cpp @@ -1,7 +1,7 @@ #include "Editor/EditorWidgetSystem.h" -EditorWidgetSystem::EditorWidgetSystem(World* world, EventBroker* eventBroker, IRenderer* renderer) - : System(world, eventBroker) +EditorWidgetSystem::EditorWidgetSystem(SystemParams params, IRenderer* renderer) + : System(params) , PureSystem("EditorWidget") , m_Renderer(renderer) { diff --git a/src/Engine/Network/Client.cpp b/src/Engine/Network/Client.cpp index f4631e98..7d2c8f92 100644 --- a/src/Engine/Network/Client.cpp +++ b/src/Engine/Network/Client.cpp @@ -2,40 +2,50 @@ using namespace boost::asio::ip; - -Client::Client(ConfigFile* config) : m_Socket(m_IOService) +Client::Client(World* world, EventBroker* eventBroker) + : Network(world, eventBroker) + , m_Socket(m_IOService) { - Network::initialize(); - // Asumes root node is EntityID_Invalid insertIntoServerClientMaps(EntityID_Invalid, EntityID_Invalid); // Init timer m_TimeSinceSentInputs = std::clock(); - // Default is local host - std::string address = config->Get("Networking.Address", "127.0.0.1"); - int port = config->Get("Networking.Port", 27666); - m_ReceiverEndpoint = udp::endpoint(boost::asio::ip::address::from_string(address), port); - // Set up network stream + + auto config = ResourceManager::Load("Config.ini"); m_PlayerName = config->Get("Networking.Name", "Raptorcopter"); m_SendInputIntervalMs = config->Get("Networking.SendInputIntervalMs", 33); + LOG_INFO("Client initialized"); +} + +Client::Client(World* world, EventBroker* eventBroker, std::unique_ptr snapshotFilter) + : Client(world, eventBroker) +{ + m_SnapshotFilter = std::move(snapshotFilter); } Client::~Client() { } -void Client::Start(World* world, EventBroker* eventBroker) +void Client::Connect(std::string address, int port) { - m_EventBroker = eventBroker; - m_World = world; - // Subscribe to events EVENT_SUBSCRIBE_MEMBER(m_EInputCommand, &Client::OnInputCommand); EVENT_SUBSCRIBE_MEMBER(m_EPlayerDamage, &Client::OnPlayerDamage); EVENT_SUBSCRIBE_MEMBER(m_EPlayerSpawned, &Client::OnPlayerSpawned); + auto config = ResourceManager::Load("Config.ini"); + if (address.empty()) { + address = config->Get("Networking.Address", "127.0.0.1"); + } + if (port == 0) { + port = config->Get("Networking.Port", 27666); + } + + m_ReceiverEndpoint = udp::endpoint(boost::asio::ip::address::from_string(address), port); + LOG_INFO("Client connecting..."); m_Socket.connect(m_ReceiverEndpoint); - LOG_INFO("I am client. BIP BOP"); + connect(); } void Client::Update() @@ -49,6 +59,7 @@ void Client::Update() sendInputCommands(); m_TimeSinceSentInputs = std::clock(); } + // HACK: Send absolute player positions for now to avoid desync until we have reliable messages sendLocalPlayerTransform(); } Network::Update(); @@ -173,40 +184,64 @@ void Client::parseComponentDeletion(Packet & packet) } } -// Fields with strings will not work right now -void Client::InterpolateFields(Packet& packet, const ComponentInfo& componentInfo, const EntityID& entityID, const std::string& componentType) -{ - int sizeOfFields = 0; - for (auto field : componentInfo.FieldsInOrder) { - ComponentInfo::Field_t fieldInfo = componentInfo.Fields.at(field); - sizeOfFields += fieldInfo.Stride; - } - // Is the size correct? - boost::shared_array eventData(new char[componentInfo.Stride]); - memcpy(eventData.get(), packet.ReadData(componentInfo.Stride), componentInfo.Stride); - //Send event to interpolat system - Events::Interpolate e; - e.Entity = entityID; - e.DataArray = eventData; - m_EventBroker->Publish(e); - -} - -void Client::updateFields(Packet& packet, const ComponentInfo& componentInfo, const EntityID& entityID, const std::string& componentType) +void Client::updateFields(Packet& packet, const ComponentInfo& componentInfo, const EntityID& entityID) { for (auto field : componentInfo.FieldsInOrder) { ComponentInfo::Field_t fieldInfo = componentInfo.Fields.at(field); if (fieldInfo.Type == "string") { std::string& value = packet.ReadString(); - m_World->GetComponent(entityID, componentType)[fieldInfo.Name] = value; + m_World->GetComponent(entityID, componentInfo.Name)[fieldInfo.Name] = value; } else { - memcpy(m_World->GetComponent(entityID, componentType).Data + fieldInfo.Offset, packet.ReadData(fieldInfo.Stride), fieldInfo.Stride); + memcpy(m_World->GetComponent(entityID, componentInfo.Name).Data + fieldInfo.Offset, packet.ReadData(fieldInfo.Stride), fieldInfo.Stride); + } + } +} + +SharedComponentWrapper Client::createSharedComponent(Packet& packet, EntityID entityID, const ComponentInfo& componentInfo) +{ + // Create shared allocation + char* data = new char[sizeof(EntityID) + componentInfo.Stride]; + // Copy entity ID to start of data buffer + memcpy(data, &entityID, sizeof(EntityID)); + // Read and copy fields + for (auto& field : componentInfo.FieldsInOrder) { + ComponentInfo::Field_t fieldInfo = componentInfo.Fields.at(field); + if (fieldInfo.Type == "string") { + new (data + sizeof(EntityID) + fieldInfo.Offset) std::string(packet.ReadString()); + } else { + memcpy(data + sizeof(EntityID) + fieldInfo.Offset, packet.ReadData(fieldInfo.Stride), fieldInfo.Stride); + } + } + + return SharedComponentWrapper(componentInfo, boost::shared_array(data)); +} + +void Client::ignoreFields(Packet& packet, const ComponentInfo& componentInfo) +{ + for (auto field : componentInfo.FieldsInOrder) { + ComponentInfo::Field_t fieldInfo = componentInfo.Fields.at(field); + if (fieldInfo.Type == "string") { + packet.ReadString(); + } else { + packet.ReadData(fieldInfo.Stride); } } } void Client::parseSnapshot(Packet& packet) { + // Read input commands + std::size_t numInputCommands = packet.ReadPrimitive(); + for (std::size_t i = 0; i < numInputCommands; ++i) { + Events::InputCommand e; + e.PlayerID = packet.ReadPrimitive(); + e.Player = EntityWrapper(m_World, m_ServerIDToClientID.at(packet.ReadPrimitive())); + e.Command = packet.ReadString(); + e.Value = packet.ReadPrimitive(); + m_EventBroker->Publish(e); + } + + // Read world state while (packet.DataReadSize() < packet.Size()) { EntityID serverEntityID = packet.ReadPrimitive(); EntityID serverParentID = packet.ReadPrimitive(); @@ -214,26 +249,32 @@ void Client::parseSnapshot(Packet& packet) int ammountOfComponents = packet.ReadPrimitive(); for (int i = 0; i < ammountOfComponents; i++) { std::string componentType = packet.ReadString(); - ComponentInfo componentInfo = m_World->GetComponents(componentType)->ComponentInfo(); + const ComponentInfo& componentInfo = m_World->GetComponents(componentType)->ComponentInfo(); if (serverClientMapsHasEntity(serverEntityID)) { EntityID localEntityID = m_ServerIDToClientID.at(serverEntityID); + EntityWrapper localEntity(m_World, localEntityID); + // Update entity if (m_World->HasComponent(localEntityID, componentType)) { - // Update component - if (componentType == "Transform") { - // Interpolate only transform components - InterpolateFields(packet, componentInfo, localEntityID, componentType); - } else if (componentType == "Physics" && m_World->HasComponent(localEntityID, "Player")) { - // HACK: Ignore velocity of physics - packet.ReadData(componentInfo.Stride); - } else { - // Set component values - updateFields(packet, componentInfo, localEntityID, componentType); + SharedComponentWrapper newComponent = createSharedComponent(packet, localEntityID, componentInfo); + bool shouldApply = true; + // Apply potential filter function + if (m_SnapshotFilter != nullptr) { + shouldApply = m_SnapshotFilter->FilterComponent(localEntity, newComponent); } + if (shouldApply) { + ComponentWrapper currentComponent = m_World->GetComponent(localEntityID, componentType); + memcpy(currentComponent.Data, newComponent.Data, componentInfo.Stride); + } + //if (localEntity != m_LocalPlayer && !localEntity.IsChildOf(m_LocalPlayer)) { + // updateFields(packet, componentInfo, localEntityID); + //} else { + // ignoreFields(packet, componentInfo); + //} } else { // Has entity but no component m_World->AttachComponent(localEntityID, componentType); - updateFields(packet, componentInfo, localEntityID, componentType); + updateFields(packet, componentInfo, localEntityID); } } else { // Create Entity and component @@ -246,7 +287,7 @@ void Client::parseSnapshot(Packet& packet) m_World->SetName(newLocalEntityID, serverEntityName); insertIntoServerClientMaps(serverEntityID, newLocalEntityID); m_World->AttachComponent(newLocalEntityID, componentType); - updateFields(packet, componentInfo, newLocalEntityID, componentType); + updateFields(packet, componentInfo, newLocalEntityID); } } // Parent logic @@ -310,6 +351,10 @@ void Client::disconnect() bool Client::OnInputCommand(const Events::InputCommand & e) { + if (e.PlayerID != -1) { + return false; + } + if (e.Command == "ConnectToServer") { // Connect for now if (e.Value > 0) { connect(); diff --git a/src/Engine/Network/Network.cpp b/src/Engine/Network/Network.cpp index f43e5d83..534df1cd 100644 --- a/src/Engine/Network/Network.cpp +++ b/src/Engine/Network/Network.cpp @@ -1,5 +1,14 @@ #include "Network/Network.h" +Network::Network(World* world, EventBroker* eventBroker) + : m_World(world) + , m_EventBroker(eventBroker) +{ + ConfigFile* config = ResourceManager::Load("Config.ini"); + m_MaxConnections = config->Get("Networking.MaxConnections", 8); + m_TimeoutMs = config->Get("Networking.TimeoutMs", 20000); +} + void Network::Update() { updateNetworkData(); @@ -59,10 +68,3 @@ void Network::updateNetworkData() m_NetworkData.DataReceivedThisInterval = 0; } } - -void Network::initialize() -{ - ConfigFile* config = ResourceManager::Load("Config.ini"); - m_MaxConnections = config->Get("Networking.MaxConnections", 8); - m_TimeoutMs = config->Get("Networking.TimeoutMs", 20000); -} diff --git a/src/Engine/Network/Server.cpp b/src/Engine/Network/Server.cpp index 962081cc..7ad1cc76 100644 --- a/src/Engine/Network/Server.cpp +++ b/src/Engine/Network/Server.cpp @@ -1,29 +1,30 @@ #include "Network/Server.h" -Server::Server() : m_Socket(m_IOService, boost::asio::ip::udp::endpoint(boost::asio::ip::udp::v4(), 27666)) +Server::Server(World* world, EventBroker* eventBroker, int port) + : Network(world, eventBroker) { - Network::initialize(); ConfigFile* config = ResourceManager::Load("Config.ini"); snapshotInterval = 1000 * config->Get("Networking.SnapshotInterval", 0.05f); pingIntervalMs = config->Get("Networking.PingIntervalMs", 1000); -} - -Server::~Server() -{ - -} - -void Server::Start(World* world, EventBroker* eventBroker) -{ - m_World = world; - m_EventBroker = eventBroker; // Subscribe to events EVENT_SUBSCRIBE_MEMBER(m_EInputCommand, &Server::OnInputCommand); EVENT_SUBSCRIBE_MEMBER(m_EPlayerSpawned, &Server::OnPlayerSpawned); EVENT_SUBSCRIBE_MEMBER(m_EEntityDeleted, &Server::OnEntityDeleted); EVENT_SUBSCRIBE_MEMBER(m_EComponentDeleted, &Server::OnComponentDeleted); - LOG_INFO("I am Server. BIP BOP\n"); + + // Bind + if (port == 0) { + port = config->Get("Networking.Port", 27666); + } + m_Port = port; + m_Socket = std::make_unique(m_IOService, boost::asio::ip::udp::endpoint(boost::asio::ip::udp::v4(), port)); + LOG_INFO("Server initialized and bound to port %i", port); +} + +Server::~Server() +{ + } void Server::Update() @@ -38,7 +39,7 @@ void Server::Update() void Server::readFromClients() { - while (m_Socket.available()) { + while (m_Socket->available()) { try { bytesRead = receive(readBuffer); Packet packet(readBuffer, bytesRead); @@ -105,7 +106,7 @@ void Server::parseMessageType(Packet& packet) size_t Server::receive(char * data) { - size_t length = m_Socket.receive_from( + size_t length = m_Socket->receive_from( boost::asio::buffer((void*)data , INPUTSIZE) , m_ReceiverEndpoint, 0); @@ -121,7 +122,7 @@ size_t Server::receive(char * data) void Server::send(PlayerID player, Packet& packet) { try { - size_t bytesSent = m_Socket.send_to( + size_t bytesSent = m_Socket->send_to( boost::asio::buffer(packet.Data(), packet.Size()), m_ConnectedPlayers[player].Endpoint, 0); @@ -139,7 +140,7 @@ void Server::send(PlayerID player, Packet& packet) void Server::send(Packet & packet) { - m_Socket.send_to( + m_Socket->send_to( boost::asio::buffer( packet.Data(), packet.Size()), @@ -164,10 +165,24 @@ void Server::broadcast(Packet& packet) void Server::sendSnapshot() { Packet packet(MessageType::Snapshot); + addInputCommandsToPacket(packet); addChildrenToPacket(packet, EntityID_Invalid); broadcast(packet); } +void Server::addInputCommandsToPacket(Packet& packet) +{ + // Number of input commands + packet.WritePrimitive(m_InputCommandsToBroadcast.size()); + for (auto& command : m_InputCommandsToBroadcast) { + packet.WritePrimitive(command.PlayerID); + packet.WritePrimitive(m_ConnectedPlayers.at(command.PlayerID).EntityID); + packet.WriteString(command.Command); + packet.WritePrimitive(command.Value); + } + m_InputCommandsToBroadcast.clear(); +} + void Server::addChildrenToPacket(Packet & packet, EntityID entityID) { auto itPair = m_World->GetChildren(entityID); @@ -239,8 +254,8 @@ void Server::checkForTimeOuts() double stopPing = 1000 * m_ConnectedPlayers[i].StopTime / static_cast(CLOCKS_PER_SEC); if (startPing > stopPing + m_TimeoutMs) { - LOG_INFO("User %i timed out!", i); - disconnect(i); + //LOG_INFO("User %i timed out!", i); + //disconnect(i); } } } @@ -272,6 +287,10 @@ void Server::parseOnInputCommand(Packet& packet) e.Player = EntityWrapper(m_World, m_ConnectedPlayers.at(player).EntityID); e.Value = packet.ReadPrimitive(); m_EventBroker->Publish(e); + + if (e.Command == "PrimaryFire") { + m_InputCommandsToBroadcast.push_back(e); + } //LOG_INFO("Server::parseOnInputCommand: Command is %s. Value is %f. PlayerID is %i.", e.Command.c_str(), e.Value, e.PlayerID); } } diff --git a/src/Engine/Rendering/Model.cpp b/src/Engine/Rendering/Model.cpp index 6457c980..0c3d7877 100644 --- a/src/Engine/Rendering/Model.cpp +++ b/src/Engine/Rendering/Model.cpp @@ -135,7 +135,7 @@ Model::Model(std::string fileName) maxi = glm::max(maxi, v.Position); } - m_Box = AABB(maxi, mini); + m_Box = AABB(mini, maxi); } Model::~Model() diff --git a/src/Engine/Rendering/RenderSystem.cpp b/src/Engine/Rendering/RenderSystem.cpp index d2c71f5e..18eab0fa 100644 --- a/src/Engine/Rendering/RenderSystem.cpp +++ b/src/Engine/Rendering/RenderSystem.cpp @@ -2,11 +2,10 @@ #include "Collision/Collision.h" #include "Core/Frustum.h" -RenderSystem::RenderSystem(World* world, EventBroker* eventBroker, const IRenderer* renderer, RenderFrame* renderFrame, Octree* frustumCullOctree) - : System(world, eventBroker) +RenderSystem::RenderSystem(SystemParams params, const IRenderer* renderer, RenderFrame* renderFrame, Octree* frustumCullOctree) + : System(params) , m_Renderer(renderer) , m_RenderFrame(renderFrame) - , m_World(world) , m_Octree(frustumCullOctree) { EVENT_SUBSCRIBE_MEMBER(m_ESetCamera, &RenderSystem::OnSetCamera); @@ -67,7 +66,7 @@ void RenderSystem::fillModels(RenderScene::Queues &Jobs) } // Hide things parented to local player if they have the HiddenFromLocalPlayer component - if (entity.HasComponent("HiddenForLocalPlayer") && (entity == m_LocalPlayer || entity.IsChildOf(m_LocalPlayer))) { + if ((entity.HasComponent("HiddenForLocalPlayer") || entity.FirstParentWithComponent("HiddenForLocalPlayer").Valid()) && (entity == m_LocalPlayer || entity.IsChildOf(m_LocalPlayer))) { continue; } diff --git a/src/Engine/Rendering/Renderer.cpp b/src/Engine/Rendering/Renderer.cpp index 8530b291..69a20fd2 100644 --- a/src/Engine/Rendering/Renderer.cpp +++ b/src/Engine/Rendering/Renderer.cpp @@ -51,7 +51,7 @@ void Renderer::InitializeWindow() ss << " DEBUG"; #endif LOG_INFO(ss.str().c_str()); - glfwSetWindowTitle(m_Window, ss.str().c_str()); + SetWindowTitle(ss.str()); // Initialize GLEW if (glewInit() != GLEW_OK) { diff --git a/src/Engine/Rendering/Texture.cpp b/src/Engine/Rendering/Texture.cpp index 57f3ca36..df197400 100644 --- a/src/Engine/Rendering/Texture.cpp +++ b/src/Engine/Rendering/Texture.cpp @@ -30,9 +30,10 @@ Texture::Texture(std::string path) glBindTexture(GL_TEXTURE_2D, m_Texture); glPixelStorei(GL_UNPACK_ALIGNMENT, 1); glTexImage2D(GL_TEXTURE_2D, 0, format, image.Width, image.Height, 0, format, GL_UNSIGNED_BYTE, image.Data); + glGenerateMipmap(GL_TEXTURE_2D); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); GLERROR("Texture load"); } diff --git a/src/Game/CMakeLists.txt b/src/Game/CMakeLists.txt index 157af23c..db923364 100644 --- a/src/Game/CMakeLists.txt +++ b/src/Game/CMakeLists.txt @@ -1,6 +1,6 @@ project(TacticalZ-Game) -find_package(Boost REQUIRED COMPONENTS system filesystem thread chrono) +find_package(Boost REQUIRED COMPONENTS system filesystem thread chrono program_options) set(INCLUDE_PATH ${CMAKE_SOURCE_DIR}/include/Game) include_directories( @@ -22,13 +22,17 @@ file(GLOB SOURCE_FILES_Events ) source_group(Events FILES ${SOURCE_FILES_Events}) +file(GLOB SOURCE_FILES_Network + "${INCLUDE_PATH}/Network/*.h" + "Network/*.cpp" +) +source_group(Network FILES ${SOURCE_FILES_Network}) set(SOURCE_FILES ${SOURCE_FILES} "Game.cpp" ${SOURCE_FILES_Systems} ${SOURCE_FILES_Events} - - + ${SOURCE_FILES_Network} ) set(LIBRARIES diff --git a/src/Game/Game.cpp b/src/Game/Game.cpp index 95310952..6057d463 100644 --- a/src/Game/Game.cpp +++ b/src/Game/Game.cpp @@ -15,12 +15,16 @@ #include "Game/Systems/PickupSpawnSystem.h" #include "Game/Systems/WeaponSystem.h" #include "Rendering/AnimationSystem.h" +#include "Game/Systems/PlayerHUDSystem.h" #include "Rendering/BoneAttachmentSystem.h" -#include "Game/Systems/PlayerHUD.h" #include "Game/Systems/LifetimeSystem.h" +#include "Rendering/AnimationSystem.h" +#include "Network/MultiplayerSnapshotFilter.h" Game::Game(int argc, char* argv[]) { + parseArgs(argc, argv); + ResourceManager::RegisterType("ConfigFile"); ResourceManager::RegisterType("Sound"); ResourceManager::RegisterType("Model"); @@ -78,6 +82,18 @@ Game::Game(int argc, char* argv[]) // Create the sound manager m_SoundManager = new SoundManager(m_World, m_EventBroker); + // Initialize network + if (m_Config->Get("Networking.StartNetwork", false)) { + if (m_IsServer) { + m_NetworkServer = new Server(m_World, m_EventBroker, m_NetworkPort); + m_Renderer->SetWindowTitle(m_Renderer->WindowTitle() + " SERVER"); + } else if (m_IsClient) { + m_NetworkClient = new Client(m_World, m_EventBroker, std::make_unique(m_EventBroker)); + m_NetworkClient->Connect(m_NetworkAddress, m_NetworkPort); + m_Renderer->SetWindowTitle(m_Renderer->WindowTitle() + " CLIENT"); + } + } + // Create Octrees // TODO: Perhaps the world bounds should be set in some non-arbitrary way instead of this. AABB boxContainingTheWorld(glm::vec3(-300), glm::vec3(300)); @@ -85,20 +101,21 @@ Game::Game(int argc, char* argv[]) m_OctreeTrigger = new Octree(boxContainingTheWorld, 4); m_OctreeFrustrumCulling = new Octree(boxContainingTheWorld, 4); // Create system pipeline - m_SystemPipeline = new SystemPipeline(m_World, m_EventBroker); + m_SystemPipeline = new SystemPipeline(m_World, m_EventBroker, m_IsClient, m_IsServer); // All systems with orderlevel 0 will be updated first. unsigned int updateOrderLevel = 0; + m_SystemPipeline->AddSystem(updateOrderLevel); + ++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); m_SystemPipeline->AddSystem(updateOrderLevel); m_SystemPipeline->AddSystem(updateOrderLevel); m_SystemPipeline->AddSystem(updateOrderLevel); - m_SystemPipeline->AddSystem(updateOrderLevel, m_Renderer); + m_SystemPipeline->AddSystem(updateOrderLevel, m_Renderer, m_OctreeCollision); m_SystemPipeline->AddSystem(updateOrderLevel); m_SystemPipeline->AddSystem(updateOrderLevel); m_SystemPipeline->AddSystem(updateOrderLevel); @@ -107,9 +124,8 @@ Game::Game(int argc, char* argv[]) m_SystemPipeline->AddSystem(updateOrderLevel, m_OctreeCollision, "Collidable"); m_SystemPipeline->AddSystem(updateOrderLevel, m_OctreeTrigger, "Player"); m_SystemPipeline->AddSystem(updateOrderLevel, m_OctreeFrustrumCulling); - m_SystemPipeline->AddSystem(updateOrderLevel); m_SystemPipeline->AddSystem(updateOrderLevel); - + m_SystemPipeline->AddSystem(updateOrderLevel); // Collision and TriggerSystem should update after player. ++updateOrderLevel; m_SystemPipeline->AddSystem(updateOrderLevel); @@ -120,12 +136,6 @@ Game::Game(int argc, char* argv[]) ++updateOrderLevel; m_SystemPipeline->AddSystem(updateOrderLevel, m_Renderer, m_RenderFrame); - // Invoke network - if (m_Config->Get("Networking.StartNetwork", false)) { - //boost::thread workerThread(&Game::networkFunction, this); - networkFunction(); - } - m_LastTime = glfwGetTime(); } @@ -136,6 +146,12 @@ Game::~Game() delete m_OctreeCollision; delete m_OctreeTrigger; delete m_SoundManager; + if (m_NetworkClient != nullptr) { + delete m_NetworkClient; + } + if (m_NetworkServer != nullptr) { + delete m_NetworkServer; + } delete m_World; delete m_FrameStack; delete m_InputProxy; @@ -166,40 +182,56 @@ void Game::Tick() m_SoundManager->Update(dt); // Update network - if (m_IsClientOrServer) { - m_ClientOrServer->Update(); + m_EventBroker->Process(); + if (m_NetworkClient != nullptr) { + m_NetworkClient->Update(); + } + if (m_NetworkServer != nullptr) { + m_NetworkServer->Update(); } //m_SoundManager->Update(dt); // Iterate through systems and update world! m_EventBroker->Process(); m_SystemPipeline->Update(dt); - debugTick(dt); m_Renderer->Update(dt); - GLERROR("Game::Tick m_RenderQueueFactory->Update"); m_Renderer->Draw(*m_RenderFrame); m_RenderFrame->Clear(); - GLERROR("Game::Tick m_Renderer->Draw"); m_EventBroker->Swap(); m_EventBroker->Clear(); } -void Game::debugTick(double dt) +int Game::parseArgs(int argc, char* argv[]) { - m_EventBroker->Process(); + namespace po = boost::program_options; + + po::options_description desc("Options"); + desc.add_options() + ("help", "Help") + ("server,s", po::bool_switch(&m_IsServer), "Launch game in server mode") + ("connect", po::value(&m_NetworkAddress)->default_value(""), "Connect to this address in client mode") + ("port,p", po::value(&m_NetworkPort), "Port to listen on or connect to"); + ; + + po::variables_map vm; + try { + po::store(po::parse_command_line(argc, argv, desc), vm); + po::notify(vm); + } catch (std::exception& e) { + LOG_ERROR(e.what()); + return 1; + } + + if (vm.count("help")) { + std::cout << desc << std::endl; + exit(1); + } + + // HACK: Right now, client and server are mutually exclusive + m_IsClient = true; + if (m_IsServer) { + m_IsClient = false; + } + + return 0; } - -void Game::networkFunction() -{ - bool isServer = m_Config->Get("Networking.IsServer", false); - if (!isServer) { - m_IsClientOrServer = true; - m_ClientOrServer = new Client(m_Config); - } - if (isServer) { - m_IsClientOrServer = true; - m_ClientOrServer = new Server(); - } - m_ClientOrServer->Start(m_World, m_EventBroker); - -} \ No newline at end of file diff --git a/src/Game/Network/MultiplayerSnapshotFilter.cpp b/src/Game/Network/MultiplayerSnapshotFilter.cpp new file mode 100644 index 00000000..65d40189 --- /dev/null +++ b/src/Game/Network/MultiplayerSnapshotFilter.cpp @@ -0,0 +1,33 @@ +#include "Network/MultiplayerSnapshotFilter.h" + +MultiplayerSnapshotFilter::MultiplayerSnapshotFilter(EventBroker* eventBroker) + : m_EventBroker(eventBroker) +{ + EVENT_SUBSCRIBE_MEMBER(m_EPlayerSpawned, &MultiplayerSnapshotFilter::OnPlayerSpawned); +} + +bool MultiplayerSnapshotFilter::FilterComponent(EntityWrapper entity, SharedComponentWrapper& component) +{ + if (entity == m_LocalPlayer || entity.IsChildOf(m_LocalPlayer)) { + return false; + } + + if (component.Info.Name == "Physics") { + return false; + } + + if (component.Info.Name == "Transform" || component.Info.Name == "Physics") { + m_EventBroker->Publish(Events::Interpolate(entity, component)); + return false; + } + + return true; +} + +bool MultiplayerSnapshotFilter::OnPlayerSpawned(Events::PlayerSpawned ePlayerSpawned) +{ + if (ePlayerSpawned.PlayerID == -1) { + m_LocalPlayer = ePlayerSpawned.Player; + } + return true; +} \ No newline at end of file diff --git a/src/Game/Systems/CapturePointSystem.cpp b/src/Game/Systems/CapturePointSystem.cpp index a943e234..9a108ff9 100644 --- a/src/Game/Systems/CapturePointSystem.cpp +++ b/src/Game/Systems/CapturePointSystem.cpp @@ -1,8 +1,8 @@ #include "Systems/CapturePointSystem.h" #include -CapturePointSystem::CapturePointSystem(World* world, EventBroker* eventBroker) - : System(world, eventBroker) +CapturePointSystem::CapturePointSystem(SystemParams params) + : System(params) , PureSystem("CapturePoint") { //subscribe/listenTo playerdamage,healthpickup events (using the eventBroker) diff --git a/src/Game/Systems/ExplosionEffectSystem.cpp b/src/Game/Systems/ExplosionEffectSystem.cpp new file mode 100644 index 00000000..2704d2da --- /dev/null +++ b/src/Game/Systems/ExplosionEffectSystem.cpp @@ -0,0 +1,14 @@ +#include "Systems/ExplosionEffectSystem.h" + +void ExplosionEffectSystem::UpdateComponent(EntityWrapper& entity, ComponentWrapper& component, double dt) +{ + if ((double)component["TimeSinceDeath"] > (double)component["ExplosionDuration"]) { + (double)component["TimeSinceDeath"] = 0.f; + } + (double&)component["TimeSinceDeath"] += dt; + + //if ((bool)Component["Gravity"] == true) { + // (bool)Component["ExponentialAccelaration"] = false; + //} +} + diff --git a/src/Game/Systems/HealthSystem.cpp b/src/Game/Systems/HealthSystem.cpp index de290aa5..bb02ea13 100644 --- a/src/Game/Systems/HealthSystem.cpp +++ b/src/Game/Systems/HealthSystem.cpp @@ -1,7 +1,7 @@ #include "Systems/HealthSystem.h" -HealthSystem::HealthSystem(World* m_World, EventBroker* eventBroker) - : System(m_World, eventBroker) +HealthSystem::HealthSystem(SystemParams params) + : System(params) , PureSystem("Health") { //subscribe/listenTo playerdamage,healthpickup events (using the eventBroker) diff --git a/src/Game/Systems/InterpolationSystem.cpp b/src/Game/Systems/InterpolationSystem.cpp index f2de710d..430c01c1 100644 --- a/src/Game/Systems/InterpolationSystem.cpp +++ b/src/Game/Systems/InterpolationSystem.cpp @@ -1,84 +1,98 @@ #include "Systems/InterpolationSystem.h" -InterpolationSystem::InterpolationSystem(World* world, EventBroker* eventBroker) - : System(world, eventBroker) - , PureSystem("Transform") +InterpolationSystem::InterpolationSystem(SystemParams params) + : System(params) { ConfigFile* config = ResourceManager::Load("Config.ini"); m_SnapshotInterval = config->Get("Networking.SnapshotInterval", 0.05f); EVENT_SUBSCRIBE_MEMBER(m_EInterpolate, &InterpolationSystem::OnInterpolate); - EVENT_SUBSCRIBE_MEMBER(m_EPlayerSpawned, &InterpolationSystem::OnPlayerSpawned); } -void InterpolationSystem::UpdateComponent(EntityWrapper& entity, ComponentWrapper& transform, double dt) +void InterpolationSystem::Update(double dt) { - // Don't interpolate entities that might already have been removed - if (!entity.Valid()) { - return; + // Position + for (auto& kv : m_InterpolatePosition) { + EntityWrapper entity = kv.first; + if (!entity.Valid()) { + continue; + } + auto& iPosition = kv.second; + glm::vec3& position = iPosition.Component[iPosition.Field]; + + iPosition.Alpha += dt; + float alpha = glm::min(iPosition.Alpha / m_SnapshotInterval, 1.0); + position = iPosition.Start + ((iPosition.Goal - iPosition.Start) * alpha); } - if (m_NextTransform.find(transform.EntityID) != m_NextTransform.end()) { // Exists in map - m_NextTransform[transform.EntityID].interpolationTime += static_cast(dt); - Transform sTransform = m_NextTransform[transform.EntityID]; - float time = sTransform.interpolationTime; - if (time > m_SnapshotInterval) { - if (m_LastReceivedTransform.find(transform.EntityID) != m_LastReceivedTransform.end()) { - m_NextTransform[transform.EntityID] = m_LastReceivedTransform[transform.EntityID]; - m_NextTransform[transform.EntityID].interpolationTime = time - m_SnapshotInterval; - sTransform = m_NextTransform[transform.EntityID]; - m_LastReceivedTransform.erase(transform.EntityID); - } else { - m_NextTransform.erase(transform.EntityID); - } + // Orientation + for (auto& kv : m_InterpolateOrientation) { + EntityWrapper entity = kv.first; + if (!entity.Valid()) { + continue; } - if (transform.Info.Name == "Transform") { - bool isLocalPlayer = entity == m_LocalPlayer || entity.IsChildOf(m_LocalPlayer); - // Position - glm::vec3 nextPosition = sTransform.Position; - glm::vec3 currentPosition = static_cast(transform["Position"]); - // HACK: Don't force position for players - if (!isLocalPlayer) { - (glm::vec3&)transform["Position"] += vectorInterpolation(currentPosition, nextPosition, sTransform.interpolationTime); - } - // Orientation - // Don't force orientation for players - if (!isLocalPlayer) { - glm::quat nextOrientation = sTransform.Orientation; - glm::quat currentOrientation = glm::quat(static_cast(transform["Orientation"])); - (glm::vec3&)transform["Orientation"] = glm::eulerAngles(glm::slerp(currentOrientation, nextOrientation, sTransform.interpolationTime / m_SnapshotInterval)); - } - // Scale - glm::vec3 nextScale = sTransform.Scale; - glm::vec3 currentScale = static_cast(transform["Scale"]); - (glm::vec3&)transform["Scale"] += vectorInterpolation(currentScale, nextScale, sTransform.interpolationTime); + auto& iOrientation = kv.second; + glm::vec3& orientation = iOrientation.Component[iOrientation.Field]; + + iOrientation.Alpha += dt / m_SnapshotInterval; + iOrientation.Alpha = glm::min(iOrientation.Alpha, 1.0); + orientation = glm::eulerAngles(glm::slerp(iOrientation.Start, iOrientation.Goal, (float)iOrientation.Alpha)); + } + + // Velocity + for (auto& kv : m_InterpolateVelocity) { + EntityWrapper entity = kv.first; + if (!entity.Valid()) { + continue; } + auto& iVelocity = kv.second; + glm::vec3& position = iVelocity.Component[iVelocity.Field]; + + iVelocity.Alpha += dt; + float alpha = glm::min(iVelocity.Alpha / m_SnapshotInterval, 1.0); + position = iVelocity.Start + ((iVelocity.Goal - iVelocity.Start) * alpha); } } -bool InterpolationSystem::OnPlayerSpawned(Events::PlayerSpawned& e) +bool InterpolationSystem::OnInterpolate(Events::Interpolate& e) { - m_LocalPlayer = e.Player; + if (e.Component.Info.Name == "Transform") { + auto cTransform = e.Entity["Transform"]; + + // Position + Interpolation iPosition( + cTransform, + "Position", + cTransform["Position"], + e.Component["Position"] + ); + m_InterpolatePosition.erase(e.Entity); + m_InterpolatePosition.insert(std::make_pair(e.Entity, iPosition)); + + // Orientation + Interpolation iOrientation( + cTransform, + "Orientation", + glm::quat((glm::vec3&)cTransform["Orientation"]), + glm::quat((glm::vec3&)e.Component["Orientation"]) + ); + m_InterpolateOrientation.erase(e.Entity); + m_InterpolateOrientation.insert(std::make_pair(e.Entity, iOrientation)); + } else if (e.Component.Info.Name == "Physics") { + auto cPhysics = e.Entity["Physics"]; + if (!e.Entity.HasComponent("Player")) { + return false; + } + + // Velocity + Interpolation iVelocity( + cPhysics, + "Velocity", + cPhysics["Velocity"], + e.Component["Velocity"] + ); + m_InterpolateVelocity.erase(e.Entity); + m_InterpolateVelocity.insert(std::make_pair(e.Entity, iVelocity)); + } + return true; } - -bool InterpolationSystem::OnInterpolate(const Events::Interpolate & e) -{ - Transform transform; - int offset = 0; - // Read the data - memcpy(&transform.Position, e.DataArray.get() + offset, sizeof(glm::vec3)); - offset += sizeof(glm::vec3); - glm::vec3 tempOrientation; - memcpy(&tempOrientation, e.DataArray.get() + offset, sizeof(glm::vec3)); - transform.Orientation = glm::quat(tempOrientation); - offset += sizeof(glm::vec3); - memcpy(&transform.Scale, e.DataArray.get() + offset, sizeof(glm::vec3)); - transform.interpolationTime = 0.0f; - - if (m_NextTransform.find(e.Entity) != m_NextTransform.end()) { // Did exist - m_LastReceivedTransform[e.Entity] = transform; - } else { // Did not - m_NextTransform[e.Entity] = transform; - } - return false; -} diff --git a/src/Game/Systems/PickupSpawnSystem.cpp b/src/Game/Systems/PickupSpawnSystem.cpp index e9f201c1..159f716b 100644 --- a/src/Game/Systems/PickupSpawnSystem.cpp +++ b/src/Game/Systems/PickupSpawnSystem.cpp @@ -1,7 +1,7 @@ #include "Systems/PickupSpawnSystem.h" -PickupSpawnSystem::PickupSpawnSystem(World* m_World, EventBroker* eventBroker) - : System(m_World, eventBroker) +PickupSpawnSystem::PickupSpawnSystem(SystemParams params) + : System(params) { EVENT_SUBSCRIBE_MEMBER(m_ETriggerTouch, &PickupSpawnSystem::OnTriggerTouch); } diff --git a/src/Game/Systems/PlayerDeathSystem.cpp b/src/Game/Systems/PlayerDeathSystem.cpp index 60c31ce5..29ed9832 100644 --- a/src/Game/Systems/PlayerDeathSystem.cpp +++ b/src/Game/Systems/PlayerDeathSystem.cpp @@ -1,7 +1,7 @@ #include "Systems/PlayerDeathSystem.h" -PlayerDeathSystem::PlayerDeathSystem(World* m_World, EventBroker* eventBroker) - : System(m_World, eventBroker) +PlayerDeathSystem::PlayerDeathSystem(SystemParams params) + : System(params) { EVENT_SUBSCRIBE_MEMBER(m_OnPlayerDeath, &PlayerDeathSystem::OnPlayerDeath); } diff --git a/src/Game/Systems/PlayerHUD.cpp b/src/Game/Systems/PlayerHUDSystem.cpp similarity index 85% rename from src/Game/Systems/PlayerHUD.cpp rename to src/Game/Systems/PlayerHUDSystem.cpp index 55d0c3f1..898d8bea 100644 --- a/src/Game/Systems/PlayerHUD.cpp +++ b/src/Game/Systems/PlayerHUDSystem.cpp @@ -1,21 +1,6 @@ -#include "Game/Systems/PlayerHUD.h" +#include "Game/Systems/PlayerHUDSystem.h" -PlayerHUD::PlayerHUD(World* world, EventBroker* eventBrokerer) - :System(world, eventBrokerer) - , m_World(world) - , m_EventBroker(eventBrokerer) -{ - - -} - -PlayerHUD::~PlayerHUD() -{ - - -} - -void PlayerHUD::Update(double dt) +void PlayerHUDSystem::Update(double dt) { auto healthHUDs = m_World->GetComponents("HealthHUD"); if (healthHUDs == nullptr) { diff --git a/src/Game/Systems/PlayerMovementSystem.cpp b/src/Game/Systems/PlayerMovementSystem.cpp index 99a2def5..7c69f0ce 100644 --- a/src/Game/Systems/PlayerMovementSystem.cpp +++ b/src/Game/Systems/PlayerMovementSystem.cpp @@ -1,8 +1,7 @@ #include "Systems/PlayerMovementSystem.h" -PlayerMovementSystem::PlayerMovementSystem(World* world, EventBroker* eventBroker) - : System(world, eventBroker) - , PureSystem("Player") +PlayerMovementSystem::PlayerMovementSystem(SystemParams params) + : System(params) { EVENT_SUBSCRIBE_MEMBER(m_EPlayerSpawned, &PlayerMovementSystem::OnPlayerSpawned); } @@ -15,6 +14,12 @@ PlayerMovementSystem::~PlayerMovementSystem() } void PlayerMovementSystem::Update(double dt) +{ + updateMovementControllers(dt); + updateVelocity(dt); +} + +void PlayerMovementSystem::updateMovementControllers(double dt) { for (auto& kv : m_PlayerInputControllers) { EntityWrapper player = kv.first; @@ -24,12 +29,20 @@ void PlayerMovementSystem::Update(double dt) continue; } + // Aim pitch EntityWrapper cameraEntity = player.FirstChildByName("Camera"); if (cameraEntity.Valid()) { glm::vec3& cameraOrientation = cameraEntity["Transform"]["Orientation"]; cameraOrientation.x += controller->Rotation().x; // Limit camera pitch so we don't break our necks cameraOrientation.x = glm::clamp(cameraOrientation.x, -glm::half_pi(), glm::half_pi()); + // Set third person model aim pitch + EntityWrapper playerModel = player.FirstChildByName("PlayerModel"); + if (playerModel.Valid()) { + ComponentWrapper cAnimationOffset = playerModel["AnimationOffset"]; + double time = (cameraOrientation.x + glm::half_pi()) / glm::pi(); + cAnimationOffset["Time"] = time; + } } ComponentWrapper& cTransform = player["Transform"]; @@ -119,24 +132,74 @@ void PlayerMovementSystem::Update(double dt) EntityWrapper playerModel = player.FirstChildByName("PlayerModel"); if (playerModel.Valid()) { ComponentWrapper cAnimation = playerModel["Animation"]; + std::string& animationName1 = cAnimation["AnimationName1"]; + std::string& animationName2 = cAnimation["AnimationName2"]; + double& animationTime1 = cAnimation["Time1"]; + double& animationTime2 = cAnimation["Time2"]; + double& animationSpeed1 = cAnimation["Speed1"]; + double& animationSpeed2 = cAnimation["Speed2"]; + double& animationWeight1 = cAnimation["Weight1"]; + double& animationWeight2 = cAnimation["Weight2"]; float movementLength = glm::length(groundVelocity); //TODO: add assault dash animation here if (glm::length(controller->Movement()) > 0.f) { - if (controller->Crouching()) { - cAnimation["AnimationName1"] = "Crouch Walk"; - (double&)cAnimation["Speed1"] = 1.f * -glm::sign(controller->Movement().z); + double forwardMovement = controller->Movement().z; + double strafeMovement = controller->Movement().x; + + if (controller->Crouching() && animationName1 != "CrouchWalk") { + animationName1 = "CrouchWalk"; + animationSpeed1 = 1.0 * -glm::sign(controller->Movement().z); } else { - cAnimation["AnimationName1"] = "Run"; - (double&)cAnimation["Speed1"] = 2.f * -glm::sign(controller->Movement().z); + if (glm::abs(forwardMovement) > 0) { + if (animationName1 != "Run") { + animationName1 = "Run"; + if (animationName2 == "StrafeLeft" || animationName2 == "StrafeRight") { + animationTime1 = animationTime2; + } else { + animationTime1 = 0.0; + } + } + animationSpeed1 = 2.f * -glm::sign(forwardMovement); + } + + if (glm::abs(strafeMovement) > 0) { + if (animationName2 != "StrafeLeft" && animationName2 != "StrafeRight") { + if (strafeMovement < 0) { + animationName2 = "StrafeLeft"; + } + if (strafeMovement > 0) { + animationName2 = "StrafeRight"; + } + if (animationName1 == "Run") { + animationTime2 = animationTime1; + } else { + animationTime2 = 0.0; + } + } + animationSpeed2 = 2.f * glm::abs(strafeMovement); + } + + double strafeWeight = glm::abs(strafeMovement) / (glm::abs(forwardMovement) + glm::abs(strafeMovement)); + animationWeight2 = strafeWeight; + animationWeight1 = 1.0 - strafeWeight; } } else { if (controller->Crouching()) { - cAnimation["AnimationName1"] = "Crouch"; - (double&)cAnimation["Speed"] = 1.f; + animationName1 = "Crouch"; + animationName2 = ""; + animationSpeed1 = 1.0; + animationSpeed2 = 0.0; + animationWeight1 = 1.0; + animationWeight2 = 0.0; } else { - cAnimation["AnimationName1"] = "Hold Pos"; - (double&)cAnimation["Speed1"] = 1.f; + animationName1 = "Idle"; + animationName2 = ""; + animationSpeed1 = 1.f; + animationSpeed2 = 0.0; + animationWeight1 = 1.0; + animationWeight2 = 0.0; + //cAnimation["AnimationName2"] = "Idle"; } } } @@ -147,14 +210,16 @@ void PlayerMovementSystem::Update(double dt) playerStep(dt); } -void PlayerMovementSystem::UpdateComponent(EntityWrapper& entity, ComponentWrapper& component, double dt) + +void PlayerMovementSystem::updateVelocity(double dt) { - ComponentWrapper& cTransform = entity["Transform"]; - if (!entity.HasComponent("Physics")) { + // Only apply velocity to local player + if (!LocalPlayer.Valid()) { return; } - ComponentWrapper& cPhysics = entity["Physics"]; + ComponentWrapper& cTransform = LocalPlayer["Transform"]; + ComponentWrapper& cPhysics = LocalPlayer["Physics"]; glm::vec3& velocity = cPhysics["Velocity"]; bool isOnGround = (bool)cPhysics["IsOnGround"]; @@ -172,6 +237,7 @@ void PlayerMovementSystem::UpdateComponent(EntityWrapper& entity, ComponentWrapp velocity.z *= multiplier; } + // Gravity if (cPhysics["Gravity"]) { velocity.y -= 9.82f * (float)dt; } @@ -187,13 +253,12 @@ void PlayerMovementSystem::playerStep(double dt) } // Position of the local player, used see how far a player has moved. glm::vec3 pos = (glm::vec3)m_World->GetComponent(m_LocalPlayer.ID, "Transform")["Position"]; - // Velocity of the local player, used to see if a player is airborne. - glm::vec3 vel = (glm::vec3)m_World->GetComponent(m_LocalPlayer.ID, "Physics")["Velocity"]; + // Used to see if a player is airborne. + bool grounded = (bool)m_World->GetComponent(m_LocalPlayer.ID, "Physics")["IsOnGround"]; m_DistanceMoved += glm::length(pos - m_LastPosition); // Set the last position for next iteration m_LastPosition = pos; - bool isAirborne = vel.y != 0; - if (m_DistanceMoved > m_PlayerStepLength && !isAirborne) { + if (m_DistanceMoved > m_PlayerStepLength && grounded) { // Player moved a step's distance // Create footstep sound Events::PlaySoundOnEntity e; diff --git a/src/Game/Systems/PlayerSpawnSystem.cpp b/src/Game/Systems/PlayerSpawnSystem.cpp index 5f46cce3..507ed0f5 100644 --- a/src/Game/Systems/PlayerSpawnSystem.cpp +++ b/src/Game/Systems/PlayerSpawnSystem.cpp @@ -1,7 +1,7 @@ #include "Systems/PlayerSpawnSystem.h" -PlayerSpawnSystem::PlayerSpawnSystem(World* m_World, EventBroker* eventBroker) - : System(m_World, eventBroker) +PlayerSpawnSystem::PlayerSpawnSystem(SystemParams params) + : System(params) { EVENT_SUBSCRIBE_MEMBER(m_OnInputCommand, &PlayerSpawnSystem::OnInputCommand); EVENT_SUBSCRIBE_MEMBER(m_OnPlayerSpawnerd, &PlayerSpawnSystem::OnPlayerSpawned); @@ -71,6 +71,9 @@ bool PlayerSpawnSystem::OnInputCommand(const Events::InputCommand& e) bool PlayerSpawnSystem::OnPlayerSpawned(Events::PlayerSpawned& e) { // When a player is actually spawned (since the actual spawning is handled on the server) + if (!IsClient) { + return false; + } // Check if a player already exists if (m_PlayerEntities.count(e.PlayerID) != 0) { diff --git a/src/Game/Systems/SoundSystem.cpp b/src/Game/Systems/SoundSystem.cpp index df14cd86..10dc61f7 100644 --- a/src/Game/Systems/SoundSystem.cpp +++ b/src/Game/Systems/SoundSystem.cpp @@ -1,19 +1,15 @@ #include "Game/Systems/SoundSystem.h" -SoundSystem::SoundSystem(World* world, EventBroker* eventbroker) - : System(world, eventbroker) +SoundSystem::SoundSystem(SystemParams params) + : System(params) , PureSystem("SoundEmitter") - //, ImpureSystem() { ConfigFile* config = ResourceManager::Load("Config.ini"); m_Announcer = ResourceManager::Load("Config.ini")->Get("Sound.Announcer", "female"); - m_World = world; - m_EventBroker = eventbroker; EVENT_SUBSCRIBE_MEMBER(m_EPlayerSpawned, &SoundSystem::OnPlayerSpawned); EVENT_SUBSCRIBE_MEMBER(m_InputCommand, &SoundSystem::OnInputCommand); EVENT_SUBSCRIBE_MEMBER(m_EDoubleJump, &SoundSystem::OnDoubleJump); EVENT_SUBSCRIBE_MEMBER(m_EDashAbility, &SoundSystem::OnDashAbility); - EVENT_SUBSCRIBE_MEMBER(m_EShoot, &SoundSystem::OnShoot); EVENT_SUBSCRIBE_MEMBER(m_EPlayerDamage, &SoundSystem::OnPlayerDamage); EVENT_SUBSCRIBE_MEMBER(m_ECaptured, &SoundSystem::OnCaptured); EVENT_SUBSCRIBE_MEMBER(m_ETriggerTouch, &SoundSystem::OnTriggerTouch); @@ -25,7 +21,7 @@ void SoundSystem::UpdateComponent(EntityWrapper& entity, ComponentWrapper& cComp void SoundSystem::Update(double dt) { // Temp for play test. - if(m_DrumsIsPlaying) { + if (m_DrumsIsPlaying) { m_DrumsIsPlaying = !drumTimer(dt); } } @@ -34,9 +30,8 @@ bool SoundSystem::OnPlayerSpawned(const Events::PlayerSpawned &e) { if (e.PlayerID == -1) { // Local player m_World->AttachComponent(e.Player.ID, "Listener"); - m_LocalPlayer = e.Player; Events::PlaySoundOnEntity go; - go.EmitterID = m_LocalPlayer.ID; + go.EmitterID = LocalPlayer.ID; go.FilePath = "Audio/announcer/" + m_Announcer + "/go.wav"; m_EventBroker->Publish(go); // TEMP: starts bgm @@ -59,7 +54,7 @@ bool SoundSystem::OnInputCommand(const Events::InputCommand & e) } if (e.Command == "TakeDamage" && e.Value > 0) { Events::PlayerDamage ev; - ev.Player = m_LocalPlayer; + ev.Player = LocalPlayer; ev.Damage = 1.0; m_EventBroker->Publish(ev); } @@ -69,10 +64,14 @@ bool SoundSystem::OnInputCommand(const Events::InputCommand & e) void SoundSystem::playerJumps() { - glm::vec3 vel = (glm::vec3)m_World->GetComponent(m_LocalPlayer.ID, "Physics")["Velocity"]; - if (vel.y == 0) { + if (!LocalPlayer.Valid()) { + return; + } + + bool grounded = (bool)m_World->GetComponent(LocalPlayer.ID, "Physics")["IsOnGround"]; + if (grounded) { Events::PlaySoundOnEntity e; - e.EmitterID = m_LocalPlayer.ID; + e.EmitterID = LocalPlayer.ID; e.FilePath = "Audio/jump/jump1.wav"; m_EventBroker->Publish(e); } @@ -89,26 +88,17 @@ bool SoundSystem::drumTimer(double dt) } } -bool SoundSystem::OnShoot(const Events::Shoot & e) -{ - Events::PlaySoundOnEntity ev; - ev.EmitterID = m_LocalPlayer.ID; - ev.FilePath = "Audio/laser/laser1.wav"; - m_EventBroker->Publish(ev); - return true; -} - bool SoundSystem::OnCaptured(const Events::Captured & e) { int homeTeam = (int)m_World->GetComponent(e.CapturePointID, "Team")["Team"]; - int team = (int)m_World->GetComponent(m_LocalPlayer.ID, "Team")["Team"]; + int team = (int)m_World->GetComponent(LocalPlayer.ID, "Team")["Team"]; Events::PlaySoundOnEntity ev; if (team == homeTeam) { ev.FilePath = "Audio/announcer/" + m_Announcer + "/objective_achieved.wav"; } else { ev.FilePath = "Audio/announcer/" + m_Announcer + "/objective_failed.wav"; // have not been tested } - ev.EmitterID = m_LocalPlayer.ID; + ev.EmitterID = LocalPlayer.ID; m_EventBroker->Publish(ev); // Temp for play test. m_DrumsIsPlaying = false; @@ -124,13 +114,13 @@ bool SoundSystem::OnPlayerDamage(const Events::PlayerDamage & e) std::vector paths; paths.push_back("Audio/hurt/hurt" + std::to_string(rand) + ".wav"); -// // Breathe -// int ammountOfbreaths = (static_cast(e.Damage) / 10) + 2; // TEMP: Idk something stupid like this shit -// for (int i = 0; i < ammountOfbreaths; i++) { -// paths.push_back("Audio/exhausted/breath.wav"); -// } + // // Breathe + // int ammountOfbreaths = (static_cast(e.Damage) / 10) + 2; // TEMP: Idk something stupid like this shit + // for (int i = 0; i < ammountOfbreaths; i++) { + // paths.push_back("Audio/exhausted/breath.wav"); + // } Events::PlayQueueOnEntity ev; - ev.Emitter = m_LocalPlayer; + ev.Emitter = LocalPlayer; ev.FilePaths = paths; m_EventBroker->Publish(ev); return false; @@ -139,8 +129,8 @@ bool SoundSystem::OnPlayerDamage(const Events::PlayerDamage & e) bool SoundSystem::OnPlayerDeath(const Events::PlayerDeath & e) { Events::PlaySoundOnEntity ev; - ev.EmitterID = m_LocalPlayer.ID; - ev.FilePath = "Audio/die/die2.wav"; + ev.EmitterID = LocalPlayer.ID; + ev.FilePath = "Audio/die/die2.wav"; m_EventBroker->Publish(ev); return false; } @@ -148,7 +138,7 @@ bool SoundSystem::OnPlayerDeath(const Events::PlayerDeath & e) bool SoundSystem::OnPlayerHealthPickup(const Events::PlayerHealthPickup & e) { Events::PlaySoundOnEntity ev; - ev.EmitterID = m_LocalPlayer.ID; + ev.EmitterID = LocalPlayer.ID; ev.FilePath = "Audio/pickup/pickup2.wav"; m_EventBroker->Publish(ev); return false; @@ -162,7 +152,7 @@ bool SoundSystem::OnTriggerTouch(const Events::TriggerTouch & e) } if (m_World->HasComponent(e.Trigger.ID, "CapturePoint")) { Events::PlaySoundOnEntity ev; // should be BGM - ev.EmitterID = m_LocalPlayer.ID; + ev.EmitterID = LocalPlayer.ID; ev.FilePath = "Audio/bgm/drumstest.wav"; m_EventBroker->Publish(ev); // Temp for play test. @@ -174,7 +164,7 @@ bool SoundSystem::OnTriggerTouch(const Events::TriggerTouch & e) bool SoundSystem::OnDoubleJump(const Events::DoubleJump & e) { Events::PlaySoundOnEntity ev; - ev.EmitterID = m_LocalPlayer.ID; + ev.EmitterID = LocalPlayer.ID; ev.FilePath = "Audio/jump/jump2.wav"; m_EventBroker->Publish(ev); return false; @@ -183,7 +173,7 @@ bool SoundSystem::OnDoubleJump(const Events::DoubleJump & e) bool SoundSystem::OnDashAbility(const Events::DashAbility &e) { Events::PlaySoundOnEntity ev; - ev.EmitterID = m_LocalPlayer.ID; + ev.EmitterID = LocalPlayer.ID; ev.FilePath = "Audio/jump/dash1.wav"; m_EventBroker->Publish(ev); return false; diff --git a/src/Game/Systems/SpawnerSystem.cpp b/src/Game/Systems/SpawnerSystem.cpp index 7a0a13c9..99f5df93 100644 --- a/src/Game/Systems/SpawnerSystem.cpp +++ b/src/Game/Systems/SpawnerSystem.cpp @@ -1,7 +1,7 @@ #include "Systems/SpawnerSystem.h" -SpawnerSystem::SpawnerSystem(World* world, EventBroker* eventBroker) - : System(world, eventBroker) +SpawnerSystem::SpawnerSystem(SystemParams params) + : System(params) { EVENT_SUBSCRIBE_MEMBER(m_OnSpawnerSpawn, &SpawnerSystem::OnSpawnerSpawn); } @@ -51,7 +51,7 @@ EntityWrapper SpawnerSystem::Spawn(EntityWrapper spawner, EntityWrapper parent / // Set its position and orientation to that of the SpawnPoint spawnedEntity["Transform"]["Position"] = Transform::AbsolutePosition(spawnPoint.World, spawnPoint.ID); // TODO: Quaternions, bitch - //spawnedEntity["Transform"]["Orientation"] = glm::eulerAngles(Transform::AbsoluteOrientation(spawnPoint.World, spawnPoint.ID)); + spawnedEntity["Transform"]["Orientation"] = glm::eulerAngles(Transform::AbsoluteOrientation(spawnPoint)); return spawnedEntity; } diff --git a/src/Game/Systems/WeaponSystem.cpp b/src/Game/Systems/WeaponSystem.cpp index 1613cb7a..eeb7dd00 100644 --- a/src/Game/Systems/WeaponSystem.cpp +++ b/src/Game/Systems/WeaponSystem.cpp @@ -1,13 +1,15 @@ #include "Systems/WeaponSystem.h" -WeaponSystem::WeaponSystem(World* world, EventBroker* eventBroker, IRenderer* renderer) - : System(world, eventBroker) - , ImpureSystem() +WeaponSystem::WeaponSystem(SystemParams params, IRenderer* renderer, Octree* collisionOctree) + : System(params) + , PureSystem("Player") + , m_SystemParams(params) , m_Renderer(renderer) + , m_CollisionOctree(collisionOctree) { - EVENT_SUBSCRIBE_MEMBER(m_EPlayerSpawned, &WeaponSystem::OnPlayerSpawned); EVENT_SUBSCRIBE_MEMBER(m_EInputCommand, &WeaponSystem::OnInputCommand); EVENT_SUBSCRIBE_MEMBER(m_EShoot, &WeaponSystem::OnShoot); + EVENT_SUBSCRIBE_MEMBER(m_EPlayerSpawned, &WeaponSystem::OnPlayerSpawned); } void WeaponSystem::Update(double dt) @@ -15,90 +17,84 @@ void WeaponSystem::Update(double dt) } -bool WeaponSystem::OnPlayerSpawned(const Events::PlayerSpawned& e) +void WeaponSystem::UpdateComponent(EntityWrapper& entity, ComponentWrapper& cPlayer, double dt) { + // Update potential weapon behaviour for player + auto it = m_ActiveWeapons.find(entity); + if (it == m_ActiveWeapons.end()) { + selectWeapon(entity, 1); + } + + m_ActiveWeapons.at(entity)->Update(dt); +} + +bool WeaponSystem::OnInputCommand(Events::InputCommand& e) +{ + EntityWrapper player = e.Player; if (e.PlayerID == -1) { - m_LocalPlayer = e.Player; + player = LocalPlayer; } - return true; -} -bool WeaponSystem::OnInputCommand(const Events::InputCommand& e) -{ - // Only shoot client-side! - if (e.PlayerID != -1) { + // Make sure player is alive + if (!player.Valid()) { return false; } - // Only shoot if the player is alive - if (!m_LocalPlayer.Valid()) { - return false; - } - - if (e.Command == "PrimaryFire" && e.Value > 0) { - Events::Shoot eShoot; - if (e.PlayerID == -1) { - eShoot.Player = m_LocalPlayer; - } else { - eShoot.Player = e.Player; + // Weapon selection + if (e.Command == "SelectWeapon") { + if (e.Value != 0) { + //selectWeapon(player, static_cast(e.Value)); + } + } + + // Fire + if (e.Command == "PrimaryFire") { + if (m_ActiveWeapons.find(player) != m_ActiveWeapons.end()) { + auto weapon = m_ActiveWeapons.at(player); + if (e.Value > 0) { + weapon->Fire(); + } else { + weapon->CeaseFire(); + } } - m_EventBroker->Publish(eShoot); } return true; } -bool WeaponSystem::OnShoot(Events::Shoot& eShoot) +void WeaponSystem::selectWeapon(EntityWrapper player, ComponentInfo::EnumType slot) +{ + // Primary + if (slot == 1) { + // TODO: if class... + if (m_ActiveWeapons.count(player) == 0) { + m_ActiveWeapons.insert(std::make_pair(player, std::make_shared(m_SystemParams, m_CollisionOctree, player))); + } else { + //m_ActiveWeapons.erase(player); + } + } + + // Secondary + if (slot == 2) { + //m_ActiveWeapons[player] = std::make_shared(); + } +} + +bool WeaponSystem::OnPlayerSpawned(Events::PlayerSpawned& e) +{ + // Select primary weapon on player spawn + // TODO: Select the active one specified by player component + return true; +} + +bool WeaponSystem::OnShoot(Events::Shoot& eShoot) { if (!eShoot.Player.Valid()) { return false; } - // TODO: Weapon firing effects here - - auto rayRed = ResourceManager::Load("Schema/Entities/RayRed.xml"); - auto rayBlue = ResourceManager::Load("Schema/Entities/RayBlue.xml"); - - EntityWrapper weapon = eShoot.Player.FirstChildByName("WeaponMuzzle"); - if (weapon.Valid()) { - EntityWrapper ray; - if ((ComponentInfo::EnumType)eShoot.Player["Team"]["Team"] == eShoot.Player["Team"]["Team"].Enum("Red")) { - EntityFileParser parser(rayRed); - EntityID rayID = parser.MergeEntities(m_World); - ray = EntityWrapper(m_World, rayID); - } else { - EntityFileParser parser(rayBlue); - EntityID rayID = parser.MergeEntities(m_World); - ray = EntityWrapper(m_World, rayID); - } - - glm::mat4 transformation = Transform::AbsoluteTransformation(weapon); - glm::vec3 scale; - glm::vec3 translation; - glm::quat orientation; - glm::vec3 skew; - glm::vec4 perspective; - glm::decompose(transformation, scale, orientation, translation, skew, perspective); - - // Matrix to euler angles - glm::vec3 euler; - euler.y = glm::asin(-transformation[0][2]); - if (cos(euler.y) != 0) { - euler.x = atan2(transformation[1][2], transformation[2][2]); - euler.z = atan2(transformation[0][1], transformation[0][0]); - } else { - euler.x = atan2(-transformation[2][0], transformation[1][1]); - euler.z = 0; - } - - //LOG_DEBUG("rotation: %f %f %f", euler.x, euler.y, euler.z); - (glm::vec3&)ray["Transform"]["Position"] = translation; - (glm::vec3&)ray["Transform"]["Orientation"] = euler; - //(glm::vec3&)ray["Transform"]["Orientation"] = Transform::AbsoluteOrientationEuler(weapon); - } - - // Only run further picking code client-side! - if (eShoot.Player != m_LocalPlayer) { + // Only run further picking code for the local player! + if (eShoot.Player != LocalPlayer) { return false; } @@ -138,4 +134,4 @@ bool WeaponSystem::OnShoot(Events::Shoot& eShoot) m_EventBroker->Publish(ePlayerDamage); return true; -} +} \ No newline at end of file