Arma Reforger Explorer  1.1.0.42
Arma Reforger Code Explorer by Zeroy - Thanks to MisterOutofTime
SCR_LocalPlayerPenalty.c
Go to the documentation of this file.
1 [EntityEditorProps(category: "GameScripted/GameMode", description: "Takes care of player penalties, kicks, bans etc.", color: "0 0 255 255")]
3 {
4 }
5 
6 class SCR_LocalPlayerPenalty : Managed
7 {
8  //[Attribute("3", desc: "Penalty score for killing a friendly player.")]
9  protected int m_iFriendlyPlayerKillPenalty;
10 
11  //[Attribute("1", desc: "Penalty score for killing a friendly AI.")]
12  protected int m_iFriendlyAIKillPenalty;
13 
14  //[Attribute("10", desc: "Penalty score limit for a kick from the match.")]
15  protected int m_iKickPenaltyLimit;
16 
17  //[Attribute("1800", desc: "Ban duration after a kick (in seconds, -1 for a session-long ban).")]
18  protected int m_iBanDuration;
19 
20  //[Attribute("900", desc: "How often penalty score subtraction happens (in seconds).")]
22 
23  //[Attribute("2", desc: "How many penalty points get substracted after each subtraction period.")]
25 
26  protected static SCR_LocalPlayerPenalty s_Instance;
27  protected static const int EVALUATION_PERIOD = 1000;
28 
29  protected ref array<ref SCR_LocalPlayerPenaltyData> m_aPlayerPenaltyData = {};
30 
31  //------------------------------------------------------------------------------------------------
33  void OnPlayerConnected(int playerId)
34  {
35  //GetPlayerPenaltyData creates the PlayerPenaltyStandaloneData for this playerId if it doesn't exist
36  GetPlayerPenaltyData(playerId);
37  }
38 
39  //------------------------------------------------------------------------------------------------
43  void OnControllableDestroyed(IEntity entity, IEntity killerEntity, Instigator instigator)
44  {
45  if (instigator.GetInstigatorType() != InstigatorType.INSTIGATOR_PLAYER || (m_iFriendlyAIKillPenalty == 0 && m_iFriendlyPlayerKillPenalty == 0))
46  return;
47 
48  SCR_ChimeraCharacter victimChar = SCR_ChimeraCharacter.Cast(entity);
49 
50  if (!victimChar)
51  return;
52 
53  int killerPlayerId = instigator.GetInstigatorPlayerID();
54  int victimPlayerId = GetGame().GetPlayerManager().GetPlayerIdFromControlledEntity(victimChar);
55 
56  //Suicide is not punishable by the Player Penalty system
57  if (killerPlayerId == victimPlayerId)
58  return;
59 
60  SCR_FactionManager factionManager = SCR_FactionManager.Cast(GetGame().GetFactionManager());
61  if (!factionManager)
62  return;
63 
64  Faction factionKiller = Faction.Cast(factionManager.GetPlayerFaction(killerPlayerId));
65  if (!factionKiller)
66  return;
67 
68  //If it's no friendly kill, no wrongdoing was committed
69  if (!factionKiller.IsFactionFriendly(victimChar.GetFaction()))
70  return;
71 
72  SCR_LocalPlayerPenaltyData playerPenaltyData = GetPlayerPenaltyData(killerPlayerId);
73 
74  if (victimPlayerId <= 0)
75  playerPenaltyData.AddPenaltyScore(m_iFriendlyAIKillPenalty);
76  else
77  playerPenaltyData.AddPenaltyScore(m_iFriendlyPlayerKillPenalty);
78  }
79 
80  //------------------------------------------------------------------------------------------------
83  {
84  return s_Instance;
85  }
86 
87  //------------------------------------------------------------------------------------------------
91  //IT SHOULD NOT BE STATIC. TODO: IMPROVE THIS
92  static SCR_ChimeraCharacter GetInstigatorFromVehicle(IEntity veh, bool gunner = false)
93  {
94  BaseCompartmentManagerComponent compartmentManager = BaseCompartmentManagerComponent.Cast(veh.FindComponent(BaseCompartmentManagerComponent));
95 
96  if (!compartmentManager)
97  return null;
98 
99  array<BaseCompartmentSlot> compartments = new array <BaseCompartmentSlot>();
100 
101  for (int i = 0, cnt = compartmentManager.GetCompartments(compartments); i < cnt; i++)
102  {
103  BaseCompartmentSlot slot = compartments[i];
104 
105  if (slot && (!gunner && slot.Type() == PilotCompartmentSlot) || (gunner && slot.Type() == TurretCompartmentSlot))
106  return SCR_ChimeraCharacter.Cast(slot.GetOccupant());
107  }
108 
109  return null;
110  }
111 
112  //------------------------------------------------------------------------------------------------
114  {
115  if (playerId == 0)
116  return null;
117 
118  SCR_LocalPlayerPenaltyData playerPenaltyData;
119 
120  // Check if the client is reconnecting
121  //Also if there's going to be many entries, the search might prove very expensive.
122  for (int i = 0, count = m_aPlayerPenaltyData.Count(); i < count; i++)
123  {
124  if (m_aPlayerPenaltyData[i].GetPlayerId() == playerId)
125  {
126  playerPenaltyData = m_aPlayerPenaltyData[i];
127  break;
128  }
129  }
130 
131  // Client reconnected, return saved data
132  if (playerPenaltyData)
133  return playerPenaltyData;
134 
135  // Check validity of playerId before registering new data
136  PlayerController pc = GetGame().GetPlayerManager().GetPlayerController(playerId);
137 
138  if (!pc)
139  {
140  Print(string.Format("SCR_PlayerPenaltyComponent: No player with playerId %1 found.", playerId), LogLevel.ERROR);
141  return null;
142  }
143 
144  // First connection, register new data
145  playerPenaltyData = new SCR_LocalPlayerPenaltyData();
146  playerPenaltyData.SetPlayerId(playerId);
147  m_aPlayerPenaltyData.Insert(playerPenaltyData);
148 
149  return playerPenaltyData;
150  }
151 
152  //------------------------------------------------------------------------------------------------
153  protected void EvaluatePlayerPenalties()
154  {
155  ChimeraWorld world = GetGame().GetWorld();
156  WorldTimestamp currentTime = world.GetServerTimestamp();
157  for (int i = 0, count = m_aPlayerPenaltyData.Count(); i < count; i++)
158  {
159  SCR_LocalPlayerPenaltyData playerPenaltyData = m_aPlayerPenaltyData[i];
160 
161  // Periodically forgive a portion of penalty score, don't go below zero
162  if (playerPenaltyData.GetPenaltyScore() > 0 && playerPenaltyData.GetNextPenaltySubtractionTimestamp().Less(currentTime))
163  {
164  int forgivenScore;
165 
166  if (m_iPenaltySubtractionPoints > playerPenaltyData.GetPenaltyScore())
167  forgivenScore = playerPenaltyData.GetPenaltyScore();
168  else
169  forgivenScore = m_iPenaltySubtractionPoints;
170 
171  playerPenaltyData.AddPenaltyScore(-forgivenScore);
172  }
173 
174  int playerId = playerPenaltyData.GetPlayerId();
175 
176  // Player is not connected
177  if (!GetGame().GetPlayerManager().GetPlayerController(playerId))
178  continue;
179 
180  // Player is host
181  if (playerId == SCR_PlayerController.GetLocalPlayerId())
182  continue;
183 
184  // Check penalty limit for kick / ban
185  if (m_iKickPenaltyLimit > 0 && playerPenaltyData.GetPenaltyScore() >= m_iKickPenaltyLimit)
186  {
187  // TODO: Use callback from backend instead
188  KickPlayer(playerId, m_iBanDuration, SCR_PlayerManagerKickReason.FRIENDLY_FIRE);
189  continue;
190  }
191  }
192  }
193 
194  //------------------------------------------------------------------------------------------------
199  void KickPlayer(int playerId, int duration, SCR_PlayerManagerKickReason reason)
200  {
201  SCR_LocalPlayerPenaltyData playerPenaltyData = GetPlayerPenaltyData(playerId);
202 
203  if (playerPenaltyData)
204  playerPenaltyData.AddPenaltyScore(-playerPenaltyData.GetPenaltyScore());
205 
206  GetGame().GetPlayerManager().KickPlayer(playerId, reason, duration);
207  }
208 
209  //------------------------------------------------------------------------------------------------
212  {
213  return m_iPenaltySubtractionPeriod * 1000; // Converting s to ms
214  }
215 
216  //------------------------------------------------------------------------------------------------
217  // constructor
224  void SCR_LocalPlayerPenalty(int friendlyPlayerKillPenalty, int friendlyAIKillPenalty, int penaltyLimit, int banDuration, int penaltySubtractionPeriod, int penaltySubtractionPoints)
225  {
226  m_iFriendlyPlayerKillPenalty = friendlyPlayerKillPenalty;
227  m_iFriendlyAIKillPenalty = friendlyAIKillPenalty;
228  m_iKickPenaltyLimit = penaltyLimit;
229  m_iBanDuration = banDuration;
230  m_iPenaltySubtractionPeriod = penaltySubtractionPeriod;
231  m_iPenaltySubtractionPoints = penaltySubtractionPoints;
232 
234  Print("SCR_PlayerPenaltyComponent: Ban duration is shorter than Penalty substraction period. This will cause the player to remain banned until their penalty is substracted.", LogLevel.WARNING);
235 
236  s_Instance = this;
237  //Looping every EVALUATION_PERIOD seconds and don't need other EOn events
238  GetGame().GetCallqueue().CallLater(EvaluatePlayerPenalties, EVALUATION_PERIOD, true);
239  }
240 }
241 
243 {
244  protected int m_iPlayerId;
245  protected int m_iPenaltyScore;
246  protected WorldTimestamp m_fNextPenaltySubtractionTimestamp;
247  protected SCR_PlayerManagerKickReason m_eKickReason = SCR_PlayerManagerKickReason.DISRUPTIVE_BEHAVIOUR;
248 
249  //------------------------------------------------------------------------------------------------
251  void SetPlayerId(int playerId)
252  {
253  m_iPlayerId = playerId;
254  }
255 
256  //------------------------------------------------------------------------------------------------
258  int GetPlayerId()
259  {
260  return m_iPlayerId;
261  }
262 
263  //------------------------------------------------------------------------------------------------
266  void AddPenaltyScore(int points)
267  {
268  m_iPenaltyScore += points;
269 
270  // Start the timer on penalty substraction when player was penalized while the timer was stopped
271  ChimeraWorld world = GetGame().GetWorld();
272  WorldTimestamp currentTime = world.GetServerTimestamp();
273  if ((points > 0 && m_fNextPenaltySubtractionTimestamp.Less(currentTime)) || (points < 0 && m_iPenaltyScore > 0))
274  m_fNextPenaltySubtractionTimestamp = currentTime.PlusMilliseconds(SCR_LocalPlayerPenalty.GetInstance().GetPenaltySubtractionPeriod());
275  }
276 
277  //------------------------------------------------------------------------------------------------
279  float GetPenaltyScore()
280  {
281  return m_iPenaltyScore;
282  }
283 
284  //------------------------------------------------------------------------------------------------
286  void SetNextPenaltySubstractionTimestamp(WorldTimestamp timestamp)
287  {
288  m_fNextPenaltySubtractionTimestamp = timestamp;
289  }
290 
291  //------------------------------------------------------------------------------------------------
293  WorldTimestamp GetNextPenaltySubtractionTimestamp()
294  {
295  return m_fNextPenaltySubtractionTimestamp;
296  }
297 }
ChimeraWorld
Definition: ChimeraWorld.c:12
GetPlayerPenaltyData
protected SCR_LocalPlayerPenaltyData GetPlayerPenaltyData(int playerId)
Definition: SCR_LocalPlayerPenalty.c:113
InstigatorType
InstigatorType
Definition: InstigatorType.c:12
m_iFriendlyPlayerKillPenalty
SCR_LocalPlayerPenaltyClass m_iFriendlyPlayerKillPenalty
SCR_PlayerController
Definition: SCR_PlayerController.c:31
SCR_LocalPlayerPenaltyData
Definition: SCR_LocalPlayerPenalty.c:242
OnControllableDestroyed
void OnControllableDestroyed(IEntity entity, IEntity killerEntity, Instigator instigator)
Definition: SCR_LocalPlayerPenalty.c:43
EntityEditorProps
enum EQueryType EntityEditorProps(category:"GameScripted/Sound", description:"THIS IS THE SCRIPT DESCRIPTION.", color:"0 0 255 255")
Definition: SCR_AmbientSoundsComponent.c:12
m_iPenaltySubtractionPoints
protected int m_iPenaltySubtractionPoints
Definition: SCR_LocalPlayerPenalty.c:24
GetInstance
SCR_TextsTaskManagerComponentClass ScriptComponentClass GetInstance()
Definition: SCR_TextsTaskManagerComponent.c:50
GetGame
ArmaReforgerScripted GetGame()
Definition: game.c:1424
OnPlayerConnected
void OnPlayerConnected(int playerId)
Definition: SCR_LocalPlayerPenalty.c:33
PilotCompartmentSlot
Definition: PilotCompartmentSlot.c:12
SCR_LocalPlayerPenalty
void SCR_LocalPlayerPenalty(int friendlyPlayerKillPenalty, int friendlyAIKillPenalty, int penaltyLimit, int banDuration, int penaltySubtractionPeriod, int penaltySubtractionPoints)
Definition: SCR_LocalPlayerPenalty.c:224
GetPlayerController
proto external PlayerController GetPlayerController()
Definition: SCR_PlayerDeployMenuHandlerComponent.c:307
KickPlayer
void KickPlayer(int playerId, int duration, SCR_PlayerManagerKickReason reason)
Definition: SCR_LocalPlayerPenalty.c:199
Instigator
Definition: Instigator.c:6
m_iFriendlyAIKillPenalty
protected int m_iFriendlyAIKillPenalty
Definition: SCR_LocalPlayerPenalty.c:12
m_iBanDuration
protected int m_iBanDuration
Definition: SCR_LocalPlayerPenalty.c:18
m_aPlayerPenaltyData
protected ref array< ref SCR_LocalPlayerPenaltyData > m_aPlayerPenaltyData
Definition: SCR_LocalPlayerPenalty.c:29
TurretCompartmentSlot
Definition: TurretCompartmentSlot.c:12
m_iKickPenaltyLimit
protected int m_iKickPenaltyLimit
Definition: SCR_LocalPlayerPenalty.c:15
SCR_LocalPlayerPenaltyClass
Definition: SCR_LocalPlayerPenalty.c:2
m_iPlayerId
protected int m_iPlayerId
Definition: SCR_CallsignCharacterComponent.c:14
Faction
Definition: Faction.c:12
EvaluatePlayerPenalties
protected void EvaluatePlayerPenalties()
Definition: SCR_LocalPlayerPenalty.c:153
SCR_FactionManager
void SCR_FactionManager(IEntitySource src, IEntity parent)
Definition: SCR_FactionManager.c:461
GetPenaltySubtractionPeriod
int GetPenaltySubtractionPeriod()
Definition: SCR_LocalPlayerPenalty.c:211
m_iPenaltySubtractionPeriod
protected int m_iPenaltySubtractionPeriod
Definition: SCR_LocalPlayerPenalty.c:21
GetPlayerId
proto external int GetPlayerId()
Definition: SCR_SpawnRequestComponent.c:39
category
params category
Definition: SCR_VehicleDamageManagerComponent.c:180