Decompiled source of Ratatoskr v0.2.2

plugins/Ratatoskr.dll

Decompiled a week ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using System.Text.RegularExpressions;
using BepInEx;
using Microsoft.CodeAnalysis;
using UnityEngine;
using ValheimRcon;
using ValheimRcon.Commands;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: IgnoresAccessChecksTo("assembly_guiutils")]
[assembly: IgnoresAccessChecksTo("assembly_valheim")]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.0.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace Ratatoskr
{
	internal sealed class Args
	{
		public readonly List<string> Positional = new List<string>();

		public Vector3? NearCenter;

		public float NearRadius;

		public int Offset;

		public bool All;

		public string Player;

		public float Days;

		public long Since;

		public string Text => string.Join(" ", Positional).Trim();

		public Args(IReadOnlyList<string> raw)
		{
			//IL_009a: Unknown result type (might be due to invalid IL or missing references)
			for (int i = 0; i < raw.Count; i++)
			{
				switch (raw[i])
				{
				case "-near":
					NearCenter = new Vector3(F(raw, i + 1), 0f, F(raw, i + 2));
					NearRadius = F(raw, i + 3);
					i += 3;
					break;
				case "-offset":
					Offset = Mathf.Max(0, (int)F(raw, i + 1));
					i++;
					break;
				case "-player":
					if (i + 1 >= raw.Count)
					{
						throw new ArgumentException("-player needs a name");
					}
					Player = raw[i + 1];
					i++;
					break;
				case "-days":
					Days = F(raw, i + 1);
					i++;
					break;
				case "-since":
				{
					if (!long.TryParse((i + 1 < raw.Count) ? raw[i + 1] : "", out var result))
					{
						throw new ArgumentException("-since needs a number");
					}
					Since = result;
					i++;
					break;
				}
				case "-all":
					All = true;
					break;
				default:
					Positional.Add(raw[i]);
					break;
				}
			}
		}

		public static string WithoutOffset(string raw)
		{
			return Regex.Replace(raw, "(^|\\s)-offset\\s+\\S+", "").Trim();
		}

		public bool InRange(Vector3 p)
		{
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: 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)
			if (!NearCenter.HasValue)
			{
				return true;
			}
			Vector3 value = NearCenter.Value;
			float num = p.x - value.x;
			float num2 = p.z - value.z;
			return num * num + num2 * num2 <= NearRadius * NearRadius;
		}

		private static float F(IReadOnlyList<string> raw, int i)
		{
			if (i >= raw.Count || !float.TryParse(raw[i], NumberStyles.Float, CultureInfo.InvariantCulture, out var result))
			{
				throw new ArgumentException("bad or missing number at argument " + i);
			}
			return result;
		}
	}
	internal static class Events
	{
		private const int Capacity = 1000;

		private static readonly LinkedList<(long Seq, string Json)> Ring = new LinkedList<(long, string)>();

		public static readonly string Boot = Guid.NewGuid().ToString("N").Substring(0, 8);

		public static long Seq { get; private set; }

		public static long Now => DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();

		public static void Add(string type, Action<Json> props = null)
		{
			Json json = new Json().Obj().Prop("seq", ++Seq).Prop("t", Now)
				.Prop("type", type);
			props?.Invoke(json);
			Ring.AddLast((Seq, json.EndObj().ToString()));
			while (Ring.Count > 1000)
			{
				Ring.RemoveFirst();
			}
		}

		public static List<string> Since(long seq)
		{
			List<string> list = new List<string>();
			foreach (var item in Ring)
			{
				if (item.Seq > seq)
				{
					list.Add(item.Json);
				}
			}
			return list;
		}
	}
	internal sealed class Contents
	{
		public uint Revision;

		public int Slots;

		public readonly Dictionary<string, (string Label, string English, int Count)> Items = new Dictionary<string, (string, string, int)>();
	}
	internal static class InventoryCache
	{
		private static readonly Dictionary<ZDOID, Contents> Cache = new Dictionary<ZDOID, Contents>();

		public static Contents Get(ZDO zdo, Container container)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e2: Unknown result type (might be due to invalid IL or missing references)
			if (Cache.TryGetValue(zdo.m_uid, out var value) && value.Revision == zdo.DataRevision)
			{
				return value;
			}
			Inventory obj = (((Object)(object)container != (Object)null) ? World.LoadInventory(zdo, container) : World.LoadTombInventory(zdo));
			value = new Contents
			{
				Revision = zdo.DataRevision
			};
			foreach (ItemData allItem in obj.GetAllItems())
			{
				value.Slots++;
				PlayerNames.Learn(allItem.m_crafterID, allItem.m_crafterName);
				string key = World.ItemId(allItem);
				value.Items.TryGetValue(key, out (string, string, int) value2);
				value.Items[key] = (World.ItemLabel(allItem), World.ItemEnglish(allItem), value2.Item3 + allItem.m_stack);
			}
			Cache[zdo.m_uid] = value;
			return value;
		}

		public static void Prune(List<ZDOID> storage, List<ZDOID> tombs)
		{
			//IL_0028: 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_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			HashSet<ZDOID> hashSet = new HashSet<ZDOID>(storage);
			hashSet.UnionWith(tombs);
			List<ZDOID> list = new List<ZDOID>();
			foreach (ZDOID key in Cache.Keys)
			{
				if (!hashSet.Contains(key))
				{
					list.Add(key);
				}
			}
			foreach (ZDOID item in list)
			{
				Cache.Remove(item);
			}
		}
	}
	internal sealed class Json
	{
		private readonly StringBuilder _sb = new StringBuilder();

		private readonly Stack<bool> _first = new Stack<bool>();

		private bool _skipNext;

		public Json Obj()
		{
			Sep();
			_sb.Append('{');
			_first.Push(item: true);
			return this;
		}

		public Json EndObj()
		{
			_sb.Append('}');
			_first.Pop();
			return this;
		}

		public Json Arr()
		{
			Sep();
			_sb.Append('[');
			_first.Push(item: true);
			return this;
		}

		public Json EndArr()
		{
			_sb.Append(']');
			_first.Pop();
			return this;
		}

		public Json Key(string key)
		{
			Sep();
			Str(key);
			_sb.Append(':');
			_skipNext = true;
			return this;
		}

		public Json Val(string v)
		{
			Sep();
			if (v == null)
			{
				_sb.Append("null");
			}
			else
			{
				Str(v);
			}
			return this;
		}

		public Json Val(long v)
		{
			Sep();
			_sb.Append(v.ToString(CultureInfo.InvariantCulture));
			return this;
		}

		public Json Val(double v)
		{
			Sep();
			_sb.Append(Math.Round(v, 2).ToString(CultureInfo.InvariantCulture));
			return this;
		}

		public Json Val(bool v)
		{
			Sep();
			_sb.Append(v ? "true" : "false");
			return this;
		}

		public Json Null()
		{
			Sep();
			_sb.Append("null");
			return this;
		}

		public Json Raw(string json)
		{
			Sep();
			_sb.Append(json);
			return this;
		}

		public Json Pos(Vector3 p)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			return Arr().Val(p.x).Val(p.y).Val(p.z)
				.EndArr();
		}

		public Json Prop(string k, string v)
		{
			return Key(k).Val(v);
		}

		public Json Prop(string k, long v)
		{
			return Key(k).Val(v);
		}

		public Json Prop(string k, double v)
		{
			return Key(k).Val(v);
		}

		public Json Prop(string k, bool v)
		{
			return Key(k).Val(v);
		}

		private void Sep()
		{
			if (_skipNext)
			{
				_skipNext = false;
			}
			else if (_first.Count != 0)
			{
				if (_first.Peek())
				{
					_first.Pop();
					_first.Push(item: false);
				}
				else
				{
					_sb.Append(',');
				}
			}
		}

		private void Str(string s)
		{
			_sb.Append('"');
			foreach (char c in s)
			{
				switch (c)
				{
				case '"':
					_sb.Append("\\\"");
					continue;
				case '\\':
					_sb.Append("\\\\");
					continue;
				case '\n':
					_sb.Append("\\n");
					continue;
				case '\r':
					_sb.Append("\\r");
					continue;
				case '\t':
					_sb.Append("\\t");
					continue;
				}
				if (c < ' ')
				{
					_sb.AppendFormat("\\u{0:x4}", (int)c);
				}
				else
				{
					_sb.Append(c);
				}
			}
			_sb.Append('"');
		}

		public override string ToString()
		{
			return _sb.ToString();
		}
	}
	internal static class Pager
	{
		private const int Budget = 3800;

		public static string Page(IList<string> items, int offset, string extraProps = null)
		{
			StringBuilder stringBuilder = new StringBuilder();
			int num = 0;
			int i;
			for (i = offset; i < items.Count; i++)
			{
				int num2 = Encoding.UTF8.GetByteCount(items[i]) + 1;
				if (i > offset && num + num2 > 3680)
				{
					break;
				}
				if (i > offset)
				{
					stringBuilder.Append(',');
				}
				stringBuilder.Append(items[i]);
				num += num2;
			}
			StringBuilder stringBuilder2 = new StringBuilder();
			stringBuilder2.Append("{\"total\":").Append(items.Count).Append(",\"offset\":")
				.Append(offset)
				.Append(",\"next\":")
				.Append((i < items.Count) ? i.ToString() : "null");
			if (!string.IsNullOrEmpty(extraProps))
			{
				stringBuilder2.Append(',').Append(extraProps);
			}
			stringBuilder2.Append(",\"items\":[").Append((object?)stringBuilder).Append("]}");
			return stringBuilder2.ToString();
		}
	}
	internal static class PlayerNames
	{
		private static readonly Dictionary<long, string> Names = new Dictionary<long, string>();

		private static bool _dirty;

		private static string FilePath => Path.Combine(Paths.ConfigPath, "ratatoskr.players.tsv");

		public static void Load()
		{
			if (!File.Exists(FilePath))
			{
				return;
			}
			string[] array = File.ReadAllLines(FilePath);
			for (int i = 0; i < array.Length; i++)
			{
				string[] array2 = array[i].Split(new char[1] { '\t' });
				if (array2.Length == 2 && long.TryParse(array2[0], out var result))
				{
					Names[result] = array2[1];
				}
			}
		}

		public static void Learn(long id, string name)
		{
			if (id != 0L && !string.IsNullOrEmpty(name) && (!Names.TryGetValue(id, out var value) || !(value == name)))
			{
				Names[id] = name;
				_dirty = true;
			}
		}

		public static string Get(long id)
		{
			if (!Names.TryGetValue(id, out var value))
			{
				return null;
			}
			return value;
		}

		public static void LearnOnline()
		{
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)ZNet.instance == (Object)null || ZDOMan.instance == null)
			{
				return;
			}
			foreach (ZNetPeer peer in ZNet.instance.GetPeers())
			{
				ZDO zDO = ZDOMan.instance.GetZDO(peer.m_characterID);
				if (zDO != null)
				{
					Learn(zDO.GetLong(ZDOVars.s_playerID, 0L), zDO.GetString(ZDOVars.s_playerName, ""));
				}
			}
			Save();
		}

		public static void Save()
		{
			if (!_dirty)
			{
				return;
			}
			List<string> list = new List<string>();
			foreach (KeyValuePair<long, string> name in Names)
			{
				list.Add(name.Key + "\t" + name.Value.Replace('\t', ' '));
			}
			File.WriteAllLines(FilePath, list);
			_dirty = false;
		}
	}
	[BepInPlugin("dev.tiene.ratatoskr", "Ratatoskr", "0.2.2")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public class Plugin : BaseUnityPlugin
	{
		public const string Guid = "dev.tiene.ratatoskr";

		public const string Name = "Ratatoskr";

		public const string Version = "0.2.2";

		private float _nextLearn;

		private float _nextTick;

		private bool _tickFailed;

		private void Awake()
		{
			Translations.Load(((BaseUnityPlugin)this).Config.Bind<string>("General", "Language", "English", "Language for item names in replies (a column of the game's localization, e.g. French, German). Queries match this language, English and prefab names.").Value);
			PlayerNames.Load();
			RconCommandsUtil.RegisterAllCommands(Assembly.GetExecutingAssembly());
		}

		private void Update()
		{
			float time = Time.time;
			if (time >= _nextTick)
			{
				_nextTick = time + 2f;
				try
				{
					Tracker.Tick();
					_tickFailed = false;
				}
				catch (Exception ex)
				{
					if (!_tickFailed)
					{
						((BaseUnityPlugin)this).Logger.LogError((object)ex);
					}
					_tickFailed = true;
				}
			}
			if (!(time < _nextLearn))
			{
				_nextLearn = time + 60f;
				PlayerNames.LearnOnline();
			}
		}

		private void OnDestroy()
		{
			Tracker.Shutdown();
		}
	}
	internal sealed class Store
	{
		private readonly string _path;

		public bool Exists => File.Exists(_path);

		public Store(string name)
		{
			_path = Path.Combine(Paths.ConfigPath, name);
		}

		public void Append(params object[] fields)
		{
			string[] array = new string[fields.Length];
			for (int i = 0; i < fields.Length; i++)
			{
				array[i] = (fields[i]?.ToString() ?? "").Replace('\t', ' ').Replace('\n', ' ');
			}
			File.AppendAllText(_path, string.Join("\t", array) + "\n");
		}

		public List<string[]> Read(int max = 0)
		{
			List<string[]> list = new List<string[]>();
			if (!File.Exists(_path))
			{
				return list;
			}
			string[] array = File.ReadAllLines(_path);
			for (int i = ((max > 0) ? Math.Max(0, array.Length - max) : 0); i < array.Length; i++)
			{
				if (array[i].Length > 0)
				{
					list.Add(array[i].Split(new char[1] { '\t' }));
				}
			}
			return list;
		}
	}
	internal sealed class JournalEntry
	{
		public long T;

		public string Player;

		public int Delta;

		public string Item;

		public string Label;

		public string Container;

		public string ContainerLabel;

		public float X;

		public float Z;
	}
	internal sealed class Session
	{
		public long PlayerId;

		public string Name;

		public long Start;

		public long End;
	}
	internal static class Tracker
	{
		private sealed class PlayerState
		{
			public string Name;

			public long PlayerId;

			public long JoinedAt;

			public ZDOID DeadFor = ZDOID.None;
		}

		private const int JournalInMemory = 5000;

		private static readonly Store BiomeStore = new Store("ratatoskr.biomes.tsv");

		private static readonly Store SessionStore = new Store("ratatoskr.sessions.tsv");

		private static readonly Store JournalStore = new Store("ratatoskr.journal.tsv");

		private static readonly Dictionary<long, PlayerState> Online = new Dictionary<long, PlayerState>();

		private static readonly Dictionary<ZDOID, (uint Rev, Dictionary<string, int> Counts)> Chests = new Dictionary<ZDOID, (uint, Dictionary<string, int>)>();

		private static HashSet<string> _knownBiomes;

		private static HashSet<string> _keys;

		private static string _raid;

		private static bool _started;

		public static readonly List<JournalEntry> Journal = new List<JournalEntry>();

		public static readonly List<Session> Sessions = new List<Session>();

		public static IEnumerable<Session> OpenSessions()
		{
			return Online.Values.Select((PlayerState p) => new Session
			{
				PlayerId = p.PlayerId,
				Name = p.Name,
				Start = p.JoinedAt,
				End = Events.Now
			});
		}

		public static void Tick()
		{
			if (!((Object)(object)ZNet.instance == (Object)null) && ZDOMan.instance != null && !((Object)(object)ZoneSystem.instance == (Object)null) && !((Object)(object)EnvMan.instance == (Object)null))
			{
				if (!_started)
				{
					Start();
				}
				TrackPlayers();
				TrackKeys();
				TrackRaid();
				TrackChests();
			}
		}

		public static void Shutdown()
		{
			foreach (Session item in OpenSessions())
			{
				SessionStore.Append(item.PlayerId, item.Name, item.Start, item.End);
			}
			Online.Clear();
		}

		private static void Start()
		{
			//IL_022b: Unknown result type (might be due to invalid IL or missing references)
			_started = true;
			foreach (string[] item in SessionStore.Read())
			{
				if (item.Length >= 4 && long.TryParse(item[0], out var result) && long.TryParse(item[2], out var result2) && long.TryParse(item[3], out var result3))
				{
					Sessions.Add(new Session
					{
						PlayerId = result,
						Name = item[1],
						Start = result2,
						End = result3
					});
				}
			}
			foreach (string[] item2 in JournalStore.Read(5000))
			{
				if (item2.Length >= 9 && long.TryParse(item2[0], out var result4) && int.TryParse(item2[2], out var result5))
				{
					Journal.Add(new JournalEntry
					{
						T = result4,
						Player = item2[1],
						Delta = result5,
						Item = item2[3],
						Label = item2[4],
						Container = item2[5],
						ContainerLabel = ((item2[6].Length > 0) ? item2[6] : null),
						X = float.Parse(item2[7], CultureInfo.InvariantCulture),
						Z = float.Parse(item2[8], CultureInfo.InvariantCulture)
					});
				}
			}
			_knownBiomes = new HashSet<string>(from r in BiomeStore.Read()
				select r[0]);
			if (!BiomeStore.Exists)
			{
				SeedBiomes();
			}
			_keys = new HashSet<string>(ZoneSystem.instance.GetGlobalKeys());
			_raid = CurrentRaid()?.m_name;
			foreach (ZDO item3 in WorldIndex.Containers())
			{
				World.PrefabInfo info = World.Info(item3);
				if (World.IsStorage(item3, info, all: false))
				{
					Chests[item3.m_uid] = (item3.DataRevision, Counts(item3, info));
				}
			}
		}

		private static void SeedBiomes()
		{
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			foreach (ZDO item in World.All())
			{
				World.PrefabInfo prefabInfo = World.Info(item);
				if (item.GetLong(ZDOVars.s_creator, 0L) != 0L || prefabInfo.IsTombstone || prefabInfo.IsPortal)
				{
					string text = World.Biome(item.GetPosition());
					if (text != null && _knownBiomes.Add(text))
					{
						BiomeStore.Append(text, "", Events.Now);
					}
				}
			}
		}

		private static void TrackPlayers()
		{
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0132: Unknown result type (might be due to invalid IL or missing references)
			//IL_017c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0181: Unknown result type (might be due to invalid IL or missing references)
			//IL_0188: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ca: Unknown result type (might be due to invalid IL or missing references)
			HashSet<long> seen = new HashSet<long>();
			foreach (ZNetPeer peer in ZNet.instance.GetPeers())
			{
				if (peer.m_characterID == ZDOID.None)
				{
					if (Online.ContainsKey(peer.m_uid))
					{
						seen.Add(peer.m_uid);
					}
					continue;
				}
				seen.Add(peer.m_uid);
				if (!Online.TryGetValue(peer.m_uid, out var st))
				{
					st = new PlayerState
					{
						Name = peer.m_playerName,
						JoinedAt = Events.Now
					};
					Online[peer.m_uid] = st;
					bool first = Sessions.All((Session s) => s.Name != st.Name);
					Events.Add("join", delegate(Json j)
					{
						j.Prop("player", st.Name).Prop("first", first);
					});
				}
				ZDO zDO = ZDOMan.instance.GetZDO(peer.m_characterID);
				if (zDO == null)
				{
					continue;
				}
				st.PlayerId = zDO.GetLong(ZDOVars.s_playerID, 0L);
				PlayerNames.Learn(st.PlayerId, st.Name);
				Vector3 pos = zDO.GetPosition();
				string biome = World.Biome(pos);
				if (zDO.GetBool(ZDOVars.s_dead, false) && st.DeadFor != peer.m_characterID)
				{
					st.DeadFor = peer.m_characterID;
					Events.Add("death", delegate(Json j)
					{
						//IL_0021: Unknown result type (might be due to invalid IL or missing references)
						j.Prop("player", st.Name).Key("pos").Pos(pos)
							.Prop("biome", biome);
					});
				}
				if (biome != null && biome != "None" && _knownBiomes.Add(biome))
				{
					BiomeStore.Append(biome, st.Name, Events.Now);
					Events.Add("biome", delegate(Json j)
					{
						//IL_0031: Unknown result type (might be due to invalid IL or missing references)
						j.Prop("player", st.Name).Prop("biome", biome).Key("pos")
							.Pos(pos);
					});
				}
			}
			foreach (long item in Online.Keys.Where((long u) => !seen.Contains(u)).ToList())
			{
				PlayerState st2 = Online[item];
				Online.Remove(item);
				Session session = new Session
				{
					PlayerId = st2.PlayerId,
					Name = st2.Name,
					Start = st2.JoinedAt,
					End = Events.Now
				};
				Sessions.Add(session);
				SessionStore.Append(session.PlayerId, session.Name, session.Start, session.End);
				Events.Add("leave", delegate(Json j)
				{
					j.Prop("player", st2.Name).Prop("seconds", (session.End - session.Start) / 1000);
				});
			}
		}

		private static void TrackKeys()
		{
			foreach (string key in ZoneSystem.instance.GetGlobalKeys())
			{
				if (_keys.Add(key) && key.StartsWith("defeated_"))
				{
					string names = string.Join(", ", Online.Values.Select((PlayerState p) => p.Name));
					Events.Add("boss", delegate(Json j)
					{
						j.Prop("key", key).Prop("online", names);
					});
				}
			}
		}

		private static RandomEvent CurrentRaid()
		{
			RandEventSystem instance = RandEventSystem.instance;
			object obj;
			if (!((Object)(object)instance == (Object)null))
			{
				obj = instance.GetCurrentRandomEvent();
				if (obj == null)
				{
					return instance.m_forcedEvent;
				}
			}
			else
			{
				obj = null;
			}
			return (RandomEvent)obj;
		}

		private static void TrackRaid()
		{
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			RandomEvent val = CurrentRaid();
			string name = val?.m_name;
			if (name == _raid)
			{
				return;
			}
			if (name != null)
			{
				Vector3 pos = val.m_pos;
				object obj = Translations.Get(val.m_startMessage);
				if (obj == null)
				{
					Localization instance = Localization.instance;
					obj = ((instance != null) ? instance.Localize(val.m_startMessage) : null);
				}
				string message = (string)obj;
				Events.Add("raid", delegate(Json j)
				{
					//IL_002c: Unknown result type (might be due to invalid IL or missing references)
					//IL_003c: Unknown result type (might be due to invalid IL or missing references)
					//IL_0051: Unknown result type (might be due to invalid IL or missing references)
					j.Prop("raid", name).Prop("message", message).Key("pos")
						.Pos(pos)
						.Prop("biome", World.Biome(pos))
						.Prop("label", World.LabelFor(pos, WorldIndex.Signs(), 40f));
				});
			}
			else
			{
				string ended = _raid;
				Events.Add("raidEnd", delegate(Json j)
				{
					j.Prop("raid", ended);
				});
			}
			_raid = name;
		}

		private static Dictionary<string, int> Counts(ZDO zdo, World.PrefabInfo info)
		{
			return InventoryCache.Get(zdo, info.Container).Items.ToDictionary((KeyValuePair<string, (string Label, string English, int Count)> kv) => kv.Key, (KeyValuePair<string, (string Label, string English, int Count)> kv) => kv.Value.Count);
		}

		private static void TrackChests()
		{
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ef: Unknown result type (might be due to invalid IL or missing references)
			//IL_024b: 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_0257: Unknown result type (might be due to invalid IL or missing references)
			foreach (ZDO item2 in WorldIndex.Containers())
			{
				World.PrefabInfo info = World.Info(item2);
				if (!World.IsStorage(item2, info, all: false))
				{
					continue;
				}
				uint dataRevision = item2.DataRevision;
				if (!Chests.TryGetValue(item2.m_uid, out (uint, Dictionary<string, int>) value))
				{
					Chests[item2.m_uid] = (dataRevision, Counts(item2, info));
				}
				else
				{
					if (value.Item1 == dataRevision)
					{
						continue;
					}
					Contents contents = InventoryCache.Get(item2, info.Container);
					Dictionary<string, int> dictionary = contents.Items.ToDictionary((KeyValuePair<string, (string Label, string English, int Count)> kv) => kv.Key, (KeyValuePair<string, (string Label, string English, int Count)> kv) => kv.Value.Count);
					Chests[item2.m_uid] = (dataRevision, dictionary);
					List<(string Item, string Label, int Delta)> changes = new List<(string, string, int)>();
					foreach (string id in dictionary.Keys.Union(value.Item2.Keys))
					{
						dictionary.TryGetValue(id, out var value2);
						value.Item2.TryGetValue(id, out var value3);
						if (value2 == value3)
						{
							continue;
						}
						object obj;
						if (contents.Items.TryGetValue(id, out (string, string, int) value4))
						{
							(obj, _, _) = value4;
						}
						else
						{
							obj = Journal.LastOrDefault((JournalEntry e) => e.Item == id)?.Label ?? id;
						}
						string item = (string)obj;
						changes.Add((id, item, value2 - value3));
					}
					if (changes.Count == 0)
					{
						continue;
					}
					long owner = item2.GetOwner();
					string who = ZNet.instance.GetPeer(owner)?.m_playerName ?? ((owner == ZDOMan.GetSessionID()) ? "server" : "?");
					Vector3 pos = item2.GetPosition();
					string chestLabel = World.LabelFor(pos, WorldIndex.Signs());
					foreach (var item3 in changes)
					{
						JournalEntry journalEntry = new JournalEntry
						{
							T = Events.Now,
							Player = who,
							Delta = item3.Delta,
							Item = item3.Item,
							Label = item3.Label,
							Container = info.Name,
							ContainerLabel = chestLabel,
							X = pos.x,
							Z = pos.z
						};
						Journal.Add(journalEntry);
						JournalStore.Append(journalEntry.T, journalEntry.Player, journalEntry.Delta, journalEntry.Item, journalEntry.Label, journalEntry.Container, journalEntry.ContainerLabel, journalEntry.X.ToString("0.#", CultureInfo.InvariantCulture), journalEntry.Z.ToString("0.#", CultureInfo.InvariantCulture));
					}
					if (Journal.Count > 5000)
					{
						Journal.RemoveRange(0, Journal.Count - 5000);
					}
					Events.Add("chest", delegate(Json j)
					{
						//IL_0041: Unknown result type (might be due to invalid IL or missing references)
						j.Prop("player", who).Prop("container", info.Name).Prop("label", chestLabel)
							.Key("pos")
							.Pos(pos)
							.Key("changes")
							.Arr();
						foreach (var item4 in changes)
						{
							j.Obj().Prop("item", item4.Item).Prop("name", item4.Label)
								.Prop("delta", item4.Delta)
								.EndObj();
						}
						j.EndArr();
					});
				}
			}
		}
	}
	internal static class Translations
	{
		private static Dictionary<string, string> _words;

		public static string Language { get; private set; } = "English";

		public static void Load(string language)
		{
			Language = (string.IsNullOrWhiteSpace(language) ? "English" : language.Trim());
			_words = null;
		}

		public static string Get(string token)
		{
			if (string.IsNullOrEmpty(token) || token[0] != '$')
			{
				return null;
			}
			if (_words == null)
			{
				_words = Build(Language);
			}
			if (!_words.TryGetValue(token.Substring(1), out var value))
			{
				return null;
			}
			return value;
		}

		private static Dictionary<string, string> Build(string language)
		{
			Dictionary<string, string> dictionary = new Dictionary<string, string>();
			Localization instance = Localization.instance;
			LocalizationSettings localizationSettings = Localization.m_localizationSettings;
			if (instance == null || (Object)(object)localizationSettings == (Object)null)
			{
				return dictionary;
			}
			foreach (TextAsset localization in localizationSettings.Localizations)
			{
				if ((Object)(object)localization == (Object)null)
				{
					continue;
				}
				StringReader stringReader = new StringReader(localization.text);
				string[] array = stringReader.ReadLine()?.Split(new char[1] { ',' });
				if (array == null)
				{
					continue;
				}
				int num = -1;
				for (int i = 0; i < array.Length; i++)
				{
					if (array[i].Trim(new char[1] { '"' }) == language)
					{
						num = i;
						break;
					}
				}
				if (num < 0)
				{
					continue;
				}
				foreach (List<string> item in instance.DoQuoteLineSplit(stringReader))
				{
					if (item.Count > num && item[0].Length != 0 && !item[0].StartsWith("//"))
					{
						string text = item[num].Trim();
						if (text.Length > 0 && text[0] != '\r')
						{
							dictionary[item[0]] = text;
						}
					}
				}
			}
			return dictionary;
		}
	}
	internal static class World
	{
		internal sealed class PrefabInfo
		{
			public string Name;

			public Container Container;

			public bool IsSign;

			public bool IsPortal;

			public bool IsTombstone;
		}

		internal struct SignText
		{
			public Vector3 Pos;

			public string Text;
		}

		private static readonly Dictionary<int, PrefabInfo> Prefabs = new Dictionary<int, PrefabInfo>();

		private static readonly Regex Tags = new Regex("<[^>]*>", RegexOptions.Compiled);

		public static IEnumerable<ZDO> All()
		{
			return ZDOMan.instance.m_objectsByID.Values;
		}

		public static PrefabInfo Info(ZDO zdo)
		{
			int prefab = zdo.GetPrefab();
			if (Prefabs.TryGetValue(prefab, out var value))
			{
				return value;
			}
			value = new PrefabInfo();
			GameObject val = (Object.op_Implicit((Object)(object)ZNetScene.instance) ? ZNetScene.instance.GetPrefab(prefab) : null);
			if ((Object)(object)val != (Object)null)
			{
				value.Name = ((Object)val).name;
				value.Container = val.GetComponentInChildren<Container>();
				value.IsSign = (Object)(object)val.GetComponent<Sign>() != (Object)null;
				value.IsPortal = (Object)(object)val.GetComponent<TeleportWorld>() != (Object)null;
				value.IsTombstone = (Object)(object)val.GetComponent<TombStone>() != (Object)null;
			}
			else
			{
				value.Name = prefab.ToString();
			}
			Prefabs[prefab] = value;
			return value;
		}

		public static bool IsStorage(ZDO zdo, PrefabInfo info, bool all)
		{
			if ((Object)(object)info.Container == (Object)null || info.IsTombstone)
			{
				return false;
			}
			if (!all)
			{
				return zdo.GetLong(ZDOVars.s_creator, 0L) != 0;
			}
			return true;
		}

		public static Inventory LoadInventory(ZDO zdo, Container c)
		{
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Expected O, but got Unknown
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Expected O, but got Unknown
			Inventory val = new Inventory(c.m_name, (Sprite)null, c.m_width, c.m_height);
			byte[] byteArray = zdo.GetByteArray(ZDOVars.s_items, (byte[])null);
			if (byteArray != null)
			{
				val.Load(new ZPackage(byteArray));
			}
			return val;
		}

		public static Inventory LoadTombInventory(ZDO zdo)
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_000e: Expected O, but got Unknown
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Expected O, but got Unknown
			Inventory val = new Inventory("tomb", (Sprite)null, 8, 8);
			byte[] byteArray = zdo.GetByteArray(ZDOVars.s_items, (byte[])null);
			if (byteArray != null)
			{
				val.Load(new ZPackage(byteArray));
			}
			return val;
		}

		public static string ItemId(ItemData item)
		{
			if (!((Object)(object)item.m_dropPrefab != (Object)null))
			{
				return item.m_shared.m_name;
			}
			return ((Object)item.m_dropPrefab).name;
		}

		public static string ItemEnglish(ItemData item)
		{
			string name = item.m_shared.m_name;
			if (Localization.instance == null)
			{
				return name;
			}
			return Localization.instance.Localize(name);
		}

		public static string ItemLabel(ItemData item)
		{
			return Translations.Get(item.m_shared.m_name) ?? ItemEnglish(item);
		}

		public static string Biome(Vector3 pos)
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			if (WorldGenerator.instance == null)
			{
				return null;
			}
			return ((object)WorldGenerator.instance.GetBiome(pos)/*cast due to .constrained prefix*/).ToString();
		}

		public static string Clean(string s)
		{
			if (!string.IsNullOrEmpty(s))
			{
				return Tags.Replace(s, "").Trim();
			}
			return s;
		}

		public static string LabelFor(Vector3 pos, List<SignText> signs, float range = 3f)
		{
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			string result = null;
			float num = range * range;
			foreach (SignText sign in signs)
			{
				Vector3 val = sign.Pos - pos;
				float sqrMagnitude = ((Vector3)(ref val)).sqrMagnitude;
				if (sqrMagnitude < num)
				{
					num = sqrMagnitude;
					result = sign.Text;
				}
			}
			return result;
		}
	}
	internal static class WorldIndex
	{
		public const float MaxAge = 30f;

		private static readonly List<ZDOID> StorageIds = new List<ZDOID>();

		private static readonly List<ZDOID> TombIds = new List<ZDOID>();

		private static readonly List<ZDOID> PortalIds = new List<ZDOID>();

		private static List<World.SignText> _signs = new List<World.SignText>();

		private static float _builtAt = float.NegativeInfinity;

		public static double LastScanMs { get; private set; }

		public static void EnsureFresh()
		{
			if (Time.time - _builtAt >= 30f)
			{
				Rebuild();
			}
		}

		public static void Rebuild()
		{
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0097: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dd: Unknown result type (might be due to invalid IL or missing references)
			Stopwatch stopwatch = Stopwatch.StartNew();
			StorageIds.Clear();
			TombIds.Clear();
			PortalIds.Clear();
			List<World.SignText> list = new List<World.SignText>();
			foreach (ZDO item in World.All())
			{
				World.PrefabInfo prefabInfo = World.Info(item);
				if (prefabInfo.IsTombstone)
				{
					TombIds.Add(item.m_uid);
				}
				else if ((Object)(object)prefabInfo.Container != (Object)null)
				{
					StorageIds.Add(item.m_uid);
				}
				else if (prefabInfo.IsPortal)
				{
					PortalIds.Add(item.m_uid);
				}
				else if (prefabInfo.IsSign)
				{
					string text = World.Clean(item.GetString(ZDOVars.s_text, ""));
					if (!string.IsNullOrEmpty(text))
					{
						list.Add(new World.SignText
						{
							Pos = item.GetPosition(),
							Text = text
						});
					}
				}
			}
			_signs = list;
			_builtAt = Time.time;
			LastScanMs = stopwatch.Elapsed.TotalMilliseconds;
			InventoryCache.Prune(StorageIds, TombIds);
		}

		public static IEnumerable<ZDO> Containers()
		{
			EnsureFresh();
			return Live(StorageIds);
		}

		public static IEnumerable<ZDO> Tombs()
		{
			EnsureFresh();
			return Live(TombIds);
		}

		public static IEnumerable<ZDO> Portals()
		{
			EnsureFresh();
			return Live(PortalIds);
		}

		public static List<World.SignText> Signs()
		{
			EnsureFresh();
			return _signs;
		}

		private static IEnumerable<ZDO> Live(List<ZDOID> ids)
		{
			ZDOMan man = ZDOMan.instance;
			foreach (ZDOID id in ids)
			{
				ZDO zDO = man.GetZDO(id);
				if (zDO != null)
				{
					yield return zDO;
				}
			}
		}
	}
}
namespace Ratatoskr.Commands
{
	internal class Tombs : PagedCommand
	{
		public override string Command => "rtTombs";

