DayZ 1.24
Loading...
Searching...
No Matches
missionServer.c
Go to the documentation of this file.
1
2//: string uid of the player
4
5class MissionServer extends MissionBase
6{
12 const int SCHEDULER_PLAYERS_PER_TICK = 5;
15
16 // -----------------------
17 // ARTILLERY SOUNDS SETUP
18 // -----------------------
19 private float m_ArtyBarrageTimer = 0; // This is not to be edited in Init.c this is just to increment time
20
21 // Variables to be modified in Init.c
22 protected bool m_PlayArty = false; // Toggle if Off map artillery sounds are played
23 protected float m_ArtyDelay = 0; // Set how much time there is between two barrages (in seconds)
24 protected int m_MinSimultaneousStrikes = 0; // The MIN of simultaneous shots on the map (Will be clamped between 1 and max shots)
25 protected int m_MaxSimultaneousStrikes = 0; // The MAX of simultaneous shots on the map (Will be clamped between 1 and max amount of coords)
26 protected ref array<vector> m_FiringPos; // Where we should fire from. On Init set the relevant data
27
28 //All Chernarus firing coordinates
29 protected const ref array<vector> CHERNARUS_STRIKE_POS = {
30 "-500.00 165.00 5231.69",
31 "-500.00 300.00 9934.41",
32 "10406.86 192.00 15860.00",
33 "4811.75 370.00 15860.00",
34 "-500.00 453.00 15860.00"
35 };
36
37 //All livonia firing coordinates
38 protected const ref array<vector> LIVONIA_STRIKE_POS = {
39 "7440.00 417.00 -500.00",
40 "-500.00 276.00 5473.00",
41 "-500.00 265.00 9852.00",
42 "4953.00 240.00 13300.00",
43 "9620.00 188.00 13300.00",
44 "13300.00 204.00 10322.00",
45 "13300.00 288.00 6204.00",
46 "13300.00 296.00 -500.00"
47 };
48 // -----------------------
49 // END OF ARTILLERY SETUP
50 // -----------------------
51
55
57 {
58 GetGame().GetCallQueue(CALL_CATEGORY_GAMEPLAY).CallLater(this.UpdatePlayersStats, 30000, true);
59
60 m_DeadPlayersArray = new array<ref CorpseData>;
62 m_Players = new array<Man>;
63
64 m_LogoutPlayers = new map<PlayerBase, ref LogoutInfo>;
65 m_NewLogoutPlayers = new map<PlayerBase, ref LogoutInfo>;
66 m_RainProcHandler = new RainProcurementHandler(this);
67 }
68
70 {
71 GetGame().GetCallQueue(CALL_CATEGORY_GAMEPLAY).Remove(this.UpdatePlayersStats);
72 }
73
74 override void OnInit()
75 {
76 super.OnInit();
80 //Either pass consts in Init.c or insert all desired coords (or do both ;))
81 m_FiringPos = new array<vector>();
82 }
83
84 override void OnMissionStart()
85 {
86 super.OnMissionStart();
87
88 // We will load the Effect areas on Default mission start
90 }
91
92 override void OnUpdate(float timeslice)
93 {
94 UpdateDummyScheduler();
97 m_WorldData.UpdateBaseEnvTemperature(timeslice); // re-calculate base enviro temperature
98 m_RainProcHandler.Update(timeslice);
99
101
102 super.OnUpdate(timeslice);
103 }
104
106 {
108 GetGame().SetDebugMonitorEnabled(GetGame().ServerConfigGetInt("enableDebugMonitor"));
109
110 InitialiseWorldData();
111 }
112
113
115 {
116 // ARTY barrage
117 if (m_PlayArty)
118 {
119 // We only perform timer checks and increments if we enabled the artillery barrage
120 if (m_ArtyBarrageTimer > m_ArtyDelay)
121 {
122 //We clamp to guarantee 1 and never have multiple shots on same pos, even in case of entry error
123 m_MaxSimultaneousStrikes = Math.Clamp(m_MaxSimultaneousStrikes, 1, m_FiringPos.Count());
124 m_MinSimultaneousStrikes = Math.Clamp(m_MinSimultaneousStrikes, 1, m_MaxSimultaneousStrikes);
125
126 // Variables to be used in this scope
127 int randPos; // Select random position
128 Param1<vector> pos; // The value to be sent through RPC
129 array<ref Param> params; // The RPC params
130
131 if (m_MaxSimultaneousStrikes == 1)
132 {
133 // We only have one set of coordinates to send
134 randPos = Math.RandomIntInclusive(0, m_FiringPos.Count() - 1);
135 pos = new Param1<vector>(m_FiringPos[randPos]);
137 params.Insert(pos);
138 GetGame().RPC(null, ERPCs.RPC_SOUND_ARTILLERY, params, true);
139 }
140 else
141 {
142 //We will do some extra steps to
143 /*
144 1. Send multiple coords (Send one RPC per coord set)
145 2. Ensure we don't have duplicates
146 */
147 array<int> usedIndices = new array<int>; // Will store all previusly fired upon indices
148
149 // We determine how many positions fire between MIN and MAX
150 int randFireNb = Math.RandomIntInclusive(m_MinSimultaneousStrikes, m_MaxSimultaneousStrikes);
151 for (int i = 0; i < randFireNb; i++)
152 {
153 randPos = Math.RandomIntInclusive(0, m_FiringPos.Count() - 1);
154
155 if (usedIndices.Count() <= 0 || usedIndices.Find(randPos) < 0) //We do not find the index or array is empty
156 {
157 // We prepare to send the message
158 pos = new Param1<vector>(m_FiringPos[randPos]);
160
161 // We send the message with this set of coords
162 params.Insert(pos);
163 GetGame().RPC(null, ERPCs.RPC_SOUND_ARTILLERY, params, true);
164
165 // We store the last used value
166 usedIndices.Insert(randPos);
167 }
168 }
169 }
170
171 // Reset timer for new loop
172 m_ArtyBarrageTimer = 0.0;
173 }
174
175 m_ArtyBarrageTimer += deltaTime;
176 }
177 }
178
179 override bool IsServer()
180 {
181 return true;
182 }
183
184 override bool IsPlayerDisconnecting(Man player)
185 {
186 return (m_LogoutPlayers && m_LogoutPlayers.Contains(PlayerBase.Cast(player))) || (m_NewLogoutPlayers && m_NewLogoutPlayers.Contains(PlayerBase.Cast(player)));
187 }
188
190 {
194 GetGame().GetPlayers(players);
195
196 foreach (Man man : players)
197 {
199 if (Class.CastTo(player, man))
200 {
202 player.StatUpdateByPosition(AnalyticsManagerServer.STAT_DISTANCE);
203
204 moduleLifespan.UpdateLifespan(player);
205 }
206 }
207
209 }
210
212 {
213 m_LogoutPlayers.Insert(player, info);
214 m_NewLogoutPlayers.Remove(player);
215 }
216
217 // check if logout finished for some players
219 {
220 for (int i = 0; i < m_LogoutPlayers.Count();)
221 {
222 LogoutInfo info = m_LogoutPlayers.GetElement(i);
223
224 if (GetGame().GetTime() >= info.param1)
225 {
227 PlayerBase player = m_LogoutPlayers.GetKey(i);
228 if (player)
229 {
230 identity = player.GetIdentity();
231 m_LogoutPlayers.Remove(player);
232 }
233 else
234 m_LogoutPlayers.RemoveElement(i);
235
236 // disable reconnecting to old char
237 // GetGame().RemoveFromReconnectCache(info.param2);
238
240 }
241 else
242 ++i;
243 }
244 }
245
247 {
250 int counter = 0;
251
252 switch (eventTypeId)
253 {
260 break;
261
265 player = OnClientNewEvent(newParams.param1, newParams.param2, newParams.param3);
266 if (!player)
267 {
268 Debug.Log("ClientNewEvent: Player is empty");
269 return;
270 }
271 identity = newParams.param1;
274
277
278 break;
279
283 identity = readyParams.param1;
285 if (!player)
286 {
287 Debug.Log("ClientReadyEvent: Player is empty");
288 return;
289 }
290
293 // Send list of players at all clients
297 break;
298
302 identity = respawnParams.param1;
304 if (!player)
305 {
306 Debug.Log("ClientRespawnEvent: Player is empty");
307 return;
308 }
309
311 break;
312
316
317 identity = reconnectParams.param1;
319 if (!player)
320 {
321 Debug.Log("ClientReconnectEvent: Player is empty");
322 return;
323 }
324
326 break;
327
331
332 identity = discoParams.param1;
334 int logoutTime = discoParams.param3;
335 bool authFailed = discoParams.param4;
336
337 if (!player)
338 {
339 Debug.Log("ClientDisconnectenEvent: Player is empty");
340 return;
341 }
342
344 break;
345
348
351 identity = player.GetIdentity();
352 if (identity)
353 {
354 // disable reconnecting to old char
355 // GetGame().RemoveFromReconnectCache(identity.GetId());
356 Print("[Logout]: Player " + identity.GetId() + " cancelled");
357 }
358 else
359 Print("[Logout]: Player cancelled");
360 m_LogoutPlayers.Remove(player);
361 m_NewLogoutPlayers.Remove(player);
362 break;
363 }
364 }
365
367 {
368 Debug.Log("InvokeOnConnect:" + this.ToString(), "Connect");
369 if (player)
370 player.OnConnect();
371 }
372
374 {
375 Debug.Log("InvokeOnDisconnect:" + this.ToString(), "Connect");
376 if (player)
377 player.OnDisconnect();
378 }
379
381 {
382 if (GetHive())
383 {
384 // use character from database
385 useDB = true;
386 }
387 else
388 {
389 // use following data without database
390 useDB = false;
391 pos = "1189.3 0.0 5392.48";
392 yaw = 0;
393 }
394 }
395
396 // Enables/Disables personal light on the given player.
398 {
399 if (player)
400 {
401 bool is_personal_light = ! GetGame().ServerConfigGetInt("disablePersonalLight");
403 GetGame().RPCSingleParam(player, ERPCs.RPC_TOGGLE_PERSONAL_LIGHT, personal_light_toggle, true, player.GetIdentity());
404 }
405 else
406 Error("Error! Player was not initialized at the right time. Thus cannot send RPC command to enable or disable personal light!");
407 }
408
409 // syncs global lighting setup from the server (lightingConfig server config parameter)
411 {
412 if (player)
413 {
414 int lightingID = GetGame().ServerConfigGetInt("lightingConfig");
416 GetGame().RPCSingleParam(player, ERPCs.RPC_SEND_LIGHTING_SETUP, lightID, true, player.GetIdentity());
417 }
418 }
419
422 {
423 //creates temporary server-side structure for handling default character spawn
424 return GetGame().GetMenuDefaultCharacterData(false).DeserializeCharacterData(ctx);
425 }
426
427 //
429 {
431 playerEnt = GetGame().CreatePlayer(identity, characterName, pos, 0, "NONE");//Creates random player
433
434 GetGame().SelectPlayer(identity, m_player);
435
436 return m_player;
437 }
438
441 {
442 int slot_ID;
443 string attachment_type;
444 for (int i = 0; i < DefaultCharacterCreationMethods.GetAttachmentSlotsArray().Count(); i++)
445 {
446 slot_ID = DefaultCharacterCreationMethods.GetAttachmentSlotsArray().Get(i);
447 attachment_type = "";
448 if (m_RespawnMode != GameConstants.RESPAWN_MODE_CUSTOM || !char_data.GetAttachmentMap().Find(slot_ID, attachment_type) || !VerifyAttachmentType(slot_ID, attachment_type)) //todo insert verification fn here
449 {
450 //randomize
451 if (DefaultCharacterCreationMethods.GetConfigArrayCountFromSlotID(slot_ID) > 0)
452 attachment_type = DefaultCharacterCreationMethods.GetConfigAttachmentTypes(slot_ID).GetRandomElement();
453 else //undefined, moving on
454 continue;
455 }
456
457 if (attachment_type != "")
458 m_player.GetInventory().CreateAttachmentEx(attachment_type, slot_ID);
459 }
460
462 }
463
468
470 {
471 return DefaultCharacterCreationMethods.GetConfigAttachmentTypes(slot_ID).Find(attachment_type) > -1;
472 }
473
475 {
476 string characterType = GetGame().CreateRandomPlayer();
477 bool generateRandomEquip = false;
478
479 // get login data for new character
480 if (ProcessLoginData(ctx) && (m_RespawnMode == GameConstants.RESPAWN_MODE_CUSTOM) && !GetGame().GetMenuDefaultCharacterData(false).IsRandomCharacterForced())
481 {
482 if (GetGame().ListAvailableCharacters().Find(GetGame().GetMenuDefaultCharacterData().GetCharacterType()) > -1)
483 characterType = GetGame().GetMenuDefaultCharacterData().GetCharacterType();
484 }
485 else
486 generateRandomEquip = true;
487
489 {
491 if (presetData && presetData.IsValid())
492 {
493 string presetCharType = presetData.GetRandomCharacterType();
494 if (presetCharType == string.Empty)
497 {
499 return m_player;
500 }
501 else
502 ErrorEx("Failed to create character from type: " + presetCharType + ", using default spawning method");
503 }
504 else
505 ErrorEx("Failed to load PlayerSpawnPreset data properly, using default spawning method");
506 }
507
509 {
511 GetGame().GetMenuDefaultCharacterData().GenerateRandomEquip();
512 EquipCharacter(GetGame().GetMenuDefaultCharacterData());
513 }
514
515 return m_player;
516 }
517
519 {
520 GetGame().SelectPlayer(identity, player);
521
522#ifdef DIAG_DEVELOPER
523 if (FeatureTimeAccel.m_CurrentTimeAccel)
524 GetGame().RPCSingleParam(player, ERPCs.DIAG_TIMEACCEL_CLIENT_SYNC, FeatureTimeAccel.m_CurrentTimeAccel, true, identity);
525#endif
526 }
527
529 {
530 if (player)
531 {
532 if (player.IsUnconscious() || player.IsRestrained())
533 {
534 // kill character
535 player.SetHealth("", "", 0.0);
536 }
537 }
538
539#ifdef DIAG_DEVELOPER
540 if (FeatureTimeAccel.m_CurrentTimeAccel)
541 GetGame().RPCSingleParam(player, ERPCs.DIAG_TIMEACCEL_CLIENT_SYNC, FeatureTimeAccel.m_CurrentTimeAccel, true, identity);
542#endif
543 }
544
546 {
547 if (player)
548 player.OnReconnect();
549 }
550
552 {
553 bool disconnectNow = true;
554
555 // TODO: get out of vehicle
556 // using database and no saving if authorization failed
557 if (GetHive() && !authFailed)
558 {
559 if (player.IsAlive())
560 {
561 if (!m_LogoutPlayers.Contains(player) && !m_NewLogoutPlayers.Contains(player))
562 {
563 Print("[Logout]: New player " + identity.GetId() + " with logout time " + logoutTime.ToString());
564
565 // send statistics to client
566 player.StatSyncToClient();
567
568 // inform client about logout time
569 GetGame().SendLogoutTime(player, logoutTime);
570
571 // wait for some time before logout and save
572 LogoutInfo params = new LogoutInfo(GetGame().GetTime() + logoutTime * 1000, identity.GetId());
573
574 m_NewLogoutPlayers.Insert(player, params);
575 GetGame().GetCallQueue(CALL_CATEGORY_GAMEPLAY).CallLater(AddNewPlayerLogout, 0, false, player, params);
576
577 // allow reconnecting to old char only if not in cars, od ladders etc. as they cannot be properly synchronized for reconnect
578 //if (!player.GetCommand_Vehicle() && !player.GetCommand_Ladder())
579 //{
580 // GetGame().AddToReconnectCache(identity);
581 //}
582 // wait until logout timer runs out
583 disconnectNow = false;
584 }
585 return;
586 }
587 }
588
589 if (disconnectNow)
590 {
591 Print("[Logout]: New player " + identity.GetId() + " with instant logout");
592
593 // inform client about instant logout
594 GetGame().SendLogoutTime(player, 0);
595
597 }
598 }
599
601 {
602 // Note: At this point, identity can be already deleted
603 if (!player)
604 {
605 Print("[Logout]: Skipping player " + uid + ", already removed");
606 return;
607 }
608
609 // disable reconnecting to old char
610 //GetGame().RemoveFromReconnectCache(uid);
611
612 // now player can't cancel logout anymore, so call everything needed upon disconnect
614
615 Print("[Logout]: Player " + uid + " finished");
616
617 if (GetHive())
618 {
619 // save player
620 player.Save();
621
622 // unlock player in DB
623 GetHive().CharacterExit(player);
624 }
625
626 // handle player's existing char in the world
627 player.ReleaseNetworkControls();
629
630 // remove player from server
631 GetGame().DisconnectPlayer(identity, uid);
632 // Send list of players at all clients
633 GetGame().GetCallQueue(CALL_CATEGORY_SYSTEM).CallLater(SyncEvents.SendPlayerList, 1000);
634 }
635
637 {
638 if (player.IsUnconscious() || player.IsRestrained())
639 {
640 switch (player.GetKickOffReason())
641 {
642 case EClientKicked.SERVER_EXIT:
643 return false;
644 case EClientKicked.KICK_ALL_ADMIN:
645 return false;
646 case EClientKicked.KICK_ALL_SERVER:
647 return false;
648 case EClientKicked.SERVER_SHUTDOWN:
649 return false;
650 default:
651 return true;
652 }
653 }
654
655 return false;
656 }
657
659 {
660 if (player.IsAlive())
661 {
663 {
664 player.SetHealth("", "", 0.0);//kill
665 }
666 else
667 {
668 player.Delete();// remove the body
669 }
670 }
671 }
672
674 {
675 GetGame().GetWorld().GetPlayerList(m_Players);
676 int players_count = m_Players.Count();
677 int tick_count_max = Math.Min(players_count, SCHEDULER_PLAYERS_PER_TICK);
678
679 for (int i = 0; i < tick_count_max; i++)
680 {
681 if (m_currentPlayer >= players_count)
682 m_currentPlayer = 0;
683
684 PlayerBase currentPlayer = PlayerBase.Cast(m_Players.Get(m_currentPlayer));
685
686 if (currentPlayer)
687 currentPlayer.OnTick();
688 m_currentPlayer++;
689 }
690 }
691
692 //--------------------------------------------------
693 override bool InsertCorpse(Man player)
694 {
696 return m_DeadPlayersArray.Insert(corpse_data) >= 0;
697 }
698
700 {
701 if (m_DeadPlayersArray.Count() == 0)//nothing to process, abort
702 return;
703 int current_time = GetGame().GetTime();
706
707 for (int i = 0; i < m_DeadPlayersArray.Count(); i++)
708 {
709 corpse_data = m_DeadPlayersArray.Get(i);
710 if (!corpse_data || (corpse_data && (!corpse_data.m_Player || !corpse_data.m_bUpdate)))
711 invalid_corpses.Insert(i);
712 else if (corpse_data.m_bUpdate && current_time - corpse_data.m_iLastUpdateTime >= 30000)
713 {
714 corpse_data.UpdateCorpseState();
715 corpse_data.m_iLastUpdateTime = current_time;
716 }
717 }
718
719 //cleanup
720 if (invalid_corpses.Count() > 0)
721 {
722 for (i = invalid_corpses.Count() - 1; i > -1; i--)
723 m_DeadPlayersArray.Remove(invalid_corpses.Get(i));
724 }
725 }
726 //--------------------------------------------------
727
729 {
730 ScriptRPC rpc = new ScriptRPC();
731 rpc.Write(m_RespawnMode);
732 rpc.Send(null, ERPCs.RPC_SERVER_RESPAWN_MODE, true, identity);
733 }
734
739}
740
EClientKicked
ERPCs
Definition ERPCs.c:2
proto string ToString()
Empty
Definition Hand_States.c:14
proto native Hive GetHive()
float GetTime()
void PluginLifespan()
PluginBase GetPlugin(typename plugin_type)
DayZPlayer m_player
static bool GetDisableRespawnDialog()
static void SyncDataSendEx(notnull PlayerIdentity identity)
Super root of all classes in Enforce script.
Definition EnScript.c:11
Definition Debug.c:14
static void Log(string message=LOG_DEFAULT, string plugin=LOG_DEFAULT, string author=LOG_DEFAULT, string label=LOG_DEFAULT, string entity=LOG_DEFAULT)
Prints debug message with normal prio.
Definition Debug.c:133
Definition Camera.c:2
Definition EnMath.c:7
void RandomArtillery(float deltaTime)
void ~MissionServer()
ref array< vector > m_FiringPos
void EquipCharacter(MenuDefaultCharacterData char_data)
Spawns character equip from received data. Checks validity against config, randomizes if invalid valu...
override void OnUpdate(float timeslice)
override void OnInit()
PluginAdditionalInfo m_moduleDefaultCharacter
ref array< Man > m_Players
void AddNewPlayerLogout(PlayerBase player, notnull LogoutInfo info)
void SyncGlobalLighting(PlayerBase player)
override bool InsertCorpse(Man player)
void UpdateCorpseStatesServer()
override RainProcurementHandler GetRainProcurementHandler()
override void OnGameplayDataHandlerLoad()
void HandleBody(PlayerBase player)
void MissionServer()
override bool IsServer()
void TickScheduler(float timeslice)
override void OnEvent(EventType eventTypeId, Param params)
MissionBase m_mission
void UpdatePlayersStats()
bool ProcessLoginData(ParamsReadContext ctx)
returns whether received data is valid, ctx can be filled on client in StoreLoginData()
ref RainProcurementHandler m_RainProcHandler
void InvokeOnConnect(PlayerBase player, PlayerIdentity identity)
PlayerBase CreateCharacter(PlayerIdentity identity, vector pos, ParamsReadContext ctx, string characterName)
void PlayerDisconnected(PlayerBase player, PlayerIdentity identity, string uid)
bool ShouldPlayerBeKilled(PlayerBase player)
void InvokeOnDisconnect(PlayerBase player)
void ControlPersonalLight(PlayerBase player)
bool VerifyAttachmentType(int slot_ID, string attachment_type)
ref map< PlayerBase, ref LogoutInfo > m_NewLogoutPlayers
void StartingEquipSetup(PlayerBase player, bool clothesChosen)
can be overriden to manually set up starting equip. 'clothesChosen' is legacy parameter,...
PlayerBase m_player
void OnClientReadyEvent(PlayerIdentity identity, PlayerBase player)
void OnClientPrepareEvent(PlayerIdentity identity, out bool useDB, out vector pos, out float yaw, out int preloadTimeout)
override void SyncRespawnModeInfo(PlayerIdentity identity)
void OnClientDisconnectedEvent(PlayerIdentity identity, PlayerBase player, int logoutTime, bool authFailed)
ref map< PlayerBase, ref LogoutInfo > m_LogoutPlayers
void UpdateLogoutPlayers()
override void OnMissionStart()
void OnClientReconnectEvent(PlayerIdentity identity, PlayerBase player)
PlayerBase OnClientNewEvent(PlayerIdentity identity, vector pos, ParamsReadContext ctx)
void OnClientRespawnEvent(PlayerIdentity identity, PlayerBase player)
ref array< ref CorpseData > m_DeadPlayersArray
override bool IsPlayerDisconnecting(Man player)
Base Param Class with no parameters. Used as general purpose parameter overloaded with Param1 to Para...
Definition param.c:12
The class that will be instanced (moddable)
Definition gameplay.c:376
static bool ProcessEquipmentData(PlayerBase player, PlayerSpawnPreset data)
equips character with the chosen preset
static PlayerSpawnPreset GetRandomCharacterPreset()
Serialization general interface. Serializer API works with:
Definition Serializer.c:56
static void SendPlayerList()
Definition SyncEvents.c:45
static void SyncDataSend(PlayerIdentity identity)
static void SpawnAllTriggerCarriers()
const EventType LogoutCancelEventTypeID
params: LogoutCancelEventParams
Definition gameplay.c:514
const EventType ClientNewEventTypeID
params: ClientNewEventParams
Definition gameplay.c:494
const EventType ClientReconnectEventTypeID
params: ClientReconnectEventParams
Definition gameplay.c:500
const EventType ClientRespawnEventTypeID
params: ClientRespawnEventParams
Definition gameplay.c:498
const EventType ClientDisconnectedEventTypeID
params: ClientDisconnectedEventParams
Definition gameplay.c:504
proto native CGame GetGame()
const EventType ClientReadyEventTypeID
params: ClientReadyEventParams
Definition gameplay.c:502
const EventType ClientPrepareEventTypeID
params: ClientPrepareEventParams
Definition gameplay.c:492
void Error(string err)
Messagebox with error message.
Definition EnDebug.c:90
proto void Print(void var)
Prints content of variable to console/log.
enum ShapeType ErrorEx
const int RESPAWN_MODE_CUSTOM
Definition constants.c:901
static proto bool CastTo(out Class to, Class from)
Try to safely down-cast base class to child class.
static proto float Min(float x, float y)
Returns smaller of two given values.
static proto float Clamp(float value, float min, float max)
Clamps 'value' to 'min' if it is lower than 'min', or to 'max' if it is higher than 'max'.
static int RandomIntInclusive(int min, int max)
Returns a random int number between and min [inclusive] and max [inclusive].
Definition EnMath.c:54
const int CALL_CATEGORY_GAMEPLAY
Definition tools.c:10
const int CALL_CATEGORY_SYSTEM
Definition tools.c:8
Param2< int, string > LogoutInfo
int time of the logout end