diff --git a/include/Engine/Core/EntityWrapper.h b/include/Engine/Core/EntityWrapper.h index b0e65d9e..b64eb49b 100644 --- a/include/Engine/Core/EntityWrapper.h +++ b/include/Engine/Core/EntityWrapper.h @@ -29,6 +29,7 @@ struct EntityWrapper EntityWrapper Parent(); EntityWrapper FirstChildByName(const std::string& name); EntityWrapper FirstParentWithComponent(const std::string& componentType); + std::vector ChildrenWithComponent(const std::string& componentType); bool IsChildOf(EntityWrapper potentialParent); bool Valid() const; @@ -39,6 +40,7 @@ struct EntityWrapper private: EntityWrapper firstChildByNameRecursive(const std::string& name, EntityID parent); + void childrenWithComponentRecursive(const std::string& componentType, EntityWrapper& entity, std::vector& childrenWithComponent); }; namespace std diff --git a/include/Game/Systems/Weapon/AssaultWeaponBehaviour.h b/include/Game/Systems/Weapon/AssaultWeaponBehaviour.h index 7bd9c175..4cb9de94 100644 --- a/include/Game/Systems/Weapon/AssaultWeaponBehaviour.h +++ b/include/Game/Systems/Weapon/AssaultWeaponBehaviour.h @@ -1,13 +1,14 @@ +#ifndef AssaultWeaponBehaviour_h__ +#define AssaultWeaponBehaviour_h__ + #include "Sound/EPlaySoundOnEntity.h" #include "Collision/Collision.h" -#include "Rendering/AnimationSystem.h" #include "Core/ConfigFile.h" #include "WeaponBehaviour.h" #include "../SpawnerSystem.h" #include "Core/EPlayerDamage.h" #include "Core/EShoot.h" - class AssaultWeaponBehaviour : public WeaponBehaviour { public: @@ -22,16 +23,13 @@ public: private: EntityWrapper m_FirstPersonModel; EntityWrapper m_ThirdPersonModel; + // State bool m_Firing = false; bool m_Reloading = false; double m_ReloadTimer = 0.0; - EntityWrapper m_FirstPersonReloadImpersonator; - EntityWrapper m_ThirdPersonReloadImpersonator; double m_TimeSinceLastFire = 0.0; - - EventRelay m_EAnimationComplete; - bool OnAnimationComplete(Events::AnimationComplete& e); + EntityWrapper m_FirstPersonReloadImpostor; bool hasAmmo(); void fireRound(); @@ -47,3 +45,5 @@ private: bool shoot(double damage); void showHitMarker(); }; + +#endif \ No newline at end of file diff --git a/include/Game/Systems/Weapon/DefenderWeaponBehaviour.h b/include/Game/Systems/Weapon/DefenderWeaponBehaviour.h new file mode 100644 index 00000000..1b549dab --- /dev/null +++ b/include/Game/Systems/Weapon/DefenderWeaponBehaviour.h @@ -0,0 +1,16 @@ +#include "WeaponBehaviour.h" + +class DefenderWeaponBehaviour : public WeaponBehaviour +{ +public: + DefenderWeaponBehaviour(SystemParams systemParams, IRenderer* renderer, Octree* collisionOctree, EntityWrapper weaponEntity); + + virtual void Fire() override; + //virtual void CeaseFire() override; + //virtual void Reload() override; + + //virtual void Update(double dt) override; + +private: + double m_TimeSinceLastFire = 0.0; +}; \ No newline at end of file diff --git a/include/Game/Systems/Weapon/WeaponBehaviour.h b/include/Game/Systems/Weapon/WeaponBehaviour.h index 7a0b4626..41f479ed 100644 --- a/include/Game/Systems/Weapon/WeaponBehaviour.h +++ b/include/Game/Systems/Weapon/WeaponBehaviour.h @@ -8,17 +8,21 @@ class WeaponBehaviour : public System { + friend class WeaponSystem; + public: - WeaponBehaviour(SystemParams systemParams, IRenderer* renderer, Octree* collisionOctree, EntityWrapper player) + WeaponBehaviour(SystemParams systemParams, IRenderer* renderer, Octree* collisionOctree, EntityWrapper player, EntityWrapper firstPersonWeapon, EntityWrapper thirdPersonWeapon) : System(systemParams) , m_Renderer(renderer) , m_CollisionOctree(collisionOctree) , m_Player(player) + , m_FirstPerson(firstPersonWeapon) + , m_ThirdPerson(thirdPersonWeapon) { } virtual ~WeaponBehaviour() = default; WeaponBehaviour(const WeaponBehaviour&) = delete; - WeaponBehaviour& operator=(const WeaponBehaviour &) = delete; + WeaponBehaviour& operator=(const WeaponBehaviour&) = delete; virtual void Fire() = 0; virtual void CeaseFire() { } @@ -29,6 +33,8 @@ protected: IRenderer* m_Renderer; Octree* m_CollisionOctree; EntityWrapper m_Player; + EntityWrapper m_FirstPerson; + EntityWrapper m_ThirdPerson; }; #endif diff --git a/resources/Schema/Components.xsd b/resources/Schema/Components.xsd index 42abed82..c858251e 100644 --- a/resources/Schema/Components.xsd +++ b/resources/Schema/Components.xsd @@ -46,4 +46,5 @@ + \ No newline at end of file diff --git a/resources/Schema/Components/Weapon.xml b/resources/Schema/Components/Weapon.xml deleted file mode 100644 index 38c6fce9..00000000 --- a/resources/Schema/Components/Weapon.xml +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/resources/Schema/Components/Weapon.xsd b/resources/Schema/Components/Weapon.xsd deleted file mode 100644 index 8bddd8a9..00000000 --- a/resources/Schema/Components/Weapon.xsd +++ /dev/null @@ -1,17 +0,0 @@ - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/resources/Schema/Components/WeaponAttachment.xml b/resources/Schema/Components/WeaponAttachment.xml new file mode 100644 index 00000000..38c31c07 --- /dev/null +++ b/resources/Schema/Components/WeaponAttachment.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/resources/Schema/Components/WeaponAttachment.xsd b/resources/Schema/Components/WeaponAttachment.xsd new file mode 100644 index 00000000..68ac8024 --- /dev/null +++ b/resources/Schema/Components/WeaponAttachment.xsd @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Combine with a spawner to define a weapon attachment point + + + + + + + + \ No newline at end of file diff --git a/resources/Schema/Types/Entity.xsd b/resources/Schema/Types/Entity.xsd index a9c5f641..1661e1e5 100644 --- a/resources/Schema/Types/Entity.xsd +++ b/resources/Schema/Types/Entity.xsd @@ -50,6 +50,7 @@ + diff --git a/src/Engine/Core/EntityWrapper.cpp b/src/Engine/Core/EntityWrapper.cpp index 4b45b8d0..1050ae9e 100644 --- a/src/Engine/Core/EntityWrapper.cpp +++ b/src/Engine/Core/EntityWrapper.cpp @@ -51,6 +51,13 @@ EntityWrapper EntityWrapper::FirstParentWithComponent(const std::string& compone return EntityWrapper::Invalid; } +std::vector EntityWrapper::ChildrenWithComponent(const std::string& componentType) +{ + std::vector childrenWithComponent; + childrenWithComponentRecursive(componentType, *this, childrenWithComponent); + return childrenWithComponent; +} + bool EntityWrapper::IsChildOf(EntityWrapper potentialParent) { EntityWrapper entity = *this; @@ -131,3 +138,18 @@ EntityWrapper EntityWrapper::firstChildByNameRecursive(const std::string& name, return EntityWrapper::Invalid; } +void EntityWrapper::childrenWithComponentRecursive(const std::string& componentType, EntityWrapper& entity, std::vector& childrenWithComponent) +{ + auto itPair = this->World->GetChildren(entity.ID); + if (itPair.first == itPair.second) { + return; + } + + for (auto it = itPair.first; it != itPair.second; ++it) { + if (entity.HasComponent(componentType)) { + childrenWithComponent.push_back(entity); + } + childrenWithComponentRecursive(componentType, entity, childrenWithComponent); + } +} + diff --git a/src/Game/Systems/Weapon/AssaultWeaponBehaviour.cpp b/src/Game/Systems/Weapon/AssaultWeaponBehaviour.cpp index 84d3ccd4..062d0ab2 100644 --- a/src/Game/Systems/Weapon/AssaultWeaponBehaviour.cpp +++ b/src/Game/Systems/Weapon/AssaultWeaponBehaviour.cpp @@ -5,7 +5,6 @@ AssaultWeaponBehaviour::AssaultWeaponBehaviour(SystemParams systemParams, IRende { m_FirstPersonModel = m_Player.FirstChildByName("Hands"); m_ThirdPersonModel = m_Player.FirstChildByName("PlayerModel"); - EVENT_SUBSCRIBE_MEMBER(m_EAnimationComplete, &AssaultWeaponBehaviour::OnAnimationComplete); } void AssaultWeaponBehaviour::Fire() @@ -36,7 +35,7 @@ void AssaultWeaponBehaviour::Reload() return; } - // Don't reload if we're completly out of ammo + // Don't reload if we're completely out of ammo if (ammo == 0) { playEmptySound(); m_TimeSinceLastFire = -0.0f; // HACK: To make empty sound play with interval @@ -56,14 +55,14 @@ void AssaultWeaponBehaviour::Update(double dt) { if (m_Reloading) { m_ReloadTimer -= dt; - // Re-enable glow on reload impersonator half-way through the animation + // Re-enable glow on reload impostor half-way through the animation if (IsClient) { if (m_ReloadTimer <= (double)m_Player["AssaultWeapon"]["ReloadTime"] / 2.0) { - if (m_FirstPersonReloadImpersonator.Valid()) { - m_FirstPersonReloadImpersonator["Model"]["GlowMap"] = true; + if (m_FirstPersonReloadImpostor.Valid()) { + m_FirstPersonReloadImpostor["Model"]["GlowMap"] = true; } - if (m_ThirdPersonReloadImpersonator.Valid()) { - m_ThirdPersonReloadImpersonator["Model"]["GlowMap"] = true; + if (m_ThirdPersonReloadImpostor.Valid()) { + m_ThirdPersonReloadImpostor["Model"]["GlowMap"] = true; } } } @@ -96,21 +95,6 @@ void AssaultWeaponBehaviour::Update(double dt) } } -bool AssaultWeaponBehaviour::OnAnimationComplete(Events::AnimationComplete& e) -{ - if (e.Entity != m_FirstPersonModel) { - return false; - } - - //if (e.Name == "ShootRifle") { - // if (!m_Firing) { - // playIdleAnimation(); - // } - //} - - return true; -} - bool AssaultWeaponBehaviour::hasAmmo() { ComponentWrapper& cAssaultWeapon = m_Player["AssaultWeapon"]; @@ -215,6 +199,12 @@ void AssaultWeaponBehaviour::playEmptySound() void AssaultWeaponBehaviour::viewPunch() { + // Since we send absolute client orientations to server, running this server side would + // cause aim desync. + if (!IsClient) { + return; + } + EntityWrapper playerCamera = m_Player.FirstChildByName("Camera"); if (!playerCamera.Valid()) { return; @@ -323,8 +313,8 @@ void AssaultWeaponBehaviour::playReloadAnimation() EntityWrapper firstPersonWeaponModel = m_Player.FirstChildByName("WeaponModel"); EntityWrapper reloadSpawner = m_Player.FirstChildByName("FirstPersonReloadSpawner"); if (IsClient) { - m_FirstPersonReloadImpersonator = SpawnerSystem::Spawn(reloadSpawner, reloadSpawner); - firstPersonWeaponModel["Model"].Copy(m_FirstPersonReloadImpersonator["Model"]); + m_FirstPersonReloadImpostor = SpawnerSystem::Spawn(reloadSpawner, reloadSpawner); + firstPersonWeaponModel["Model"].Copy(m_FirstPersonReloadImpostor["Model"]); } firstPersonWeaponModel["Model"]["Visible"] = false; } @@ -332,8 +322,8 @@ void AssaultWeaponBehaviour::playReloadAnimation() EntityWrapper thirdPersonWeaponModel = m_Player.FirstChildByName("ThirdPersonWeaponModel"); EntityWrapper reloadSpawner = m_Player.FirstChildByName("ThirdPersonReloadSpawner"); if (IsClient) { - m_ThirdPersonReloadImpersonator = SpawnerSystem::Spawn(reloadSpawner, reloadSpawner); - thirdPersonWeaponModel["Model"].Copy(m_ThirdPersonReloadImpersonator["Model"]); + m_ThirdPersonReloadImpostor = SpawnerSystem::Spawn(reloadSpawner, reloadSpawner); + thirdPersonWeaponModel["Model"].Copy(m_ThirdPersonReloadImpostor["Model"]); } thirdPersonWeaponModel["Model"]["Visible"] = false; } @@ -371,7 +361,7 @@ bool AssaultWeaponBehaviour::shoot(double damage) return false; } - // Don't let us shoot ourselves in the foot + // Don't let us shoot ourselves in the foot somehow if (victim == LocalPlayer) { return false; } diff --git a/src/Game/Systems/Weapon/DefenderWeaponBehaviour.cpp b/src/Game/Systems/Weapon/DefenderWeaponBehaviour.cpp new file mode 100644 index 00000000..f187a8fc --- /dev/null +++ b/src/Game/Systems/Weapon/DefenderWeaponBehaviour.cpp @@ -0,0 +1,10 @@ +#include "Systems/Weapon/DefenderWeaponBehaviour.h" + +DefenderWeaponBehaviour::DefenderWeaponBehaviour(SystemParams systemParams, IRenderer* renderer, Octree* collisionOctree, EntityWrapper weaponEntity) + : WeaponBehaviour(systemParams, renderer, collisionOctree, weaponEntity) { } + +void DefenderWeaponBehaviour::Fire() +{ + +} + diff --git a/src/Game/Systems/Weapon/WeaponSystem.cpp b/src/Game/Systems/Weapon/WeaponSystem.cpp index 3a49ae90..d33c5098 100644 --- a/src/Game/Systems/Weapon/WeaponSystem.cpp +++ b/src/Game/Systems/Weapon/WeaponSystem.cpp @@ -13,7 +13,7 @@ WeaponSystem::WeaponSystem(SystemParams params, IRenderer* renderer, Octree weaponAttachments = player.ChildrenWithComponent("WeaponAttachment"); + + // Find the weapon attachments matching the slot selected + EntityWrapper firstPersonAttachment; + EntityWrapper thirdPersonAttachment; + for (auto& attachment : weaponAttachments) { + ComponentWrapper cWeaponAttachment = attachment["WeaponAttachment"]; + if ((ComponentInfo::EnumType)cWeaponAttachment["Slot"] == slot) { + ComponentWrapper::SubscriptProxy person = cWeaponAttachment["Person"]; + if (person == person.Enum("FirstPerson")) { + firstPersonAttachment = attachment; + } else if (person == person.Enum("ThirdPerson")) { + thirdPersonAttachment = attachment; + } + } + } + + if (firstPersonAttachment.Valid() && thirdPersonAttachment.Valid()) { + LOG_WARNING("No weapon attachment found for slot %i of player #%i", slot, player.ID); + return; + } + + // TODO: Delete old weapons + + // Spawn the weapon(s) + EntityWrapper firstPersonWeapon; + EntityWrapper thirdPersonWeapon; + if (firstPersonAttachment.Valid()) { + firstPersonWeapon = SpawnerSystem::Spawn(firstPersonAttachment, firstPersonAttachment); + } + if (thirdPersonAttachment.Valid()) { + firstPersonWeapon = SpawnerSystem::Spawn(thirdPersonAttachment, thirdPersonAttachment); + } + + // Create the correct behaviour + if (firstPersonWeapon.Valid()) { + if (firstPersonWeapon.HasComponent("AssaultWeapon") { + + } + } + // 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_Renderer, m_CollisionOctree, player))); - } else { - //m_ActiveWeapons.erase(player); - } + nextBehaviour = std::make_shared(m_SystemParams, m_Renderer, m_CollisionOctree, player); } // Secondary if (slot == 2) { //m_ActiveWeapons[player] = std::make_shared(); } + + if (nextBehaviour != nullptr) { + // TODO: Destroy previous behaviour and make new + if (m_ActiveWeapons.count(player) == 0) { + m_ActiveWeapons[player] = nextBehaviour; + } + } } bool WeaponSystem::OnPlayerSpawned(Events::PlayerSpawned& e)