		public override string Description => "Player tombstones with position, biome, in-game day of death and most valuable items. Usage: rtTombs [player] [-offset n]";

		protected override Result Produce(Args args)
		{
			//IL_0092: Unknown result type (might be due to invalid IL or missing references)
			//IL_0097: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e0: Unknown result type (might be due to invalid IL or missing references)
			string text = args.Text;
			List<(DateTime?, string)> list = new List<(DateTime?, string)>();
			foreach (ZDO item2 in WorldIndex.Tombs())
			{
				string text2 = item2.GetString(ZDOVars.s_ownerName, "");
				if (text.Length > 0 && text2.IndexOf(text, StringComparison.OrdinalIgnoreCase) < 0)
				{
					continue;
				}
				PlayerNames.Learn(item2.GetLong(ZDOVars.s_owner, 0L), text2);
				long num = item2.GetLong(ZDOVars.s_timeOfDeath, 0L);
				DateTime? item = ((num > 0) ? new DateTime?(new DateTime(num)) : ((DateTime?)null));
				Vector3 position = item2.GetPosition();
				Json json = new Json().Obj().Prop("id", ((object)Unsafe.As<ZDOID, ZDOID>(ref item2.m_uid)/*cast due to .constrained prefix*/).ToString()).Prop("owner", text2)
					.Key("pos")
					.Pos(position)
					.Prop("biome", World.Biome(position))
					.Key("diedDay");
				if (item.HasValue && (Object)(object)EnvMan.instance != (Object)null)
				{
					json.Val(EnvMan.instance.GetDay((item.Value - DateTime.MinValue).TotalSeconds));
				}
				else
				{
					json.Null();
				}
				Inventory val = World.LoadTombInventory(item2);
				json.Prop("stacks", val.NrOfItems()).Key("top").Arr();
				foreach (ItemData item3 in (from i in val.GetAllItems()
					orderby i.m_shared.m_value * i.m_stack + i.m_quality descending
					select i).Take(5))
				{
					json.Val(World.ItemLabel(item3) + ((item3.m_stack > 1) ? (" x" + item3.m_stack) : ""));
				}
				list.Add((item, json.EndArr().EndObj().ToString()));
			}
			PlayerNames.Save();
			return new Result
			{
				Items = (from t in list
					orderby t.When ?? DateTime.MinValue descending
					select t.Json).ToList()
			};
		}
	}
	internal class Portals : PagedCommand
	{
		public override string Command => "rtPortals";

