mirror of
https://github.com/s1lentq/ReGameDLL_CS.git
synced 2025-04-05 09:19:00 +03:00
ZBot: Implemented immediate reloading of nav data after bot analysis, without requiring a full map restart
ZBot: Added cleanup for dangling navigation pointers in bots, enabling seamless map reanalysis Minor refactoring
This commit is contained in:
parent
f5cc6f3a8b
commit
6f70d6dd8e
@ -900,3 +900,129 @@ float CCSBot::GetRangeToFarthestEscortedHostage() const
|
||||
|
||||
return away.m_farRange;
|
||||
}
|
||||
|
||||
// Remove all occurrences of a given area from the path list
|
||||
void CCSBot::RemovePath(CNavArea *area)
|
||||
{
|
||||
int i = 0;
|
||||
while (i < m_pathLength)
|
||||
{
|
||||
if (m_path[i].area == area)
|
||||
{
|
||||
// If this area is linked to a ladder, clear the reference
|
||||
if (m_path[i].ladder == m_pathLadder)
|
||||
m_pathLadder = nullptr;
|
||||
|
||||
m_pathLength--;
|
||||
|
||||
// adjust the current path index if the removed element is being used
|
||||
if (i == m_pathIndex)
|
||||
{
|
||||
if (i > 0)
|
||||
m_pathIndex = i - 1;
|
||||
else
|
||||
m_pathIndex = 0;
|
||||
}
|
||||
|
||||
if (m_pathLength != i)
|
||||
Q_memmove(&m_path[i], &m_path[i + 1], (m_pathLength - i) * sizeof(m_path[0]));
|
||||
|
||||
// clear the slot
|
||||
Q_memset(&m_path[m_pathLength], 0, sizeof(m_path[m_pathLength]));
|
||||
}
|
||||
else
|
||||
{
|
||||
i++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Remove a hiding spot from the checked spots list
|
||||
void CCSBot::RemoveHidingSpot(HidingSpot *spot)
|
||||
{
|
||||
int i = 0;
|
||||
while (i < m_pathLength)
|
||||
{
|
||||
if (m_checkedHidingSpot[i].spot == spot)
|
||||
{
|
||||
m_checkedHidingSpotCount--;
|
||||
|
||||
if (m_checkedHidingSpotCount != i)
|
||||
Q_memmove(&m_checkedHidingSpot[i], &m_checkedHidingSpot[i + 1], (m_checkedHidingSpotCount - i) * sizeof(m_checkedHidingSpot[0]));
|
||||
|
||||
// clear the slot
|
||||
Q_memset(&m_checkedHidingSpot[m_checkedHidingSpotCount], 0, sizeof(m_checkedHidingSpot[m_checkedHidingSpotCount]));
|
||||
}
|
||||
else
|
||||
{
|
||||
i++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Handle navigation-related cleanup when a nav area, spot, or encounter is destroyed
|
||||
void CCSBot::OnDestroyNavDataNotify(NavNotifyDestroyType navNotifyType, void *dead)
|
||||
{
|
||||
switch (navNotifyType)
|
||||
{
|
||||
case NAV_NOTIFY_DESTROY_AREA:
|
||||
{
|
||||
CNavArea *area = static_cast<CNavArea *>(dead);
|
||||
|
||||
// If the destroyed area was linked to a spot encounter, clear it
|
||||
if (m_spotEncounter)
|
||||
{
|
||||
if (m_spotEncounter->from.area == area || m_spotEncounter->to.area == area)
|
||||
m_spotEncounter = nullptr;
|
||||
}
|
||||
|
||||
RemovePath(area);
|
||||
|
||||
// Invalidate any references to the destroyed area
|
||||
|
||||
if (m_noiseArea == area)
|
||||
m_noiseArea = nullptr;
|
||||
|
||||
if (m_currentArea == area)
|
||||
m_currentArea = nullptr;
|
||||
|
||||
if (m_lastKnownArea == area)
|
||||
m_lastKnownArea = nullptr;
|
||||
|
||||
if (m_hideState.GetSearchArea() == area)
|
||||
m_hideState.SetSearchArea(nullptr);
|
||||
|
||||
if (m_huntState.GetHuntArea() == area)
|
||||
m_huntState.ClearHuntArea();
|
||||
|
||||
break;
|
||||
}
|
||||
case NAV_NOTIFY_DESTROY_SPOT_ENCOUNTER:
|
||||
{
|
||||
CNavArea *area = static_cast<CNavArea *>(dead);
|
||||
|
||||
// Remove the encounter if it references the destroyed area
|
||||
if (m_spotEncounter && area->HasSpotEncounter(m_spotEncounter))
|
||||
m_spotEncounter = nullptr;
|
||||
|
||||
break;
|
||||
}
|
||||
case NAV_NOTIFY_DESTROY_SPOT:
|
||||
{
|
||||
HidingSpot *spot = static_cast<HidingSpot *>(dead);
|
||||
|
||||
// Remove the destroyed hiding spot from the spot order list
|
||||
if (m_spotEncounter)
|
||||
{
|
||||
SpotOrderList &spotOrderList = m_spotEncounter->spotList;
|
||||
spotOrderList.erase(std::remove_if(spotOrderList.begin(), spotOrderList.end(), [&](SpotOrder &spotOrder) {
|
||||
return spotOrder.spot == spot;
|
||||
}
|
||||
), spotOrderList.end());
|
||||
}
|
||||
|
||||
RemoveHidingSpot(spot);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -71,6 +71,7 @@ public:
|
||||
virtual const char *GetName() const { return "Hunt"; }
|
||||
|
||||
void ClearHuntArea() { m_huntArea = nullptr; }
|
||||
CNavArea *GetHuntArea() { return m_huntArea; }
|
||||
|
||||
private:
|
||||
CNavArea *m_huntArea;
|
||||
@ -204,6 +205,7 @@ public:
|
||||
const Vector &GetHidingSpot() const { return m_hidingSpot; }
|
||||
|
||||
void SetSearchArea(CNavArea *area) { m_searchFromArea = area; }
|
||||
CNavArea *GetSearchArea() { return m_searchFromArea; }
|
||||
void SetSearchRange(float range) { m_range = range; }
|
||||
|
||||
void SetDuration(float time) { m_duration = time; }
|
||||
@ -544,6 +546,10 @@ public:
|
||||
|
||||
float GetFeetZ() const; // return Z of bottom of feet
|
||||
|
||||
void OnDestroyNavDataNotify(NavNotifyDestroyType navNotifyType, void *dead);
|
||||
void RemovePath(CNavArea *area);
|
||||
void RemoveHidingSpot(HidingSpot *spot);
|
||||
|
||||
enum PathResult
|
||||
{
|
||||
PROGRESSING, // we are moving along the path
|
||||
|
@ -337,7 +337,7 @@ void CCSBot::ResetValues()
|
||||
// NOTE: For some reason, this can be called twice when a bot is added.
|
||||
void CCSBot::SpawnBot()
|
||||
{
|
||||
TheCSBots()->ValidateMapData();
|
||||
TheCSBots()->LoadNavigationMap();
|
||||
ResetValues();
|
||||
|
||||
Q_strlcpy(m_name, STRING(pev->netname));
|
||||
|
@ -477,31 +477,24 @@ void CCSBot::StartSaveProcess()
|
||||
|
||||
void CCSBot::UpdateSaveProcess()
|
||||
{
|
||||
char msg[256];
|
||||
char cmd[128];
|
||||
|
||||
char gd[64]{};
|
||||
GET_GAME_DIR(gd);
|
||||
|
||||
char filename[MAX_OSPATH];
|
||||
Q_snprintf(filename, sizeof(filename), "%s\\%s", gd, TheBots->GetNavMapFilename());
|
||||
|
||||
HintMessageToAllPlayers("Saving...");
|
||||
SaveNavigationMap(filename);
|
||||
|
||||
char msg[256]{};
|
||||
Q_snprintf(msg, sizeof(msg), "Navigation file '%s' saved.", filename);
|
||||
HintMessageToAllPlayers(msg);
|
||||
CONSOLE_ECHO("%s\n", msg);
|
||||
|
||||
hideProgressMeter();
|
||||
StartNormalProcess();
|
||||
|
||||
#ifndef REGAMEDLL_FIXES
|
||||
Q_snprintf(cmd, sizeof(cmd), "map %s\n", STRING(gpGlobals->mapname));
|
||||
#else
|
||||
Q_snprintf(cmd, sizeof(cmd), "changelevel %s\n", STRING(gpGlobals->mapname));
|
||||
#endif
|
||||
|
||||
SERVER_COMMAND(cmd);
|
||||
// tell bot manager that the analysis is completed
|
||||
if (TheCSBots())
|
||||
TheCSBots()->AnalysisCompleted();
|
||||
}
|
||||
|
||||
void CCSBot::StartNormalProcess()
|
||||
|
@ -231,13 +231,12 @@ bool CCSBotManager::IsOnOffense(CBasePlayer *pPlayer) const
|
||||
// Invoked when a map has just been loaded
|
||||
void CCSBotManager::ServerActivate()
|
||||
{
|
||||
DestroyNavigationMap();
|
||||
m_isMapDataLoaded = false;
|
||||
|
||||
m_zoneCount = 0;
|
||||
m_gameScenario = SCENARIO_DEATHMATCH;
|
||||
|
||||
ValidateMapData();
|
||||
LoadNavigationMap();
|
||||
RestartRound();
|
||||
|
||||
m_isLearningMap = false;
|
||||
@ -591,7 +590,8 @@ void CCSBotManager::ServerCommand(const char *pcmd)
|
||||
}
|
||||
else if (FStrEq(pcmd, "bot_nav_load"))
|
||||
{
|
||||
ValidateMapData();
|
||||
m_isMapDataLoaded = false; // force nav reload
|
||||
LoadNavigationMap();
|
||||
}
|
||||
else if (FStrEq(pcmd, "bot_nav_use_place"))
|
||||
{
|
||||
@ -1144,7 +1144,6 @@ private:
|
||||
CCSBotManager::Zone *m_zone;
|
||||
};
|
||||
|
||||
#ifdef REGAMEDLL_ADD
|
||||
LINK_ENTITY_TO_CLASS(info_spawn_point, CPointEntity, CCSPointEntity)
|
||||
|
||||
inline bool IsFreeSpace(Vector vecOrigin, int iHullNumber, edict_t *pSkipEnt = nullptr)
|
||||
@ -1163,6 +1162,9 @@ inline bool pointInRadius(Vector vecOrigin, float radius)
|
||||
CBaseEntity *pEntity = nullptr;
|
||||
while ((pEntity = UTIL_FindEntityInSphere(pEntity, vecOrigin, radius)))
|
||||
{
|
||||
if (!UTIL_IsValidEntity(pEntity->edict()))
|
||||
continue; // ignore the entity marked for deletion
|
||||
|
||||
if (FClassnameIs(pEntity->edict(), "info_spawn_point"))
|
||||
return true;
|
||||
}
|
||||
@ -1171,12 +1173,10 @@ inline bool pointInRadius(Vector vecOrigin, float radius)
|
||||
}
|
||||
|
||||
// a simple algorithm that searches for the farthest point (so that the player does not look at the wall)
|
||||
inline Vector GetBestAngle(const Vector &vecStart)
|
||||
inline bool GetIdealLookYawForSpawnPoint(const Vector &vecStart, float &flIdealLookYaw)
|
||||
{
|
||||
const float ANGLE_STEP = 30.0f;
|
||||
float bestAngle = 0.0f;
|
||||
float bestDistance = 0.0f;
|
||||
Vector vecBestAngle = Vector(0, -1, 0);
|
||||
|
||||
for (float angleYaw = 0.0f; angleYaw <= 360.0f; angleYaw += ANGLE_STEP)
|
||||
{
|
||||
@ -1187,15 +1187,14 @@ inline Vector GetBestAngle(const Vector &vecStart)
|
||||
UTIL_TraceLine(vecStart, vecEnd, ignore_monsters, nullptr, &tr);
|
||||
|
||||
float distance = (vecStart - tr.vecEndPos).Length();
|
||||
|
||||
if (distance > bestDistance)
|
||||
{
|
||||
bestDistance = distance;
|
||||
vecBestAngle.y = angleYaw;
|
||||
flIdealLookYaw = angleYaw;
|
||||
}
|
||||
}
|
||||
|
||||
return vecBestAngle;
|
||||
return bestDistance > 0.0f;
|
||||
}
|
||||
|
||||
// this function from leaked csgo sources 2020y
|
||||
@ -1231,58 +1230,69 @@ inline bool IsValidArea(CNavArea *area)
|
||||
return false;
|
||||
}
|
||||
|
||||
void GetSpawnPositions()
|
||||
{
|
||||
const float MIN_AREA_SIZE = 32.0f;
|
||||
const int MAX_SPAWNS_POINTS = 128;
|
||||
const float MAX_SLOPE = 0.85f;
|
||||
#ifdef REGAMEDLL_ADD
|
||||
|
||||
// Generates spawn points (info_spawn_point entities) for players and bots based on the navigation map data
|
||||
// It uses the navigation areas to find valid spots for spawn points considering factors like area size, slope,
|
||||
// available free space, and distance from other spawn points.
|
||||
void GenerateSpawnPointsFromNavData()
|
||||
{
|
||||
// Remove any existing spawn points
|
||||
UTIL_RemoveOther("info_spawn_point");
|
||||
|
||||
const int MAX_SPAWNS_POINTS = 128; // Max allowed spawn points
|
||||
|
||||
const float MAX_SLOPE = 0.85f; // Maximum slope allowed for a spawn point
|
||||
const float MIN_AREA_SIZE = 32.0f; // Minimum area size for a valid spawn point
|
||||
const float MIN_NEARBY_SPAWNPOINT = 128.0f; // Minimum distance between spawn point
|
||||
|
||||
// Total number of spawn points generated
|
||||
int totalSpawns = 0;
|
||||
|
||||
for (NavAreaList::iterator iter = TheNavAreaList.begin(); iter != TheNavAreaList.end(); iter++)
|
||||
for (CNavArea *area : TheNavAreaList)
|
||||
{
|
||||
if (totalSpawns >= MAX_SPAWNS_POINTS)
|
||||
break;
|
||||
|
||||
CNavArea *area = *iter;
|
||||
|
||||
if (!area)
|
||||
continue;
|
||||
|
||||
// ignore small areas
|
||||
// Skip areas that are too small
|
||||
if (area->GetSizeX() < MIN_AREA_SIZE || area->GetSizeY() < MIN_AREA_SIZE)
|
||||
continue;
|
||||
|
||||
// ignore areas jump, crouch etc
|
||||
if (area->GetAttributes())
|
||||
// Skip areas with unwanted attributes (jump, crouch, etc.)
|
||||
if (area->GetAttributes() != 0)
|
||||
continue;
|
||||
|
||||
// Skip areas with steep slopes
|
||||
if (area->GetAreaSlope() < MAX_SLOPE)
|
||||
{
|
||||
//CONSOLE_ECHO("Skip area slope: %0.3f\n", area->GetAreaSlope());
|
||||
continue;
|
||||
}
|
||||
|
||||
// Calculate the spawn point position above the area center
|
||||
Vector vecOrigin = *area->GetCenter() + Vector(0, 0, HalfHumanHeight + 5);
|
||||
|
||||
// Ensure there is free space at the calculated position
|
||||
if (!IsFreeSpace(vecOrigin, human_hull))
|
||||
{
|
||||
//CONSOLE_ECHO("No free space!\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (pointInRadius(vecOrigin, 128.0f))
|
||||
continue;
|
||||
if (pointInRadius(vecOrigin, MIN_NEARBY_SPAWNPOINT))
|
||||
continue; // spawn point is too close to others
|
||||
|
||||
if (!IsValidArea(area))
|
||||
continue;
|
||||
|
||||
Vector bestAngle = GetBestAngle(vecOrigin);
|
||||
|
||||
if (bestAngle.y != -1)
|
||||
// Calculate ideal spawn point yaw angle
|
||||
float flIdealSpawnPointYaw = 0.0f;
|
||||
if (GetIdealLookYawForSpawnPoint(vecOrigin, flIdealSpawnPointYaw))
|
||||
{
|
||||
CBaseEntity* pPoint = CBaseEntity::Create("info_spawn_point", vecOrigin, bestAngle, nullptr);
|
||||
|
||||
CBaseEntity *pPoint = CBaseEntity::Create("info_spawn_point", vecOrigin, Vector(0, flIdealSpawnPointYaw, 0), nullptr);
|
||||
if (pPoint)
|
||||
{
|
||||
totalSpawns++;
|
||||
@ -1302,24 +1312,64 @@ void GetSpawnPositions()
|
||||
|
||||
CONSOLE_ECHO("Total spawns points: %i\n", totalSpawns);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
// Search the map entities to determine the game scenario and define important zones.
|
||||
void CCSBotManager::ValidateMapData()
|
||||
// Load the map's navigation data
|
||||
bool CCSBotManager::LoadNavigationMap()
|
||||
{
|
||||
// check if the map data is already loaded or if bots are not allowed
|
||||
if (m_isMapDataLoaded || !AreBotsAllowed())
|
||||
return;
|
||||
return false;
|
||||
|
||||
m_isMapDataLoaded = true;
|
||||
|
||||
if (LoadNavigationMap())
|
||||
// Clear navigation map data from previous map
|
||||
DestroyNavigationMap();
|
||||
|
||||
// Try to load the map's navigation file
|
||||
NavErrorType navStatus = ::LoadNavigationMap();
|
||||
if (navStatus != NAV_OK)
|
||||
{
|
||||
CONSOLE_ECHO("Failed to load navigation map.\n");
|
||||
return;
|
||||
CONSOLE_ECHO("ERROR: Failed to load 'maps/%s.nav' file navigation map!\n", STRING(gpGlobals->mapname));
|
||||
|
||||
switch (navStatus)
|
||||
{
|
||||
case NAV_CANT_ACCESS_FILE:
|
||||
CONSOLE_ECHO("\tNavigation file not found or access denied.\n");
|
||||
break;
|
||||
case NAV_INVALID_FILE:
|
||||
CONSOLE_ECHO("\tInvalid navigation file format.\n");
|
||||
break;
|
||||
case NAV_BAD_FILE_VERSION:
|
||||
CONSOLE_ECHO("\tBad navigation file version.\n");
|
||||
break;
|
||||
case NAV_CORRUPT_DATA:
|
||||
CONSOLE_ECHO("\tCorrupted navigation data detected.\n");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (navStatus != NAV_CANT_ACCESS_FILE)
|
||||
CONSOLE_ECHO("\tTry regenerating it using the command: bot_nav_analyze\n");
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
CONSOLE_ECHO("Navigation map loaded.\n");
|
||||
// Determine the scenario for the current map (e.g., bomb defuse, hostage rescue etc)
|
||||
DetermineMapScenario();
|
||||
|
||||
#ifdef REGAMEDLL_ADD
|
||||
GenerateSpawnPointsFromNavData();
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Search the map entities to determine the game scenario and define important zones.
|
||||
void CCSBotManager::DetermineMapScenario()
|
||||
{
|
||||
m_zoneCount = 0;
|
||||
m_gameScenario = SCENARIO_DEATHMATCH;
|
||||
|
||||
@ -1459,6 +1509,59 @@ void CCSBotManager::ValidateMapData()
|
||||
}
|
||||
}
|
||||
|
||||
// Tell all bots that the given nav data no longer exists
|
||||
// This function is called when a part of the map or the nav data is destroyed
|
||||
void CCSBotManager::OnDestroyNavDataNotify(NavNotifyDestroyType navNotifyType, void *dead)
|
||||
{
|
||||
for (int i = 1; i <= gpGlobals->maxClients; i++)
|
||||
{
|
||||
CBasePlayer *pPlayer = UTIL_PlayerByIndex(i);
|
||||
|
||||
if (!UTIL_IsValidPlayer(pPlayer))
|
||||
continue;
|
||||
|
||||
if (!pPlayer->IsBot())
|
||||
continue;
|
||||
|
||||
// Notify the bot about the destroyed nav data
|
||||
CCSBot *pBot = static_cast<CCSBot *>(pPlayer);
|
||||
pBot->OnDestroyNavDataNotify(navNotifyType, dead);
|
||||
}
|
||||
}
|
||||
|
||||
// Called when the map analysis process has completed
|
||||
// This function makes sure all bots are removed from the map analysis process
|
||||
// and are reset to normal bot behavior. It also reloads the navigation map
|
||||
// and triggers a game restart after the analysis is completed
|
||||
void CCSBotManager::AnalysisCompleted()
|
||||
{
|
||||
// Ensure that all bots are no longer involved in map analysis and start their normal process
|
||||
for (int i = 1; i <= gpGlobals->maxClients; i++)
|
||||
{
|
||||
CBasePlayer *pPlayer = UTIL_PlayerByIndex(i);
|
||||
|
||||
if (!UTIL_IsValidPlayer(pPlayer))
|
||||
continue;
|
||||
|
||||
if (!pPlayer->IsBot())
|
||||
continue;
|
||||
|
||||
CCSBot *pBot = static_cast<CCSBot *>(pPlayer);
|
||||
pBot->StartNormalProcess();
|
||||
}
|
||||
|
||||
m_isLearningMap = false;
|
||||
m_isMapDataLoaded = false;
|
||||
m_isAnalysisRequested = false;
|
||||
|
||||
// Try to reload the navigation map from the file
|
||||
if (LoadNavigationMap())
|
||||
{
|
||||
// Initiate a game restart in 3 seconds
|
||||
CVAR_SET_FLOAT("sv_restart", 3);
|
||||
}
|
||||
}
|
||||
|
||||
bool CCSBotManager::AddBot(const BotProfile *profile, BotProfileTeamType team)
|
||||
{
|
||||
if (!AreBotsAllowed())
|
||||
|
@ -56,13 +56,16 @@ public:
|
||||
virtual bool IsImportantPlayer(CBasePlayer *pPlayer) const; // return true if pPlayer is important to scenario (VIP, bomb carrier, etc)
|
||||
|
||||
public:
|
||||
void ValidateMapData();
|
||||
bool LoadNavigationMap();
|
||||
void DetermineMapScenario();
|
||||
void OnFreeEntPrivateData(CBaseEntity *pEntity);
|
||||
void OnDestroyNavDataNotify(NavNotifyDestroyType navNotifyType, void *dead);
|
||||
bool IsLearningMap() const { return m_isLearningMap; }
|
||||
void SetLearningMapFlag() { m_isLearningMap = true; }
|
||||
bool IsAnalysisRequested() const { return m_isAnalysisRequested; }
|
||||
void RequestAnalysis() { m_isAnalysisRequested = true; }
|
||||
void AckAnalysisRequest() { m_isAnalysisRequested = false; }
|
||||
void AnalysisCompleted();
|
||||
|
||||
// difficulty levels
|
||||
static BotDifficultyType GetDifficultyLevel()
|
||||
@ -269,6 +272,4 @@ inline bool AreBotsAllowed()
|
||||
}
|
||||
|
||||
void PrintAllEntities();
|
||||
#ifdef REGAMEDLL_ADD
|
||||
void GetSpawnPositions();
|
||||
#endif
|
||||
void GenerateSpawnPointsFromNavData();
|
||||
|
@ -1003,7 +1003,7 @@ CBasePlayer *CCSBot::FindMostDangerousThreat()
|
||||
return currentThreat;
|
||||
}
|
||||
|
||||
// if we are a sniper and we see a sniper threat, attack it unless
|
||||
// if we are a sniper and we see a sniper threat, attack it unless
|
||||
// there are other close enemies facing me
|
||||
if (IsSniper() && sniperThreat)
|
||||
{
|
||||
|
@ -844,7 +844,7 @@ void Host_Say(edict_t *pEntity, BOOL teamonly)
|
||||
#ifdef REGAMEDLL_ADD
|
||||
// there's no team on FFA mode
|
||||
if (teamonly && CSGameRules()->IsFreeForAll() && (pPlayer->m_iTeam == CT || pPlayer->m_iTeam == TERRORIST))
|
||||
teamonly = FALSE;
|
||||
teamonly = FALSE;
|
||||
#endif
|
||||
|
||||
// team only
|
||||
@ -1001,7 +1001,7 @@ void Host_Say(edict_t *pEntity, BOOL teamonly)
|
||||
if (gpGlobals->deathmatch != 0.0f && CSGameRules()->m_VoiceGameMgr.PlayerHasBlockedPlayer(pReceiver, pPlayer))
|
||||
continue;
|
||||
|
||||
if (teamonly
|
||||
if (teamonly
|
||||
#ifdef REGAMEDLL_FIXES
|
||||
&& CSGameRules()->PlayerRelationship(pPlayer, pReceiver) != GR_TEAMMATE
|
||||
#else
|
||||
@ -1020,7 +1020,7 @@ void Host_Say(edict_t *pEntity, BOOL teamonly)
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((pReceiver->m_iIgnoreGlobalChat == IGNOREMSG_ENEMY
|
||||
if ((pReceiver->m_iIgnoreGlobalChat == IGNOREMSG_ENEMY
|
||||
#ifdef REGAMEDLL_FIXES
|
||||
&& CSGameRules()->PlayerRelationship(pPlayer, pReceiver) == GR_TEAMMATE
|
||||
#else
|
||||
@ -3833,11 +3833,6 @@ void EXT_FUNC ServerActivate(edict_t *pEdictList, int edictCount, int clientMax)
|
||||
|
||||
#ifdef REGAMEDLL_ADD
|
||||
CSGameRules()->ServerActivate();
|
||||
|
||||
if (LoadNavigationMap() == NAV_OK)
|
||||
{
|
||||
GetSpawnPositions();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -174,9 +174,9 @@ cvar_t freezetime_duck = { "mp_freezetime_duck", "1", 0, 1.0f,
|
||||
cvar_t freezetime_jump = { "mp_freezetime_jump", "1", 0, 1.0f, nullptr };
|
||||
cvar_t jump_height = { "mp_jump_height", "45", FCVAR_SERVER, 45.0f, nullptr };
|
||||
|
||||
cvar_t hostages_rescued_ratio = { "mp_hostages_rescued_ratio", "1.0", 0, 1.0f, nullptr };
|
||||
cvar_t hostages_rescued_ratio = { "mp_hostages_rescued_ratio", "1.0", 0, 1.0f, nullptr };
|
||||
|
||||
cvar_t legacy_vehicle_block = { "mp_legacy_vehicle_block", "1", 0, 0.0f, nullptr };
|
||||
cvar_t legacy_vehicle_block = { "mp_legacy_vehicle_block", "1", 0, 0.0f, nullptr };
|
||||
|
||||
cvar_t dying_time = { "mp_dying_time", "3.0", 0, 3.0f, nullptr };
|
||||
cvar_t defuser_allocation = { "mp_defuser_allocation", "0", 0, 0.0f, nullptr };
|
||||
|
@ -5594,7 +5594,9 @@ CTSpawn:
|
||||
// The terrorist spawn points
|
||||
else if (g_pGameRules->IsDeathmatch() && m_iTeam == TERRORIST)
|
||||
{
|
||||
#ifdef REGAMEDLL_ADD
|
||||
TSpawn:
|
||||
#endif
|
||||
pSpot = g_pLastTerroristSpawn;
|
||||
|
||||
if (SelectSpawnSpot("info_player_deathmatch", pSpot))
|
||||
|
@ -1464,7 +1464,7 @@ void UTIL_Remove(CBaseEntity *pEntity)
|
||||
pEntity->pev->targetname = 0;
|
||||
}
|
||||
|
||||
NOXREF BOOL UTIL_IsValidEntity(edict_t *pent)
|
||||
BOOL UTIL_IsValidEntity(edict_t *pent)
|
||||
{
|
||||
if (!pent || pent->free || (pent->v.flags & FL_KILLME))
|
||||
return FALSE;
|
||||
|
@ -71,6 +71,13 @@ enum NavAttributeType
|
||||
NAV_NO_JUMP = 0x08, // inhibit discontinuity jumping
|
||||
};
|
||||
|
||||
enum NavNotifyDestroyType
|
||||
{
|
||||
NAV_NOTIFY_DESTROY_AREA,
|
||||
NAV_NOTIFY_DESTROY_SPOT,
|
||||
NAV_NOTIFY_DESTROY_SPOT_ENCOUNTER
|
||||
};
|
||||
|
||||
enum NavDirType
|
||||
{
|
||||
NORTH = 0,
|
||||
|
@ -72,17 +72,29 @@ NOXREF void buildGoodSizedList()
|
||||
|
||||
void DestroyHidingSpots()
|
||||
{
|
||||
// remove all hiding spot references from the nav areas
|
||||
for (auto area : TheNavAreaList)
|
||||
area->m_hidingSpotList.clear();
|
||||
|
||||
HidingSpot::m_nextID = 0;
|
||||
|
||||
// free all the HidingSpots
|
||||
for (auto spot : TheHidingSpotList)
|
||||
for (HidingSpot *spot : TheHidingSpotList)
|
||||
{
|
||||
TheCSBots()->OnDestroyNavDataNotify(NAV_NOTIFY_DESTROY_SPOT, spot);
|
||||
delete spot;
|
||||
}
|
||||
|
||||
TheHidingSpotList.clear();
|
||||
|
||||
// remove all hiding spot references from the nav areas
|
||||
for (CNavArea *area : TheNavAreaList)
|
||||
{
|
||||
area->m_hidingSpotList.clear();
|
||||
|
||||
// free all the HidingSpots in area
|
||||
for (SpotEncounter &e : area->m_spotEncounterList)
|
||||
e.spotList.clear();
|
||||
|
||||
TheCSBots()->OnDestroyNavDataNotify(NAV_NOTIFY_DESTROY_SPOT_ENCOUNTER, area);
|
||||
area->m_spotEncounterList.clear();
|
||||
}
|
||||
|
||||
HidingSpot::m_nextID = 0;
|
||||
}
|
||||
|
||||
// For use when loading from a file
|
||||
@ -249,6 +261,9 @@ CNavArea::CNavArea(CNavNode *nwNode, class CNavNode *neNode, class CNavNode *seN
|
||||
// Destructor
|
||||
CNavArea::~CNavArea()
|
||||
{
|
||||
// tell all bots that this area no longer exists
|
||||
TheCSBots()->OnDestroyNavDataNotify(NAV_NOTIFY_DESTROY_AREA, this);
|
||||
|
||||
// if we are resetting the system, don't bother cleaning up - all areas are being destroyed
|
||||
if (m_isReset)
|
||||
return;
|
||||
@ -344,6 +359,7 @@ void CNavArea::FinishMerge(CNavArea *adjArea)
|
||||
|
||||
// remove subsumed adjacent area
|
||||
TheNavAreaList.remove(adjArea);
|
||||
TheCSBots()->OnDestroyNavDataNotify(NAV_NOTIFY_DESTROY_AREA, this);
|
||||
delete adjArea;
|
||||
}
|
||||
|
||||
@ -536,6 +552,7 @@ bool CNavArea::SplitEdit(bool splitAlongX, float splitEdge, CNavArea **outAlpha,
|
||||
|
||||
// remove original area
|
||||
TheNavAreaList.remove(this);
|
||||
TheCSBots()->OnDestroyNavDataNotify(NAV_NOTIFY_DESTROY_AREA, this);
|
||||
delete this;
|
||||
|
||||
return true;
|
||||
@ -868,6 +885,7 @@ bool CNavArea::MergeEdit(CNavArea *adj)
|
||||
|
||||
// remove subsumed adjacent area
|
||||
TheNavAreaList.remove(adj);
|
||||
TheCSBots()->OnDestroyNavDataNotify(NAV_NOTIFY_DESTROY_AREA, adj);
|
||||
delete adj;
|
||||
|
||||
return true;
|
||||
@ -900,6 +918,9 @@ void DestroyNavigationMap()
|
||||
{
|
||||
CNavArea::m_isReset = true;
|
||||
|
||||
// destroy all hiding spots
|
||||
DestroyHidingSpots();
|
||||
|
||||
// remove each element of the list and delete them
|
||||
while (!TheNavAreaList.empty())
|
||||
{
|
||||
@ -913,8 +934,8 @@ void DestroyNavigationMap()
|
||||
// destroy ladder representations
|
||||
DestroyLadders();
|
||||
|
||||
// destroy all hiding spots
|
||||
DestroyHidingSpots();
|
||||
// cleanup from previous analysis
|
||||
CleanupApproachAreaAnalysisPrep();
|
||||
|
||||
// destroy navigation nodes created during map learning
|
||||
CNavNode *node, *next;
|
||||
@ -2828,6 +2849,22 @@ SpotEncounter *CNavArea::GetSpotEncounter(const CNavArea *from, const CNavArea *
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Checks if a SpotEncounter is present in the list of encounters for the given CNavArea
|
||||
bool CNavArea::HasSpotEncounter(const SpotEncounter *encounter)
|
||||
{
|
||||
SpotEncounter *e;
|
||||
|
||||
for (SpotEncounterList::iterator iter = m_spotEncounterList.begin(); iter != m_spotEncounterList.end(); iter++)
|
||||
{
|
||||
e = &(*iter);
|
||||
|
||||
if (e == encounter)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Add spot encounter data when moving from area to area
|
||||
void CNavArea::AddSpotEncounters(const class CNavArea *from, NavDirType fromDir, const CNavArea *to, NavDirType toDir)
|
||||
{
|
||||
@ -3968,6 +4005,7 @@ void EditNavAreas(NavEditCmdType cmd)
|
||||
case EDIT_DELETE:
|
||||
EMIT_SOUND_DYN(ENT(pLocalPlayer->pev), CHAN_ITEM, "buttons/blip1.wav", 1, ATTN_NORM, 0, 100);
|
||||
TheNavAreaList.remove(area);
|
||||
TheCSBots()->OnDestroyNavDataNotify(NAV_NOTIFY_DESTROY_AREA, area);
|
||||
delete area;
|
||||
return;
|
||||
case EDIT_ATTRIB_CROUCH:
|
||||
|
@ -273,6 +273,7 @@ public:
|
||||
void ComputeHidingSpots(); // analyze local area neighborhood to find "hiding spots" in this area - for map learning
|
||||
void ComputeSniperSpots(); // analyze local area neighborhood to find "sniper spots" in this area - for map learning
|
||||
|
||||
bool HasSpotEncounter(const SpotEncounter *encounter);
|
||||
SpotEncounter *GetSpotEncounter(const CNavArea *from, const CNavArea *to); // given the areas we are moving between, return the spots we will encounter
|
||||
void ComputeSpotEncounters(); // compute spot encounter data - for map learning
|
||||
|
||||
|
@ -623,6 +623,13 @@ bool SaveNavigationMap(const char *filename)
|
||||
area->Save(fd, version);
|
||||
}
|
||||
|
||||
// Ensure that all data is flushed to disk
|
||||
#ifdef WIN32
|
||||
_commit(fd);
|
||||
#else
|
||||
fsync(fd);
|
||||
#endif
|
||||
|
||||
_close(fd);
|
||||
return true;
|
||||
}
|
||||
|
@ -932,7 +932,7 @@
|
||||
<Optimization>Disabled</Optimization>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>REGAMEDLL_ADD;REGAMEDLL_API;REGAMEDLL_FIXES;REGAMEDLL_SSE;REGAMEDLL_SELF;REGAMEDLL_CHECKS;UNICODE_FIXES;BUILD_LATEST;BUILD_LATEST_FIXES;CLIENT_WEAPONS;USE_QSTRING;_CRT_SECURE_NO_WARNINGS;_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<FloatingPointModel>Fast</FloatingPointModel>
|
||||
<FloatingPointModel>Precise</FloatingPointModel>
|
||||
<AdditionalOptions>/arch:IA32 %(AdditionalOptions)</AdditionalOptions>
|
||||
<AdditionalOptions Condition="'$(PlatformToolset)' == 'v140_xp' OR '$(PlatformToolset)' == 'v141_xp'">/Zc:threadSafeInit- %(AdditionalOptions)</AdditionalOptions>
|
||||
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
|
||||
@ -969,7 +969,7 @@
|
||||
<Optimization>Full</Optimization>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>REGAMEDLL_ADD;REGAMEDLL_API;REGAMEDLL_FIXES;REGAMEDLL_SSE;REGAMEDLL_SELF;REGAMEDLL_CHECKS;UNICODE_FIXES;BUILD_LATEST;BUILD_LATEST_FIXES;CLIENT_WEAPONS;USE_QSTRING;_CRT_SECURE_NO_WARNINGS;NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<FloatingPointModel>Fast</FloatingPointModel>
|
||||
<FloatingPointModel>Precise</FloatingPointModel>
|
||||
<AdditionalOptions>/arch:IA32 %(AdditionalOptions)</AdditionalOptions>
|
||||
<AdditionalOptions Condition="'$(PlatformToolset)' == 'v140_xp' OR '$(PlatformToolset)' == 'v141_xp'">/Zc:threadSafeInit- %(AdditionalOptions)</AdditionalOptions>
|
||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||
@ -1102,6 +1102,7 @@
|
||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||
<PrecompiledHeaderFile>precompiled.h</PrecompiledHeaderFile>
|
||||
<EnableEnhancedInstructionSet>NoExtensions</EnableEnhancedInstructionSet>
|
||||
<FloatingPointModel>Precise</FloatingPointModel>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
|
Loading…
x
Reference in New Issue
Block a user