Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of CrewStats v1.1.0
CrewStats.dll
Decompiled 4 hours agousing System; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.IO; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Text; using BepInEx; using BepInEx.Configuration; using HarmonyLib; using UnityEngine; using UnityEngine.Events; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: AssemblyVersion("0.0.0.0")] namespace CrewStats; [BepInPlugin("dukr.crewstats", "CrewStats", "1.1.0")] public class Plugin : BaseUnityPlugin { private class Def { public int id; public string label; public string kind; } private class Tab { public string name; public string page = "rows"; public List<Def> defs = new List<Def>(); } private class BP { public string name; public string nemesis; public bool online; public float bestLife; public int nemesisCount; public Dictionary<int, float[]> v = new Dictionary<int, float[]>(); } private class DeathLine { public long ticks; public string player; public string killer; public int biome; } private class BossLine { public long ticks; public string boss; public string players; } private class AwardRow { public string title; public string winner; public string value; public Color col; } internal static Plugin I; private const string RpcUp = "crew_up"; private const string RpcReq = "crew_req"; private const string RpcBoard = "crew_board"; private const string RpcDeath = "crew_death"; private static readonly CultureInfo Inv = CultureInfo.InvariantCulture; private const int PotionId = 1000; private const int TimeOnlineId = 1100; private static readonly List<Tab> tabs = new List<Tab>(); private static readonly Dictionary<int, Def> byId = new Dictionary<int, Def>(); private static readonly List<int> allIds = new List<int>(); private static readonly List<int> customIds = new List<int>(); private static readonly Dictionary<string, int> resByToken = new Dictionary<string, int>(); private static readonly HashSet<string> bossTokens = new HashSet<string> { "$enemy_eikthyr", "$enemy_gdking", "$enemy_bonemass", "$enemy_dragon", "$enemy_goblinking", "$enemy_seekerqueen", "$enemy_fader", "$enemy_frozenking_p3" }; private static int idKills = -1; private static int idDeaths = -1; private static int idBoss = -1; private static readonly Dictionary<string, int> sid = new Dictionary<string, int>(); private static readonly string[,] Res = new string[24, 4] { { "2001", "$item_copperore", "Copper ore", "ore" }, { "2002", "$item_tinore", "Tin ore", "ore" }, { "2003", "$item_ironore", "Iron ore", "ore" }, { "2004", "$item_ironscrap", "Iron scrap", "ore" }, { "2005", "$item_silverore", "Silver ore", "ore" }, { "2006", "$item_blackmetalscrap", "Black metal scrap", "ore" }, { "2007", "$item_flametalore", "Flametal ore", "ore" }, { "2008", "$item_goldore", "Gold ore", "ore" }, { "2010", "$item_stone", "Stone", "stone" }, { "2011", "$item_flint", "Flint", "stone" }, { "2012", "$item_coal", "Coal", "stone" }, { "2013", "$item_obsidian", "Obsidian", "stone" }, { "2014", "$item_crystal", "Crystal", "stone" }, { "2015", "$item_blackmarble", "Black marble", "stone" }, { "2016", "$item_grausten", "Grausten", "stone" }, { "2017", "$item_sulfurstone", "Sulfur stone", "stone" }, { "2018", "$item_ice", "Ice", "ice" }, { "2020", "$item_wood", "Wood", "wood" }, { "2021", "$item_finewood", "Fine wood", "wood" }, { "2022", "$item_roundlog", "Core wood", "wood" }, { "2023", "$item_elderbark", "Elder bark", "wood" }, { "2024", "$item_yggdrasilwood", "Yggdrasil wood", "wood" }, { "2025", "$item_blackwood", "Ashwood", "wood" }, { "2026", "$item_frostwood", "Timberwood", "wood" } }; private ConfigEntry<KeyboardShortcut> toggleKey; private ConfigEntry<float> reportSeconds; private ConfigEntry<float> windowScale; private ConfigEntry<string> logFile; private string dataDir; private object registeredFor; private readonly Store store = new Store(); private bool dirty; private float saveAt; private float onlineAt; private readonly Dictionary<string, float> deathAt = new Dictionary<string, float>(); private static readonly Dictionary<int, float> pend = new Dictionary<int, float>(); private Dictionary<int, float> lastSent; private Dictionary<string, float> lastSentCre; private bool loginSent; private float spawnT; private float nextReport; private float warnAt; private readonly List<BP> board = new List<BP>(); private readonly Dictionary<int, string> cNames = new Dictionary<int, string>(); private readonly List<DeathLine> deathLines = new List<DeathLine>(); private readonly List<BossLine> bossLines = new List<BossLine>(); private bool boardDirty; private float boardAt; private bool open; private int tab; private int period = 1; private float reqAt; private bool needRender; private GameObject root; private RectTransform panel; private Font font; private readonly Dictionary<string, Sprite> sprites = new Dictionary<string, Sprite>(); private readonly List<GameObject> dyn = new List<GameObject>(); private static readonly string[] Periods = new string[3] { "Today", "Last 7 days", "All time" }; private static readonly uint[] Palette = new uint[12] { 5809919u, 16756060u, 6935196u, 13994726u, 15126370u, 15759496u, 6084053u, 11048959u, 11851371u, 15569340u, 7912913u, 14067320u }; private static readonly Color Parchment = new Color(0.93f, 0.89f, 0.78f, 1f); private static readonly Color Gold = new Color(1f, 0.8f, 0.35f, 1f); private static readonly Color GoldDim = new Color(0.86f, 0.7f, 0.4f, 1f); private static readonly Color Dim = new Color(0.62f, 0.58f, 0.48f, 1f); private GameObject invBtn; private static object locInstance; private static MethodInfo locMethod; private static bool locTried; private static int Stat(string name) { if (!sid.TryGetValue(name, out var value)) { return -1; } return value; } private static void BuildCatalog() { if (tabs.Count > 0) { return; } Tab t = Add("Combat"); D(t, "EnemyKills", "Enemies killed", "n"); D(t, "EnemyKillsLastHits", "Killing blows", "n"); D(t, "BossKills", "Bosses killed", "n"); D(t, "EnemyHits", "Hits dealt", "n"); D(t, "HitsTakenEnemies", "Hits taken", "n"); D(t, "ArrowsShot", "Arrows shot", "n"); D(t, "Deaths", "Deaths", "n"); t = Add("Gathering"); D(t, "Mines", "Rocks mined", "n"); D(t, "MineHits", "Mining hits", "n"); D(t, "TreeChops", "Tree hits", "n"); D(t, "Tree", "Trees felled", "n"); D(t, "Logs", "Logs cut", "n"); D(t, "HarvestCrop", "Crops harvested", "n"); D(t, "HarvestBerry", "Berries picked", "n"); D(t, "HarvestMushroom", "Mushrooms picked", "n"); D(t, "FishCaught", "Fish caught", "n"); t = Add("Ore & more"); for (int i = 0; i < Res.GetLength(0); i++) { int num = int.Parse(Res[i, 0], Inv); Custom(t, num, Res[i, 2], "n"); resByToken[Res[i, 1]] = num; } t = Add("Craft & food"); D(t, "Crafts", "Items crafted", "n"); D(t, "Upgrades", "Items upgraded", "n"); D(t, "CraftFood", "Food cooked", "n"); D(t, "CraftGrill", "Grilled", "n"); D(t, "CraftWeapon", "Weapons crafted", "n"); D(t, "CraftArmor", "Armor crafted", "n"); D(t, "FoodEaten", "Food eaten", "n"); Custom(t, 1000, "Potions drunk", "n"); D(t, "BuiltPieces", "Pieces built", "n"); D(t, "CreatureTamed", "Animals tamed", "n"); t = Add("Travel"); Custom(t, 1100, "Time online", "h"); D(t, "DistanceWalk", "Walked", "km"); D(t, "DistanceRun", "Ran", "km"); D(t, "DistanceSail", "Sailed", "km"); D(t, "DistanceAir", "In the air", "km"); D(t, "PortalsUsed", "Portals used", "n"); D(t, "TimeInBase", "Time in base", "h"); D(t, "TimeOutOfBase", "Time out of base", "h"); D(t, "Sleep", "Nights slept", "n"); D(t, "Jumps", "Jumps", "n"); t = Add("Creatures"); t.page = "creatures"; t = Add("Deaths"); D(t, "Deaths", "All deaths", "n"); D(t, "DeathByEnemyHit", "By enemies", "n"); D(t, "DeathByFall", "Fall", "n"); D(t, "DeathByDrowning", "Drowning", "n"); D(t, "DeathByBurning", "Burning", "n"); D(t, "DeathByFreezing", "Freezing", "n"); D(t, "DeathByPoisoned", "Poison", "n"); D(t, "DeathByAshlandsLava", "Lava", "n"); D(t, "DeathByCinderFire", "Cinder fire", "n"); D(t, "DeathByBoat", "Boat", "n"); D(t, "TombstonesOpenedOwn", "Own tombstones opened", "n"); t = Add("Awards"); t.page = "awards"; foreach (Tab tab in tabs) { foreach (Def def in tab.defs) { if (!allIds.Contains(def.id) && !customIds.Contains(def.id) && def.id < 1000) { allIds.Add(def.id); } } } idKills = Stat("EnemyKills"); idDeaths = Stat("Deaths"); idBoss = Stat("BossKills"); } private static Tab Add(string name) { Tab tab = new Tab(); tab.name = name; tabs.Add(tab); return tab; } private static void D(Tab t, string enumName, string label, string kind) { object obj; try { obj = Enum.Parse(typeof(PlayerStatType), enumName); } catch (Exception) { return; } int num = (int)obj; sid[enumName] = num; if (!byId.TryGetValue(num, out var value)) { value = new Def(); value.id = num; value.label = label; value.kind = kind; byId[num] = value; } t.defs.Add(value); } private static void Custom(Tab t, int id, string label, string kind) { if (!byId.TryGetValue(id, out var value)) { value = new Def(); value.id = id; value.label = label; value.kind = kind; byId[id] = value; } if (!customIds.Contains(id)) { customIds.Add(id); } t.defs.Add(value); } private static bool ClientCustom(int id) { if (id != 1000) { if (id >= 2000 && id < 3000) { return byId.ContainsKey(id); } return false; } return true; } private void Awake() { //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_0073: Expected O, but got Unknown //IL_00a7: Unknown result type (might be due to invalid IL or missing references) //IL_00b1: Expected O, but got Unknown //IL_014b: Unknown result type (might be due to invalid IL or missing references) //IL_0151: Expected O, but got Unknown I = this; BuildCatalog(); toggleKey = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("Window", "Toggle key", new KeyboardShortcut((KeyCode)288, Array.Empty<KeyCode>()), "Opens and closes the crew statistics window. Left/Right arrows change the tab, Up/Down the period."); windowScale = ((BaseUnityPlugin)this).Config.Bind<float>("Window", "Scale", 1f, new ConfigDescription("Size of the window.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.6f, 2f), Array.Empty<object>())); reportSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("Client", "ReportSeconds", 30f, new ConfigDescription("How often your game sends its statistics to the server (only when something changed).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(15f, 600f), Array.Empty<object>())); logFile = ((BaseUnityPlugin)this).Config.Bind<string>("Server", "LogFile", Path.Combine(Paths.BepInExRootPath, "crewstats.log"), "Where the server writes what players gained outside of this server."); dataDir = Path.Combine(Paths.BepInExRootPath, "crewstats-data"); store.KillsId = idKills; store.DeathsId = idDeaths; try { Directory.CreateDirectory(dataDir); store.Load(Path.Combine(dataDir, "stats.tsv")); } catch (Exception) { } Harmony val = new Harmony("dukr.crewstats"); Type[] array = new Type[6] { typeof(RegisterRpc), typeof(ConsumePatch), typeof(CommandPatch), typeof(PickupPatch), typeof(DeathPatch), typeof(LogoutPatch) }; foreach (Type type in array) { try { val.CreateClassProcessor(type).Patch(); } catch (Exception ex2) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("CrewStats patch " + type.Name + " failed: " + ex2.Message)); } } PrepareAll(); ((BaseUnityPlugin)this).Logger.LogInfo((object)"CrewStats 1.1.0 loaded"); } private static void PrepareAll() { try { Type[] types = typeof(Plugin).Assembly.GetTypes(); foreach (Type type in types) { if (type.ContainsGenericParameters) { continue; } MethodInfo[] methods = type.GetMethods(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); foreach (MethodInfo methodInfo in methods) { if (!methodInfo.IsAbstract && !methodInfo.ContainsGenericParameters) { try { RuntimeHelpers.PrepareMethod(methodInfo.MethodHandle); } catch (Exception) { } } } } } catch (Exception) { } } private static string Clean(string s, int max) { if (string.IsNullOrEmpty(s)) { return ""; } StringBuilder stringBuilder = new StringBuilder(); foreach (char c in s) { if (c >= ' ' && c != '\u007f') { stringBuilder.Append(c); if (stringBuilder.Length >= max) { break; } } } return stringBuilder.ToString().Trim(); } private void Log(string text) { try { File.AppendAllText(logFile.Value, DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + " " + text.Replace('\n', ' ') + Environment.NewLine); } catch (Exception) { } } internal void Register() { if (ZRoutedRpc.instance != null && registeredFor != ZRoutedRpc.instance) { registeredFor = ZRoutedRpc.instance; ZRoutedRpc.instance.Register<ZPackage>("crew_up", (Action<long, ZPackage>)OnUp); ZRoutedRpc.instance.Register<ZPackage>("crew_req", (Action<long, ZPackage>)OnReq); ZRoutedRpc.instance.Register<ZPackage>("crew_board", (Action<long, ZPackage>)OnBoard); ZRoutedRpc.instance.Register<ZPackage>("crew_death", (Action<long, ZPackage>)OnDeathRpc); } } private static string PeerName(long sender) { foreach (ZNetPeer peer in ZNet.instance.GetPeers()) { if (peer.m_uid == sender) { return Clean(peer.m_playerName, 48); } } return null; } private void ServerTick(float now) { if (onlineAt <= 0f) { onlineAt = now; } if (now - onlineAt >= 10f) { float num = Mathf.Min(now - onlineAt, 30f); onlineAt = now; DateTime now2 = DateTime.Now; foreach (ZNetPeer peer in ZNet.instance.GetPeers()) { string text = Clean(peer.m_playerName, 48); if (text.Length > 0) { store.AddCustom(text, 1100, num, now2); } } dirty = true; } if (dirty && now >= saveAt) { saveAt = now + 60f; dirty = false; try { store.Save(Path.Combine(dataDir, "stats.tsv"), DateTime.Now); } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("CrewStats save failed: " + ex.Message)); } } } private static float Fin(float v) { if (!float.IsNaN(v) && !float.IsInfinity(v)) { return v; } return 0f; } private void OnUp(long sender, ZPackage pkg) { if ((Object)(object)ZNet.instance == (Object)null || !ZNet.instance.IsServer()) { return; } try { string text = PeerName(sender); if (string.IsNullOrEmpty(text)) { return; } int num = pkg.ReadByte(); if (num != 1 && num != 2) { return; } bool flag = pkg.ReadBool(); int num2 = pkg.ReadInt(); if (num2 < 0 || num2 > 400) { return; } Dictionary<int, float> dictionary = new Dictionary<int, float>(); for (int i = 0; i < num2; i++) { int num3 = pkg.ReadInt(); float value = Fin(pkg.ReadSingle()); if (num3 < 1000 && byId.ContainsKey(num3)) { dictionary[num3] = value; } } Dictionary<int, float> dictionary2 = new Dictionary<int, float>(); int num4 = pkg.ReadInt(); if (num4 < 0 || num4 > 60) { return; } for (int j = 0; j < num4; j++) { int num5 = pkg.ReadInt(); float value2 = Fin(pkg.ReadSingle()); if (ClientCustom(num5)) { dictionary2[num5] = value2; } } if (num >= 2) { int num6 = pkg.ReadInt(); if (num6 < 0 || num6 > 250) { return; } for (int k = 0; k < num6; k++) { string text2 = Clean(pkg.ReadString(), 48); float value3 = Fin(pkg.ReadSingle()); if (text2.Length >= 8 && text2.StartsWith("$enemy_", StringComparison.Ordinal)) { int num7 = Store.CreatureId(text2); store.NoteName(num7, text2); if (store.names.ContainsKey(num7)) { dictionary[num7] = value3; } } } } if (!store.players.ContainsKey(text) && store.players.Count >= 64) { return; } DateTime now = DateTime.Now; Dictionary<int, double> deltas; Dictionary<int, double> dictionary3 = store.Report(text, dictionary, dictionary2, flag, now, out deltas); dirty = true; foreach (KeyValuePair<int, double> item in deltas) { if (Store.IsCreature(item.Key) && store.names.TryGetValue(item.Key, out var value4) && bossTokens.Contains(value4)) { store.AddBoss(value4, text, now); } } if (flag && dictionary3.Count > 0) { List<KeyValuePair<int, double>> list = new List<KeyValuePair<int, double>>(dictionary3); list.RemoveAll((KeyValuePair<int, double> kv) => Store.IsCreature(kv.Key)); list.Sort((KeyValuePair<int, double> a, KeyValuePair<int, double> b) => b.Value.CompareTo(a.Value)); StringBuilder stringBuilder = new StringBuilder("OFFLINE " + text + " changed outside this server:"); for (int num8 = 0; num8 < list.Count && num8 < 14; num8++) { stringBuilder.Append((num8 == 0) ? " " : ", ").Append(byId.TryGetValue(list[num8].Key, out var value5) ? value5.label : list[num8].Key.ToString()).Append(" +") .Append(list[num8].Value.ToString("0.#", Inv)); } if (list.Count > 0) { Log(stringBuilder.ToString()); } } } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("CrewStats report from peer " + sender + ": " + ex.Message)); } } private void OnDeathRpc(long sender, ZPackage pkg) { if ((Object)(object)ZNet.instance == (Object)null || !ZNet.instance.IsServer()) { return; } try { string text = PeerName(sender); if (!string.IsNullOrEmpty(text) && pkg.ReadByte() == 1) { string killer = Clean(pkg.ReadString(), 48); int biome = pkg.ReadInt(); float realtimeSinceStartup = Time.realtimeSinceStartup; if (!deathAt.TryGetValue(text, out var value) || !(realtimeSinceStartup - value < 8f)) { deathAt[text] = realtimeSinceStartup; store.AddDeath(text, killer, biome, DateTime.Now); dirty = true; } } } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("CrewStats death from peer " + sender + ": " + ex.Message)); } } private void OnReq(long sender, ZPackage pkg) { //IL_011b: Unknown result type (might be due to invalid IL or missing references) //IL_0122: Expected O, but got Unknown if ((Object)(object)ZNet.instance == (Object)null || !ZNet.instance.IsServer()) { return; } try { DateTime now = DateTime.Now; HashSet<string> hashSet = new HashSet<string>(); foreach (ZNetPeer peer in ZNet.instance.GetPeers()) { hashSet.Add(Clean(peer.m_playerName, 48)); } List<KeyValuePair<string, PlayerData>> list = new List<KeyValuePair<string, PlayerData>>(store.players); list.RemoveAll((KeyValuePair<string, PlayerData> kv) => !kv.Value.hasBase); list.Sort((KeyValuePair<string, PlayerData> a, KeyValuePair<string, PlayerData> b) => b.Value.lastSeen.CompareTo(a.Value.lastSeen)); if (list.Count > 10) { list.RemoveRange(10, list.Count - 10); } List<int> list2 = new List<int>(allIds); list2.AddRange(customIds); list2.AddRange(store.names.Keys); HashSet<int> hashSet2 = new HashSet<int>(); ZPackage val = new ZPackage(); val.Write((byte)2); val.Write(list.Count); foreach (KeyValuePair<string, PlayerData> item in list) { int count; string text = store.Nemesis(item.Value, out count); val.Write(item.Key); val.Write(hashSet.Contains(item.Key)); val.Write((float)item.Value.bestLife); val.Write(text); val.Write(count); List<int> list3 = new List<int>(); List<float[]> list4 = new List<float[]>(); foreach (int item2 in list2) { float num = (float)store.Value(item.Value, item2, 0, now); float num2 = (float)store.Value(item.Value, item2, 1, now); float num3 = (float)store.Value(item.Value, item2, 2, now); if (num != 0f || num2 != 0f || num3 != 0f) { list3.Add(item2); list4.Add(new float[3] { num, num2, num3 }); if (Store.IsCreature(item2)) { hashSet2.Add(item2); } } } val.Write(list3.Count); for (int num4 = 0; num4 < list3.Count; num4++) { val.Write(list3[num4]); val.Write(list4[num4][0]); val.Write(list4[num4][1]); val.Write(list4[num4][2]); } } val.Write(hashSet2.Count); foreach (int item3 in hashSet2) { val.Write(item3); val.Write(store.names[item3]); } int num5 = Math.Min(12, store.deaths.Count); val.Write(num5); for (int num6 = 0; num6 < num5; num6++) { DeathRec deathRec = store.deaths[num6]; val.Write(deathRec.ticks); val.Write(deathRec.player); val.Write(deathRec.killer); val.Write(deathRec.biome); } int num7 = Math.Min(12, store.bosses.Count); val.Write(num7); for (int num8 = 0; num8 < num7; num8++) { BossRec bossRec = store.bosses[num8]; val.Write(bossRec.ticks); val.Write(bossRec.boss); val.Write(string.Join(", ", bossRec.players.ToArray())); } ZRoutedRpc.instance.InvokeRoutedRPC(sender, "crew_board", new object[1] { val }); } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("CrewStats board: " + ex.Message)); } } internal static void AddPend(int id, float n) { pend.TryGetValue(id, out var value); pend[id] = value + n; } internal static bool ResId(string token, out int id) { return resByToken.TryGetValue(token ?? "", out id); } private void Update() { if ((Object)(object)ZNet.instance == (Object)null || ZRoutedRpc.instance == null) { return; } float realtimeSinceStartup = Time.realtimeSinceStartup; if (ZNet.instance.IsServer()) { try { ServerTick(realtimeSinceStartup); return; } catch (Exception) { return; } } if ((Object)(object)Player.m_localPlayer == (Object)null) { loginSent = false; spawnT = 0f; lastSent = null; lastSentCre = null; HideWindow(); return; } if (spawnT <= 0f) { spawnT = realtimeSinceStartup; } try { WindowTick(realtimeSinceStartup); InventoryButtonTick(); } catch (Exception ex2) { Warn("window: " + ex2.Message); } if (realtimeSinceStartup < nextReport || realtimeSinceStartup - spawnT < 15f) { return; } nextReport = realtimeSinceStartup + Mathf.Max(15f, reportSeconds.Value); try { Report(!loginSent); } catch (Exception ex3) { Warn("report: " + ex3.Message); } } private void Warn(string m) { float realtimeSinceStartup = Time.realtimeSinceStartup; if (!(realtimeSinceStartup < warnAt)) { warnAt = realtimeSinceStartup + 30f; ((BaseUnityPlugin)this).Logger.LogWarning((object)("CrewStats " + m)); } } internal void FlushNow() { try { if ((Object)(object)ZNet.instance != (Object)null && !ZNet.instance.IsServer() && (Object)(object)Player.m_localPlayer != (Object)null && loginSent) { Report(login: false); } } catch (Exception) { } } private void Report(bool login) { //IL_0218: Unknown result type (might be due to invalid IL or missing references) //IL_021f: Expected O, but got Unknown PlayerProfile val = (((Object)(object)Game.instance != (Object)null) ? Game.instance.GetPlayerProfile() : null); if (val == null) { return; } PlayerStats val2 = ((val.m_playerStats != null && val.m_playerStats.Length != 0) ? val.m_playerStats[0] : null); if (val2 == null || val2.m_stats == null) { return; } ZNetPeer serverPeer = ZNet.instance.GetServerPeer(); if (serverPeer == null) { return; } Dictionary<int, float> dictionary = new Dictionary<int, float>(); foreach (int allId in allIds) { if (val2.m_stats.TryGetValue((PlayerStatType)allId, out var value)) { dictionary[allId] = value; } } Dictionary<string, float> dictionary2 = new Dictionary<string, float>(); if (val2.m_enemyStats != null && val2.m_enemyStats.Length != 0 && val2.m_enemyStats[0] != null) { foreach (KeyValuePair<string, float> item in val2.m_enemyStats[0]) { if (item.Key != null && item.Key.StartsWith("$enemy_", StringComparison.Ordinal) && dictionary2.Count < 240) { dictionary2[item.Key] = item.Value; } } } bool flag = login || pend.Count > 0 || lastSent == null || lastSentCre == null; if (!flag) { foreach (KeyValuePair<int, float> item2 in dictionary) { if (!lastSent.TryGetValue(item2.Key, out var value2) || value2 != item2.Value) { flag = true; break; } } } if (!flag) { foreach (KeyValuePair<string, float> item3 in dictionary2) { if (!lastSentCre.TryGetValue(item3.Key, out var value3) || value3 != item3.Value) { flag = true; break; } } } if (!flag) { return; } ZPackage val3 = new ZPackage(); val3.Write((byte)2); val3.Write(login); val3.Write(dictionary.Count); foreach (KeyValuePair<int, float> item4 in dictionary) { val3.Write(item4.Key); val3.Write(item4.Value); } List<KeyValuePair<int, float>> list = new List<KeyValuePair<int, float>>(pend); if (list.Count > 50) { list.RemoveRange(50, list.Count - 50); } val3.Write(list.Count); foreach (KeyValuePair<int, float> item5 in list) { val3.Write(item5.Key); val3.Write(item5.Value); } val3.Write(dictionary2.Count); foreach (KeyValuePair<string, float> item6 in dictionary2) { val3.Write(item6.Key); val3.Write(item6.Value); } ZRoutedRpc.instance.InvokeRoutedRPC(serverPeer.m_uid, "crew_up", new object[1] { val3 }); lastSent = dictionary; lastSentCre = dictionary2; foreach (KeyValuePair<int, float> item7 in list) { float num = pend[item7.Key] - item7.Value; if (num > 0.001f) { pend[item7.Key] = num; } else { pend.Remove(item7.Key); } } loginSent = true; } internal void SendDeath(string killer, int biome) { //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Expected O, but got Unknown try { if (!((Object)(object)ZNet.instance == (Object)null) && !ZNet.instance.IsServer() && ZRoutedRpc.instance != null) { ZNetPeer serverPeer = ZNet.instance.GetServerPeer(); if (serverPeer != null) { ZPackage val = new ZPackage(); val.Write((byte)1); val.Write(Clean(killer, 48)); val.Write(biome); ZRoutedRpc.instance.InvokeRoutedRPC(serverPeer.m_uid, "crew_death", new object[1] { val }); } } } catch (Exception) { } } private bool FromServer(long sender) { try { ZNetPeer val = (((Object)(object)ZNet.instance != (Object)null) ? ZNet.instance.GetServerPeer() : null); if (val != null && val.m_uid == sender) { return true; } } catch (Exception) { } return false; } private void OnBoard(long sender, ZPackage pkg) { if ((Object)(object)ZNet.instance == (Object)null || ZNet.instance.IsServer() || !FromServer(sender)) { return; } try { if (pkg.ReadByte() != 2) { return; } int num = pkg.ReadInt(); if (num < 0 || num > 12) { return; } List<BP> list = new List<BP>(); for (int i = 0; i < num; i++) { BP bP = new BP(); bP.name = Clean(pkg.ReadString(), 48); bP.online = pkg.ReadBool(); bP.bestLife = pkg.ReadSingle(); bP.nemesis = Clean(pkg.ReadString(), 48); bP.nemesisCount = pkg.ReadInt(); int num2 = pkg.ReadInt(); if (num2 < 0 || num2 > 600) { return; } for (int j = 0; j < num2; j++) { int key = pkg.ReadInt(); float num3 = pkg.ReadSingle(); float num4 = pkg.ReadSingle(); float num5 = pkg.ReadSingle(); bP.v[key] = new float[3] { num3, num4, num5 }; } list.Add(bP); } Dictionary<int, string> dictionary = new Dictionary<int, string>(); int num6 = pkg.ReadInt(); if (num6 < 0 || num6 > 700) { return; } for (int k = 0; k < num6; k++) { int key2 = pkg.ReadInt(); dictionary[key2] = Clean(pkg.ReadString(), 48); } List<DeathLine> list2 = new List<DeathLine>(); int num7 = pkg.ReadInt(); if (num7 < 0 || num7 > 20) { return; } for (int l = 0; l < num7; l++) { DeathLine deathLine = new DeathLine(); deathLine.ticks = pkg.ReadLong(); deathLine.player = Clean(pkg.ReadString(), 48); deathLine.killer = Clean(pkg.ReadString(), 48); deathLine.biome = pkg.ReadInt(); list2.Add(deathLine); } List<BossLine> list3 = new List<BossLine>(); int num8 = pkg.ReadInt(); if (num8 < 0 || num8 > 20) { return; } for (int m = 0; m < num8; m++) { BossLine bossLine = new BossLine(); bossLine.ticks = pkg.ReadLong(); bossLine.boss = Clean(pkg.ReadString(), 48); bossLine.players = Clean(pkg.ReadString(), 120); list3.Add(bossLine); } board.Clear(); board.AddRange(list); cNames.Clear(); foreach (KeyValuePair<int, string> item in dictionary) { cNames[item.Key] = item.Value; } deathLines.Clear(); deathLines.AddRange(list2); bossLines.Clear(); bossLines.AddRange(list3); boardDirty = true; boardAt = Time.realtimeSinceStartup; } catch (Exception ex) { Warn("board parse: " + ex.Message); } } private void RequestBoard() { //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Expected O, but got Unknown ZNetPeer val = (((Object)(object)ZNet.instance != (Object)null) ? ZNet.instance.GetServerPeer() : null); if (val != null) { ZPackage val2 = new ZPackage(); val2.Write((byte)1); ZRoutedRpc.instance.InvokeRoutedRPC(val.m_uid, "crew_req", new object[1] { val2 }); } } private static bool UiBlocked() { try { if (Menu.IsVisible() || Minimap.IsOpen() || TextInput.IsVisible()) { return true; } } catch (Exception) { } try { if (Console.IsVisible()) { return true; } } catch (Exception) { } return false; } internal void Toggle() { open = !open; if (open) { RequestBoard(); reqAt = Time.realtimeSinceStartup; needRender = true; } } private void HideWindow() { if ((Object)(object)root != (Object)null && root.activeSelf) { root.SetActive(false); } } private void WindowTick(float now) { //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) bool flag = (Object)(object)Chat.instance != (Object)null && Chat.instance.HasFocus(); KeyboardShortcut value = toggleKey.Value; KeyCode mainKey = ((KeyboardShortcut)(ref value)).MainKey; if ((int)mainKey != 0 && !flag && Input.GetKeyDown(mainKey)) { Toggle(); } if (!open || UiBlocked()) { HideWindow(); return; } if (!flag) { if (Input.GetKeyDown((KeyCode)275)) { tab = (tab + 1) % tabs.Count; needRender = true; } if (Input.GetKeyDown((KeyCode)276)) { tab = (tab + tabs.Count - 1) % tabs.Count; needRender = true; } if (Input.GetKeyDown((KeyCode)273)) { period = (period + 2) % 3; needRender = true; } if (Input.GetKeyDown((KeyCode)274)) { period = (period + 1) % 3; needRender = true; } } if (now - reqAt > 10f) { reqAt = now; RequestBoard(); } if (!((Object)(object)root == (Object)null) || CreateWindow()) { if (!root.activeSelf) { root.SetActive(true); needRender = true; } if (boardDirty || needRender) { boardDirty = false; needRender = false; Render(); } } } private static Font ResolveFont() { Font[] array = Resources.FindObjectsOfTypeAll<Font>(); foreach (Font val in array) { if ((Object)(object)val != (Object)null && ((Object)val).name == "AveriaSerifLibre-Bold") { return val; } } array = Resources.FindObjectsOfTypeAll<Font>(); foreach (Font val2 in array) { if ((Object)(object)val2 != (Object)null && val2.HasCharacter('Č')) { return val2; } } try { Font builtinResource = Resources.GetBuiltinResource<Font>("Arial.ttf"); if ((Object)(object)builtinResource != (Object)null) { return builtinResource; } } catch (Exception) { } try { Font builtinResource2 = Resources.GetBuiltinResource<Font>("LegacyRuntime.ttf"); if ((Object)(object)builtinResource2 != (Object)null) { return builtinResource2; } } catch (Exception) { } return null; } private Sprite FindSprite(string name) { if (sprites.TryGetValue(name, out var value) && (Object)(object)value != (Object)null) { return value; } value = null; try { Sprite[] array = Resources.FindObjectsOfTypeAll<Sprite>(); foreach (Sprite val in array) { if ((Object)(object)val != (Object)null && ((Object)val).name == name) { value = val; break; } } } catch (Exception) { } sprites[name] = value; return value; } private static void SetRect(RectTransform r, float x, float y, float w, float h) { //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Unknown result type (might be due to invalid IL or missing references) r.anchorMin = new Vector2(0f, 1f); r.anchorMax = new Vector2(0f, 1f); r.pivot = new Vector2(0f, 1f); r.anchoredPosition = new Vector2(x, y); r.sizeDelta = new Vector2(w, h); } private Image AddImage(Transform parent, string name, string sprite, Color col, bool sliced, bool fill) { //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0077: Unknown result type (might be due to invalid IL or missing references) GameObject val = new GameObject(name, new Type[2] { typeof(RectTransform), typeof(Image) }); val.transform.SetParent(parent, false); RectTransform val2 = (RectTransform)val.transform; val2.anchorMin = Vector2.zero; val2.anchorMax = Vector2.one; val2.offsetMin = Vector2.zero; val2.offsetMax = Vector2.zero; Image component = val.GetComponent<Image>(); ((Graphic)component).raycastTarget = false; ((Graphic)component).color = col; Sprite val3 = ((sprite != null) ? FindSprite(sprite) : null); if ((Object)(object)val3 != (Object)null) { component.sprite = val3; if (sliced) { component.type = (Type)1; component.pixelsPerUnitMultiplier = 2.5f; } } return component; } private Text AddText(Transform parent, string text, float x, float y, float w, float h, int size, TextAnchor al, FontStyle st, Color col) { //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Expected O, but got Unknown //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Expected O, but got Unknown //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_007a: Unknown result type (might be due to invalid IL or missing references) //IL_00b8: Unknown result type (might be due to invalid IL or missing references) //IL_00cc: Unknown result type (might be due to invalid IL or missing references) GameObject val = new GameObject("T", new Type[2] { typeof(RectTransform), typeof(Text) }); val.transform.SetParent(parent, false); SetRect((RectTransform)val.transform, x, y, w, h); Text component = val.GetComponent<Text>(); component.font = font; component.fontSize = size; component.fontStyle = st; component.alignment = al; ((Graphic)component).color = col; ((Graphic)component).raycastTarget = false; component.text = text; component.horizontalOverflow = (HorizontalWrapMode)1; component.verticalOverflow = (VerticalWrapMode)0; Outline obj = val.AddComponent<Outline>(); ((Shadow)obj).effectColor = new Color(0f, 0f, 0f, 0.8f); ((Shadow)obj).effectDistance = new Vector2(1f, -1f); dyn.Add(val); return component; } private void AddClick(float x, float y, float w, float h, UnityAction act) { //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Expected O, but got Unknown //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Expected O, but got Unknown //IL_007a: Unknown result type (might be due to invalid IL or missing references) GameObject val = new GameObject("Click", new Type[3] { typeof(RectTransform), typeof(Image), typeof(Button) }); val.transform.SetParent((Transform)(object)panel, false); SetRect((RectTransform)val.transform, x, y, w, h); Image component = val.GetComponent<Image>(); ((Graphic)component).color = new Color(1f, 1f, 1f, 0.004f); ((Graphic)component).raycastTarget = true; ((UnityEvent)val.GetComponent<Button>().onClick).AddListener(act); dyn.Add(val); } private void InventoryButtonTick() { //IL_0083: Unknown result type (might be due to invalid IL or missing references) //IL_008d: Expected O, but got Unknown //IL_00aa: Unknown result type (might be due to invalid IL or missing references) //IL_00af: Unknown result type (might be due to invalid IL or missing references) //IL_00b0: Unknown result type (might be due to invalid IL or missing references) //IL_00c2: Unknown result type (might be due to invalid IL or missing references) //IL_00c8: Unknown result type (might be due to invalid IL or missing references) //IL_00ce: Unknown result type (might be due to invalid IL or missing references) //IL_00d9: Unknown result type (might be due to invalid IL or missing references) //IL_00e3: Unknown result type (might be due to invalid IL or missing references) //IL_00ee: Unknown result type (might be due to invalid IL or missing references) //IL_0102: Unknown result type (might be due to invalid IL or missing references) //IL_012c: Unknown result type (might be due to invalid IL or missing references) //IL_0166: Unknown result type (might be due to invalid IL or missing references) //IL_019d: Unknown result type (might be due to invalid IL or missing references) //IL_01f5: Unknown result type (might be due to invalid IL or missing references) //IL_01fa: Unknown result type (might be due to invalid IL or missing references) //IL_0211: Unknown result type (might be due to invalid IL or missing references) //IL_0217: Unknown result type (might be due to invalid IL or missing references) //IL_021c: Unknown result type (might be due to invalid IL or missing references) //IL_021d: Unknown result type (might be due to invalid IL or missing references) //IL_022f: Unknown result type (might be due to invalid IL or missing references) //IL_0235: Unknown result type (might be due to invalid IL or missing references) //IL_023b: Unknown result type (might be due to invalid IL or missing references) //IL_0246: Unknown result type (might be due to invalid IL or missing references) //IL_0250: Unknown result type (might be due to invalid IL or missing references) //IL_0265: Unknown result type (might be due to invalid IL or missing references) //IL_0278: Unknown result type (might be due to invalid IL or missing references) //IL_0288: Unknown result type (might be due to invalid IL or missing references) //IL_02bf: Unknown result type (might be due to invalid IL or missing references) //IL_02c9: Expected O, but got Unknown if ((Object)(object)invBtn != (Object)null) { return; } InventoryGui instance = InventoryGui.instance; if ((Object)(object)instance == (Object)null || !InventoryGui.IsVisible()) { return; } RectTransform player = instance.m_player; if (!((Object)(object)player == (Object)null)) { if ((Object)(object)font == (Object)null) { font = ResolveFont(); } invBtn = new GameObject("CrewStatsButton", new Type[3] { typeof(RectTransform), typeof(Image), typeof(Button) }); invBtn.transform.SetParent((Transform)(object)player, false); RectTransform val = (RectTransform)invBtn.transform; Vector2 val2 = default(Vector2); ((Vector2)(ref val2))..ctor(1f, 0f); val.anchorMax = val2; val.anchorMin = val2; val.pivot = new Vector2(0f, 1f); val.anchoredPosition = new Vector2(8f, -95f); val.sizeDelta = new Vector2(40f, 40f); Image component = invBtn.GetComponent<Image>(); ((Graphic)component).color = new Color(1f, 1f, 1f, 0.004f); ((Graphic)component).raycastTarget = true; AddImage(invBtn.transform, "Fill", "panel_interior_bkg_128", new Color(0.55f, 0.36f, 0.18f, 0.9f), sliced: true, fill: false); AddImage(invBtn.transform, "Border", "panel_border_128", new Color(1f, 1f, 1f, 0.95f), sliced: true, fill: false); float[] array = new float[4] { 10f, 20f, 15f, 26f }; for (int i = 0; i < array.Length; i++) { GameObject val3 = new GameObject("Bar" + i, new Type[2] { typeof(RectTransform), typeof(Image) }); val3.transform.SetParent(invBtn.transform, false); RectTransform val4 = (RectTransform)val3.transform; ((Vector2)(ref val2))..ctor(0f, 0f); val4.anchorMax = val2; val4.anchorMin = val2; val4.pivot = new Vector2(0f, 0f); val4.anchoredPosition = new Vector2(8f + (float)i * 6.5f, 7f); val4.sizeDelta = new Vector2(5f, array[i]); Image component2 = val3.GetComponent<Image>(); ((Graphic)component2).color = Gold; ((Graphic)component2).raycastTarget = false; } ((UnityEvent)invBtn.GetComponent<Button>().onClick).AddListener((UnityAction)delegate { Toggle(); }); } } private bool CreateWindow() { //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Expected O, but got Unknown //IL_00ab: Unknown result type (might be due to invalid IL or missing references) //IL_00d7: Unknown result type (might be due to invalid IL or missing references) //IL_00dd: Expected O, but got Unknown //IL_00fb: Unknown result type (might be due to invalid IL or missing references) //IL_0105: Expected O, but got Unknown //IL_011b: Unknown result type (might be due to invalid IL or missing references) //IL_0120: Unknown result type (might be due to invalid IL or missing references) //IL_0121: Unknown result type (might be due to invalid IL or missing references) //IL_0127: Unknown result type (might be due to invalid IL or missing references) //IL_013d: Unknown result type (might be due to invalid IL or missing references) //IL_014d: Unknown result type (might be due to invalid IL or missing references) try { font = ResolveFont(); if ((Object)(object)font == (Object)null) { return false; } root = new GameObject("CrewStatsWindow", new Type[4] { typeof(RectTransform), typeof(Canvas), typeof(CanvasScaler), typeof(GraphicRaycaster) }); Object.DontDestroyOnLoad((Object)(object)root); Canvas component = root.GetComponent<Canvas>(); component.renderMode = (RenderMode)0; component.sortingOrder = 41; CanvasScaler component2 = root.GetComponent<CanvasScaler>(); component2.uiScaleMode = (ScaleMode)1; component2.referenceResolution = new Vector2(1920f, 1080f); component2.matchWidthOrHeight = 0.5f; GameObject val = new GameObject("Panel", new Type[1] { typeof(RectTransform) }); val.transform.SetParent(root.transform, false); panel = (RectTransform)val.transform; RectTransform obj = panel; Vector2 anchorMin = (panel.anchorMax = new Vector2(0.5f, 0.5f)); obj.anchorMin = anchorMin; panel.pivot = new Vector2(0.5f, 0.5f); panel.anchoredPosition = Vector2.zero; return true; } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("CrewStats window creation failed: " + ex.Message)); if ((Object)(object)root != (Object)null) { Object.Destroy((Object)(object)root); } root = null; return false; } } private static string Fmt(Def d, float v) { if (v <= 0f) { return "-"; } if (d.kind == "km") { return (v / 1000f).ToString("0.0", Inv) + " km"; } if (d.kind == "h") { int num = (int)(v / 60f); return num / 60 + "h " + (num % 60).ToString("00") + "m"; } return ((long)Math.Round(v)).ToString("#,0", Inv).Replace(',', ' '); } private static string FmtN(double v) { return ((long)Math.Round(v)).ToString("#,0", Inv).Replace(',', ' '); } private static string Localize(string token) { try { if (!locTried || locInstance == null) { locTried = true; Type type = AccessTools.TypeByName("Localization"); if (type != null) { FieldInfo fieldInfo = AccessTools.Field(type, "m_instance"); PropertyInfo propertyInfo = AccessTools.Property(type, "instance"); locInstance = ((propertyInfo != null) ? propertyInfo.GetValue(null, null) : ((fieldInfo != null) ? fieldInfo.GetValue(null) : null)); locMethod = AccessTools.Method(type, "Localize", new Type[1] { typeof(string) }, (Type[])null); } } if (locInstance != null && locMethod != null) { string text = locMethod.Invoke(locInstance, new object[1] { token }) as string; if (!string.IsNullOrEmpty(text) && text != token && text.IndexOf('$') < 0) { return text; } } } catch (Exception) { } string text2 = (token.StartsWith("$enemy_", StringComparison.Ordinal) ? token.Substring(7) : token.TrimStart(new char[1] { '$' })); text2 = text2.Replace('_', ' '); if (text2.Length <= 0) { return token; } return char.ToUpperInvariant(text2[0]) + text2.Substring(1); } private static string KillerName(string k) { if (string.IsNullOrEmpty(k)) { return "unknown"; } if (k.StartsWith("player:", StringComparison.Ordinal)) { return k.Substring(7) + " (PvP)"; } if (k.StartsWith("$hit_", StringComparison.Ordinal)) { return Localize("$" + k.Substring(5)).Replace("$", ""); } return Localize(k); } private static string BiomeName(int b) { return b switch { 1 => "Meadows", 2 => "Swamp", 4 => "Mountain", 8 => "Black Forest", 16 => "Plains", 32 => "Ashlands", 64 => "Deep North", 256 => "Ocean", 512 => "Mistlands", _ => "?", }; } private float V(BP p, int id) { if (id < 0 || !p.v.TryGetValue(id, out var value)) { return 0f; } return value[period]; } private float VS(BP p, params int[] ids) { float num = 0f; foreach (int id in ids) { num += V(p, id); } return num; } private static int[] ResIds(string group) { List<int> list = new List<int>(); for (int i = 0; i < Res.GetLength(0); i++) { if (Res[i, 3] == group) { list.Add(int.Parse(Res[i, 0], Inv)); } } return list.ToArray(); } private Color PlayerColor(string name) { //IL_004c: Unknown result type (might be due to invalid IL or missing references) uint num = Palette[(uint)Hash(name) % (uint)Palette.Length]; return new Color((float)((num >> 16) & 0xFF) / 255f, (float)((num >> 8) & 0xFF) / 255f, (float)(num & 0xFF) / 255f, 1f); } private List<AwardRow> BuildAwards() { //IL_028e: Unknown result type (might be due to invalid IL or missing references) //IL_0293: Unknown result type (might be due to invalid IL or missing references) List<AwardRow> list = new List<AwardRow>(); int[] ore = ResIds("ore"); int[] wood = ResIds("wood"); int[] stone = ResIds("stone"); int[] ice = ResIds("ice"); Aw(list, "Slayer - most enemies killed", (BP p) => V(p, idKills), "n"); Aw(list, "Boss hunter - most bosses killed", (BP p) => V(p, idBoss), "n"); Aw(list, "Marksman - most arrows shot", (BP p) => V(p, Stat("ArrowsShot")), "n"); Aw(list, "Punching bag - most hits taken", (BP p) => V(p, Stat("HitsTakenEnemies")), "n"); Aw(list, "Daredevil - most deaths", (BP p) => V(p, idDeaths), "n"); Aw(list, "Miner - most ore picked up", (BP p) => VS(p, ore), "n"); Aw(list, "Lumberjack - most wood picked up", (BP p) => VS(p, wood), "n"); Aw(list, "Mason - most stone picked up", (BP p) => VS(p, stone), "n"); Aw(list, "Iceman - most ice picked up", (BP p) => VS(p, ice), "n"); Aw(list, "Explorer - farthest on foot", (BP p) => VS(p, Stat("DistanceWalk"), Stat("DistanceRun")), "km"); Aw(list, "Sailor - farthest at sea", (BP p) => V(p, Stat("DistanceSail")), "km"); Aw(list, "Chef - most food cooked", (BP p) => VS(p, Stat("CraftFood"), Stat("CraftGrill")), "n"); Aw(list, "Blacksmith - most gear forged", (BP p) => VS(p, Stat("CraftWeapon"), Stat("CraftArmor"), Stat("Upgrades")), "n"); Aw(list, "Farmer - most harvested", (BP p) => VS(p, Stat("HarvestCrop"), Stat("HarvestBerry"), Stat("HarvestMushroom")), "n"); Aw(list, "Angler - most fish caught", (BP p) => V(p, Stat("FishCaught")), "n"); Aw(list, "Homebody - most time in base", (BP p) => V(p, Stat("TimeInBase")), "h"); Aw(list, "Veteran - most time online", (BP p) => V(p, 1100), "h"); AwardRow awardRow = null; float num = 0f; foreach (BP item in board) { if (item.bestLife > num) { num = item.bestLife; awardRow = new AwardRow(); awardRow.winner = item.name; awardRow.col = PlayerColor(item.name); } } if (awardRow != null) { awardRow.title = "Legendary life - most kills without dying (all time)"; awardRow.value = FmtN(num); list.Add(awardRow); } return list; } private void Aw(List<AwardRow> rows, string title, Func<BP, float> f, string kind) { //IL_00a5: Unknown result type (might be due to invalid IL or missing references) //IL_00aa: Unknown result type (might be due to invalid IL or missing references) BP bP = null; float num = 0f; bool flag = false; foreach (BP item in board) { float num2 = f(item); if (num2 > num) { num = num2; bP = item; flag = false; } else if (num2 == num && num2 > 0f) { flag = true; } } if (bP != null && !(num <= 0f)) { AwardRow awardRow = new AwardRow(); awardRow.title = title; awardRow.winner = bP.name + (flag ? " (tie)" : ""); awardRow.col = PlayerColor(bP.name); Def def = new Def(); def.kind = kind; awardRow.value = Fmt(def, num); rows.Add(awardRow); } } private List<Def> CreatureDefs() { Dictionary<int, double> dictionary = new Dictionary<int, double>(); foreach (BP item in board) { foreach (KeyValuePair<int, float[]> item2 in item.v) { if (Store.IsCreature(item2.Key) && item2.Value[period] > 0f) { dictionary.TryGetValue(item2.Key, out var value); dictionary[item2.Key] = value + (double)item2.Value[period]; } } } List<KeyValuePair<int, double>> list = new List<KeyValuePair<int, double>>(dictionary); list.Sort((KeyValuePair<int, double> a, KeyValuePair<int, double> b) => b.Value.CompareTo(a.Value)); List<Def> list2 = new List<Def>(); for (int num = 0; num < list.Count && num < 16; num++) { Def def = new Def(); def.id = list[num].Key; def.kind = "n"; def.label = (cNames.TryGetValue(list[num].Key, out var value2) ? Localize(value2) : "?"); list2.Add(def); } return list2; } private void Render() { //IL_0063: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Expected O, but got Unknown //IL_025a: Unknown result type (might be due to invalid IL or missing references) //IL_026a: Unknown result type (might be due to invalid IL or missing references) //IL_0289: Unknown result type (might be due to invalid IL or missing references) //IL_02b8: Unknown result type (might be due to invalid IL or missing references) //IL_02ea: Unknown result type (might be due to invalid IL or missing references) //IL_02fb: Unknown result type (might be due to invalid IL or missing references) //IL_031c: Expected O, but got Unknown //IL_0341: Unknown result type (might be due to invalid IL or missing references) //IL_0372: Unknown result type (might be due to invalid IL or missing references) //IL_03ea: Unknown result type (might be due to invalid IL or missing references) //IL_03e3: Unknown result type (might be due to invalid IL or missing references) //IL_04ab: Unknown result type (might be due to invalid IL or missing references) //IL_04a4: Unknown result type (might be due to invalid IL or missing references) //IL_0645: Unknown result type (might be due to invalid IL or missing references) //IL_0415: Unknown result type (might be due to invalid IL or missing references) //IL_041f: Expected O, but got Unknown //IL_04d6: Unknown result type (might be due to invalid IL or missing references) //IL_04e0: Expected O, but got Unknown //IL_06b4: Unknown result type (might be due to invalid IL or missing references) //IL_06c5: Unknown result type (might be due to invalid IL or missing references) //IL_06e6: Expected O, but got Unknown //IL_0684: Unknown result type (might be due to invalid IL or missing references) //IL_071f: Unknown result type (might be due to invalid IL or missing references) //IL_056f: Unknown result type (might be due to invalid IL or missing references) //IL_05a4: Unknown result type (might be due to invalid IL or missing references) //IL_05b5: Unknown result type (might be due to invalid IL or missing references) //IL_05e9: Expected O, but got Unknown //IL_0b4c: Unknown result type (might be due to invalid IL or missing references) //IL_0882: Unknown result type (might be due to invalid IL or missing references) //IL_0bf5: Unknown result type (might be due to invalid IL or missing references) //IL_0ba3: Unknown result type (might be due to invalid IL or missing references) //IL_0bb4: Unknown result type (might be due to invalid IL or missing references) //IL_0bd2: Expected O, but got Unknown //IL_0f66: Unknown result type (might be due to invalid IL or missing references) //IL_0f6b: Unknown result type (might be due to invalid IL or missing references) //IL_0f6f: Unknown result type (might be due to invalid IL or missing references) //IL_0f74: Unknown result type (might be due to invalid IL or missing references) //IL_0fac: Unknown result type (might be due to invalid IL or missing references) //IL_0df8: Unknown result type (might be due to invalid IL or missing references) //IL_07b9: Unknown result type (might be due to invalid IL or missing references) //IL_07fb: Unknown result type (might be due to invalid IL or missing references) //IL_082c: Unknown result type (might be due to invalid IL or missing references) //IL_0764: Unknown result type (might be due to invalid IL or missing references) //IL_0775: Unknown result type (might be due to invalid IL or missing references) //IL_0793: Expected O, but got Unknown //IL_08c8: Unknown result type (might be due to invalid IL or missing references) //IL_0e3e: Unknown result type (might be due to invalid IL or missing references) //IL_09d6: Unknown result type (might be due to invalid IL or missing references) //IL_092f: Unknown result type (might be due to invalid IL or missing references) //IL_0976: Unknown result type (might be due to invalid IL or missing references) //IL_0e9b: Unknown result type (might be due to invalid IL or missing references) //IL_0ed1: Unknown result type (might be due to invalid IL or missing references) //IL_0f22: Unknown result type (might be due to invalid IL or missing references) //IL_0a4f: Unknown result type (might be due to invalid IL or missing references) //IL_0a9b: Unknown result type (might be due to invalid IL or missing references) //IL_0af7: Unknown result type (might be due to invalid IL or missing references) //IL_0ccd: Unknown result type (might be due to invalid IL or missing references) //IL_0cd2: Unknown result type (might be due to invalid IL or missing references) //IL_0ced: Unknown result type (might be due to invalid IL or missing references) //IL_0cfb: Unknown result type (might be due to invalid IL or missing references) //IL_0d2a: Expected O, but got Unknown //IL_0d75: Unknown result type (might be due to invalid IL or missing references) //IL_0d6e: Unknown result type (might be due to invalid IL or missing references) foreach (GameObject item in dyn) { if ((Object)(object)item != (Object)null) { Object.Destroy((Object)(object)item); } } dyn.Clear(); foreach (Transform item2 in (Transform)panel) { Transform val = item2; if ((Object)(object)val != (Object)null) { Object.Destroy((Object)(object)((Component)val).gameObject); } } Tab tab = tabs[this.tab]; int num = Math.Max(1, board.Count); List<Def> list = ((tab.page == "creatures") ? CreatureDefs() : tab.defs); List<AwardRow> list2 = ((tab.page == "awards") ? BuildAwards() : null); bool flag = tab.name == "Deaths"; int num2 = 0; if (list2 != null) { num2 = 2 + Math.Min(bossLines.Count, 6) + ((bossLines.Count == 0) ? 1 : 0) + 2 + Math.Min(NemesisCount(), 5) + ((NemesisCount() == 0) ? 1 : 0); } else if (flag) { num2 = 2 + Math.Min(deathLines.Count, 6) + ((deathLines.Count == 0) ? 1 : 0); } int num3 = ((list2 != null) ? (list2.Count + ((list2.Count == 0) ? 1 : 0)) : Math.Max(1, list.Count)); float num4 = 14f; foreach (Tab tab2 in tabs) { num4 += 22f + (float)tab2.name.Length * 9f + 6f; } float num5 = Mathf.Max(190f + 96f * (float)num + 36f, Mathf.Max(num4 + 14f, (list2 != null) ? 640f : 0f)); float num6 = 92f + 24f * (float)(num3 + 1 + num2) + 34f; panel.sizeDelta = new Vector2(num5, num6); ((Transform)panel).localScale = Vector3.one * Mathf.Clamp(windowScale.Value, 0.6f, 2f); AddImage((Transform)(object)panel, "Interior", "panel_interior_bkg_128", new Color(1f, 1f, 1f, 0.92f), sliced: true, fill: false); SetRect((RectTransform)((Component)AddImage((Transform)(object)panel, "Band", "panel_interior_bkg_128", new Color(0.55f, 0.36f, 0.18f, 0.55f), sliced: true, fill: false)).transform, 4f, -4f, num5 - 8f, 34f); AddImage((Transform)(object)panel, "Border", "panel_border_128", new Color(1f, 1f, 1f, 0.95f), sliced: true, fill: false); AddText((Transform)(object)panel, "Crew stats", 14f, -4f, 220f, 34f, 20, (TextAnchor)3, (FontStyle)1, Gold); float num7 = num5 - 14f; for (int num8 = 2; num8 >= 0; num8--) { float num9 = ((num8 == 1) ? 108f : 78f); num7 -= num9; AddText((Transform)(object)panel, Periods[num8], num7, -4f, num9, 34f, 14, (TextAnchor)4, (FontStyle)1, (num8 == period) ? Gold : Dim); int pi = num8; AddClick(num7, -4f, num9, 34f, (UnityAction)delegate { period = pi; needRender = true; }); } float num10 = 14f; for (int num11 = 0; num11 < tabs.Count; num11++) { float num12 = 22f + (float)tabs[num11].name.Length * 9f; AddText((Transform)(object)panel, tabs[num11].name, num10, -44f, num12, 24f, 15, (TextAnchor)4, (FontStyle)1, (num11 == this.tab) ? Gold : Dim); int ti = num11; AddClick(num10, -44f, num12, 24f, (UnityAction)delegate { this.tab = ti; needRender = true; }); num10 += num12 + 6f; } if (list2 == null) { for (int num13 = 0; num13 < board.Count; num13++) { BP bP = board[num13]; AddText((Transform)(object)panel, bP.name, 208f + (float)num13 * 96f, -66f, 96f - (bP.online ? 12f : 0f), 24f, 13, (TextAnchor)5, (FontStyle)1, PlayerColor(bP.name)); if (bP.online) { SetRect((RectTransform)((Component)AddImage((Transform)(object)panel, "On", null, new Color(0.45f, 0.85f, 0.45f, 1f), sliced: false, fill: true)).transform, 208f + (float)num13 * 96f + 96f - 9f, -73f, 7f, 7f); } } } else { AddText((Transform)(object)panel, "Who leads in " + Periods[period].ToLowerInvariant() + " (counted on this server only)", 18f, -66f, num5 - 36f, 24f, 13, (TextAnchor)3, (FontStyle)0, Dim); } if (board.Count == 0) { AddText((Transform)(object)panel, "No data yet. Statistics arrive when players play with CrewStats.", 18f, -66f, num5 - 36f, 24f, 13, (TextAnchor)3, (FontStyle)0, Dim); } SetRect((RectTransform)((Component)AddImage((Transform)(object)panel, "Sep", "panel_separator", new Color(1f, 1f, 1f, 0.7f), sliced: false, fill: false)).transform, 12f, -90f, num5 - 24f, 4f); float num14 = -96f; if (list2 != null) { if (list2.Count == 0) { AddText((Transform)(object)panel, "Nothing to award yet.", 18f, num14, num5 - 36f, 24f, 14, (TextAnchor)3, (FontStyle)0, Dim); } int num15 = 0; while (num15 < list2.Count) { AwardRow awardRow = list2[num15]; if (num15 % 2 == 1) { SetRect((RectTransform)((Component)AddImage((Transform)(object)panel, "Row", null, new Color(1f, 0.95f, 0.8f, 0.05f), sliced: false, fill: true)).transform, 10f, num14, num5 - 20f, 24f); } AddText((Transform)(object)panel, awardRow.title, 18f, num14, num5 * 0.55f, 24f, 14, (TextAnchor)3, (FontStyle)0, Parchment); AddText((Transform)(object)panel, awardRow.winner, num5 * 0.55f + 10f, num14, num5 * 0.45f - 90f, 24f, 14, (TextAnchor)3, (FontStyle)1, awardRow.col); AddText((Transform)(object)panel, awardRow.value, num5 - 94f, num14, 80f, 24f, 14, (TextAnchor)5, (FontStyle)1, Gold); num15++; num14 -= 24f; } num14 -= 12f; AddText((Transform)(object)panel, "Boss chronicle", 18f, num14, num5 - 36f, 24f, 15, (TextAnchor)3, (FontStyle)1, Gold); num14 -= 24f; if (bossLines.Count == 0) { AddText((Transform)(object)panel, "No boss killed with CrewStats yet.", 18f, num14, num5 - 36f, 24f, 13, (TextAnchor)3, (FontStyle)0, Dim); num14 -= 24f; } int num16 = 0; while (num16 < bossLines.Count && num16 < 6) { BossLine bossLine = bossLines[num16]; DateTime dateTime = new DateTime(bossLine.ticks); AddText((Transform)(object)panel, dateTime.ToString("dd.MM. HH:mm", Inv), 18f, num14, 110f, 24f, 13, (TextAnchor)3, (FontStyle)0, Dim); AddText((Transform)(object)panel, Localize(bossLine.boss) + " - " + bossLine.players, 130f, num14, num5 - 150f, 24f, 13, (TextAnchor)3, (FontStyle)0, Parchment); num16++; num14 -= 24f; } num14 -= 12f; AddText((Transform)(object)panel, "Nemesis (what killed each player most)", 18f, num14, num5 - 36f, 24f, 15, (TextAnchor)3, (FontStyle)1, Gold); num14 -= 24f; int num17 = 0; foreach (BP item3 in board) { if (item3.nemesisCount > 0 && num17 < 5) { num17++; AddText((Transform)(object)panel, item3.name, 18f, num14, 160f, 24f, 13, (TextAnchor)3, (FontStyle)1, PlayerColor(item3.name)); AddText((Transform)(object)panel, KillerName(item3.nemesis) + " x" + item3.nemesisCount, 180f, num14, num5 - 200f, 24f, 13, (TextAnchor)3, (FontStyle)0, Parchment); num14 -= 24f; } } if (num17 == 0) { AddText((Transform)(object)panel, "No deaths recorded yet.", 18f, num14, num5 - 36f, 24f, 13, (TextAnchor)3, (FontStyle)0, Dim); } } else { if (list.Count == 0) { AddText((Transform)(object)panel, (tab.page == "creatures") ? "No kills counted yet." : "-", 18f, num14, num5 - 36f, 24f, 14, (TextAnchor)3, (FontStyle)0, Dim); } for (int num18 = 0; num18 < list.Count; num18++) { Def def = list[num18]; float num19 = 0f - (96f + (float)num18 * 24f); if (num18 % 2 == 1) { SetRect((RectTransform)((Component)AddImage((Transform)(object)panel, "Row", null, new Color(1f, 0.95f, 0.8f, 0.05f), sliced: false, fill: true)).transform, 10f, num19, num5 - 20f, 24f); } AddText((Transform)(object)panel, def.label, 18f, num19, 190f, 24f, 14, (TextAnchor)3, (FontStyle)0, Parchment); float num20 = 0f; for (int num21 = 0; num21 < board.Count; num21++) { if (board[num21].v.TryGetValue(def.id, out var value) && value[period] > num20) { num20 = value[period]; } } for (int num22 = 0; num22 < board.Count; num22++) { float[] value2; float num23 = (board[num22].v.TryGetValue(def.id, out value2) ? value2[period] : 0f); float num24 = 208f + (float)num22 * 96f; if (num23 > 0f && num20 > 0f) { Color col = PlayerColor(board[num22].name); col.a = 0.28f; SetRect((RectTransform)((Component)AddImage((Transform)(object)panel, "Bar", null, col, sliced: false, fill: true)).transform, num24 + 2f, num19 - 2f, 88f * Mathf.Clamp01(num23 / num20), 20f); } bool flag2 = num23 > 0f && num23 >= num20; AddText((Transform)(object)panel, Fmt(def, num23), num24, num19, 92f, 24f, 14, (TextAnchor)5, (FontStyle)(flag2 ? 1 : 0), flag2 ? Gold : Parchment); } } num14 = 0f - (96f + (float)Math.Max(1, list.Count) * 24f) - 12f; if (flag) { AddText((Transform)(object)panel, "Latest deaths", 18f, num14, num5 - 36f, 24f, 15, (TextAnchor)3, (FontStyle)1, Gold); num14 -= 24f; if (deathLines.Count == 0) { AddText((Transform)(object)panel, "No deaths recorded yet.", 18f, num14, num5 - 36f, 24f, 13, (TextAnchor)3, (FontStyle)0, Dim); } int num25 = 0; while (num25 < deathLines.Count && num25 < 6) { DeathLine deathLine = deathLines[num25]; DateTime dateTime2 = new DateTime(deathLine.ticks); AddText((Transform)(object)panel, dateTime2.ToString("dd.MM. HH:mm", Inv), 18f, num14, 110f, 24f, 13, (TextAnchor)3, (FontStyle)0, Dim); AddText((Transform)(object)panel, deathLine.player, 130f, num14, 130f, 24f, 13, (TextAnchor)3, (FontStyle)1, PlayerColor(deathLine.player)); AddText((Transform)(object)panel, KillerName(deathLine.killer) + " (" + BiomeName(deathLine.biome) + ")", 262f, num14, num5 - 280f, 24f, 13, (TextAnchor)3, (FontStyle)0, Parchment); num25++; num14 -= 24f; } } } RectTransform parent = panel; KeyboardShortcut value3 = toggleKey.Value; AddText((Transform)(object)parent, "Left/Right arrows or click: tab Up/Down arrows or click: period " + ((object)((KeyboardShortcut)(ref value3)).MainKey/*cast due to .constrained prefix*/).ToString() + ": close (counted on this server only)", 14f, 0f - (num6 - 28f), num5 - 28f, 24f, 12, (TextAnchor)3, (FontStyle)0, Dim); } private int NemesisCount() { int num = 0; foreach (BP item in board) { if (item.nemesisCount > 0) { num++; } } return num; } private static int Hash(string s) { uint num = 2166136261u; foreach (char c in s) { num = (num ^ c) * 16777619; } return (int)(num & 0x7FFFFFFF); } } [HarmonyPatch(typeof(ZNet), "OnNewConnection")] internal static class RegisterRpc { private static void Postfix() { try { if ((Object)(object)Plugin.I != (Object)null) { Plugin.I.Register(); } } catch (Exception) { } } } [HarmonyPatch(typeof(Player), "ConsumeItem")] internal static class ConsumePatch { private static void Postfix(Player __instance, ItemData item, bool __result) { //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Invalid comparison between Unknown and I4 try { if (__result && !((Object)(object)__instance != (Object)(object)Player.m_localPlayer) && item != null && item.m_shared != null) { SharedData shared = item.m_shared; if ((int)shared.m_itemType == 2 && shared.m_food <= 0f && shared.m_foodStamina <= 0f && shared.m_foodEitr <= 0f && (Object)(object)shared.m_consumeStatusEffect != (Object)null) { Plugin.AddPend(1000, 1f); } } } catch (Exception) { } } } internal class PickState { public int id; public int stack; public ItemDrop drop; } [HarmonyPatch(typeof(Humanoid), "Pickup", new Type[] { typeof(GameObject), typeof(bool), typeof(bool) })] internal static class PickupPatch { private static void Prefix(Humanoid __instance, GameObject __0, ref PickState __state) { __state = null; try { if (!((Object)(object)__0 == (Object)null) && !((Object)(object)__instance == (Object)null) && !((Object)(object)__instance != (Object)(object)Player.m_localPlayer)) { ItemDrop component = __0.GetComponent<ItemDrop>(); if (!((Object)(object)component == (Object)null) && component.m_itemData != null && component.m_itemData.m_shared != null && !component.m_itemData.m_pickedUp && Plugin.ResId(component.m_itemData.m_shared.m_name, out var id)) { PickState pickState = new PickState(); pickState.id = id; pickState.stack = component.m_itemData.m_stack; pickState.drop = component; __state = pickState; } } } catch (Exception) { } } private static void Postfix(bool __result, PickState __state) { try { if (__state != null) { int num = (__result ? __state.stack : (((Object)(object)__state.drop != (Object)null && __state.drop.m_itemData != null) ? (__state.stack - __state.drop.m_itemData.m_stack) : 0)); if (num > 0 && num <= 1000) { Plugin.AddPend(__state.id, num); } } } catch (Exception) { } } } [HarmonyPatch(typeof(Player), "OnDeath")] internal static class DeathPatch { private static readonly FieldInfo lastHit = AccessTools.Field(typeof(Character), "m_lastHit"); private static void Postfix(Player __instance) { //IL_00b4: Unknown result type (might be due to invalid IL or missing references) //IL_00b9: Unknown result type (might be due to invalid IL or missing references) //IL_00bf: Expected I4, but got Unknown //IL_0067: Unknown result type (might be due to invalid IL or missing references) try { if (!((Object)(object)__instance == (Object)null) && !((Object)(object)__instance != (Object)(object)Player.m_localPlayer) && !((Object)(object)Plugin.I == (Object)null)) { string killer = ""; HitData val = (HitData)((lastHit != null) ? /*isinst with value type is only supported in some contexts*/: null); if (val != null) { Character attacker = val.GetAttacker(); killer = ((attacker is Player) ? ("player:" + ((Player)attacker).GetPlayerName()) : ((!((Object)(object)attacker != (Object)null)) ? ("$hit_" + ((object)Unsafe.As<HitType, HitType>(ref val.m_hitType)/*cast due to .constrained prefix*/).ToString().ToLowerInvariant()) : attacker.m_name)); } int biome = 0; try { biome = (int)Heightmap.FindBiome(((Component)__instance).transform.position); } catch (Exception) { } Plugin.I.SendDeath(killer, biome); } } catch (Exception) { } } } [HarmonyPatch(typeof(Game), "Logout")] internal static class LogoutPatch { private static void Prefix() { try { if ((Object)(object)Plugin.I != (Object)null) { Plugin.I.FlushNow(); } } catch (Exception) { } } } [HarmonyPatch(typeof(Terminal), "InitTerminal")] internal static class CommandPatch { [Serializable] [CompilerGenerated] private sealed class <>c { public static readonly <>c <>9 = new <>c(); public static ConsoleEvent <>9__1_0; internal void <Postfix>b__1_0(ConsoleEventArgs args) { if ((Object)(object)Plugin.I != (Object)null) { Plugin.I.Toggle(); } } } private static bool done; private static void Postfix() { //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Expected O, but got Unknown try { if (done) { return; } done = true; object obj = <>c.<>9__1_0; if (obj == null) { ConsoleEvent val = delegate { if ((Object)(object)Plugin.I != (Object)null) { Plugin.I.Toggle(); } }; <>c.<>9__1_0 = val; obj = (object)val; } new ConsoleCommand("crew", "CrewStats: opens or closes the crew statistics window", (ConsoleEvent)obj, false, false, false, false, false, false, (ConsoleOptionsFetcher)null, false, false, false); } catch (Exception) { } } } internal class PlayerData { public Dictionary<int, float> last = new Dictionary<int, float>(); public Dictionary<int, double> total = new Dictionary<int, double>(); public Dictionary<string, Dictionary<int, double>> daily = new Dictionary<string, Dictionary<int, double>>(); public Dictionary<int, double> offline = new Dictionary<int, double>(); public Dictionary<string, int> killers = new Dictionary<string, int>(); public bool hasBase; public DateTime lastSeen; public double lifeKills; public double bestLife; } internal class DeathRec { public long ticks; public string player; public string killer; public int biome; } internal class BossRec { public long ticks; public string boss; public List<string> players = new List<string>(); } internal class Store { public readonly Dictionary<string, PlayerData> players = new Dictionary<string, PlayerData>(); public readonly Dictionary<int, string> names = new Dictionary<int, string>(); public readonly List<DeathRec> deaths = new List<DeathRec>(); public readonly List<BossRec> bosses = new List<BossRec>(); public const double MaxDelta = 1000000.0; public const int KeepDays = 60; public const int MaxNames = 600; public const int MaxDeaths = 40; public const int MaxBosses = 30; public const int CreatureBase = 536870912; public static readonly TimeSpan ContinueWindow = TimeSpan.FromMinutes(3.0); public int KillsId = -1; public int DeathsId = -1; private static readonly CultureInfo Inv = CultureInfo.InvariantCulture; public static string Day(DateTime t) { return t.ToString("yyyy-MM-dd", Inv); } public static bool IsCreature(int id) { return (id & 0x70000000) == 536870912; } public static int CreatureId(string token) { uint num = 2166136261u; string text = token ?? ""; foreach (char c in text) { num = (num ^ c) * 16777619; } return (int)(0x20000000 | (num & 0xFFFFFFF)); } public PlayerData Get(string name) { if (!players.TryGetValue(name, out var value)) { value = new PlayerData(); players[name] = value; } return value; } public void NoteName(int id, string token) { if (names.Count < 600 && !names.ContainsKey(id) && !string.IsNullOrEmpty(token)) { names[id] = Clean(token); } } private void Add(PlayerData p, int id, double d, DateTime now) { p.total.TryGetValue(id, out var value); p.total[id] = value + d; string key = Day(now); if (!p.daily.TryGetValue(key, out var value2)) { value2 = new Dictionary<int, double>(); p.daily[key] = value2; } value2.TryGetValue(id, out var value3); value2[id] = value3 + d; } public void AddCustom(string name, int id, double d, DateTime now) { if (players.TryGetValue(name, out var value) && value.hasBase && !(d <= 0.0) && !(d > 1000000.0)) { Add(value, id, d, now); } } public Dictionary<int, double> Report(string name, Dictionary<int, float> abs, Dictionary<int, float> adds, bool login, DateTime now) { Dictionary<int, double> deltas; return Report(name, abs, adds, login, now, out deltas); } public Dictionary<int, double> Report(string name, Dictionary<int, float> abs, Dictionary<int, float> adds, bool login, DateTime now, out Dictionary<int, double> deltas) { PlayerData playerData = Get(name); DateTime lastSeen = playerData.lastSeen; playerData.lastSeen = now; Dictionary<int, double> dictionary = new Dictionary<int, double>(); deltas = new Dictionary<int, double>(); bool flag = login && playerData.hasBase && now - lastSeen >= ContinueWindow; if (!playerData.hasBase) { foreach (KeyValuePair<int, float> ab in abs) { playerData.last[ab.Key] = ab.Value; } playerData.hasBase = true; } else if (flag) { foreach (KeyValuePair<int, float> ab2 in abs) { float value; bool flag2 = playerData.last.TryGetValue(ab2.Key, out value); if (!flag2 && IsCreature(ab2.Key)) { flag2 = true; value = 0f; } double num = ab2.Value - value; if (flag2 && num > 0.0) { dictionary[ab2.Key] = num; playerData.offline.TryGetValue(ab2.Key, out var value2); playerData.offline[ab2.Key] = value2 + num; } playerData.last[ab2.Key] = ab2.Value; } } else { foreach (KeyValuePair<int, float> ab3 in abs) { float value3; bool flag3 = playerData.last.TryGetValue(ab3.Key, out value3); if (!flag3 && IsCreature(ab3.Key)) { flag3 = true; value3 = 0f; } double num2 = ab3.Value - value3; if (flag3 && num2 > 0.0 && num2 <= 1000000.0) { Add(playerData, ab3.Key, num2, now); deltas[ab3.Key] = num2; } playerData.last[ab3.Key] = ab3.Value; } if (KillsId >= 0 && deltas.TryGetValue(KillsId, out var value4)) { playerData.lifeKills += value4; } if (playerData.lifeKills > playerData.bestLife) { playerData.bestLife = playerData.lifeKills; } if (DeathsId >= 0 && deltas.TryGetValue(DeathsId, out var value5) && value5 > 0.0) { playerData.lifeKills = 0.0; } } if (adds != null) { foreach (KeyValuePair<int, float> add in adds) { if (add.Value > 0f && (double)add.Value <= 1000000.0) { Add(playerData, add.Key, add.Value, now); } } } return dictionary; } public void AddDeath(string player, string killer, int biome, DateTime now) { DeathRec deathRec = new DeathRec(); deathRec.ticks = now.Ticks; deathRec.player = Clean(player); deathRec.killer = Clean(killer); deathRec.biome = biome; deaths.Insert(0, deathRec); if (deaths.Count > 40) { deaths.RemoveRange(40, deaths.Count - 40); } if (deathRec.killer.Length > 0 && players.TryGetValue(deathRec.player, out var value) && (value.killers.Count < 60 || value.killers.ContainsKey(deathRec.killer))) { value.killers.TryGetValue(deathRec.killer, out var value2); value.killers[deathRec.killer] = value2 + 1; } } public void AddBoss(string boss, string player, DateTime now) { player = Clean(player); boss = Clean(boss); foreach (BossRec boss2 in bosses) { if (boss2.boss == boss && Math.Abs(now.Ticks - boss2.ticks) < TimeSpan.FromMinutes(10.0).Ticks) { if (!boss2.players.Contains(player)) { boss2.players.Add(player); } return; } } BossRec bossRec = new BossRec(); bossRec.ticks = now.Ticks; bossRec.boss = boss; bossRec.players.Add(player); bosses.Insert(0, bossRec); if (bosses.Count > 30) { bosses.RemoveRange(30, bosses.Count - 30); } } public string Nemesis(PlayerData p, out int count) { string result = ""; count = 0; foreach (KeyValuePair<string, int> killer in p.killers) { if (killer.Value > count) { count = killer.Value; result = killer.Key; } } return result; } public double Value(PlayerData p, int id, int period, DateTime now) { if (period == 2) { p.total.TryGetValue(id, out var value); return value; } double num = 0.0; int num2 = ((period == 0) ? 1 : 7); for (int i = 0; i < num2; i++) { if (p.daily.TryGetValue(Day(now.AddDays(-i)), out var value2) && value2.TryGetValue(id, out var value3)) { num += value3; } } return num; } public void Save(string path, DateTime now) { StringBuilder stringBuilder = new StringBuilder(); string strB = Day(now.AddDays(-60.0)); foreach (KeyValuePair<string, PlayerData> player in players) { string value = Clean(player.Key); PlayerData value2 = player.Value; stringBuilder.Append("P\t").Append(value).Append('\t') .Append(value2.lastSeen.Ticks) .Append('\t') .Append(value2.hasBase ? 1 : 0) .Append('\t') .Append(value2.lifeKills.ToString("R", Inv)) .Append('\t') .Append(value2.bestLife.ToString("R", Inv)) .Append('\n'); foreach (KeyValuePair<int, float> item in value2.last) { stringBuilder.Append("L\t").Append(value).Append('\t') .Append(item.Key) .Append('\t') .Append(item.Value.ToString("R", Inv)) .Append('\n'); } foreach (KeyValuePair<int, double> item2 in value2.total) { stringBuilder.Append("T\t").Append(value).Append('\t') .Append(item2.Key) .Append('\t') .Append(item2.Value.ToString("R", Inv)) .Append('\n'); } foreach (KeyValuePair<int, double> item3 in value2.offline) { stringBuilder.Append("O\t").Append(value).Append('\t') .Append(item3.Key) .Append('\t') .Append(item3.Value.ToString("R", Inv)) .Append('\n'); } foreach (KeyValuePair<string, int> killer in value2.killers) { stringBuilder.Append("K\t").Append(value).Append('\t') .Append(Clean(killer.Key)) .Append('\t') .Append(killer.Value) .Append('\n'); } foreach (KeyValuePair<string, Dictionary<int, double>> item4 in value2.daily) { if (string.CompareOrdinal(item4.Key, strB) < 0) { continue; } foreach (KeyValuePair<int, double> item5 in item4.Value) { stringBuilder.Append("D\t").Append(value).Append('\t') .Append(item4.Key) .Append('\t') .Append(item5.Key) .Append('\t') .Append(item5.Value.ToString("R", Inv)) .Append('\n'); } } } foreach (KeyValuePair<int, string> name in names) { stringBuilder.Append("N\t").Append(name.Key).Append('\t') .Append(Clean(name.Value)) .Append('\n'); } foreach (DeathRec death in deaths) { stringBuilder.Append("X\t").Append(death.ticks).Append('\t') .Append(Clean(death.player)) .Append('\t') .Append(Clean(death.killer)) .Append('\t') .Append(death.biome) .Append('\n'); } foreach (BossRec boss in bosses) { stringBuilder.Append("B\t").Append(boss.ticks).Append('\t') .Append(Clean(boss.boss)) .Append('\t') .Append(Clean(string.Join(",", boss.players.ToArray()))) .Append('\n'); } string text = path + ".tmp"; File.WriteAllText(text, stringBuilder.ToString()); File.Copy(text, path, overwrite: true); } public void Load(string path) { if (!File.Exists(path)) { return; } List<DeathRec> list = new List<DeathRec>(); List<BossRec> list2 = new List<BossRec>(); string[] array = File.ReadAllLines(path); for (int i = 0; i < array.Length; i++) { string[] array2 = array[i].Split(new char[1] { '\t' }); if (array2.Length < 3) { continue; } try { switch (array2[0]) { case "N": names[int.Parse(array2[1], Inv)] = array2[2]; continue; case "X": if (array2.Length >= 5) { DeathRec deathRec = new DeathRec(); deathRec.ticks = long.Parse(array2[1], Inv); deathRec.player = array2[2]; deathRec.killer = array2[3]; deathRec.biome = int.Parse(array2[4], Inv); list.Add(deathRec); } continue; case "B": { BossRec bossRec = new BossRec(); bossRec.ticks = long.Parse(array2[1], Inv); bossRec.boss = array2[2]; if (array2.Length >= 4) { string[] array3 = array2[3].Split(new char[1] { ',' }); foreach (string text in array3) { if (text.Length > 0) { bossRec.players.Add(text); } } } list2.Add(bossRec); continue; } } PlayerData playerData = Get(array2[1]); if (array2[0] == "P" && array2.Length >= 4) { playerData.lastSeen = new DateTime(long.Parse(array2[2], Inv)); playerData.hasBase = array2[3] == "1"; if (array2.Length >= 6) { playerData.lifeKills = double.Parse(array2[4], Inv); playerData.bestLife = double.Parse(array2[5], Inv); } } else if (array2[0] == "L") { playerData.last[int.Parse(array2[2], Inv)] = float.Parse(array2[3], Inv); } else if (array2[0] == "T") { playerData.total[int.Parse(array2[2], Inv)] = double.Parse(array2[3], Inv); } else if (array2[0] == "O") { playerData.offline[int.Parse(array2[2], Inv)] = double.Parse(array2[3], Inv); } else if (array2[0] == "K" && array2.Length >= 4) { playerData.killers[array2[2]] = int.Parse(array2[3], Inv); } else if (array2[0] == "D" && array2.Length >= 5) { if (!playerData.daily.TryGetValue(array2[2], out var value)) { value = new Dictionary<int, double>(); playerData.daily[array2[2]] = value; } value[int.Parse(array2[3], Inv)] = double.Parse(array2[4], Inv); } } catch (Exception) { } } deaths.Clear(); deaths.AddRange(list); bosses.Clear(); bosses.AddRange(list2); } private static string Clean(string s) { StringBuilder stringBuilder = new StringBuilder(); string text = s ?? ""; foreach (char c in text) { if (c >= ' ' && c != '\u007f') { stringBuilder.Append(c); if (stringBuilder.Length >= 48) { break; } } } return stringBuilder.ToString().Trim(); } }