		public override string Description => "Portals grouped by tag; flags unpaired ones. Usage: rtPortals [-offset n]";

		protected override Result Produce(Args args)
		{
			List<(ZDO, World.PrefabInfo, string)> source = (from z in WorldIndex.Portals()
				select (Zdo: z, Info: World.Info(z), Tag: z.GetString(ZDOVars.s_tag, ""))).ToList();
			Dictionary<string, int> byTag = (from p in source
				group p by p.Tag).ToDictionary((IGrouping<string, (ZDO Zdo, World.PrefabInfo Info, string Tag)> g) => g.Key, (IGrouping<string, (ZDO Zdo, World.PrefabInfo Info, string Tag)> g) => g.Count());
			return new Result
			{
				Items = source.OrderBy<(ZDO, World.PrefabInfo, string), string>(((ZDO Zdo, World.PrefabInfo Info, string Tag) p) => p.Tag).Select<(ZDO, World.PrefabInfo, string), string>(delegate((ZDO Zdo, World.PrefabInfo Info, string Tag) p)
				{
					//IL_0006: Unknown result type (might be due to invalid IL or missing references)
					//IL_000b: Unknown result type (might be due to invalid IL or missing references)
					//IL_0045: 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)
					Vector3 position = p.Zdo.GetPosition();
					return new Json().Obj().Prop("tag", p.Tag).Prop("prefab", p.Info.Name)
						.Key("pos")
						.Pos(position)
						.Prop("biome", World.Biome(position))
						.Prop("paired", byTag[p.Tag] == 2)
						.Prop("sameTag", byTag[p.Tag])
						.EndObj()
						.ToString();
				}).ToList()
			};
		}
	}
	internal class Builds : PagedCommand
	{
		public override string Command => "rtBuilds";

