Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/game/server/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -1400,6 +1400,8 @@ target_sources_grouped(
neo/neo_player.h
neo/neo_smokelineofsightblocker.cpp
neo/neo_smokelineofsightblocker.h
neo/neo_spawn_manager.cpp
neo/neo_spawn_manager.h
neo/neo_smokegrenade.cpp
neo/neo_smokegrenade.h
neo/neo_te_tocflash.cpp
Expand Down
12 changes: 12 additions & 0 deletions src/game/server/gameinterface.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,10 @@ extern ConVar tf_mm_servermode;
#include "NextBotManager.h"
#endif

#ifdef NEO
#include "neo_spawn_manager.h"
#endif

#ifdef USES_ECON_ITEMS
#include "econ_item_system.h"
#endif // USES_ECON_ITEMS
Expand Down Expand Up @@ -1180,6 +1184,10 @@ void CServerGameDLL::ServerActivate( edict_t *pEdictList, int edictCount, int cl
#ifdef NEXT_BOT
TheNextBots().OnMapLoaded();
#endif

#ifdef NEO
NeoSpawnManager::Init();
#endif
}

//-----------------------------------------------------------------------------
Expand Down Expand Up @@ -1448,6 +1456,10 @@ void CServerGameDLL::LevelShutdown( void )
}
#endif
#endif

#ifdef NEO
NeoSpawnManager::Deinit();
#endif
}

//-----------------------------------------------------------------------------
Expand Down
31 changes: 2 additions & 29 deletions src/game/server/neo/neo_player.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
#include "neo_player_shared.h"
#include "bot/neo_bot.h"
#include "nav_mesh.h"
#include "neo_spawn_manager.h"

// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
Expand Down Expand Up @@ -2917,35 +2918,7 @@ CBaseEntity* CNEO_Player::EntSelectSpawnPoint( void )
}
}

pSpot = pLastSpawnPoint;
// Randomize the start spot
for (int i = random->RandomInt(1, 5); i > 0; i--)
pSpot = gEntList.FindEntityByClassname(pSpot, pSpawnpointName);
if (!pSpot) // skip over the null point
pSpot = gEntList.FindEntityByClassname(pSpot, pSpawnpointName);

CBaseEntity *pFirstSpot = pSpot;

do
{
if (pSpot)
{
// check if pSpot is valid
if (g_pGameRules->IsSpawnPointValid(pSpot, this))
{
if (pSpot->GetLocalOrigin() == vec3_origin)
{
pSpot = gEntList.FindEntityByClassname(pSpot, pSpawnpointName);
continue;
}

// if so, go to pSpot
goto ReturnSpot;
}
}
// increment pSpot
pSpot = gEntList.FindEntityByClassname(pSpot, pSpawnpointName);
} while (pSpot != pFirstSpot); // loop if we're not back to the start
pSpot = NeoSpawnManager::RequestSpawn(GetTeamNumber(), this);

// we haven't found a place to spawn yet, so kill any guy at the first spawn point and spawn there
if (pSpot)
Expand Down
130 changes: 130 additions & 0 deletions src/game/server/neo/neo_spawn_manager.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
#include "neo_spawn_manager.h"

#include <GameEventListener.h>
#include <ehandle.h>
#include <utlvector.h>

#include "neo_gamerules.h"
#include "neo_player_spawnpoint.h"

// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"

struct SpawnInfo
{
CHandle<CNEOSpawnPoint> handle;
bool isUsed; // Whether this spawn point has been spawned into for the current round.
};

class CBasePlayer;

class CNEO_SpawnManager : public CGameEventListener
{
public:
CNEO_SpawnManager();
CNEOSpawnPoint* RequestSpawn(int team, CBasePlayer* player);
virtual void FireGameEvent(IGameEvent* event) override final;

CUtlVector<SpawnInfo> m_spawns;
} manager;

CNEO_SpawnManager::CNEO_SpawnManager()
{
m_spawns.EnsureCapacity(MAX_PLAYERS);
}

void CNEO_SpawnManager::FireGameEvent(IGameEvent* event)
{
Assert(!V_strcmp("round_start", event->GetName()));
for (int i = 0; i < manager.m_spawns.Count(); ++i)
{
auto& spawn = manager.m_spawns[i];
if (!spawn.handle || !spawn.handle.IsValid())
manager.m_spawns.Remove(i--);
else
spawn.isUsed = false;
}
manager.m_spawns.Shuffle();
}

