Arma Reforger Explorer 1.7.0.54
Arma Reforger Code Explorer by Zeroy - Thanks to MisterOutofTime
Loading...
Searching...
No Matches
SCR_DataCollectorDriverModule.c
Go to the documentation of this file.
1class SCR_DataCollectorDriverModuleContext : Managed
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{
19
20 //------------------------------------------------------------------------------------------------
21 protected override void AddInvokers(IEntity player)
22 {
23 super.AddInvokers(player);
24 if (!player)
25 return;
26
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
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?
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/*
102TODO: 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 instigator, notnull SCR_InstigatorContextData instigatorContextData)
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 (instigator.GetInstigatorType() != InstigatorType.INSTIGATOR_PLAYER)
188 return;
189
190 //~ The player was not killed by a player so do nothing (Like suicide)
191 if (!instigatorContextData.HasAnyVictimKillerRelation(SCR_ECharacterDeathStatusRelations.KILLED_BY_ENEMY_PLAYER | SCR_ECharacterDeathStatusRelations.KILLED_BY_FRIENDLY_PLAYER))
192 return;
193
194 int killerId = instigator.GetInstigatorPlayerID();
195
196 //If the killer is not tracked as a driver, then this was no roadkill
198 if (!killerContext || !killerContext.m_bPilot)
199 return;
200
201 //~ Get killer data in order to add roadkill stats
202 SCR_PlayerData killerData = GetGame().GetDataCollector().GetPlayerData(killerId);
203 if (!killerData)
204 return;
205
206 //~ Roadkill enemy
207 if (instigatorContextData.HasAnyVictimKillerRelation(SCR_ECharacterDeathStatusRelations.KILLED_BY_ENEMY_PLAYER))
208 {
209 if (!instigatorContextData.IsEnemyKillPunished(SCR_EDisguisedKillingPunishment.WARCRIME))
210 killerData.AddStat(SCR_EDataStats.ROADKILLS);
211 //~ Killing while disguised is a warcrime
212 else
213 killerData.AddStat(SCR_EDataStats.FRIENDLY_ROADKILLS);
214 }
215
216 //~ Roadkill friendly
217 else
218 {
219 if (instigatorContextData.DoesPlayerKillCountAsTeamKill())
220 killerData.AddStat(SCR_EDataStats.FRIENDLY_ROADKILLS);
221 }
222
223 }
224
225 //------------------------------------------------------------------------------------------------
226 override void OnAIKilled(IEntity AIEntity, IEntity killerEntity, notnull Instigator instigator, notnull SCR_InstigatorContextData instigatorContextData)
227 {
228 //We are only looking for roadkills here. That's why we don't call super.OnAIKilled. This behaviour is very specific
229 if (instigator.GetInstigatorType() != InstigatorType.INSTIGATOR_PLAYER)
230 return;
231
232 //~ The player was not killed by a player so do nothing (Like suicide)
233 if (!instigatorContextData.HasAnyVictimKillerRelation(SCR_ECharacterDeathStatusRelations.KILLED_BY_ENEMY_PLAYER | SCR_ECharacterDeathStatusRelations.KILLED_BY_FRIENDLY_PLAYER))
234 return;
235
236 int killerId = instigator.GetInstigatorPlayerID();
237
238 SCR_ChimeraCharacter AIEntityChar = SCR_ChimeraCharacter.Cast(AIEntity);
239 if (!AIEntityChar)
240 return;
241
243 //If the killer is not tracked as a driver, then this was no roadkill
244 if (!killerContext || !killerContext.m_bPilot)
245 return;
246
247 //Now we know the killer is not an AI and they are a driver. Add roadkill!
248 SCR_PlayerData killerData = GetGame().GetDataCollector().GetPlayerData(killerId);
249
250 //Add an AI kill. Find if friendly or unfriendly
251 if (instigatorContextData.HasAnyVictimKillerRelation(SCR_ECharacterDeathStatusRelations.KILLED_BY_ENEMY_PLAYER))
252 {
253 if (!instigatorContextData.IsEnemyKillPunished(SCR_EDisguisedKillingPunishment.WARCRIME))
254 killerData.AddStat(SCR_EDataStats.AI_ROADKILLS);
255 //~ Killing while disguised is a warcrime
256 else
257 killerData.AddStat(SCR_EDataStats.FRIENDLY_AI_ROADKILLS);
258 }
259 //~ friendly
260 else
261 {
262 //~ Counts as teamkill
263 if (instigatorContextData.DoesPlayerKillCountAsTeamKill())
264 killerData.AddStat(SCR_EDataStats.FRIENDLY_AI_ROADKILLS);
265 }
266
267 }
268
269 //------------------------------------------------------------------------------------------------
270 override void OnPlayerDisconnected(int playerID, IEntity controlledEntity = null)
271 {
272 if (!controlledEntity)
273 controlledEntity = GetGame().GetPlayerManager().GetPlayerControlledEntity(playerID);
274 super.OnPlayerDisconnected(playerID, controlledEntity);
275
276 m_mTrackedPlayersInVehicles.Remove(playerID);
277 }
278
279 //------------------------------------------------------------------------------------------------
280 override void Update(float timeTick)
281 {
282 //If there are no players tracked, do nothing
283 if (m_mTrackedPlayersInVehicles.IsEmpty())
284 return;
285
286 m_fTimeSinceUpdate += timeTick;
287
289 return;
290
291 //Changed from for to foreach to avoid out of bounds exception
292 array<int> playerIDsToRemove = {};
293 foreach (int playerId, SCR_DataCollectorDriverModuleContext playerContext: m_mTrackedPlayersInVehicles)
294 {
295 if (!playerContext.m_Player || !playerContext.m_Vehicle)
296 {
297 Print("DataCollectorDriverModule:Update: this context's player or vehicle is null. Player ID: " + playerId + ". Seems wrong", LogLevel.WARNING);
298
299 if (!playerIDsToRemove.Contains(playerId))
300 playerIDsToRemove.Insert(playerId);
301
302 continue;
303 }
304
305 Physics physics = playerContext.m_Vehicle.GetPhysics();
306 if (!physics)
307 {
308 Print("DataCollectorDriverModule:Update: Couldn't find the vehicle's physics. Player ID: " + playerId + ". Player is a pilot: " + playerContext.m_bPilot, LogLevel.WARNING);
309
310 if (!playerIDsToRemove.Contains(playerId))
311 playerIDsToRemove.Insert(playerId);
312
313 continue;
314 }
315
316 float distanceTraveled = physics.GetVelocity().Length() * m_fTimeSinceUpdate;
317 if (distanceTraveled < 1)
318 continue;
319
320 SCR_PlayerData playerData = GetGame().GetDataCollector().GetPlayerData(playerId);
321
322 //If player is driver we give some points, if not we give others
323 if (playerContext.m_bPilot)
324 {
325 playerData.AddStat(SCR_EDataStats.DISTANCE_DRIVEN, distanceTraveled);
326
327 //Need to find the number of players this pilot is driving around
328 //TODO: Replace this using a C++ implemented method to get the count of occupants of the vehicle
329 SCR_BaseCompartmentManagerComponent compartmentManagerComponent = SCR_BaseCompartmentManagerComponent.Cast(playerContext.m_Vehicle.FindComponent(SCR_BaseCompartmentManagerComponent));
330 if (!compartmentManagerComponent)
331 {
332 Print("DataCollectorDriverModule:Update: Could not add POINTS_AS_DRIVER_OF_PLAYERS because could find this vehicle's compartmentManagerComponent", LogLevel.WARNING);
333 continue;
334 }
335
336 array<IEntity> occupants = {};
337 compartmentManagerComponent.GetOccupants(occupants);
338 int crewSize = occupants.Count();
339
340 //Ignore dead crew and AI
341 foreach (IEntity occupant : occupants)
342 {
343 if (!EntityUtils.IsPlayer(occupant))
344 {
345 crewSize--;
346 continue;
347 }
348
349 ChimeraCharacter character = ChimeraCharacter.Cast(occupant);
350
351 if (!character)
352 continue;
353
354 CharacterControllerComponent characterController = character.GetCharacterController();
355
356 if (!characterController || !characterController.IsDead())
357 continue;
358
359 crewSize--;
360 }
361
362 //Give points to driver for driving distanceTraveled meters. Not counting the driver as occupant for points calculation
363 //Only if there are some living crewmembers apart from the driver
364 if (crewSize > 1)
365 playerData.AddStat(SCR_EDataStats.POINTS_AS_DRIVER_OF_PLAYERS, distanceTraveled * (crewSize - 1) * playerData.GetConfigs().MODIFIER_DRIVER_OF_PLAYERS);
366 }
367 else
368 {
369 //Add distanceTraveled meters as occupant of a vehicle
370 playerData.AddStat(SCR_EDataStats.DISTANCE_AS_OCCUPANT, distanceTraveled);
371 }
372
373 //DEBUG display
374#ifdef ENABLE_DIAG
376 {
377 m_StatsVisualization.Get(EDriverModuleStats.MetersDriven).SetText(playerData.GetStat(SCR_EDataStats.DISTANCE_DRIVEN).ToString());
378 m_StatsVisualization.Get(EDriverModuleStats.MetersAsOccupant).SetText(playerData.GetStat(SCR_EDataStats.DISTANCE_AS_OCCUPANT).ToString());
379 m_StatsVisualization.Get(EDriverModuleStats.PointsAsDriver).SetText(playerData.GetStat(SCR_EDataStats.POINTS_AS_DRIVER_OF_PLAYERS).ToString());
380 m_StatsVisualization.Get(EDriverModuleStats.RoadKills).SetText(playerData.GetStat(SCR_EDataStats.ROADKILLS).ToString());
381 m_StatsVisualization.Get(EDriverModuleStats.AIRoadKills).SetText(playerData.GetStat(SCR_EDataStats.AI_ROADKILLS).ToString());
382 m_StatsVisualization.Get(EDriverModuleStats.FriendlyRoadKills).SetText(playerData.GetStat(SCR_EDataStats.FRIENDLY_ROADKILLS).ToString());
383 m_StatsVisualization.Get(EDriverModuleStats.FriendlyAIRoadKills).SetText(playerData.GetStat(SCR_EDataStats.FRIENDLY_AI_KILLS).ToString());
384 m_StatsVisualization.Get(EDriverModuleStats.PlayersDiedInVehicle).SetText(playerData.GetStat(SCR_EDataStats.PLAYERS_DIED_IN_VEHICLE).ToString());
385 }
386#endif
387 }
388
389 foreach (int playerIdToRemove : playerIDsToRemove)
390 {
391 m_mTrackedPlayersInVehicles.Remove(playerIdToRemove);
392 }
393
395 }
396
397#ifdef ENABLE_DIAG
398 //------------------------------------------------------------------------------------------------
399 override void CreateVisualization()
400 {
401 super.CreateVisualization();
403 return;
404
405 CreateEntry("Meters driven: ", 0, EDriverModuleStats.MetersDriven);
406 CreateEntry("Meters as Occupant: ", 0, EDriverModuleStats.MetersAsOccupant);
407 CreateEntry("Points as Driver of ppl: ", 0, EDriverModuleStats.PointsAsDriver);
408 CreateEntry("RoadKills: ", 0, EDriverModuleStats.RoadKills);
409 CreateEntry("AI RoadKills: ", 0, EDriverModuleStats.AIRoadKills);
410 CreateEntry("Friendly RoadKills: ", 0, EDriverModuleStats.FriendlyRoadKills);
411 CreateEntry("Friendly AI RoadKills: ", 0, EDriverModuleStats.FriendlyAIRoadKills);
412 CreateEntry("DeadPlayers at ur Vehicle: ", 0, EDriverModuleStats.PlayersDiedInVehicle);
413 }
414#endif
415};
416
417#ifdef ENABLE_DIAG
418enum EDriverModuleStats
419{
420 MetersDriven,
421 MetersAsOccupant,
422 PointsAsDriver,
423 RoadKills,
424 AIRoadKills,
425 FriendlyRoadKills,
426 FriendlyAIRoadKills,
427 PlayersDiedInVehicle
428};
429#endif
ECompartmentType
ArmaReforgerScripted GetGame()
Definition game.c:1398
SCR_AIAnimation_Loitering BaseContainerProps
Commanding menu commanding element class.
SCR_EDataStats
proto external Managed FindComponent(typename typeName)
ScriptInvoker GetOnCompartmentEntered(bool createNew=true)
ScriptInvoker GetOnCompartmentLeft(bool createNew=true)
void PlayerDied(int PlayerID, notnull SCR_DataCollectorDriverModuleContext playerContext)
void OnCompartmentLeft(IEntity targetEntity, BaseCompartmentManagerComponent manager, int mgrID, int slotID, bool move)
override void OnPlayerDisconnected(int playerID, IEntity controlledEntity=null)
void OnCompartmentEntered(IEntity targetEntity, BaseCompartmentManagerComponent manager, int mgrID, int slotID, bool move)
override void AddInvokers(IEntity player)
override void OnAIKilled(IEntity AIEntity, IEntity killerEntity, notnull Instigator instigator, notnull SCR_InstigatorContextData instigatorContextData)
ref map< int, ref SCR_DataCollectorDriverModuleContext > m_mTrackedPlayersInVehicles
override void RemoveInvokers(IEntity player)
override void OnPlayerKilled(int playerId, IEntity playerEntity, IEntity killerEntity, notnull Instigator instigator, notnull SCR_InstigatorContextData instigatorContextData)
ref map< int, TextWidget > m_StatsVisualization
static const float MODIFIER_DRIVER_OF_PLAYERS
SCR_PlayerDataConfigs GetConfigs()
void AddStat(SCR_EDataStats stat, float amount=1, bool temp=true)
float GetStat(SCR_EDataStats stat, bool newStat=true)
static SCR_PlayerData GetPlayerData(int playerID)
Definition Types.c:486
InstigatorType
proto void Print(void var, LogLevel level=LogLevel.NORMAL)
Prints content of variable to console/log.
LogLevel
Enum with severity of the logging message.
Definition LogLevel.c:14
EDamageState