		public override string Description => "Build pieces per creator (name when known). Usage: rtBuilds [-near x z r] [-offset n]";

		protected override Result Produce(Args args)
		{
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			Dictionary<long, int> dictionary = new Dictionary<long, int>();
			foreach (ZDO item in World.All())
			{
				long num = item.GetLong(ZDOVars.s_creator, 0L);
				if (num != 0L && args.InRange(item.GetPosition()))
				{
					dictionary.TryGetValue(num, out var value);
					dictionary[num] = value + 1;
				}
			}
			return new Result
			{
				Items = (from kv in dictionary
					orderby kv.Value descending
					select new Json().Obj().Prop("playerId", kv.Key).Prop("name", PlayerNames.Get(kv.Key))
						.Prop("pieces", kv.Value)
						.EndObj()
						.ToString()).ToList()
			};
		}
	}
	internal abstract class RtCommand : RconCommand
	{
		protected override string OnHandle(CommandArgs args)
		{
			if (ZDOMan.instance == null || (Object)(object)ZNet.instance == (Object)null)
			{
				return new Json().Obj().Prop("error", "world not loaded").EndObj()
					.ToString();
			}
			try
			{
				return Handle(new Args(args.Arguments), string.Join(" ", args.Arguments));
			}
			catch (Exception ex)
			{
				return new Json().Obj().Prop("error", ex.Message).EndObj()
					.ToString();
			}
		}

