C#:
using Newtonsoft.Json;
using Oxide.Core;
using Oxide.Core.Database;
using Oxide.Core.Libraries.Covalence;
using Oxide.Core.Plugins;
using Oxide.Game.Rust.Cui;
using Rust;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
///Скачано с дискорд сервера Rust Edit [PRO+]
///discord.gg/9vyTXsJyKR
namespace Oxide.Plugins {
[Info("Better Statistics", "discord.gg/9vyTXsJyKR", "1.0.14")]
[Description("A plugin that syncs players statistics to a MySQL database.")]
public class BetterStatistics : CovalencePlugin {
#region Config
static Configuration config;
public class DBInfo {
[JsonProperty(PropertyName = "Host IP")]
public string sql_host;
[JsonProperty(PropertyName = "Port")]
public int sql_port;
[JsonProperty(PropertyName = "Database name")]
public string sql_db;
[JsonProperty(PropertyName = "Username")]
public string sql_user;
[JsonProperty(PropertyName = "Password")]
public string sql_passwword;
}
public class Configuration {
[JsonProperty(PropertyName = "Developer Mode (Debug Messages)")]
public bool developerMode;
[JsonProperty(PropertyName = "MySQL Database Connection Info")]
public DBInfo connectionInfo;
[JsonProperty(PropertyName = "Server Prefix (For tables Ex: (prefix)_stats_wipe, (prefix)_stats_overall)")]
public string serverPrefix;
[JsonProperty(PropertyName = "Save Interval (Mins) (0 = Disabled)")]
public int saveInterval;
[JsonProperty(PropertyName = "Use In-Game UI")]
public bool useIngameUI;
[JsonProperty(PropertyName = "Exclude NPC Type Deaths from death count?")]
public bool excludeNPCDeaths;
[JsonProperty(PropertyName = "Only count kills on players that have a stash on them?")]
public bool onlyStashKills;
public static Configuration DefaultConfig() {
return new Configuration {
developerMode = false, connectionInfo = new DBInfo {
sql_host = "localhost", sql_port = 3306, sql_user = "root", sql_passwword = "", sql_db = "betterstatistics"
}
, serverPrefix = "main", saveInterval = 10, useIngameUI = true, excludeNPCDeaths = true, onlyStashKills = false
}
;
}
}
protected override void LoadConfig() {
base.LoadConfig();
try {
config = Config.ReadObject<Configuration>();
if (config == null) LoadDefaultConfig();
SaveConfig();
}
catch (Exception e) {
Debug.LogException(e);
PrintWarning("Creating new config file.");
LoadDefaultConfig();
}
}
protected override void LoadDefaultConfig() => config = Configuration.DefaultConfig();
protected override void SaveConfig() => Config.WriteObject(config);
#endregion
#region Language
protected override void LoadDefaultMessages() {
lang.RegisterMessages(new Dictionary<string, string> {
["UpdatedPlayerStats"]
= "Updated {0} stats.", ["NoDatabaseConnection"] = "Database connection failed.Please check your credentials and try again.", ["PlayerNotFound"] = "Player not found in wipe stats table.", ["PlayerNotFoundOverall"] = "Player not found in overall stats table, these stats are filled when the server wipes.", ["UITitle"] = "Better Statistics", ["UIWipeButton"] = "WIPE", ["UIOverallButton"] = "OVERALL", ["UIExitButton"] = "EXIT", ["UIHead"] = "Head", ["UITorso"] = "Torso", ["UILeftArm"] = "Left Arm", ["UIRightArm"] = "Right Arm", ["UILeftLeg"] = "Left Leg", ["UIRightLeg"] = "Right Leg", ["UILeftFoot"] = "Left Foot", ["UIRightFoot"] = "Right Foot", ["UIPlayerStats"] = "Player Stats", ["UIConnects"] = "Connects", ["UIPlaytime"] = "Playtime", ["UIKills"] = "Kills", ["UIDeaths"] = "Deaths", ["UISuicides"] = "Suicides", ["UIWounded"] = "Wounded", ["UIKDRatio"] = "K/D Ratio", ["UIAccuracy"] = "Accuracy", ["UISatchels"] = "Satchels", ["UIC4"] = "C4", ["UIRockets"] = "Rockets", ["UITCsDestroyed"] = "TCs Destroyed", ["UINPCKills"] = "NPC Kills", ["UIChickens"] = "Chickens", ["UIBoars"] = "Boars", ["UIStags"] = "Stags", ["UIHorses"] = "Horses", ["UIWolves"] = "Wolves", ["UIBears"] = "Bears", ["UIScientists"] = "Scientists", ["UIHelicopters"] = "Helicopters", ["UIBradleys"] = "Bradleys", ["UIWeaponKills"] = "Weapon Kills", ["UINextPage"] = "NEXT PAGE", ["UIPreviousPage"] = "PREV PAGE"
}
, this);
}
private string GetLang(string langKey, params object[] args) {
return string.Format(lang.GetMessage(langKey, this), args);
}
#endregion
#region Classes
public class PlayerStats {
public string name = string.Empty;
public int connections = 0;
public int playtime = 0;
public DateTime connected = DateTime.Now;
public int kills = 0;
public int deaths = 0;
public int bfired = 0;
public int suicides = 0;
public int wounded = 0;
public int rocketsfired = 0;
public int c4thrown = 0;
public int satchelsthrown = 0;
public int tcsdestroyed = 0;
public NPCStats npcStats = new NPCStats();
public WeaponStats weaponStats = new WeaponStats();
public BodyParts hits = new BodyParts();
}
public class NPCStats {
public int chickens = 0;
public int boars = 0;
public int deers = 0;
public int horses = 0;
public int wolves = 0;
public int bears = 0;
public int scientists = 0;
public int helicopters = 0;
public int bradleys = 0;
}
;
public class WeaponStats {
public int ak47 = 0;
public int lr300 = 0;
public int m39 = 0;
public int sar = 0;
public int hmlmg = 0;
public int m249 = 0;
public int bolt = 0;
public int l96 = 0;
public int mp5 = 0;
public int thompson = 0;
public int custom = 0;
public int doublebarrel = 0;
public int pump = 0;
public int spaz12 = 0;
public int m92 = 0;
public int python = 0;
public int semipistol = 0;
public int revolver = 0;
public int waterpipe = 0;
public int eoka = 0;
public int compound = 0;
public int crossbow = 0;
public int bow = 0;
}
;
public class BodyParts {
public int head = 0;
public int torso = 0;
public int lefthand = 0;
public int righthand = 0;
public int leftleg = 0;
public int rightleg = 0;
public int leftfoot = 0;
public int rightfoot = 0;
}
;
public class Weapon {
public string WeaponName = "";
public string WeaponIcon = "";
}
List<Weapon> weapons = new List<Weapon>() {
new Weapon {
WeaponName = "AK", WeaponIcon = "https://i.imgur.com/DX6M8IM.png"
}
, new Weapon {
WeaponName = "LR", WeaponIcon = "https://i.imgur.com/EqSj6od.png"
}
, new Weapon {
WeaponName = "M39", WeaponIcon = "https://i.imgur.com/pj5eK7W.png"
}
, new Weapon {
WeaponName = "M249", WeaponIcon = "https://i.imgur.com/5ebpq7S.png"
}
, new Weapon {
WeaponName = "HMLMG", WeaponIcon = "https://i.imgur.com/WcruPRb.png"
}
, new Weapon {
WeaponName = "SAR", WeaponIcon = "https://i.imgur.com/n1N0y5R.png"
}
, new Weapon {
WeaponName = "L9", WeaponIcon = "https://i.imgur.com/WG8tWwT.png"
}
, new Weapon {
WeaponName = "BOLT", WeaponIcon = "https://i.imgur.com/SC8tLG6.png"
}
, new Weapon {
WeaponName = "MP5", WeaponIcon = "https://i.imgur.com/trJCQry.png"
}
, new Weapon {
WeaponName = "THOMPSON", WeaponIcon = "https://i.imgur.com/J4cAEf8.png"
}
, new Weapon {
WeaponName = "CUSTOMSMG", WeaponIcon = "https://i.imgur.com/KqK3ffK.png"
}
, new Weapon {
WeaponName = "PUMP", WeaponIcon = "https://i.imgur.com/7LwdMsG.png"
}
, new Weapon {
WeaponName = "DOUBLE", WeaponIcon = "https://i.imgur.com/eXT2fkS.png"
}
, new Weapon {
WeaponName = "SPAZ12", WeaponIcon = "https://i.imgur.com/PKfrRmz.png"
}
, new Weapon {
WeaponName = "M92", WeaponIcon = "https://i.imgur.com/nLn1Kyx.png"
}
, new Weapon {
WeaponName = "PYTHON", WeaponIcon = "https://i.imgur.com/BlJKetO.png"
}
, new Weapon {
WeaponName = "SEMIPISTOL", WeaponIcon = "https://i.imgur.com/OCH6rsz.png"
}
, new Weapon {
WeaponName = "REVOLVER", WeaponIcon = "https://i.imgur.com/NRlB8Ds.png"
}
, new Weapon {
WeaponName = "WATERPIPE", WeaponIcon = "https://i.imgur.com/fHKeAhR.png"
}
, new Weapon {
WeaponName = "EOKA", WeaponIcon = "https://i.imgur.com/Uh6bya5.png"
}
, new Weapon {
WeaponName = "COMPOUND", WeaponIcon = "https://i.imgur.com/pU8CXpI.png"
}
, new Weapon {
WeaponName = "CROSSBOW", WeaponIcon = "https://i.imgur.com/e6ukhQV.png"
}
, new Weapon {
WeaponName = "BOW", WeaponIcon = "https://i.imgur.com/lfbpVqR.png"
}
}
;
private int GetAmount(WeaponStats wStats, string weapon) {
switch (weapon) {
case "AK" : return wStats.ak47;
case "LR" : return wStats.lr300;
case "M39" : return wStats.m39;
case "M249" : return wStats.m249;
case "HMLMG" : return wStats.hmlmg;
case "SAR" : return wStats.sar;
case "L9" : return wStats.l96;
case "BOLT" : return wStats.bolt;
case "MP5" : return wStats.mp5;
case "THOMPSON" : return wStats.thompson;
case "CUSTOMSMG" : return wStats.custom;
case "PUMP" : return wStats.pump;
case "DOUBLE" : return wStats.doublebarrel;
case "SPAZ12" : return wStats.spaz12;
case "M92" : return wStats.m92;
case "PYTHON" : return wStats.python;
case "SEMIPISTOL" : return wStats.semipistol;
case "REVOLVER" : return wStats.revolver;
case "WATERPIPE" : return wStats.waterpipe;
case "EOKA" : return wStats.eoka;
case "COMPOUND" : return wStats.compound;
case "CROSSBOW" : return wStats.crossbow;
case "BOW" : return wStats.bow;
}
return -1;
}
#endregion
#region Defines
[PluginReference]
private Plugin ImageLibrary;
Dictionary<string, PlayerStats> playerStats = new Dictionary<string, PlayerStats>();
Dictionary<string, PlayerStats> playerStatsOverall = new Dictionary<string, PlayerStats>();
Core.MySql.Libraries.MySql SQL = Interface.Oxide.GetLibrary<Core.MySql.Libraries.MySql>();
Connection connection;
PlayerStats stats;
private const string TableExists = "SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = @0";
BasePlayer HeliAttacker = null;
DamageType[] suicideDamageTypes = {
DamageType.Suicide, DamageType.Radiation, DamageType.RadiationExposure, DamageType.Poison, DamageType.Hunger, DamageType.Thirst, DamageType.Fall, DamageType.Drowned
}
;
#endregion
#region Hooks
void Loaded() {
connection = SQL.OpenDb(config.connectionInfo.sql_host, config.connectionInfo.sql_port, config.connectionInfo.sql_db, config.connectionInfo.sql_user, config.connectionInfo.sql_passwword, this);
connection.Con.Open();
if (connection == null || connection.Con == null) {
Puts(GetLang("NoDatabaseConnection"));
return;
}
}
void Unload() {
connection?.Con?.Dispose();
config = null;
}
void OnNewSave(string filename) {
if (config.developerMode) Puts("Moving wipe table to overall due to new save file.");
var query = Sql.Builder.Append($"CALL `wipeTime`('{config.serverPrefix}')");
SQL.Query(query, connection, created => {
}
);
}
void OnServerSave() {
if (ServerMgr.Instance.Restarting) {
if (config.developerMode) Puts("Ran OnServerSave since server is restarting.");
SaveAllStats();
}
}
void OnServerInitialized(bool initial) {
ServerMgr.Instance.StartCoroutine(Startup());
ImageLibrary?.Call("AddImage", "https://i.imgur.com/BtYyVsQ.png", "PlayerImage");
ImageLibrary?.Call("AddImage", "https://i.imgur.com/hvnWown.png", "GrungeBackground");
ImageLibrary?.Call("AddImage", "https://i.imgur.com/FZHGHUc.png", "ConnectionsIcon");
ImageLibrary?.Call("AddImage", "https://i.imgur.com/DRdUVK6.png", "PlaytimeIcon");
ImageLibrary?.Call("AddImage", "https://i.imgur.com/0Bmhgma.png", "DeathsIcon");
ImageLibrary?.Call("AddImage", "https://i.imgur.com/5Sbd7Ir.png", "KDRIcon");
ImageLibrary?.Call("AddImage", "https://i.imgur.com/85BOzMc.png", "AccuracyIcon");
ImageLibrary?.Call("AddImage", "https://i.imgur.com/ycz4eyv.png", "WoundedIcon");
ImageLibrary?.Call("AddImage", "https://i.imgur.com/ttLSDHS.png", "SuicidesIcon");
ImageLibrary?.Call("AddImage", "https://i.imgur.com/bZA0E92.png", "SatchelsIcon");
ImageLibrary?.Call("AddImage", "https://i.imgur.com/4ix2QDq.png", "C4Icon");
ImageLibrary?.Call("AddImage", "https://i.imgur.com/m0VKILI.png", "RocketsIcon");
ImageLibrary?.Call("AddImage", "https://i.imgur.com/n2b0FlG.png", "TCIcon");
ImageLibrary?.Call("AddImage", "https://i.imgur.com/iXPMAhu.png", "ChickenIcon");
ImageLibrary?.Call("AddImage", "https://i.imgur.com/suelqfc.png", "BoarIcon");
ImageLibrary?.Call("AddImage", "https://i.imgur.com/VIszPrw.png", "DeerIcon");
ImageLibrary?.Call("AddImage", "https://i.imgur.com/nErC1Ht.png", "HorseIcon");
ImageLibrary?.Call("AddImage", "https://i.imgur.com/LGka2Zw.png", "WolveIcon");
ImageLibrary?.Call("AddImage", "https://i.imgur.com/0lYoss1.png", "BearIcon");
ImageLibrary?.Call("AddImage", "https://i.imgur.com/09sY8jQ.png", "ScientistIcon");
ImageLibrary?.Call("AddImage", "https://i.imgur.com/q0KkIgi.png", "HelicopterIcon");
ImageLibrary?.Call("AddImage", "https://i.imgur.com/RwqvbVv.png", "BradleyIcon");
foreach (var weapon in weapons) ImageLibrary?.Call("AddImage", weapon.WeaponIcon, weapon.WeaponName);
if (config.saveInterval != 0) timer.Every(config.saveInterval * 60, () => {
SaveAllStats();
}
);
if (!initial) {
foreach (BasePlayer player in BasePlayer.activePlayerList) if (playerStats.TryGetValue(player.UserIDString, out stats)) stats.connected = DateTime.Now;
}
}
void OnPlayerConnected(BasePlayer player) {
if (connection == null || connection.Con == null) return;
if (playerStats.TryGetValue(player.UserIDString, out stats)) {
stats.connected = DateTime.Now;
stats.connections += 1;
}
Sql query = Sql.Builder.Append($"SELECT steamid FROM {config.serverPrefix}_stats_wipe WHERE steamid = '{player.userID}'");
SQL.Query(query, connection, list => {
if (list.Count == 0) {
Sql insquery = Sql.Builder.Append($"INSERT INTO {config.serverPrefix}_stats_wipe (steamid, name) VALUES ({player.UserIDString}, '{RemoveSpecialCharacters(player.displayName)}')");
SQL.Insert(insquery, connection);
playerStats.Add(player.UserIDString, new PlayerStats {
name = RemoveSpecialCharacters(player.displayName), connections = 1, playtime = 0, kills = 0, deaths = 0, bfired = 0, suicides = 0, wounded = 0, c4thrown = 0, satchelsthrown = 0, rocketsfired = 0, tcsdestroyed = 0, npcStats = new NPCStats {
chickens = 0, boars = 0, deers = 0, horses = 0, wolves = 0, bears = 0, scientists = 0, helicopters = 0, bradleys = 0
}
, weaponStats = new WeaponStats {
ak47 = 0, lr300 = 0, m39 = 0, sar = 0, m249 = 0, hmlmg = 0, l96 = 0, bolt = 0, mp5 = 0, thompson = 0, custom = 0, pump = 0, doublebarrel = 0, spaz12 = 0, m92 = 0, python = 0, semipistol = 0, revolver = 0, waterpipe = 0, eoka = 0, compound = 0, crossbow = 0, bow = 0
}
, hits = new BodyParts {
head = 0, torso = 0, lefthand = 0, righthand = 0, leftleg = 0, rightleg = 0, leftfoot = 0, rightfoot = 0
}
,
}
);
}
}
);
}
void OnPlayerDisconnected(BasePlayer player, string reason) {
if (reason.Equals("Server Restarting", StringComparison.OrdinalIgnoreCase)) return;
SavePlayerStats(player, true);
}
void OnEntityDeath(BasePlayer player, HitInfo info) {
if (!playerStats.TryGetValue(player.UserIDString, out stats)) return;
if (suicideDamageTypes.Contains(player.lastDamage)) stats.suicides++;
else {
if (!(config.excludeNPCDeaths && info?.Initiator is BaseNpc)) stats.deaths++;
}
BasePlayer attacker = info?.InitiatorPlayer;
if (attacker == null || attacker == player || (attacker.currentTeam > 0 && attacker.currentTeam == player.currentTeam) || (config.onlyStashKills && !player.HasPlayerFlag(BasePlayer.PlayerFlags.DisplaySash))) return;
if (!playerStats.TryGetValue(attacker.UserIDString, out stats)) return;
stats.kills++;
Item weaponItem = info.Weapon?.GetItem();
if (weaponItem == null) return;
switch (weaponItem.info.shortname) {
case "rifle.ak" : case "rifle.ak.ice" : stats.weaponStats.ak47++;
break;
case "rifle.lr300" : stats.weaponStats.lr300++;
break;
case "rifle.m39" : stats.weaponStats.m39++;
break;
case "rifle.semiauto" : stats.weaponStats.sar++;
break;
case "lmg.m249" : stats.weaponStats.m249++;
break;
case "hmlmg" : stats.weaponStats.hmlmg++;
break;
case "rifle.l96" : stats.weaponStats.l96++;
break;
case "rifle.bolt" : stats.weaponStats.bolt++;
break;
case "smg.mp5" : stats.weaponStats.mp5++;
break;
case "smg.thompson" : stats.weaponStats.thompson++;
break;
case "smg.2" : stats.weaponStats.custom++;
break;
case "shotgun.double" : stats.weaponStats.doublebarrel++;
break;
case "shotgun.pump" : stats.weaponStats.pump++;
break;
case "shotgun.spas12" : stats.weaponStats.spaz12++;
break;
case "pistol.m92" : stats.weaponStats.m92++;
break;
case "pistol.python" : stats.weaponStats.python++;
break;
case "pistol.semiauto" : stats.weaponStats.semipistol++;
break;
case "pistol.revolver" : stats.weaponStats.revolver++;
break;
case "shotgun.waterpipe" : stats.weaponStats.waterpipe++;
break;
case "pistol.eoka" : stats.weaponStats.eoka++;
break;
case "bow.compound" : stats.weaponStats.compound++;
break;
case "crossbow" : stats.weaponStats.crossbow++;
break;
case "bow.hunting" : stats.weaponStats.bow++;
break;
}
}
void OnEntityDeath(BuildingPrivlidge entity, HitInfo info) {
BasePlayer attacker = info?.InitiatorPlayer;
if (attacker == null) return;
if (playerStats.TryGetValue(attacker.UserIDString, out stats)) stats.tcsdestroyed++;
}
void OnEntityDeath(NPCPlayer scientist, HitInfo info) {
BasePlayer attacker = info?.InitiatorPlayer;
if (attacker == null) return;
if (playerStats.TryGetValue(attacker.UserIDString, out stats)) stats.npcStats.scientists++;
}
void OnEntityDeath(BaseAnimalNPC animal, HitInfo info) {
BasePlayer attacker = info?.InitiatorPlayer;
if (attacker == null) return;
if (playerStats.TryGetValue(attacker.UserIDString, out stats)) {
switch (animal.ShortPrefabName) {
case "chicken" : stats.npcStats.chickens++;
break;
case "boar" : stats.npcStats.boars++;
break;
case "stag" : stats.npcStats.deers++;
break;
case "horse" : stats.npcStats.horses++;
break;
case "wolf" : stats.npcStats.wolves++;
break;
case "bear" : stats.npcStats.bears++;
break;
}
}
}
void OnEntityTakeDamage(BaseHelicopter entity, HitInfo info) {
if (info.Initiator is BasePlayer) HeliAttacker = info?.InitiatorPlayer;
}
void OnEntityDeath(BaseHelicopter heli, HitInfo info) {
if (HeliAttacker == null) return;
if (playerStats.TryGetValue(HeliAttacker.UserIDString, out stats)) stats.npcStats.helicopters++;
HeliAttacker = null;
}
void OnEntityDeath(BradleyAPC bradley, HitInfo info) {
BasePlayer attacker = info?.InitiatorPlayer;
if (attacker == null) return;
if (playerStats.TryGetValue(attacker.UserIDString, out stats)) stats.npcStats.bradleys++;
}
void OnExplosiveThrown(BasePlayer player, BaseEntity entity) {
if (!playerStats.TryGetValue(player.UserIDString, out stats)) return;
switch (player.GetActiveItem()?.info.shortname) {
case "explosive.timed" : stats.c4thrown++;
break;
case "explosive.satchel" : stats.satchelsthrown++;
break;
}
}
void OnRocketLaunched(BasePlayer player, BaseEntity entity) {
if (!playerStats.TryGetValue(player.UserIDString, out stats)) return;
stats.rocketsfired++;
}
object OnPlayerWound(BasePlayer player, HitInfo hitInfo) {
if (playerStats.TryGetValue(player.UserIDString, out stats)) stats.wounded++;
return null;
}
object OnPlayerAttack(BasePlayer attacker, HitInfo info) {
BasePlayer victim = info.HitEntity?.ToPlayer();
if (victim != null) {
if (!playerStats.TryGetValue(attacker.UserIDString, out stats)) return null;
switch (info.boneName.ToLower()) {
case "head" : stats.hits.head++;
break;
case "neck" : case "chest" : case "lowerspine" : stats.hits.torso++;
break;
case "pelvis" : case "hip" : stats.hits.leftleg++;
stats.hits.rightleg++;
break;
case "left knee" : stats.hits.leftleg++;
break;
case "right knee" : stats.hits.rightleg++;
break;
case "left foot" : stats.hits.leftfoot++;
break;
case "right foot" : stats.hits.rightfoot++;
break;
case "left arm" : case "left forearm" : case "left hand" : stats.hits.lefthand++;
break;
case "right arm" : case "right forearm" : case "right hand" : stats.hits.righthand++;
break;
}
}
return null;
}
void OnWeaponFired(BaseProjectile projectile, BasePlayer player, ItemModProjectile mod, ProtoBuf.ProjectileShoot projectiles) {
if (!playerStats.TryGetValue(player.UserIDString, out stats)) return;
stats.bfired++;
}
#endregion
#region Functions
public string RemoveSpecialCharacters(string str) {
return str.Replace("'", "");
}
string CalculateAccuracy(int bulletsFired, BodyParts hits) {
int totalHits = hits.head + hits.torso + hits.lefthand + hits.righthand + hits.leftleg + hits.rightleg + hits.leftfoot + hits.rightfoot;
if (totalHits == 0 || bulletsFired == 0) return "100%";
return $"{Math.Round(((float)totalHits / bulletsFired) * 100, 2)}%";
}
void CreateTable(string tableName) {
Sql query = Sql.Builder.Append(TableExists, tableName);
SQL.Query(query, connection, list => {
if (list.Count == 0) {
var queryNew = Sql.Builder.Append($"CALL `createTable`('{tableName}')");
SQL.Query(queryNew, connection, created => {
}
);
}
}
);
}
void SaveAllStats() {
foreach (BasePlayer player in BasePlayer.activePlayerList) SavePlayerStats(player);
}
void SavePlayerStats(BasePlayer player, bool disconnect = false) {
if (connection == null || connection.Con == null) return;
if (player == null) return;
if (playerStats.TryGetValue(player.UserIDString, out stats)) {
stats.playtime += (int)DateTime.Now.Subtract(stats.connected).TotalMinutes;
stats.connected = DateTime.Now;
var query = Sql.Builder.Append($"UPDATE {config.serverPrefix}_stats_wipe SET name = '{RemoveSpecialCharacters(player.displayName)}', connections = {stats.connections}, playtime = {stats.playtime}, kills = {stats.kills}, deaths = {stats.deaths}, bfired = {stats.bfired}, suicides = {stats.suicides}, wounded = {stats.wounded}, c4thrown = {stats.c4thrown}, satchelsthrown = {stats.satchelsthrown}, rocketsfired = {stats.rocketsfired}, tcsdestroyed = {stats.tcsdestroyed}, chickens = {stats.npcStats.chickens}, boars = {stats.npcStats.boars}, deers = {stats.npcStats.deers}, horses = {stats.npcStats.horses}, wolves = {stats.npcStats.wolves}, bears = {stats.npcStats.bears}, scientists = {stats.npcStats.scientists}, helicopters = {stats.npcStats.helicopters}, bradleys = {stats.npcStats.bradleys}, ak47 = {stats.weaponStats.ak47}, lr300 = {stats.weaponStats.lr300}, m39 = {stats.weaponStats.m39}, sar = {stats.weaponStats.sar}, m249 = {stats.weaponStats.m249}, hmlmg = {stats.weaponStats.hmlmg}, l96 = {stats.weaponStats.l96}, bolt = {stats.weaponStats.bolt}, mp5 = {stats.weaponStats.mp5}, thompson = {stats.weaponStats.thompson}, custom = {stats.weaponStats.custom}, pump = {stats.weaponStats.pump}, doublebarrel = {stats.weaponStats.doublebarrel}, spaz12 = {stats.weaponStats.spaz12}, m92 = {stats.weaponStats.m92}, python = {stats.weaponStats.python}, semipistol = {stats.weaponStats.semipistol}, revolver = {stats.weaponStats.revolver}, waterpipe = {stats.weaponStats.waterpipe}, eoka = {stats.weaponStats.eoka}, compound = {stats.weaponStats.compound}, crossbow = {stats.weaponStats.crossbow}, bow = {stats.weaponStats.bow}, head_hits = {stats.hits.head}, torso_hits = {stats.hits.torso}, leftarm_hits = {stats.hits.lefthand}, rightarm_hits = {stats.hits.righthand}, leftleg_hits = {stats.hits.leftleg}, rightleg_hits = {stats.hits.rightleg}, leftfoot_hits = {stats.hits.leftfoot}, rightfoot_hits = {stats.hits.rightfoot} WHERE steamid = {player.UserIDString}");
SQL.Update(query, connection, output => {
if (player == null) return;
if (config.developerMode) Puts(GetLang("UpdatedPlayerStats", RemoveSpecialCharacters(player.displayName)));
}
);
}
}
IEnumerator Startup() {
CreateTable($"{config.serverPrefix}_stats_wipe");
CreateTable($"{config.serverPrefix}_stats_overall");
yield return CoroutineEx.waitForSeconds(3f);
Sql query = Sql.Builder.Append($"SELECT * FROM {config.serverPrefix}_stats_wipe");
SQL.Query(query, connection, list => {
playerStats.Clear();
foreach (var stats in list) {
if (playerStats.ContainsKey(stats.Values.ElementAt(2).ToString())) continue;
playerStats.Add(stats.Values.ElementAt(2).ToString(), new PlayerStats {
name = stats.Values.ElementAt(1).ToString(), connections = Convert.ToInt32(stats.Values.ElementAt(3)), playtime = Convert.ToInt32(stats.Values.ElementAt(4)), kills = Convert.ToInt32(stats.Values.ElementAt(5)), deaths = Convert.ToInt32(stats.Values.ElementAt(6)), bfired = Convert.ToInt32(stats.Values.ElementAt(7)), suicides = Convert.ToInt32(stats.Values.ElementAt(8)), wounded = Convert.ToInt32(stats.Values.ElementAt(9)), c4thrown = Convert.ToInt32(stats.Values.ElementAt(10)), satchelsthrown = Convert.ToInt32(stats.Values.ElementAt(11)), rocketsfired = Convert.ToInt32(stats.Values.ElementAt(12)), tcsdestroyed = Convert.ToInt32(stats.Values.ElementAt(13)), npcStats = new NPCStats {
chickens = Convert.ToInt32(stats.Values.ElementAt(14)), boars = Convert.ToInt32(stats.Values.ElementAt(15)), deers = Convert.ToInt32(stats.Values.ElementAt(16)), horses = Convert.ToInt32(stats.Values.ElementAt(17)), wolves = Convert.ToInt32(stats.Values.ElementAt(18)), bears = Convert.ToInt32(stats.Values.ElementAt(19)), scientists = Convert.ToInt32(stats.Values.ElementAt(20)), helicopters = Convert.ToInt32(stats.Values.ElementAt(21)), bradleys = Convert.ToInt32(stats.Values.ElementAt(22)),
}
, weaponStats = new WeaponStats {
ak47 = Convert.ToInt32(stats.Values.ElementAt(23)), lr300 = Convert.ToInt32(stats.Values.ElementAt(24)), m39 = Convert.ToInt32(stats.Values.ElementAt(25)), sar = Convert.ToInt32(stats.Values.ElementAt(26)), m249 = Convert.ToInt32(stats.Values.ElementAt(27)), hmlmg = Convert.ToInt32(stats.Values.ElementAt(28)), l96 = Convert.ToInt32(stats.Values.ElementAt(29)), bolt = Convert.ToInt32(stats.Values.ElementAt(30)), mp5 = Convert.ToInt32(stats.Values.ElementAt(31)), thompson = Convert.ToInt32(stats.Values.ElementAt(32)), custom = Convert.ToInt32(stats.Values.ElementAt(33)), pump = Convert.ToInt32(stats.Values.ElementAt(34)), doublebarrel = Convert.ToInt32(stats.Values.ElementAt(35)), spaz12 = Convert.ToInt32(stats.Values.ElementAt(36)), m92 = Convert.ToInt32(stats.Values.ElementAt(37)), python = Convert.ToInt32(stats.Values.ElementAt(38)), semipistol = Convert.ToInt32(stats.Values.ElementAt(39)), revolver = Convert.ToInt32(stats.Values.ElementAt(40)), waterpipe = Convert.ToInt32(stats.Values.ElementAt(41)), eoka = Convert.ToInt32(stats.Values.ElementAt(42)), compound = Convert.ToInt32(stats.Values.ElementAt(43)), crossbow = Convert.ToInt32(stats.Values.ElementAt(44)), bow = Convert.ToInt32(stats.Values.ElementAt(45)),
}
, hits = new BodyParts {
head = Convert.ToInt32(stats.Values.ElementAt(46)), torso = Convert.ToInt32(stats.Values.ElementAt(47)), lefthand = Convert.ToInt32(stats.Values.ElementAt(48)), righthand = Convert.ToInt32(stats.Values.ElementAt(49)), leftleg = Convert.ToInt32(stats.Values.ElementAt(50)), rightleg = Convert.ToInt32(stats.Values.ElementAt(51)), leftfoot = Convert.ToInt32(stats.Values.ElementAt(52)), rightfoot = Convert.ToInt32(stats.Values.ElementAt(53)),
}
,
}
);
}
;
Sql overallquery = Sql.Builder.Append($"SELECT * FROM {config.serverPrefix}_stats_overall");
SQL.Query(overallquery, connection, newlist => {
playerStatsOverall.Clear();
foreach (var stats in newlist) {
if (playerStatsOverall.ContainsKey(stats.Values.ElementAt(2).ToString())) continue;
playerStatsOverall.Add(stats.Values.ElementAt(2).ToString(), new PlayerStats {
name = stats.Values.ElementAt(1).ToString(), connections = Convert.ToInt32(stats.Values.ElementAt(3)), playtime = Convert.ToInt32(stats.Values.ElementAt(4)), kills = Convert.ToInt32(stats.Values.ElementAt(5)), deaths = Convert.ToInt32(stats.Values.ElementAt(6)), bfired = Convert.ToInt32(stats.Values.ElementAt(7)), suicides = Convert.ToInt32(stats.Values.ElementAt(8)), wounded = Convert.ToInt32(stats.Values.ElementAt(9)), c4thrown = Convert.ToInt32(stats.Values.ElementAt(10)), satchelsthrown = Convert.ToInt32(stats.Values.ElementAt(11)), rocketsfired = Convert.ToInt32(stats.Values.ElementAt(12)), tcsdestroyed = Convert.ToInt32(stats.Values.ElementAt(13)), npcStats = new NPCStats {
chickens = Convert.ToInt32(stats.Values.ElementAt(14)), boars = Convert.ToInt32(stats.Values.ElementAt(15)), deers = Convert.ToInt32(stats.Values.ElementAt(16)), horses = Convert.ToInt32(stats.Values.ElementAt(17)), wolves = Convert.ToInt32(stats.Values.ElementAt(18)), bears = Convert.ToInt32(stats.Values.ElementAt(19)), scientists = Convert.ToInt32(stats.Values.ElementAt(20)), helicopters = Convert.ToInt32(stats.Values.ElementAt(21)), bradleys = Convert.ToInt32(stats.Values.ElementAt(22)),
}
, weaponStats = new WeaponStats {
ak47 = Convert.ToInt32(stats.Values.ElementAt(23)), lr300 = Convert.ToInt32(stats.Values.ElementAt(24)), m39 = Convert.ToInt32(stats.Values.ElementAt(25)), sar = Convert.ToInt32(stats.Values.ElementAt(26)), m249 = Convert.ToInt32(stats.Values.ElementAt(27)), hmlmg = Convert.ToInt32(stats.Values.ElementAt(28)), l96 = Convert.ToInt32(stats.Values.ElementAt(29)), bolt = Convert.ToInt32(stats.Values.ElementAt(30)), mp5 = Convert.ToInt32(stats.Values.ElementAt(31)), thompson = Convert.ToInt32(stats.Values.ElementAt(32)), custom = Convert.ToInt32(stats.Values.ElementAt(33)), pump = Convert.ToInt32(stats.Values.ElementAt(34)), doublebarrel = Convert.ToInt32(stats.Values.ElementAt(35)), spaz12 = Convert.ToInt32(stats.Values.ElementAt(36)), m92 = Convert.ToInt32(stats.Values.ElementAt(37)), python = Convert.ToInt32(stats.Values.ElementAt(38)), semipistol = Convert.ToInt32(stats.Values.ElementAt(39)), revolver = Convert.ToInt32(stats.Values.ElementAt(40)), waterpipe = Convert.ToInt32(stats.Values.ElementAt(41)), eoka = Convert.ToInt32(stats.Values.ElementAt(42)), compound = Convert.ToInt32(stats.Values.ElementAt(43)), crossbow = Convert.ToInt32(stats.Values.ElementAt(44)), bow = Convert.ToInt32(stats.Values.ElementAt(45)),
}
, hits = new BodyParts {
head = Convert.ToInt32(stats.Values.ElementAt(46)), torso = Convert.ToInt32(stats.Values.ElementAt(47)), lefthand = Convert.ToInt32(stats.Values.ElementAt(48)), righthand = Convert.ToInt32(stats.Values.ElementAt(49)), leftleg = Convert.ToInt32(stats.Values.ElementAt(50)), rightleg = Convert.ToInt32(stats.Values.ElementAt(51)), leftfoot = Convert.ToInt32(stats.Values.ElementAt(52)), rightfoot = Convert.ToInt32(stats.Values.ElementAt(53)),
}
,
}
);
}
}
);
}
);
yield return null;
}
#endregion
#region Commands
[Command("stats.save")]
private void SaveStatsCMD(IPlayer iPlayer, string command, string[] args) {
if (!iPlayer.IsServer) return;
if (args.Length > 0) {
BasePlayer player = BasePlayer.FindAwakeOrSleeping(args[0]);
if (player == null) return;
SavePlayerStats(player);
}
else SaveAllStats();
}
[Command("stats")]
private void MyStatsCMD(IPlayer iPlayer, string command, string[] args) {
if (iPlayer.IsServer || !config.useIngameUI) return;
BasePlayer player = iPlayer.Object as BasePlayer;
CuiHelper.DestroyUi(player, "BetterStatsContainer");
if (args.Length == 1) BetterStatsContainer(player, args[0]);
else BetterStatsContainer(player, player.UserIDString);
}
[Command("destroyui")]
private void DestroyUICMD(IPlayer iPlayer, string command, string[] args) {
if (iPlayer.IsServer) return;
BasePlayer player = iPlayer.Object as BasePlayer;
CuiHelper.DestroyUi(player, args[0]);
}
#endregion
#region UI
private void BetterStatsContainer(BasePlayer player, string userId, int page = 1, bool wipeTable = true) {
CuiHelper.DestroyUi(player, "BetterStatsContainer");
if (wipeTable) {
if (!playerStats.TryGetValue(userId, out stats)) {
player.ChatMessage(GetLang("PlayerNotFound"));
return;
}
}
else {
if (!playerStatsOverall.TryGetValue(userId, out stats)) {
player.ChatMessage(GetLang("PlayerNotFoundOverall"));
return;
}
}
string playtime = "0";
TimeSpan elapsedTime = new TimeSpan(0, stats.playtime, 0);
int day = elapsedTime.Days;
int hour = elapsedTime.Hours;
int mins = elapsedTime.Minutes;
if (day > 0) playtime = $"{day}d {hour}h {mins}m";
else if (hour > 0) playtime = $"{hour}h {mins}m";
else if (mins > 0) playtime = $"{mins}m";
var container = new CuiElementContainer();
container.Add(new CuiPanel {
CursorEnabled = true, Image = {
Color = "0.1037736 0.101466 0.08762015 1"
}
, RectTransform = {
AnchorMin = "0.5 0.5", AnchorMax = "0.5 0.5", OffsetMin = "-630.789 -359.317", OffsetMax = "640.789 355.983"
}
}
, "Overlay", "BetterStatsContainer");
container.Add(new CuiElement {
Name = "Grunge", Parent = "BetterStatsContainer", Components = {
new CuiRawImageComponent {
Color = "1 1 1 0.08", Png = ImageLibrary?.Call<string>("GetImage", "GrungeBackground"), Sprite = "assets/content/textures/generic/fulltransparent.tga"
}
, new CuiRectTransformComponent {
AnchorMin = "0 0", AnchorMax = "1 1", OffsetMin = "0 0", OffsetMax = "0 0"
}
}
}
);
container.Add(new CuiPanel {
CursorEnabled = false, Image = {
Color = "0.08235294 0.07843138 0.07450981 0.8"
}
, RectTransform = {
AnchorMin = "0.5 1", AnchorMax = "0.5 1", OffsetMin = "-635.797 -69", OffsetMax = "635.802 0"
}
}
, "BetterStatsContainer", "BetterStatsHeader");
container.Add(new CuiElement {
Name = "HeaderTitle", Parent = "BetterStatsHeader", Components = {
new CuiTextComponent {
Text = GetLang("UITitle"), Font = "robotocondensed-bold.ttf", FontSize = 24, Align = TextAnchor.MiddleLeft, Color = "1 1 1 1"
}
, new CuiRectTransformComponent {
AnchorMin = "0 0.5", AnchorMax = "0 0.5", OffsetMin = "32.4 -18.171", OffsetMax = "211.821 18.17"
}
}
}
);
container.Add(new CuiButton {
Button = {
Color = $"{(wipeTable ? "0.2392157 0.2941177 0.1529412 1" : "0.5882353 0.1843137 0.1254902 1")}", Command = $"reloadstats {userId} prev true"
}
, Text = {
Text = GetLang("UIWipeButton"), Font = "robotocondensed-bold.ttf", FontSize = 18, Align = TextAnchor.MiddleCenter, Color = $"{(wipeTable ? "0.6509804 0.8039216 0.3882353 1" : "0.7803922 0.5960785 0.5921569 1")}"
}
, RectTransform = {
AnchorMin = "0.5 0.5", AnchorMax = "0.5 0.5", OffsetMin = "-140.31 -16.657", OffsetMax = "-12.49 16.657"
}
}
, "BetterStatsHeader", "WipeButton");
container.Add(new CuiButton {
Button = {
Color = $"{(!wipeTable ? "0.2392157 0.2941177 0.1529412 1" : "0.5882353 0.1843137 0.1254902 1")}", Command = $"reloadstats {userId} prev false"
}
, Text = {
Text = GetLang("UIOverallButton"), Font = "robotocondensed-bold.ttf", FontSize = 18, Align = TextAnchor.MiddleCenter, Color = $"{(!wipeTable ? "0.6509804 0.8039216 0.3882353 1" : "0.7803922 0.5960785 0.5921569 1")}"
}
, RectTransform = {
AnchorMin = "0.5 0.5", AnchorMax = "0.5 0.5", OffsetMin = "8.89 -16.657", OffsetMax = "136.71 16.657"
}
}
, "BetterStatsHeader", "OverallButton");
container.Add(new CuiButton {
Button = {
Color = "0.5882353 0.1843137 0.1254902 1", Command = "destroyui BetterStatsContainer"
}
, RectTransform = {
AnchorMin = "1 0.5", AnchorMax = "1 0.5", OffsetMin = "-141.221 -13.031", OffsetMax = "-31.979 16.657"
}
}
, "BetterStatsHeader", "CloseButton");
container.Add(new CuiElement {
Name = "CloseText", Parent = "CloseButton", Components = {
new CuiTextComponent {
Text = GetLang("UIExitButton"), Font = "robotocondensed-bold.ttf", FontSize = 18, Align = TextAnchor.MiddleLeft, Color = "0.7803922 0.5960785 0.5921569 1"
}
, new CuiRectTransformComponent {
AnchorMin = "1 0.5", AnchorMax = "1 0.5", OffsetMin = "-63.06 -15", OffsetMax = "0 15"
}
}
}
);
container.Add(new CuiElement {
Name = "Image_9016", Parent = "CloseButton", Components = {
new CuiTextComponent {
Text = "X", Font = "robotocondensed-bold.ttf", FontSize = 13, Align = TextAnchor.MiddleCenter, Color = "0.7803922 0.5960785 0.5921569 1"
}
, new CuiRectTransformComponent {
AnchorMin = "0 0.5", AnchorMax = "0 0.5", OffsetMin = "24.169 -7.365", OffsetMax = "38.9 7.365"
}
}
}
);
container.Add(new CuiPanel {
CursorEnabled = false, Image = {
Color = "0.08235294 0.07843138 0.07450981 0.8078431"
}
, RectTransform = {
AnchorMin = "0.5 0.5", AnchorMax = "0.5 0.5", OffsetMin = "-615.245 -295.746", OffsetMax = "-313.755 271.718"
}
}
, "BetterStatsContainer", "PlayerViewPanel");
container.Add(new CuiPanel {
CursorEnabled = false, Image = {
Color = "0.08235294 0.07843138 0.07450981 1"
}
, RectTransform = {
AnchorMin = "0.5 1", AnchorMax = "0.5 1", OffsetMin = "-150.746 -37", OffsetMax = "150.744 0"
}
}
, "PlayerViewPanel", "PlayerViewHeader");
container.Add(new CuiElement {
Name = "PlayerViewHeaderText", Parent = "PlayerViewHeader", Components = {
new CuiTextComponent {
Text = $"{stats.name}", Font = "robotocondensed-bold.ttf", FontSize = 22, Align = TextAnchor.MiddleLeft, Color = "1 1 1 1"
}
, new CuiRectTransformComponent {
AnchorMin = "0.5 0.5", AnchorMax = "0.5 0.5", OffsetMin = "-139.065 -15.214", OffsetMax = "150.744 15.213"
}
}
}
);
container.Add(new CuiElement {
Name = "PlayerImage", Parent = "PlayerViewPanel", Components = {
new CuiRawImageComponent {
Color = "1 1 1 1", Png = ImageLibrary?.Call<string>("GetImage", "PlayerImage"), Sprite = "assets/content/textures/generic/fulltransparent.tga"
}
, new CuiRectTransformComponent {
AnchorMin = "0.5 0.5", AnchorMax = "0.5 0.5", OffsetMin = "-90.286 -269.7", OffsetMax = "90.284 229.7"
}
}
}
);
container.Add(new CuiPanel {
CursorEnabled = false, Image = {
// ... [Code preview truncated due to length. Full source in attached file] ...