namespace NeoSpawnManager
{
void Init()
{
manager.ListenForGameEvent("round_start");
}

void Deinit()
{
manager.StopListeningForAllEvents();
}

CNEOSpawnPoint* RequestSpawn(int team, CBasePlayer* player)
{
// Nothing we can do to salvage this... This will fall back
// to spawning at info_player_start or related logic in the caller.
if (manager.m_spawns.IsEmpty())
return nullptr;

auto rules = NEORules();
if (!rules)
{
Assert(false);
return nullptr;
}

CNEOSpawnPoint* backup = nullptr;
auto idx = manager.m_spawns.FindPredicate(
[rules, team, player, &backup](const auto& spawn)->bool
{
if (!spawn.handle || !spawn.handle.IsValid())
{
Assert(false);
return false;
}

if (team != spawn.handle.Get()->GetOwningTeam())
return false;

// We know this spawn is valid and belongs to our team.
// Save it as backup, just in case we can't find a good fresh spawn.
backup = spawn.handle;

if (spawn.isUsed)
return false;

if (!rules->IsSpawnPointValid(spawn.handle, player))
return false;

return true;
});

if (idx == manager.m_spawns.InvalidIndex())
{
// If we didn't find any free capzones, at least return an overlapping one.
// This can happen for maps with too few capzones for the amount of (re)spawns occurring.
// Can be nullptr if we got >0 spawns but none of them were considered valid,
// in which case it's up to the caller to handle.
return backup;
}

manager.m_spawns[idx].isUsed = true;
return manager.m_spawns[idx].handle;
}

void Register(CNEOSpawnPoint* spawn)
{
manager.m_spawns.AddToTail({
.handle{spawn},
.isUsed{false}});
}
void Unregister(CNEOSpawnPoint* spawn)
{
auto idx = manager.m_spawns.FindPredicate([spawn](const auto& s)->bool
{
return spawn == s.handle;
});
if (idx != manager.m_spawns.InvalidIndex())
manager.m_spawns.Remove(idx);
}
}
15 changes: 15 additions & 0 deletions src/game/server/neo/neo_spawn_manager.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
#pragma once

#include "neo_player_spawnpoint.h"

class CBasePlayer;
class CNEOSpawnPoint;
namespace NeoSpawnManager
{
CNEOSpawnPoint* RequestSpawn(int team, CBasePlayer* player);

void Init();
void Deinit();
void Register(CNEOSpawnPoint*);
void Unregister(CNEOSpawnPoint*);
};
2 changes: 1 addition & 1 deletion src/game/shared/gamerules.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -236,7 +236,7 @@ bool CGameRules::IsSpawnPointValid( CBaseEntity *pSpot, CBasePlayer *pPlayer )
CBaseEntity *ent = NULL;

#if defined NEO && defined GAME_DLL
if ( auto* pNEOSpot = dynamic_cast<CNEOSpawnPoint*>( pSpot ) )
if ( auto* pNEOSpot = assert_cast<CNEOSpawnPoint*>( pSpot ) )
{
if ( pNEOSpot->m_bDisabled )
{
Expand Down
12 changes: 11 additions & 1 deletion src/game/shared/neo/neo_player_spawnpoint.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@

#include "neo_gamerules.h"

#ifdef GAME_DLL
#include "neo_spawn_manager.h"
#endif

// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"

Expand Down Expand Up @@ -56,7 +60,9 @@ CNEOSpawnPoint::CNEOSpawnPoint()

CNEOSpawnPoint::~CNEOSpawnPoint()
{

#ifdef GAME_DLL
NeoSpawnManager::Unregister(this);
#endif
}

void CNEOSpawnPoint::Spawn()
Expand All @@ -71,6 +77,10 @@ void CNEOSpawnPoint::Spawn()
(m_iOwningTeam == TEAM_JINRAI ? "Jinrai" : "NSF"),
GetAbsOrigin().x, GetAbsOrigin().y, GetAbsOrigin().z);
#endif

#ifdef GAME_DLL
NeoSpawnManager::Register(this);
#endif
}

#ifdef GAME_DLL
Expand Down
4 changes: 3 additions & 1 deletion src/game/shared/neo/neo_player_spawnpoint.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#pragma once
#endif

#include "cbase.h"
#include "baseentity_shared.h"
#include "baseplayer_shared.h"

Expand All @@ -26,7 +27,8 @@ class CNEOSpawnPoint : public CBaseEntity
CNEOSpawnPoint();
~CNEOSpawnPoint();

virtual void Spawn();
virtual void Spawn() override;
int GetOwningTeam() const { return m_iOwningTeam; }

#ifdef GAME_DLL
bool m_bDisabled;
Expand Down
Loading