		protected abstract string Handle(Args args, string raw);
	}
	internal sealed class Result
	{
		public List<string> Items = new List<string>();

		public string Extra;
	}
	internal abstract class PagedCommand : RtCommand
	{
		private static readonly Dictionary<string, (float At, Result R)> Snapshots = new Dictionary<string, (float, Result)>();

		protected override string Handle(Args args, string raw)
		{
			string key = ((RconCommand)this).Command + " " + Args.WithoutOffset(raw);
			Result result;
			if (args.Offset == 0 || !Snapshots.TryGetValue(key, out (float, Result) value) || Time.time - value.Item1 > 60f)
			{
				result = Produce(args);
				foreach (string item in (from kv in Snapshots
					where Time.time - kv.Value.At > 60f
					select kv.Key).ToList())
				{
					Snapshots.Remove(item);
				}
				Snapshots[key] = (Time.time, result);
			}
			else
			{
				result = value.Item2;
			}
			return Pager.Page(result.Items, args.Offset, result.Extra);
		}

		protected abstract Result Produce(Args args);
	}
	internal sealed class Stored
	{
		public ZDO Zdo;

		public World.PrefabInfo Info;

		public string Label;

		public Contents Contents;

		public static List<Stored> Scan(Args args)
		{
			//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_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			List<World.SignText> signs = WorldIndex.Signs();
			List<Stored> list = new List<Stored>();
			foreach (ZDO item in WorldIndex.Containers())
			{
				World.PrefabInfo prefabInfo = World.Info(item);
				if (World.IsStorage(item, prefabInfo, args.All))
				{
					Vector3 position = item.GetPosition();
					if (args.InRange(position))
					{
						list.Add(new Stored
						{
							Zdo = item,
							Info = prefabInfo,
							Label = World.LabelFor(position, signs),
							Contents = InventoryCache.Get(item, prefabInfo.Container)
						});
					}
				}
			}
			PlayerNames.Save();
			return list;
		}

