4 protected static const int CHECK_INTERVAL = 3;
5 protected static const int DESPAWN_TIMEOUT = 10000;
6 protected static const int SPAWN_RADIUS_MIN_SQ = 500 * 500;
7 protected static const int SPAWN_RADIUS_MAX_SQ = 1000 * 1000;
8 protected static const int SPAWN_RADIUS_BLOCK_SQ = 150 * 150;
9 protected static const int DESPAWN_RADIUS_DIFF_SQ = 200 * 200;
11 protected ref array<SCR_AmbientPatrolSpawnPointComponent> m_aPatrols = {};
12 protected ref array<IEntity> m_aPlayers = {};
14 protected int m_iLastAssignedIndex;
15 protected int m_iIndexToCheck;
16 protected int m_iSpawnDistanceSq;
17 protected int m_iDespawnDistanceSq;
19 protected float m_fTimer;
20 protected float m_fCheckInterval;
23 override event protected void OnInit()
26 if (m_aPatrols.IsEmpty())
32 int fractionOfVD =
GetGame().GetViewDistance() * 0.3;
33 m_iSpawnDistanceSq = fractionOfVD * fractionOfVD;
34 m_iSpawnDistanceSq = Math.Min(SPAWN_RADIUS_MAX_SQ, m_iSpawnDistanceSq);
35 m_iSpawnDistanceSq = Math.Max(SPAWN_RADIUS_MIN_SQ, m_iSpawnDistanceSq);
36 m_iDespawnDistanceSq = m_iSpawnDistanceSq + DESPAWN_RADIUS_DIFF_SQ;
43 gameMode.GetOnPlayerSpawned().Insert(OnPlayerSpawnedOrDeleted);
44 gameMode.GetOnPlayerKilled().Insert(OnPlayerKilled);
45 gameMode.GetOnPlayerDeleted().Insert(OnPlayerSpawnedOrDeleted);
46 gameMode.GetOnPlayerDisconnected().Insert(OnPlayerDisconnected);
50 override event protected void OnCleanup()
57 gameMode.GetOnPlayerSpawned().Remove(OnPlayerSpawnedOrDeleted);
58 gameMode.GetOnPlayerKilled().Remove(OnPlayerKilled);
59 gameMode.GetOnPlayerDeleted().Remove(OnPlayerSpawnedOrDeleted);
60 gameMode.GetOnPlayerDisconnected().Remove(OnPlayerDisconnected);
64 override event protected void OnUpdate(ESystemPoint point)
72 float timeSlice = GetWorld().GetFixedTimeSlice();
87 ProcessSpawnpoint(m_iIndexToCheck);
90 if (!m_aPatrols.IsIndexValid(m_iIndexToCheck))
95 override event bool ShouldBePaused()
103 World world =
GetGame().GetWorld();
112 protected void UpdateCheckInterval()
114 m_fCheckInterval = CHECK_INTERVAL / m_aPatrols.Count();
118 protected void RefreshPlayerList()
121 array<int> playerIds = {};
123 int playersCount = pc.GetPlayers(playerIds);
125 foreach (
int playerId : playerIds)
127 IEntity player = pc.GetPlayerControlledEntity(playerId);
132 CharacterControllerComponent comp = CharacterControllerComponent.Cast(player.FindComponent(CharacterControllerComponent));
134 if (!comp || comp.IsDead())
137 m_aPlayers.Insert(player);
142 protected void OnPlayerSpawnedOrDeleted(
int playerId, IEntity player)
149 int GetRemainingPatrolsInfo(out notnull array<int> remnantsInfo)
153 WorldTimestamp curTime = world.GetServerTimestamp();
155 foreach (SCR_AmbientPatrolSpawnPointComponent presence : m_aPatrols)
162 if (presence.GetMembersAlive() < 0 && !grp && !presence.GetIsSpawned())
165 remnantsInfo.Insert(presence.GetID());
169 size = remnantsInfo.Insert(grp.GetAgentsCount());
173 if (presence.GetIsSpawned())
174 size = remnantsInfo.Insert(0);
176 size = remnantsInfo.Insert(presence.GetMembersAlive());
180 remnantsInfo.Insert(presence.GetRespawnTimestamp().DiffMilliseconds(curTime));
187 protected void ProcessSpawnpoint(
int spawnpointIndex)
189 SCR_AmbientPatrolSpawnPointComponent spawnpoint = m_aPatrols[spawnpointIndex];
191 if (!spawnpoint || (spawnpoint.GetMembersAlive() == 0 && !spawnpoint.GetIsSpawned()))
195 WorldTimestamp currentTime = world.GetServerTimestamp();
196 if (spawnpoint.GetRespawnTimestamp().Greater(currentTime))
199 if (!spawnpoint.GetIsSpawned())
201 spawnpoint.SpawnPatrol();
206 bool playersVeryNear;
207 bool playersFar =
true;
208 vector location = spawnpoint.GetOwner().GetOrigin();
212 foreach (IEntity player : m_aPlayers)
217 distance = vector.DistanceSq(player.GetOrigin(), location);
219 if (
distance > m_iDespawnDistanceSq)
229 if (
distance > SPAWN_RADIUS_BLOCK_SQ)
232 playersVeryNear =
true;
237 AIWorld aiWorld =
GetGame().GetAIWorld();
241 int maxChars = aiWorld.GetLimitOfActiveAIs();
244 isAIOverLimit =
true;
246 isAIOverLimit = ((float)aiWorld.GetCurrentNumOfActiveAIs() / (float)maxChars) > spawnpoint.GetAILimitThreshold();
249 if (!isAIOverLimit && !playersVeryNear)
250 spawnpoint.SetIsPaused(
false);
252 if (playersNear && !spawnpoint.GetIsPaused() && !spawnpoint.IsGroupActive())
257 spawnpoint.SetIsPaused(
true);
261 spawnpoint.ActivateGroup();
266 if (spawnpoint.GetIsSpawned() && playersFar && spawnpoint.IsGroupActive())
268 WorldTimestamp despawnT = spawnpoint.GetDespawnTimer();
271 spawnpoint.SetDespawnTimer(currentTime.PlusMilliseconds(DESPAWN_TIMEOUT));
272 else if (currentTime.Greater(despawnT))
273 spawnpoint.DeactivateGroup();
277 spawnpoint.SetDespawnTimer(
null);
282 void RegisterPatrol(notnull SCR_AmbientPatrolSpawnPointComponent patrol)
287 m_aPatrols.Insert(patrol);
288 patrol.SetID(m_iLastAssignedIndex);
289 m_iLastAssignedIndex++;
290 UpdateCheckInterval();
294 void UnregisterPatrol(notnull SCR_AmbientPatrolSpawnPointComponent patrol)
296 m_aPatrols.RemoveItem(patrol);
299 if (!m_aPatrols.IsEmpty())
301 UpdateCheckInterval();
309 int GetPatrols(out array<SCR_AmbientPatrolSpawnPointComponent> patrols)
312 return patrols.Copy(m_aPatrols);
314 return m_aPatrols.Count();
324 void OnPlayerKilled(
int playerId, IEntity playerEntity, IEntity killerEntity, notnull
Instigator killer)