· 6 years ago · Mar 08, 2019, 01:50 PM
1using Rust;
2using System.Collections.Generic;
3using System;
4using System.Text;
5using UnityEngine;
6using Oxide.Core;
7using Oxide.Core.Plugins;
8using Oxide.Core.Libraries;
9using Oxide.Core.Configuration;
10using System.Linq;
11using Oxide.Game.Rust.Cui;
12using System.Reflection;
13
14//Repair bug fix.
15//Non-firing hooks fix
16namespace Oxide.Plugins
17{
18 [Info("PlayerRanks", "Steenamaroo", "1.4.0", ResourceId = 2359)]
19 class PlayerRanks : RustPlugin
20 {
21 [PluginReference]
22 Plugin Clans, Friends, EventManager, PlaytimeTracker, Economics;
23
24 #region RustIO
25 private Library lib;
26 private MethodInfo isInstalled;
27 private MethodInfo hasFriend;
28
29 bool IsInstalled()
30 {
31 return (lib != null) && (bool)isInstalled.Invoke(lib, new object[] { });
32 }
33
34 bool HasFriend(string playerId, string friendId)
35 {
36 return (lib != null) && (bool)hasFriend.Invoke(lib, new object[] { playerId, friendId });
37 }
38 #endregion
39 Dictionary<uint, Dictionary<ulong, float>> BradleyAttackers = new Dictionary<uint, Dictionary<ulong, float>>();
40 Dictionary<uint, Dictionary<ulong, int>> HeliAttackers = new Dictionary<uint, Dictionary<ulong, int>>();
41 Dictionary<ulong, WoundedData> woundedData = new Dictionary<ulong, WoundedData>();
42 bool HasPermission(string id, string perm) => permission.UserHasPermission(id, perm);
43 private Dictionary<string, bool> allowedCats = new Dictionary<string, bool>();
44 List<ulong> airdrops = new List<ulong>();
45 const string permAllowed = "playerranks.allowed";
46 List<string> Broadcast = new List<string>();
47 List<ulong> MenuOpen = new List<ulong>();
48 bool catsOnOff;
49 Timer broadcastTimer;
50
51 public class DataStorage
52 {
53 public Dictionary<ulong, PRDATA> PlayerRankData = new Dictionary<ulong, PRDATA>();
54 public Dictionary<DateTime, Dictionary<string, LeaderBoardData>> leaderBoards = new Dictionary<DateTime, Dictionary<string, LeaderBoardData>>();
55 }
56
57 public class LeaderBoardData
58 {
59 public ulong UserID;
60 public string UserName;
61 public double Score;
62 }
63
64 public class PRDATA
65 {
66 public object GetValue(String category)
67 {
68 if (category == "PVPKills") return PVPKills;
69 if (category == "PVPDistance") return PVPDistance;
70 if (category == "PVEKills") return PVEKills;
71 if (category == "PVEDistance") return PVEDistance;
72 if (category == "NPCKills") return NPCKills;
73 if (category == "NPCDistance") return NPCDistance;
74 if (category == "SleepersKilled") return SleepersKilled;
75 if (category == "HeadShots") return HeadShots;
76 if (category == "Deaths") return Deaths;
77 if (category == "Suicides") return Suicides;
78 if (category == "KDR") return KDR;
79 if (category == "SDR") return SDR;
80 if (category == "SkullsCrushed") return SkullsCrushed;
81 if (category == "TimesWounded") return TimesWounded;
82 if (category == "TimesHealed") return TimesHealed;
83 if (category == "HeliHits") return HeliHits;
84 if (category == "HeliKills") return HeliKills;
85 if (category == "APCHits") return APCHits;
86 if (category == "APCKills") return APCKills;
87 if (category == "BarrelsDestroyed") return BarrelsDestroyed;
88 if (category == "ExplosivesThrown") return ExplosivesThrown;
89 if (category == "ArrowsFired") return ArrowsFired;
90 if (category == "BulletsFired") return BulletsFired;
91 if (category == "RocketsLaunched") return RocketsLaunched;
92 if (category == "WeaponTrapsDestroyed") return WeaponTrapsDestroyed;
93 if (category == "DropsLooted") return DropsLooted;
94 if (category == "StructuresBuilt") return StructuresBuilt;
95 if (category == "StructuresDemolished") return StructuresDemolished;
96 if (category == "ItemsDeployed") return ItemsDeployed;
97 if (category == "ItemsCrafted") return ItemsCrafted;
98 if (category == "EntitiesRepaired") return EntitiesRepaired;
99 if (category == "ResourcesGathered") return ResourcesGathered;
100 if (category == "StructuresUpgraded") return StructuresUpgraded;
101 return "Not Found";
102 }
103
104 public bool Admin;
105 public ulong UserID;
106 public string Name;
107 public string TimePlayed = "0";
108 public string Status = "offline";
109 public int Economics;
110 public DateTime ActiveDate = DateTime.UtcNow;
111 public int PVPKills;
112 public double PVPDistance;
113 public int PVEKills;
114 public double PVEDistance;
115 public int NPCKills;
116 public double NPCDistance;
117 public int SleepersKilled;
118 public int HeadShots;
119 public int Deaths;
120 public int Suicides;
121 public double KDR;
122 public double SDR;
123 public int SkullsCrushed;
124 public int TimesWounded;
125 public int TimesHealed;
126 public int HeliHits;
127 public int HeliKills;
128 public int APCHits;
129 public int APCKills;
130 public int BarrelsDestroyed;
131 public int ExplosivesThrown;
132 public int ArrowsFired;
133 public int BulletsFired;
134 public int RocketsLaunched;
135 public int WeaponTrapsDestroyed;
136 public int DropsLooted;
137
138 //intense options
139 public int StructuresBuilt;
140 public int StructuresDemolished;
141 public int ItemsDeployed;
142 public int ItemsCrafted;
143 public int EntitiesRepaired;
144 public int ResourcesGathered;
145 public int StructuresUpgraded;
146 }
147
148 class WoundedData
149 {
150 public float distance;
151 public ulong attackerId;
152 }
153
154 DataStorage data;
155 private DynamicConfigFile PRData;
156
157 void Loaded()
158 {
159 SetUp();
160 lang.RegisterMessages(messages, this);
161 permission.RegisterPermission(permAllowed, this);
162 cmd.AddChatCommand($"{conf.Options.chatCommandAlias}", this, "CmdTarget");
163 CheckDependencies();
164 Sql_conn = Sql.OpenDb(conf.MySQL.sql_host, conf.MySQL.sql_port, conf.MySQL.sql_db, conf.MySQL.sql_user, conf.MySQL.sql_pass + ";CharSet=utf8mb4", this);
165 }
166
167 void Unload()
168 {
169 Sql_conn.Con.Dispose();
170 foreach (BasePlayer current in BasePlayer.activePlayerList)
171 if (MenuOpen.Contains(current.userID))
172 {
173 CuiHelper.DestroyUi(current, "ranksgui");
174 MenuOpen.Remove(current.userID);
175 }
176 SaveData(false);
177 }
178
179 void OnPlayerDisconnected(BasePlayer player)
180 {
181 data.PlayerRankData[player.userID].Status = "offline";
182 if (MenuOpen.Contains(player.userID))
183 {
184 CuiHelper.DestroyUi(player, "ranksgui");
185 MenuOpen.Remove(player.userID);
186 }
187 }
188
189 void SetUp()
190 {
191 PRData = Interface.Oxide.DataFileSystem.GetFile("PlayerRanks");
192 LoadData();
193 LoadConfigVariables();
194 foreach (var entry in data.PlayerRankData)
195 entry.Value.Status = "offline";
196 foreach (BasePlayer player in BasePlayer.activePlayerList)
197 OnPlayerInit(player);
198
199 timer.Every(conf.Options.saveTimer * 60, () =>
200 {
201 SaveData(true);
202 Puts("Player Ranks Local Database Was Saved.");
203 }
204 );
205 UpdateCategories();
206 SetUpBroadcast();
207 }
208
209 void SetUpBroadcast()
210 {
211 if (conf.Options.useTimedTopList)
212 {
213 if (broadcastTimer != null)
214 broadcastTimer.Destroy();
215 Broadcast.Clear();
216 foreach (var cat in allowedCats)
217 {
218 if (allowedCats[cat.Key] == true)
219 Broadcast.Add(cat.Key);
220 }
221 if (Broadcast.Count != 0)
222 BroadcastLooper(0);
223 }
224 }
225
226 void BroadcastLooper(int counter)
227 {
228 var time = 10f;
229 if (BroadcastMethod(Broadcast[counter]))
230 time = conf.Options.TimedTopListTimer * 60;
231
232 counter++;
233 if (counter == Broadcast.Count)
234 counter = 0;
235 broadcastTimer = timer.Once(time, () => BroadcastLooper(counter));
236 }
237
238 void UpdateCategories()
239 {
240 allowedCats.Clear();
241 allowedCats.Add("PVPKills", conf.Categories.usepvpkills);
242 allowedCats.Add("PVPDistance", conf.Categories.usepvpdistance);
243 allowedCats.Add("PVEKills", conf.Categories.usepvekills);
244 allowedCats.Add("PVEDistance", conf.Categories.usepvedistance);
245 allowedCats.Add("NPCKills", conf.Categories.usenpckills);
246 allowedCats.Add("NPCDistance", conf.Categories.usenpcdistance);
247 allowedCats.Add("SleepersKilled", conf.Categories.usesleeperskilled);
248 allowedCats.Add("HeadShots", conf.Categories.useheadshots);
249 allowedCats.Add("Deaths", conf.Categories.usedeaths);
250 allowedCats.Add("Suicides", conf.Categories.usesuicides);
251 allowedCats.Add("KDR", conf.Categories.usekdr);
252 allowedCats.Add("SDR", conf.Categories.usesdr);
253 allowedCats.Add("SkullsCrushed", conf.Categories.useskullscrushed);
254 allowedCats.Add("TimesWounded", conf.Categories.usetimeswounded);
255 allowedCats.Add("TimesHealed", conf.Categories.usetimeshealed);
256 allowedCats.Add("HeliHits", conf.Categories.usehelihits);
257 allowedCats.Add("HeliKills", conf.Categories.usehelikills);
258 allowedCats.Add("APCHits", conf.Categories.useapchits);
259 allowedCats.Add("APCKills", conf.Categories.useapckills);
260 allowedCats.Add("BarrelsDestroyed", conf.Categories.usebarrelsdestroyed);
261 allowedCats.Add("ExplosivesThrown", conf.Categories.useexplosivesthrown);
262 allowedCats.Add("ArrowsFired", conf.Categories.usearrowsfired);
263 allowedCats.Add("BulletsFired", conf.Categories.usebulletsfired);
264 allowedCats.Add("RocketsLaunched", conf.Categories.userocketslaunched);
265 allowedCats.Add("WeaponTrapsDestroyed", conf.Categories.useweapontrapsdestroyed);
266 allowedCats.Add("DropsLooted", conf.Categories.usedropslooted);
267
268 if (conf.Options.useIntenseOptions)
269 {
270 allowedCats.Add("StructuresBuilt", conf.Categories.usestructuresbuilt);
271 allowedCats.Add("StructuresDemolished", conf.Categories.usestructuresdemolished);
272 allowedCats.Add("ItemsDeployed", conf.Categories.useitemsdeployed);
273 allowedCats.Add("ItemsCrafted", conf.Categories.useitemscrafted);
274 allowedCats.Add("EntitiesRepaired", conf.Categories.useentitiesrepaired);
275 allowedCats.Add("ResourcesGathered", conf.Categories.useresourcesgathered);
276 allowedCats.Add("StructuresUpgraded", conf.Categories.usestructuresupgraded);
277 }
278 }
279
280 void CheckDependencies()
281 {
282 //warn if enabled and missing
283 if (Friends == null)
284 if (conf.Options.useFriendsAPI && conf.Options.useFriendsAPI)
285 PrintWarning("{0}: {1}", Title, "FriendsAPI is not installed and will not be used.");
286 if (Clans == null && conf.Options.useClans)
287 PrintWarning("{0}: {1}", Title, "Clans is not installed and will not be used.");
288 lib = Interface.GetMod().GetLibrary<Library>("RustIO");
289 if (lib == null || (isInstalled = lib.GetFunction("IsInstalled")) == null || (hasFriend = lib.GetFunction("HasFriend")) == null)
290 {
291 lib = null;
292 if (conf.Options.useRustIO)
293 PrintWarning("{0}: {1}", Title, "Rust:IO is not installed and will not be used.");
294 }
295 //just warn if missing
296 if (PlaytimeTracker == null)
297 PrintWarning("{0}: {1}", Title, "PlayTime Tracker is not installed and will not be used.");
298 if (Economics == null)
299 PrintWarning("{0}: {1}", Title, "Economics is not installed and will not be used.");
300 }
301
302 void OnPlayerInit(BasePlayer player)
303 {
304 if (ServerUsers.Is(player.userID, ServerUsers.UserGroup.Banned))
305 if (data.PlayerRankData.ContainsKey(player.userID))
306 {
307 data.PlayerRankData.Remove(player.userID);
308 SaveData(true);
309 return;
310 }
311
312 if (MenuOpen.Contains(player.userID))
313 {
314 MenuOpen.Remove(player.userID);
315 CuiHelper.DestroyUi(player, "ranksgui");
316 }
317
318 if (!data.PlayerRankData.ContainsKey(player.userID))
319 {
320 data.PlayerRankData.Add(player.userID, new PRDATA()
321 {
322 Admin = IsAuth(player),
323 UserID = player.userID,
324 Name = player.displayName,
325 TimePlayed = "0",
326 Status = "online",
327 ActiveDate = DateTime.UtcNow,
328 Economics = 0,
329 PVPKills = 0,
330 PVPDistance = 0.0,
331 PVEKills = 0,
332 PVEDistance = 0.0,
333 NPCKills = 0,
334 NPCDistance = 0.0,
335 SleepersKilled = 0,
336 HeadShots = 0,
337 Deaths = 0,
338 Suicides = 0,
339 KDR = 0,
340 SDR = 0,
341 SkullsCrushed = 0,
342 TimesHealed = 0,
343 TimesWounded = 0,
344 HeliHits = 0,
345 HeliKills = 0,
346 APCHits = 0,
347 APCKills = 0,
348 BarrelsDestroyed = 0,
349 ExplosivesThrown = 0,
350 ArrowsFired = 0,
351 BulletsFired = 0,
352 RocketsLaunched = 0,
353 WeaponTrapsDestroyed = 0,
354 DropsLooted = 0,
355
356 //intense options
357 StructuresBuilt = 0,
358 StructuresDemolished = 0,
359 ItemsDeployed = 0,
360 ItemsCrafted = 0,
361 EntitiesRepaired = 0,
362 ResourcesGathered = 0,
363 StructuresUpgraded = 0,
364 });
365 }
366 else
367 UpdatePlayer(player);
368 }
369
370 void UpdatePlayer(BasePlayer player)
371 {
372 var path = data.PlayerRankData[player.userID];
373 var time = PlaytimeTracker?.Call("GetPlayTime", player.UserIDString);
374 var playTime = (time != null) ? GetPlaytimeClock((double)time) : null;
375
376 path.Admin = IsAuth(player);
377 path.Name = player.displayName;
378 path.Status = "online";
379 path.ActiveDate = DateTime.UtcNow;
380 if (Economics)
381 path.Economics = Convert.ToInt32(Economics?.Call("Balance", player.userID));
382 path.TimePlayed = (!string.IsNullOrEmpty(playTime)) ? playTime : string.Empty;
383 }
384
385 void OnPlayerBanned(string name, ulong id, string address, string reason)=>data.PlayerRankData.Remove(id);
386
387 private string GetPlaytimeClock(double time)
388 {
389 TimeSpan dateDifference = TimeSpan.FromSeconds((float)time);
390 var days = dateDifference.Days;
391 var hours = dateDifference.Hours;
392 hours += (days * 24);
393 var mins = dateDifference.Minutes;
394 var secs = dateDifference.Seconds;
395 return string.Format("{0:00}:{1:00}:{2:00}", hours, mins, secs);
396 }
397
398 void OnEntityTakeDamage(BaseEntity entity, HitInfo hitinfo)
399 {
400 if (hitinfo.Initiator == null || !(hitinfo.Initiator is BasePlayer)) return;
401 var player = hitinfo.Initiator as BasePlayer;
402 DamageType type = hitinfo.damageTypes.GetMajorityDamageType();
403 float amount = hitinfo.damageTypes.Total();
404
405 if (conf.Options.blockEvents)
406 if (CheckEvents(player))return;
407
408 if (entity is BaseHelicopter)
409 {
410 if (!HeliAttackers.ContainsKey(entity.net.ID))
411 HeliAttackers.Add(entity.net.ID, new Dictionary<ulong, int>());
412 if (!HeliAttackers[entity.net.ID].ContainsKey(player.userID))
413 HeliAttackers[entity.net.ID].Add(player.userID, 1);
414 else
415 {
416 HeliAttackers[entity.net.ID][player.userID]++;
417 ProcessHeliHits(player);
418 }
419 }
420 if (entity is BradleyAPC)
421 {
422 if (type.ToString() == "Bullet")
423 {
424 ProcessAPCHits(player);//plain bullets count as hits, but not towards majority damage
425 return;
426 }
427 if (!BradleyAttackers.ContainsKey(entity.net.ID)) //explosive ammo does get this far, because two damage types are processed.
428 BradleyAttackers.Add(entity.net.ID, new Dictionary<ulong, float>());
429 if (!BradleyAttackers[entity.net.ID].ContainsKey(player.userID))
430 BradleyAttackers[entity.net.ID].Add(player.userID, amount);
431 else
432 {
433 BradleyAttackers[entity.net.ID][player.userID] = BradleyAttackers[entity.net.ID][player.userID] + amount;
434 ProcessAPCHits(player);
435 }
436 }
437 if (entity is BasePlayer)
438 if (hitinfo.isHeadshot && !FriendCheck(player, entity as BasePlayer))
439 ProcessHeadShot(player);
440 }
441
442 ulong GetMajorityAttacker(uint id)
443 {
444 ulong majorityPlayer = 0U;
445 if (HeliAttackers.ContainsKey(id))
446 {
447 Dictionary<ulong, int> majority = HeliAttackers[id].OrderByDescending(pair => pair.Value).Take(1).ToDictionary(pair => pair.Key, pair => pair.Value);
448 foreach (var name in majority)
449 {
450 majorityPlayer = name.Key;
451 }
452 }
453 if (BradleyAttackers.ContainsKey(id))
454 {
455 Dictionary<ulong, float> majority = BradleyAttackers[id].OrderByDescending(pair => pair.Value).Take(1).ToDictionary(pair => pair.Key, pair => pair.Value);
456 foreach (var name in majority)
457 {
458 majorityPlayer = name.Key;
459 }
460 }
461 return majorityPlayer;
462 }
463
464 void OnEntityDeath(BaseEntity entity, HitInfo hitinfo)
465 {
466 if (entity.name.Contains("corpse"))
467 return;
468
469 var victim = entity as BasePlayer;
470
471 if (hitinfo?.Initiator == null && entity is BasePlayer)
472 {
473 if (woundedData.ContainsKey(victim.userID))
474 {
475 BasePlayer attacker = BasePlayer.FindByID(woundedData[victim.userID].attackerId);
476 if (conf.Options.blockEvents)
477 if (CheckEvents(attacker))return;
478 var distance = woundedData[victim.userID].distance;
479 if (!victim.userID.IsSteamId() || victim is NPCPlayer || victim is HTNPlayer)
480 {
481 if (attacker != null)
482 {
483 if (data.PlayerRankData.ContainsKey(attacker.userID))
484 data.PlayerRankData[attacker.userID].NPCKills++;
485 if (distance > data.PlayerRankData[attacker.userID].NPCDistance)
486 data.PlayerRankData[attacker.userID].NPCDistance = Math.Round(distance, 2); //process method not called, because distance is from record
487 }
488 return;
489 }
490
491 if (victim.userID.IsSteamId())
492 {
493 ProcessDeath(victim);
494 if (attacker != null)
495 {
496 if (data.PlayerRankData.ContainsKey(attacker.userID))
497 data.PlayerRankData[attacker.userID].PVPKills++;
498 if (distance > data.PlayerRankData[attacker.userID].PVPDistance)
499 data.PlayerRankData[attacker.userID].PVPDistance = Math.Round(distance, 2);
500 }
501 return;
502 }
503 woundedData.Remove(victim.userID);
504 }
505 String [] stringArray = {"Cold", "Drowned", "Heat", "Suicide", "Generic", "Posion", "Radiation", "Thirst", "Hunger", "Fall"};
506 if (stringArray.Any(victim.lastDamage.ToString().Contains))
507 ProcessSuicide(victim);
508 ProcessDeath(victim);
509 return;
510 }
511
512 if (entity is BaseHelicopter)
513 {
514 BasePlayer player = null;
515 player = BasePlayer.FindByID(GetMajorityAttacker(entity.net.ID));
516 if (player != null)
517 {
518 ProcessHeliKills(player);
519 HeliAttackers.Remove(entity.net.ID);
520 }
521 return;
522 }
523
524 if (entity is BradleyAPC)
525 {
526 BasePlayer player;
527 var BradleyID = entity.net.ID;
528 player = BasePlayer.FindByID(GetMajorityAttacker(BradleyID));
529 if (player != null)
530 {
531 ProcessAPCKills(player);
532 BradleyAttackers.Remove(BradleyID);
533 }
534 return;
535 }
536
537 if (hitinfo?.Initiator is BasePlayer)
538 {
539 var player = hitinfo.Initiator as BasePlayer;
540 if (player.userID.IsSteamId() && !(player is NPCPlayer) && !(player is HTNPlayer))
541 {
542 if (entity.name.Contains("agents/"))
543 ProcessPVEKill(player, entity);
544 else if (entity.name.Contains("barrel"))
545 ProcessBarrelsDestroyed(player);
546 else if (!(entity is BasePlayer) && entity.name.Contains("turret"))
547 ProcessWeaponTrapsDestroyed(player);
548 else if (entity.name.Contains("guntrap"))
549 ProcessWeaponTrapsDestroyed(player);
550 else if (victim is BasePlayer && !victim.userID.IsSteamId())
551 ProcessNPCKills(player, victim);
552 else if (victim is BasePlayer && (victim is NPCPlayer || victim is HTNPlayer))
553 ProcessNPCKills(player, victim);
554 else if (victim is BasePlayer && victim.userID.IsSteamId())
555 {
556 ProcessDeath(victim);
557 if (hitinfo.Initiator != entity)
558 ProcessPVPKill(player, victim);
559 if (victim.IsSleeping())
560 ProcessSleepersKilled(player, victim);
561 if (hitinfo.Initiator == entity)
562 ProcessSuicide(player);
563 }
564 return;
565 }
566 }
567 if (victim == null) return;
568
569 if (victim is BasePlayer && !(victim is NPCPlayer) && !(victim is HTNPlayer))
570 ProcessDeath(victim);
571
572 if (woundedData.ContainsKey(victim.userID))
573 woundedData.Remove(victim.userID);
574 return;
575 }
576
577 void OnExplosiveThrown(BasePlayer player, BaseEntity entity, Item item)
578 {
579 if (!(player.GetActiveItem().info.displayName.english == "Supply Signal"))
580 ProcessExplosivesThrown(player);
581 }
582
583 void OnWeaponFired(BaseProjectile projectile, BasePlayer player, ItemModProjectile mod)
584 {
585 if (mod.ToString().Contains("arrow"))
586 ProcessArrowsFired(player);
587
588 if (mod.ToString().Contains("ammo"))
589 ProcessBulletsFired(player);
590 }
591
592 void OnRocketLaunched(BasePlayer player)=>ProcessRocketsLaunched(player);
593
594 void OnEntityBuilt(Planner plan, GameObject objectBlock)
595 {
596 if (conf.Options.useIntenseOptions)
597 {
598 BasePlayer player = plan.GetOwnerPlayer();
599 if (player.GetActiveItem().info.displayName.english == "Building Plan")
600 ProcessStructuresBuilt(player);
601 else
602 ProcessItemsDeployed(player);
603 }
604 }
605
606 void OnStructureDemolish(BaseCombatEntity entity, BasePlayer player)=>ProcessStructuresDemolished(player);
607
608 void OnItemCraft(ItemCraftTask item)
609 {
610 if (conf.Options.useIntenseOptions)
611 {
612 BasePlayer crafter = item.owner;
613 if (crafter != null)
614 ProcessItemsCrafted(crafter);
615 }
616 }
617
618 void OnStructureRepair(BaseCombatEntity entity, BasePlayer player)
619 {
620 float before = 0,after = 0;
621 if (conf.Options.useIntenseOptions)
622 {
623 if (entity.health != null)
624 {
625 before = entity.health;
626 timer.Once(0.1f,()=>
627 {
628 after = entity.health;
629 if (!Mathf.Approximately(before,after))
630 ProcessEntitiesRepaired(player);
631 });
632 }
633 }
634 }
635
636 void OnHealingItemUse(HeldEntity item, BasePlayer target)=>ProcessTimesHealed(target);
637
638 void OnItemUse(Item item)
639 {
640 BasePlayer player = item?.GetOwnerPlayer();
641 if (item.GetOwnerPlayer() == null) return;
642
643 if (player != null && item.info.displayName.english == "Large Medkit")
644 ProcessTimesHealed(player);
645
646 if (item.info.shortname != "skull.human") return;//credit redBDGR
647 string skullName = null;
648 if (item.name != null)
649 skullName = item.name.Substring(10, item.name.Length - 11);
650 else return;
651
652 if (!player.displayName.Contains($"{skullName}")) //.contains is for [God] - UserID would be better here
653 ProcessSkullsCrushed(player);
654 }
655
656 void CanBeWounded(BasePlayer player, HitInfo hitInfo)
657 {
658 if (player == null || hitInfo == null) return;
659 if (!(player.userID.IsSteamId()) || player is NPCPlayer || player is HTNPlayer) return;
660 var attacker = hitInfo.InitiatorPlayer;
661 if (attacker != null)
662 {
663 if (attacker == player || IsFriend(attacker.userID, player.userID) || IsClanmate(attacker.userID, player.userID)) return;
664 woundedData[player.userID] = new WoundedData {distance = Vector3.Distance(player.transform.position, attacker.transform.position), attackerId = attacker.userID };
665 {
666 NextTick(() =>
667 {
668 if (player.IsWounded())
669 ProcessTimesWounded(player);
670 });
671 }
672 }
673 }
674
675 void OnPlayerRecover(BasePlayer player)
676 {
677 if (woundedData.ContainsKey(player.userID))
678 woundedData.Remove(player.userID);
679 }
680
681 void OnStructureUpgrade(BaseCombatEntity entity, BasePlayer player, BuildingGrade.Enum grade)=>ProcessStructuresUpgraded(player);
682
683 void OnCollectiblePickup(Item item, BasePlayer player)
684 {
685 if (conf.Options.useIntenseOptions)
686 ProcessResourcesGathered(player, item.amount);
687 }
688
689 void OnDispenserGather(ResourceDispenser dispenser, BaseEntity entity, Item item)
690 {
691 if (conf.Options.useIntenseOptions)
692 {
693 BasePlayer player = entity?.ToPlayer();
694 ProcessResourcesGathered(player, item.amount);
695 }
696 }
697
698 void OnEntitySpawned(BaseEntity entity)
699 {
700 if (entity.name.Contains("supply_drop"))
701 airdrops.Add(entity.net.ID);
702 }
703
704 void OnLootEntity(BasePlayer player, BaseEntity entity)
705 {
706 if (airdrops.Contains(entity.net.ID))
707 {
708 airdrops.Remove(entity.net.ID);
709 ProcessDropsLooted(player);
710 }
711 }
712
713 #region processes
714 bool ProcessChecks(BasePlayer player)
715 {
716 if(!conf.Options.statCollection) return false;
717 if (conf.Options.blockEvents)
718 if (CheckEvents(player))return false;
719
720 return data.PlayerRankData.ContainsKey(player.userID);
721 }
722
723 bool FriendCheck(BasePlayer player, BasePlayer victim)
724 {
725 if (victim != null)
726 {
727 if (conf.Options.useClans && IsClanmate(player.userID, victim.userID))
728 return true;
729 if (conf.Options.useFriendsAPI && IsFriend(player.userID, victim.userID))
730 return true;
731 if (conf.Options.useRustIO && HasFriend(player.userID.ToString(), victim.userID.ToString()))
732 return true;
733 }
734 return false;
735 }
736 void ProcessPVPKill(BasePlayer player, BasePlayer victim)
737 {
738 if (FriendCheck(player, victim))
739 return;
740
741 if (ProcessChecks(player))
742 {
743 data.PlayerRankData[player.userID].PVPKills++;
744 if (victim.Distance(player.transform.position) > data.PlayerRankData[player.userID].PVPDistance)
745 data.PlayerRankData[player.userID].PVPDistance = Math.Round(victim.Distance(player.transform.position), 2);
746
747 if ((data.PlayerRankData[player.userID].Deaths) > 0)
748 {
749 var KDR = Convert.ToDouble(data.PlayerRankData[player.userID].PVPKills) / (data.PlayerRankData[player.userID].Deaths);
750 data.PlayerRankData[player.userID].KDR = Math.Round(KDR, 2);
751 }
752 else
753 data.PlayerRankData[player.userID].KDR = (data.PlayerRankData[player.userID].PVPKills);
754 }
755 }
756
757 void ProcessPVEKill(BasePlayer player, BaseEntity victim)
758 {
759 if (ProcessChecks(player))
760 {
761 data.PlayerRankData[player.userID].PVEKills++;
762 if (victim.Distance(player.transform.position) > data.PlayerRankData[player.userID].PVEDistance)
763 data.PlayerRankData[player.userID].PVEDistance = Math.Round(victim.Distance(player.transform.position), 2);
764 }
765 }
766
767 void ProcessNPCKills(BasePlayer player, BaseEntity victim)
768 {
769 if (ProcessChecks(player))
770 {
771 data.PlayerRankData[player.userID].NPCKills++;
772 if (victim.Distance(player.transform.position) > data.PlayerRankData[player.userID].NPCDistance)
773 data.PlayerRankData[player.userID].NPCDistance = Math.Round(victim.Distance(player.transform.position), 2);
774 }
775 }
776
777 void ProcessSleepersKilled(BasePlayer player, BaseEntity victim)
778 {
779 if (ProcessChecks(player))
780 {
781 data.PlayerRankData[player.userID].SleepersKilled++;
782 if (victim.Distance(player.transform.position) > data.PlayerRankData[player.userID].PVPDistance)
783 data.PlayerRankData[player.userID].PVPDistance = Math.Round(victim.Distance(player.transform.position), 2);
784 }
785 }
786
787 void ProcessHeadShot(BasePlayer player)
788 {
789 if (ProcessChecks(player))
790 data.PlayerRankData[player.userID].HeadShots++;
791 }
792
793 void ProcessDeath(BasePlayer player)
794 {
795 if (ProcessChecks(player))
796 {
797 data.PlayerRankData[player.userID].Deaths++;
798
799 var SDR = Convert.ToDouble(data.PlayerRankData[player.userID].Suicides) / (data.PlayerRankData[player.userID].Deaths);
800 data.PlayerRankData[player.userID].SDR = Math.Round(SDR, 2);
801
802 var KDR = Convert.ToDouble(data.PlayerRankData[player.userID].PVPKills) / (data.PlayerRankData[player.userID].Deaths);
803 data.PlayerRankData[player.userID].KDR = Math.Round(KDR, 2);
804 }
805 }
806
807 void ProcessSuicide(BasePlayer player)
808 {
809 if (ProcessChecks(player))
810 {
811 data.PlayerRankData[player.userID].Suicides++;
812
813 if ((data.PlayerRankData[player.userID].Deaths) > 0)
814 {
815 var SDR = Convert.ToDouble(data.PlayerRankData[player.userID].Suicides) / (data.PlayerRankData[player.userID].Deaths);
816 data.PlayerRankData[player.userID].SDR = Math.Round(SDR, 2);
817
818 var KDR = Convert.ToDouble(data.PlayerRankData[player.userID].PVPKills) / (data.PlayerRankData[player.userID].Deaths);
819 data.PlayerRankData[player.userID].KDR = Math.Round(KDR, 2);
820 }
821 else
822 {
823 data.PlayerRankData[player.userID].SDR = (data.PlayerRankData[player.userID].Suicides);
824 data.PlayerRankData[player.userID].KDR = (data.PlayerRankData[player.userID].PVPKills);
825 }
826 }
827 }
828
829 void ProcessSkullsCrushed(BasePlayer player)
830 {
831 if (ProcessChecks(player))
832 data.PlayerRankData[player.userID].SkullsCrushed++;
833 }
834
835 void ProcessTimesWounded(BasePlayer player)
836 {
837 if (ProcessChecks(player))
838 data.PlayerRankData[player.userID].TimesWounded++;
839 }
840
841 void ProcessTimesHealed(BasePlayer player)
842 {
843 if (ProcessChecks(player))
844 data.PlayerRankData[player.userID].TimesHealed++;
845 }
846
847 void ProcessHeliHits(BasePlayer player)
848 {
849 if (ProcessChecks(player))
850 data.PlayerRankData[player.userID].HeliHits++;
851 }
852
853 void ProcessHeliKills(BasePlayer player)
854 {
855 if (ProcessChecks(player))
856 data.PlayerRankData[player.userID].HeliKills++;
857 }
858
859 void ProcessAPCHits(BasePlayer player)
860 {
861 if (ProcessChecks(player))
862 data.PlayerRankData[player.userID].APCHits++;
863 }
864
865 void ProcessAPCKills(BasePlayer player)
866 {
867 if (ProcessChecks(player))
868 data.PlayerRankData[player.userID].APCKills++;
869 }
870
871 void ProcessBarrelsDestroyed(BasePlayer player)
872 {
873 if (ProcessChecks(player))
874 data.PlayerRankData[player.userID].BarrelsDestroyed++;
875 }
876
877 void ProcessExplosivesThrown(BasePlayer player)
878 {
879 if (ProcessChecks(player))
880 data.PlayerRankData[player.userID].ExplosivesThrown++;
881 }
882
883 void ProcessArrowsFired(BasePlayer player)
884 {
885 if (ProcessChecks(player))
886 data.PlayerRankData[player.userID].ArrowsFired++;
887 }
888
889 void ProcessBulletsFired(BasePlayer player)
890 {
891 if (ProcessChecks(player))
892 data.PlayerRankData[player.userID].BulletsFired++;
893 }
894
895 void ProcessRocketsLaunched(BasePlayer player)
896 {
897 if (ProcessChecks(player))
898 data.PlayerRankData[player.userID].RocketsLaunched++;
899 }
900
901 void ProcessWeaponTrapsDestroyed(BasePlayer player)
902 {
903 if (ProcessChecks(player))
904 data.PlayerRankData[player.userID].WeaponTrapsDestroyed++;
905 }
906
907 void ProcessDropsLooted(BasePlayer player)
908 {
909 if (ProcessChecks(player))
910 data.PlayerRankData[player.userID].DropsLooted++;
911 }
912
913 void ProcessStructuresBuilt(BasePlayer player)
914 {
915 if (ProcessChecks(player))
916 data.PlayerRankData[player.userID].StructuresBuilt++;
917 }
918
919 void ProcessStructuresDemolished(BasePlayer player)
920 {
921 if (ProcessChecks(player))
922 data.PlayerRankData[player.userID].StructuresDemolished++;
923 }
924
925 void ProcessItemsDeployed(BasePlayer player)
926 {
927 if (ProcessChecks(player))
928 data.PlayerRankData[player.userID].ItemsDeployed++;
929 }
930
931 void ProcessItemsCrafted(BasePlayer player)
932 {
933 if (ProcessChecks(player))
934 data.PlayerRankData[player.userID].ItemsCrafted++;
935 }
936
937 void ProcessEntitiesRepaired(BasePlayer player)
938 {
939 if (ProcessChecks(player))
940 data.PlayerRankData[player.userID].EntitiesRepaired++;
941 }
942
943 void ProcessResourcesGathered(BasePlayer player, int amount = 0)
944 {
945 if (ProcessChecks(player))
946 data.PlayerRankData[player.userID].ResourcesGathered+=amount;
947 }
948
949 void ProcessStructuresUpgraded(BasePlayer player)
950 {
951 if (ProcessChecks(player))
952 data.PlayerRankData[player.userID].StructuresUpgraded++;
953 }
954
955 void BroadcastToAll(string msg, string keyword) => PrintToChat(conf.GUI.fontColor1 + keyword + " </color>" + conf.GUI.fontColor2 + msg + "</color>");
956
957 bool IsClanmate(ulong playerId, ulong friendId)
958 {
959 if (!Clans || !conf.Options.useClans) return false;
960 object playerTag = Clans?.Call("GetClanOf", playerId);
961 object friendTag = Clans?.Call("GetClanOf", friendId);
962 if (playerTag is string && friendTag is string)
963 if (playerTag == friendTag) return true;
964 return false;
965 }
966
967 bool IsFriend(ulong playerID, ulong friendID)
968 {
969 if (!Friends || !conf.Options.useFriendsAPI) return false;
970 bool isFriend = (bool)Friends?.Call("IsFriend", playerID, friendID);
971 return isFriend;
972 }
973
974 bool CheckEvents(BasePlayer player)
975 {
976 object isPlaying = EventManager?.Call("isPlaying", new object[] { player });
977 if (isPlaying is bool)
978 if ((bool)isPlaying)
979 return true;
980 return false;
981 }
982 #endregion
983 void PersonalAndCategoryUI(BasePlayer player, string personalStatsCat, string personalStatsVal, string pageTitle)
984 {
985 string guiString = String.Format("0.1 0.1 0.1 {0}", conf.GUI.guitransparency);
986 var elements = new CuiElementContainer();
987 var buttonColour = conf.GUI.buttonColour;
988 var mainName = elements.Add(new CuiPanel { Image = { Color = guiString }, RectTransform = { AnchorMin = "0.1 0.12", AnchorMax = "0.9 0.98" }, CursorEnabled = true, FadeOut = 0.1f }, "Overlay", "ranksgui");
989 elements.Add(new CuiElement { Parent = "ranksgui", Components = { new CuiRectTransformComponent { AnchorMin = "0 0", AnchorMax = "1 1" } } });
990
991 elements.Add(new CuiButton { Button = { Command = $"CallPersonalStatsUI true", Color = buttonColour }, RectTransform = { AnchorMin = "0.03 0.95", AnchorMax = "0.22 0.98" }, Text = { Text = lang.GetMessage("mystats", this, player.UserIDString), FontSize = 16, Align = TextAnchor.MiddleCenter } }, mainName);
992 elements.Add(new CuiButton { Button = { Command = $"CallLeaderBoardUI true", Color = buttonColour }, RectTransform = { AnchorMin = "0.27 0.95", AnchorMax = "0.47 0.98" }, Text = { Text = lang.GetMessage("leaderboard", this, player.UserIDString), FontSize = 16, Align = TextAnchor.MiddleCenter } }, mainName);
993 elements.Add(new CuiButton { Button = { Command = $"CallCategoriesUI", Color = buttonColour }, RectTransform = { AnchorMin = "0.53 0.95", AnchorMax = "0.72 0.98" }, Text = { Text = lang.GetMessage("categories", this, player.UserIDString), FontSize = 16, Align = TextAnchor.MiddleCenter } }, mainName);
994 if (HasPermission(player.UserIDString, permAllowed))
995 elements.Add(new CuiButton { Button = { Command = $"CallAdminUI", Color = buttonColour }, RectTransform = { AnchorMin = "0.77 0.95", AnchorMax = "0.97 0.98" }, Text = { Text = lang.GetMessage("admin", this, player.UserIDString), FontSize = 16, Align = TextAnchor.MiddleCenter } }, mainName);
996
997 elements.Add(new CuiLabel { Text = { Text = pageTitle, FontSize = 20, Align = TextAnchor.MiddleCenter }, RectTransform = { AnchorMin = "0 0.88", AnchorMax = "1 0.92" } }, mainName);
998
999 elements.Add(new CuiLabel { Text = { Text = personalStatsCat, FontSize = 12, Align = TextAnchor.MiddleRight }, RectTransform = { AnchorMin = "0.1 0.10", AnchorMax = "0.48 0.88" } }, mainName);
1000 elements.Add(new CuiLabel { Text = { Text = personalStatsVal, FontSize = 12, Align = TextAnchor.MiddleLeft }, RectTransform = { AnchorMin = "0.52 0.10", AnchorMax = "0.9 0.88" } }, mainName);
1001
1002 elements.Add(new CuiButton { Button = { Command = "Close", Color = buttonColour }, RectTransform = { AnchorMin = "0.4 0.02", AnchorMax = "0.6 0.082" }, Text = { Text = lang.GetMessage("close", this, player.UserIDString), FontSize = 20, Align = TextAnchor.MiddleCenter } }, mainName);
1003
1004 CuiHelper.AddUi(player, elements);
1005 }
1006
1007 void CategoriesUI(BasePlayer player, string pageTitle)
1008 {
1009 string guiString = String.Format("0.1 0.1 0.1 {0}", conf.GUI.guitransparency);
1010 var elements = new CuiElementContainer();
1011 var buttonColour = conf.GUI.buttonColour;
1012 var mainName = elements.Add(new CuiPanel { Image = { Color = guiString }, RectTransform = { AnchorMin = "0.1 0.12", AnchorMax = "0.9 0.98" }, CursorEnabled = true, FadeOut = 0.1f }, "Overlay", "ranksgui");
1013 elements.Add(new CuiElement { Parent = "ranksgui", Components = { new CuiRectTransformComponent { AnchorMin = "0 0", AnchorMax = "1 1" } } });
1014
1015 elements.Add(new CuiButton { Button = { Command = $"CallPersonalStatsUI true", Color = buttonColour }, RectTransform = { AnchorMin = "0.03 0.95", AnchorMax = "0.22 0.98" }, Text = { Text = lang.GetMessage("mystats", this, player.UserIDString), FontSize = 16, Align = TextAnchor.MiddleCenter } }, mainName);
1016 elements.Add(new CuiButton { Button = { Command = $"CallLeaderBoardUI true", Color = buttonColour }, RectTransform = { AnchorMin = "0.27 0.95", AnchorMax = "0.47 0.98" }, Text = { Text = lang.GetMessage("leaderboard", this, player.UserIDString), FontSize = 16, Align = TextAnchor.MiddleCenter } }, mainName);
1017 elements.Add(new CuiButton { Button = { Command = null, Color = buttonColour }, RectTransform = { AnchorMin = "0.53 0.95", AnchorMax = "0.72 0.98" }, Text = { Text = lang.GetMessage("categories", this, player.UserIDString), FontSize = 16, Align = TextAnchor.MiddleCenter } }, mainName);
1018
1019 if (HasPermission(player.UserIDString, permAllowed))
1020 elements.Add(new CuiButton { Button = { Command = $"CallAdminUI false", Color = buttonColour }, RectTransform = { AnchorMin = "0.77 0.95", AnchorMax = "0.97 0.98" }, Text = { Text = lang.GetMessage("admin", this, player.UserIDString), FontSize = 16, Align = TextAnchor.MiddleCenter } }, mainName);
1021
1022 var buttonTop = 0.853;
1023 var buttonBottom = 0.873;
1024 foreach (var cat in allowedCats)
1025 {
1026 if (cat.Value == true)
1027 {
1028 elements.Add(new CuiButton { Button = { Command = $"GetCategory {cat.Key}", Color = "0.7 0.32 0.17 0.0" }, RectTransform = { AnchorMin = $"0.3 {buttonTop}", AnchorMax = $"0.7 {buttonBottom}" }, Text = { Text = lang.GetMessage(cat.Key, this), FontSize = 12, Align = TextAnchor.MiddleCenter } }, mainName);
1029
1030 buttonTop = buttonTop - 0.021;
1031 buttonBottom = buttonBottom - 0.021;
1032 }
1033 }
1034 elements.Add(new CuiLabel { Text = { Text = pageTitle, FontSize = 20, Align = TextAnchor.MiddleCenter }, RectTransform = { AnchorMin = "0 0.88", AnchorMax = "1 0.92" } }, mainName);
1035
1036 elements.Add(new CuiButton { Button = { Command = "Close", Color = buttonColour }, RectTransform = { AnchorMin = "0.4 0.02", AnchorMax = "0.6 0.082" }, Text = { Text = lang.GetMessage("close", this, player.UserIDString), FontSize = 20, Align = TextAnchor.MiddleCenter } }, mainName);
1037
1038 CuiHelper.AddUi(player, elements);
1039 }
1040
1041 void LeaderBoardUI(BasePlayer player, string leaderBoardCat, string leaderBoardName, string leaderBoardScore, string pageTitle)
1042 {
1043 string guiString = String.Format("0.1 0.1 0.1 {0}", conf.GUI.guitransparency);
1044 var elements = new CuiElementContainer();
1045 var buttonColour = conf.GUI.buttonColour;
1046 var mainName = elements.Add(new CuiPanel { Image = { Color = guiString }, RectTransform = { AnchorMin = "0.1 0.12", AnchorMax = "0.9 0.98" }, CursorEnabled = true, FadeOut = 0.1f }, "Overlay", "ranksgui");
1047 elements.Add(new CuiElement { Parent = "ranksgui", Components = { new CuiRectTransformComponent { AnchorMin = "0 0", AnchorMax = "1 1" } } });
1048
1049 elements.Add(new CuiButton { Button = { Command = $"CallPersonalStatsUI true", Color = buttonColour }, RectTransform = { AnchorMin = "0.03 0.95", AnchorMax = "0.22 0.98" }, Text = { Text = lang.GetMessage("mystats", this, player.UserIDString), FontSize = 16, Align = TextAnchor.MiddleCenter } }, mainName);
1050 elements.Add(new CuiButton { Button = { Command = null, Color = buttonColour }, RectTransform = { AnchorMin = "0.27 0.95", AnchorMax = "0.47 0.98" }, Text = { Text = lang.GetMessage("leaderboard", this, player.UserIDString), FontSize = 16, Align = TextAnchor.MiddleCenter } }, mainName);
1051 elements.Add(new CuiButton { Button = { Command = $"CallCategoriesUI", Color = buttonColour }, RectTransform = { AnchorMin = "0.53 0.95", AnchorMax = "0.72 0.98" }, Text = { Text = lang.GetMessage("categories", this, player.UserIDString), FontSize = 16, Align = TextAnchor.MiddleCenter } }, mainName);
1052
1053 if (HasPermission(player.UserIDString, permAllowed))
1054 elements.Add(new CuiButton { Button = { Command = $"CallAdminUI false", Color = buttonColour }, RectTransform = { AnchorMin = "0.77 0.95", AnchorMax = "0.97 0.98" }, Text = { Text = lang.GetMessage("admin", this, player.UserIDString), FontSize = 16, Align = TextAnchor.MiddleCenter } }, mainName);
1055
1056 elements.Add(new CuiLabel { Text = { Text = pageTitle, FontSize = 20, Align = TextAnchor.MiddleCenter }, RectTransform = { AnchorMin = "0 0.88", AnchorMax = "1 0.92" } }, mainName);
1057
1058 elements.Add(new CuiLabel { Text = { Text = leaderBoardCat, FontSize = 12, Align = TextAnchor.MiddleRight }, RectTransform = { AnchorMin = "0 0.10", AnchorMax = "0.38 0.88" } }, mainName);
1059 elements.Add(new CuiLabel { Text = { Text = leaderBoardScore, FontSize = 12, Align = TextAnchor.MiddleCenter }, RectTransform = { AnchorMin = "0.4 0.10", AnchorMax = "0.6 0.88" } }, mainName);
1060 elements.Add(new CuiLabel { Text = { Text = leaderBoardName, FontSize = 12, Align = TextAnchor.MiddleLeft }, RectTransform = { AnchorMin = "0.62 0.10", AnchorMax = "1 0.88" } }, mainName);
1061
1062 elements.Add(new CuiButton { Button = { Command = "Close", Color = buttonColour }, RectTransform = { AnchorMin = "0.4 0.02", AnchorMax = "0.6 0.082" }, Text = { Text = lang.GetMessage("close", this, player.UserIDString), FontSize = 20, Align = TextAnchor.MiddleCenter } }, mainName);
1063
1064 CuiHelper.AddUi(player, elements);
1065 }
1066
1067 void AdminUI(BasePlayer player, bool wipe)
1068 {
1069 string guiString = String.Format("0.1 0.1 0.1 {0}", conf.GUI.guitransparency);
1070 var elements = new CuiElementContainer();
1071 var buttonColour = conf.GUI.buttonColour;
1072 var mainName = elements.Add(new CuiPanel { Image = { Color = guiString }, RectTransform = { AnchorMin = "0.1 0.12", AnchorMax = "0.9 0.98" }, CursorEnabled = true, FadeOut = 0.1f }, "Overlay", "ranksgui");
1073 elements.Add(new CuiElement { Parent = "ranksgui", Components = { new CuiRectTransformComponent { AnchorMin = "0 0", AnchorMax = "1 1" } } });
1074
1075 elements.Add(new CuiButton { Button = { Command = $"CallPersonalStatsUI true", Color = buttonColour }, RectTransform = { AnchorMin = "0.03 0.95", AnchorMax = "0.22 0.98" }, Text = { Text = lang.GetMessage("mystats", this, player.UserIDString), FontSize = 16, Align = TextAnchor.MiddleCenter } }, mainName);
1076 elements.Add(new CuiButton { Button = { Command = $"CallLeaderBoardUI true", Color = buttonColour }, RectTransform = { AnchorMin = "0.27 0.95", AnchorMax = "0.47 0.98" }, Text = { Text = lang.GetMessage("leaderboard", this, player.UserIDString), FontSize = 16, Align = TextAnchor.MiddleCenter } }, mainName);
1077 elements.Add(new CuiButton { Button = { Command = $"CallCategoriesUI", Color = buttonColour }, RectTransform = { AnchorMin = "0.53 0.95", AnchorMax = "0.72 0.98" }, Text = { Text = lang.GetMessage("categories", this, player.UserIDString), FontSize = 16, Align = TextAnchor.MiddleCenter } }, mainName);
1078 if (HasPermission(player.UserIDString, permAllowed))
1079 elements.Add(new CuiButton { Button = { Command = null, Color = buttonColour }, RectTransform = { AnchorMin = "0.77 0.95", AnchorMax = "0.97 0.98" }, Text = { Text = lang.GetMessage("admin", this, player.UserIDString), FontSize = 16, Align = TextAnchor.MiddleCenter } }, mainName);
1080
1081 var buttonTop = 0.853;
1082 var buttonBottom = 0.873;
1083
1084 foreach (var cat in allowedCats)
1085 {
1086 elements.Add(new CuiLabel { Text = { Text = cat.Key, FontSize = 11, Align = TextAnchor.MiddleCenter }, RectTransform = { AnchorMin = $"0 {buttonTop}", AnchorMax = $"0.2 {buttonBottom}" } }, mainName);
1087 if (cat.Value == true)
1088 elements.Add(new CuiButton { Button = { Command = $"ToggleCategory {cat.Key}", Color = buttonColour }, RectTransform = { AnchorMin = $"0.22 {buttonTop}", AnchorMax = $"0.32 {buttonBottom}" }, Text = { Text = lang.GetMessage("on", this, player.UserIDString), FontSize = 10, Align = TextAnchor.MiddleCenter } }, mainName);
1089 else
1090 elements.Add(new CuiButton { Button = { Command = $"ToggleCategory {cat.Key}", Color = "0.7 0.32 0.17 0.5" }, RectTransform = { AnchorMin = $"0.22 {buttonTop}", AnchorMax = $"0.32 {buttonBottom}" }, Text = { Text = lang.GetMessage("off", this, player.UserIDString), FontSize = 10, Align = TextAnchor.MiddleCenter } }, mainName);
1091
1092 buttonTop = buttonTop - 0.021;
1093 buttonBottom = buttonBottom - 0.021;
1094 }
1095 buttonTop = buttonTop - 0.031;
1096 buttonBottom = buttonBottom - 0.031;
1097
1098 buttonTop = buttonTop - 0.031;
1099 buttonBottom = buttonBottom - 0.031;
1100 elements.Add(new CuiLabel { Text = { Text = "Intense Options", FontSize = 11, Align = TextAnchor.MiddleCenter }, RectTransform = { AnchorMin = $"0 {buttonTop}", AnchorMax = $"0.2 {buttonBottom}" } }, mainName);
1101 if (conf.Options.useIntenseOptions == true)
1102 elements.Add(new CuiButton { Button = { Command = "ToggleIntenseOptions", Color = buttonColour }, RectTransform = { AnchorMin = $"0.22 {buttonTop}", AnchorMax = $"0.32 {buttonBottom}" }, Text = { Text = lang.GetMessage("on", this, player.UserIDString), FontSize = 10, Align = TextAnchor.MiddleCenter } }, mainName);
1103 else
1104 elements.Add(new CuiButton { Button = { Command = "ToggleIntenseOptions", Color = buttonColour }, RectTransform = { AnchorMin = $"0.22 {buttonTop}", AnchorMax = $"0.32 {buttonBottom}" }, Text = { Text = lang.GetMessage("off", this, player.UserIDString), FontSize = 10, Align = TextAnchor.MiddleCenter } }, mainName);
1105
1106
1107 if (conf.Options.statCollection)
1108 elements.Add(new CuiButton { Button = { Command = "toggleStatCollection", Color = buttonColour }, RectTransform = { AnchorMin = "0.7 0.8", AnchorMax = "0.9 0.83" }, Text = { Text = lang.GetMessage("gatherStatsOnButton", this, player.UserIDString), FontSize = 16, Align = TextAnchor.MiddleCenter } }, mainName);
1109 else
1110 elements.Add(new CuiButton { Button = { Command = "toggleStatCollection", Color = buttonColour }, RectTransform = { AnchorMin = "0.7 0.8", AnchorMax = "0.9 0.83" }, Text = { Text = lang.GetMessage("gatherStatsOffButton", this, player.UserIDString), FontSize = 16, Align = TextAnchor.MiddleCenter } }, mainName);
1111
1112 if (conf.Options.allowadmin)
1113 elements.Add(new CuiButton { Button = { Command = "AllowAdmin", Color = buttonColour }, RectTransform = { AnchorMin = "0.7 0.75", AnchorMax = "0.9 0.78" }, Text = { Text = lang.GetMessage("disableAdminStatsButton", this, player.UserIDString), FontSize = 16, Align = TextAnchor.MiddleCenter } }, mainName);
1114 else
1115 elements.Add(new CuiButton { Button = { Command = "AllowAdmin", Color = buttonColour }, RectTransform = { AnchorMin = "0.7 0.75", AnchorMax = "0.9 0.78" }, Text = { Text = lang.GetMessage("AllowAdminStatsButton", this, player.UserIDString), FontSize = 16, Align = TextAnchor.MiddleCenter } }, mainName);
1116
1117 elements.Add(new CuiButton { Button = { Command = "playerranks.save", Color = buttonColour }, RectTransform = { AnchorMin = "0.7 0.7", AnchorMax = "0.9 0.73" }, Text = { Text = lang.GetMessage("savePlayerDataButton", this, player.UserIDString), FontSize = 16, Align = TextAnchor.MiddleCenter } }, mainName);
1118
1119 if (wipe == false)
1120 elements.Add(new CuiButton { Button = { Command = "wipeFirst", Color = buttonColour }, RectTransform = { AnchorMin = "0.7 0.65", AnchorMax = "0.9 0.68" }, Text = { Text = lang.GetMessage("wipePlayerDataButton", this, player.UserIDString), FontSize = 16, Align = TextAnchor.MiddleCenter } }, mainName);
1121 else
1122 elements.Add(new CuiButton { Button = { Command = "playerranks.wipe", Color = buttonColour }, RectTransform = { AnchorMin = "0.7 0.65", AnchorMax = "0.9 0.68" }, Text = { Text = lang.GetMessage("confirm", this, player.UserIDString), FontSize = 16, Align = TextAnchor.MiddleCenter } }, mainName);
1123
1124 elements.Add(new CuiButton { Button = { Command = "saveLeaderboard", Color = buttonColour }, RectTransform = { AnchorMin = "0.7 0.6", AnchorMax = "0.9 0.63" }, Text = { Text = lang.GetMessage("saveLeaderBoardButton", this, player.UserIDString), FontSize = 16, Align = TextAnchor.MiddleCenter } }, mainName);
1125
1126 elements.Add(new CuiButton { Button = { Command = "wipeLeaderBoards", Color = buttonColour }, RectTransform = { AnchorMin = "0.7 0.55", AnchorMax = "0.9 0.58" }, Text = { Text = "Wipe LeaderBoards", FontSize = 16, Align = TextAnchor.MiddleCenter } }, mainName);
1127
1128 elements.Add(new CuiButton { Button = { Command = "Close", Color = buttonColour }, RectTransform = { AnchorMin = "0.4 0.02", AnchorMax = "0.6 0.082" }, Text = { Text = lang.GetMessage("close", this, player.UserIDString), FontSize = 20, Align = TextAnchor.MiddleCenter } }, mainName);
1129
1130 CuiHelper.AddUi(player, elements);
1131 }
1132 #region UI methods
1133
1134 [ConsoleCommand("CallPersonalStatsUI")]
1135 void PSUI(ConsoleSystem.Arg arg)
1136 {
1137 var player = arg.Connection.player as BasePlayer;
1138 CallPersonalStatsUI(player, arg.Args[0]);
1139 }
1140 void CallPersonalStatsUI(BasePlayer player, string button)
1141 {
1142 if (player == null) return;
1143 var d = data.PlayerRankData[player.userID];
1144 var dictToUse = data.PlayerRankData;
1145
1146 string pageTitle = conf.GUI.fontColor1 + lang.GetMessage("title", this, player.UserIDString) + "</color>" + conf.GUI.fontColor2 + d.Name + "</color> \n";
1147 string playerTopStatsCat = "";
1148 string playerTopStatsVal = "";
1149
1150 foreach (var cat in allowedCats)
1151 {
1152 if (allowedCats[cat.Key] == true)
1153 {
1154 playerTopStatsCat += conf.GUI.fontColor3 + lang.GetMessage($"{cat.Key}", this)+ "</color> \n";
1155 if (cat.Key.Contains("Distance"))
1156 playerTopStatsVal += conf.GUI.fontColor1 + d.GetValue(cat.Key) + "m</color> \n";//append M to distances
1157 else
1158 playerTopStatsVal += conf.GUI.fontColor1 + d.GetValue(cat.Key) + "</color> \n";
1159 }
1160 }
1161
1162 if (MenuOpen.Contains(player.userID))
1163 {
1164 CuiHelper.DestroyUi(player, "ranksgui");
1165 MenuOpen.Remove(player.userID);
1166 if (button != "true") return;
1167 }
1168 PersonalAndCategoryUI(player, playerTopStatsCat, playerTopStatsVal, pageTitle);
1169 MenuOpen.Add(player.userID);
1170 return;
1171 }
1172
1173 [ConsoleCommand("CallCategoriesUI")]
1174 void CatUI(ConsoleSystem.Arg arg)
1175 {
1176 var player = arg.Connection.player as BasePlayer;
1177 CallCategoriesUI(player);
1178
1179 }
1180 void CallCategoriesUI(BasePlayer player)
1181 {
1182 string pageTitle = conf.GUI.fontColor1 + lang.GetMessage("title", this, player.UserIDString) + "</color>" + conf.GUI.fontColor2 + lang.GetMessage("categories", this, player.UserIDString) + "</color> \n";
1183
1184 if (MenuOpen.Contains(player.userID))
1185 {
1186 CuiHelper.DestroyUi(player, "ranksgui");
1187 MenuOpen.Remove(player.userID);
1188 }
1189 CategoriesUI(player, pageTitle);
1190 MenuOpen.Add(player.userID);
1191 }
1192
1193 [ConsoleCommand("GetCategory")]
1194 void GetCategory(ConsoleSystem.Arg arg)
1195 {
1196 var player = arg.Connection.player as BasePlayer;
1197 string pageTitle = conf.GUI.fontColor1 + lang.GetMessage("title", this, player.UserIDString) + "</color>" + conf.GUI.fontColor2 + lang.GetMessage($"{arg.Args[0]}", this, player.UserIDString) + "</color> \n";
1198 string catTopName = "";
1199 string catTopVal = "";
1200
1201 foreach (var cat in allowedCats)
1202 {
1203 if (allowedCats[cat.Key] == true)
1204 if (cat.Key.ToLower() == arg.Args[0].ToLower())
1205 {
1206 var d = data.PlayerRankData[player.userID];
1207 var dictToUse = data.PlayerRankData;
1208 if (conf.Options.allowadmin == false)
1209 {
1210 dictToUse = data.PlayerRankData.Where(pair => pair.Value.Admin == false).ToDictionary(val => val.Key, val => val.Value);
1211 }
1212 Dictionary<ulong, PRDATA> top = dictToUse.OrderByDescending(pair => pair.Value.GetValue(cat.Key)).Take(30).ToDictionary(pair => pair.Key, pair => pair.Value);
1213
1214 var addPlayerManually = true;
1215 foreach (var name in top)
1216 {
1217 catTopName += conf.GUI.fontColor3 + name.Value.Name + "</color> \n";
1218 if (cat.Key.Contains("Distance"))
1219 catTopVal += conf.GUI.fontColor1 + name.Value.GetValue(cat.Key) + "m</color> \n";//append M to distances
1220 else
1221 catTopVal += conf.GUI.fontColor1 + name.Value.GetValue(cat.Key) + "</color> \n";
1222
1223 if (player.userID == name.Key) addPlayerManually = false;
1224 }
1225 if (addPlayerManually && dictToUse.ContainsKey(player.userID)) //admin double check
1226 {
1227 catTopName += "\n" + conf.GUI.fontColor3 + d.Name + "</color>";
1228 if (cat.Key.Contains("Distance"))
1229 catTopVal += "\n" + conf.GUI.fontColor1 + d.GetValue(cat.Key) + "m</color>";//append M to distances
1230 else
1231 catTopVal += "\n" + conf.GUI.fontColor1 + d.GetValue(cat.Key) + "</color>";
1232 }
1233 break;
1234 }
1235 }
1236 if (MenuOpen.Contains(player.userID))
1237 {
1238 CuiHelper.DestroyUi(player, "ranksgui");
1239 MenuOpen.Remove(player.userID);
1240 }
1241 PersonalAndCategoryUI(player, catTopName, catTopVal, pageTitle);
1242 MenuOpen.Add(player.userID);
1243 return;
1244 }
1245
1246 [ConsoleCommand("CallLeaderBoardUI")]
1247 void LBUI(ConsoleSystem.Arg arg)
1248 {
1249 var player = arg.Connection.player as BasePlayer;
1250 CallLeaderBoardUI(player, arg.Args[0]);
1251 }
1252
1253 void CallLeaderBoardUI(BasePlayer player, string button)
1254 {
1255 if (player == null) return;
1256 var d = data.PlayerRankData[player.userID];
1257 var dictToUse = data.PlayerRankData;
1258
1259 string pageTitle = conf.GUI.fontColor1 + lang.GetMessage("title", this) + "</color>" + conf.GUI.fontColor2 + lang.GetMessage("leaderboard", this) +"</color> \n";
1260 string leaderBoardCat = "";
1261 string leaderBoardName = "";
1262 string leaderBoardScore = "";
1263
1264 foreach (var cat in allowedCats)
1265 {
1266 if (allowedCats[cat.Key] == true)
1267 {
1268 if (conf.Options.allowadmin == false)
1269 dictToUse = data.PlayerRankData.Where(pair => pair.Value.Admin == false).ToDictionary(val => val.Key, val => val.Value);
1270
1271 Dictionary<string, object> top = dictToUse.OrderByDescending(pair => pair.Value.GetValue(cat.Key)).Take(1).ToDictionary(pair => pair.Value.Name, pair => pair.Value.GetValue(cat.Key));
1272
1273 foreach (var item in top)
1274 {
1275 leaderBoardCat += conf.GUI.fontColor3 + lang.GetMessage($"{cat.Key}", this) + "</color>\n";
1276 if (cat.Key.Contains("Distance"))
1277 leaderBoardScore += conf.GUI.fontColor1 + item.Value + "m</color>\n";//append M to distances
1278 else
1279 leaderBoardScore += conf.GUI.fontColor1 + item.Value + "</color>\n";
1280 var nameString = item.Key;
1281 if (nameString.Length > 32)
1282 nameString = string.Format(item.Key.Substring(0,30) + "...");
1283 leaderBoardName += conf.GUI.fontColor3 + $"{nameString}" + "</color>\n";
1284 break;
1285 }
1286 }
1287 }
1288
1289 if (MenuOpen.Contains(player.userID))
1290 {
1291 CuiHelper.DestroyUi(player, "ranksgui");
1292 MenuOpen.Remove(player.userID);
1293 if (button != "true") return;
1294 }
1295
1296 LeaderBoardUI(player, leaderBoardCat, leaderBoardName, leaderBoardScore, pageTitle);
1297 MenuOpen.Add(player.userID);
1298 return;
1299 }
1300
1301 [ConsoleCommand("CallAdminUI")]
1302 void ADUI(ConsoleSystem.Arg arg)
1303 {
1304 var player = arg.Connection.player as BasePlayer;
1305 CallAdminUI(player, false);
1306 }
1307 void CallAdminUI(BasePlayer player, bool wipe)
1308 {
1309 if (player == null) return;
1310
1311 string pageTitle = conf.GUI.fontColor1 + lang.GetMessage("title", this) + "</color>" + conf.GUI.fontColor2 + lang.GetMessage("leaderBoard", this) +"</color> \n";
1312
1313
1314 if (MenuOpen.Contains(player.userID))
1315 {
1316 CuiHelper.DestroyUi(player, "ranksgui");
1317 MenuOpen.Remove(player.userID);
1318 }
1319
1320 AdminUI(player, wipe);
1321 MenuOpen.Add(player.userID);
1322 return;
1323 }
1324 #endregion
1325
1326 #region console commands
1327
1328 [ConsoleCommand("ToggleCategory")]
1329 void ToggleCat(ConsoleSystem.Arg arg)
1330 {
1331 var player = arg.Connection.player as BasePlayer;
1332 if (arg.Args[0] == "PVPKills") conf.Categories.usepvpkills = !conf.Categories.usepvpkills;
1333 if (arg.Args[0] == "PVPDistance") conf.Categories.usepvpdistance = !conf.Categories.usepvpdistance;
1334 if (arg.Args[0] == "PVEKills") conf.Categories.usepvekills = !conf.Categories.usepvekills;
1335 if (arg.Args[0] == "PVEDistance") conf.Categories.usepvedistance = !conf.Categories.usepvedistance;
1336 if (arg.Args[0] == "NPCKills") conf.Categories.usenpckills = !conf.Categories.usenpckills;
1337 if (arg.Args[0] == "NPCDistance") conf.Categories.usenpcdistance = !conf.Categories.usenpcdistance;
1338 if (arg.Args[0] == "SleepersKilled") conf.Categories.usesleeperskilled = !conf.Categories.usesleeperskilled;
1339 if (arg.Args[0] == "HeadShots") conf.Categories.useheadshots = !conf.Categories.useheadshots;
1340 if (arg.Args[0] == "Deaths") conf.Categories.usedeaths = !conf.Categories.usedeaths;
1341 if (arg.Args[0] == "Suicides") conf.Categories.usesuicides = !conf.Categories.usesuicides;
1342 if (arg.Args[0] == "KDR") conf.Categories.usekdr = !conf.Categories.usekdr;
1343 if (arg.Args[0] == "SDR") conf.Categories.usesdr = !conf.Categories.usesdr;
1344 if (arg.Args[0] == "SkullsCrushed") conf.Categories.useskullscrushed = !conf.Categories.useskullscrushed;
1345 if (arg.Args[0] == "TimesWounded") conf.Categories.usetimeswounded = !conf.Categories.usetimeswounded;
1346 if (arg.Args[0] == "TimesHealed") conf.Categories.usetimeshealed = !conf.Categories.usetimeshealed;
1347 if (arg.Args[0] == "HeliHits") conf.Categories.usehelihits = !conf.Categories.usehelihits;
1348 if (arg.Args[0] == "HeliKills") conf.Categories.usehelikills = !conf.Categories.usehelikills;
1349 if (arg.Args[0] == "APCHits") conf.Categories.useapchits = !conf.Categories.useapchits;
1350 if (arg.Args[0] == "APCKills") conf.Categories.useapckills = !conf.Categories.useapckills;
1351 if (arg.Args[0] == "BarrelsDestroyed") conf.Categories.usebarrelsdestroyed = !conf.Categories.usebarrelsdestroyed;
1352 if (arg.Args[0] == "ExplosivesThrown") conf.Categories.useexplosivesthrown = !conf.Categories.useexplosivesthrown;
1353 if (arg.Args[0] == "ArrowsFired") conf.Categories.usearrowsfired = !conf.Categories.usearrowsfired;
1354 if (arg.Args[0] == "BulletsFired") conf.Categories.usebulletsfired = !conf.Categories.usebulletsfired;
1355 if (arg.Args[0] == "RocketsLaunched") conf.Categories.userocketslaunched = !conf.Categories.userocketslaunched;
1356 if (arg.Args[0] == "WeaponTrapsDestroyed") conf.Categories.useweapontrapsdestroyed = !conf.Categories.useweapontrapsdestroyed;
1357 if (arg.Args[0] == "DropsLooted") conf.Categories.usedropslooted = !conf.Categories.usedropslooted;
1358
1359 if (conf.Options.useIntenseOptions)
1360 {
1361 if (arg.Args[0] == "StructuresBuilt") conf.Categories.usestructuresbuilt = !conf.Categories.usestructuresbuilt;
1362 if (arg.Args[0] == "StructuresDemolished") conf.Categories.usestructuresdemolished = !conf.Categories.usestructuresdemolished;
1363 if (arg.Args[0] == "ItemsDeployed") conf.Categories.useitemsdeployed = !conf.Categories.useitemsdeployed;
1364 if (arg.Args[0] == "ItemsCrafted") conf.Categories.useitemscrafted = !conf.Categories.useitemscrafted;
1365 if (arg.Args[0] == "EntitiesRepaired") conf.Categories.useentitiesrepaired = !conf.Categories.useentitiesrepaired;
1366 if (arg.Args[0] == "ResourcesGathered") conf.Categories.useresourcesgathered = !conf.Categories.useresourcesgathered;
1367 if (arg.Args[0] == "StructuresUpgraded") conf.Categories.usestructuresupgraded = !conf.Categories.usestructuresupgraded;
1368 }
1369 SaveConfig(conf);
1370 UpdateCategories();
1371 SetUpBroadcast();
1372 CallAdminUI(player, false);
1373 }
1374
1375 [ConsoleCommand("ToggleIntenseOptions")]
1376 void ToggleIntense(ConsoleSystem.Arg arg)
1377 {
1378 var player = arg.Connection.player as BasePlayer;
1379 if (!HasPermission(player.UserIDString, permAllowed))
1380 return;
1381 conf.Options.useIntenseOptions = !conf.Options.useIntenseOptions;
1382
1383 SaveConfig(conf);
1384 UpdateCategories();
1385 CallAdminUI(player, false);
1386 }
1387
1388 [ConsoleCommand("toggleStatCollection")]
1389 void ToggleCollection(ConsoleSystem.Arg arg)
1390 {
1391 var player = arg.Connection.player as BasePlayer;
1392 if (HasPermission(player.UserIDString, permAllowed))
1393 conf.Options.statCollection = !conf.Options.statCollection;
1394
1395 SaveConfig(conf);
1396 UpdateCategories();
1397 CallAdminUI(player, false);
1398 }
1399
1400 [ConsoleCommand("AllowAdmin")]
1401 void AllowAdmin(ConsoleSystem.Arg arg)
1402 {
1403 var player = arg.Connection.player as BasePlayer;
1404 if (!HasPermission(player.UserIDString, permAllowed))
1405 return;
1406 conf.Options.allowadmin = !conf.Options.allowadmin;
1407
1408 SaveConfig(conf);
1409 UpdateCategories();
1410 CallAdminUI(player, false);
1411 }
1412
1413 [ConsoleCommand("wipeFirst")]
1414 void WipeAttempt(ConsoleSystem.Arg arg)
1415 {
1416 var player = arg.Connection.player as BasePlayer;
1417 if (!HasPermission(player.UserIDString, permAllowed)) return;
1418 CallAdminUI(player, true);
1419 }
1420
1421 [ConsoleCommand("saveLeaderboard")]
1422 void SaveBoard(ConsoleSystem.Arg arg)
1423 {
1424 var player = arg.Connection.player as BasePlayer;
1425 if (!HasPermission(player.UserIDString, permAllowed)) return;
1426 var dictToUse = data.PlayerRankData;
1427 var date = DateTime.UtcNow;
1428 data.leaderBoards.Add(date, new Dictionary<string, LeaderBoardData>());
1429 var lBoard = data.leaderBoards[date];
1430 //create leaderboard
1431 foreach (var cat in allowedCats)
1432 {
1433 if (allowedCats[cat.Key] == true)
1434 {
1435 if (conf.Options.allowadmin == false)
1436 dictToUse = data.PlayerRankData.Where(pair => pair.Value.Admin == false).ToDictionary(val => val.Key, val => val.Value);
1437
1438 Dictionary<ulong, PRDATA> top = dictToUse.OrderByDescending(pair => pair.Value.GetValue(cat.Key)).Take(1).ToDictionary(pair => pair.Key, pair => pair.Value);
1439 foreach (var leader in top)
1440 {
1441 data.leaderBoards[date].Add(cat.Key, new LeaderBoardData
1442 {
1443 UserID = leader.Key,
1444 UserName = leader.Value.Name,
1445 Score = Convert.ToDouble(data.PlayerRankData[leader.Key].GetValue(cat.Key))
1446 });
1447 }
1448 }
1449 }
1450 SaveConfig(conf);
1451 SaveData(true);
1452 CallAdminUI(player, false);
1453 }
1454
1455 [ConsoleCommand("wipeLeaderBoards")]
1456 void WipeBoards(ConsoleSystem.Arg arg)
1457 {
1458 var player = arg.Connection.player as BasePlayer;
1459 if (!HasPermission(player.UserIDString, permAllowed))
1460 return;
1461 var dictToUse = data.PlayerRankData;
1462
1463 data.leaderBoards.Clear();
1464 SaveData(true);
1465 CallAdminUI(player, false);
1466 }
1467
1468 [ConsoleCommand("Close")]
1469 void Close(ConsoleSystem.Arg arg)
1470 {
1471 var player = arg.Connection.player as BasePlayer;
1472 if (MenuOpen.Contains(player.userID))
1473 {
1474 CuiHelper.DestroyUi(player, "ranksgui");
1475 MenuOpen.Remove(player.userID);
1476 }
1477 return;
1478 }
1479
1480 [ConsoleCommand("playerranks.save")]
1481 void CmdSave()
1482 {
1483 SaveData(true);
1484 Puts("PlayerRanks database was saved.");
1485 }
1486
1487 [ConsoleCommand("playerranks.wipe")]
1488 void CmdWipe(ConsoleSystem.Arg arg)
1489 {
1490 if (arg.Connection != null)
1491 {
1492 var player = arg.Connection.player as BasePlayer;
1493 if (!HasPermission(player.UserIDString, permAllowed))
1494 return;
1495 }
1496 data.PlayerRankData.Clear();
1497 PRData.WriteObject(data);
1498 SetUp();
1499 if (conf.MySQL.useMySQL)
1500 LoadMySQL(true);
1501 Puts("PlayerRanks database was wiped.");
1502 }
1503 #endregion
1504
1505 #region chat commands
1506 [ChatCommand("pr")]
1507 void CmdTarget(BasePlayer player, string command, string[] args)
1508 {
1509 var dictToUse = data.PlayerRankData;
1510
1511 if (args == null || args.Length == 0)
1512 {
1513 CallPersonalStatsUI(player, "true");
1514 return;
1515 }
1516
1517 var d = data.PlayerRankData[player.userID];
1518
1519 switch (args[0].ToLower())
1520 {
1521 case "save":
1522 if (HasPermission(player.UserIDString, permAllowed))
1523 {
1524 SaveData(true);
1525 SendReply(player, conf.GUI.fontColor1 + lang.GetMessage("title", this) + "</color>" + lang.GetMessage("save", this));
1526 }
1527 return;
1528
1529 case "wipe":
1530 if (HasPermission(player.UserIDString, permAllowed))
1531 {
1532 data.PlayerRankData.Clear();
1533 PRData.WriteObject(data);
1534 SetUp();
1535 if (conf.MySQL.useMySQL)
1536 LoadMySQL(true);
1537 SendReply(player, conf.GUI.fontColor1 + lang.GetMessage("title", this) + "</color>" + lang.GetMessage("wipe", this));
1538 }
1539 return;
1540
1541 case "del":
1542 if (HasPermission(player.UserIDString, permAllowed))
1543 {
1544 if (args.Length == 2)
1545 {
1546 string s = args[1];
1547 ulong result;
1548 if (ulong.TryParse(s, out result))
1549 {
1550 ulong arg = Convert.ToUInt64(args[1]);
1551 if (data.PlayerRankData.ContainsKey(arg))
1552 {
1553 data.PlayerRankData.Remove(arg);
1554 PRData.WriteObject(data);
1555 SetUp();
1556 SendReply(player, conf.GUI.fontColor1 + lang.GetMessage("title", this) + "</color>" + lang.GetMessage("dbremoved", this));
1557 }
1558 else
1559 SendReply(player, conf.GUI.fontColor1 + lang.GetMessage("title", this) + "</color>" + lang.GetMessage("noentry", this));
1560 }
1561 else
1562 SendReply(player, conf.GUI.fontColor1 + lang.GetMessage("title", this) + "</color>" + lang.GetMessage("syntax", this));
1563 }
1564 }
1565 return;
1566
1567 case "wipecategory":
1568 if (args.Length == 2)
1569 {
1570 if (HasPermission(player.UserIDString, permAllowed))
1571 {
1572 var request = args[1].ToLower();
1573 bool found = false;
1574 foreach (var cat in allowedCats)
1575 {
1576 if (cat.Key.ToLower() == request)
1577 {
1578 foreach (var Entry in data.PlayerRankData)
1579 {
1580 if (request == "pvpkills") data.PlayerRankData[Entry.Key].PVPKills = 0;
1581 if (request == "pvpdistance") data.PlayerRankData[Entry.Key].PVPDistance = 0;
1582 if (request == "pvekills") data.PlayerRankData[Entry.Key].PVEKills = 0;
1583 if (request == "pvedistance") data.PlayerRankData[Entry.Key].PVEDistance = 0;
1584 if (request == "npckills") data.PlayerRankData[Entry.Key].NPCKills = 0;
1585 if (request == "npcdistance") data.PlayerRankData[Entry.Key].NPCDistance = 0;
1586 if (request == "sleeperskilled") data.PlayerRankData[Entry.Key].SleepersKilled = 0;
1587 if (request == "headshots") data.PlayerRankData[Entry.Key].HeadShots = 0;
1588 if (request == "deaths") data.PlayerRankData[Entry.Key].Deaths = 0;
1589 if (request == "suicides") data.PlayerRankData[Entry.Key].Suicides = 0;
1590 if (request == "kdr") data.PlayerRankData[Entry.Key].KDR = 0;
1591 if (request == "sdr") data.PlayerRankData[Entry.Key].SDR = 0;
1592 if (request == "skullscrushed") data.PlayerRankData[Entry.Key].SkullsCrushed = 0;
1593 if (request == "timeswounded") data.PlayerRankData[Entry.Key].TimesWounded = 0;
1594 if (request == "timeshealed") data.PlayerRankData[Entry.Key].TimesHealed = 0;
1595 if (request == "helihits") data.PlayerRankData[Entry.Key].HeliHits = 0;
1596 if (request == "helikills") data.PlayerRankData[Entry.Key].HeliKills = 0;
1597 if (request == "apchits") data.PlayerRankData[Entry.Key].APCHits = 0;
1598 if (request == "apckills") data.PlayerRankData[Entry.Key].APCKills = 0;
1599 if (request == "barrelsdestroyed") data.PlayerRankData[Entry.Key].BarrelsDestroyed = 0;
1600 if (request == "explosivesthrown") data.PlayerRankData[Entry.Key].ExplosivesThrown = 0;
1601 if (request == "arrowsfired") data.PlayerRankData[Entry.Key].ArrowsFired = 0;
1602 if (request == "bulletsfired") data.PlayerRankData[Entry.Key].BulletsFired = 0;
1603 if (request == "rocketslaunched") data.PlayerRankData[Entry.Key].RocketsLaunched = 0;
1604 if (request == "weapontrapsdestroyed") data.PlayerRankData[Entry.Key].WeaponTrapsDestroyed = 0;
1605 if (request == "dropslooted") data.PlayerRankData[Entry.Key].DropsLooted = 0;
1606 if (request == "structuresbuilt") data.PlayerRankData[Entry.Key].StructuresBuilt = 0;
1607 if (request == "structuresdemolished") data.PlayerRankData[Entry.Key].StructuresDemolished = 0;
1608 if (request == "itemsdeployed") data.PlayerRankData[Entry.Key].ItemsDeployed = 0;
1609 if (request == "itemscrafted") data.PlayerRankData[Entry.Key].ItemsCrafted = 0;
1610 if (request == "entitiesrepaired") data.PlayerRankData[Entry.Key].EntitiesRepaired = 0;
1611 if (request == "resourcesgathered") data.PlayerRankData[Entry.Key].ResourcesGathered = 0;
1612 if (request == "structuresupgraded") data.PlayerRankData[Entry.Key].StructuresUpgraded = 0;
1613 }
1614 found = true;
1615 break;
1616 }
1617 }
1618 if (found ==true)
1619 {
1620 PRData.WriteObject(data);
1621 SetUp();
1622 SendReply(player, conf.GUI.fontColor1 + lang.GetMessage("title", this) + "</color>" + lang.GetMessage("category", this));
1623 }
1624 else
1625 SendReply(player, conf.GUI.fontColor1 + lang.GetMessage("title", this) + "</color>" + lang.GetMessage("nocategory", this));
1626 }
1627 }
1628 return;
1629 }
1630 }
1631
1632 bool BroadcastMethod(String category)
1633 {
1634 var dictToUse = data.PlayerRankData;
1635 int amount = conf.Options.TimedTopListAmount;
1636 if (conf.Options.allowadmin == false)
1637 {
1638 dictToUse = data.PlayerRankData.Where(pair => pair.Value.Admin == false).ToDictionary(val => val.Key, val => val.Value);
1639 }
1640 Dictionary<string, object> top = dictToUse.OrderByDescending(pair => pair.Value.GetValue(category)).Take(amount).ToDictionary(pair => pair.Value.Name, pair => pair.Value.GetValue(category));
1641 top = top.Where(kvp => Convert.ToDouble(kvp.Value) > 0).ToDictionary(x => x.Key, x => x.Value);
1642 if (top.Count > 0)
1643 {
1644 var outMsg = conf.GUI.fontColor1 + lang.GetMessage("title", this) + "</color>" + conf.GUI.fontColor2 + lang.GetMessage("bestHits", this) + lang.GetMessage(category, this) + "</color> \n";
1645 foreach (var name in top)
1646 {
1647 outMsg += string.Format(conf.GUI.fontColor3 + "{0} : " + "</color>" + conf.GUI.fontColor1 + "{1}" + "</color>" + "\n", name.Key, name.Value);
1648 }
1649 if (outMsg != "")
1650 Server.Broadcast($"<size={conf.Options.TimedTopListSize}>{outMsg}</size>");
1651 return true;
1652 }
1653 return false;
1654 }
1655
1656 bool IsAuth(BasePlayer player)
1657 {
1658 return (player.net.connection != null && player.net.connection.authLevel == 2);
1659 }
1660
1661 public static string RemoveSurrogatePairs(string str, string replacementCharacter = "?")
1662 {
1663 if (str == null) return null;
1664
1665 StringBuilder sb = null;
1666
1667 for (int i = 0; i < str.Length; i++)
1668 {
1669 char ch = str[i];
1670 if (char.IsSurrogate(ch))
1671 {
1672 if (sb == null)
1673 sb = new StringBuilder(str, 0, i, str.Length);
1674
1675 sb.Append(replacementCharacter);
1676
1677 if (i + 1 < str.Length && char.IsHighSurrogate(ch) && char.IsLowSurrogate(str[i + 1]))
1678 i++;
1679 }
1680 else if (sb != null)
1681 sb.Append(ch);
1682 }
1683 return sb == null ? str : sb.ToString();
1684 }
1685
1686
1687 Core.MySql.Libraries.MySql Sql = Interface.Oxide.GetLibrary<Core.MySql.Libraries.MySql>();
1688 Core.Database.Connection Sql_conn;
1689
1690 void LoadMySQL(bool wipe)
1691 {
1692 try { Sql_conn.Con.Open(); }
1693 catch (Exception e) { PrintWarning(e.Message); return; }
1694
1695 try
1696 {
1697 if (Sql_conn == null || Sql_conn.Con == null)
1698 {
1699 Puts("Player Ranks MySQL connection has failed. Please check your credentials.");
1700 return;
1701 }
1702 if (wipe && conf.MySQL.autoWipe)
1703 {
1704 Sql.Insert(Core.Database.Sql.Builder.Append($"DROP TABLE IF EXISTS {conf.MySQL.tablename}"), Sql_conn);
1705 Puts("Player Ranks MySQL Table Was Dropped.");
1706 }
1707
1708 Sql.Insert(Core.Database.Sql.Builder.Append($"CREATE TABLE IF NOT EXISTS {conf.MySQL.tablename} ( `UserID` VARCHAR(17) NOT NULL, `Name` LONGTEXT NOT NULL, `PVPKills` INT(11) NOT NULL, `PVPDistance` DOUBLE NOT NULL, `PVEKills` INT(11) NOT NULL, `PVEDistance` DOUBLE NOT NULL, `NPCKills` INT(11) NOT NULL, `NPCDistance` DOUBLE NOT NULL, `SleepersKilled` INT(11) NOT NULL, `HeadShots` Int(11) NOT NULL, `Deaths` INT(11) NOT NULL, `Suicides` INT(11) NOT NULL, `KDR` DOUBLE NOT NULL, `SDR` DOUBLE NOT NULL, `SkullsCrushed` INT(11) NOT NULL, `TimesWounded` INT(11) NOT NULL, `TimesHealed` INT(11) NOT NULL, `HeliHits` INT(11) NOT NULL, `HeliKills` INT(11) NOT NULL, `APCHits` INT(11) NOT NULL, `APCKills` INT(11) NOT NULL, `BarrelsDestroyed` INT(11) NOT NULL, `ExplosivesThrown` INT(11) NOT NULL, `ArrowsFired` INT(11) NOT NULL, `BulletsFired` INT(11) NOT NULL, `RocketsLaunched` INT(11) NOT NULL, `WeaponTrapsDestroyed` INT(11) NOT NULL, `DropsLooted` Int(11) NOT NULL, `StructuresBuilt` INT(11) NOT NULL, `StructuresDemolished` INT(11) NOT NULL, `ItemsDeployed` INT(11) NOT NULL, `ItemsCrafted` INT(11) NOT NULL, `EntitiesRepaired` INT(11) NOT NULL, `ResourcesGathered` INT(11) NOT NULL, `StructuresUpgraded` INT(11) NOT NULL, `Status` VARCHAR(11) NOT NULL, `TimePlayed` TIME NOT NULL, `Admin` BOOLEAN NOT NULL, `Economics` INT(11) NOT NULL, `ActiveDate` DateTime NOT NULL, PRIMARY KEY (`UserID`));"), Sql_conn);
1709
1710 Sql.Insert(Core.Database.Sql.Builder.Append($"CREATE TABLE IF NOT EXISTS {conf.MySQL.LBtableName} ( `Date` DateTime NOT NULL,`PVPKillsName` LONGTEXT NOT NULL,`PVPKills` INT(11) NOT NULL,`PVPDistanceName` LONGTEXT NOT NULL,`PVPDistance` DOUBLE NOT NULL,`PVEKillsName` LONGTEXT NOT NULL,`PVEKills` INT(11) NOT NULL,`PVEDistanceName` LONGTEXT NOT NULL,`PVEDistance` DOUBLE NOT NULL,`NPCKillsName` LONGTEXT NOT NULL,`NPCKills` INT(11) NOT NULL,`NPCDistanceName` LONGTEXT NOT NULL,`NPCDistance` DOUBLE NOT NULL,`SleepersKilledName` LONGTEXT NOT NULL,`SleepersKilled` INT(11) NOT NULL,`HeadShotsName` LONGTEXT NOT NULL,`HeadShots` Int(11) NOT NULL,`DeathsName` LONGTEXT NOT NULL,`Deaths` INT(11) NOT NULL,`SuicidesName` LONGTEXT NOT NULL,`Suicides` INT(11) NOT NULL,`KDRName` LONGTEXT NOT NULL,`KDR` DOUBLE NOT NULL,`SDRName` LONGTEXT NOT NULL,`SDR` DOUBLE NOT NULL,`SkullsCrushedName` LONGTEXT NOT NULL,`SkullsCrushed` INT(11) NOT NULL,`TimesWoundedName` LONGTEXT NOT NULL,`TimesWounded` INT(11) NOT NULL,`TimesHealedName` LONGTEXT NOT NULL,`TimesHealed` INT(11) NOT NULL,`HeliHitsName` LONGTEXT NOT NULL,`HeliHits` INT(11) NOT NULL,`HeliKillsName` LONGTEXT NOT NULL,`HeliKills` INT(11) NOT NULL,`APCHitsName` LONGTEXT NOT NULL,`APCHits` INT(11) NOT NULL,`APCKillsName` LONGTEXT NOT NULL,`APCKills` INT(11) NOT NULL,`BarrelsDestroyedName` LONGTEXT NOT NULL,`BarrelsDestroyed` INT(11) NOT NULL,`ExplosivesThrownName` LONGTEXT NOT NULL,`ExplosivesThrown` INT(11) NOT NULL,`ArrowsFiredName` LONGTEXT NOT NULL,`ArrowsFired` INT(11) NOT NULL,`BulletsFiredName` LONGTEXT NOT NULL,`BulletsFired` INT(11) NOT NULL,`RocketsLaunchedName` LONGTEXT NOT NULL,`RocketsLaunched` INT(11) NOT NULL,`WeaponTrapsDestroyedName` LONGTEXT NOT NULL,`WeaponTrapsDestroyed` INT(11) NOT NULL,`DropsLootedName` LONGTEXT NOT NULL,`DropsLooted` Int(11) NOT NULL,`StructuresBuiltName` LONGTEXT NOT NULL,`StructuresBuilt` INT(11) NOT NULL,`StructuresDemolishedName` LONGTEXT NOT NULL,`StructuresDemolished` INT(11) NOT NULL,`ItemsDeployedName` LONGTEXT NOT NULL,`ItemsDeployed` INT(11) NOT NULL,`ItemsCraftedName` LONGTEXT NOT NULL,`ItemsCrafted` INT(11) NOT NULL,`EntitiesRepairedName` LONGTEXT NOT NULL,`EntitiesRepaired` INT(11) NOT NULL,`ResourcesGatheredName` LONGTEXT NOT NULL,`ResourcesGathered` INT(11) NOT NULL,`StructuresUpgradedName` LONGTEXT NOT NULL,`StructuresUpgraded` INT(11) NOT NULL,PRIMARY KEY (`Date`));"), Sql_conn);
1711 }
1712 catch (Exception e)
1713 {
1714 Puts("Player Ranks did not succesfully create a table.");
1715 }
1716
1717 try
1718 {
1719 foreach(var c in data.PlayerRankData)
1720 {
1721 Sql.Insert(Core.Database.Sql.Builder.Append($"INSERT INTO {conf.MySQL.tablename} ( `UserID`, `Name`, `PVPKills`, `PVPDistance`, `PVEKills`, `PVEDistance`, `NPCKills`, `NPCDistance`, `SleepersKilled`, `Headshots`, `Deaths`, `Suicides`, `KDR`, `SDR`, `SkullsCrushed`, `TimesWounded`, `TimesHealed`, `HeliHits`, `HeliKills`, `APCHits`, `APCKills`, `BarrelsDestroyed`, `ExplosivesThrown`, `ArrowsFired`, `BulletsFired`, `RocketsLaunched`, `WeaponTrapsDestroyed`, `DropsLooted`, `StructuresBuilt`, `StructuresDemolished`, `ItemsDeployed`, `ItemsCrafted`, `EntitiesRepaired`, `ResourcesGathered`, `StructuresUpgraded`, `Status`, `TimePlayed`, `Admin`, `Economics`, `ActiveDate`) VALUES ( @0, @1, @2, @3, @4, @5, @6, @7, @8, @9, @10, @11, @12, @13, @14, @15, @16, @17, @18, @19, @20, @21, @22, @23, @24, @25, @26, @27, @28, @29, @30, @31, @32, @33, @34, @35, @36, @37, @38, @39) ON DUPLICATE KEY UPDATE UserID = @0, Name = @1, PVPKills = @2, PVPDistance = @3, PVEKills = @4, PVEDistance = @5, NPCKills = @6, NPCDistance = @7,SleepersKilled = @8, HeadShots = @9, Deaths = @10, Suicides = @11, KDR = @12, SDR = @13, SkullsCrushed = @14, TimesWounded = @15, TimesHealed = @16, HeliHits = @17, HeliKills = @18, APCHits = @19, APCKills = @20, BarrelsDestroyed = @21, ExplosivesThrown = @22, ArrowsFired = @23, BulletsFired = @24, RocketsLaunched = @25, WeaponTrapsDestroyed = @26, DropsLooted = @27, StructuresBuilt = @28, StructuresDemolished = @29, ItemsDeployed = @30, ItemsCrafted = @31, EntitiesRepaired = @32, ResourcesGathered = @33, StructuresUpgraded = @34, Status = @35, TimePlayed = @36, Admin = @37, Economics = @38, ActiveDate = @39;", c.Value.UserID, RemoveSurrogatePairs(c.Value.Name, ""), c.Value.PVPKills, c.Value.PVPDistance, c.Value.PVEKills, c.Value.PVEDistance, c.Value.NPCKills, c.Value.NPCDistance, c.Value.SleepersKilled, c.Value.HeadShots, c.Value.Deaths, c.Value.Suicides, c.Value.KDR, c.Value.SDR, c.Value.SkullsCrushed, c.Value.TimesWounded, c.Value.TimesHealed, c.Value.HeliHits, c.Value.HeliKills, c.Value.APCHits, c.Value.APCKills, c.Value.BarrelsDestroyed, c.Value.ExplosivesThrown, c.Value.ArrowsFired, c.Value.BulletsFired, c.Value.RocketsLaunched, c.Value.WeaponTrapsDestroyed, c.Value.DropsLooted, c.Value.StructuresBuilt, c.Value.StructuresDemolished, c.Value.ItemsDeployed, c.Value.ItemsCrafted, c.Value.EntitiesRepaired, c.Value.ResourcesGathered, c.Value.StructuresUpgraded, c.Value.Status, c.Value.TimePlayed, c.Value.Admin, c.Value.Economics, c.Value.ActiveDate), Sql_conn);
1722 }
1723
1724 foreach(var c in data.leaderBoards)
1725 {
1726 Sql.Insert(Core.Database.Sql.Builder.Append($"INSERT INTO {conf.MySQL.LBtableName} ( `Date`,`PVPKillsName`, `PVPKills`, `PVPDistanceName`, `PVPDistance`, `PVEKillsName`, `PVEKills`, `PVEDistanceName`, `PVEDistance`, `NPCKillsName`, `NPCKills`, `NPCDistanceName`, `NPCDistance`, `SleepersKilledName`, `SleepersKilled`, `HeadshotsName`,`Headshots`,`DeathsName`, `Deaths`, `SuicidesName`, `Suicides`, `KDRName`, `KDR`, `SDRName`,`SDR`,`SkullsCrushedName`, `SkullsCrushed`, `TimesWoundedName`, `TimesWounded`, `TimesHealedName`, `TimesHealed`, `HeliHitsName`,`HeliHits`,`HeliKillsName`, `HeliKills`, `APCHitsName`, `APCHits`, `APCKillsName`, `APCKills`, `BarrelsDestroyedName`,`BarrelsDestroyed`,`ExplosivesThrownName`, `ExplosivesThrown`, `ArrowsFiredName`, `ArrowsFired`, `BulletsFiredName`, `BulletsFired`, `RocketsLaunchedName`,`RocketsLaunched`,`WeaponTrapsDestroyedName`, `WeaponTrapsDestroyed`, `DropsLootedName`, `DropsLooted`, `StructuresBuiltName`, `StructuresBuilt`, `StructuresDemolishedName`,`StructuresDemolished`,`ItemsDeployedName`, `ItemsDeployed`, `ItemsCraftedName`, `ItemsCrafted`, `EntitiesRepairedName`, `EntitiesRepaired`, `ResourcesGatheredName`,`ResourcesGathered`,`StructuresUpgradedName`, `StructuresUpgraded`) VALUES ( @0, @1, @2, @3, @4, @5, @6, @7, @8, @9, @10, @11, @12, @13, @14, @15, @16, @17, @18, @19, @20, @21, @22, @23, @24, @25, @26, @27, @28, @29, @30, @31, @32, @33, @34, @35, @36, @37, @38, @39, @40, @41, @42, @43, @44, @45, @46, @47, @48, @49, @50, @51, @52, @53, @54, @55, @56, @57, @58, @59, @60, @61, @62, @63, @64, @65, @66 ) ON DUPLICATE KEY UPDATE Date = @0, PVPKillsName = @1, PVPKills = @2, PVPDistanceName = @3, PVPDistance = @4, PVEKillsName = @5, PVEKills = @6, PVEDistanceName = @7,PVEDistance = @8,NPCKillsName = @9, NPCKills = @10, NPCDistanceName = @11, NPCDistance = @12, SleepersKilledName = @13, SleepersKilled = @14, HeadshotsName = @15, Headshots = @16,DeathsName = @17, Deaths = @18, SuicidesName = @19, Suicides = @20, KDRName = @21, KDR = @22, SDRName = @23, SDR = @24,SkullsCrushedName = @25, SkullsCrushed = @26, TimesWoundedName = @27, TimesWounded = @28, TimesHealedName = @29, TimesHealed = @30, HeliHitsName = @31, HeliHits = @32,HeliKillsName = @33, HeliKills = @34, APCHitsName = @35, APCHits = @36, APCKillsName = @37, APCKills = @38, BarrelsDestroyedName = @39, BarrelsDestroyed = @40,ExplosivesThrownName = @41, ExplosivesThrown = @42, ArrowsFiredName = @43, ArrowsFired = @44, BulletsFiredName = @45, BulletsFired = @46, RocketsLaunchedName = @47, RocketsLaunched = @48,WeaponTrapsDestroyedName = @49, WeaponTrapsDestroyed = @50, DropsLootedName = @51, DropsLooted = @52, StructuresBuiltName = @53, StructuresBuilt = @54, StructuresDemolishedName = @55, StructuresDemolished = @56,ItemsDeployedName = @57, ItemsDeployed = @58, ItemsCraftedName = @59, ItemsCrafted = @60, EntitiesRepairedName = @61, EntitiesRepaired = @62, ResourcesGatheredName = @63, ResourcesGathered = @64,StructuresUpgradedName = @65, StructuresUpgraded = @66;",c.Key,RemoveSurrogatePairs(c.Value["PVPKills"].UserName, ""),c.Value["PVPKills"].Score,RemoveSurrogatePairs(c.Value["PVPDistance"].UserName, ""),c.Value["PVPDistance"].Score,RemoveSurrogatePairs(c.Value["PVEKills"].UserName, ""),c.Value["PVEKills"].Score,RemoveSurrogatePairs(c.Value["PVEDistance"].UserName, ""),c.Value["PVEDistance"].Score,RemoveSurrogatePairs(c.Value["NPCKills"].UserName, ""),c.Value["NPCKills"].Score,RemoveSurrogatePairs(c.Value["NPCDistance"].UserName, ""),c.Value["NPCDistance"].Score,RemoveSurrogatePairs(c.Value["SleepersKilled"].UserName, ""),c.Value["SleepersKilled"].Score,RemoveSurrogatePairs(c.Value["HeadShots"].UserName, ""),c.Value["HeadShots"].UserName,RemoveSurrogatePairs(c.Value["Deaths"].UserName, ""),c.Value["Deaths"].Score,RemoveSurrogatePairs(c.Value["Suicides"].UserName, ""),c.Value["Suicides"].Score,RemoveSurrogatePairs(c.Value["KDR"].UserName, ""),c.Value["KDR"].Score,RemoveSurrogatePairs(c.Value["SDR"].UserName, ""),c.Value["SDR"].Score,RemoveSurrogatePairs(c.Value["SkullsCrushed"].UserName, ""),c.Value["SkullsCrushed"].Score,RemoveSurrogatePairs(c.Value["TimesWounded"].UserName, ""),c.Value["TimesWounded"].Score,RemoveSurrogatePairs(c.Value["TimesHealed"].UserName, ""),c.Value["TimesHealed"].Score,RemoveSurrogatePairs(c.Value["HeliHits"].UserName, ""),c.Value["HeliHits"].Score,RemoveSurrogatePairs(c.Value["HeliKills"].UserName, ""),c.Value["HeliKills"].Score,RemoveSurrogatePairs(c.Value["APCHits"].UserName, ""),c.Value["APCHits"].Score,RemoveSurrogatePairs(c.Value["APCKills"].UserName, ""),c.Value["APCKills"].Score,RemoveSurrogatePairs(c.Value["BarrelsDestroyed"].UserName, ""),c.Value["BarrelsDestroyed"].Score,RemoveSurrogatePairs(c.Value["ExplosivesThrown"].UserName, ""),c.Value["ExplosivesThrown"].Score,RemoveSurrogatePairs(c.Value["ArrowsFired"].UserName, ""),c.Value["ArrowsFired"].Score,RemoveSurrogatePairs(c.Value["BulletsFired"].UserName, ""),c.Value["BulletsFired"].Score,RemoveSurrogatePairs(c.Value["RocketsLaunched"].UserName, ""),c.Value["RocketsLaunched"].Score,RemoveSurrogatePairs(c.Value["WeaponTrapsDestroyed"].UserName, ""),c.Value["WeaponTrapsDestroyed"].Score,RemoveSurrogatePairs(c.Value["DropsLooted"].UserName, ""),c.Value["DropsLooted"].Score,RemoveSurrogatePairs(c.Value["StructuresBuilt"].UserName, ""),c.Value["StructuresBuilt"].Score,RemoveSurrogatePairs(c.Value["StructuresDemolished"].UserName, ""),c.Value["StructuresDemolished"].Score,RemoveSurrogatePairs(c.Value["ItemsDeployed"].UserName, ""),c.Value["ItemsDeployed"].Score,RemoveSurrogatePairs(c.Value["ItemsCrafted"].UserName, ""),c.Value["ItemsCrafted"].Score,RemoveSurrogatePairs(c.Value["EntitiesRepaired"].UserName, ""),c.Value["EntitiesRepaired"].Score,RemoveSurrogatePairs(c.Value["ResourcesGathered"].UserName, ""),c.Value["ResourcesGathered"].Score,RemoveSurrogatePairs(c.Value["StructuresUpgraded"].UserName, ""),c.Value["StructuresUpgraded"].Score), Sql_conn);
1727 }
1728 Puts("Player Ranks MySQL Table Was Saved.");
1729 }
1730 catch (Exception e)
1731 {
1732 Puts("Player Ranks did not succesfully save data to SQL.");
1733 }
1734
1735 }
1736 #endregion
1737
1738 #region config
1739 private ConfigData conf;
1740 public class ConfigData
1741 {
1742 public Options Options = new Options();
1743 public GUI GUI = new GUI();
1744 public Categories Categories = new Categories();
1745 public MySQL MySQL = new MySQL();
1746 }
1747 public class Options
1748 {
1749 public bool useFriendsAPI;
1750 public bool useClans;
1751 public bool useRustIO;
1752 public bool blockEvents = true;
1753 public bool useIntenseOptions = true;
1754 public int TimedTopListTimer = 10;
1755 public int TimedTopListAmount = 3;
1756 public bool useTimedTopList = true;
1757 public int TimedTopListSize = 12;
1758 public int saveTimer = 30;
1759 public string chatCommandAlias = "ranks";
1760 public bool allowadmin;
1761 public bool statCollection = true;
1762 public int lastLoginLimit;
1763 }
1764
1765 public class GUI
1766 {
1767 public string fontColor1 = "<color=orange>";
1768 public string fontColor2 = "<color=#939393>";
1769 public string fontColor3 = "<color=white>";
1770 public string buttonColour = "0.7 0.32 0.17 1";
1771 public double guitransparency = 0.5;
1772 }
1773 public class Categories
1774 {
1775 public bool usepvpkills = true;
1776 public bool usepvpdistance = true;
1777 public bool usepvekills = true;
1778 public bool usepvedistance = true;
1779 public bool usenpckills = true;
1780 public bool usenpcdistance = true;
1781 public bool usesleeperskilled = true;
1782 public bool useheadshots = true;
1783 public bool usedeaths = true;
1784 public bool usesuicides = true;
1785 public bool usekdr = true;
1786 public bool usesdr = true;
1787 public bool useskullscrushed = true;
1788 public bool usetimeswounded = true;
1789 public bool usetimeshealed = true;
1790 public bool usehelihits = true;
1791 public bool usehelikills = true;
1792 public bool useapchits = true;
1793 public bool useapckills = true;
1794 public bool usebarrelsdestroyed = true;
1795 public bool useexplosivesthrown = true;
1796 public bool usearrowsfired = true;
1797 public bool usebulletsfired = true;
1798 public bool userocketslaunched = true;
1799 public bool useweapontrapsdestroyed = true;
1800 public bool usedropslooted = true;
1801 public bool usestructuresbuilt = true;
1802 public bool usestructuresdemolished = true;
1803 public bool useitemsdeployed = true;
1804 public bool useitemscrafted = true;
1805 public bool useentitiesrepaired = true;
1806 public bool useresourcesgathered = true;
1807 public bool usestructuresupgraded = true;
1808 }
1809
1810 public class MySQL
1811 {
1812 public bool useMySQL;
1813 public string sql_host = "";
1814 public int sql_port = 3306;
1815 public string sql_db = "";
1816 public string sql_user = "";
1817 public string sql_pass = "";
1818 public string tablename = "playerranksdb";
1819 public string LBtableName = "playerranksLeaderdb";
1820 public bool autoWipe = true;
1821 }
1822
1823 protected override void LoadDefaultConfig()
1824 {
1825 Puts("Creating new config file.");
1826 var config = new ConfigData();
1827 SaveConfig();
1828 }
1829
1830 private void LoadConfigVariables()
1831 {
1832 conf = Config.ReadObject<ConfigData>();
1833 SaveConfig(conf);
1834 }
1835
1836 void SaveConfig(ConfigData config)
1837 {
1838 Config.WriteObject(config, true);
1839 }
1840 #endregion
1841
1842 #region classes and data storage
1843
1844 void SaveData(bool sql)
1845 {
1846 var banlist = new List<ulong>();
1847 foreach(var entry in data.PlayerRankData)
1848 {
1849 if (ServerUsers.Is(entry.Key, ServerUsers.UserGroup.Banned))
1850 {
1851 banlist.Add(entry.Key);
1852 }
1853 entry.Value.Status = "offline";
1854 }
1855 foreach (var banned in banlist)
1856 if (data.PlayerRankData.ContainsKey(banned))
1857 data.PlayerRankData.Remove(banned);
1858
1859 DateTime cutoff = DateTime.UtcNow.Subtract(TimeSpan.FromDays(conf.Options.lastLoginLimit));
1860 if (conf.Options.lastLoginLimit > 0)
1861 data.PlayerRankData = data.PlayerRankData.Where(x=>x.Value.ActiveDate > cutoff).ToDictionary(x=>x.Key,x=>x.Value);
1862
1863 foreach(BasePlayer player in BasePlayer.activePlayerList)
1864 if (data.PlayerRankData.ContainsKey(player.userID))
1865 UpdatePlayer(player);
1866
1867 PRData.WriteObject(data);
1868 if (conf.MySQL.useMySQL && sql)
1869 LoadMySQL(false);
1870 }
1871
1872 void LoadData()
1873 {
1874 try
1875 {
1876 data = Interface.GetMod().DataFileSystem.ReadObject<DataStorage>("PlayerRanks");
1877 PRData.WriteObject(data);//forces to conform immediately if structure has changed
1878 }
1879 catch
1880 {
1881 data = new DataStorage();
1882 }
1883 }
1884 #endregion
1885
1886 #region messages
1887
1888 readonly Dictionary<string, string> messages = new Dictionary<string, string>()
1889 {
1890 {"title", "PlayerRanks: " },
1891 {"wipe", "PlayerRanks database wiped."},
1892 {"nowipe", "PlayerRanks database was already empty."},
1893 {"save", "PlayerRanks database saved."},
1894 {"del", "PlayerRanks for this player were wiped."},
1895 {"bestHits", "Top " },
1896 {"dbremoved", "Details for this ID have been removed." },
1897 {"noentry", "There is no entry in the database for this ID." },
1898 {"syntax", "ID must be 17 digits." },
1899 {"category", "Stats for this category have been removed." },
1900 {"nocategory", "This is not a recognised category." },
1901 {"noResults", "There are no statistics for this category." },
1902 {"disabled", "This category has been disabled." },
1903 {"leaderboard", "Leader Board" },
1904 {"categories", "Categories" },
1905 {"close", "Close" },
1906 {"mystats", "My Stats" },
1907 {"admin", "Admin" },
1908
1909
1910 {"gatherStatsOnButton", "Gather Stats - On" },
1911 {"gatherStatsOffButton", "Gather Stats - Off" },
1912 {"disableAdminStatsButton", "Disable Admin Stats" },
1913 {"AllowAdminStatsButton", "Allow Admin Stats" },
1914 {"savePlayerDataButton", "Save Player Data" },
1915 {"wipePlayerDataButton", "Wipe Player Data" },
1916 {"confirmbutton", "Confirm" },
1917 {"saveLeaderBoardButton", "Save Leaderboard" },
1918 {"wipeLeaderBoardButton", "Wipe Leaderboards" },
1919 {"on", "On" },
1920 {"off", "Off" },
1921
1922 {"PVPKills", "PVP Kills " },
1923 {"PVPDistance", "PVP Distance " },
1924 {"PVEKills", "PVE Kills " },
1925 {"PVEDistance", "PVE Distance " },
1926 {"NPCKills", "NPC Kills " },
1927 {"NPCDistance", "NPC Distance " },
1928 {"SleepersKilled", "Sleepers Killed " },
1929 {"HeadShots", "Head Shots " },
1930 {"Deaths", "Deaths " },
1931 {"Suicides", "Suicides " },
1932 {"KDR", "KDR " },
1933 {"SDR", "SDR " },
1934 {"SkullsCrushed", "Skulls Crushed " },
1935 {"TimesWounded", "Times Wounded " },
1936 {"TimesHealed", "Times Healed " },
1937 {"HeliHits", "Heli Hits " },
1938 {"HeliKills", "Heli Kills " },
1939 {"APCHits", "APC Hits " },
1940 {"APCKills", "APC Kills " },
1941 {"BarrelsDestroyed", "Barrels Destroyed " },
1942 {"ExplosivesThrown", "Explosives Thrown " },
1943 {"ArrowsFired", "Arrows Fired " },
1944 {"BulletsFired", "Bullets Fired " },
1945 {"RocketsLaunched", "Rockets Launched " },
1946 {"WeaponTrapsDestroyed", "Weapon Traps Destroyed " },
1947 {"DropsLooted", "Airdrops Looted " },
1948
1949 //intense options
1950 {"StructuresBuilt", "Structures Built " },
1951 {"StructuresDemolished", "Structures Demolished " },
1952 {"ItemsDeployed", "Items Deployed " },
1953 {"ItemsCrafted", "Items Crafted " },
1954 {"EntitiesRepaired", "Entities Repaired " },
1955 {"ResourcesGathered", "Resources Gathered " },
1956 {"StructuresUpgraded", "Structures Upgraded " },
1957 };
1958 #endregion
1959 }
1960}