		public static bool Matches(string id, (string Label, string English, int Count) item, string query)
		{
			if (!Has(id, query) && !Has(item.Label, query))
			{
				return Has(item.English, query);
			}
			return true;
		}

		public static bool Has(string s, string q)
		{
			if (s != null)
			{
				return s.IndexOf(q, StringComparison.OrdinalIgnoreCase) >= 0;
			}
			return false;
		}

		public Json Head(Json j)
		{
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			return j.Prop("id", ((object)Unsafe.As<ZDOID, ZDOID>(ref Zdo.m_uid)/*cast due to .constrained prefix*/).ToString()).Prop("prefab", Info.Name).Prop("label", Label)
				.Key("pos")
				.Pos(Zdo.GetPosition());
		}
	}
	internal class Containers : PagedCommand
	{
		public override string Command => "rtContainers";

		public override string Description => "Player storage (chests, carts, ships) with label from the nearest sign. Usage: rtContainers [-near x z r] [-all] [-offset n]";

		protected override Result Produce(Args args)
		{
			return new Result
			{
				Items = (from s in Stored.Scan(args)
					orderby s.Label == null, s.Label
					select s.Head(new Json().Obj()).Prop("slots", s.Contents.Slots).Prop("capacity", s.Info.Container.m_width * s.Info.Container.m_height)
						.EndObj()
						.ToString()).ToList()
			};
		}
	}
	internal class ContainerContents : PagedCommand
	{
		public override string Command => "rtContainer";

