Merge pull request #105 from teamfisk/Respawning

Automatic respawning
This commit is contained in:
2016-02-12 02:07:36 +01:00
10 changed files with 127 additions and 28 deletions
+4 -1
View File
@@ -9,6 +9,7 @@
#include "Core/EPlayerDamage.h"
#include "Core/EPlayerHealthPickup.h"
#include "Core/EPlayerDeath.h"
#include "../Engine/Input/EInputCommand.h"
#include <tuple>
#include <vector>
@@ -28,7 +29,9 @@ private:
bool HealthSystem::OnPlayerDamaged(Events::PlayerDamage& e);
EventRelay<HealthSystem, Events::PlayerHealthPickup> m_EPlayerHealthPickup;
bool HealthSystem::OnPlayerHealthPickup(Events::PlayerHealthPickup& e);
EventRelay<HealthSystem, Events::InputCommand> m_InputCommand;
bool HealthSystem::OnInputCommand(Events::InputCommand& e);
//vector which will keep track of health changes
std::vector<std::tuple<EntityID, double>> m_DeltaHealthVector;
+12 -1
View File
@@ -13,6 +13,8 @@ public:
PlayerSpawnSystem(SystemParams params);
virtual void Update(double dt) override;
static void SetRespawnTime(float respawnTime) { m_RespawnTime = respawnTime; };
private:
struct SpawnRequest
@@ -23,10 +25,19 @@ private:
bool m_NetworkEnabled = false;
std::vector<SpawnRequest> m_SpawnRequests;
//Player ID -> EntityWrapper.
std::map<int, EntityWrapper> m_PlayerEntities;
//EntityWrapper ID -> Player ID.
std::map<EntityID, int> m_PlayerIDs;
static float m_RespawnTime;
float m_Timer;
EventRelay<PlayerSpawnSystem, Events::InputCommand> m_OnInputCommand;
bool OnInputCommand(const Events::InputCommand& e);
bool OnInputCommand(Events::InputCommand& e);
EventRelay<PlayerSpawnSystem, Events::PlayerSpawned> m_OnPlayerSpawnerd;
bool OnPlayerSpawned(Events::PlayerSpawned& e);
EventRelay<PlayerSpawnSystem, Events::PlayerDeath> m_OnPlayerDeath;
bool OnPlayerDeath(Events::PlayerDeath& e);
};
+1
View File
@@ -4,6 +4,7 @@ LoadMap=
; if true -> Pool allocation is not used when calling Allocate/Free, just use regular dynamic allocation.
; if false -> Use pool allocation.
DisableMemoryPool=false
RespawnTime = 8.0
EditorEnabled=false
OutOfBodyExperience=false
+2 -1
View File
@@ -24,4 +24,5 @@ F1=ToggleEditor
C=ConnectToServer
N=SwitchToServer
M=SwitchToClient
P=SwitchToPlayer
P=SwitchToPlayer
K=TakeDamage,1500
+2 -1
View File
@@ -42,6 +42,7 @@ Game::Game(int argc, char* argv[])
ResourceManager::UseThreading = m_Config->Get<bool>("Multithreading.ResourceLoading", true);
DisableMemoryPool::Value = m_Config->Get<bool>("Debug.DisableMemoryPool", false);
LOG_LEVEL = static_cast<_LOG_LEVEL>(m_Config->Get<int>("Debug.LogLevel", 1));
PlayerSpawnSystem::SetRespawnTime(m_Config->Get<float>("Debug.RespawnTime", 15.0f));
// Create the core event broker
m_EventBroker = new EventBroker();
@@ -118,7 +119,6 @@ Game::Game(int argc, char* argv[])
m_SystemPipeline->AddSystem<PlayerMovementSystem>(updateOrderLevel);
m_SystemPipeline->AddSystem<SpawnerSystem>(updateOrderLevel);
m_SystemPipeline->AddSystem<PlayerSpawnSystem>(updateOrderLevel);
m_SystemPipeline->AddSystem<PlayerDeathSystem>(updateOrderLevel);
m_SystemPipeline->AddSystem<WeaponSystem>(updateOrderLevel, m_Renderer, m_OctreeCollision);
m_SystemPipeline->AddSystem<LifetimeSystem>(updateOrderLevel);
m_SystemPipeline->AddSystem<CapturePointSystem>(updateOrderLevel);
@@ -132,6 +132,7 @@ Game::Game(int argc, char* argv[])
m_SystemPipeline->AddSystem<FillFrustumOctreeSystem>(updateOrderLevel, m_OctreeFrustrumCulling);
m_SystemPipeline->AddSystem<AnimationSystem>(updateOrderLevel);
m_SystemPipeline->AddSystem<UniformScaleSystem>(updateOrderLevel);
m_SystemPipeline->AddSystem<PlayerDeathSystem>(updateOrderLevel);
m_SystemPipeline->AddSystem<PlayerHUDSystem>(updateOrderLevel);
// Collision and TriggerSystem should update after player.
++updateOrderLevel;
@@ -22,6 +22,10 @@ bool DamageIndicatorSystem::OnPlayerDamage(Events::PlayerDamage& e)
return false;
}
if (!e.Inflictor.Valid() || !e.Victim.Valid()) {
return false;
}
//grab players direction
auto playerOrientation = glm::quat((glm::vec3)e.Victim["Transform"]["Orientation"]);
+12
View File
@@ -7,6 +7,7 @@ HealthSystem::HealthSystem(SystemParams params)
//subscribe/listenTo playerdamage,healthpickup events (using the eventBroker)
EVENT_SUBSCRIBE_MEMBER(m_EPlayerDamage, &HealthSystem::OnPlayerDamaged);
EVENT_SUBSCRIBE_MEMBER(m_EPlayerHealthPickup, &HealthSystem::OnPlayerHealthPickup);
EVENT_SUBSCRIBE_MEMBER(m_InputCommand, &HealthSystem::OnInputCommand);
}
void HealthSystem::UpdateComponent(EntityWrapper& entity, ComponentWrapper& component, double dt)
@@ -29,6 +30,17 @@ bool HealthSystem::OnPlayerDamaged(Events::PlayerDamage& e)
return true;
}
bool HealthSystem::OnInputCommand(Events::InputCommand& e)
{
if (e.Command == "TakeDamage" && e.Value > 0 && LocalPlayer.Valid()) {
Events::PlayerDamage ev;
ev.Victim = LocalPlayer;
ev.Damage = e.Value;
m_EventBroker->Publish(ev);
}
return true;
}
bool HealthSystem::OnPlayerHealthPickup(Events::PlayerHealthPickup& e)
{
ComponentWrapper cHealth = e.Player["Health"];
+9 -2
View File
@@ -34,8 +34,15 @@ void PlayerDeathSystem::createDeathEffect(EntityWrapper player)
//components that we need from player
auto playerCamera = player.FirstChildByName("Camera");
auto playerEntityModel = player.FirstChildByName("PlayerModel")["Model"];
auto playerEntityAnimation = player.FirstChildByName("PlayerModel")["Animation"];
auto playerModel = player.FirstChildByName("PlayerModel");
if (!playerCamera.Valid() || !playerModel.Valid()) {
return;
}
if (!playerModel.HasComponent("Model") || !playerModel.HasComponent("Animation")) {
return;
}
auto playerEntityModel = playerModel["Model"];
auto playerEntityAnimation = playerModel["Animation"];
//copy the data from player to explisioneffectmodel
playerEntityModel.Copy(deathEffectEW["Model"]);
+81 -16
View File
@@ -1,20 +1,39 @@
#include "Systems/PlayerSpawnSystem.h"
//This should be set by the config anyway.
float PlayerSpawnSystem::m_RespawnTime = 15.0f;
PlayerSpawnSystem::PlayerSpawnSystem(SystemParams params)
: System(params)
, m_Timer(0.f)
{
EVENT_SUBSCRIBE_MEMBER(m_OnInputCommand, &PlayerSpawnSystem::OnInputCommand);
EVENT_SUBSCRIBE_MEMBER(m_OnPlayerSpawnerd, &PlayerSpawnSystem::OnPlayerSpawned);
EVENT_SUBSCRIBE_MEMBER(m_OnPlayerDeath, &PlayerSpawnSystem::OnPlayerDeath);
m_NetworkEnabled = ResourceManager::Load<ConfigFile>("Config.ini")->Get("Networking.StartNetwork", false);
}
void PlayerSpawnSystem::Update(double dt)
{
//Increase timer.
m_Timer += dt;
if (m_Timer < m_RespawnTime) {
return;
}
//If respawn time has passed, we spawn all players that have requested to be spawned.
m_Timer = 0.f;
//If there are no spawn requests, return immediately, if we are client the SpawnRequests should always be empty.
if (m_SpawnRequests.size() == 0) {
return;
}
auto playerSpawns = m_World->GetComponents("PlayerSpawn");
if (playerSpawns == nullptr) {
return;
}
int numSpawnedPlayers = 0;
for (auto& req : m_SpawnRequests) {
for (auto& cPlayerSpawn : *playerSpawns) {
EntityWrapper spawner(m_World, cPlayerSpawn.EntityID);
@@ -40,29 +59,61 @@ void PlayerSpawnSystem::Update(double dt)
e.Player = player;
e.Spawner = spawner;
m_EventBroker->Publish(e);
++numSpawnedPlayers;
break;
}
}
if (numSpawnedPlayers != (int)m_SpawnRequests.size()) {
LOG_DEBUG("%i players were supposed to be spawned, but %i was spawned.", (int)m_SpawnRequests.size(), numSpawnedPlayers);
} else {
LOG_DEBUG("%i players were spawned.", numSpawnedPlayers);
}
m_SpawnRequests.clear();
}
bool PlayerSpawnSystem::OnInputCommand(const Events::InputCommand& e)
bool PlayerSpawnSystem::OnInputCommand(Events::InputCommand& e)
{
if (e.Command != "PickTeam") {
return false;
}
// Team picks should be processed ONLY server-side!
// Don't make a spawn request if PlayerID is -1, i.e. we're the client.
if (e.PlayerID == -1 && m_NetworkEnabled) {
// Don't make a spawn request if we're the client.
if (!IsServer && m_NetworkEnabled) {
return false;
}
if (e.Value != 0) {
if (e.Value == 0) {
return false;
}
//TODO: Spectating?
//Right now, return if someone picks spectator.
//1 signifies spectator here, could not get Playerteam component since it may be invalid or without team comp.
if ((ComponentInfo::EnumType)e.Value == 1) {
return false;
}
//Check if the player already requested spawn.
auto iter = m_SpawnRequests.begin();
for (; iter != m_SpawnRequests.end(); ++iter) {
if (iter->PlayerID == e.PlayerID) {
break;
}
}
if (iter != m_SpawnRequests.end()) {
//If player is in queue to spawn, then change their team affiliation in the request.
iter->Team = (ComponentInfo::EnumType)e.Value;
} else if (m_PlayerEntities.count(e.PlayerID) == 0 || !m_PlayerEntities[e.PlayerID].Valid()) {
//If player is not in queue to spawn, then create a spawn request,
//but only if they are spectating and/or just connected.
SpawnRequest req;
req.PlayerID = e.PlayerID;
req.Team = (ComponentInfo::EnumType)e.Value;
m_SpawnRequests.push_back(req);
} else {
return false;
}
return true;
@@ -70,21 +121,15 @@ bool PlayerSpawnSystem::OnInputCommand(const Events::InputCommand& e)
bool PlayerSpawnSystem::OnPlayerSpawned(Events::PlayerSpawned& e)
{
// Store the player for future reference
m_PlayerEntities[e.PlayerID] = e.Player;
m_PlayerIDs[e.Player.ID] = e.PlayerID;
// 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) {
// TODO: Disallow infinite respawning here
if (m_PlayerEntities[e.PlayerID].Valid()) {
m_World->DeleteEntity(m_PlayerEntities[e.PlayerID].ID);
}
}
// Store the player for future reference
m_PlayerEntities[e.PlayerID] = e.Player;
// Set the camera to the correct entity
EntityWrapper cameraEntity = e.Player.FirstChildByName("Camera");
@@ -114,4 +159,24 @@ bool PlayerSpawnSystem::OnPlayerSpawned(Events::PlayerSpawned& e)
}
return true;
}
}
bool PlayerSpawnSystem::OnPlayerDeath(Events::PlayerDeath& e)
{
//Only spawn request if network is disabled or we are server.
if (!IsServer && m_NetworkEnabled) {
return false;
}
if (!e.Player.HasComponent("Team")) {
return false;
}
ComponentWrapper cTeam = e.Player["Team"];
//A spectator can't die anyway
if ((ComponentInfo::EnumType)cTeam["Team"] == cTeam["Team"].Enum("Spectator")) {
return false;
}
SpawnRequest req;
req.PlayerID = m_PlayerIDs.at(e.Player.ID);
req.Team = cTeam["Team"];
m_SpawnRequests.push_back(req);
}
-6
View File
@@ -52,12 +52,6 @@ bool SoundSystem::OnInputCommand(const Events::InputCommand & e)
return true;
}
}
if (e.Command == "TakeDamage" && e.Value > 0) {
Events::PlayerDamage ev;
ev.Victim = LocalPlayer;
ev.Damage = 1.0;
m_EventBroker->Publish(ev);
}
return false;
}