Arma Reforger Explorer  1.1.0.42
Arma Reforger Code Explorer by Zeroy - Thanks to MisterOutofTime
SCR_DataCollectorCrimesModule.c
Go to the documentation of this file.
3 {
4  //------------------------------------------------------------------------------------------------
8  protected ref array<int> m_aPlayerIDs = {};
9 
10  //------------------------------------------------------------------------------------------------
14  protected int m_iNextIndex;
15 
16  //------------------------------------------------------------------------------------------------
20  [Attribute("3", UIWidgets.Slider, desc: "Seconds after last action to evaluate buffer")]
21  protected float m_fLatestActionThreshold;
22 
23  //------------------------------------------------------------------------------------------------
27  [Attribute("5", UIWidgets.Slider, desc: "Max seconds of accumulating actions before evaluating them")]
28  protected float m_fMaxTimeAccumulationThreshold;
29 
30  //------------------------------------------------------------------------------------------------
34  [Attribute()]
35  protected ref array<int> m_aLightBanPunishments;
36 
37  //------------------------------------------------------------------------------------------------
41  [Attribute("1800", UIWidgets.Slider, desc: "Seconds for reincidency of light severity")]
42  protected int m_iSecondsOfReincidencyLightBan;
43 
44  //------------------------------------------------------------------------------------------------
48  [Attribute()]
49  protected ref array<int> m_aHeavyBanPunishments;
50 
51  //------------------------------------------------------------------------------------------------
55  [Attribute("14400", UIWidgets.Slider, desc: "Seconds for reincidency of heavy severity")]
56  protected int m_iSecondsOfReincidencyHeavyBan;
57 
58  [Attribute("1", UIWidgets.CheckBox, desc: "Are War Crimes detection enabled?")]
59  protected bool m_bWarCrimesEnabled;
60 
61  [Attribute("1", UIWidgets.CheckBox, desc: "Is the proportionality principle enabled?")]
62  protected bool m_bWarCrimesProportionalityPrincipleEnabled;
63 
64  [Attribute("2", UIWidgets.Slider, desc: "Negative proportionality points for killing a friendly human-controlled soldier")]
65  protected float MODIFIER_PROPORTIONALITY_FRIENDLY_KILLS;
66 
67  [Attribute("1", UIWidgets.Slider, desc: "Negative proportionality points for killing a friendly AI-controlled soldier")]
68  protected float MODIFIER_PROPORTIONALITY_FRIENDLY_AI_KILLS;
69 
70  [Attribute("1.5", UIWidgets.Slider, desc: "Negative proportionality points for killing an enemy AI-controlled soldier")]
71  protected float MODIFIER_PROPORTIONALITY_AI_KILLS;
72 
73  [Attribute("3", UIWidgets.Slider, desc: "Positive proportionality points for killing an enemy human-controlled soldier")]
74  protected float MODIFIER_PROPORTIONALITY_KILLS;
75 
76  //~ Used in voting to make sure there is a min ban duration (in seconds)
77  static const int MIN_AUTO_BAN_DURATION = 300;
78 
79  //------------------------------------------------------------------------------------------------
80  override void OnPlayerAuditSuccess(int playerID)
81  {
82  super.OnPlayerAuditSuccess(playerID, stuff);
83 
84  //If war crimes are not enabled, the module doesn't need to do anything. Keep the array of players empty and just return
85  if (!m_bWarCrimesEnabled)
86  return;
87 
88  m_aPlayerIDs.Insert(playerID);
89 
90  //Reset time out of the player in case they were previously disconnected as a punishment
91 
92  SCR_PlayerData playerData = GetGame().GetDataCollector().GetPlayerData(playerID, false);
93  if (!playerData)
94  return;
95 
96  playerData.SetTimeOut(0);
97  }
98 
99  //------------------------------------------------------------------------------------------------
100  override void OnPlayerDisconnected(int playerID, IEntity controlledEntity = null)
101  {
102  super.OnPlayerDisconnected(playerID, controlledEntity);
103 
104  int i = m_aPlayerIDs.Find(playerID);
105 
106  //if player not found in the array, return
107  if (i == -1)
108  return;
109 
110  //Evaluate player no matter what, because they are leaving the server
111  EvaluatePlayerCrimes(playerID, false);
112 
113  //Update their acceleration
114  UpdateCriminalAcceleration(playerID);
115 
116  //Remove player from the array
117  m_aPlayerIDs.RemoveOrdered(i);
118 
119  //Adjust index if necessary
120  if (i < m_iNextIndex)
121  m_iNextIndex--;
122  }
123 
124  //------------------------------------------------------------------------------------------------
125  override void OnGameModeEnd()
126  {
127  for (int i = 0; i < m_aPlayerIDs.Count(); i++)
128  {
129  CheckPlayer(m_aPlayerIDs[i]);
130  }
131  m_aPlayerIDs.Clear();
132  }
133 
134  //------------------------------------------------------------------------------------------------
135  override void Update(float timeTick)
136  {
137  if (m_aPlayerIDs.IsEmpty())
138  return;
139 
140  m_fTimeSinceUpdate += timeTick;
141 
142  if (m_fTimeSinceUpdate < m_fUpdatePeriod)
143  return;
144 
145  if (!m_aPlayerIDs.IsIndexValid(m_iNextIndex))
146  {
147  m_iNextIndex = 0;
148  m_fTimeSinceUpdate = 0;
149  return;
150  }
151 
152  CheckPlayer(m_aPlayerIDs[m_iNextIndex]);
153 
154  m_iNextIndex++;
155  }
156 
157  //------------------------------------------------------------------------------------------------
158  protected void CheckPlayer(int playerId)
159  {
160  SCR_PlayerData playerData = GetGame().GetDataCollector().GetPlayerData(playerId, false);
161  if (!playerData)
162  return;
163 
164  //Are we accumulating actions? If not, that's it for now. Process stats and reset
165  int accumulationTick = playerData.GetAccumulatedActionsTick();
166  if (accumulationTick == 0)
167  {
168  ProcessTemporalStats(playerData);
169  return;
170  }
171 
172  //It's been more than m_fLastActionThreshold seconds since last action or more than m_fMaxTimeAccumulationThreshold since started accumulating actions? If not, keep accumulating
173  int currentTick = System.GetTickCount();
174  int latestActionTick = playerData.GetLatestActionTick();
175  if (currentTick - latestActionTick < m_fLatestActionThreshold * 1000 && currentTick - accumulationTick < m_fMaxTimeAccumulationThreshold * 1000)
176  return;
177 
178  //Evaluation of war crimes
179  EvaluatePlayerCrimes(playerId);
180  }
181 
182  //------------------------------------------------------------------------------------------------
185  protected void EvaluatePlayerCrimes(int playerId, bool evaluatePunishment = true)
186  {
187  SCR_PlayerData playerData = GetGame().GetDataCollector().GetPlayerData(playerId, false);
188  if (!playerData)
189  return;
190 
191  //Calculate decreasing of criminal score based on time lapsed
192  float decreasingOfScore = (System.GetTickCount() - playerData.GetLatestCriminalScoreUpdateTick()) * 0.001 * SCR_PlayerDataConfigs.GetInstance().GetScoreDecreasePerSecond();
193 
195  // Analsing warcrime_harming_friendlies: //
197 
198  float harmingFriendliesScore = EvaluateHarmingFriendlies(playerData) * playerData.GetStat(SCR_EDataStats.CRIME_ACCELERATION);
199 
201  // Done analysing war crimes //
203 
204  //Process temporal stats
205  ProcessTemporalStats(playerData);
206 
207  //Update score
208  UpdateCriminalScore(playerData, harmingFriendliesScore, decreasingOfScore);
209 
210  float currentScore = playerData.GetCriminalScore();
211 
212  if (harmingFriendliesScore > 0)
213  Print("Player with id " + playerId + " got " + harmingFriendliesScore + " more criminal points. Current criminal score is " + currentScore, LogLevel.DEBUG);
214  else
215  return;
216 
217  //Kick or ban players
218  if (evaluatePunishment && currentScore >= SCR_PlayerDataConfigs.GetInstance().GetScoreThreshold())
219  {
220  //Logic for kicking player
221  KickPlayer(playerId, playerData, SCR_PlayerManagerKickReason.FRIENDLY_FIRE);
222  return;
223  }
224 
225  //Send educational hints to clients
226  SendHints(playerId, currentScore);
227  }
228 
229  //------------------------------------------------------------------------------------------------
230  protected void KickPlayer(int playerId, notnull SCR_PlayerData playerData, SCR_PlayerManagerKickReason reason)
231  {
232  int durationInMinutes = RequestBanIfNecessary(playerId, playerData, reason);
233  if (durationInMinutes == -1)
234  {
235  return;
236  }
237  else
238  {
239  Print("Player Manager is kicking a player with id " + playerId + ". Banning them for " + durationInMinutes + " minutes.", LogLevel.DEBUG);
240  if (durationInMinutes == 0)
241  ExecutePunishment(playerId, SCR_PlayerManagerKickReason.KICK, 0);
242  else
243  ExecutePunishment(playerId, SCR_PlayerManagerKickReason.TEMP_BAN, durationInMinutes * 60);
244  }
245 
246  //GetGame().GetPlayerManager().KickPlayer(playerId, reason, durationInMinutes * 60);
247  }
248 
249  //------------------------------------------------------------------------------------------------
256  protected int RequestBanIfNecessary(int playerId, notnull SCR_PlayerData playerData, SCR_PlayerManagerKickReason reason)
257  {
258  if (m_aLightBanPunishments.IsEmpty() || m_aHeavyBanPunishments.IsEmpty())
259  {
260  Print("Incorrect setup on DataCollectorCrimesModule: Light or Heavy ban duration array is empty. Cannot ban players!", LogLevel.ERROR);
261  return 0;
262  }
263 
264  //Update their session duration to now
265  playerData.CalculateSessionDuration();
266 
267  //Set up the necessary fields
268  float acceleration = playerData.GetStat(SCR_EDataStats.CRIME_ACCELERATION);
269  float score = playerData.GetCriminalScore();
270 
271  SCR_PlayerDataConfigs config = SCR_PlayerDataConfigs.GetInstance();
272  int durationInMinutes;
273 
274  //Should this player be banned?
275  //Lightban requires an acceleration of 4.8 or more
276  if (config.GetMaxAcceleration() * config.GetBanEvaluationLight() <= acceleration)
277  {
278  //Yes, they should. Decide between light or heavy ban now.
279 
280  //Lightban variables
281  int timeDiffLightBan = playerData.GetStat(SCR_EDataStats.SESSION_DURATION) - playerData.GetStat(SCR_EDataStats.LIGHTBAN_SESSION_DURATION);
282  int streakLightBan = playerData.GetStat(SCR_EDataStats.LIGHTBAN_STREAK);
283  int maxStreakLightBan = m_aLightBanPunishments.Count();
284 
285  //Heavyban variables
286  int timeDiffHeavyBan = playerData.GetStat(SCR_EDataStats.SESSION_DURATION) - playerData.GetStat(SCR_EDataStats.HEAVYBAN_SESSION_DURATION);
287  int streakHeavyBan = playerData.GetStat(SCR_EDataStats.HEAVYBAN_STREAK);
288  int maxStreakHeavyBan = m_aHeavyBanPunishments.Count();
289 
290  //If It's the first ban issued to this player recently, only light ban is enough.
291  if (timeDiffLightBan > m_iSecondsOfReincidencyLightBan && timeDiffHeavyBan > m_iSecondsOfReincidencyHeavyBan)
292  {
293  durationInMinutes = m_aLightBanPunishments[0];
294  streakLightBan = 1;
295 
296  playerData.OverrideStat(SCR_EDataStats.LIGHTBAN_STREAK, streakLightBan);
297  playerData.OverrideStat(SCR_EDataStats.LIGHTBAN_SESSION_DURATION, playerData.GetStat(SCR_EDataStats.SESSION_DURATION));
298  }
299  else
300  //Else: Not a long enough time has passed since the last ban. This means this player has repeated an offense.
301  {
302  //If the streak of lightban is not big enough, or the acceleration is not big enough, lightban it is
303  //Heavyban requires an acceleration of 6 and a lightban streak of at least 3 with current configs
304  if (!(streakLightBan >= maxStreakLightBan && config.GetMaxAcceleration() * config.GetBanEvaluationHeavy() <= acceleration))
305  {
306  //Light ban is enough for this player because the streak and the acceleration don't meet (both of them) the necessary conditions
307 
308  durationInMinutes = m_aLightBanPunishments[Math.Min(streakLightBan, maxStreakLightBan - 1)];
309  streakLightBan++;
310 
311  playerData.OverrideStat(SCR_EDataStats.LIGHTBAN_STREAK, streakLightBan);
312  playerData.OverrideStat(SCR_EDataStats.LIGHTBAN_SESSION_DURATION, playerData.GetStat(SCR_EDataStats.SESSION_DURATION));
313  }
314  else
315  {
316  //Heavy ban it is
317  if (timeDiffHeavyBan > m_iSecondsOfReincidencyHeavyBan)
318  {
319  durationInMinutes = m_aHeavyBanPunishments[0];
320  streakHeavyBan = 1;
321  playerData.OverrideStat(SCR_EDataStats.HEAVYBAN_STREAK, streakHeavyBan);
322  }
323  else
324  {
325  durationInMinutes = m_aHeavyBanPunishments[Math.Min(streakHeavyBan, maxStreakHeavyBan - 1)];
326  streakHeavyBan++;
327  }
328 
329  playerData.OverrideStat(SCR_EDataStats.HEAVYBAN_STREAK, streakHeavyBan);
330  playerData.OverrideStat(SCR_EDataStats.HEAVYBAN_SESSION_DURATION, playerData.GetStat(SCR_EDataStats.SESSION_DURATION));
331 
332  BackendApi ba = GetGame().GetBackendApi();
333  if (ba)
334  ExecutePunishment(playerId, SCR_PlayerManagerKickReason.BAN, durationInMinutes * 60);
335  //ba.PlayerBanCreate("Heavy ban", durationInMinutes * 60, playerId);
336 
337  Print("Banning service is heavybanning a player with id " + playerId + ". Banning them for " + durationInMinutes + " minutes.", LogLevel.DEBUG);
338  //Player has been banned. We don't want the PlayerManager to ban them on top of the banning service. So we need to set durationInMinutes to an scape value
339  //This implementation should be improved in the future, but for now we can only kick them for 0 minutes using the PlayerManager since its the banning service what banned them.
340  durationInMinutes = -1;
341  }
342  }
343  }
344  //Not a ban. Just a kick
345  else
346  {
347  int timeDiff = playerData.GetStat(SCR_EDataStats.SESSION_DURATION) - playerData.GetStat(SCR_EDataStats.KICK_SESSION_DURATION);
348  int streak = playerData.GetStat(SCR_EDataStats.KICK_STREAK);
349 
350  if (timeDiff > 600)
351  streak = 1;
352  else
353  streak ++;
354 
355  durationInMinutes = 0;
356 
357  playerData.OverrideStat(SCR_EDataStats.KICK_STREAK, streak);
358  playerData.OverrideStat(SCR_EDataStats.KICK_SESSION_DURATION, playerData.GetStat(SCR_EDataStats.SESSION_DURATION));
359  }
360 
361  return durationInMinutes;
362  }
363 
364  //------------------------------------------------------------------------------------------------
365  protected float EvaluateHarmingFriendlies(notnull SCR_PlayerData playerData)
366  {
367  array<float> accumulatedActions = playerData.GetAccumulatedActions();
368 
369  float harmingAlliesPoints = accumulatedActions[SCR_EDataStats.FRIENDLY_KILLS] * MODIFIER_PROPORTIONALITY_FRIENDLY_KILLS + accumulatedActions[SCR_EDataStats.FRIENDLY_AI_KILLS] * MODIFIER_PROPORTIONALITY_FRIENDLY_AI_KILLS;
370  float proportionalityPoints = 0;
371 
372  if (m_bWarCrimesProportionalityPrincipleEnabled)
373  proportionalityPoints = accumulatedActions[SCR_EDataStats.KILLS] * MODIFIER_PROPORTIONALITY_KILLS + accumulatedActions[SCR_EDataStats.AI_KILLS] * MODIFIER_PROPORTIONALITY_AI_KILLS;
374 
375  if (harmingAlliesPoints <= proportionalityPoints)
376  return 0;
377 
378  playerData.AddStat(SCR_EDataStats.WARCRIME_HARMING_FRIENDLIES, harmingAlliesPoints - proportionalityPoints, false);
379  playerData.AddStat(SCR_EDataStats.WARCRIMES, harmingAlliesPoints - proportionalityPoints, false);
380 
381  //Single friendly kill or multiple friendly kills?
382  float PointsOfCrime;
383 
384  if (accumulatedActions[SCR_EDataStats.FRIENDLY_KILLS] + accumulatedActions[SCR_EDataStats.FRIENDLY_AI_KILLS] == 1)
385  PointsOfCrime = SCR_PlayerDataConfigs.GetInstance().GetCrimePointsFriendlyKill();
386  else
387  PointsOfCrime = SCR_PlayerDataConfigs.GetInstance().GetCrimePointsFriendlyMultiKill();
388 
389  return PointsOfCrime * (harmingAlliesPoints - proportionalityPoints);
390  }
391 
392  //------------------------------------------------------------------------------------------------
393  protected void ExecutePunishment(int playerId, SCR_PlayerManagerKickReason reason, int durationInSeconds)
394  {
395  GetGame().GetDataCollector().GetPlayerData(playerId).SetTimeOut(durationInSeconds);
396 
397  if (SCR_PlayerDataConfigs.GetInstance().GetVotingSuggestionEnabled())
398  VoteForKickOrBan(playerId, reason, durationInSeconds);
399  else
400  KickOrBanPlayer(playerId, reason, durationInSeconds);
401  }
402 
403  //------------------------------------------------------------------------------------------------
404  void KickOrBanPlayer(int playerId, SCR_PlayerManagerKickReason reason, int minimmumDuration)
405  {
406  int durationInSeconds = Math.Clamp(GetGame().GetDataCollector().GetPlayerData(playerId).GetTimeOut(), minimmumDuration, int.MAX);
407 
408  switch(reason)
409  {
410  case SCR_PlayerManagerKickReason.KICK:
411  {
412  GetGame().GetPlayerManager().KickPlayer(playerId, reason, 0);
413  return;
414  }
415  case SCR_PlayerManagerKickReason.KICK_VOTED:
416  {
417  GetGame().GetPlayerManager().KickPlayer(playerId, reason, durationInSeconds);
418  return;
419  }
420  case SCR_PlayerManagerKickReason.TEMP_BAN:
421  {
422  GetGame().GetPlayerManager().KickPlayer(playerId, reason, durationInSeconds);
423  return;
424  }
425  case SCR_PlayerManagerKickReason.BAN:
426  {
427  GetGame().GetBackendApi().GetBanServiceApi().CreateBanPlayerId(null, playerId, "Heavy ban", durationInSeconds);
428  GetGame().GetPlayerManager().KickPlayer(playerId, reason, 0);
429  return;
430  }
431 
432  }
433  }
434 
435  //------------------------------------------------------------------------------------------------
443  void VoteForKickOrBan(int playerId, SCR_PlayerManagerKickReason reason, int minimmumDurationBackup)
444  {
445  SCR_VotingManagerComponent votingManager = SCR_VotingManagerComponent.GetInstance();
446  if (!votingManager)
447  KickOrBanPlayer(playerId, reason, minimmumDurationBackup);
448 
449  switch(reason)
450  {
451  case SCR_PlayerManagerKickReason.KICK:
452  case SCR_PlayerManagerKickReason.KICK_VOTED:
453  if (!votingManager.StartVoting(EVotingType.AUTO_KICK, playerId))
454  KickOrBanPlayer(playerId, reason, minimmumDurationBackup);
455  return;
456  case SCR_PlayerManagerKickReason.TEMP_BAN:
457  if (!votingManager.StartVoting(EVotingType.AUTO_LIGHTBAN, playerId))
458  KickOrBanPlayer(playerId, reason, minimmumDurationBackup);
459  return;
460  case SCR_PlayerManagerKickReason.BAN:
461  if (!votingManager.StartVoting(EVotingType.AUTO_HEAVYBAN, playerId))
462  KickOrBanPlayer(playerId, reason, minimmumDurationBackup);
463  return;
464  }
465  }
466 
467  //------------------------------------------------------------------------------------------------
468  protected void SendHints(int playerId, float harmingFriendliesScore)
469  {
470  if (playerId <= 0)
471  return;
472 
473  if (harmingFriendliesScore > 0)
474  {
475  IEntity playerController = GetGame().GetPlayerManager().GetPlayerController(playerId);
476  if (!playerController)
477  return;
478 
479  SCR_KickHintComponent hintsComp = SCR_KickHintComponent.Cast(playerController.FindComponent(SCR_KickHintComponent));
480  if (!hintsComp)
481  return;
482 
483  hintsComp.NotifyClientCriminalScoreIncreased(SCR_ECrimeNotification.TEAMKILL, harmingFriendliesScore);
484  }
485  }
486 
487  //------------------------------------------------------------------------------------------------
488  protected void ProcessTemporalStats(notnull SCR_PlayerData playerData)
489  {
490  array<float> accumulatedActions = playerData.GetAccumulatedActions();
491 
492  //Add the stats to the m_aStats of the player since they are not "temporal" anymore
493  for (int i = 0, count = accumulatedActions.Count(); i < count; i++)
494  {
495  float value = accumulatedActions[i];
496  if (value != 0)
497  playerData.AddStat(i, value, false);
498  }
499 
500  playerData.ResetAccumulatedActions();
501  }
502 
503  //------------------------------------------------------------------------------------------------
504  protected void UpdateCriminalScore(notnull SCR_PlayerData playerData, float addToScore, float decreaseFromScore)
505  {
506  float currentScore = Math.Max(playerData.GetCriminalScore() - decreaseFromScore, 0);
507  currentScore += addToScore;
508 
509  playerData.SetCriminalScore(currentScore);
510  }
511 
512  //------------------------------------------------------------------------------------------------
513  protected void UpdateCriminalAcceleration(int playerId)
514  {
515  SCR_PlayerData playerData = GetGame().GetDataCollector().GetPlayerData(playerId, false);
516  if (!playerData)
517  return;
518 
519  playerData.CalculateSessionDuration();
520  float secondsSession = playerData.GetStat(SCR_EDataStats.SESSION_DURATION) - playerData.GetStat(SCR_EDataStats.SESSION_DURATION, false);
521 
522  float decreaseOfAcceleration, increaseOfAcceleration;
523 
524  if (secondsSession < 600)
525  decreaseOfAcceleration = 0;
526  else
527  decreaseOfAcceleration = Math.Log10(secondsSession) - 1;
528 
529  SCR_PlayerDataConfigs config = SCR_PlayerDataConfigs.GetInstance();
530 
531  increaseOfAcceleration = playerData.GetCriminalScore() * config.GetScoreToAccelerationMultiplier();
532 
533  float currentAcceleration = Math.Max(playerData.GetStat(SCR_EDataStats.CRIME_ACCELERATION) - decreaseOfAcceleration, config.GetMinAcceleration());
534  currentAcceleration = Math.Min(currentAcceleration + increaseOfAcceleration, config.GetMaxAcceleration());
535 
536  Print("Player with id " + playerId + " disconnecting. Old acceleration was " + playerData.GetStat(SCR_EDataStats.CRIME_ACCELERATION) + ", new acceleration is " + currentAcceleration, LogLevel.VERBOSE);
537 
538  playerData.OverrideStat(SCR_EDataStats.CRIME_ACCELERATION, currentAcceleration);
539  }
540 };
m_aPlayerIDs
protected ref set< int > m_aPlayerIDs
Definition: SCR_VotingBase.c:2
m_fTimeSinceUpdate
protected float m_fTimeSinceUpdate
Definition: SCR_RestrictedDeployableSpawnPointComponent.c:89
GetGame
ArmaReforgerScripted GetGame()
Definition: game.c:1424
desc
UI Textures DeployMenu Briefing conflict_HintBanner_1_UI desc
Definition: SCR_RespawnBriefingComponent.c:17
SCR_PlayerData
Definition: SCR_PlayerData.c:2
SCR_DataCollectorCrimesModule
Definition: SCR_DataCollectorCrimesModule.c:2
SCR_PlayerDataConfigs
Definition: SCR_PlayerDataConfigs.c:102
Attribute
typedef Attribute
Post-process effect of scripted camera.
GetPlayerData
SCR_PlayerData GetPlayerData(int playerID, bool createNew=true, bool requestFromBackend=true)
Definition: SCR_DataCollectorComponent.c:220
SCR_EDataStats
SCR_EDataStats
Definition: SCR_PlayerData.c:950
EVotingType
EVotingType
Definition: EVotingType.c:1
SCR_VotingManagerComponent
void SCR_VotingManagerComponent(IEntityComponentSource src, IEntity ent, IEntity parent)
Definition: SCR_VotingManagerComponent.c:878
GetDataCollector
SCR_DataCollectorComponent GetDataCollector()
Definition: game.c:90
SCR_ECrimeNotification
SCR_ECrimeNotification
Definition: SCR_KickHintComponent.c:43
SCR_DataCollectorModule
Definition: SCR_DataCollectorModule.c:2
BaseContainerProps
SCR_AIGoalReaction_Follow BaseContainerProps
Handles insects that are supposed to be spawned around selected prefabs defined in prefab names array...
Definition: SCR_AIGoalReaction.c:468