		public override string Description => "Contents of one container, aggregated by item. Usage: rtContainer <id|sign text> [-offset n]";

		protected override Result Produce(Args args)
		{
			string key = args.Text;
			if (key.Length == 0)
			{
				throw new ArgumentException("usage: rtContainer <id|sign text>");
			}
			List<Stored> source = Stored.Scan(new Args(new string[1] { "-all" }));
			Stored stored = source.FirstOrDefault((Stored x) => ((object)Unsafe.As<ZDOID, ZDOID>(ref x.Zdo.m_uid)/*cast due to .constrained prefix*/).ToString() == key) ?? source.FirstOrDefault((Stored x) => Stored.Has(x.Label, key)) ?? throw new ArgumentException("no container matching " + key);
			return new Result
			{
				Items = (from kv in stored.Contents.Items
					orderby kv.Value.Count descending
					select new Json().Obj().Prop("item", kv.Key).Prop("name", kv.Value.Label)
						.Prop("count", kv.Value.Count)
						.EndObj()
						.ToString()).ToList(),
				Extra = "\"container\":" + stored.Head(new Json().Obj()).EndObj()
			};
		}
	}
	internal class Find : PagedCommand
	{
		public override string Command => "rtFind";

		public override string Description => "Containers holding an item (substring of prefab, translated or English name), biggest stacks first. Usage: rtFind <query> [-near x z r] [-offset n]";

		protected override Result Produce(Args args)
		{
			string q = args.Text;
			if (q.Length == 0)
			{
				throw new ArgumentException("usage: rtFind <query>");
			}
			List<(Stored, List<KeyValuePair<string, (string, string, int)>>, int)> list = new List<(Stored, List<KeyValuePair<string, (string, string, int)>>, int)>();
			foreach (Stored item in Stored.Scan(args))
			{
				List<KeyValuePair<string, (string, string, int)>> list2 = item.Contents.Items.Where((KeyValuePair<string, (string Label, string English, int Count)> kv) => Stored.Matches(kv.Key, kv.Value, q)).ToList();
				if (list2.Count > 0)
				{
					list.Add((item, list2, list2.Sum<KeyValuePair<string, (string, string, int)>>((KeyValuePair<string, (string Label, string English, int Count)> kv) => kv.Value.Count)));
				}
			}
			Json json = new Json().Obj();
			foreach (IGrouping<string, KeyValuePair<string, (string, string, int)>> item2 in from kv in list.SelectMany<(Stored, List<KeyValuePair<string, (string, string, int)>>, int), KeyValuePair<string, (string, string, int)>>(((Stored S, List<KeyValuePair<string, (string Label, string English, int Count)>> Items, int Total) h) => h.Items)
				group kv by kv.Key)
			{
				json.Prop(item2.First().Value.Item1, item2.Sum<KeyValuePair<string, (string, string, int)>>((KeyValuePair<string, (string Label, string English, int Count)> kv) => kv.Value.Count));
			}
			return new Result
			{
				Items = list.OrderByDescending<(Stored, List<KeyValuePair<string, (string, string, int)>>, int), int>(((Stored S, List<KeyValuePair<string, (string Label, string English, int Count)>> Items, int Total) h) => h.Total).Select<(Stored, List<KeyValuePair<string, (string, string, int)>>, int), string>(delegate((Stored S, List<KeyValuePair<string, (string Label, string English, int Count)>> Items, int Total) h)
				{
					Json json2 = h.S.Head(new Json().Obj()).Key("items").Arr();
					foreach (KeyValuePair<string, (string, string, int)> item3 in h.Items.OrderByDescending((KeyValuePair<string, (string Label, string English, int Count)> kv) => kv.Value.Count))
					{
						json2.Obj().Prop("item", item3.Key).Prop("name", item3.Value.Item1)
							.Prop("count", item3.Value.Item3)
							.EndObj();
					}
					return json2.EndArr().EndObj().ToString();
				}).ToList(),
				Extra = "\"totals\":" + json.EndObj()
			};
		}
	}
	internal class Stock : PagedCommand
	{
		public override string Command => "rtStock";

		public override string Description => "Total of every item across player storage, largest first. Usage: rtStock [query] [-near x z r] [-offset n]";

		protected override Result Produce(Args args)
		{
			string text = args.Text;
			Dictionary<string, (string, int, int)> dictionary = new Dictionary<string, (string, int, int)>();
			foreach (Stored item in Stored.Scan(args))
			{
				foreach (KeyValuePair<string, (string, string, int)> item2 in item.Contents.Items)
				{
					if (text.Length <= 0 || Stored.Matches(item2.Key, item2.Value, text))
					{
						dictionary.TryGetValue(item2.Key, out var value);
						dictionary[item2.Key] = (item2.Value.Item1, value.Item2 + item2.Value.Item3, value.Item3 + 1);
					}
				}
			}
			return new Result
			{
				Items = (from kv in dictionary
					orderby kv.Value.Count descending
					select new Json().Obj().Prop("item", kv.Key).Prop("name", kv.Value.Label)
						.Prop("count", kv.Value.Count)
						.Prop("containers", kv.Value.Containers)
						.EndObj()
						.ToString()).ToList()
			};
		}
	}
	internal class JournalCommand : PagedCommand
	{
		public override string Command => "rtJournal";

		public override string Description => "Chest journal, newest first: who added/took what. Usage: rtJournal [item or chest] [-player name] [-near x z r] [-days n] [-offset n]";

