diff --git a/include/Engine/Core/World.h b/include/Engine/Core/World.h
index c9f738ce..d8e2c7ba 100644
--- a/include/Engine/Core/World.h
+++ b/include/Engine/Core/World.h
@@ -6,6 +6,7 @@
#include "ObjectPool.h"
#include "ComponentPool.h"
#include "EventBroker.h"
+struct EntityWrapper;
class World
{
@@ -49,6 +50,8 @@ public:
void SetName(EntityID entity, const std::string& name);
// Get the textual name of an entity
std::string GetName(EntityID entity) const;
+ // Get the first entity in the world with the name.
+ EntityWrapper GetFirstEntityByName(const std::string& name);
private:
EventBroker* m_EventBroker = nullptr;
diff --git a/resources/Schema/Entities/NewMapWSpectatorCam.xml b/resources/Schema/Entities/NewMapWSpectatorCam.xml
index f74a4857..5e8b6bc2 100644
--- a/resources/Schema/Entities/NewMapWSpectatorCam.xml
+++ b/resources/Schema/Entities/NewMapWSpectatorCam.xml
@@ -5335,18 +5335,197 @@
Fonts/DroidSans.ttf,64
-
+
-
+
+
+
+
+
+
+
+
+
+
+
+
+ Textures/Core/UnitHexagon.png
+
+
+
+
+
+
+
+
+
+
+
+ 2
+
+
+
+
+
+ Textures/Core/UnitHexagon_Rotated.png
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Textures/Core/UnitHexagon.png
+
+
+
+
+
+
+
+
+
+
+
+ 3
+
+
+
+
+
+ Textures/Core/UnitHexagon_Rotated.png
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Textures/Core/UnitHexagon.png
+
+
+
+
+
+
+
+
+
+
+
+ 4
+
+
+
+
+
+ Textures/Core/UnitHexagon_Rotated.png
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Textures/Core/UnitHexagon.png
+
+
+
+
+
+
+
+
+
+
+
+ 1
+
+
+ 0.59265931447347009
+
+
+
+ Textures/Core/UnitHexagon_Rotated.png
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Textures/Core/UnitHexagon.png
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Textures/Core/UnitHexagon_Rotated.png
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/resources/Schema/Entities/SpectatorCamera.xml b/resources/Schema/Entities/SpectatorCamera.xml
index dbfdecf0..5c3dc514 100644
--- a/resources/Schema/Entities/SpectatorCamera.xml
+++ b/resources/Schema/Entities/SpectatorCamera.xml
@@ -19,20 +19,199 @@
-
+ Time to respawn: 0
Fonts/DroidSans.ttf,64
-
+
-
+
+
+
+
+
+
+
+
+
+
+
+
+ Textures/Core/UnitHexagon.png
+
+
+
+
+
+
+
+
+
+
+
+ 2
+
+
+
+
+
+ Textures/Core/UnitHexagon_Rotated.png
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Textures/Core/UnitHexagon.png
+
+
+
+
+
+
+
+
+
+
+
+ 3
+
+
+
+
+
+ Textures/Core/UnitHexagon_Rotated.png
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Textures/Core/UnitHexagon.png
+
+
+
+
+
+
+
+
+
+
+
+ 4
+
+
+
+
+
+ Textures/Core/UnitHexagon_Rotated.png
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Textures/Core/UnitHexagon.png
+
+
+
+
+
+
+
+
+
+
+
+ 1
+
+
+ 0.59265931447347009
+
+
+
+ Textures/Core/UnitHexagon_Rotated.png
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Textures/Core/UnitHexagon.png
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Textures/Core/UnitHexagon_Rotated.png
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/Engine/Core/World.cpp b/src/Engine/Core/World.cpp
index 9b323ff4..65bc60d2 100644
--- a/src/Engine/Core/World.cpp
+++ b/src/Engine/Core/World.cpp
@@ -1,6 +1,7 @@
#include "Core/World.h"
#include "Core/EEntityDeleted.h"
#include "Core/EComponentDeleted.h"
+#include "Core/EntityWrapper.h"
World::~World()
{
@@ -151,6 +152,23 @@ std::string World::GetName(EntityID entity) const
}
}
+EntityWrapper World::GetFirstEntityByName(const std::string& name)
+{
+ auto itPair = GetDirectChildren(EntityID_Invalid);
+ for (auto it = itPair.first; it != itPair.second; it++) {
+ EntityID childEntityID = it->second;
+ EntityWrapper childEntity(this, childEntityID);
+ if (!childEntity.Valid()) {
+ continue;
+ }
+ EntityWrapper entityWithName = childEntity.Name() == name ? childEntity : childEntity.FirstChildByName(name);
+ if (entityWithName.Valid()) {
+ return entityWithName;
+ }
+ }
+ return EntityWrapper::Invalid;
+}
+
EntityID World::generateEntityID()
{
// TODO: Make EntityID generation smarter
diff --git a/src/Game/Systems/PlayerDeathSystem.cpp b/src/Game/Systems/PlayerDeathSystem.cpp
index f645abe7..0f05da57 100644
--- a/src/Game/Systems/PlayerDeathSystem.cpp
+++ b/src/Game/Systems/PlayerDeathSystem.cpp
@@ -74,18 +74,14 @@ bool PlayerDeathSystem::OnEntityDeleted(Events::EntityDeleted& e)
if (m_LocalPlayerDeathEffect.ID != e.DeletedEntity) {
return false;
}
- // Set the spectator camera as active, if it exists.
- auto pool = m_World->GetComponents("CapturePointGameMode");
- if (pool == nullptr || pool->size() == 0) {
- return false;
- }
- ComponentWrapper modeComponent = *pool->begin();
- EntityWrapper theLevel = EntityWrapper(m_LocalPlayerDeathEffect.World, modeComponent.EntityID);
- EntityWrapper spectatorCam = theLevel.FirstChildByName("SpectatorCamera");
- if (!spectatorCam.Valid() && spectatorCam.HasComponent("Camera")) {
+
+ // Look for the spectator camera entity in the level.
+ EntityWrapper spectatorCam = m_World->GetFirstEntityByName("SpectatorCamera");
+ if (!spectatorCam.Valid() || !spectatorCam.HasComponent("Camera") || LocalPlayer.Valid()) {
return false;
}
Events::SetCamera eSetCamera;
eSetCamera.CameraEntity = spectatorCam;
m_EventBroker->Publish(eSetCamera);
+ return true;
}
diff --git a/src/Game/Systems/PlayerSpawnSystem.cpp b/src/Game/Systems/PlayerSpawnSystem.cpp
index 2f6928af..b2bb1ecf 100644
--- a/src/Game/Systems/PlayerSpawnSystem.cpp
+++ b/src/Game/Systems/PlayerSpawnSystem.cpp
@@ -27,8 +27,7 @@ void PlayerSpawnSystem::Update(double dt)
double& timer = (double&)modeComponent["RespawnTime"];
timer += dt;
double maxRespawnTime = m_DbgConfigForceRespawn ? m_ForcedRespawnTime : (double)modeComponent["MaxRespawnTime"];
- EntityWrapper theLevel = EntityWrapper(m_World, modeComponent.EntityID);
- EntityWrapper spectatorCam = theLevel.FirstChildByName("SpectatorCamera");
+ EntityWrapper spectatorCam = m_World->GetFirstEntityByName("SpectatorCamera");
if (spectatorCam.Valid()) {
EntityWrapper HUD = spectatorCam.FirstChildByName("SpectatorHUD");
if (HUD.Valid()) {
@@ -66,7 +65,14 @@ void PlayerSpawnSystem::Update(double dt)
// If the spawner has a team affiliation, check it
if (spawner.HasComponent("Team")) {
- if ((int)spawner["Team"]["Team"] != req.Team) {
+ auto cSpawnerTeam = spawner["Team"];
+ if ((int)cSpawnerTeam["Team"] != req.Team) {
+ // Increase num spawned players if someone picks spectator, since it is valid to pick spectator
+ // but don't spawn anything, goto next spawnrequest.
+ if (req.Team == (int)cSpawnerTeam["Team"].Enum("Spectator")) {
+ ++numSpawnedPlayers;
+ break;
+ }
continue;
}
}
@@ -87,9 +93,9 @@ void PlayerSpawnSystem::Update(double dt)
}
}
if (numSpawnedPlayers != (int)m_SpawnRequests.size()) {
- LOG_DEBUG("%i players were supposed to be spawned, but %i was spawned.", (int)m_SpawnRequests.size(), numSpawnedPlayers);
+ LOG_DEBUG("%i players were supposed to be spawned or set as spectator, but only %i was handled.", (int)m_SpawnRequests.size(), numSpawnedPlayers);
} else {
- LOG_DEBUG("%i players were spawned.", numSpawnedPlayers);
+ LOG_DEBUG("%i players were spawned or set as spectator.", numSpawnedPlayers);
}
m_SpawnRequests.clear();
}
@@ -100,24 +106,29 @@ bool PlayerSpawnSystem::OnInputCommand(Events::InputCommand& e)
return false;
}
+ if (e.Value == 0) {
+ return false;
+ }
+
+ // A dead client should be able to swap to the spectator camera.
+ if (IsClient && !LocalPlayer.Valid()) {
+ // Set the spectator camera as active, if it exists.
+ // Find the camera.
+ EntityWrapper spectatorCam = m_World->GetFirstEntityByName("SpectatorCamera");
+ if (spectatorCam.Valid() && spectatorCam.HasComponent("Camera")) {
+ Events::SetCamera eSetCamera;
+ eSetCamera.CameraEntity = spectatorCam;
+ m_EventBroker->Publish(eSetCamera);
+ }
+ }
+
// Team picks should be processed ONLY server-side!
// Don't make a spawn request if we're the client.
if (!IsServer && m_NetworkEnabled) {
return false;
}
- if (e.Value == 0) {
- return false;
- }
-
- //TODO: Spectating?
- //Right now, return if someone picks spectator.
- //1 signifies spectator here, could not get Playerteam component since it may be invalid or without team comp.
- if ((ComponentInfo::EnumType)e.Value == 1) {
- return false;
- }
-
- //Check if the player already requested spawn.
+ // Check if the player already requested spawn.
auto iter = m_SpawnRequests.begin();
for (; iter != m_SpawnRequests.end(); ++iter) {
if (iter->PlayerID == e.PlayerID) {
@@ -126,11 +137,11 @@ bool PlayerSpawnSystem::OnInputCommand(Events::InputCommand& e)
}
if (iter != m_SpawnRequests.end()) {
- //If player is in queue to spawn, then change their team affiliation in the request.
+ // If player is in queue to spawn, then change their team affiliation in the request.
iter->Team = (ComponentInfo::EnumType)e.Value;
} else if (m_PlayerEntities.count(e.PlayerID) == 0 || !m_PlayerEntities[e.PlayerID].Valid()) {
- //If player is not in queue to spawn, then create a spawn request,
- //but only if they are spectating and/or just connected.
+ // If player is not in queue to spawn, then create a spawn request,
+ // but only if they are spectating and/or just connected.
SpawnRequest req;
req.PlayerID = e.PlayerID;
req.Team = (ComponentInfo::EnumType)e.Value;