Arma Reforger Explorer  1.1.0.42
Arma Reforger Code Explorer by Zeroy - Thanks to MisterOutofTime
SCR_DataCollectorDriverModule.c
Go to the documentation of this file.
2 {
3  IEntity m_Player;
4  IEntity m_Vehicle;
5  bool m_bPilot;
6 
7  void SCR_DataCollectorDriverModuleContext(notnull IEntity player, notnull IEntity vehicle, bool pilot)
8  {
9  m_Player = player;
10  m_Vehicle = vehicle;
11  m_bPilot = pilot;
12  }
13 };
14 
17 {
18  protected ref map<int, ref SCR_DataCollectorDriverModuleContext> m_mTrackedPlayersInVehicles = new map<int, ref SCR_DataCollectorDriverModuleContext>();
19 
20  //------------------------------------------------------------------------------------------------
21  protected override void AddInvokers(IEntity player)
22  {
23  super.AddInvokers(player);
24  if (!player)
25  return;
26 
27  SCR_CompartmentAccessComponent compartmentAccessComponent = SCR_CompartmentAccessComponent.Cast(player.FindComponent(SCR_CompartmentAccessComponent));
28 
29  if (!compartmentAccessComponent)
30  return;
31 
32  compartmentAccessComponent.GetOnCompartmentEntered().Insert(OnCompartmentEntered);
33  compartmentAccessComponent.GetOnCompartmentLeft().Insert(OnCompartmentLeft);
34  }
35 
36  //------------------------------------------------------------------------------------------------
37  protected override void RemoveInvokers(IEntity player)
38  {
39  super.RemoveInvokers(player);
40  if (!player)
41  return;
42 
43  SCR_CompartmentAccessComponent compartmentAccessComponent = SCR_CompartmentAccessComponent.Cast(player.FindComponent(SCR_CompartmentAccessComponent));
44 
45  if (!compartmentAccessComponent)
46  return;
47 
48  compartmentAccessComponent.GetOnCompartmentEntered().Remove(OnCompartmentEntered);
49  compartmentAccessComponent.GetOnCompartmentLeft().Remove(OnCompartmentLeft);
50  }
51 
52  //------------------------------------------------------------------------------------------------
53  protected void OnCompartmentEntered(IEntity targetEntity, BaseCompartmentManagerComponent manager, int mgrID, int slotID, bool move)
54  {
55  if (!targetEntity || !manager)
56  {
57  Print("ERROR IN DATACOLLECTOR DRIVER MODULE: TARGETENTITY OR MANAGER ARE EMPTY.", LogLevel.ERROR);
58  return;
59  }
60 
61  BaseCompartmentSlot compartment = manager.FindCompartment(slotID, mgrID);
62  if (!compartment)
63  return;
64 
65  IEntity playerEntity = compartment.GetOccupant();
66  if (!playerEntity)
67  return;
68 
69  int playerID = GetGame().GetPlayerManager().GetPlayerIdFromControlledEntity(playerEntity);
70  if (playerID == 0) // Non-player character
71  return;
72 
73  m_mTrackedPlayersInVehicles.Insert(playerID, new SCR_DataCollectorDriverModuleContext(playerEntity, targetEntity, compartment.GetType() == ECompartmentType.Pilot));
74  }
75 
76  //------------------------------------------------------------------------------------------------
77  protected void OnCompartmentLeft(IEntity targetEntity, BaseCompartmentManagerComponent manager, int mgrID, int slotID, bool move)
78  {
79  BaseCompartmentSlot compartment = manager.FindCompartment(slotID, mgrID);
80  if (!compartment)
81  return;
82 
83  int playerID = GetGame().GetPlayerManager().GetPlayerIdFromControlledEntity(compartment.GetOccupant());
84  if (playerID == 0) // Non-player character
85  return;
86 
87  //Is the player inside a vehicle?
88  SCR_DataCollectorDriverModuleContext playerContext = m_mTrackedPlayersInVehicles.Get(playerID);
89  if (!playerContext)
90  return;
91 
92  //If the player died, blame the driver of that vehicle
93  //QUESTION: WHAT IF THE PLAYER SUICIDES IN A VEHICLE
94  ChimeraCharacter playerChimeraCharacter = ChimeraCharacter.Cast(playerContext.m_Player);
95  if (playerChimeraCharacter && playerChimeraCharacter.GetDamageManager().GetState() == EDamageState.DESTROYED)
96  PlayerDied(playerID, playerContext);
97 
98  m_mTrackedPlayersInVehicles.Remove(playerID);
99  }
100 
101 /*
102 TODO: REMOVE THIS, REPLACE WITH SENDING THROUGH RPL THE STATS FROM THE SERVER RECURRENTLY, AS IT'S ONLY FOR DEBUGGING PURPOSES
103 #ifdef ENABLE_DIAG
104  //------------------------------------------------------------------------------------------------
105  override void OnControlledEntityChanged(IEntity from, IEntity to)
106  {
107  super.OnControlledEntityChanged(from, to);
108 
109  if (to)
110  {
111  int playerID = GetGame().GetPlayerManager().GetPlayerIdFromControlledEntity(to);
112  m_mTrackedPlayersInVehicles.Insert(playerID, to);
113  }
114  else if (from)
115  {
116  int playerID = GetGame().GetPlayerManager().GetPlayerIdFromControlledEntity(from);
117  m_mTrackedPlayersInVehicles.Remove(playerID);
118  }
119 
120  }
121 #endif
122 */
123 
124  //------------------------------------------------------------------------------------------------
125  //We call this method when a player dies and its ejected from a vehicle dead
126  protected void PlayerDied(int PlayerID, notnull SCR_DataCollectorDriverModuleContext playerContext)
127  {
128  //TODO: Replace this using a C++ implemented method to get the count of occupants of the vehicle
129  /**********************************************************************************************/
130  SCR_BaseCompartmentManagerComponent compartmentManager = SCR_BaseCompartmentManagerComponent.Cast(playerContext.m_Vehicle.FindComponent(SCR_BaseCompartmentManagerComponent));
131  if (!compartmentManager)
132  return;
133 
134  array<IEntity> occupants = {};
135  compartmentManager.GetOccupants(occupants);
136 
137  if (occupants.Count() <= 1) //player was alone in vehicle. Do nothing
138  return;
139  /**********************************************************************************************/
140 
141  if (playerContext.m_bPilot)
142  {
143  array<IEntity> checkPilot = {};
144  compartmentManager.GetOccupantsOfType(checkPilot, ECompartmentType.Pilot);
145 
146  if (checkPilot.IsEmpty())
147  {
148  Print("DataCollectorDriveModule: Pilot died but according to the compartmentManager there's no pilot. !!!", LogLevel.ERROR);
149  }
150  //check if pilot is pilot
151  else if (playerContext.m_Player != checkPilot.Get(0))
152  {
153  Print("DataCollectorDriveModule: The pilot from the context is not the pilot from the compartments. !!", LogLevel.ERROR);
154  }
155 
156  //The driver was killed.
157  //All players from the vehicle are in danger now because of the pilot's death, so we act as if they died
158  GetGame().GetDataCollector().GetPlayerData(PlayerID).AddStat(SCR_EDataStats.PLAYERS_DIED_IN_VEHICLE, occupants.Count()-1);
159  return;
160  }
161 
162  //Find if there's a pilot and their ID
163  array<IEntity> pilot = {};
164  compartmentManager.GetOccupantsOfType(pilot, ECompartmentType.Pilot);
165 
166  //If there's no pilot it's none's fault.
167  if (pilot.IsEmpty())
168  return;
169 
170  //Let's assume there's only one pilot, or if there are multiple, let's assume the main one is in the position 0
171  int pilotID = GetGame().GetPlayerManager().GetPlayerIdFromControlledEntity(pilot.Get(0));
172 
173  if (pilotID == 0)
174  return; //Pilot is an AI
175 
176  //A player died and it was not the pilot. So the pilot has someone dying on their vehicle
177  GetGame().GetDataCollector().GetPlayerData(PlayerID).AddStat(SCR_EDataStats.PLAYERS_DIED_IN_VEHICLE, 1);
178  //TODO: Make sure it is not possible to add this kill multiple times to the pilot if all players die simultaneously
179  }
180 
181  //------------------------------------------------------------------------------------------------
182  override void OnPlayerKilled(int playerId, IEntity playerEntity, IEntity killerEntity, notnull Instigator killer)
183  {
184  //We are only looking for roadkills here. That's why we don't call super.OnPlayerKilled. This behaviour is very specific
185 
186  //If the killer is AI count no roadKill
187  if (killer.GetInstigatorType() != InstigatorType.INSTIGATOR_PLAYER)
188  return;
189 
190  //if the player killed themselves do nothing
191  int killerId = killer.GetInstigatorPlayerID();
192  if (killerId == playerId)
193  return;
194 
195  SCR_ChimeraCharacter playerEntityChar = SCR_ChimeraCharacter.Cast(playerEntity);
196  if (!playerEntityChar)
197  return;
198 
199  SCR_FactionManager factionManager = SCR_FactionManager.Cast(GetGame().GetFactionManager());
200  if (!factionManager)
201  return;
202 
203  Faction factionKiller = Faction.Cast(factionManager.GetPlayerFaction(killerId));
204  if (!factionKiller)
205  return;
206 
207  SCR_DataCollectorDriverModuleContext killerContext = m_mTrackedPlayersInVehicles.Get(killerId);
208  //If the killer is not tracked as a driver, then this was no roadkill
209  if (!killerContext || !killerContext.m_bPilot)
210  return;
211 
212  //Now we know the killer is not an AI and they are a driver. Add roadkill!
213 
214  SCR_PlayerData killerData = GetGame().GetDataCollector().GetPlayerData(killerId);
215 
216  //Add a kill. Find if friendly or unfriendly
217  if (factionKiller.IsFactionFriendly(playerEntityChar.GetFaction()))
218  killerData.AddStat(SCR_EDataStats.FRIENDLY_ROADKILLS);
219  else
220  killerData.AddStat(SCR_EDataStats.ROADKILLS);
221  }
222 
223  //------------------------------------------------------------------------------------------------
224  override void OnAIKilled(IEntity AIEntity, IEntity killerEntity, notnull Instigator killer)
225  {
226  //We are only looking for roadkills here. That's why we don't call super.OnAIKilled. This behaviour is very specific
227 
228  //This code has many similarities with OnPlayerKilled.
229  //It would be nice to have only one method for OnCharacterKilled instead of having this duplicity
230 
231  if (killer.GetInstigatorType() != InstigatorType.INSTIGATOR_PLAYER)
232  return;
233 
234  int killerId = killer.GetInstigatorPlayerID();
235 
236  SCR_ChimeraCharacter AIEntityChar = SCR_ChimeraCharacter.Cast(AIEntity);
237  if (!AIEntityChar)
238  return;
239 
240  SCR_DataCollectorDriverModuleContext killerContext = m_mTrackedPlayersInVehicles.Get(killerId);
241  //If the killer is not tracked as a driver, then this was no roadkill
242  if (!killerContext || !killerContext.m_bPilot)
243  return;
244 
245  //Now we know the killer is not an AI and they are a driver. Add roadkill!
246  SCR_PlayerData killerData = GetGame().GetDataCollector().GetPlayerData(killerId);
247 
248  SCR_FactionManager factionManager = SCR_FactionManager.Cast(GetGame().GetFactionManager());
249  if (!factionManager)
250  return;
251 
252  Faction factionKiller = Faction.Cast(factionManager.GetPlayerFaction(killerId));
253  if (!factionKiller)
254  return;
255 
256  //Add an AI kill. Find if friendly or unfriendly
257  if (factionKiller.IsFactionFriendly(AIEntityChar.GetFaction()))
258  killerData.AddStat(SCR_EDataStats.FRIENDLY_AI_ROADKILLS);
259  else
260  killerData.AddStat(SCR_EDataStats.AI_ROADKILLS);
261  }
262 
263  //------------------------------------------------------------------------------------------------
264  override void OnPlayerDisconnected(int playerID, IEntity controlledEntity = null)
265  {
266  if (!controlledEntity)
267  controlledEntity = GetGame().GetPlayerManager().GetPlayerControlledEntity(playerID);
268  super.OnPlayerDisconnected(playerID, controlledEntity);
269 
270  m_mTrackedPlayersInVehicles.Remove(playerID);
271  }
272 
273  //------------------------------------------------------------------------------------------------
274  override void Update(float timeTick)
275  {
276  //If there are no players tracked, do nothing
277  if (m_mTrackedPlayersInVehicles.IsEmpty())
278  return;
279 
280  m_fTimeSinceUpdate += timeTick;
281 
282  if (m_fTimeSinceUpdate < m_fUpdatePeriod)
283  return;
284 
285  //Changed from for to foreach to avoid out of bounds exception
286  array<int> playerIDsToRemove = {};
287  foreach (int playerId, SCR_DataCollectorDriverModuleContext playerContext: m_mTrackedPlayersInVehicles)
288  {
289  if (!playerContext.m_Player || !playerContext.m_Vehicle)
290  {
291  Print("DataCollectorDriverModule:Update: this context's player or vehicle is null. Player ID: " + playerId + ". Seems wrong", LogLevel.WARNING);
292 
293  if (!playerIDsToRemove.Contains(playerId))
294  playerIDsToRemove.Insert(playerId);
295 
296  continue;
297  }
298 
299  Physics physics = playerContext.m_Vehicle.GetPhysics();
300  if (!physics)
301  {
302  Print("DataCollectorDriverModule:Update: Couldn't find the vehicle's physics. Player ID: " + playerId + ". Player is a pilot: " + playerContext.m_bPilot, LogLevel.WARNING);
303 
304  if (!playerIDsToRemove.Contains(playerId))
305  playerIDsToRemove.Insert(playerId);
306 
307  continue;
308  }
309 
310  float distanceTraveled = physics.GetVelocity().Length() * m_fTimeSinceUpdate;
311  if (distanceTraveled < 1)
312  continue;
313 
314  SCR_PlayerData playerData = GetGame().GetDataCollector().GetPlayerData(playerId);
315 
316  //If player is driver we give some points, if not we give others
317  if (playerContext.m_bPilot)
318  {
319  playerData.AddStat(SCR_EDataStats.DISTANCE_DRIVEN, distanceTraveled);
320 
321  //Need to find the number of players this pilot is driving around
322  //TODO: Replace this using a C++ implemented method to get the count of occupants of the vehicle
323  SCR_BaseCompartmentManagerComponent compartmentManagerComponent = SCR_BaseCompartmentManagerComponent.Cast(playerContext.m_Vehicle.FindComponent(SCR_BaseCompartmentManagerComponent));
324  if (!compartmentManagerComponent)
325  {
326  Print("DataCollectorDriverModule:Update: Could not add POINTS_AS_DRIVER_OF_PLAYERS because could find this vehicle's compartmentManagerComponent", LogLevel.WARNING);
327  continue;
328  }
329 
330  array<IEntity> occupants = {};
331  compartmentManagerComponent.GetOccupants(occupants);
332  int crewSize = occupants.Count();
333 
334  //Ignore dead crew
335  foreach (IEntity occupant : occupants)
336  {
337  ChimeraCharacter character = ChimeraCharacter.Cast(occupant);
338 
339  if (!character)
340  continue;
341 
342  CharacterControllerComponent characterController = character.GetCharacterController();
343 
344  if (!characterController || !characterController.IsDead())
345  continue;
346 
347  crewSize--;
348  }
349 
350  //Give points to driver for driving distanceTraveled meters. Not counting the driver as occupant for points calculation
351  //Only if there are some living crewmembers apart from the driver
352  if (crewSize > 1)
353  playerData.AddStat(SCR_EDataStats.POINTS_AS_DRIVER_OF_PLAYERS, distanceTraveled * (crewSize - 1) * playerData.GetConfigs().MODIFIER_DRIVER_OF_PLAYERS);
354  }
355  else
356  {
357  //Add distanceTraveled meters as occupant of a vehicle
358  playerData.AddStat(SCR_EDataStats.DISTANCE_AS_OCCUPANT, distanceTraveled);
359  }
360 
361  //DEBUG display
362 #ifdef ENABLE_DIAG
363  if (m_StatsVisualization)
364  {
365  m_StatsVisualization.Get(EDriverModuleStats.MetersDriven).SetText(playerData.GetStat(SCR_EDataStats.DISTANCE_DRIVEN).ToString());
366  m_StatsVisualization.Get(EDriverModuleStats.MetersAsOccupant).SetText(playerData.GetStat(SCR_EDataStats.DISTANCE_AS_OCCUPANT).ToString());
367  m_StatsVisualization.Get(EDriverModuleStats.PointsAsDriver).SetText(playerData.GetStat(SCR_EDataStats.POINTS_AS_DRIVER_OF_PLAYERS).ToString());
368  m_StatsVisualization.Get(EDriverModuleStats.RoadKills).SetText(playerData.GetStat(SCR_EDataStats.ROADKILLS).ToString());
369  m_StatsVisualization.Get(EDriverModuleStats.AIRoadKills).SetText(playerData.GetStat(SCR_EDataStats.AI_ROADKILLS).ToString());
370  m_StatsVisualization.Get(EDriverModuleStats.FriendlyRoadKills).SetText(playerData.GetStat(SCR_EDataStats.FRIENDLY_ROADKILLS).ToString());
371  m_StatsVisualization.Get(EDriverModuleStats.FriendlyAIRoadKills).SetText(playerData.GetStat(SCR_EDataStats.FRIENDLY_AI_KILLS).ToString());
372  m_StatsVisualization.Get(EDriverModuleStats.PlayersDiedInVehicle).SetText(playerData.GetStat(SCR_EDataStats.PLAYERS_DIED_IN_VEHICLE).ToString());
373  }
374 #endif
375  }
376 
377  foreach (int playerIdToRemove : playerIDsToRemove)
378  {
379  m_mTrackedPlayersInVehicles.Remove(playerIdToRemove);
380  }
381 
382  m_fTimeSinceUpdate = 0;
383  }
384 
385 #ifdef ENABLE_DIAG
386  //------------------------------------------------------------------------------------------------
387  override void CreateVisualization()
388  {
389  super.CreateVisualization();
390  if (!m_StatsVisualization)
391  return;
392 
393  CreateEntry("Meters driven: ", 0, EDriverModuleStats.MetersDriven);
394  CreateEntry("Meters as Occupant: ", 0, EDriverModuleStats.MetersAsOccupant);
395  CreateEntry("Points as Driver of ppl: ", 0, EDriverModuleStats.PointsAsDriver);
396  CreateEntry("RoadKills: ", 0, EDriverModuleStats.RoadKills);
397  CreateEntry("AI RoadKills: ", 0, EDriverModuleStats.AIRoadKills);
398  CreateEntry("Friendly RoadKills: ", 0, EDriverModuleStats.FriendlyRoadKills);
399  CreateEntry("Friendly AI RoadKills: ", 0, EDriverModuleStats.FriendlyAIRoadKills);
400  CreateEntry("DeadPlayers at ur Vehicle: ", 0, EDriverModuleStats.PlayersDiedInVehicle);
401  }
402 #endif
403 };
404 
405 #ifdef ENABLE_DIAG
406 enum EDriverModuleStats
407 {
408  MetersDriven,
409  MetersAsOccupant,
410  PointsAsDriver,
411  RoadKills,
412  AIRoadKills,
413  FriendlyRoadKills,
414  FriendlyAIRoadKills,
415  PlayersDiedInVehicle
416 };
417 #endif
InstigatorType
InstigatorType
Definition: InstigatorType.c:12
SCR_CompartmentAccessComponent
Definition: SCR_CompartmentAccessComponent.c:15
m_fTimeSinceUpdate
protected float m_fTimeSinceUpdate
Definition: SCR_RestrictedDeployableSpawnPointComponent.c:89
GetGame
ArmaReforgerScripted GetGame()
Definition: game.c:1424
ECompartmentType
ECompartmentType
Definition: ECompartmentType.c:7
EDamageState
EDamageState
Definition: EDamageState.c:12
SCR_PlayerData
Definition: SCR_PlayerData.c:2
Instigator
Definition: Instigator.c:6
m_Player
protected ChimeraCharacter m_Player
Definition: SCR_CampaignTutorialComponentArland.c:40
m_Vehicle
enum EAICompartmentType m_Vehicle
SCR_DataCollectorDriverModule
Definition: SCR_DataCollectorDriverModule.c:16
Faction
Definition: Faction.c:12
SCR_EDataStats
SCR_EDataStats
Definition: SCR_PlayerData.c:950
SCR_DataCollectorDriverModuleContext
Definition: SCR_DataCollectorDriverModule.c:1
SCR_FactionManager
void SCR_FactionManager(IEntitySource src, IEntity parent)
Definition: SCR_FactionManager.c:461
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