		protected override Result Produce(Args args)
		{
			//IL_0092: Unknown result type (might be due to invalid IL or missing references)
			string text = args.Text;
			long num = ((args.Days > 0f) ? (Events.Now - (long)(args.Days * 86400000f)) : 0);
			List<string> list = new List<string>();
			for (int num2 = Tracker.Journal.Count - 1; num2 >= 0; num2--)
			{
				JournalEntry journalEntry = Tracker.Journal[num2];
				if (journalEntry.T < num)
				{
					break;
				}
				if ((args.Player == null || string.Equals(journalEntry.Player, args.Player, StringComparison.OrdinalIgnoreCase)) && args.InRange(new Vector3(journalEntry.X, 0f, journalEntry.Z)) && (text.Length <= 0 || Stored.Has(journalEntry.Item, text) || Stored.Has(journalEntry.Label, text) || Stored.Has(journalEntry.ContainerLabel, text)))
				{
					list.Add(new Json().Obj().Prop("t", journalEntry.T).Prop("player", journalEntry.Player)
						.Prop("delta", journalEntry.Delta)
						.Prop("item", journalEntry.Item)
						.Prop("name", journalEntry.Label)
						.Prop("container", journalEntry.Container)
						.Prop("label", journalEntry.ContainerLabel)
						.Key("pos")
						.Arr()
						.Val(journalEntry.X)
						.Val(journalEntry.Z)
						.EndArr()
						.EndObj()
						.ToString());
				}
			}
			return new Result
			{
				Items = list
			};
		}
	}
	internal class WorldInfo : RtCommand
	{
		public override string Command => "rtWorld";

		public override string Description => "World overview as JSON: day, time, active raid, global keys, players online. Usage: rtWorld";

		protected override string Handle(Args args, string raw)
		{
			Json json = new Json().Obj();
			if ((Object)(object)EnvMan.instance != (Object)null)
			{
				int num = (int)(EnvMan.instance.GetDayFraction() * 24f * 60f);
				json.Prop("day", EnvMan.instance.GetDay()).Prop("time", $"{num / 60:00}:{num % 60:00}");
			}
			RandEventSystem instance = RandEventSystem.instance;
			RandomEvent val = (((Object)(object)instance != (Object)null) ? (instance.GetCurrentRandomEvent() ?? instance.m_forcedEvent) : null);
			json.Key("raid");
			if (val != null)
			{
				json.Val(val.m_name);
			}
			else
			{
				json.Null();
			}
			json.Key("globalKeys").Arr();
			foreach (string globalKey in ZoneSystem.instance.GetGlobalKeys())
			{
				json.Val(globalKey);
			}
			json.EndArr();
			json.Prop("players", ZNet.instance.GetPeers().Count).Prop("objects", ZDOMan.instance.m_objectsByID.Count).Prop("indexScanMs", WorldIndex.LastScanMs)
				.Prop("boot", Events.Boot)
				.Prop("seq", Events.Seq)
				.EndObj();
			return json.ToString();
		}
	}
	internal class Players : PagedCommand
	{
		public override string Command => "rtPlayers";

		public override string Description => "Online players as JSON with position, biome and health. Usage: rtPlayers";

		protected override Result Produce(Args args)
		{
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_0087: Unknown result type (might be due to invalid IL or missing references)
			//IL_0093: Unknown result type (might be due to invalid IL or missing references)
			List<string> list = new List<string>();
			foreach (ZNetPeer peer in ZNet.instance.GetPeers())
			{
				ZDO zDO = ZDOMan.instance.GetZDO(peer.m_characterID);
				Vector3 val = ((zDO != null) ? zDO.GetPosition() : peer.m_refPos);
				Json json = new Json().Obj().Prop("name", peer.m_playerName);
				ISocket socket = peer.m_socket;
				Json json2 = json.Prop("host", (socket != null) ? socket.GetHostName() : null).Key("pos").Pos(val)
					.Prop("biome", World.Biome(val));
				if (zDO != null)
				{
					long num = zDO.GetLong(ZDOVars.s_playerID, 0L);
					PlayerNames.Learn(num, zDO.GetString(ZDOVars.s_playerName, ""));
					json2.Prop("playerId", num).Prop("health", zDO.GetFloat(ZDOVars.s_health, 0f)).Prop("dead", zDO.GetBool(ZDOVars.s_dead, false));
				}
				list.Add(json2.EndObj().ToString());
			}
			return new Result
			{
				Items = list
			};
		}
	}
	internal class Prefabs : PagedCommand
	{
		public override string Command => "rtPrefabs";

		public override string Description => "Object counts by prefab, most frequent first. Usage: rtPrefabs [-near x z radius] [-offset n]";

		protected override Result Produce(Args args)
		{
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			Dictionary<string, int> dictionary = new Dictionary<string, int>();
			foreach (ZDO item in World.All())
			{
				if (args.InRange(item.GetPosition()))
				{
					string name = World.Info(item).Name;
					dictionary.TryGetValue(name, out var value);
					dictionary[name] = value + 1;
				}
			}
			return new Result
			{
				Items = (from kv in dictionary
					orderby kv.Value descending
					select new Json().Obj().Prop("prefab", kv.Key).Prop("count", kv.Value)
						.EndObj()
						.ToString()).ToList()
			};
		}
	}
	internal class EventsCommand : RtCommand
	{
		public override string Command => "rtEvents";

		public override string Description => "World events after a sequence number (join, leave, death, biome, boss, raid, raidEnd, chest). Usage: rtEvents [-since seq]";

		protected override string Handle(Args args, string raw)
		{
			return Pager.Page(Events.Since(args.Since), 0, $"\"boot\":\"{Events.Boot}\",\"seq\":{Events.Seq}");
		}
	}
	internal class Playtime : PagedCommand
	{
		public override string Command => "rtPlaytime";

		public override string Description => "Play time per player (closed + ongoing sessions). Usage: rtPlaytime [-days n] [-offset n]";

		protected override Result Produce(Args args)
		{
			long now = Events.Now;
			long cutoff = ((args.Days > 0f) ? (now - (long)(args.Days * 86400000f)) : 0);
			IOrderedEnumerable<(string, long, int, long)> source = from s in Tracker.Sessions.Concat(Tracker.OpenSessions())
				where s.End > cutoff
				group s by s.Name into g
				select (Name: g.Key, Seconds: g.Sum((Session s) => (s.End - Math.Max(s.Start, cutoff)) / 1000), Sessions: g.Count(), LastSeen: g.Max((Session s) => s.End)) into r
				orderby r.Seconds descending
				select r;
			return new Result
			{
				Items = source.Select<(string, long, int, long), string>(((string Name, long Seconds, int Sessions, long LastSeen) r) => new Json().Obj().Prop("name", r.Name).Prop("seconds", r.Seconds)
					.Prop("sessions", r.Sessions)
					.Prop("lastSeen", r.LastSeen)
					.EndObj()
					.ToString()).ToList()
			};
		}
	}
}
namespace System.Runtime.CompilerServices
{
	[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
	internal sealed class IgnoresAccessChecksToAttribute : Attribute
	{
		public IgnoresAccessChecksToAttribute(string assemblyName)
		{
		}
	}
}