using System; using System.Collections; using System.Collections.Generic; using System.Collections.Specialized; using System.Diagnostics; using System.Dynamic; using System.Globalization; using System.IO; using System.IO.Compression; using System.Linq; using System.Net; using System.Reflection; using System.Reflection.Emit; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Serialization; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using System.Text; using System.Text.RegularExpressions; using System.Threading; using System.Xml.Serialization; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using Forteca_ServerRewards; using HarmonyLib; using ItemManager; using JetBrains.Annotations; using Microsoft.CodeAnalysis; using Splatform; using TMPro; using UnityEngine; using UnityEngine.Events; using UnityEngine.UI; using fastJSON; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: Guid("304AA6D2-0783-4A5A-B05B-87001CDAF792")] [assembly: ComVisible(false)] [assembly: AssemblyTrademark("")] [assembly: AssemblyCopyright("Copyright © 2022")] [assembly: AssemblyProduct("Forteca_ServerRewards")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyDescription("")] [assembly: AssemblyTitle("Forteca_ServerRewards")] [assembly: AssemblyCompany("")] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.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.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } [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 ServerSync { [PublicAPI] public class ConfigSync { [HarmonyPatch(typeof(ZRpc), "HandlePackage")] private static class SnatchCurrentlyHandlingRPC { public static ZRpc? currentRpc; [HarmonyPrefix] private static void Prefix(ZRpc __instance) { currentRpc = __instance; } } [HarmonyPatch(typeof(ZNet), "Awake")] internal static class RegisterRPCPatch { [HarmonyPostfix] private static void Postfix(ZNet __instance) { isServer = __instance.IsServer(); foreach (ConfigSync configSync2 in configSyncs) { ZRoutedRpc.instance.Register(configSync2.Name + " ConfigSync", (Action)configSync2.RPC_FromOtherClientConfigSync); if (isServer) { configSync2.InitialSyncDone = true; Debug.Log((object)("Registered '" + configSync2.Name + " ConfigSync' RPC - waiting for incoming connections")); } } if (isServer) { ((MonoBehaviour)__instance).StartCoroutine(WatchAdminListChanges()); } static void SendAdmin(List peers, bool isAdmin) { ZPackage package = ConfigsToPackage(null, null, new PackageEntry[1] { new PackageEntry { section = "Internal", key = "lockexempt", type = typeof(bool), value = isAdmin } }); ConfigSync configSync = configSyncs.First(); if (configSync != null) { ((MonoBehaviour)ZNet.instance).StartCoroutine(configSync.sendZPackage(peers, package)); } } static IEnumerator WatchAdminListChanges() { MethodInfo listContainsId = AccessTools.DeclaredMethod(typeof(ZNet), "ListContainsId", (Type[])null, (Type[])null); SyncedList adminList = (SyncedList)AccessTools.DeclaredField(typeof(ZNet), "m_adminList").GetValue(ZNet.instance); List CurrentList = new List(adminList.GetList()); while (true) { yield return (object)new WaitForSeconds(30f); if (!adminList.GetList().SequenceEqual(CurrentList)) { CurrentList = new List(adminList.GetList()); List list = ZNet.instance.GetPeers().Where(delegate(ZNetPeer p) { string hostName = p.m_rpc.GetSocket().GetHostName(); return ((object)listContainsId == null) ? adminList.Contains(hostName) : ((bool)listContainsId.Invoke(ZNet.instance, new object[2] { adminList, hostName })); }).ToList(); SendAdmin(ZNet.instance.GetPeers().Except(list).ToList(), isAdmin: false); SendAdmin(list, isAdmin: true); } } } } } [HarmonyPatch(typeof(ZNet), "OnNewConnection")] private static class RegisterClientRPCPatch { [HarmonyPostfix] private static void Postfix(ZNet __instance, ZNetPeer peer) { if (__instance.IsServer()) { return; } foreach (ConfigSync configSync in configSyncs) { peer.m_rpc.Register(configSync.Name + " ConfigSync", (Action)configSync.RPC_FromServerConfigSync); } } } private class ParsedConfigs { public readonly Dictionary configValues = new Dictionary(); public readonly Dictionary customValues = new Dictionary(); } [HarmonyPatch(typeof(ZNet), "Shutdown")] private class ResetConfigsOnShutdown { [HarmonyPostfix] private static void Postfix() { ProcessingServerUpdate = true; foreach (ConfigSync configSync in configSyncs) { configSync.resetConfigsFromServer(); configSync.IsSourceOfTruth = true; configSync.InitialSyncDone = false; } ProcessingServerUpdate = false; } } [HarmonyPatch(typeof(ZNet), "RPC_PeerInfo")] private class SendConfigsAfterLogin { private class BufferingSocket : ISocket { public volatile bool finished; public volatile int versionMatchQueued = -1; public readonly List Package = new List(); public readonly ISocket Original; public BufferingSocket(ISocket original) { Original = original; } public bool IsConnected() { return Original.IsConnected(); } public ZPackage Recv() { return Original.Recv(); } public int GetSendQueueSize() { return Original.GetSendQueueSize(); } public int GetCurrentSendRate() { return Original.GetCurrentSendRate(); } public bool IsHost() { return Original.IsHost(); } public void Dispose() { Original.Dispose(); } public bool GotNewData() { return Original.GotNewData(); } public void Close() { Original.Close(); } public string GetEndPointString() { return Original.GetEndPointString(); } public void GetAndResetStats(out int totalSent, out int totalRecv) { Original.GetAndResetStats(ref totalSent, ref totalRecv); } public void GetConnectionQuality(out float localQuality, out float remoteQuality, out int ping, out float outByteSec, out float inByteSec) { Original.GetConnectionQuality(ref localQuality, ref remoteQuality, ref ping, ref outByteSec, ref inByteSec); } public ISocket Accept() { return Original.Accept(); } public int GetHostPort() { return Original.GetHostPort(); } public bool Flush() { return Original.Flush(); } public string GetHostName() { return Original.GetHostName(); } public void VersionMatch() { if (finished) { Original.VersionMatch(); } else { versionMatchQueued = Package.Count; } } public void Send(ZPackage pkg) { //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Expected O, but got Unknown int pos = pkg.GetPos(); pkg.SetPos(0); int num = pkg.ReadInt(); if ((num == StringExtensionMethods.GetStableHashCode("PeerInfo") || num == StringExtensionMethods.GetStableHashCode("RoutedRPC") || num == StringExtensionMethods.GetStableHashCode("ZDOData")) && !finished) { ZPackage val = new ZPackage(pkg.GetArray()); val.SetPos(pos); Package.Add(val); } else { pkg.SetPos(pos); Original.Send(pkg); } } } [HarmonyPrefix] [HarmonyPriority(800)] private static void Prefix(ref Dictionary? __state, ZNet __instance, ZRpc rpc) { //IL_0077: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Expected O, but got Unknown //IL_0080: Unknown result type (might be due to invalid IL or missing references) if (__instance.IsServer()) { BufferingSocket value = new BufferingSocket(rpc.GetSocket()); AccessTools.DeclaredField(typeof(ZRpc), "m_socket").SetValue(rpc, value); object obj = AccessTools.DeclaredMethod(typeof(ZNet), "GetPeer", new Type[1] { typeof(ZRpc) }, (Type[])null).Invoke(__instance, new object[1] { rpc }); ZNetPeer val = (ZNetPeer)((obj is ZNetPeer) ? obj : null); if (val != null && (int)ZNet.m_onlineBackend != 0) { AccessTools.DeclaredField(typeof(ZNetPeer), "m_socket").SetValue(val, value); } if (__state == null) { __state = new Dictionary(); } __state[Assembly.GetExecutingAssembly()] = value; } } [HarmonyTranspiler] private static IEnumerable Transpiler(IEnumerable instructions) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Expected O, but got Unknown //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Expected O, but got Unknown //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Expected O, but got Unknown //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Expected O, but got Unknown //IL_0084: Unknown result type (might be due to invalid IL or missing references) //IL_008a: Expected O, but got Unknown CodeMatcher val = new CodeMatcher(instructions, (ILGenerator)null); FieldInfo fieldInfo = AccessTools.Field(typeof(ZNetPeer), "m_socket"); FieldInfo fieldInfo2 = AccessTools.Field(typeof(ZPlayFabSocket), "m_remotePlayerId"); val.MatchForward(false, (CodeMatch[])(object)new CodeMatch[4] { new CodeMatch((OpCode?)OpCodes.Ldloc_1, (object)null, (string)null), new CodeMatch((OpCode?)OpCodes.Ldfld, (object)fieldInfo, (string)null), new CodeMatch((OpCode?)OpCodes.Isinst, (object)null, (string)null), new CodeMatch((OpCode?)OpCodes.Ldfld, (object)fieldInfo2, (string)null) }); if (val.IsInvalid) { return instructions; } val.SetAndAdvance(OpCodes.Ldstr, (object)"none"); val.SetOpcodeAndAdvance(OpCodes.Nop); val.SetOpcodeAndAdvance(OpCodes.Nop); val.SetOpcodeAndAdvance(OpCodes.Nop); return val.InstructionEnumeration(); } [HarmonyPostfix] private static void Postfix(Dictionary __state, ZNet __instance, ZRpc rpc) { //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_0082: Expected O, but got Unknown ZNetPeer peer; if (__instance.IsServer()) { object obj = AccessTools.DeclaredMethod(typeof(ZNet), "GetPeer", new Type[1] { typeof(ZRpc) }, (Type[])null).Invoke(__instance, new object[1] { rpc }); peer = (ZNetPeer)((obj is ZNetPeer) ? obj : null); if (peer == null) { SendBufferedData(); } else { ((MonoBehaviour)__instance).StartCoroutine(sendAsync()); } } void SendBufferedData() { //IL_008b: Unknown result type (might be due to invalid IL or missing references) //IL_0091: Expected O, but got Unknown if (rpc.GetSocket() is BufferingSocket bufferingSocket) { AccessTools.DeclaredField(typeof(ZRpc), "m_socket").SetValue(rpc, bufferingSocket.Original); object obj2 = AccessTools.DeclaredMethod(typeof(ZNet), "GetPeer", new Type[1] { typeof(ZRpc) }, (Type[])null).Invoke(__instance, new object[1] { rpc }); ZNetPeer val = (ZNetPeer)((obj2 is ZNetPeer) ? obj2 : null); if (val != null) { AccessTools.DeclaredField(typeof(ZNetPeer), "m_socket").SetValue(val, bufferingSocket.Original); } } BufferingSocket bufferingSocket2 = __state[Assembly.GetExecutingAssembly()]; bufferingSocket2.finished = true; for (int i = 0; i < bufferingSocket2.Package.Count; i++) { if (i == bufferingSocket2.versionMatchQueued) { bufferingSocket2.Original.VersionMatch(); } bufferingSocket2.Original.Send(bufferingSocket2.Package[i]); } if (bufferingSocket2.Package.Count == bufferingSocket2.versionMatchQueued) { bufferingSocket2.Original.VersionMatch(); } } IEnumerator sendAsync() { foreach (ConfigSync configSync in configSyncs) { List list = new List(); if (configSync.CurrentVersion != null) { list.Add(new PackageEntry { section = "Internal", key = "serverversion", type = typeof(string), value = configSync.CurrentVersion }); } MethodInfo methodInfo = AccessTools.DeclaredMethod(typeof(ZNet), "ListContainsId", (Type[])null, (Type[])null); SyncedList val = (SyncedList)AccessTools.DeclaredField(typeof(ZNet), "m_adminList").GetValue(ZNet.instance); list.Add(new PackageEntry { section = "Internal", key = "lockexempt", type = typeof(bool), value = (((object)methodInfo == null) ? ((object)val.Contains(rpc.GetSocket().GetHostName())) : methodInfo.Invoke(ZNet.instance, new object[2] { val, rpc.GetSocket().GetHostName() })) }); ZPackage package = ConfigsToPackage(configSync.allConfigs.Select((OwnConfigEntryBase c) => c.BaseConfig), configSync.allCustomValues, list, partial: false); yield return ((MonoBehaviour)__instance).StartCoroutine(configSync.sendZPackage(new List { peer }, package)); } SendBufferedData(); } } } private class PackageEntry { public string section; public string key; public Type type; public object? value; } [HarmonyPatch(typeof(ConfigEntryBase), "GetSerializedValue")] private static class PreventSavingServerInfo { [HarmonyPrefix] private static bool Prefix(ConfigEntryBase __instance, ref string __result) { OwnConfigEntryBase ownConfigEntryBase = configData(__instance); if (ownConfigEntryBase == null || isWritableConfig(ownConfigEntryBase)) { return true; } __result = TomlTypeConverter.ConvertToString(ownConfigEntryBase.LocalBaseValue, __instance.SettingType); return false; } } [HarmonyPatch(typeof(ConfigEntryBase), "SetSerializedValue")] private static class PreventConfigRereadChangingValues { [HarmonyPrefix] private static bool Prefix(ConfigEntryBase __instance, string value) { OwnConfigEntryBase ownConfigEntryBase = configData(__instance); if (ownConfigEntryBase == null || ownConfigEntryBase.LocalBaseValue == null) { return true; } try { ownConfigEntryBase.LocalBaseValue = TomlTypeConverter.ConvertToValue(value, __instance.SettingType); } catch (Exception ex) { Debug.LogWarning((object)$"Config value of setting \"{__instance.Definition}\" could not be parsed and will be ignored. Reason: {ex.Message}; Value: {value}"); } return false; } } private class InvalidDeserializationTypeException : Exception { public string expected; public string received; public string field = ""; } public static bool ProcessingServerUpdate; public readonly string Name; public string? DisplayName; public string? CurrentVersion; public string? MinimumRequiredVersion; public bool ModRequired; private bool? forceConfigLocking; private bool isSourceOfTruth = true; private static readonly HashSet configSyncs; private readonly HashSet allConfigs = new HashSet(); private HashSet allCustomValues = new HashSet(); private static bool isServer; private static bool lockExempt; private OwnConfigEntryBase? lockedConfig; private const byte PARTIAL_CONFIGS = 1; private const byte FRAGMENTED_CONFIG = 2; private const byte COMPRESSED_CONFIG = 4; private readonly Dictionary> configValueCache = new Dictionary>(); private readonly List> cacheExpirations = new List>(); private static long packageCounter; public bool IsLocked { get { bool? flag = forceConfigLocking; bool flag2; if (!flag.HasValue) { if (lockedConfig == null) { goto IL_0051; } flag2 = ((IConvertible)lockedConfig.BaseConfig.BoxedValue).ToInt32(CultureInfo.InvariantCulture) != 0; } else { flag2 = flag == true; } if (flag2) { return !lockExempt; } goto IL_0051; IL_0051: return false; } set { forceConfigLocking = value; } } public bool IsAdmin { get { if (!lockExempt) { return isSourceOfTruth; } return true; } } public bool IsSourceOfTruth { get { return isSourceOfTruth; } private set { if (value != isSourceOfTruth) { isSourceOfTruth = value; this.SourceOfTruthChanged?.Invoke(value); } } } public bool InitialSyncDone { get; private set; } public event Action? SourceOfTruthChanged; private event Action? lockedConfigChanged; static ConfigSync() { ProcessingServerUpdate = false; configSyncs = new HashSet(); lockExempt = false; packageCounter = 0L; RuntimeHelpers.RunClassConstructor(typeof(VersionCheck).TypeHandle); } public ConfigSync(string name) { Name = name; configSyncs.Add(this); new VersionCheck(this); } public SyncedConfigEntry AddConfigEntry(ConfigEntry configEntry) { //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Expected O, but got Unknown OwnConfigEntryBase ownConfigEntryBase = configData((ConfigEntryBase)configEntry); SyncedConfigEntry syncedEntry = ownConfigEntryBase as SyncedConfigEntry; if (syncedEntry == null) { syncedEntry = new SyncedConfigEntry(configEntry); AccessTools.DeclaredField(typeof(ConfigDescription), "k__BackingField").SetValue(((ConfigEntryBase)configEntry).Description, new object[1] { new ConfigurationManagerAttributes() }.Concat(((ConfigEntryBase)configEntry).Description.Tags ?? Array.Empty()).Concat(new SyncedConfigEntry[1] { syncedEntry }).ToArray()); configEntry.SettingChanged += delegate { if (!ProcessingServerUpdate && syncedEntry.SynchronizedConfig) { Broadcast(ZRoutedRpc.Everybody, (ConfigEntryBase)configEntry); } }; allConfigs.Add(syncedEntry); } return syncedEntry; } public SyncedConfigEntry AddLockingConfigEntry(ConfigEntry lockingConfig) where T : IConvertible { if (lockedConfig != null) { throw new Exception("Cannot initialize locking ConfigEntry twice"); } lockedConfig = AddConfigEntry(lockingConfig); lockingConfig.SettingChanged += delegate { this.lockedConfigChanged?.Invoke(); }; return (SyncedConfigEntry)lockedConfig; } internal void AddCustomValue(CustomSyncedValueBase customValue) { if (allCustomValues.Select((CustomSyncedValueBase v) => v.Identifier).Concat(new string[1] { "serverversion" }).Contains(customValue.Identifier)) { throw new Exception("Cannot have multiple settings with the same name or with a reserved name (serverversion)"); } allCustomValues.Add(customValue); allCustomValues = new HashSet(allCustomValues.OrderByDescending((CustomSyncedValueBase v) => v.Priority)); CustomSyncedValueBase customSyncedValueBase = customValue; customSyncedValueBase.ValueChanged = (Action)Delegate.Combine(customSyncedValueBase.ValueChanged, (Action)delegate { if (!ProcessingServerUpdate) { Broadcast(ZRoutedRpc.Everybody, customValue); } }); } private void RPC_FromServerConfigSync(ZRpc rpc, ZPackage package) { lockedConfigChanged += serverLockedSettingChanged; IsSourceOfTruth = false; if (HandleConfigSyncRPC(0L, package, clientUpdate: false)) { InitialSyncDone = true; } } private void RPC_FromOtherClientConfigSync(long sender, ZPackage package) { HandleConfigSyncRPC(sender, package, clientUpdate: true); } private bool HandleConfigSyncRPC(long sender, ZPackage package, bool clientUpdate) { //IL_0220: Unknown result type (might be due to invalid IL or missing references) //IL_0227: Expected O, but got Unknown //IL_01cf: Unknown result type (might be due to invalid IL or missing references) //IL_01d6: Expected O, but got Unknown //IL_0081: Unknown result type (might be due to invalid IL or missing references) //IL_0088: Expected O, but got Unknown try { if (isServer && IsLocked) { ZRpc currentRpc = SnatchCurrentlyHandlingRPC.currentRpc; object obj; if (currentRpc == null) { obj = null; } else { ISocket socket = currentRpc.GetSocket(); obj = ((socket != null) ? socket.GetHostName() : null); } string text = (string)obj; if (text != null) { MethodInfo methodInfo = AccessTools.DeclaredMethod(typeof(ZNet), "ListContainsId", (Type[])null, (Type[])null); SyncedList val = (SyncedList)AccessTools.DeclaredField(typeof(ZNet), "m_adminList").GetValue(ZNet.instance); if (!(((object)methodInfo == null) ? val.Contains(text) : ((bool)methodInfo.Invoke(ZNet.instance, new object[2] { val, text })))) { return false; } } } cacheExpirations.RemoveAll(delegate(KeyValuePair kv) { if (kv.Key < DateTimeOffset.Now.Ticks) { configValueCache.Remove(kv.Value); return true; } return false; }); byte b = package.ReadByte(); if ((b & 2) != 0) { long num = package.ReadLong(); string text2 = sender.ToString() + num; if (!configValueCache.TryGetValue(text2, out var value)) { value = new SortedDictionary(); configValueCache[text2] = value; cacheExpirations.Add(new KeyValuePair(DateTimeOffset.Now.AddSeconds(60.0).Ticks, text2)); } int key = package.ReadInt(); int num2 = package.ReadInt(); value.Add(key, package.ReadByteArray()); if (value.Count < num2) { return false; } configValueCache.Remove(text2); package = new ZPackage(value.Values.SelectMany((byte[] a) => a).ToArray()); b = package.ReadByte(); } ProcessingServerUpdate = true; if ((b & 4) != 0) { MemoryStream stream = new MemoryStream(package.ReadByteArray()); MemoryStream memoryStream = new MemoryStream(); using (DeflateStream deflateStream = new DeflateStream(stream, CompressionMode.Decompress)) { deflateStream.CopyTo(memoryStream); } package = new ZPackage(memoryStream.ToArray()); b = package.ReadByte(); } if ((b & 1) == 0) { resetConfigsFromServer(); } ParsedConfigs parsedConfigs = ReadConfigsFromPackage(package); ConfigFile val2 = null; bool saveOnConfigSet = false; foreach (KeyValuePair configValue in parsedConfigs.configValues) { if (!isServer && configValue.Key.LocalBaseValue == null) { configValue.Key.LocalBaseValue = configValue.Key.BaseConfig.BoxedValue; } if (val2 == null) { val2 = configValue.Key.BaseConfig.ConfigFile; saveOnConfigSet = val2.SaveOnConfigSet; val2.SaveOnConfigSet = false; } configValue.Key.BaseConfig.BoxedValue = configValue.Value; } if (val2 != null) { val2.SaveOnConfigSet = saveOnConfigSet; } foreach (KeyValuePair customValue in parsedConfigs.customValues) { if (!isServer) { CustomSyncedValueBase key2 = customValue.Key; if (key2.LocalBaseValue == null) { key2.LocalBaseValue = customValue.Key.BoxedValue; } } customValue.Key.BoxedValue = customValue.Value; } Debug.Log((object)string.Format("Received {0} configs and {1} custom values from {2} for mod {3}", parsedConfigs.configValues.Count, parsedConfigs.customValues.Count, (isServer || clientUpdate) ? $"client {sender}" : "the server", DisplayName ?? Name)); if (!isServer) { serverLockedSettingChanged(); } return true; } finally { ProcessingServerUpdate = false; } } private ParsedConfigs ReadConfigsFromPackage(ZPackage package) { ParsedConfigs parsedConfigs = new ParsedConfigs(); Dictionary dictionary = allConfigs.Where((OwnConfigEntryBase c) => c.SynchronizedConfig).ToDictionary((OwnConfigEntryBase c) => c.BaseConfig.Definition.Section + "_" + c.BaseConfig.Definition.Key, (OwnConfigEntryBase c) => c); Dictionary dictionary2 = allCustomValues.ToDictionary((CustomSyncedValueBase c) => c.Identifier, (CustomSyncedValueBase c) => c); int num = package.ReadInt(); for (int num2 = 0; num2 < num; num2++) { string text = package.ReadString(); string text2 = package.ReadString(); string text3 = package.ReadString(); Type type = Type.GetType(text3); if (text3 == "" || type != null) { object obj; try { obj = ((text3 == "") ? null : ReadValueWithTypeFromZPackage(package, type)); } catch (InvalidDeserializationTypeException ex) { Debug.LogWarning((object)("Got unexpected struct internal type " + ex.received + " for field " + ex.field + " struct " + text3 + " for " + text2 + " in section " + text + " for mod " + (DisplayName ?? Name) + ", expecting " + ex.expected)); continue; } OwnConfigEntryBase value2; if (text == "Internal") { CustomSyncedValueBase value; if (text2 == "serverversion") { if (obj?.ToString() != CurrentVersion) { Debug.LogWarning((object)("Received server version is not equal: server version = " + (obj?.ToString() ?? "null") + "; local version = " + (CurrentVersion ?? "unknown"))); } } else if (text2 == "lockexempt") { if (obj is bool flag) { lockExempt = flag; } } else if (dictionary2.TryGetValue(text2, out value)) { if ((text3 == "" && (!value.Type.IsValueType || Nullable.GetUnderlyingType(value.Type) != null)) || GetZPackageTypeString(value.Type) == text3) { parsedConfigs.customValues[value] = obj; continue; } Debug.LogWarning((object)("Got unexpected type " + text3 + " for internal value " + text2 + " for mod " + (DisplayName ?? Name) + ", expecting " + value.Type.AssemblyQualifiedName)); } } else if (dictionary.TryGetValue(text + "_" + text2, out value2)) { Type type2 = configType(value2.BaseConfig); if ((text3 == "" && (!type2.IsValueType || Nullable.GetUnderlyingType(type2) != null)) || GetZPackageTypeString(type2) == text3) { parsedConfigs.configValues[value2] = obj; continue; } Debug.LogWarning((object)("Got unexpected type " + text3 + " for " + text2 + " in section " + text + " for mod " + (DisplayName ?? Name) + ", expecting " + type2.AssemblyQualifiedName)); } else { Debug.LogWarning((object)("Received unknown config entry " + text2 + " in section " + text + " for mod " + (DisplayName ?? Name) + ". This may happen if client and server versions of the mod do not match.")); } continue; } Debug.LogWarning((object)("Got invalid type " + text3 + ", abort reading of received configs")); return new ParsedConfigs(); } return parsedConfigs; } private static bool isWritableConfig(OwnConfigEntryBase config) { ConfigSync configSync = configSyncs.FirstOrDefault((ConfigSync cs) => cs.allConfigs.Contains(config)); if (configSync == null) { return true; } if (!configSync.IsSourceOfTruth && config.SynchronizedConfig && config.LocalBaseValue != null) { if (!configSync.IsLocked) { if (config == configSync.lockedConfig) { return lockExempt; } return true; } return false; } return true; } private void serverLockedSettingChanged() { foreach (OwnConfigEntryBase allConfig in allConfigs) { configAttribute(allConfig.BaseConfig).ReadOnly = !isWritableConfig(allConfig); } } private void resetConfigsFromServer() { ConfigFile val = null; bool saveOnConfigSet = false; foreach (OwnConfigEntryBase item in allConfigs.Where((OwnConfigEntryBase config) => config.LocalBaseValue != null)) { if (val == null) { val = item.BaseConfig.ConfigFile; saveOnConfigSet = val.SaveOnConfigSet; val.SaveOnConfigSet = false; } item.BaseConfig.BoxedValue = item.LocalBaseValue; item.LocalBaseValue = null; } if (val != null) { val.SaveOnConfigSet = saveOnConfigSet; } foreach (CustomSyncedValueBase item2 in allCustomValues.Where((CustomSyncedValueBase config) => config.LocalBaseValue != null)) { item2.BoxedValue = item2.LocalBaseValue; item2.LocalBaseValue = null; } lockedConfigChanged -= serverLockedSettingChanged; serverLockedSettingChanged(); } private IEnumerator distributeConfigToPeers(ZNetPeer peer, ZPackage package) { ZRoutedRpc rpc = ZRoutedRpc.instance; if (rpc == null) { yield break; } byte[] data = package.GetArray(); if (data != null && data.LongLength > 250000) { int fragments = (int)(1 + (data.LongLength - 1) / 250000); long packageIdentifier = ++packageCounter; int fragment = 0; while (fragment < fragments) { foreach (bool item in waitForQueue()) { yield return item; } if (peer.m_socket.IsConnected()) { ZPackage val = new ZPackage(); val.Write((byte)2); val.Write(packageIdentifier); val.Write(fragment); val.Write(fragments); val.Write(data.Skip(250000 * fragment).Take(250000).ToArray()); SendPackage(val); if (fragment != fragments - 1) { yield return true; } int num = fragment + 1; fragment = num; continue; } break; } yield break; } foreach (bool item2 in waitForQueue()) { yield return item2; } SendPackage(package); void SendPackage(ZPackage pkg) { string text = Name + " ConfigSync"; if (isServer) { peer.m_rpc.Invoke(text, new object[1] { pkg }); } else { rpc.InvokeRoutedRPC(peer.m_server ? 0 : peer.m_uid, text, new object[1] { pkg }); } } IEnumerable waitForQueue() { float timeout = Time.time + 30f; while (peer.m_socket.GetSendQueueSize() > 20000) { if (Time.time > timeout) { Debug.Log((object)$"Disconnecting {peer.m_uid} after 30 seconds config sending timeout"); peer.m_rpc.Invoke("Error", new object[1] { 5 }); ZNet.instance.Disconnect(peer); break; } yield return false; } } } private IEnumerator sendZPackage(long target, ZPackage package) { if (!ValheimCompat.Exists((Object)(object)ZNet.instance)) { return Enumerable.Empty().GetEnumerator(); } List list = ValheimCompat.GetPeers(); if (target != ZRoutedRpc.Everybody) { list = list.Where((ZNetPeer p) => p.m_uid == target).ToList(); } return sendZPackage(list, package); } private IEnumerator sendZPackage(List peers, ZPackage package) { if (!ValheimCompat.Exists((Object)(object)ZNet.instance)) { yield break; } byte[] array = package.GetArray(); if (array != null && array.LongLength > 10000) { ZPackage val = new ZPackage(); val.Write((byte)4); MemoryStream memoryStream = new MemoryStream(); using (DeflateStream deflateStream = new DeflateStream(memoryStream, CompressionLevel.Optimal)) { deflateStream.Write(array, 0, array.Length); } val.Write(memoryStream.ToArray()); package = val; } List> writers = (from p in peers where p.IsReady() select distributeConfigToPeers(p, package)).ToList(); writers.RemoveAll((IEnumerator writer) => !writer.MoveNext()); while (writers.Count > 0) { yield return null; writers.RemoveAll((IEnumerator writer) => !writer.MoveNext()); } } private void Broadcast(long target, params ConfigEntryBase[] configs) { if (!IsLocked || isServer) { ZPackage package = ConfigsToPackage(configs); ZNet instance = ZNet.instance; if ((Object)(object)instance != (Object)null) { ((MonoBehaviour)instance).StartCoroutine(sendZPackage(target, package)); } } } private void Broadcast(long target, params CustomSyncedValueBase[] customValues) { if (!IsLocked || isServer) { ZPackage package = ConfigsToPackage(null, customValues); ZNet instance = ZNet.instance; if ((Object)(object)instance != (Object)null) { ((MonoBehaviour)instance).StartCoroutine(sendZPackage(target, package)); } } } private static OwnConfigEntryBase? configData(ConfigEntryBase config) { return config.Description.Tags?.OfType().SingleOrDefault(); } public static SyncedConfigEntry? ConfigData(ConfigEntry config) { return ((ConfigEntryBase)config).Description.Tags?.OfType>().SingleOrDefault(); } private static T configAttribute(ConfigEntryBase config) { return config.Description.Tags.OfType().First(); } private static Type configType(ConfigEntryBase config) { return configType(config.SettingType); } private static Type configType(Type type) { if (!type.IsEnum) { return type; } return Enum.GetUnderlyingType(type); } private static ZPackage ConfigsToPackage(IEnumerable? configs = null, IEnumerable? customValues = null, IEnumerable? packageEntries = null, bool partial = true) { //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Expected O, but got Unknown List list = configs?.Where((ConfigEntryBase config) => configData(config).SynchronizedConfig).ToList() ?? new List(); List list2 = customValues?.ToList() ?? new List(); ZPackage val = new ZPackage(); val.Write(partial ? ((byte)1) : ((byte)0)); val.Write(list.Count + list2.Count + (packageEntries?.Count() ?? 0)); foreach (PackageEntry item in packageEntries ?? Array.Empty()) { AddEntryToPackage(val, item); } foreach (CustomSyncedValueBase item2 in list2) { AddEntryToPackage(val, new PackageEntry { section = "Internal", key = item2.Identifier, type = item2.Type, value = item2.BoxedValue }); } foreach (ConfigEntryBase item3 in list) { AddEntryToPackage(val, new PackageEntry { section = item3.Definition.Section, key = item3.Definition.Key, type = configType(item3), value = item3.BoxedValue }); } return val; } private static void AddEntryToPackage(ZPackage package, PackageEntry entry) { package.Write(entry.section); package.Write(entry.key); package.Write((entry.value == null) ? "" : GetZPackageTypeString(entry.type)); AddValueToZPackage(package, entry.value); } private static string GetZPackageTypeString(Type type) { return type.AssemblyQualifiedName; } private static void AddValueToZPackage(ZPackage package, object? value) { Type type = value?.GetType(); if (value is Enum) { value = ((IConvertible)value).ToType(Enum.GetUnderlyingType(value.GetType()), CultureInfo.InvariantCulture); } else { if (value is ICollection collection) { package.Write(collection.Count); { foreach (object item in collection) { AddValueToZPackage(package, item); } return; } } if ((object)type != null && type.IsValueType && !type.IsPrimitive) { FieldInfo[] fields = type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); package.Write(fields.Length); FieldInfo[] array = fields; foreach (FieldInfo fieldInfo in array) { package.Write(GetZPackageTypeString(fieldInfo.FieldType)); AddValueToZPackage(package, fieldInfo.GetValue(value)); } return; } } ZRpc.Serialize(new object[1] { value }, ref package); } private static object ReadValueWithTypeFromZPackage(ZPackage package, Type type) { if ((object)type != null && type.IsValueType && !type.IsPrimitive && !type.IsEnum) { FieldInfo[] fields = type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); int num = package.ReadInt(); if (num != fields.Length) { throw new InvalidDeserializationTypeException { received = $"(field count: {num})", expected = $"(field count: {fields.Length})" }; } object uninitializedObject = FormatterServices.GetUninitializedObject(type); FieldInfo[] array = fields; foreach (FieldInfo fieldInfo in array) { string text = package.ReadString(); if (text != GetZPackageTypeString(fieldInfo.FieldType)) { throw new InvalidDeserializationTypeException { received = text, expected = GetZPackageTypeString(fieldInfo.FieldType), field = fieldInfo.Name }; } fieldInfo.SetValue(uninitializedObject, ReadValueWithTypeFromZPackage(package, fieldInfo.FieldType)); } return uninitializedObject; } if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Dictionary<, >)) { int num2 = package.ReadInt(); IDictionary dictionary = (IDictionary)Activator.CreateInstance(type); Type type2 = typeof(KeyValuePair<, >).MakeGenericType(type.GenericTypeArguments); FieldInfo field = type2.GetField("key", BindingFlags.Instance | BindingFlags.NonPublic); FieldInfo field2 = type2.GetField("value", BindingFlags.Instance | BindingFlags.NonPublic); for (int j = 0; j < num2; j++) { object obj = ReadValueWithTypeFromZPackage(package, type2); dictionary.Add(field.GetValue(obj), field2.GetValue(obj)); } return dictionary; } if (type != typeof(List) && type.IsGenericType) { Type type3 = typeof(ICollection<>).MakeGenericType(type.GenericTypeArguments[0]); if ((object)type3 != null && type3.IsAssignableFrom(type)) { int num3 = package.ReadInt(); object obj2 = Activator.CreateInstance(type); MethodInfo method = type3.GetMethod("Add"); for (int k = 0; k < num3; k++) { method.Invoke(obj2, new object[1] { ReadValueWithTypeFromZPackage(package, type.GenericTypeArguments[0]) }); } return obj2; } } ParameterInfo parameterInfo = (ParameterInfo)FormatterServices.GetUninitializedObject(typeof(ParameterInfo)); AccessTools.DeclaredField(typeof(ParameterInfo), "ClassImpl").SetValue(parameterInfo, type); List source = new List(); ZRpc.Deserialize(new ParameterInfo[2] { null, parameterInfo }, package, ref source); return source.First(); } } internal class ConfigurationManagerAttributes { [UsedImplicitly] public bool? ReadOnly = false; } [PublicAPI] public sealed class CustomSyncedValue : CustomSyncedValueBase { public T Value { get { return (T)base.BoxedValue; } set { base.BoxedValue = value; } } public void Update() { ValueChanged?.Invoke(); } public CustomSyncedValue(ConfigSync configSync, string identifier, T value = default(T), int priority = 0) : base(configSync, identifier, typeof(T), priority) { Value = value; } public void AssignLocalValue(T value) { if (localIsOwner) { Value = value; } else { LocalBaseValue = value; } } } public abstract class CustomSyncedValueBase { public Action? ValueChanged; public object? LocalBaseValue; public readonly string Identifier; public readonly Type Type; private object? boxedValue; protected bool localIsOwner; public readonly int Priority; public object? BoxedValue { get { return boxedValue; } set { boxedValue = value; ValueChanged?.Invoke(); } } protected CustomSyncedValueBase(ConfigSync configSync, string identifier, Type type, int priority) { Priority = priority; Identifier = identifier; Type = type; configSync.AddCustomValue(this); localIsOwner = configSync.IsSourceOfTruth; configSync.SourceOfTruthChanged += delegate(bool truth) { localIsOwner = truth; }; } } [PublicAPI] public abstract class OwnConfigEntryBase { public object? LocalBaseValue; public bool SynchronizedConfig = true; public abstract ConfigEntryBase BaseConfig { get; } } [PublicAPI] public class SyncedConfigEntry : OwnConfigEntryBase { public readonly ConfigEntry SourceConfig; public override ConfigEntryBase BaseConfig => (ConfigEntryBase)SourceConfig; public T Value { get { return SourceConfig.Value; } set { SourceConfig.Value = value; } } public SyncedConfigEntry(ConfigEntry sourceConfig) { SourceConfig = sourceConfig; } public void AssignLocalValue(T value) { if (LocalBaseValue == null) { Value = value; } else { LocalBaseValue = value; } } } [PublicAPI] [HarmonyPatch] public class VersionCheck { private static readonly HashSet versionChecks; private static readonly Dictionary notProcessedNames; public string Name; private string? displayName; private string? currentVersion; private string? minimumRequiredVersion; public bool ModRequired = true; private string? ReceivedCurrentVersion; private string? ReceivedMinimumRequiredVersion; private readonly List ValidatedClients = new List(); private ConfigSync? ConfigSync; public string DisplayName { get { return displayName ?? Name; } set { displayName = value; } } public string CurrentVersion { get { return currentVersion ?? "0.0.0"; } set { currentVersion = value; } } public string MinimumRequiredVersion { get { string text = minimumRequiredVersion; if (text == null) { if (!ModRequired) { return "0.0.0"; } text = CurrentVersion; } return text; } set { minimumRequiredVersion = value; } } private static void PatchServerSync() { //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Expected O, but got Unknown Patches patchInfo = PatchProcessor.GetPatchInfo((MethodBase)AccessTools.DeclaredMethod(typeof(ZNet), "Awake", (Type[])null, (Type[])null)); if (patchInfo != null && patchInfo.Postfixes.Count((Patch p) => p.PatchMethod.DeclaringType == typeof(ConfigSync.RegisterRPCPatch)) > 0) { return; } Harmony val = new Harmony("org.bepinex.helpers.ServerSync"); foreach (Type item in from t in typeof(ConfigSync).GetNestedTypes(BindingFlags.NonPublic).Concat(new Type[1] { typeof(VersionCheck) }) where t.IsClass select t) { val.PatchAll(item); } } static VersionCheck() { versionChecks = new HashSet(); notProcessedNames = new Dictionary(); typeof(ThreadingHelper).GetMethod("StartSyncInvoke").Invoke(ThreadingHelper.Instance, new object[1] { new Action(PatchServerSync) }); } public VersionCheck(string name) { Name = name; ModRequired = true; versionChecks.Add(this); } public VersionCheck(ConfigSync configSync) { ConfigSync = configSync; Name = ConfigSync.Name; versionChecks.Add(this); } public void Initialize() { ReceivedCurrentVersion = null; ReceivedMinimumRequiredVersion = null; if (ConfigSync != null) { Name = ConfigSync.Name; DisplayName = ConfigSync.DisplayName; CurrentVersion = ConfigSync.CurrentVersion; MinimumRequiredVersion = ConfigSync.MinimumRequiredVersion; ModRequired = ConfigSync.ModRequired; } } private bool IsVersionOk() { if (ReceivedMinimumRequiredVersion == null || ReceivedCurrentVersion == null) { return !ModRequired; } bool num = new Version(CurrentVersion) >= new Version(ReceivedMinimumRequiredVersion); bool flag = new Version(ReceivedCurrentVersion) >= new Version(MinimumRequiredVersion); return num && flag; } private string ErrorClient() { if (ReceivedMinimumRequiredVersion == null) { return DisplayName + " is not installed on the server."; } if (!(new Version(CurrentVersion) >= new Version(ReceivedMinimumRequiredVersion))) { return DisplayName + " needs to be at least version " + ReceivedMinimumRequiredVersion + ". You have version " + CurrentVersion + "."; } return DisplayName + " may not be higher than version " + ReceivedCurrentVersion + ". You have version " + CurrentVersion + "."; } private string ErrorServer(ZRpc rpc) { return "Disconnect: The client (" + rpc.GetSocket().GetHostName() + ") doesn't have the correct " + DisplayName + " version " + MinimumRequiredVersion; } private string Error(ZRpc? rpc = null) { if (rpc != null) { return ErrorServer(rpc); } return ErrorClient(); } private static VersionCheck[] GetFailedClient() { return versionChecks.Where((VersionCheck check) => !check.IsVersionOk()).ToArray(); } private static VersionCheck[] GetFailedServer(ZRpc rpc) { return versionChecks.Where((VersionCheck check) => check.ModRequired && !check.ValidatedClients.Contains(rpc)).ToArray(); } private static void Logout() { Game.instance.Logout(true, true); ValheimCompat.SetZNetConnectionStatus(3); } private static void DisconnectClient(ZRpc rpc) { rpc.Invoke("Error", new object[1] { 3 }); } private static void CheckVersion(ZRpc rpc, ZPackage pkg) { CheckVersion(rpc, pkg, null); } private static void CheckVersion(ZRpc rpc, ZPackage pkg, Action? original) { string text = pkg.ReadString(); string text2 = pkg.ReadString(); string text3 = pkg.ReadString(); bool flag = false; foreach (VersionCheck versionCheck in versionChecks) { if (!(text != versionCheck.Name)) { Debug.Log((object)("Received " + versionCheck.DisplayName + " version " + text3 + " and minimum version " + text2 + " from the " + (ZNet.instance.IsServer() ? "client" : "server") + ".")); versionCheck.ReceivedMinimumRequiredVersion = text2; versionCheck.ReceivedCurrentVersion = text3; if (ZNet.instance.IsServer() && versionCheck.IsVersionOk()) { versionCheck.ValidatedClients.Add(rpc); } flag = true; } } if (flag) { return; } pkg.SetPos(0); if (original != null) { original(rpc, pkg); if (pkg.GetPos() == 0) { notProcessedNames.Add(text, text3); } } } [HarmonyPatch(typeof(ZNet), "RPC_PeerInfo")] [HarmonyPrefix] private static bool RPC_PeerInfo(ZRpc rpc, ZNet __instance) { VersionCheck[] array = (__instance.IsServer() ? GetFailedServer(rpc) : GetFailedClient()); if (array.Length == 0) { return true; } VersionCheck[] array2 = array; for (int i = 0; i < array2.Length; i++) { Debug.LogWarning((object)array2[i].Error(rpc)); } if (__instance.IsServer()) { DisconnectClient(rpc); } else { Logout(); } return false; } [HarmonyPatch(typeof(ZNet), "OnNewConnection")] [HarmonyPrefix] private static void RegisterAndCheckVersion(ZNetPeer peer, ZNet __instance) { //IL_0172: Unknown result type (might be due to invalid IL or missing references) //IL_0179: Expected O, but got Unknown notProcessedNames.Clear(); IDictionary dictionary = (IDictionary)typeof(ZRpc).GetField("m_functions", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(peer.m_rpc); if (dictionary.Contains(StringExtensionMethods.GetStableHashCode("ServerSync VersionCheck"))) { object obj = dictionary[StringExtensionMethods.GetStableHashCode("ServerSync VersionCheck")]; Action action = (Action)obj.GetType().GetField("m_action", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(obj); peer.m_rpc.Register("ServerSync VersionCheck", (Action)delegate(ZRpc rpc, ZPackage pkg) { CheckVersion(rpc, pkg, action); }); } else { peer.m_rpc.Register("ServerSync VersionCheck", (Action)CheckVersion); } foreach (VersionCheck versionCheck in versionChecks) { versionCheck.Initialize(); if (versionCheck.ModRequired || __instance.IsServer()) { Debug.Log((object)("Sending " + versionCheck.DisplayName + " version " + versionCheck.CurrentVersion + " and minimum version " + versionCheck.MinimumRequiredVersion + " to the " + (__instance.IsServer() ? "client" : "server") + ".")); ZPackage val = new ZPackage(); val.Write(versionCheck.Name); val.Write(versionCheck.MinimumRequiredVersion); val.Write(versionCheck.CurrentVersion); peer.m_rpc.Invoke("ServerSync VersionCheck", new object[1] { val }); } } } [HarmonyPrefix] [HarmonyPatch(typeof(ZNet), "Disconnect")] private static void RemoveDisconnected(ZNetPeer peer, ZNet __instance) { if (!__instance.IsServer()) { return; } foreach (VersionCheck versionCheck in versionChecks) { versionCheck.ValidatedClients.Remove(peer.m_rpc); } } [HarmonyPostfix] [HarmonyPatch(typeof(FejdStartup), "ShowConnectError")] private static void ShowConnectionError(FejdStartup __instance) { //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Invalid comparison between Unknown and I4 //IL_014c: Unknown result type (might be due to invalid IL or missing references) //IL_0151: Unknown result type (might be due to invalid IL or missing references) //IL_0161: Unknown result type (might be due to invalid IL or missing references) //IL_01a4: Unknown result type (might be due to invalid IL or missing references) //IL_01b0: Unknown result type (might be due to invalid IL or missing references) //IL_01be: Unknown result type (might be due to invalid IL or missing references) //IL_01d0: Unknown result type (might be due to invalid IL or missing references) //IL_01dc: Unknown result type (might be due to invalid IL or missing references) //IL_01e1: Unknown result type (might be due to invalid IL or missing references) //IL_01ee: Unknown result type (might be due to invalid IL or missing references) if (!__instance.m_connectionFailedPanel.activeSelf || (int)ZNet.GetConnectionStatus() != 3) { return; } bool flag = false; VersionCheck[] failedClient = GetFailedClient(); if (failedClient.Length != 0) { string text = string.Join("\n", failedClient.Select((VersionCheck check) => check.Error())); TMP_Text connectionFailedError = __instance.m_connectionFailedError; connectionFailedError.text = connectionFailedError.text + "\n" + text; flag = true; } foreach (KeyValuePair item in notProcessedNames.OrderBy((KeyValuePair kv) => kv.Key)) { if (!__instance.m_connectionFailedError.text.Contains(item.Key)) { TMP_Text connectionFailedError2 = __instance.m_connectionFailedError; connectionFailedError2.text = connectionFailedError2.text + "\nServer expects you to have " + item.Key + " (Version: " + item.Value + ") installed."; flag = true; } } if (flag) { RectTransform component = ((Component)__instance.m_connectionFailedPanel.transform.Find("Image")).GetComponent(); Vector2 sizeDelta = component.sizeDelta; sizeDelta.x = 675f; component.sizeDelta = sizeDelta; __instance.m_connectionFailedError.ForceMeshUpdate(false, false); float num = __instance.m_connectionFailedError.renderedHeight + 105f; RectTransform component2 = ((Component)((Component)component).transform.Find("ButtonOk")).GetComponent(); component2.anchoredPosition = new Vector2(component2.anchoredPosition.x, component2.anchoredPosition.y - (num - component.sizeDelta.y) / 2f); sizeDelta = component.sizeDelta; sizeDelta.y = num; component.sizeDelta = sizeDelta; } } } } namespace fastJSON { internal class DataMemberAttribute : Attribute { public string Name { get; set; } } internal sealed class DatasetSchema { public List Info; public string Name; } internal class deserializer { private JSONParameters _params; private bool _usingglobals; private Dictionary _circobj; private Dictionary _cirrev = new Dictionary(); public deserializer(JSONParameters param) { if (param.OverrideObjectHashCodeChecking) { _circobj = new Dictionary(10, ReferenceEqualityComparer.Default); } else { _circobj = new Dictionary(); } param.FixValues(); _params = param.MakeCopy(); } public T ToObject(string json) { Type typeFromHandle = typeof(T); object obj = ToObject(json, typeFromHandle); if (typeFromHandle.IsArray) { if ((obj as ICollection).Count == 0) { return (T)(object)Array.CreateInstance(typeFromHandle.GetElementType(), 0); } return (T)obj; } return (T)obj; } public object ToObject(string json) { return ToObject(json, null); } public object ToObject(string json, Type type) { Type type2 = null; if (type != null && type.IsGenericType) { type2 = Reflection.Instance.GetGenericTypeDefinition(type); } _usingglobals = _params.UsingGlobalTypes; if (typeof(IDictionary).IsAssignableFrom(type2) || typeof(List<>).IsAssignableFrom(type2)) { _usingglobals = false; } object obj = new JsonParser(json, _params.AllowNonQuotedKeys).Decode(type); if (obj == null) { return null; } if (obj is IDictionary) { if (type != null && typeof(Dictionary<, >).IsAssignableFrom(type2)) { return RootDictionary(obj, type); } return ParseDictionary(obj as Dictionary, null, type, null); } if (obj is List) { if (!(type != null)) { List list = (List)obj; if (list.Count > 0 && list[0].GetType() == typeof(Dictionary)) { Dictionary globaltypes = new Dictionary(); List list2 = new List(); { foreach (object item in list) { list2.Add(ParseDictionary((Dictionary)item, globaltypes, null, null)); } return list2; } } return list.ToArray(); } if (typeof(Dictionary<, >).IsAssignableFrom(type2)) { return RootDictionary(obj, type); } if (type2 == typeof(List<>)) { return RootList(obj, type); } if (type.IsArray) { return RootArray(obj, type); } if (type == typeof(Hashtable)) { return RootHashTable((List)obj); } } else if (type != null && obj.GetType() != type) { return ChangeType(obj, type); } return obj; } private object RootHashTable(List o) { Hashtable hashtable = new Hashtable(); foreach (Dictionary item in o) { object obj2 = item["k"]; object obj3 = item["v"]; if (obj2 is Dictionary) { obj2 = ParseDictionary((Dictionary)obj2, null, typeof(object), null); } if (obj3 is Dictionary) { obj3 = ParseDictionary((Dictionary)obj3, null, typeof(object), null); } hashtable.Add(obj2, obj3); } return hashtable; } private object ChangeType(object value, Type conversionType) { if (conversionType == typeof(object)) { return value; } if (conversionType == typeof(int)) { if (!(value is string text)) { return (int)(long)value; } if (_params.AutoConvertStringToNumbers) { return Helper.CreateInteger(text, 0, text.Length); } throw new Exception("AutoConvertStringToNumbers is disabled for converting string : " + value); } if (conversionType == typeof(long)) { if (!(value is string text2)) { return (long)value; } if (_params.AutoConvertStringToNumbers) { return Helper.CreateLong(text2, 0, text2.Length); } throw new Exception("AutoConvertStringToNumbers is disabled for converting string : " + value); } if (conversionType == typeof(string)) { return (string)value; } if (conversionType.IsEnum) { return Helper.CreateEnum(conversionType, value); } if (conversionType == typeof(DateTime)) { return Helper.CreateDateTime((string)value, _params.UseUTCDateTime); } if (conversionType == typeof(DateTimeOffset)) { return Helper.CreateDateTimeOffset((string)value); } if (Reflection.Instance.IsTypeRegistered(conversionType)) { return Reflection.Instance.CreateCustom((string)value, conversionType); } if (Helper.IsNullable(conversionType)) { if (value == null) { return value; } conversionType = Helper.UnderlyingTypeOf(conversionType); } if (conversionType == typeof(Guid)) { return Helper.CreateGuid((string)value); } if (conversionType == typeof(byte[])) { return Convert.FromBase64String((string)value); } if (conversionType == typeof(TimeSpan)) { return new TimeSpan((long)value); } return Convert.ChangeType(value, conversionType, CultureInfo.InvariantCulture); } private object RootList(object parse, Type type) { Type[] genericArguments = Reflection.Instance.GetGenericArguments(type); IList list = (IList)Reflection.Instance.FastCreateList(type, ((IList)parse).Count); DoParseList((IList)parse, genericArguments[0], list); return list; } private void DoParseList(IList parse, Type it, IList o) { Dictionary globaltypes = new Dictionary(); foreach (object item in parse) { _usingglobals = false; object obj = item; obj = ((!(item is Dictionary d)) ? ChangeType(item, it) : ParseDictionary(d, globaltypes, it, null)); o.Add(obj); } } private object RootArray(object parse, Type type) { Type elementType = type.GetElementType(); IList list = (IList)Reflection.Instance.FastCreateInstance(typeof(List<>).MakeGenericType(elementType)); DoParseList((IList)parse, elementType, list); Array array = Array.CreateInstance(elementType, list.Count); list.CopyTo(array, 0); return array; } private object RootDictionary(object parse, Type type) { Type[] genericArguments = Reflection.Instance.GetGenericArguments(type); Type type2 = null; Type type3 = null; bool flag = false; if (genericArguments != null) { type2 = genericArguments[0]; type3 = genericArguments[1]; if (type3 != null) { flag = type3.Name.StartsWith("Dictionary"); } } Type elementType = type3.GetElementType(); if (parse is Dictionary) { IDictionary dictionary = (IDictionary)Reflection.Instance.FastCreateInstance(type); { foreach (KeyValuePair item in (Dictionary)parse) { object key = ChangeType(item.Key, type2); object value = ((!flag) ? ((!(item.Value is Dictionary)) ? ((type3.IsArray && type3 != typeof(byte[])) ? CreateArray((List)item.Value, type3, elementType, null) : ((!(item.Value is IList)) ? ChangeType(item.Value, type3) : CreateGenericList((List)item.Value, type3, type2, null))) : ParseDictionary(item.Value as Dictionary, null, type3, null)) : RootDictionary(item.Value, type3)); dictionary.Add(key, value); } return dictionary; } } if (parse is List) { return CreateDictionary(parse as List, type, genericArguments, null); } return null; } internal object ParseDictionary(Dictionary d, Dictionary globaltypes, Type type, object input) { object value = ""; if (type == typeof(NameValueCollection)) { return Helper.CreateNV(d); } if (type == typeof(StringDictionary)) { return Helper.CreateSD(d); } if (d.TryGetValue("$i", out value)) { object value2 = null; _cirrev.TryGetValue((int)(long)value, out value2); return value2; } if (d.TryGetValue("$types", out value)) { _usingglobals = true; if (globaltypes == null) { globaltypes = new Dictionary(); } foreach (KeyValuePair item in (Dictionary)value) { globaltypes.Add((string)item.Value, item.Key); } } if (globaltypes != null) { _usingglobals = true; } bool flag = d.TryGetValue("$type", out value); if (!flag && type == typeof(object)) { return d; } if (flag) { if (_usingglobals) { object value3 = ""; if (globaltypes != null && globaltypes.TryGetValue((string)value, out value3)) { value = value3; } } type = Reflection.Instance.GetTypeFromCache((string)value, _params.BadListTypeChecking); } if (type == null) { throw new Exception("Cannot determine type : " + value); } string fullName = type.FullName; object obj = input; if (obj == null) { obj = ((!_params.ParametricConstructorOverride) ? Reflection.Instance.FastCreateInstance(type) : FormatterServices.GetUninitializedObject(type)); } int value4 = 0; if (!_circobj.TryGetValue(obj, out value4)) { value4 = _circobj.Count + 1; _circobj.Add(obj, value4); _cirrev.Add(value4, obj); } Dictionary dictionary = Reflection.Instance.Getproperties(type, fullName, _params.ShowReadOnlyProperties); foreach (KeyValuePair item2 in d) { string key = item2.Key; object value5 = item2.Value; string text = key; if (text == "$map") { ProcessMap(obj, dictionary, (Dictionary)d[text]); } else { if ((!dictionary.TryGetValue(text, out var value6) && !dictionary.TryGetValue(text.ToLowerInvariant(), out value6)) || !value6.CanWrite) { continue; } object value7 = null; if (value5 != null) { switch (value6.Type) { case myPropInfoType.Int: value7 = (int)Helper.AutoConv(value5, _params); break; case myPropInfoType.Long: value7 = Helper.AutoConv(value5, _params); break; case myPropInfoType.String: value7 = value5.ToString(); break; case myPropInfoType.Bool: value7 = Helper.BoolConv(value5); break; case myPropInfoType.DateTime: value7 = Helper.CreateDateTime((string)value5, _params.UseUTCDateTime); break; case myPropInfoType.Enum: value7 = Helper.CreateEnum(value6.pt, value5); break; case myPropInfoType.Guid: value7 = Helper.CreateGuid((string)value5); break; case myPropInfoType.Array: if (!value6.IsValueType) { value7 = CreateArray((List)value5, value6.pt, value6.bt, globaltypes); } break; case myPropInfoType.ByteArray: value7 = Convert.FromBase64String((string)value5); break; case myPropInfoType.Dictionary: value7 = CreateDictionary((List)value5, value6.pt, value6.GenericTypes, globaltypes); break; case myPropInfoType.StringKeyDictionary: value7 = CreateStringKeyDictionary((Dictionary)value5, value6.pt, value6.GenericTypes, globaltypes); break; case myPropInfoType.NameValue: value7 = Helper.CreateNV((Dictionary)value5); break; case myPropInfoType.StringDictionary: value7 = Helper.CreateSD((Dictionary)value5); break; case myPropInfoType.Custom: value7 = Reflection.Instance.CreateCustom((string)value5, value6.pt); break; default: value7 = ((value6.IsGenericType && !value6.IsValueType && value5 is List) ? CreateGenericList((List)value5, value6.pt, value6.bt, globaltypes) : (((value6.IsClass || value6.IsStruct || value6.IsInterface) && value5 is Dictionary) ? ParseDictionary((Dictionary)value5, globaltypes, value6.pt, null) : ((value5 is List) ? CreateArray((List)value5, value6.pt, typeof(object), globaltypes) : ((!value6.IsValueType) ? value5 : ChangeType(value5, value6.changeType))))); break; } } obj = value6.setter(obj, value7); } } return obj; } private static void ProcessMap(object obj, Dictionary props, Dictionary dic) { foreach (KeyValuePair item in dic) { myPropInfo myPropInfo2 = props[item.Key]; object obj2 = myPropInfo2.getter(obj); if (Reflection.Instance.GetTypeFromCache((string)item.Value, badlistChecking: true) == typeof(Guid)) { myPropInfo2.setter(obj, Helper.CreateGuid((string)obj2)); } } } private object CreateArray(List data, Type pt, Type bt, Dictionary globalTypes) { if (bt == null) { bt = typeof(object); } Array array = Array.CreateInstance(bt, data.Count); Type elementType = bt.GetElementType(); for (int i = 0; i < data.Count; i++) { object obj = data[i]; if (obj != null) { if (obj is IDictionary) { array.SetValue(ParseDictionary((Dictionary)obj, globalTypes, bt, null), i); } else if (obj is ICollection) { array.SetValue(CreateArray((List)obj, bt, elementType, globalTypes), i); } else { array.SetValue(ChangeType(obj, bt), i); } } } return array; } private object CreateGenericList(List data, Type pt, Type bt, Dictionary globalTypes) { if (pt != typeof(object)) { IList list = (IList)Reflection.Instance.FastCreateList(pt, data.Count); Type type = Reflection.Instance.GetGenericArguments(pt)[0]; { foreach (object datum in data) { if (datum is IDictionary) { list.Add(ParseDictionary((Dictionary)datum, globalTypes, type, null)); } else if (datum is List) { if (bt.IsGenericType) { list.Add((List)datum); } else { list.Add(((List)datum).ToArray()); } } else { list.Add(ChangeType(datum, type)); } } return list; } } return data; } private object CreateStringKeyDictionary(Dictionary reader, Type pt, Type[] types, Dictionary globalTypes) { IDictionary dictionary = (IDictionary)Reflection.Instance.FastCreateInstance(pt); Type type = null; Type type2 = null; if (types != null) { type2 = types[1]; } Type bt = null; Type[] genericArguments = Reflection.Instance.GetGenericArguments(type2); if (genericArguments.Length != 0) { bt = genericArguments[0]; } type = type2.GetElementType(); foreach (KeyValuePair item in reader) { string key = item.Key; object obj = null; obj = ((!(item.Value is Dictionary)) ? ((types != null && type2.IsArray) ? ((!(item.Value is Array)) ? CreateArray((List)item.Value, type2, type, globalTypes) : item.Value) : ((!(item.Value is IList)) ? ChangeType(item.Value, type2) : CreateGenericList((List)item.Value, type2, bt, globalTypes))) : ParseDictionary((Dictionary)item.Value, globalTypes, type2, null)); dictionary.Add(key, obj); } return dictionary; } private object CreateDictionary(List reader, Type pt, Type[] types, Dictionary globalTypes) { IDictionary dictionary = (IDictionary)Reflection.Instance.FastCreateInstance(pt); Type type = null; Type type2 = null; Type bt = null; if (types != null) { type = types[0]; type2 = types[1]; } Type bt2 = type2; if (type2 != null) { Type[] genericArguments = Reflection.Instance.GetGenericArguments(type2); if (genericArguments.Length != 0) { bt = genericArguments[0]; } bt2 = type2.GetElementType(); } bool flag = typeof(IDictionary).IsAssignableFrom(type2); foreach (Dictionary item in reader) { object obj2 = item["k"]; object obj3 = item["v"]; obj2 = ((!(obj2 is Dictionary)) ? ChangeType(obj2, type) : ParseDictionary((Dictionary)obj2, globalTypes, type, null)); obj3 = ((!flag) ? ((!(obj3 is Dictionary)) ? ((types != null && type2.IsArray) ? CreateArray((List)obj3, type2, bt2, globalTypes) : ((!(obj3 is IList)) ? ChangeType(obj3, type2) : CreateGenericList((List)obj3, type2, bt, globalTypes))) : ParseDictionary((Dictionary)obj3, globalTypes, type2, null)) : RootDictionary(obj3, type2)); dictionary.Add(obj2, obj3); } return dictionary; } } internal class DynamicJson : DynamicObject, IEnumerable { private IDictionary _dictionary { get; set; } private List _list { get; set; } public DynamicJson(string json) { object obj = JSON.Parse(json); if (obj is IDictionary) { _dictionary = (IDictionary)obj; } else { _list = (List)obj; } } private DynamicJson(object dictionary) { if (dictionary is IDictionary) { _dictionary = (IDictionary)dictionary; } } public override IEnumerable GetDynamicMemberNames() { return _dictionary.Keys.ToList(); } public override bool TryGetIndex(GetIndexBinder binder, object[] indexes, out object result) { object obj = indexes[0]; if (obj is int) { result = _list[(int)obj]; } else { result = _dictionary[(string)obj]; } if (result is IDictionary) { result = new DynamicJson(result as IDictionary); } return true; } public override bool TryGetMember(GetMemberBinder binder, out object result) { if (!_dictionary.TryGetValue(binder.Name, out result) && !_dictionary.TryGetValue(binder.Name.ToLowerInvariant(), out result)) { return false; } if (result is IDictionary) { result = new DynamicJson(result as IDictionary); } else if (result is List) { List list = new List(); foreach (object item in (List)result) { if (item is IDictionary) { list.Add(new DynamicJson(item as IDictionary)); } else { list.Add(item); } } result = list; } return _dictionary.ContainsKey(binder.Name); } IEnumerator IEnumerable.GetEnumerator() { foreach (object item in _list) { yield return new DynamicJson(item as IDictionary); } } } internal static class Formatter { private static void AppendIndent(StringBuilder sb, int count, string indent) { while (count > 0) { sb.Append(indent); count--; } } public static string PrettyPrint(string input) { return PrettyPrint(input, new string(' ', JSON.Parameters.FormatterIndentSpaces)); } public static string PrettyPrint(string input, string spaces) { StringBuilder stringBuilder = new StringBuilder(); int num = 0; int length = input.Length; char[] array = input.ToCharArray(); for (int i = 0; i < length; i++) { char c = array[i]; if (c == '"') { bool flag = true; while (flag) { stringBuilder.Append(c); c = array[++i]; switch (c) { case '\\': stringBuilder.Append(c); c = array[++i]; break; case '"': flag = false; break; } } } switch (c) { case '[': case '{': stringBuilder.Append(c); stringBuilder.AppendLine(); AppendIndent(stringBuilder, ++num, spaces); break; case ']': case '}': stringBuilder.AppendLine(); AppendIndent(stringBuilder, --num, spaces); stringBuilder.Append(c); break; case ',': stringBuilder.Append(c); stringBuilder.AppendLine(); AppendIndent(stringBuilder, num, spaces); break; case ':': stringBuilder.Append(" : "); break; default: if (!char.IsWhiteSpace(c)) { stringBuilder.Append(c); } break; } } return stringBuilder.ToString(); } } internal struct Getters { public string Name; public string lcName; public string memberName; public Reflection.GenericGetter Getter; public bool ReadOnly; } internal class Helper { public static bool IsNullable(Type t) { if (!t.IsGenericType) { return false; } return t.GetGenericTypeDefinition().Equals(typeof(Nullable<>)); } public static Type UnderlyingTypeOf(Type t) { return Reflection.Instance.GetGenericArguments(t)[0]; } public static DateTimeOffset CreateDateTimeOffset(int year, int month, int day, int hour, int min, int sec, int milli, int extraTicks, TimeSpan offset) { DateTimeOffset dateTimeOffset = new DateTimeOffset(year, month, day, hour, min, sec, milli, offset); if (extraTicks > 0) { return dateTimeOffset + TimeSpan.FromTicks(extraTicks); } return dateTimeOffset; } public static bool BoolConv(object v) { bool result = false; if (v is bool) { result = (bool)v; } else if (v is long) { result = (long)v > 0; } else if (v is string) { switch (((string)v).ToLowerInvariant()) { case "1": case "true": case "yes": case "on": result = true; break; } } return result; } public static long AutoConv(object value, JSONParameters param) { if (value is string) { if (param.AutoConvertStringToNumbers) { string text = (string)value; return CreateLong(text, 0, text.Length); } throw new Exception("AutoConvertStringToNumbers is disabled for converting string : " + value); } if (value is long) { return (long)value; } return Convert.ToInt64(value); } public unsafe static long CreateLong(string s, int index, int count) { long num = 0L; int num2 = 1; fixed (char* ptr = s) { char* ptr2 = ptr; ptr2 += index; if (*ptr2 == '-') { num2 = -1; ptr2++; count--; } if (*ptr2 == '+') { ptr2++; count--; } while (count > 0) { num = num * 10 + (*ptr2 - 48); ptr2++; count--; } } return num * num2; } public unsafe static long CreateLong(char[] s, int index, int count) { long num = 0L; int num2 = 1; fixed (char* ptr = s) { char* ptr2 = ptr; ptr2 += index; if (*ptr2 == '-') { num2 = -1; ptr2++; count--; } if (*ptr2 == '+') { ptr2++; count--; } while (count > 0) { num = num * 10 + (*ptr2 - 48); ptr2++; count--; } } return num * num2; } public unsafe static int CreateInteger(string s, int index, int count) { int num = 0; int num2 = 1; fixed (char* ptr = s) { char* ptr2 = ptr; ptr2 += index; if (*ptr2 == '-') { num2 = -1; ptr2++; count--; } if (*ptr2 == '+') { ptr2++; count--; } while (count > 0) { num = num * 10 + (*ptr2 - 48); ptr2++; count--; } } return num * num2; } public static object CreateEnum(Type pt, object v) { return Enum.Parse(pt, v.ToString(), ignoreCase: true); } public static Guid CreateGuid(string s) { if (s.Length > 30) { return new Guid(s); } return new Guid(Convert.FromBase64String(s)); } public static StringDictionary CreateSD(Dictionary d) { StringDictionary stringDictionary = new StringDictionary(); foreach (KeyValuePair item in d) { stringDictionary.Add(item.Key, (string)item.Value); } return stringDictionary; } public static NameValueCollection CreateNV(Dictionary d) { NameValueCollection nameValueCollection = new NameValueCollection(); foreach (KeyValuePair item in d) { nameValueCollection.Add(item.Key, (string)item.Value); } return nameValueCollection; } public static object CreateDateTimeOffset(string value) { int milli = 0; int extraTicks = 0; int num = 0; int num2 = 0; int year = CreateInteger(value, 0, 4); int month = CreateInteger(value, 5, 2); int day = CreateInteger(value, 8, 2); int hour = CreateInteger(value, 11, 2); int min = CreateInteger(value, 14, 2); int sec = CreateInteger(value, 17, 2); int num3 = 20; if (value.Length > 21 && value[19] == '.') { milli = CreateInteger(value, num3, 3); num3 = 23; if (value.Length > 25 && char.IsDigit(value[num3])) { extraTicks = CreateInteger(value, num3, 4); num3 = 27; } } if (value[num3] == 'Z') { return CreateDateTimeOffset(year, month, day, hour, min, sec, milli, extraTicks, TimeSpan.Zero); } if (value[num3] == ' ') { num3++; } num = CreateInteger(value, num3 + 1, 2); num2 = CreateInteger(value, num3 + 1 + 2 + 1, 2); if (value[num3] == '-') { num = -num; } return CreateDateTimeOffset(year, month, day, hour, min, sec, milli, extraTicks, new TimeSpan(num, num2, 0)); } public static DateTime CreateDateTime(string value, bool UseUTCDateTime) { if (value.Length < 19) { return DateTime.MinValue; } bool flag = false; int millisecond = 0; int year = CreateInteger(value, 0, 4); int month = CreateInteger(value, 5, 2); int day = CreateInteger(value, 8, 2); int hour = CreateInteger(value, 11, 2); int minute = CreateInteger(value, 14, 2); int second = CreateInteger(value, 17, 2); if (value.Length > 21 && value[19] == '.') { millisecond = CreateInteger(value, 20, 3); } if (value[value.Length - 1] == 'Z') { flag = true; } if (!UseUTCDateTime && !flag) { return new DateTime(year, month, day, hour, minute, second, millisecond); } return new DateTime(year, month, day, hour, minute, second, millisecond, DateTimeKind.Utc).ToLocalTime(); } } internal static class JSON { public static JSONParameters Parameters = new JSONParameters(); public static string ToNiceJSON(object obj) { return Beautify(ToJSON(obj, Parameters)); } public static string ToNiceJSON(object obj, JSONParameters param) { return Beautify(ToJSON(obj, param), param.FormatterIndentSpaces); } public static string ToJSON(object obj) { return ToJSON(obj, Parameters); } public static string ToJSON(object obj, JSONParameters param) { param.FixValues(); param = param.MakeCopy(); Type c = null; if (obj == null) { return "null"; } if (obj.GetType().IsGenericType) { c = Reflection.Instance.GetGenericTypeDefinition(obj.GetType()); } if (typeof(IDictionary).IsAssignableFrom(c) || typeof(List<>).IsAssignableFrom(c)) { param.UsingGlobalTypes = false; } if (param.EnableAnonymousTypes) { param.UseExtensions = false; param.UsingGlobalTypes = false; } return new JSONSerializer(param).ConvertToJSON(obj); } public static object Parse(string json) { return new JsonParser(json, Parameters.AllowNonQuotedKeys).Decode(null); } public static dynamic ToDynamic(string json) { return new DynamicJson(json); } public static T ToObject(string json) { return new deserializer(Parameters).ToObject(json); } public static T ToObject(string json, JSONParameters param) { return new deserializer(param).ToObject(json); } public static object ToObject(string json) { return new deserializer(Parameters).ToObject(json, null); } public static object ToObject(string json, JSONParameters param) { return new deserializer(param).ToObject(json, null); } public static object ToObject(string json, Type type) { return new deserializer(Parameters).ToObject(json, type); } public static object ToObject(string json, Type type, JSONParameters par) { return new deserializer(par).ToObject(json, type); } public static object FillObject(object input, string json) { if (!(new JsonParser(json, Parameters.AllowNonQuotedKeys).Decode(input.GetType()) is Dictionary d)) { return null; } return new deserializer(Parameters).ParseDictionary(d, null, input.GetType(), input); } public static object DeepCopy(object obj) { return new deserializer(Parameters).ToObject(ToJSON(obj)); } public static T DeepCopy(T obj) { return new deserializer(Parameters).ToObject(ToJSON(obj)); } public static string Beautify(string input) { string spaces = new string(' ', Parameters.FormatterIndentSpaces); return Formatter.PrettyPrint(input, spaces); } public static string Beautify(string input, byte spaces) { string spaces2 = new string(' ', spaces); return Formatter.PrettyPrint(input, spaces2); } public static void RegisterCustomType(Type type, Reflection.Serialize serializer, Reflection.Deserialize deserializer) { Reflection.Instance.RegisterCustomType(type, serializer, deserializer); } public static void ClearReflectionCache() { Reflection.Instance.ClearReflectionCache(); } } internal sealed class JSONParameters { public bool UseOptimizedDatasetSchema = true; public bool UseFastGuid = true; public bool SerializeNullValues = true; public bool UseUTCDateTime = true; public bool ShowReadOnlyProperties; public bool UsingGlobalTypes = true; [Obsolete("Not needed anymore and will always match")] public bool IgnoreCaseOnDeserialize; public bool EnableAnonymousTypes; public bool UseExtensions = true; public bool UseEscapedUnicode = true; public bool KVStyleStringDictionary; public bool UseValuesOfEnums; public List IgnoreAttributes = new List { typeof(XmlIgnoreAttribute), typeof(NonSerializedAttribute) }; public bool ParametricConstructorOverride; public bool DateTimeMilliseconds; public byte SerializerMaxDepth = 20; public bool InlineCircularReferences; public bool SerializeToLowerCaseNames; public byte FormatterIndentSpaces = 3; public bool AllowNonQuotedKeys; public bool AutoConvertStringToNumbers = true; public bool OverrideObjectHashCodeChecking; [Obsolete("Racist term removed, please use BadListTypeChecking")] public bool BlackListTypeChecking = true; public bool BadListTypeChecking = true; public bool FullyQualifiedDataSetSchema; public void FixValues() { if (!UseExtensions) { UsingGlobalTypes = false; InlineCircularReferences = true; } if (EnableAnonymousTypes) { ShowReadOnlyProperties = true; } } public JSONParameters MakeCopy() { return new JSONParameters { AllowNonQuotedKeys = AllowNonQuotedKeys, DateTimeMilliseconds = DateTimeMilliseconds, EnableAnonymousTypes = EnableAnonymousTypes, FormatterIndentSpaces = FormatterIndentSpaces, IgnoreAttributes = new List(IgnoreAttributes), InlineCircularReferences = InlineCircularReferences, KVStyleStringDictionary = KVStyleStringDictionary, ParametricConstructorOverride = ParametricConstructorOverride, SerializeNullValues = SerializeNullValues, SerializerMaxDepth = SerializerMaxDepth, SerializeToLowerCaseNames = SerializeToLowerCaseNames, ShowReadOnlyProperties = ShowReadOnlyProperties, UseEscapedUnicode = UseEscapedUnicode, UseExtensions = UseExtensions, UseFastGuid = UseFastGuid, UseOptimizedDatasetSchema = UseOptimizedDatasetSchema, UseUTCDateTime = UseUTCDateTime, UseValuesOfEnums = UseValuesOfEnums, UsingGlobalTypes = UsingGlobalTypes, AutoConvertStringToNumbers = AutoConvertStringToNumbers, OverrideObjectHashCodeChecking = OverrideObjectHashCodeChecking, FullyQualifiedDataSetSchema = FullyQualifiedDataSetSchema, BadListTypeChecking = BadListTypeChecking }; } } internal sealed class JsonParser { private enum Token { None = -1, Curly_Open, Curly_Close, Squared_Open, Squared_Close, Colon, Comma, String, Number, True, False, Null, PosInfinity, NegInfinity, NaN } private readonly char[] json; private readonly StringBuilder s = new StringBuilder(); private Token lookAheadToken = Token.None; private int index; private bool allownonquotedkey; private int _len; private SafeDictionary _lookup; private SafeDictionary _seen; private bool _parseJsonType; private bool _parseType; internal JsonParser(string json, bool AllowNonQuotedKeys) { allownonquotedkey = AllowNonQuotedKeys; this.json = json.ToCharArray(); _len = json.Length; } private void SetupLookup() { _lookup = new SafeDictionary(); _seen = new SafeDictionary(); _lookup.Add("$types", value: true); _lookup.Add("$type", value: true); _lookup.Add("$i", value: true); _lookup.Add("$map", value: true); _lookup.Add("$schema", value: true); _lookup.Add("k", value: true); _lookup.Add("v", value: true); } public unsafe object Decode(Type objtype) { fixed (char* p = json) { if (objtype != null && !CheckForTypeInJson(p)) { _parseJsonType = true; SetupLookup(); BuildLookup(objtype); if (!_parseJsonType || _lookup.Count() == 7) { _lookup = null; } } return ParseValue(p); } } private unsafe bool CheckForTypeInJson(char* p) { int i = 0; for (int num = ((_len > 1000) ? 1000 : _len); i < num; i++) { if (p[i] == '$' && p[i + 1] == 't' && p[i + 2] == 'y' && p[i + 3] == 'p' && p[i + 4] == 'e' && p[i + 5] == 's') { return true; } } return false; } private void BuildGenericTypeLookup(Type t) { if (_seen.TryGetValue(t, out var _)) { return; } Type[] genericArguments = t.GetGenericArguments(); foreach (Type type in genericArguments) { if (!type.IsPrimitive) { bool flag = type.IsValueType && !type.IsEnum; if ((type.IsClass || flag || type.IsAbstract) && type != typeof(string) && type != typeof(DateTime) && type != typeof(Guid)) { BuildLookup(type); } } } } private void BuildArrayTypeLookup(Type t) { if (!_seen.TryGetValue(t, out var _)) { bool flag = t.IsValueType && !t.IsEnum; if ((t.IsClass || flag) && t != typeof(string) && t != typeof(DateTime) && t != typeof(Guid)) { BuildLookup(t.GetElementType()); } } } private void BuildLookup(Type objtype) { if (objtype == null || objtype == typeof(NameValueCollection) || objtype == typeof(StringDictionary) || typeof(IDictionary).IsAssignableFrom(objtype) || _seen.TryGetValue(objtype, out var _)) { return; } if (objtype.IsGenericType) { BuildGenericTypeLookup(objtype); return; } if (objtype.IsArray) { BuildArrayTypeLookup(objtype); return; } _seen.Add(objtype, value: true); foreach (KeyValuePair item in Reflection.Instance.Getproperties(objtype, objtype.FullName, ShowReadOnlyProperties: true)) { Type pt = item.Value.pt; _lookup.Add(item.Key, value: true); if (pt.IsArray) { BuildArrayTypeLookup(pt); } if (pt.IsGenericType) { if (typeof(IDictionary).IsAssignableFrom(pt)) { _parseJsonType = false; break; } BuildGenericTypeLookup(pt); } if (pt.FullName.IndexOf("System.") == -1) { BuildLookup(pt); } } } private bool InLookup(string name) { if (_lookup == null) { return true; } bool value; return _lookup.TryGetValue(name.ToLowerInvariant(), out value); } private unsafe Dictionary ParseObject(char* p) { Dictionary dictionary = new Dictionary(); ConsumeToken(); while (true) { switch (LookAhead(p)) { case Token.Comma: ConsumeToken(); continue; case Token.Curly_Close: ConsumeToken(); return dictionary; } string text = ParseKey(p); if (NextToken(p) != Token.Colon) { throw new Exception("Expected colon at index " + index); } if (_parseJsonType) { if (text == "$types") { _parseType = true; Dictionary dictionary2 = (Dictionary)ParseValue(p); _parseType = false; if (_lookup == null) { SetupLookup(); } foreach (string key in dictionary2.Keys) { BuildLookup(Reflection.Instance.GetTypeFromCache(key, badlistChecking: true)); } dictionary[text] = dictionary2; } else if (text == "$schema") { _parseType = true; object value = ParseValue(p); _parseType = false; dictionary[text] = value; } else if (_parseType || InLookup(text)) { dictionary[text] = ParseValue(p); } else { SkipValue(p); } } else { dictionary[text] = ParseValue(p); } } } private unsafe void SkipValue(char* p) { switch (LookAhead(p)) { case Token.Number: ParseNumber(p, skip: true); break; case Token.String: SkipString(p); break; case Token.Curly_Open: SkipObject(p); break; case Token.Squared_Open: SkipArray(p); break; case Token.True: case Token.False: case Token.Null: case Token.PosInfinity: case Token.NegInfinity: case Token.NaN: ConsumeToken(); break; case Token.Curly_Close: case Token.Squared_Close: case Token.Colon: case Token.Comma: break; } } private unsafe void SkipObject(char* p) { ConsumeToken(); while (true) { switch (LookAhead(p)) { case Token.Comma: ConsumeToken(); continue; case Token.Curly_Close: ConsumeToken(); return; } SkipString(p); if (NextToken(p) != Token.Colon) { throw new Exception("Expected colon at index " + index); } SkipValue(p); } } private unsafe void SkipArray(char* p) { ConsumeToken(); while (true) { switch (LookAhead(p)) { case Token.Comma: ConsumeToken(); break; case Token.Squared_Close: ConsumeToken(); return; default: SkipValue(p); break; } } } private unsafe void SkipString(char* p) { ConsumeToken(); int len = _len; while (index < len) { switch (p[index++]) { case '"': return; case '\\': if (p[index++] == 'u') { index += 4; } break; } } } private unsafe List ParseArray(char* p) { List list = new List(); ConsumeToken(); while (true) { switch (LookAhead(p)) { case Token.Comma: ConsumeToken(); break; case Token.Squared_Close: ConsumeToken(); return list; default: list.Add(ParseValue(p)); break; } } } private unsafe object ParseValue(char* p) { switch (LookAhead(p)) { case Token.Number: return ParseNumber(p, skip: false); case Token.String: return ParseString(p); case Token.Curly_Open: return ParseObject(p); case Token.Squared_Open: return ParseArray(p); case Token.True: ConsumeToken(); return true; case Token.False: ConsumeToken(); return false; case Token.Null: ConsumeToken(); return null; case Token.PosInfinity: ConsumeToken(); return double.PositiveInfinity; case Token.NegInfinity: ConsumeToken(); return double.NegativeInfinity; case Token.NaN: ConsumeToken(); return double.NaN; default: throw new Exception("Unrecognized token at index " + index); } } private unsafe string ParseKey(char* p) { if (!allownonquotedkey || p[index - 1] == '"') { return ParseString(p); } ConsumeToken(); int len = _len; int num = 0; while (index + num < len) { if (p[index + num++] == ':') { string result = UnsafeSubstring(p, index, num - 1).Trim(); index += num - 1; return result; } } throw new Exception("Unable to read key"); } private unsafe string ParseString(char* p) { char c = p[index - 1]; ConsumeToken(); if (s.Length > 0) { s.Length = 0; } int len = _len; int num = 0; while (index + num < len) { char c2 = p[index + num++]; if (c2 == '\\') { break; } if (c2 == c) { string result = UnsafeSubstring(p, index, num - 1); index += num; return result; } } while (index < len) { char c3 = p[index++]; if (c3 == c) { return s.ToString(); } if (c3 != '\\') { s.Append(c3); continue; } c3 = p[index++]; switch (c3) { case 'b': s.Append('\b'); continue; case 'f': s.Append('\f'); continue; case 'n': s.Append('\n'); continue; case 'r': s.Append('\r'); continue; case 't': s.Append('\t'); continue; case 'u': { uint num2 = ParseUnicode(p[index], p[index + 1], p[index + 2], p[index + 3]); s.Append((char)num2); index += 4; continue; } } if (c3 == '\r' || c3 == '\n' || c3 == ' ' || c3 == '\t') { while (c3 == '\r' || c3 == '\n' || c3 == ' ' || c3 == '\t') { index++; c3 = p[index]; if (c3 == '\r' || c3 == '\n') { c3 = p[index + 1]; if (c3 == '\r' || c3 == '\n') { index += 2; c3 = p[index]; } break; } } } else { s.Append(c3); } } return s.ToString(); } private unsafe string ParseJson5String(char* p) { throw new NotImplementedException(); } private uint ParseSingleChar(char c1, uint multipliyer) { uint result = 0u; if (c1 >= '0' && c1 <= '9') { result = (uint)(c1 - 48) * multipliyer; } else if (c1 >= 'A' && c1 <= 'F') { result = (uint)(c1 - 65 + 10) * multipliyer; } else if (c1 >= 'a' && c1 <= 'f') { result = (uint)(c1 - 97 + 10) * multipliyer; } return result; } private uint ParseUnicode(char c1, char c2, char c3, char c4) { uint num = ParseSingleChar(c1, 4096u); uint num2 = ParseSingleChar(c2, 256u); uint num3 = ParseSingleChar(c3, 16u); uint num4 = ParseSingleChar(c4, 1u); return num + num2 + num3 + num4; } private unsafe object ParseNumber(char* p, bool skip) { ConsumeToken(); int num = index - 1; bool flag = false; bool flag2 = false; bool flag3 = true; if (p[num] == '.') { flag = true; } while (index != _len) { switch (p[index]) { case 'X': case 'x': index++; return ReadHexNumber(p); case '+': case '-': case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': index++; break; case 'E': case 'e': flag2 = true; index++; break; case '.': index++; flag = true; break; case 'N': case 'n': index += 3; return double.NaN; default: flag3 = false; break; } if (index == _len) { flag3 = false; } if (!flag3) { break; } } if (skip) { return 0; } int num2 = index - num; if (flag2 || num2 > 31) { return double.Parse(UnsafeSubstring(p, num, num2), NumberFormatInfo.InvariantInfo); } if (!flag && num2 < 20) { return Helper.CreateLong(json, num, num2); } return decimal.Parse(UnsafeSubstring(p, num, num2), NumberFormatInfo.InvariantInfo); } private unsafe object ReadHexNumber(char* p) { long num = 0L; bool flag = true; while (flag && index < _len) { char c = p[index]; switch (c) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': index++; num = (num << 4) + (c - 48); break; case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': index++; num = (num << 4) + (c - 97) + 10; break; case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': index++; num = (num << 4) + (c - 65) + 10; break; default: flag = false; break; } } return num; } private unsafe Token LookAhead(char* p) { if (lookAheadToken != Token.None) { return lookAheadToken; } return lookAheadToken = NextTokenCore(p); } private void ConsumeToken() { lookAheadToken = Token.None; } private unsafe Token NextToken(char* p) { Token result = ((lookAheadToken != Token.None) ? lookAheadToken : NextTokenCore(p)); lookAheadToken = Token.None; return result; } private unsafe void SkipWhitespace(char* p) { char c; do { c = p[index]; if (c == '/' && p[index + 1] == '/') { index++; index++; do { c = p[index]; } while (c != '\r' && c != '\n' && ++index < _len); } if (c != '/' || p[index + 1] != '*') { continue; } index++; index++; do { c = p[index]; if (c == '*' && p[index + 1] == '/') { index += 2; c = p[index]; break; } } while (++index < _len); } while ((c == ' ' || c == '\t' || c == '\n' || c == '\r') && ++index < _len); } private unsafe Token NextTokenCore(char* p) { int len = _len; SkipWhitespace(p); if (index == len) { throw new Exception("Reached end of string unexpectedly"); } char c = p[index]; index++; switch (c) { case '{': return Token.Curly_Open; case '}': return Token.Curly_Close; case '[': return Token.Squared_Open; case ']': return Token.Squared_Close; case ',': return Token.Comma; case '"': case '\'': return Token.String; case '-': if (p[index] == 'i' || p[index] == 'I') { index += 8; return Token.NegInfinity; } return Token.Number; case '+': if (p[index] == 'i' || p[index] == 'I') { index += 8; return Token.PosInfinity; } return Token.Number; case '.': case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': return Token.Number; case ':': return Token.Colon; case 'I': case 'i': index += 7; return Token.PosInfinity; case 'f': if (len - index >= 4 && p[index] == 'a' && p[index + 1] == 'l' && p[index + 2] == 's' && p[index + 3] == 'e') { index += 4; return Token.False; } break; case 't': if (len - index >= 3 && p[index] == 'r' && p[index + 1] == 'u' && p[index + 2] == 'e') { index += 3; return Token.True; } break; case 'N': case 'n': if (len - index >= 3 && p[index] == 'u' && p[index + 1] == 'l' && p[index + 2] == 'l') { index += 3; return Token.Null; } if (len - index >= 2 && p[index] == 'a' && (p[index + 1] == 'n' || p[index + 1] == 'N')) { index += 2; return Token.NaN; } break; } if (allownonquotedkey) { index--; return Token.String; } string[] obj = new string[5] { "Could not find token at index ", null, null, null, null }; obj[1] = (--index).ToString(); obj[2] = " got '"; obj[3] = p[index].ToString(); obj[4] = "'"; throw new Exception(string.Concat(obj)); } private unsafe static string UnsafeSubstring(char* p, int startIndex, int length) { return new string(p, startIndex, length); } } internal sealed class JSONSerializer { private StringBuilder _output = new StringBuilder(); private int _before; private int _MAX_DEPTH = 20; private int _current_depth; private Dictionary _globalTypes = new Dictionary(); private Dictionary _cirobj; private JSONParameters _params; private bool _useEscapedUnicode; private bool _TypesWritten; internal JSONSerializer(JSONParameters param) { if (param.OverrideObjectHashCodeChecking) { _cirobj = new Dictionary(10, ReferenceEqualityComparer.Default); } else { _cirobj = new Dictionary(); } _params = param; _useEscapedUnicode = _params.UseEscapedUnicode; _MAX_DEPTH = _params.SerializerMaxDepth; } internal string ConvertToJSON(object obj) { WriteValue(obj); if (_params.UsingGlobalTypes && _globalTypes != null && _globalTypes.Count > 0) { StringBuilder stringBuilder = new StringBuilder(); stringBuilder.Append("\"$types\":{"); bool flag = false; foreach (KeyValuePair globalType in _globalTypes) { if (flag) { stringBuilder.Append(','); } flag = true; stringBuilder.Append('"'); stringBuilder.Append(globalType.Key); stringBuilder.Append("\":\""); stringBuilder.Append(globalType.Value); stringBuilder.Append('"'); } stringBuilder.Append("},"); _output.Insert(_before, stringBuilder.ToString()); } return _output.ToString(); } private void WriteValue(object obj) { if (obj == null || obj is DBNull) { _output.Append("null"); } else if (obj is string || obj is char) { WriteString(obj.ToString()); } else if (obj is Guid) { WriteGuid((Guid)obj); } else if (obj is bool) { _output.Append(((bool)obj) ? "true" : "false"); } else if (obj is int || obj is long || obj is decimal || obj is byte || obj is short || obj is sbyte || obj is ushort || obj is uint || obj is ulong) { _output.Append(((IConvertible)obj).ToString(NumberFormatInfo.InvariantInfo)); } else if (obj is double || obj is double) { double d = (double)obj; if (double.IsNaN(d)) { _output.Append("\"NaN\""); } else if (double.IsInfinity(d)) { _output.Append('"'); _output.Append(((IConvertible)obj).ToString(NumberFormatInfo.InvariantInfo)); _output.Append('"'); } else { _output.Append(((IConvertible)obj).ToString(NumberFormatInfo.InvariantInfo)); } } else if (obj is float || obj is float) { float f = (float)obj; if (float.IsNaN(f)) { _output.Append("\"NaN\""); } else if (float.IsInfinity(f)) { _output.Append('"'); _output.Append(((IConvertible)obj).ToString(NumberFormatInfo.InvariantInfo)); _output.Append('"'); } else { _output.Append(((IConvertible)obj).ToString(NumberFormatInfo.InvariantInfo)); } } else if (obj is DateTime) { WriteDateTime((DateTime)obj); } else if (obj is DateTimeOffset) { WriteDateTimeOffset((DateTimeOffset)obj); } else if (obj is TimeSpan) { _output.Append(((TimeSpan)obj).Ticks); } else if (!_params.KVStyleStringDictionary && obj is IEnumerable>) { WriteStringDictionary((IEnumerable>)obj); } else if (!_params.KVStyleStringDictionary && obj is IDictionary && obj.GetType().IsGenericType && Reflection.Instance.GetGenericArguments(obj.GetType())[0] == typeof(string)) { WriteStringDictionary((IDictionary)obj); } else if (obj is IDictionary) { WriteDictionary((IDictionary)obj); } else if (obj is byte[]) { WriteBytes((byte[])obj); } else if (obj is StringDictionary) { WriteSD((StringDictionary)obj); } else if (obj is NameValueCollection) { WriteNV((NameValueCollection)obj); } else if (obj is Array) { WriteArrayRanked((Array)obj); } else if (obj is IEnumerable) { WriteArray((IEnumerable)obj); } else if (obj is Enum) { WriteEnum((Enum)obj); } else if (Reflection.Instance.IsTypeRegistered(obj.GetType())) { WriteCustom(obj); } else { WriteObject(obj); } } private void WriteDateTimeOffset(DateTimeOffset d) { DateTime dt = (_params.UseUTCDateTime ? d.UtcDateTime : d.DateTime); write_date_value(dt); long num = dt.Ticks % 10000000; _output.Append('.'); _output.Append(num.ToString("0000000", NumberFormatInfo.InvariantInfo)); if (_params.UseUTCDateTime) { _output.Append('Z'); } else { if (d.Offset.Hours > 0) { _output.Append('+'); } else { _output.Append('-'); } _output.Append(d.Offset.Hours.ToString("00", NumberFormatInfo.InvariantInfo)); _output.Append(':'); _output.Append(d.Offset.Minutes.ToString("00", NumberFormatInfo.InvariantInfo)); } _output.Append('"'); } private void WriteNV(NameValueCollection nameValueCollection) { _output.Append('{'); bool flag = false; foreach (string item in nameValueCollection) { if (_params.SerializeNullValues || nameValueCollection[item] != null) { if (flag) { _output.Append(','); } if (_params.SerializeToLowerCaseNames) { WritePair(item.ToLowerInvariant(), nameValueCollection[item]); } else { WritePair(item, nameValueCollection[item]); } flag = true; } } _output.Append('}'); } private void WriteSD(StringDictionary stringDictionary) { _output.Append('{'); bool flag = false; foreach (DictionaryEntry item in stringDictionary) { if (_params.SerializeNullValues || item.Value != null) { if (flag) { _output.Append(','); } string text = (string)item.Key; if (_params.SerializeToLowerCaseNames) { WritePair(text.ToLowerInvariant(), item.Value); } else { WritePair(text, item.Value); } flag = true; } } _output.Append('}'); } private void WriteCustom(object obj) { Reflection.Instance._customSerializer.TryGetValue(obj.GetType(), out var value); WriteStringFast(value(obj)); } private void WriteEnum(Enum e) { if (_params.UseValuesOfEnums) { WriteValue(Convert.ToInt32(e)); } else { WriteStringFast(e.ToString()); } } private void WriteGuid(Guid g) { if (!_params.UseFastGuid) { WriteStringFast(g.ToString()); } else { WriteBytes(g.ToByteArray()); } } private void WriteBytes(byte[] bytes) { WriteStringFast(Convert.ToBase64String(bytes, 0, bytes.Length, Base64FormattingOptions.None)); } private void WriteDateTime(DateTime dateTime) { DateTime dt = dateTime; if (_params.UseUTCDateTime) { dt = dateTime.ToUniversalTime(); } write_date_value(dt); if (_params.DateTimeMilliseconds) { _output.Append('.'); _output.Append(dt.Millisecond.ToString("000", NumberFormatInfo.InvariantInfo)); } if (_params.UseUTCDateTime) { _output.Append('Z'); } _output.Append('"'); } private void write_date_value(DateTime dt) { _output.Append('"'); _output.Append(dt.Year.ToString("0000", NumberFormatInfo.InvariantInfo)); _output.Append('-'); _output.Append(dt.Month.ToString("00", NumberFormatInfo.InvariantInfo)); _output.Append('-'); _output.Append(dt.Day.ToString("00", NumberFormatInfo.InvariantInfo)); _output.Append('T'); _output.Append(dt.Hour.ToString("00", NumberFormatInfo.InvariantInfo)); _output.Append(':'); _output.Append(dt.Minute.ToString("00", NumberFormatInfo.InvariantInfo)); _output.Append(':'); _output.Append(dt.Second.ToString("00", NumberFormatInfo.InvariantInfo)); } private void WriteObject(object obj) { int value = 0; if (!_cirobj.TryGetValue(obj, out value)) { _cirobj.Add(obj, _cirobj.Count + 1); } else if (_current_depth > 0 && !_params.InlineCircularReferences) { _output.Append("{\"$i\":"); _output.Append(value.ToString()); _output.Append('}'); return; } if (!_params.UsingGlobalTypes) { _output.Append('{'); } else if (!_TypesWritten) { _output.Append('{'); _before = _output.Length; } else { _output.Append('{'); } _TypesWritten = true; _current_depth++; if (_current_depth > _MAX_DEPTH) { throw new Exception("Serializer encountered maximum depth of " + _MAX_DEPTH); } Dictionary dictionary = new Dictionary(); Type type = obj.GetType(); bool flag = false; if (_params.UseExtensions) { if (!_params.UsingGlobalTypes) { WritePairFast("$type", Reflection.Instance.GetTypeAssemblyName(type)); } else { int value2 = 0; string typeAssemblyName = Reflection.Instance.GetTypeAssemblyName(type); if (!_globalTypes.TryGetValue(typeAssemblyName, out value2)) { value2 = _globalTypes.Count + 1; _globalTypes.Add(typeAssemblyName, value2); } WritePairFast("$type", value2.ToString()); } flag = true; } Getters[] getters = Reflection.Instance.GetGetters(type, _params.IgnoreAttributes); int num = getters.Length; for (int i = 0; i < num; i++) { Getters getters2 = getters[i]; if (!_params.ShowReadOnlyProperties && getters2.ReadOnly) { continue; } object obj2 = getters2.Getter(obj); if (!_params.SerializeNullValues && (obj2 == null || obj2 is DBNull)) { continue; } if (flag) { _output.Append(','); } if (getters2.memberName != null) { WritePair(getters2.memberName, obj2); } else if (_params.SerializeToLowerCaseNames) { WritePair(getters2.lcName, obj2); } else { WritePair(getters2.Name, obj2); } if (obj2 != null && _params.UseExtensions) { Type type2 = obj2.GetType(); if (type2 == typeof(object)) { dictionary.Add(getters2.Name, type2.ToString()); } } flag = true; } if (dictionary.Count > 0 && _params.UseExtensions) { _output.Append(",\"$map\":"); WriteStringDictionary(dictionary); } _output.Append('}'); _current_depth--; } private void WritePairFast(string name, string value) { WriteStringFast(name); _output.Append(':'); WriteStringFast(value); } private void WritePair(string name, object value) { WriteString(name); _output.Append(':'); WriteValue(value); } private void WriteArray(IEnumerable array) { _output.Append('['); bool flag = false; foreach (object item in array) { if (flag) { _output.Append(','); } WriteValue(item); flag = true; } _output.Append(']'); } private void WriteArrayRanked(Array array) { if (array.Rank == 1) { WriteArray(array); return; } _output.Append('['); bool flag = false; foreach (object item in array) { if (flag) { _output.Append(','); } WriteValue(item); flag = true; } _output.Append(']'); } private void WriteStringDictionary(IDictionary dic) { _output.Append('{'); bool flag = false; foreach (DictionaryEntry item in dic) { if (_params.SerializeNullValues || item.Value != null) { if (flag) { _output.Append(','); } string text = (string)item.Key; if (_params.SerializeToLowerCaseNames) { WritePair(text.ToLowerInvariant(), item.Value); } else { WritePair(text, item.Value); } flag = true; } } _output.Append('}'); } private void WriteStringDictionary(IEnumerable> dic) { _output.Append('{'); bool flag = false; foreach (KeyValuePair item in dic) { if (_params.SerializeNullValues || item.Value != null) { if (flag) { _output.Append(','); } string key = item.Key; if (_params.SerializeToLowerCaseNames) { WritePair(key.ToLowerInvariant(), item.Value); } else { WritePair(key, item.Value); } flag = true; } } _output.Append('}'); } private void WriteDictionary(IDictionary dic) { _output.Append('['); bool flag = false; foreach (DictionaryEntry item in dic) { if (flag) { _output.Append(','); } _output.Append('{'); WritePair("k", item.Key); _output.Append(','); WritePair("v", item.Value); _output.Append('}'); flag = true; } _output.Append(']'); } private void WriteStringFast(string s) { _output.Append('"'); _output.Append(s); _output.Append('"'); } private void WriteString(string s) { _output.Append('"'); int num = -1; int length = s.Length; for (int i = 0; i < length; i++) { char c = s[i]; if (_useEscapedUnicode) { if (c >= ' ' && c < '\u0080' && c != '"' && c != '\\') { if (num == -1) { num = i; } continue; } } else if (c != '\t' && c != '\n' && c != '\r' && c != '"' && c != '\\' && c != 0) { if (num == -1) { num = i; } continue; } if (num != -1) { _output.Append(s, num, i - num); num = -1; } switch (c) { case '\t': _output.Append('\\').Append('t'); continue; case '\r': _output.Append('\\').Append('r'); continue; case '\n': _output.Append('\\').Append('n'); continue; case '"': case '\\': _output.Append('\\'); _output.Append(c); continue; case '\0': _output.Append("\\u0000"); continue; } if (_useEscapedUnicode) { _output.Append("\\u"); StringBuilder output = _output; int num2 = c; output.Append(num2.ToString("X4", NumberFormatInfo.InvariantInfo)); } else { _output.Append(c); } } if (num != -1) { _output.Append(s, num, s.Length - num); } _output.Append('"'); } } internal class myPropInfo { public Type pt; public Type bt; public Type changeType; public Reflection.GenericSetter setter; public Reflection.GenericGetter getter; public Type[] GenericTypes; public string Name; public string memberName; public myPropInfoType Type; public bool CanWrite; public bool IsClass; public bool IsValueType; public bool IsGenericType; public bool IsStruct; public bool IsInterface; } internal enum myPropInfoType { Int, Long, String, Bool, DateTime, Enum, Guid, Array, ByteArray, Dictionary, StringKeyDictionary, NameValue, StringDictionary, Hashtable, DataSet, DataTable, Custom, Unknown } internal class ReferenceEqualityComparer : IEqualityComparer, IEqualityComparer { public static ReferenceEqualityComparer Default { get; } = new ReferenceEqualityComparer(); public new bool Equals(object x, object y) { return x.Equals(y); } public int GetHashCode(object obj) { return RuntimeHelpers.GetHashCode(obj); } } internal sealed class Reflection { public delegate string Serialize(object data); public delegate object Deserialize(string data); public delegate object GenericSetter(object target, object value); public delegate object GenericGetter(object obj); private delegate object CreateObject(); private delegate object CreateList(int capacity); private static readonly Reflection instance; public static bool RDBMode; private SafeDictionary _tyname = new SafeDictionary(10); private SafeDictionary _typecache = new SafeDictionary(10); private SafeDictionary _constrcache = new SafeDictionary(10); private SafeDictionary _conlistcache = new SafeDictionary(10); private SafeDictionary _getterscache = new SafeDictionary(10); private SafeDictionary> _propertycache = new SafeDictionary>(10); private SafeDictionary _genericTypes = new SafeDictionary(10); private SafeDictionary _genericTypeDef = new SafeDictionary(10); private static SafeDictionary _opCodes; private static List _badlistTypes; private static UTF8Encoding utf8; internal SafeDictionary _customSerializer = new SafeDictionary(); internal SafeDictionary _customDeserializer = new SafeDictionary(); public static Reflection Instance => instance; static Reflection() { instance = new Reflection(); RDBMode = false; _badlistTypes = new List { "system.configuration.install.assemblyinstaller", "system.activities.presentation.workflowdesigner", "system.windows.resourcedictionary", "system.windows.data.objectdataprovider", "system.windows.forms.bindingsource", "microsoft.exchange.management.systemmanager.winforms.exchangesettingsprovider" }; utf8 = new UTF8Encoding(); } private Reflection() { } private static bool TryGetOpCode(short code, out OpCode opCode) { if (_opCodes != null) { return _opCodes.TryGetValue(code, out opCode); } SafeDictionary safeDictionary = new SafeDictionary(); FieldInfo[] fields = typeof(OpCodes).GetFields(BindingFlags.Static | BindingFlags.Public); foreach (FieldInfo fieldInfo in fields) { if (typeof(OpCode).IsAssignableFrom(fieldInfo.FieldType)) { OpCode value = (OpCode)fieldInfo.GetValue(null); if (value.OpCodeType != OpCodeType.Nternal) { safeDictionary.Add(value.Value, value); } } } _opCodes = safeDictionary; return _opCodes.TryGetValue(code, out opCode); } public static byte[] UTF8GetBytes(string str) { return utf8.GetBytes(str); } public static string UTF8GetString(byte[] bytes, int offset, int len) { return utf8.GetString(bytes, offset, len); } public unsafe static byte[] UnicodeGetBytes(string str) { int num = str.Length * 2; byte[] array = new byte[num]; fixed (void* value = str) { Marshal.Copy(new IntPtr(value), array, 0, num); } return array; } public static string UnicodeGetString(byte[] b) { return UnicodeGetString(b, 0, b.Length); } public unsafe static string UnicodeGetString(byte[] bytes, int offset, int buflen) { string result; fixed (byte* ptr = bytes) { char* value = (char*)(ptr + offset); result = new string(value, 0, buflen / 2); } return result; } internal object CreateCustom(string v, Type type) { _customDeserializer.TryGetValue(type, out var value); return value(v); } internal void RegisterCustomType(Type type, Serialize serializer, Deserialize deserializer) { if (type != null && serializer != null && deserializer != null) { _customSerializer.Add(type, serializer); _customDeserializer.Add(type, deserializer); Instance.ResetPropertyCache(); } } internal bool IsTypeRegistered(Type t) { if (_customSerializer.Count() == 0) { return false; } Serialize value; return _customSerializer.TryGetValue(t, out value); } public Type GetGenericTypeDefinition(Type t) { Type value = null; if (_genericTypeDef.TryGetValue(t, out value)) { return value; } value = t.GetGenericTypeDefinition(); _genericTypeDef.Add(t, value); return value; } public Type[] GetGenericArguments(Type t) { Type[] value = null; if (_genericTypes.TryGetValue(t, out value)) { return value; } value = t.GetGenericArguments(); _genericTypes.Add(t, value); return value; } public Dictionary Getproperties(Type type, string typename, bool ShowReadOnlyProperties) { Dictionary value = null; if (_propertycache.TryGetValue(typename, out value)) { return value; } value = new Dictionary(10); BindingFlags bindingAttr = BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public; PropertyInfo[] properties = type.GetProperties(bindingAttr); foreach (PropertyInfo propertyInfo in properties) { if (propertyInfo.GetIndexParameters().Length != 0) { continue; } myPropInfo myPropInfo2 = CreateMyProp(propertyInfo.PropertyType, propertyInfo.Name); myPropInfo2.setter = CreateSetMethod(type, propertyInfo, ShowReadOnlyProperties); if (myPropInfo2.setter != null) { myPropInfo2.CanWrite = true; } myPropInfo2.getter = CreateGetMethod(type, propertyInfo); object[] customAttributes = propertyInfo.GetCustomAttributes(inherit: true); foreach (object obj in customAttributes) { if (obj is DataMemberAttribute) { DataMemberAttribute dataMemberAttribute = (DataMemberAttribute)obj; if (dataMemberAttribute.Name != "") { myPropInfo2.memberName = dataMemberAttribute.Name; } } } if (myPropInfo2.memberName != null) { value.Add(myPropInfo2.memberName, myPropInfo2); } else { value.Add(propertyInfo.Name.ToLowerInvariant(), myPropInfo2); } } FieldInfo[] fields = type.GetFields(bindingAttr); foreach (FieldInfo fieldInfo in fields) { myPropInfo myPropInfo3 = CreateMyProp(fieldInfo.FieldType, fieldInfo.Name); if (fieldInfo.IsLiteral) { continue; } if (!fieldInfo.IsInitOnly) { myPropInfo3.setter = CreateSetField(type, fieldInfo); } if (myPropInfo3.setter != null) { myPropInfo3.CanWrite = true; } myPropInfo3.getter = CreateGetField(type, fieldInfo); object[] customAttributes = fieldInfo.GetCustomAttributes(inherit: true); foreach (object obj2 in customAttributes) { if (obj2 is DataMemberAttribute) { DataMemberAttribute dataMemberAttribute2 = (DataMemberAttribute)obj2; if (dataMemberAttribute2.Name != "") { myPropInfo3.memberName = dataMemberAttribute2.Name; } } } if (myPropInfo3.memberName != null) { value.Add(myPropInfo3.memberName, myPropInfo3); } else { value.Add(fieldInfo.Name.ToLowerInvariant(), myPropInfo3); } } _propertycache.Add(typename, value); return value; } private myPropInfo CreateMyProp(Type t, string name) { myPropInfo myPropInfo2 = new myPropInfo(); myPropInfoType type = myPropInfoType.Unknown; if (t == typeof(int) || t == typeof(int?)) { type = myPropInfoType.Int; } else if (t == typeof(long) || t == typeof(long?)) { type = myPropInfoType.Long; } else if (t == typeof(string)) { type = myPropInfoType.String; } else if (t == typeof(bool) || t == typeof(bool?)) { type = myPropInfoType.Bool; } else if (t == typeof(DateTime) || t == typeof(DateTime?)) { type = myPropInfoType.DateTime; } else if (t.IsEnum) { type = myPropInfoType.Enum; } else if (t == typeof(Guid) || t == typeof(Guid?)) { type = myPropInfoType.Guid; } else if (t == typeof(StringDictionary)) { type = myPropInfoType.StringDictionary; } else if (t == typeof(NameValueCollection)) { type = myPropInfoType.NameValue; } else if (t.IsArray) { myPropInfo2.bt = t.GetElementType(); type = ((!(t == typeof(byte[]))) ? myPropInfoType.Array : myPropInfoType.ByteArray); } else if (t.Name.Contains("Dictionary")) { myPropInfo2.GenericTypes = Instance.GetGenericArguments(t); type = ((myPropInfo2.GenericTypes.Length == 0 || !(myPropInfo2.GenericTypes[0] == typeof(string))) ? myPropInfoType.Dictionary : myPropInfoType.StringKeyDictionary); } else if (IsTypeRegistered(t)) { type = myPropInfoType.Custom; } if (t.IsValueType && !t.IsPrimitive && !t.IsEnum && t != typeof(decimal)) { myPropInfo2.IsStruct = true; } myPropInfo2.IsInterface = t.IsInterface; myPropInfo2.IsClass = t.IsClass; myPropInfo2.IsValueType = t.IsValueType; if (t.IsGenericType) { myPropInfo2.IsGenericType = true; myPropInfo2.bt = Instance.GetGenericArguments(t)[0]; } myPropInfo2.pt = t; myPropInfo2.Name = name; myPropInfo2.changeType = GetChangeType(t); myPropInfo2.Type = type; return myPropInfo2; } private Type GetChangeType(Type conversionType) { if (conversionType.IsGenericType && conversionType.GetGenericTypeDefinition().Equals(typeof(Nullable<>))) { return Instance.GetGenericArguments(conversionType)[0]; } return conversionType; } public string GetTypeAssemblyName(Type t) { string value = ""; if (_tyname.TryGetValue(t, out value)) { return value; } string assemblyQualifiedName = t.AssemblyQualifiedName; _tyname.Add(t, assemblyQualifiedName); return assemblyQualifiedName; } internal Type GetTypeFromCache(string typename, bool badlistChecking) { Type value = null; if (_typecache.TryGetValue(typename, out value)) { return value; } if (badlistChecking) { string text = typename.Trim().ToLowerInvariant(); foreach (string badlistType in _badlistTypes) { if (text.StartsWith(badlistType, StringComparison.Ordinal)) { throw new Exception("Black list type encountered, possible attack vector when using $type : " + typename); } } } Type type = Type.GetType(typename); _typecache.Add(typename, type); return type; } internal object FastCreateList(Type objtype, int capacity) { try { int capacity2 = 10; if (capacity > 10) { capacity2 = capacity; } CreateList value = null; if (_conlistcache.TryGetValue(objtype, out value)) { if (value != null) { return value(capacity2); } return FastCreateInstance(objtype); } if (objtype.GetConstructor(new Type[1] { typeof(int) }) != null) { DynamicMethod dynamicMethod = new DynamicMethod("_fcil", objtype, new Type[1] { typeof(int) }, restrictedSkipVisibility: true); ILGenerator iLGenerator = dynamicMethod.GetILGenerator(); iLGenerator.Emit(OpCodes.Ldarg_0); iLGenerator.Emit(OpCodes.Newobj, objtype.GetConstructor(new Type[1] { typeof(int) })); iLGenerator.Emit(OpCodes.Ret); value = (CreateList)dynamicMethod.CreateDelegate(typeof(CreateList)); _conlistcache.Add(objtype, value); return value(capacity2); } _conlistcache.Add(objtype, null); return FastCreateInstance(objtype); } catch (Exception innerException) { throw new Exception("Failed to fast create instance for type '" + objtype.FullName + "' from assembly '" + objtype.AssemblyQualifiedName + "'", innerException); } } internal object FastCreateInstance(Type objtype) { try { CreateObject value = null; if (_constrcache.TryGetValue(objtype, out value)) { return value(); } if (objtype.IsClass) { DynamicMethod dynamicMethod = new DynamicMethod("_fcic", objtype, null, restrictedSkipVisibility: true); ILGenerator iLGenerator = dynamicMethod.GetILGenerator(); iLGenerator.Emit(OpCodes.Newobj, objtype.GetConstructor(Type.EmptyTypes)); iLGenerator.Emit(OpCodes.Ret); value = (CreateObject)dynamicMethod.CreateDelegate(typeof(CreateObject)); _constrcache.Add(objtype, value); } else { DynamicMethod dynamicMethod2 = new DynamicMethod("_fcis", typeof(object), null, restrictedSkipVisibility: true); ILGenerator iLGenerator2 = dynamicMethod2.GetILGenerator(); iLGenerator2.Emit(local: iLGenerator2.DeclareLocal(objtype), opcode: OpCodes.Ldloca_S); iLGenerator2.Emit(OpCodes.Initobj, objtype); iLGenerator2.Emit(OpCodes.Ldloc_0); iLGenerator2.Emit(OpCodes.Box, objtype); iLGenerator2.Emit(OpCodes.Ret); value = (CreateObject)dynamicMethod2.CreateDelegate(typeof(CreateObject)); _constrcache.Add(objtype, value); } return value(); } catch (Exception innerException) { throw new Exception("Failed to fast create instance for type '" + objtype.FullName + "' from assembly '" + objtype.AssemblyQualifiedName + "'", innerException); } } internal static GenericSetter CreateSetField(Type type, FieldInfo fieldInfo) { Type[] array = new Type[2]; array[0] = (array[1] = typeof(object)); DynamicMethod dynamicMethod = new DynamicMethod("_csf", typeof(object), array, type, skipVisibility: true); ILGenerator iLGenerator = dynamicMethod.GetILGenerator(); if (!type.IsClass) { LocalBuilder local = iLGenerator.DeclareLocal(type); iLGenerator.Emit(OpCodes.Ldarg_0); iLGenerator.Emit(OpCodes.Unbox_Any, type); iLGenerator.Emit(OpCodes.Stloc_0); iLGenerator.Emit(OpCodes.Ldloca_S, local); iLGenerator.Emit(OpCodes.Ldarg_1); if (fieldInfo.FieldType.IsClass) { iLGenerator.Emit(OpCodes.Castclass, fieldInfo.FieldType); } else { iLGenerator.Emit(OpCodes.Unbox_Any, fieldInfo.FieldType); } iLGenerator.Emit(OpCodes.Stfld, fieldInfo); iLGenerator.Emit(OpCodes.Ldloc_0); iLGenerator.Emit(OpCodes.Box, type); iLGenerator.Emit(OpCodes.Ret); } else { iLGenerator.Emit(OpCodes.Ldarg_0); iLGenerator.Emit(OpCodes.Ldarg_1); if (fieldInfo.FieldType.IsValueType) { iLGenerator.Emit(OpCodes.Unbox_Any, fieldInfo.FieldType); } iLGenerator.Emit(OpCodes.Stfld, fieldInfo); iLGenerator.Emit(OpCodes.Ldarg_0); iLGenerator.Emit(OpCodes.Ret); } return (GenericSetter)dynamicMethod.CreateDelegate(typeof(GenericSetter)); } internal static FieldInfo GetGetterBackingField(PropertyInfo autoProperty) { MethodInfo getMethod = autoProperty.GetGetMethod(); if (!getMethod.IsDefined(typeof(CompilerGeneratedAttribute), inherit: false)) { return null; } byte[] array = getMethod.GetMethodBody()?.GetILAsByteArray() ?? new byte[0]; OpCode opCode; for (int i = 0; i < array.Length; i += ((opCode.OperandType != OperandType.InlineNone) ? ((opCode.OperandType == OperandType.ShortInlineBrTarget || opCode.OperandType == OperandType.ShortInlineI || opCode.OperandType == OperandType.ShortInlineVar) ? 1 : ((opCode.OperandType == OperandType.InlineVar) ? 2 : ((opCode.OperandType == OperandType.InlineI8 || opCode.OperandType == OperandType.InlineR) ? 8 : ((opCode.OperandType == OperandType.InlineSwitch) ? (4 * (BitConverter.ToInt32(array, i) + 1)) : 4)))) : 0)) { byte b = array[i++]; if (!TryGetOpCode(b, out opCode) && (i >= array.Length || !TryGetOpCode((short)(b * 256 + array[i++]), out opCode))) { throw new NotSupportedException("Unknown IL code detected."); } if (opCode == OpCodes.Ldfld && opCode.OperandType == OperandType.InlineField && i + 4 <= array.Length) { return getMethod.Module.ResolveMember(BitConverter.ToInt32(array, i), getMethod.DeclaringType?.GetGenericArguments(), null) as FieldInfo; } } return null; } internal static GenericSetter CreateSetMethod(Type type, PropertyInfo propertyInfo, bool ShowReadOnlyProperties) { MethodInfo setMethod = propertyInfo.GetSetMethod(ShowReadOnlyProperties); if (setMethod == null) { if (!ShowReadOnlyProperties) { return null; } FieldInfo getterBackingField = GetGetterBackingField(propertyInfo); if (!(getterBackingField != null)) { return null; } return CreateSetField(type, getterBackingField); } Type[] array = new Type[2]; array[0] = (array[1] = typeof(object)); DynamicMethod dynamicMethod = new DynamicMethod("_csm", typeof(object), array, restrictedSkipVisibility: true); ILGenerator iLGenerator = dynamicMethod.GetILGenerator(); if (!type.IsClass) { LocalBuilder local = iLGenerator.DeclareLocal(type); iLGenerator.Emit(OpCodes.Ldarg_0); iLGenerator.Emit(OpCodes.Unbox_Any, type); iLGenerator.Emit(OpCodes.Stloc_0); iLGenerator.Emit(OpCodes.Ldloca_S, local); iLGenerator.Emit(OpCodes.Ldarg_1); if (propertyInfo.PropertyType.IsClass) { iLGenerator.Emit(OpCodes.Castclass, propertyInfo.PropertyType); } else { iLGenerator.Emit(OpCodes.Unbox_Any, propertyInfo.PropertyType); } iLGenerator.EmitCall(OpCodes.Call, setMethod, null); iLGenerator.Emit(OpCodes.Ldloc_0); iLGenerator.Emit(OpCodes.Box, type); } else if (!setMethod.IsStatic) { iLGenerator.Emit(OpCodes.Ldarg_0); iLGenerator.Emit(OpCodes.Castclass, propertyInfo.DeclaringType); iLGenerator.Emit(OpCodes.Ldarg_1); if (propertyInfo.PropertyType.IsClass) { iLGenerator.Emit(OpCodes.Castclass, propertyInfo.PropertyType); } else { iLGenerator.Emit(OpCodes.Unbox_Any, propertyInfo.PropertyType); } iLGenerator.EmitCall(OpCodes.Callvirt, setMethod, null); iLGenerator.Emit(OpCodes.Ldarg_0); } else { iLGenerator.Emit(OpCodes.Ldarg_0); iLGenerator.Emit(OpCodes.Ldarg_1); if (propertyInfo.PropertyType.IsClass) { iLGenerator.Emit(OpCodes.Castclass, propertyInfo.PropertyType); } else { iLGenerator.Emit(OpCodes.Unbox_Any, propertyInfo.PropertyType); } iLGenerator.Emit(OpCodes.Call, setMethod); } iLGenerator.Emit(OpCodes.Ret); return (GenericSetter)dynamicMethod.CreateDelegate(typeof(GenericSetter)); } internal static GenericGetter CreateGetField(Type type, FieldInfo fieldInfo) { DynamicMethod dynamicMethod = new DynamicMethod("_cgf", typeof(object), new Type[1] { typeof(object) }, type, skipVisibility: true); ILGenerator iLGenerator = dynamicMethod.GetILGenerator(); if (!type.IsClass) { LocalBuilder local = iLGenerator.DeclareLocal(type); iLGenerator.Emit(OpCodes.Ldarg_0); iLGenerator.Emit(OpCodes.Unbox_Any, type); iLGenerator.Emit(OpCodes.Stloc_0); iLGenerator.Emit(OpCodes.Ldloca_S, local); iLGenerator.Emit(OpCodes.Ldfld, fieldInfo); if (fieldInfo.FieldType.IsValueType) { iLGenerator.Emit(OpCodes.Box, fieldInfo.FieldType); } } else { iLGenerator.Emit(OpCodes.Ldarg_0); iLGenerator.Emit(OpCodes.Ldfld, fieldInfo); if (fieldInfo.FieldType.IsValueType) { iLGenerator.Emit(OpCodes.Box, fieldInfo.FieldType); } } iLGenerator.Emit(OpCodes.Ret); return (GenericGetter)dynamicMethod.CreateDelegate(typeof(GenericGetter)); } internal static GenericGetter CreateGetMethod(Type type, PropertyInfo propertyInfo) { MethodInfo getMethod = propertyInfo.GetGetMethod(); if (getMethod == null) { return null; } DynamicMethod dynamicMethod = new DynamicMethod("_cgm", typeof(object), new Type[1] { typeof(object) }, type, skipVisibility: true); ILGenerator iLGenerator = dynamicMethod.GetILGenerator(); if (!type.IsClass) { LocalBuilder local = iLGenerator.DeclareLocal(type); iLGenerator.Emit(OpCodes.Ldarg_0); iLGenerator.Emit(OpCodes.Unbox_Any, type); iLGenerator.Emit(OpCodes.Stloc_0); iLGenerator.Emit(OpCodes.Ldloca_S, local); iLGenerator.EmitCall(OpCodes.Call, getMethod, null); if (propertyInfo.PropertyType.IsValueType) { iLGenerator.Emit(OpCodes.Box, propertyInfo.PropertyType); } } else { if (!getMethod.IsStatic) { iLGenerator.Emit(OpCodes.Ldarg_0); iLGenerator.Emit(OpCodes.Castclass, propertyInfo.DeclaringType); iLGenerator.EmitCall(OpCodes.Callvirt, getMethod, null); } else { iLGenerator.Emit(OpCodes.Call, getMethod); } if (propertyInfo.PropertyType.IsValueType) { iLGenerator.Emit(OpCodes.Box, propertyInfo.PropertyType); } } iLGenerator.Emit(OpCodes.Ret); return (GenericGetter)dynamicMethod.CreateDelegate(typeof(GenericGetter)); } public Getters[] GetGetters(Type type, List IgnoreAttributes) { Getters[] value = null; if (_getterscache.TryGetValue(type, out value)) { return value; } BindingFlags bindingAttr = BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public; PropertyInfo[] properties = type.GetProperties(bindingAttr); List list = new List(); PropertyInfo[] array = properties; foreach (PropertyInfo propertyInfo in array) { bool readOnly = false; if (propertyInfo.GetIndexParameters().Length != 0) { continue; } if (!propertyInfo.CanWrite) { readOnly = true; } if (IgnoreAttributes != null) { bool flag = false; foreach (Type IgnoreAttribute in IgnoreAttributes) { if (propertyInfo.IsDefined(IgnoreAttribute, inherit: false)) { flag = true; break; } } if (flag) { continue; } } string memberName = null; object[] customAttributes = propertyInfo.GetCustomAttributes(inherit: true); foreach (object obj in customAttributes) { if (obj is DataMemberAttribute) { DataMemberAttribute dataMemberAttribute = (DataMemberAttribute)obj; if (dataMemberAttribute.Name != "") { memberName = dataMemberAttribute.Name; } } } GenericGetter genericGetter = CreateGetMethod(type, propertyInfo); if (genericGetter != null) { list.Add(new Getters { Getter = genericGetter, Name = propertyInfo.Name, lcName = propertyInfo.Name.ToLowerInvariant(), memberName = memberName, ReadOnly = readOnly }); } } FieldInfo[] fields = type.GetFields(bindingAttr); foreach (FieldInfo fieldInfo in fields) { bool readOnly2 = false; if (fieldInfo.IsInitOnly) { readOnly2 = true; } if (IgnoreAttributes != null) { bool flag2 = false; foreach (Type IgnoreAttribute2 in IgnoreAttributes) { if (fieldInfo.IsDefined(IgnoreAttribute2, inherit: false)) { flag2 = true; break; } } if (flag2) { continue; } } string memberName2 = null; object[] customAttributes = fieldInfo.GetCustomAttributes(inherit: true); foreach (object obj2 in customAttributes) { if (obj2 is DataMemberAttribute) { DataMemberAttribute dataMemberAttribute2 = (DataMemberAttribute)obj2; if (dataMemberAttribute2.Name != "") { memberName2 = dataMemberAttribute2.Name; } } } if (!fieldInfo.IsLiteral) { GenericGetter genericGetter2 = CreateGetField(type, fieldInfo); if (genericGetter2 != null) { list.Add(new Getters { Getter = genericGetter2, Name = fieldInfo.Name, lcName = fieldInfo.Name.ToLowerInvariant(), memberName = memberName2, ReadOnly = readOnly2 }); } } } value = list.ToArray(); _getterscache.Add(type, value); return value; } internal void ResetPropertyCache() { _propertycache = new SafeDictionary>(); } internal void ClearReflectionCache() { _tyname = new SafeDictionary(10); _typecache = new SafeDictionary(10); _constrcache = new SafeDictionary(10); _getterscache = new SafeDictionary(10); _propertycache = new SafeDictionary>(10); _genericTypes = new SafeDictionary(10); _genericTypeDef = new SafeDictionary(10); } } internal sealed class SafeDictionary { private readonly object _Padlock = new object(); private readonly Dictionary _Dictionary; public TValue this[TKey key] { get { lock (_Padlock) { return _Dictionary[key]; } } set { lock (_Padlock) { _Dictionary[key] = value; } } } public SafeDictionary(int capacity) { _Dictionary = new Dictionary(capacity); } public SafeDictionary() { _Dictionary = new Dictionary(); } public bool TryGetValue(TKey key, out TValue value) { lock (_Padlock) { return _Dictionary.TryGetValue(key, out value); } } public int Count() { lock (_Padlock) { return _Dictionary.Count; } } public void Add(TKey key, TValue value) { lock (_Padlock) { if (!_Dictionary.ContainsKey(key)) { _Dictionary.Add(key, value); } } } } } namespace Forteca_ServerRewards { internal static class ValheimCompat { private const BindingFlags AnyInstance = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic; private const BindingFlags AnyStatic = BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic; internal static bool Exists(Object obj) { return obj != (Object)null; } internal static double TotalSeconds() { object instance = EnvMan.instance; if (instance != null) { Type type = instance.GetType(); string[] array = new string[3] { "m_totalSeconds", "m_totalTime", "m_time" }; foreach (string name in array) { FieldInfo field = type.GetField(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (field != null && TryToDouble(field.GetValue(instance), out var result)) { return result; } PropertyInfo property = type.GetProperty(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (property != null && TryToDouble(property.GetValue(instance, null), out result)) { return result; } } } return Time.time; } private static bool TryToDouble(object value, out double result) { try { if (value != null) { result = Convert.ToDouble(value); return true; } } catch { } result = 0.0; return false; } internal static long GetServerPeerID() { ZRoutedRpc instance = ZRoutedRpc.instance; if (instance != null) { MethodInfo method = ((object)instance).GetType().GetMethod("GetServerPeerID", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (method != null) { object obj = method.Invoke(instance, null); if (obj is long) { return (long)obj; } } } ZNet instance2 = ZNet.instance; return ((instance2 != null) ? instance2.GetServerPeer() : null)?.m_uid ?? 0; } internal static ZNetPeer GetPeer(ZRpc rpc) { if ((Object)(object)ZNet.instance == (Object)null || rpc == null) { return null; } foreach (ZNetPeer peer in GetPeers()) { if (peer != null && peer.m_rpc == rpc) { return peer; } } return null; } internal static List GetPeers() { if ((Object)(object)ZNet.instance == (Object)null) { return new List(); } try { List peers = ZNet.instance.GetPeers(); if (peers != null) { return peers; } } catch { } FieldInfo? obj2 = typeof(ZNet).GetField("m_peers", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic) ?? typeof(ZRoutedRpc).GetField("m_peers", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); object obj3 = ((obj2?.DeclaringType == typeof(ZRoutedRpc)) ? ((object)ZRoutedRpc.instance) : ((object)ZNet.instance)); return (obj2?.GetValue(obj3) as List) ?? new List(); } internal static Inventory GetInventory(Humanoid humanoid) { if ((Object)(object)humanoid == (Object)null) { return null; } try { return humanoid.GetInventory(); } catch { object? obj2 = typeof(Humanoid).GetField("m_inventory", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.GetValue(humanoid); return (Inventory)((obj2 is Inventory) ? obj2 : null); } } internal static Inventory GetInventory(InventoryGrid grid) { if ((Object)(object)grid == (Object)null) { return null; } MethodInfo method = ((object)grid).GetType().GetMethod("GetInventory", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (method != null) { object? obj = method.Invoke(grid, null); return (Inventory)((obj is Inventory) ? obj : null); } object? obj2 = ((object)grid).GetType().GetField("m_inventory", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.GetValue(grid); return (Inventory)((obj2 is Inventory) ? obj2 : null); } internal static void SaveItemDrop(ItemDrop itemDrop) { if (!((Object)(object)itemDrop == (Object)null)) { ((object)itemDrop).GetType().GetMethod("Save", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.Invoke(itemDrop, null); } } internal static void SetTooltipShowTimer(UITooltip tooltip, float value) { if (!((Object)(object)tooltip == (Object)null)) { ((object)tooltip).GetType().GetField("m_showTimer", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.SetValue(tooltip, value); } } internal static void ReloadSyncedList(SyncedList list) { if (list == null) { return; } string[] array = new string[3] { "CheckLoad", "Reload", "Load" }; foreach (string name in array) { MethodInfo method = ((object)list).GetType().GetMethod(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (method != null && method.GetParameters().Length == 0) { method.Invoke(list, null); break; } } } internal static List GetSyncedListEntries(SyncedList list) { if (list == null) { return new List(); } if (((object)list).GetType().GetMethod("GetList", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.Invoke(list, null) is IEnumerable source) { return source.ToList(); } string[] array = new string[4] { "m_list", "list", "List", "Values" }; foreach (string name in array) { if (((object)list).GetType().GetField(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.GetValue(list) is IEnumerable source2) { return source2.ToList(); } if (((object)list).GetType().GetProperty(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.GetValue(list, null) is IEnumerable source3) { return source3.ToList(); } } return new List(); } internal static void SetZNetConnectionStatus(int status) { FieldInfo field = typeof(ZNet).GetField("m_connectionStatus", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); if (!(field == null)) { object value = (field.FieldType.IsEnum ? Enum.ToObject(field.FieldType, status) : ((object)status)); field.SetValue(null, value); } } } internal static class AdminSuite { internal sealed class PlayerRewardPackView { public string Name = ""; public string Description = ""; public int TokenCost; public string Status = ""; public List Rewards = new List(); } private sealed class RewardLine { public string Prefab = "Wood"; public int Amount = 1; public int Quality = 1; public int Variant; public string ToLine() { return Prefab + "," + Amount + "," + Quality + "," + Variant; } public RewardLine Clone() { return new RewardLine { Prefab = Prefab, Amount = Amount, Quality = Quality, Variant = Variant }; } public static RewardLine Parse(string line) { string[] array = (line ?? "Wood,1").Split(new char[1] { ',' }); return new RewardLine { Prefab = ((array.Length != 0 && array[0].Trim().Length > 0) ? array[0].Trim() : "Wood"), Amount = ParseInt(array, 1, 1), Quality = ParseInt(array, 2, 1), Variant = ParseInt(array, 3, 0) }; } } private sealed class DailyData { public string Name = "Daily"; public int Cooldown = 86400; public List Rewards = new List(); public RewardLine Get(int dayIndex) { while (Rewards.Count < 28) { Rewards.Add(new RewardLine()); } return Rewards[Mathf.Clamp(dayIndex, 1, 28) - 1]; } } private static class DailyManager { private static readonly Dictionary Data = new Dictionary(StringComparer.OrdinalIgnoreCase); private static RewardLine copiedDay; private static List copiedWeek; private static readonly Dictionary> UndoStacks = new Dictionary>(StringComparer.OrdinalIgnoreCase); private static readonly Dictionary> RedoStacks = new Dictionary>(StringComparer.OrdinalIgnoreCase); public static void LoadAll() { string[] categories = Categories; for (int i = 0; i < categories.Length; i++) { Load(categories[i]); } } public static DailyData Get(string cat) { if (!Data.ContainsKey(cat)) { Load(cat); } return Data[cat]; } public static string PathFor(string cat) { return FortecaPaths.DailyPathFor(cat); } public static void Load(string cat) { string path = PathFor(cat); if (!File.Exists(path)) { Data[cat] = Default(cat); Save(cat); return; } List list = (from x in File.ReadAllLines(path) select (x ?? "").Trim() into x where x.Length > 0 && !x.StartsWith("#") select x).ToList(); DailyData dailyData = new DailyData { Name = cat, Cooldown = 86400 }; if (list.Count > 0) { string[] array = list[0].Split(new char[1] { ',' }); if (array.Length != 0 && array[0].Trim().Length > 0) { dailyData.Name = array[0].Trim(); } if (array.Length > 1 && int.TryParse(array[1].Trim(), out var result)) { dailyData.Cooldown = result; } } for (int num = 1; num < list.Count; num++) { if (dailyData.Rewards.Count >= 28) { break; } dailyData.Rewards.Add(RewardLine.Parse(list[num])); } while (dailyData.Rewards.Count < 28) { dailyData.Rewards.Add(new RewardLine()); } Data[cat] = dailyData; } public static void Save(string cat) { DailyData dailyData = Get(cat); string path = PathFor(cat); BackupFile(path); List list = new List { dailyData.Name + "," + dailyData.Cooldown }; for (int i = 1; i <= 28; i++) { list.Add(dailyData.Get(i).ToLine()); } File.WriteAllLines(path, list); HistoryManager.Add("Admin", "0", "Daily Rewards", cat, "", "Admin UI", "Saved", "Saved " + cat); SetStatus(cat + " saved"); } public static void Update(string cat, int index, string prefab, string amount, string quality, string variant) { if (string.IsNullOrWhiteSpace(prefab)) { SetStatus("Prefab required"); return; } if (!int.TryParse(amount, out var result) || result < 0) { SetStatus("Invalid amount"); return; } if (!int.TryParse(quality, out var result2) || result2 < 0) { SetStatus("Invalid quality"); return; } if (!int.TryParse(variant, out var result3) || result3 < 0) { SetStatus("Invalid variant"); return; } Snapshot(cat); RewardLine rewardLine = Get(cat).Get(index); rewardLine.Prefab = prefab.Trim(); rewardLine.Amount = result; rewardLine.Quality = result2; rewardLine.Variant = result3; SetStatus("Updated " + cat + " day " + index + (((Object)(object)ZNetScene.instance != (Object)null && (Object)(object)ZNetScene.instance.GetPrefab(rewardLine.Prefab) == (Object)null && rewardLine.Prefab != "Coins" && rewardLine.Prefab != "Tokens") ? " (prefab warning)" : "")); } public static void CopyDay(string cat, int index) { copiedDay = Get(cat).Get(index).Clone(); SetStatus("Copied day " + index); } public static void PasteDay(string cat, int index) { if (copiedDay == null) { SetStatus("No copied day"); return; } Snapshot(cat); Get(cat).Rewards[index - 1] = copiedDay.Clone(); SetStatus("Pasted day " + index); } public static void CopyWeek(string cat, int index) { int start = (index - 1) / 7 * 7 + 1; copiedWeek = (from i in Enumerable.Range(start, 7) select Get(cat).Get(i).Clone()).ToList(); SetStatus("Copied week " + start); } public static void PasteWeek(string cat, int index) { if (copiedWeek == null) { SetStatus("No copied week"); return; } Snapshot(cat); int num = (index - 1) / 7 * 7 + 1; for (int i = 0; i < 7 && num + i <= 28; i++) { Get(cat).Rewards[num + i - 1] = copiedWeek[i].Clone(); } SetStatus("Pasted week " + num); } public static void Duplicate(string cat, int index) { Snapshot(cat); int num = Mathf.Clamp(index + 1, 1, 28); Get(cat).Rewards[num - 1] = Get(cat).Get(index).Clone(); SetStatus("Duplicated day " + index + " to " + num); } public static void ResetDay(string cat, int index) { Snapshot(cat); Get(cat).Rewards[index - 1] = new RewardLine(); SetStatus("Reset day " + index); } public static void ResetCategory(string cat) { Snapshot(cat); Data[cat] = Default(cat); SetStatus("Reset " + cat + " in editor"); } public static void AddReward(string cat, int index) { Snapshot(cat); Get(cat).Rewards[index - 1] = new RewardLine { Prefab = "Wood", Amount = 1, Quality = 1, Variant = 0 }; SetStatus("Added reward to day " + index); } public static void RemoveReward(string cat, int index) { Snapshot(cat); Get(cat).Rewards[index - 1] = new RewardLine { Prefab = "Wood", Amount = 0, Quality = 1, Variant = 0 }; SetStatus("Removed reward from day " + index + " (saved as Wood,0 for compatibility)"); } public static void Undo(string cat) { if (!UndoStacks.ContainsKey(cat) || UndoStacks[cat].Count == 0) { SetStatus("Nothing to undo"); return; } PushRedo(cat); Data[cat] = UndoStacks[cat].Pop(); SetStatus("Undo " + cat); } public static void Redo(string cat) { if (!RedoStacks.ContainsKey(cat) || RedoStacks[cat].Count == 0) { SetStatus("Nothing to redo"); return; } Snapshot(cat, clearRedo: false); Data[cat] = RedoStacks[cat].Pop(); SetStatus("Redo " + cat); } private static void Snapshot(string cat, bool clearRedo = true) { if (!UndoStacks.ContainsKey(cat)) { UndoStacks[cat] = new Stack(); } UndoStacks[cat].Push(Clone(Get(cat))); if (clearRedo) { if (!RedoStacks.ContainsKey(cat)) { RedoStacks[cat] = new Stack(); } else { RedoStacks[cat].Clear(); } } } private static void PushRedo(string cat) { if (!RedoStacks.ContainsKey(cat)) { RedoStacks[cat] = new Stack(); } RedoStacks[cat].Push(Clone(Get(cat))); } private static DailyData Clone(DailyData data) { DailyData dailyData = new DailyData { Name = data.Name, Cooldown = data.Cooldown, Rewards = data.Rewards.Select((RewardLine r) => r.Clone()).ToList() }; while (dailyData.Rewards.Count < 28) { dailyData.Rewards.Add(new RewardLine()); } return dailyData; } private static DailyData Default(string cat) { DailyData dailyData = new DailyData { Name = cat }; for (int i = 0; i < 28; i++) { dailyData.Rewards.Add(new RewardLine { Prefab = "Wood", Amount = 1, Quality = 1, Variant = 0 }); } return dailyData; } } private sealed class RewardPackFile { public List Packs = new List(); } private sealed class RewardPack { public string Name = "NewPack"; public string Description = ""; public string Icon = ""; public int TokenCost; public int Cost; public int Price; public bool Disabled; public List Rewards = new List(); } private static class RewardPackManager { private static RewardPackFile file = new RewardPackFile(); private static string lastLoadMessage = ""; public static string Path => FortecaPaths.RewardPacksPath; public static void Load() { lastLoadMessage = ""; try { if (!File.Exists(Path)) { lastLoadMessage = "RewardPacks.json missing: " + Path; LogsModule.Log("[ServerRewards Config] Missing RewardPacks path: " + Path); file = new RewardPackFile(); return; } file = JSON.ToObject(File.ReadAllText(Path)) ?? new RewardPackFile(); } catch (Exception ex) { lastLoadMessage = "RewardPacks.json parse failed: " + Path; LogsModule.Log("[ServerRewards Config] Parse error path=" + Path + " reason=" + ex.Message); file = new RewardPackFile(); } if (file.Packs == null) { file.Packs = new List(); } foreach (RewardPack pack in file.Packs) { if (pack.Rewards == null) { pack.Rewards = new List(); } } } public static void Save() { BackupFile(Path); File.WriteAllText(Path, JSON.ToNiceJSON(file)); HistoryManager.Add("Admin", "0", "Reward Packs", "RewardPacks", "", "Admin UI", "Saved", "Reward packs saved"); SetStatus("Reward packs saved"); } public static void Create() { string text = "Pack_" + DateTime.Now.ToString("HHmmss"); file.Packs.Add(new RewardPack { Name = text, Description = "Created in Admin UI", TokenCost = 0, Rewards = new List { new RewardLine { Prefab = "Wood", Amount = 10 } } }); SetStatus("Created " + text); } public static IEnumerable Describe() { if (!string.IsNullOrWhiteSpace(lastLoadMessage)) { yield return lastLoadMessage; } if (file.Packs.Count == 0) { yield return "No reward packs configured. Path: " + Path; } foreach (RewardPack p in file.Packs.OrderBy((RewardPack rewardPack) => rewardPack.Name)) { yield return p.Name + " | tokens=" + CostOf(p) + " | rewards=" + p.Rewards.Count + " | " + p.Description; foreach (RewardLine item in p.Rewards.Take(5)) { yield return " " + item.ToLine(); } } } public static List Views() { List list = new List(); if (!string.IsNullOrWhiteSpace(lastLoadMessage)) { list.Add(new PlayerRewardPackView { Name = "Reward Packs", Description = lastLoadMessage, Status = "Check JSON path", TokenCost = 0 }); return list; } foreach (RewardPack item in file.Packs.OrderBy((RewardPack p) => p.Name)) { PlayerRewardPackView playerRewardPackView = new PlayerRewardPackView { Name = (string.IsNullOrWhiteSpace(item.Name) ? "Unnamed Pack" : item.Name), Description = (item.Description ?? ""), TokenCost = CostOf(item), Status = (item.Disabled ? "Disabled" : "Available") }; foreach (RewardLine item2 in (item.Rewards ?? new List()).Take(8)) { playerRewardPackView.Rewards.Add(item2.ToLine()); } list.Add(playerRewardPackView); } return list; } private static int CostOf(RewardPack p) { if (p == null) { return 0; } if (p.TokenCost > 0) { return p.TokenCost; } if (p.Cost > 0) { return p.Cost; } if (p.Price > 0) { return p.Price; } return 0; } } private static class RedeemAdminManager { public static string Search = ""; private static RedeemSystem.RedeemCodesData data = new RedeemSystem.RedeemCodesData(); public static string Path => FortecaPaths.RedeemCodesPath; public static void Load() { Directory.CreateDirectory(System.IO.Path.GetDirectoryName(Path)); if (!File.Exists(Path)) { LogsModule.Log("[ServerRewards Config] Missing RedeemCodes path: " + Path); data = new RedeemSystem.RedeemCodesData(); return; } try { data = JSON.ToObject(File.ReadAllText(Path)) ?? new RedeemSystem.RedeemCodesData(); } catch (Exception ex) { LogsModule.Log("[ServerRewards Config] Parse error path=" + Path + " reason=" + ex.Message); data = new RedeemSystem.RedeemCodesData(); } if (data.Codes == null) { data.Codes = new List(); } } public static void Save() { BackupFile(Path); File.WriteAllText(Path, JSON.ToNiceJSON(data)); HistoryManager.Add("Admin", "0", "Redeem Codes", "RedeemCodes", "", "Admin UI", "Saved", "Redeem codes saved"); SetStatus("Redeem codes saved"); } public static void Create(bool random) { string code = (random ? RandomCode() : ("NEWCODE" + DateTime.Now.ToString("HHmmss"))); if (data.Codes.Any((RedeemSystem.RedeemCode c) => string.Equals(c.Code, code, StringComparison.OrdinalIgnoreCase))) { SetStatus("Duplicate code: " + code); return; } data.Codes.Add(new RedeemSystem.RedeemCode { Code = code, MaxUses = 1, OneTimePerSteamID = true, Rewards = new List { new RedeemSystem.RedeemReward { Prefab = "Wood", Amount = 10, Quality = 1 } } }); SetStatus("Created code " + code); } public static void DuplicateFirst() { RedeemSystem.RedeemCode redeemCode = Filtered().FirstOrDefault(); if (redeemCode == null) { SetStatus("No code selected"); return; } string code = redeemCode.Code + "_COPY" + DateTime.Now.ToString("HHmmss"); data.Codes.Add(new RedeemSystem.RedeemCode { Code = code, Disabled = redeemCode.Disabled, MaxUses = redeemCode.MaxUses, ExpirationUtc = redeemCode.ExpirationUtc, OneTimePerSteamID = redeemCode.OneTimePerSteamID, AllowedSteamIDs = new List(redeemCode.AllowedSteamIDs ?? new List()), Rewards = (redeemCode.Rewards ?? new List()).Select((RedeemSystem.RedeemReward r) => new RedeemSystem.RedeemReward { Prefab = r.Prefab, Amount = r.Amount, Quality = r.Quality, Variant = r.Variant }).ToList() }); SetStatus("Duplicated " + redeemCode.Code); } public static void DisableFirst() { RedeemSystem.RedeemCode redeemCode = Filtered().FirstOrDefault(); if (redeemCode == null) { SetStatus("No code selected"); return; } redeemCode.Disabled = true; SetStatus("Disabled " + redeemCode.Code); } public static void DeleteFirst() { RedeemSystem.RedeemCode redeemCode = Filtered().FirstOrDefault(); if (redeemCode == null) { SetStatus("No code selected"); return; } data.Codes.Remove(redeemCode); SetStatus("Deleted " + redeemCode.Code + "; press Save"); } public static RedeemSystem.RedeemCode FirstFiltered() { return (from c in Filtered() orderby c.Code select c).FirstOrDefault(); } public static void UpdateFirst(string newCode, string maxUses, string expirationUtc, string allowedSteamIds, bool disabled, bool oneTimePerSteam, string rewardPrefab, string rewardAmount) { RedeemSystem.RedeemCode redeemCode = FirstFiltered(); if (redeemCode == null) { SetStatus("No code selected"); return; } if (string.IsNullOrWhiteSpace(newCode)) { SetStatus("Code is required"); return; } if (!string.Equals(redeemCode.Code, newCode, StringComparison.OrdinalIgnoreCase) && data.Codes.Any((RedeemSystem.RedeemCode x) => string.Equals(x.Code, newCode, StringComparison.OrdinalIgnoreCase))) { SetStatus("Duplicate code rejected"); return; } if (!int.TryParse(maxUses, out var result) || result < 0) { SetStatus("Invalid max uses"); return; } if (!string.IsNullOrWhiteSpace(expirationUtc) && !DateTime.TryParse(expirationUtc, out var _)) { SetStatus("Invalid expiration date"); return; } if (!int.TryParse(rewardAmount, out var result3) || result3 < 0) { SetStatus("Invalid reward amount"); return; } if (string.IsNullOrWhiteSpace(rewardPrefab)) { SetStatus("Reward prefab required"); return; } redeemCode.Code = newCode.Trim(); redeemCode.MaxUses = result; redeemCode.ExpirationUtc = expirationUtc ?? ""; redeemCode.Disabled = disabled; redeemCode.OneTimePerSteamID = oneTimePerSteam; redeemCode.AllowedSteamIDs = (from x in (allowedSteamIds ?? "").Split(new char[1] { ';' }, StringSplitOptions.RemoveEmptyEntries) select x.Trim() into x where x.Length > 0 select x).ToList(); if (redeemCode.Rewards == null) { redeemCode.Rewards = new List(); } if (redeemCode.Rewards.Count == 0) { redeemCode.Rewards.Add(new RedeemSystem.RedeemReward()); } redeemCode.Rewards[0].Prefab = rewardPrefab.Trim(); redeemCode.Rewards[0].Amount = result3; if (redeemCode.Rewards[0].Quality <= 0) { redeemCode.Rewards[0].Quality = 1; } SetStatus("Updated redeem code " + redeemCode.Code + "; press Save"); } public static IEnumerable Describe() { IEnumerable rows = (from c in Filtered() orderby c.Code select c).ToList(); if (!rows.Any()) { yield return "No redeem codes match filter."; } foreach (RedeemSystem.RedeemCode item in rows) { yield return item.Code + " | disabled=" + item.Disabled + " | used=" + item.Used + "/" + ((item.MaxUses <= 0) ? "unlimited" : item.MaxUses.ToString()) + " | oneSteam=" + item.OneTimePerSteamID + " | rewards=" + (item.Rewards?.Count ?? 0) + " | expires=" + item.ExpirationUtc; } } private static IEnumerable Filtered() { if (data == null) { Load(); } if (data.Codes == null) { data.Codes = new List(); } string needle = Search ?? ""; return data.Codes.Where((RedeemSystem.RedeemCode c) => string.IsNullOrWhiteSpace(needle) || (c.Code ?? "").IndexOf(needle, StringComparison.OrdinalIgnoreCase) >= 0); } private static string RandomCode() { Random r = new Random(); return new string((from _ in Enumerable.Range(0, 10) select "ABCDEFGHJKLMNPQRSTUVWXYZ23456789"[r.Next("ABCDEFGHJKLMNPQRSTUVWXYZ23456789".Length)]).ToArray()); } } private static class GrantManager { public static string Validate(string prefab, string amount, string tokens) { if (string.IsNullOrWhiteSpace(prefab)) { return "Prefab required"; } if (!int.TryParse(amount, out var result) || result < 0) { return "Invalid amount"; } if (!int.TryParse(tokens, out var result2) || result2 < 0) { return "Invalid tokens"; } if ((Object)(object)ZNetScene.instance != (Object)null && (Object)(object)ZNetScene.instance.GetPrefab(prefab) == (Object)null && prefab != "Coins" && prefab != "Tokens") { return "Warning: prefab not found"; } return "Grant data valid"; } public static void Grant(string target, string pack, string prefab, string amount, string tokens, bool broadcast, bool notify) { string text = Validate(prefab, amount, tokens); HistoryManager.Add(target, target, "Grant Rewards", prefab, pack, "Admin UI", text.StartsWith("Invalid") ? "Rejected" : "Logged", "Amount=" + amount + ", Tokens=" + tokens + ", Broadcast=" + broadcast + ", Notify=" + notify + ", " + text); SetStatus("Grant logged: " + text); } public static void GrantToMyself(string pack, string prefab, string amountText, string tokensText, bool broadcast, bool notify) { //IL_00c3: 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_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) //IL_00e2: Unknown result type (might be due to invalid IL or missing references) //IL_00ec: Unknown result type (might be due to invalid IL or missing references) //IL_00f1: Unknown result type (might be due to invalid IL or missing references) //IL_00f6: Unknown result type (might be due to invalid IL or missing references) string text = Validate(prefab, amountText, tokensText); if (text.StartsWith("Invalid") || text == "Prefab required") { SetStatus(text); return; } if (!int.TryParse(amountText, out var result)) { result = 0; } if (!int.TryParse(tokensText, out var result2)) { result2 = 0; } Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null) { SetStatus("No local player available"); return; } if (result > 0 && prefab != "Coins" && prefab != "Tokens") { GameObject val = (((Object)(object)ZNetScene.instance != (Object)null) ? ZNetScene.instance.GetPrefab(prefab) : null); if ((Object)(object)val == (Object)null) { SetStatus("Prefab not found: " + prefab); return; } GameObject val2 = Object.Instantiate(val, ((Component)localPlayer).transform.position + ((Component)localPlayer).transform.forward * 1.5f + Vector3.up * 1.5f, Quaternion.identity); ItemDrop component = val2.GetComponent(); component.m_itemData.m_stack = result; ValheimCompat.SaveItemDrop(component); if (ValheimCompat.GetInventory((Humanoid)(object)localPlayer).CanAddItem(val2, -1)) { ValheimCompat.GetInventory((Humanoid)(object)localPlayer).AddItem(component.m_itemData); ZNetScene.instance.Destroy(val2); } } if (result2 > 0 && ZRoutedRpc.instance != null) { ZRoutedRpc.instance.InvokeRoutedRPC(ValheimCompat.GetServerPeerID(), "Forteca_Shop RequestTokens_Int", new object[2] { result2, "Admin Grant To Myself" }); } HistoryManager.Add(localPlayer.GetPlayerName(), "local", "Grant To Myself", prefab, pack, "Admin UI", "Granted", "Amount=" + result + ", Tokens=" + result2 + ", Broadcast=" + broadcast + ", Notify=" + notify); SetStatus("Granted to myself: " + prefab + " x" + result + ((result2 > 0) ? (", tokens " + result2) : "")); } } private sealed class AccessRow { public string SteamID = ""; public bool Admin; public bool Premium; public bool Epic; public bool Legendary; public bool BuiltIn; } private static class AccessManager { private static readonly string[] Types = new string[4] { "Admin", "Premium", "Epic", "Legendary" }; private static readonly Dictionary> Data = new Dictionary>(StringComparer.OrdinalIgnoreCase); private static readonly string[] BuiltIns = new string[2] { "76561198007625196", "76561199693548808" }; public static void Load() { string[] types = Types; foreach (string text in types) { Data[text] = ReadExternal(PathFor(text)); } } public static IEnumerable Rows() { HashSet hashSet = new HashSet(StringComparer.OrdinalIgnoreCase); string[] builtIns = BuiltIns; foreach (string item in builtIns) { hashSet.Add(item); } foreach (HashSet value in Data.Values) { foreach (string item2 in value) { hashSet.Add(item2); } } return (from id in hashSet select new AccessRow { SteamID = id, BuiltIn = SteamIdAccess.IsBuiltIn(id), Admin = (SteamIdAccess.IsBuiltIn(id) || Data["Admin"].Contains(id)), Premium = (SteamIdAccess.IsBuiltIn(id) || Data["Premium"].Contains(id)), Epic = (SteamIdAccess.IsBuiltIn(id) || Data["Epic"].Contains(id)), Legendary = (SteamIdAccess.IsBuiltIn(id) || Data["Legendary"].Contains(id)) } into r orderby r.BuiltIn descending, r.SteamID select r).ToList(); } public static void Add(string steamId, string type) { steamId = (steamId ?? "").Trim(); type = NormalizeType(type); if (string.IsNullOrEmpty(steamId)) { SetStatus("Enter a SteamID64."); return; } if (!SteamIdAccess.IsValidSteamId64(steamId)) { SetStatus("SteamID64 must contain exactly 17 digits."); return; } if (SteamIdAccess.IsBuiltIn(steamId)) { SetStatus("Built-in Owner already has all access."); return; } Load(); if (Data[type].Contains(steamId)) { SetStatus("This SteamID already has this access."); return; } pendingSelfAdminRemoval = ""; Data[type].Add(steamId); if (!SaveType(type)) { SetStatus("Unable to update the access file."); return; } LogsModule.Log("Access added: " + steamId + " type=" + type + " file=" + PathFor(type)); SetStatus("Access added successfully."); Forteca_ServerRewards.RefreshAccessAfterAdminEdit(); } public static void Update(string steamId, bool admin, bool premium, bool epic, bool legendary) { steamId = (steamId ?? "").Trim(); if (!SteamIdAccess.IsValidSteamId64(steamId)) { SetStatus("SteamID64 must contain exactly 17 digits."); return; } if (SteamIdAccess.IsBuiltIn(steamId)) { SetStatus("Built-in Owner access cannot be removed."); return; } Load(); if (WouldRemoveCurrentExternalAdmin(steamId, admin, "update")) { return; } pendingSelfAdminRemoval = ""; SetFlag("Admin", steamId, admin); SetFlag("Premium", steamId, premium); SetFlag("Epic", steamId, epic); SetFlag("Legendary", steamId, legendary); string[] types = Types; foreach (string text in types) { if (!SaveType(text)) { SetStatus("Unable to update the access file."); return; } LogsModule.Log("Access updated: " + steamId + " type=" + text + " file=" + PathFor(text)); } editSteamId = ""; SetStatus("Access updated successfully."); Forteca_ServerRewards.RefreshAccessAfterAdminEdit(); } public static void RemoveAll(string steamId) { steamId = (steamId ?? "").Trim(); if (SteamIdAccess.IsBuiltIn(steamId)) { SetStatus("Built-in Owner access cannot be removed."); return; } Load(); if (WouldRemoveCurrentExternalAdmin(steamId, adminAfter: false, "remove-all")) { return; } pendingSelfAdminRemoval = ""; string[] types = Types; foreach (string text in types) { Data[text].Remove(steamId); if (!SaveType(text)) { SetStatus("Unable to update the access file."); return; } LogsModule.Log("Access removed: " + steamId + " type=" + text + " file=" + PathFor(text)); } SetStatus("Access removed successfully."); Forteca_ServerRewards.RefreshAccessAfterAdminEdit(); } private static void SetFlag(string type, string steamId, bool enabled) { if (enabled) { Data[type].Add(steamId); } else { Data[type].Remove(steamId); } } private static bool WouldRemoveCurrentExternalAdmin(string steamId, bool adminAfter, string action) { string text = (Forteca_ServerRewards.CurrentUserID ?? "").Trim(); if (adminAfter || string.IsNullOrEmpty(text) || text == "ERROR") { return false; } if (!string.Equals(text, steamId, StringComparison.OrdinalIgnoreCase)) { return false; } if (SteamIdAccess.IsBuiltIn(text)) { return false; } if (!Data["Admin"].Contains(steamId)) { return false; } string text2 = action + ":" + steamId; if (pendingSelfAdminRemoval == text2) { return false; } pendingSelfAdminRemoval = text2; SetStatus("You are removing your own Admin access. Click again to confirm."); return true; } private static string NormalizeType(string type) { string[] types = Types; foreach (string text in types) { if (string.Equals(text, type, StringComparison.OrdinalIgnoreCase)) { return text; } } return "Admin"; } private static string PathFor(string type) { return type switch { "Premium" => FortecaPaths.PremiumUsersPath, "Epic" => FortecaPaths.EpicUsersPath, "Legendary" => FortecaPaths.LegendaryUsersPath, _ => FortecaPaths.AdminUsersPath, }; } private static HashSet ReadExternal(string path) { HashSet hashSet = new HashSet(StringComparer.OrdinalIgnoreCase); try { FortecaPaths.EnsureTextFile(path, "# One SteamID64 per line." + Environment.NewLine); string[] array = File.ReadAllLines(path); for (int i = 0; i < array.Length; i++) { string text = (array[i] ?? "").Trim(); if (text.Length != 0 && !text.StartsWith("#") && SteamIdAccess.IsValidSteamId64(text) && !SteamIdAccess.IsBuiltIn(text)) { hashSet.Add(text); } } } catch (Exception ex) { LogsModule.Log("Failed to read access file " + path + ": " + ex.Message); } return hashSet; } private static bool SaveType(string type) { string text = PathFor(type); try { Directory.CreateDirectory(Path.GetDirectoryName(text)); object source = (File.Exists(text) ? ((object)File.ReadAllLines(text)) : ((object)new string[0])); List list = ((IEnumerable)source).Where((string line) => (line ?? "").TrimStart(Array.Empty()).StartsWith("#")).ToList(); if (list.Count == 0) { list.Add("# One SteamID64 per line."); } HashSet hashSet = new HashSet(((IEnumerable)source).Select((string line) => (line ?? "").Trim()).Where(SteamIdAccess.IsBuiltIn), StringComparer.OrdinalIgnoreCase); List list2 = (from id in (from id in Data[type].Where(SteamIdAccess.IsValidSteamId64) where !SteamIdAccess.IsBuiltIn(id) select id).Distinct(StringComparer.OrdinalIgnoreCase) orderby id select id).ToList(); list2.InsertRange(0, from id in BuiltIns.Where(hashSet.Contains) orderby id select id); List list3 = new List(); list3.AddRange(list); if (list3.Count > 0 && list3[list3.Count - 1].Length != 0) { list3.Add(""); } list3.AddRange(list2); string text2 = text + ".tmp"; File.WriteAllLines(text2, list3, new UTF8Encoding(encoderShouldEmitUTF8Identifier: false)); if (File.Exists(text)) { File.Replace(text2, text, null); } else { File.Move(text2, text); } return true; } catch (Exception ex) { LogsModule.Log("Unable to update access file " + text + ": " + ex.Message); return false; } } } private sealed class WebhookSettings { public string WebhookUrl = ""; public bool EnableWebhook; public bool StorePurchases = true; public bool DailyClaims = true; public bool PremiumClaims = true; public bool EpicClaims = true; public bool LegendaryClaims = true; public bool RedeemSuccess = true; public bool RedeemFailed = true; public bool RewardGrants = true; public bool AdminActions = true; public bool Errors = true; public bool ServerStarted = true; public bool ServerStopped = true; public bool FutureEventRewards; public string LastSendStatus = "Never sent"; public string LastHttpError = ""; public string LastSendUtc = ""; } private static class WebhookManager { private static readonly object Sync = new object(); public static WebhookSettings Data = new WebhookSettings(); public static string Path => FortecaPaths.WebhookSettingsPath; public static void Load() { lock (Sync) { try { FortecaPaths.EnsureFreshStructure(); if (!File.Exists(Path)) { MigrateLegacyJsonIfPossible(); SaveNoStatus(); return; } WebhookSettings webhookSettings = new WebhookSettings(); string[] array = File.ReadAllLines(Path); for (int i = 0; i < array.Length; i++) { string text = (array[i] ?? "").Trim(); if (text.Length != 0 && !text.StartsWith("#")) { int num = text.IndexOf('='); if (num > 0) { Apply(webhookSettings, text.Substring(0, num).Trim(), text.Substring(num + 1).Trim()); } } } Data = webhookSettings; } catch (Exception ex) { LogsModule.Log("Failed to parse webhook settings: " + ex.Message); Data = new WebhookSettings(); } } } public static void Save() { lock (Sync) { BackupFile(Path); SaveNoStatus(); SetStatus("Webhook saved"); } } private static void SaveNoStatus() { string directoryName = System.IO.Path.GetDirectoryName(Path); if (!string.IsNullOrWhiteSpace(directoryName)) { Directory.CreateDirectory(directoryName); } File.WriteAllLines(Path, Lines(Data), Encoding.UTF8); } public static void Update(string url, bool enabled, bool store, bool daily, bool premium, bool epic, bool legendary, bool redeemOk, bool redeemFail, bool grants, bool admin, bool errors, bool started, bool stopped, bool future) { Load(); string text = (url ?? "").Trim(); if (!string.IsNullOrWhiteSpace(text) && text.IndexOf("***", StringComparison.OrdinalIgnoreCase) < 0) { Data.WebhookUrl = text; } Data.EnableWebhook = enabled; Data.StorePurchases = store; Data.DailyClaims = daily; Data.PremiumClaims = premium; Data.EpicClaims = epic; Data.LegendaryClaims = legendary; Data.RedeemSuccess = redeemOk; Data.RedeemFailed = redeemFail; Data.RewardGrants = grants; Data.AdminActions = admin; Data.Errors = errors; Data.ServerStarted = started; Data.ServerStopped = stopped; Data.FutureEventRewards = future; Save(); } public static void Clear() { Load(); Data.WebhookUrl = ""; Data.LastSendStatus = "URL cleared"; Data.LastHttpError = ""; Save(); } public static void Test() { Load(); bool flag = SendNow("Test Webhook", "Forteca_ServerRewards test webhook from Admin Suite."); HistoryManager.Add("Admin", "0", "Webhook", "Test", "", "Admin UI", flag ? "Sent" : "Failed", Data.LastSendStatus + " " + Data.LastHttpError); Save(); SetStatus(flag ? "Webhook test sent" : ("Webhook test failed: " + Data.LastHttpError)); } public static void SendEvent(string eventName, string message) { try { Load(); if (!ShouldSend(eventName)) { return; } ThreadPool.QueueUserWorkItem(delegate { try { SendNow(eventName, message); lock (Sync) { SaveNoStatus(); } } catch (Exception ex2) { try { LogsModule.Log("Webhook event failed without blocking reward: " + ex2.Message); } catch { } } }); } catch (Exception ex) { LogsModule.Log("Webhook event skipped without blocking reward: " + ex.Message); } } public static string MaskedUrl() { string text = ((Data != null) ? (Data.WebhookUrl ?? "") : ""); if (string.IsNullOrWhiteSpace(text)) { return "not configured"; } if (text.Length <= 16) { return "***"; } return text.Substring(0, Math.Min(28, text.Length)) + "...***"; } private static bool ShouldSend(string eventName) { if (Data == null || !Data.EnableWebhook || string.IsNullOrWhiteSpace(Data.WebhookUrl)) { return false; } string text = (eventName ?? "").ToLowerInvariant(); if (text.Contains("kit") || text.Contains("store")) { return Data.StorePurchases; } if (text.Contains("daily claim")) { return Data.DailyClaims; } if (text.Contains("premium")) { return Data.PremiumClaims; } if (text.Contains("epic")) { return Data.EpicClaims; } if (text.Contains("legendary")) { return Data.LegendaryClaims; } if (text.Contains("redeem success")) { return Data.RedeemSuccess; } if (text.Contains("redeem fail") || text.Contains("redeem failure")) { return Data.RedeemFailed; } if (text.Contains("redeem")) { return Data.RedeemSuccess; } if (text.Contains("grant")) { return Data.RewardGrants; } if (text.Contains("admin")) { return Data.AdminActions; } if (text.Contains("error")) { return Data.Errors; } if (text.Contains("started")) { return Data.ServerStarted; } if (text.Contains("stopped")) { return Data.ServerStopped; } if (text.Contains("future")) { return Data.FutureEventRewards; } return true; } private static bool SendNow(string eventName, string message) { try { if (Data == null) { Data = new WebhookSettings(); } if (!Data.EnableWebhook) { Data.LastSendStatus = "Skipped: disabled"; Data.LastHttpError = ""; return false; } if (string.IsNullOrWhiteSpace(Data.WebhookUrl)) { Data.LastSendStatus = "Skipped: missing URL"; Data.LastHttpError = "Webhook URL is empty"; return false; } string s = "{\"content\":\"" + JsonEscape("**Forteca ServerRewards**\n" + eventName + "\n" + message) + "\"}"; byte[] bytes = Encoding.UTF8.GetBytes(s); HttpWebRequest httpWebRequest = (HttpWebRequest)WebRequest.Create(Data.WebhookUrl); httpWebRequest.Method = "POST"; httpWebRequest.ContentType = "application/json"; httpWebRequest.Timeout = 8000; httpWebRequest.ReadWriteTimeout = 8000; httpWebRequest.ContentLength = bytes.Length; using (Stream stream = httpWebRequest.GetRequestStream()) { stream.Write(bytes, 0, bytes.Length); } using HttpWebResponse httpWebResponse = (HttpWebResponse)httpWebRequest.GetResponse(); int statusCode = (int)httpWebResponse.StatusCode; Data.LastSendUtc = DateTime.UtcNow.ToString("o"); Data.LastSendStatus = "HTTP " + statusCode + " " + httpWebResponse.StatusDescription; Data.LastHttpError = ((statusCode >= 200 && statusCode < 300) ? "" : Data.LastSendStatus); return statusCode >= 200 && statusCode < 300; } catch (WebException ex) { Data.LastSendUtc = DateTime.UtcNow.ToString("o"); Data.LastSendStatus = "Failed"; Data.LastHttpError = ReadWebException(ex); LogsModule.Log("Webhook send failed: " + Data.LastHttpError); return false; } catch (Exception ex2) { Data.LastSendUtc = DateTime.UtcNow.ToString("o"); Data.LastSendStatus = "Failed"; Data.LastHttpError = ex2.Message; LogsModule.Log("Webhook send failed: " + ex2.Message); return false; } } private static string ReadWebException(WebException ex) { try { if (ex.Response is HttpWebResponse httpWebResponse) { using (httpWebResponse) { using StreamReader streamReader = new StreamReader(httpWebResponse.GetResponseStream() ?? Stream.Null); string text = streamReader.ReadToEnd(); return "HTTP " + (int)httpWebResponse.StatusCode + " " + httpWebResponse.StatusDescription + (string.IsNullOrWhiteSpace(text) ? "" : (": " + text)); } } } catch { } return ex.Message; } private static string JsonEscape(string value) { return (value ?? "").Replace("\\", "\\\\").Replace("\"", "\\\"").Replace("\r", "") .Replace("\n", "\\n"); } private static void Apply(WebhookSettings s, string key, string value) { bool flag = Bool(value); string text = (key ?? "").Trim().ToLowerInvariant(); if (text == null) { return; } switch (text.Length) { case 10: switch (text[0]) { case 'w': if (text == "webhookurl") { s.WebhookUrl = value ?? ""; } break; case 'e': if (text == "epicclaims") { s.EpicClaims = flag; } break; } break; case 13: switch (text[8]) { case 'b': if (text == "enablewebhook") { s.EnableWebhook = flag; } break; case 'l': if (text == "premiumclaims") { s.PremiumClaims = flag; } break; case 'c': if (text == "redeemsuccess") { s.RedeemSuccess = flag; } break; case 'a': if (text == "serverstarted") { s.ServerStarted = flag; } break; case 'o': if (text == "serverstopped") { s.ServerStopped = flag; } break; case 'e': if (text == "lasthttperror") { s.LastHttpError = value ?? ""; } break; } break; case 14: switch (text[0]) { case 's': if (text == "storepurchases") { s.StorePurchases = flag; } break; case 'l': if (text == "lastsendstatus") { s.LastSendStatus = value ?? ""; } break; } break; case 11: switch (text[0]) { case 'd': if (text == "dailyclaims") { s.DailyClaims = flag; } break; case 'l': if (text == "lastsendutc") { s.LastSendUtc = value ?? ""; } break; } break; case 12: switch (text[2]) { case 'd': if (text == "redeemfailed") { s.RedeemFailed = flag; } break; case 'w': if (text == "rewardgrants") { s.RewardGrants = flag; } break; case 'm': if (text == "adminactions") { s.AdminActions = flag; } break; } break; case 15: if (text == "legendaryclaims") { s.LegendaryClaims = flag; } break; case 6: if (text == "errors") { s.Errors = flag; } break; case 18: if (text == "futureeventrewards") { s.FutureEventRewards = flag; } break; case 7: case 8: case 9: case 16: case 17: break; } } private static bool Bool(string value) { if (!string.Equals(value, "true", StringComparison.OrdinalIgnoreCase) && !(value == "1")) { return string.Equals(value, "yes", StringComparison.OrdinalIgnoreCase); } return true; } private static IEnumerable Lines(WebhookSettings s) { yield return "# Forteca_ServerRewards Discord webhook settings"; yield return "# URL is stored here for server-side delivery. The Admin UI masks the saved URL."; yield return "EnableWebhook=" + s.EnableWebhook; yield return "WebhookUrl=" + s.WebhookUrl; yield return "StorePurchases=" + s.StorePurchases; yield return "DailyClaims=" + s.DailyClaims; yield return "PremiumClaims=" + s.PremiumClaims; yield return "EpicClaims=" + s.EpicClaims; yield return "LegendaryClaims=" + s.LegendaryClaims; yield return "RedeemSuccess=" + s.RedeemSuccess; yield return "RedeemFailed=" + s.RedeemFailed; yield return "RewardGrants=" + s.RewardGrants; yield return "AdminActions=" + s.AdminActions; yield return "Errors=" + s.Errors; yield return "ServerStarted=" + s.ServerStarted; yield return "ServerStopped=" + s.ServerStopped; yield return "FutureEventRewards=" + s.FutureEventRewards; yield return "LastSendStatus=" + s.LastSendStatus; yield return "LastHttpError=" + (s.LastHttpError ?? "").Replace(Environment.NewLine, " "); yield return "LastSendUtc=" + s.LastSendUtc; } private static void MigrateLegacyJsonIfPossible() { try { if (File.Exists(FortecaPaths.WebhookPath)) { WebhookSettings webhookSettings = JSON.ToObject(File.ReadAllText(FortecaPaths.WebhookPath)); if (webhookSettings != null) { Data = webhookSettings; } } } catch { } } } private sealed class HistoryFile { public List Entries = new List(); } private sealed class HistoryEntry { public string Player = ""; public string SteamID = ""; public string RewardType = ""; public string RewardName = ""; public string RewardPack = ""; public string RedeemCode = ""; public string GrantedBy = ""; public string DateUtc = ""; public string Status = ""; public string Result = ""; } private static class HistoryManager { public static string Search = ""; public static string Filter = "All"; private static HistoryFile file = new HistoryFile(); public static string Path => FortecaPaths.ClaimHistoryPath; public static void Load() { try { if (!File.Exists(Path)) { file = new HistoryFile(); Save(); return; } file = JSON.ToObject(File.ReadAllText(Path)) ?? new HistoryFile(); } catch (Exception ex) { LogsModule.Log("Failed to parse claim history: " + ex.Message); file = new HistoryFile(); } if (file.Entries == null) { file.Entries = new List(); } } public static void Save() { BackupFile(Path); File.WriteAllText(Path, JSON.ToNiceJSON(file)); } public static void Add(string player, string steam, string type, string name, string pack, string by, string state, string result) { Load(); file.Entries.Add(new HistoryEntry { Player = (player ?? ""), SteamID = (steam ?? ""), RewardType = (type ?? ""), RewardName = (name ?? ""), RewardPack = (pack ?? ""), GrantedBy = (by ?? ""), DateUtc = DateTime.UtcNow.ToString("o"), Status = (state ?? ""), Result = (result ?? "") }); Save(); } public static IEnumerable Describe() { IEnumerable rows = (from e in Filtered() orderby e.DateUtc descending select e).Take(120).ToList(); if (!rows.Any()) { yield return "No history entries match filter."; } foreach (HistoryEntry item in rows) { yield return item.DateUtc + " | " + item.Status + " | " + item.Player + " | " + item.SteamID + " | " + item.RewardType + " | " + item.RewardName + " | " + item.Result; } } private static IEnumerable Filtered() { DateTime now = DateTime.UtcNow; return from e in file.Entries where DateOk(e, now) where string.IsNullOrWhiteSpace(Search) || (e.Player + " " + e.SteamID + " " + e.RedeemCode + " " + e.RewardPack + " " + e.RewardName).IndexOf(Search, StringComparison.OrdinalIgnoreCase) >= 0 select e; } private static bool DateOk(HistoryEntry e, DateTime now) { if (!DateTime.TryParse(e.DateUtc, out var result)) { return true; } if (Filter == "Today") { return result.Date == now.Date; } if (Filter == "Week") { return (now - result).TotalDays <= 7.0; } if (Filter == "Month") { return (now - result).TotalDays <= 31.0; } return true; } } private sealed class AdminSettings { public int TokensPerHour = 10; public bool RewardPopup = true; public float PopupDuration = 4f; public bool Animations = true; public bool RedeemEnabled = true; public bool WebhookEnabled; public bool AutoReload = true; public bool DebugLogging; public bool ConfigAutoBackup = true; } private static class SettingsManager { public static AdminSettings Data = new AdminSettings(); public static string Path => FortecaPaths.SettingsPath; public static void Load() { try { if (!File.Exists(Path)) { Save(); } else { Data = JSON.ToObject(File.ReadAllText(Path)) ?? new AdminSettings(); } } catch (Exception ex) { LogsModule.Log("Failed to parse internal settings: " + ex.Message); Data = new AdminSettings(); } } public static void Save() { BackupFile(Path); File.WriteAllText(Path, JSON.ToNiceJSON(Data)); SetStatus("Settings saved"); } public static void Update(string tokens, bool popup, string duration, bool animations, bool redeem, bool webhook, bool reload, bool debug, bool backup) { if (int.TryParse(tokens, out var result) && result >= 0) { Data.TokensPerHour = result; } if (float.TryParse(duration, out var result2) && result2 >= 0f) { Data.PopupDuration = result2; } Data.RewardPopup = popup; Data.Animations = animations; Data.RedeemEnabled = redeem; Data.WebhookEnabled = webhook; Data.AutoReload = reload; Data.DebugLogging = debug; Data.ConfigAutoBackup = backup; Save(); } } [Serializable] [CompilerGenerated] private sealed class <>c { public static readonly <>c <>9 = new <>c(); public static UnityAction <>9__24_2; public static UnityAction <>9__24_3; public static UnityAction <>9__24_4; public static UnityAction <>9__24_5; public static UnityAction <>9__24_6; public static UnityAction <>9__24_7; public static UnityAction <>9__24_8; public static UnityAction <>9__24_9; public static UnityAction <>9__24_10; public static UnityAction <>9__24_11; public static UnityAction <>9__24_12; public static UnityAction <>9__24_13; public static UnityAction <>9__24_14; public static UnityAction <>9__25_0; public static UnityAction <>9__25_1; public static UnityAction <>9__25_2; public static UnityAction <>9__25_3; public static UnityAction <>9__26_1; public static UnityAction <>9__26_2; public static UnityAction <>9__26_3; public static UnityAction <>9__26_4; public static UnityAction <>9__26_5; public static UnityAction <>9__26_6; public static UnityAction <>9__26_7; public static UnityAction <>9__26_8; public static UnityAction <>9__27_1; public static Func <>9__27_3; public static UnityAction <>9__27_5; public static UnityAction <>9__30_1; public static UnityAction <>9__30_2; public static UnityAction <>9__30_3; public static UnityAction <>9__31_1; public static UnityAction <>9__32_1; public static UnityAction <>9__32_2; public static UnityAction <>9__32_3; public static Func <>9__55_1; internal void b__24_2() { DailyManager.AddReward(category, day); Render(root, header); } internal void b__24_3() { DailyManager.RemoveReward(category, day); Render(root, header); } internal void b__24_4() { DailyManager.CopyDay(category, day); Render(root, header); } internal void b__24_5() { DailyManager.PasteDay(category, day); Render(root, header); } internal void b__24_6() { DailyManager.CopyWeek(category, day); Render(root, header); } internal void b__24_7() { DailyManager.PasteWeek(category, day); Render(root, header); } internal void b__24_8() { DailyManager.ResetDay(category, day); Render(root, header); } internal void b__24_9() { DailyManager.ResetCategory(category); Render(root, header); } internal void b__24_10() { DailyManager.Undo(category); Render(root, header); } internal void b__24_11() { DailyManager.Redo(category); Render(root, header); } internal void b__24_12() { DailyManager.Save(category); Render(root, header); } internal void b__24_13() { DailyManager.Load(category); SetStatus("Reloaded " + category); Render(root, header); } internal void b__24_14() { ExportFile(DailyManager.PathFor(category), category + "Rewards"); Render(root, header); } internal void b__25_0() { RewardPackManager.Create(); Render(root, header); } internal void b__25_1() { RewardPackManager.Save(); Render(root, header); } internal void b__25_2() { RewardPackManager.Load(); SetStatus("Reward packs reloaded"); Render(root, header); } internal void b__25_3() { ExportFile(RewardPackManager.Path, "RewardPacks"); Render(root, header); } internal void b__26_1() { RedeemAdminManager.Create(random: false); Render(root, header); } internal void b__26_2() { RedeemAdminManager.Create(random: true); Render(root, header); } internal void b__26_3() { RedeemAdminManager.DuplicateFirst(); Render(root, header); } internal void b__26_4() { RedeemAdminManager.DisableFirst(); Render(root, header); } internal void b__26_5() { RedeemAdminManager.DeleteFirst(); Render(root, header); } internal void b__26_6() { RedeemAdminManager.Save(); Render(root, header); } internal void b__26_7() { RedeemAdminManager.Load(); SetStatus("Redeem codes reloaded"); Render(root, header); } internal void b__26_8() { ExportFile(RedeemAdminManager.Path, "RedeemCodes"); Render(root, header); } internal void b__27_1() { AccessManager.Load(); SetStatus("Access lists reloaded"); Render(root, header); } internal bool b__27_3(AccessRow r) { return r.SteamID == editSteamId; } internal void b__27_5() { editSteamId = ""; Render(root, header); } internal void b__30_1() { WebhookManager.Clear(); Render(root, header); } internal void b__30_2() { WebhookManager.Test(); Render(root, header); } internal void b__30_3() { ExportFile(WebhookManager.Path, "Webhook"); Render(root, header); } internal void b__31_1() { ExportFile(HistoryManager.Path, "History"); Render(root, header); } internal void b__32_1() { Forteca_ServerRewards.ReloadExternalAssetsFromAdmin(); SetStatus("Custom Themes & Assets reloaded from " + ExternalAssetSystem.RootPath); Render(root, header); } internal void b__32_2() { ExportAll(); Render(root, header); } internal void b__32_3() { SetStatus("Import prepared: place reviewed JSON/CFG files in " + exportPath + " and reload the relevant page."); Render(root, header); } internal string b__55_1(string n) { return n; } } private static readonly string[] Pages = new string[8] { "Daily Rewards", "Reward Packs", "Redeem Codes", "Grant Rewards", "Access Management", "Webhook", "History", "Settings" }; private static readonly string[] Categories = new string[4] { "Daily", "Premium", "Epic", "Legendary" }; private static string rootPath; private static string backupPath; private static string exportPath; private static string page = "Daily Rewards"; private static string category = "Daily"; private static int day = 1; private static string status = "Ready"; private static string globalSearch = ""; private static string prefabSearch = ""; private static string accessSteamId = ""; private static string accessType = "Admin"; private static string editSteamId = ""; private static string pendingSelfAdminRemoval = ""; private static GameObject root; private static Text header; private static Font font; internal static void Init() { FortecaPaths.EnsureFreshStructure(); rootPath = FortecaPaths.Root; backupPath = FortecaPaths.BackupsPath; exportPath = FortecaPaths.ExportsPath; Directory.CreateDirectory(rootPath); Directory.CreateDirectory(backupPath); Directory.CreateDirectory(exportPath); font = Resources.GetBuiltinResource("Arial.ttf"); DailyManager.LoadAll(); RewardPackManager.Load(); RedeemAdminManager.Load(); WebhookManager.Load(); HistoryManager.Load(); SettingsManager.Load(); } internal static void Render(GameObject container, Text headerText) { //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_02e3: Unknown result type (might be due to invalid IL or missing references) //IL_02fd: Unknown result type (might be due to invalid IL or missing references) //IL_0312: Unknown result type (might be due to invalid IL or missing references) //IL_0327: Unknown result type (might be due to invalid IL or missing references) //IL_033b: Unknown result type (might be due to invalid IL or missing references) //IL_0135: Unknown result type (might be due to invalid IL or missing references) //IL_015d: Unknown result type (might be due to invalid IL or missing references) //IL_0172: Unknown result type (might be due to invalid IL or missing references) //IL_0187: Unknown result type (might be due to invalid IL or missing references) //IL_019b: Unknown result type (might be due to invalid IL or missing references) //IL_00f1: Unknown result type (might be due to invalid IL or missing references) //IL_00ea: Unknown result type (might be due to invalid IL or missing references) //IL_00fe: Unknown result type (might be due to invalid IL or missing references) //IL_0108: Expected O, but got Unknown Init(); root = container; header = headerText; Clear(root.transform); root.SetActive(true); header.text = "Admin - " + page; GameObject val = Panel(root.transform, "AdminSuite", new Color(0.03f, 0.025f, 0.02f, 0.86f)); ((Graphic)val.GetComponent()).raycastTarget = false; Stretch(val.GetComponent()); GameObject val2 = NavGrid(val.transform, "Nav", 78f); string[] pages = Pages; foreach (string text in pages) { string capture = text; MakeButton(val2.transform, text, (text == page) ? Green() : Brown(), (UnityAction)delegate { page = capture; Render(root, header); }); } GameObject val3 = Panel(val.transform, "Body", new Color(0f, 0f, 0f, 0.15f)); ((Graphic)val3.GetComponent()).raycastTarget = false; RectTransform component = val3.GetComponent(); component.anchorMin = new Vector2(0f, 0f); component.anchorMax = new Vector2(1f, 1f); component.offsetMin = new Vector2(8f, 34f); component.offsetMax = new Vector2(-8f, -92f); val3.AddComponent(); try { if (page == "Daily Rewards") { RenderDaily(val3.transform); } else if (page == "Reward Packs") { RenderRewardPacks(val3.transform); } else if (page == "Redeem Codes") { RenderRedeem(val3.transform); } else if (page == "Grant Rewards") { RenderGrant(val3.transform); } else if (page == "Access Management") { RenderAccessManagement(val3.transform); } else if (page == "Webhook") { RenderWebhook(val3.transform); } else if (page == "History") { RenderHistory(val3.transform); } else { RenderSettings(val3.transform); } } catch (Exception ex) { LogsModule.Log("Admin section render failed: " + page + " - " + ex.Message); ShowAdminSectionError(val3.transform, page, ex); } val2.transform.SetAsLastSibling(); RectTransform component2 = ((Component)MakeLabel(val.transform, status, 13, (TextAnchor)3, Color.yellow)).GetComponent(); component2.anchorMin = new Vector2(0f, 0f); component2.anchorMax = new Vector2(1f, 0f); component2.offsetMin = new Vector2(12f, 6f); component2.offsetMax = new Vector2(-12f, 30f); } private static void ShowAdminSectionError(Transform parent, string failedPage, Exception ex) { //IL_001a: 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_004a: 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_007c: Unknown result type (might be due to invalid IL or missing references) GameObject obj = Panel(parent, "AdminSectionError", new Color(0.08f, 0.025f, 0.015f, 0.88f)); RectTransform component = obj.GetComponent(); component.anchorMin = new Vector2(0.12f, 0.35f); component.anchorMax = new Vector2(0.88f, 0.62f); component.offsetMin = Vector2.zero; component.offsetMax = Vector2.zero; Stretch(((Component)MakeLabel(obj.transform, failedPage + " could not be rendered.\nCheck the log and configuration, then reload.", 16, (TextAnchor)4, Color.yellow)).GetComponent()); } internal static List GetRewardPackViews() { RewardPackManager.Load(); return RewardPackManager.Views(); } private static void RenderGlobalSearch(Transform parent) { //IL_0033: 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) GameObject val = Form(parent, 0f, 0f, 1f, 1f); MakeLabel(val.transform, "Global Search: " + globalSearch, 16, (TextAnchor)3, Color.white); foreach (string item in BuildGlobalSearchResults(globalSearch).Take(120)) { MakeLabel(val.transform, item, 12, (TextAnchor)3, Color.white); } } private static void RenderDaily(Transform parent) { //IL_002b: 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_0049: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_0095: Unknown result type (might be due to invalid IL or missing references) //IL_009f: Expected O, but got Unknown //IL_011f: Unknown result type (might be due to invalid IL or missing references) //IL_012e: 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_014c: Unknown result type (might be due to invalid IL or missing references) //IL_015b: Unknown result type (might be due to invalid IL or missing references) //IL_0177: Unknown result type (might be due to invalid IL or missing references) //IL_018c: Unknown result type (might be due to invalid IL or missing references) //IL_01a8: Unknown result type (might be due to invalid IL or missing references) //IL_01b2: Expected O, but got Unknown //IL_00df: 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_00ec: Unknown result type (might be due to invalid IL or missing references) //IL_00f6: Expected O, but got Unknown //IL_024f: Unknown result type (might be due to invalid IL or missing references) //IL_025e: Unknown result type (might be due to invalid IL or missing references) //IL_026d: Unknown result type (might be due to invalid IL or missing references) //IL_027c: Unknown result type (might be due to invalid IL or missing references) //IL_028b: 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 //IL_02e2: Unknown result type (might be due to invalid IL or missing references) //IL_0359: Unknown result type (might be due to invalid IL or missing references) //IL_041f: Unknown result type (might be due to invalid IL or missing references) //IL_0452: Unknown result type (might be due to invalid IL or missing references) //IL_045e: Unknown result type (might be due to invalid IL or missing references) //IL_0468: Expected O, but got Unknown //IL_0204: Unknown result type (might be due to invalid IL or missing references) //IL_01e9: 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_021b: Expected O, but got Unknown //IL_04b8: Unknown result type (might be due to invalid IL or missing references) //IL_04c5: Unknown result type (might be due to invalid IL or missing references) //IL_04cf: Expected O, but got Unknown //IL_0502: Unknown result type (might be due to invalid IL or missing references) //IL_0527: Unknown result type (might be due to invalid IL or missing references) //IL_0536: Unknown result type (might be due to invalid IL or missing references) //IL_0545: Unknown result type (might be due to invalid IL or missing references) //IL_0554: Unknown result type (might be due to invalid IL or missing references) //IL_0563: Unknown result type (might be due to invalid IL or missing references) //IL_057e: Unknown result type (might be due to invalid IL or missing references) //IL_0593: Unknown result type (might be due to invalid IL or missing references) //IL_05af: Unknown result type (might be due to invalid IL or missing references) //IL_05b9: Expected O, but got Unknown //IL_05c4: Unknown result type (might be due to invalid IL or missing references) //IL_05d0: Unknown result type (might be due to invalid IL or missing references) //IL_05da: Expected O, but got Unknown //IL_05e6: Unknown result type (might be due to invalid IL or missing references) //IL_061b: Unknown result type (might be due to invalid IL or missing references) //IL_05ff: Unknown result type (might be due to invalid IL or missing references) //IL_0604: Unknown result type (might be due to invalid IL or missing references) //IL_060a: Expected O, but got Unknown //IL_0650: Unknown result type (might be due to invalid IL or missing references) //IL_0634: Unknown result type (might be due to invalid IL or missing references) //IL_0639: Unknown result type (might be due to invalid IL or missing references) //IL_063f: Expected O, but got Unknown //IL_0685: Unknown result type (might be due to invalid IL or missing references) //IL_0669: Unknown result type (might be due to invalid IL or missing references) //IL_066e: Unknown result type (might be due to invalid IL or missing references) //IL_0674: Expected O, but got Unknown //IL_06ba: Unknown result type (might be due to invalid IL or missing references) //IL_069e: Unknown result type (might be due to invalid IL or missing references) //IL_06a3: Unknown result type (might be due to invalid IL or missing references) //IL_06a9: Expected O, but got Unknown //IL_06ef: Unknown result type (might be due to invalid IL or missing references) //IL_06d3: Unknown result type (might be due to invalid IL or missing references) //IL_06d8: Unknown result type (might be due to invalid IL or missing references) //IL_06de: Expected O, but got Unknown //IL_0724: Unknown result type (might be due to invalid IL or missing references) //IL_0708: Unknown result type (might be due to invalid IL or missing references) //IL_070d: Unknown result type (might be due to invalid IL or missing references) //IL_0713: Expected O, but got Unknown //IL_0759: Unknown result type (might be due to invalid IL or missing references) //IL_073d: Unknown result type (might be due to invalid IL or missing references) //IL_0742: Unknown result type (might be due to invalid IL or missing references) //IL_0748: Expected O, but got Unknown //IL_078e: Unknown result type (might be due to invalid IL or missing references) //IL_0772: Unknown result type (might be due to invalid IL or missing references) //IL_0777: Unknown result type (might be due to invalid IL or missing references) //IL_077d: Expected O, but got Unknown //IL_07c3: Unknown result type (might be due to invalid IL or missing references) //IL_07a7: Unknown result type (might be due to invalid IL or missing references) //IL_07ac: Unknown result type (might be due to invalid IL or missing references) //IL_07b2: Expected O, but got Unknown //IL_07f8: Unknown result type (might be due to invalid IL or missing references) //IL_07dc: Unknown result type (might be due to invalid IL or missing references) //IL_07e1: Unknown result type (might be due to invalid IL or missing references) //IL_07e7: Expected O, but got Unknown //IL_082d: Unknown result type (might be due to invalid IL or missing references) //IL_0811: Unknown result type (might be due to invalid IL or missing references) //IL_0816: Unknown result type (might be due to invalid IL or missing references) //IL_081c: Expected O, but got Unknown //IL_0861: Unknown result type (might be due to invalid IL or missing references) //IL_0846: Unknown result type (might be due to invalid IL or missing references) //IL_084b: Unknown result type (might be due to invalid IL or missing references) //IL_0851: Expected O, but got Unknown //IL_087a: Unknown result type (might be due to invalid IL or missing references) //IL_087f: Unknown result type (might be due to invalid IL or missing references) //IL_0885: Expected O, but got Unknown DailyData dailyData = DailyManager.Get(category); GameObject val = AnchoredPanel(parent, "DailyCategoryBar", new Color(0f, 0f, 0f, 0.18f), new Vector2(0f, 0.89f), new Vector2(1f, 1f), new Vector2(8f, -38f), new Vector2(-8f, -4f)); HorizontalLayoutGroup obj = val.AddComponent(); ((HorizontalOrVerticalLayoutGroup)obj).childControlWidth = true; ((HorizontalOrVerticalLayoutGroup)obj).childForceExpandWidth = true; ((HorizontalOrVerticalLayoutGroup)obj).spacing = 6f; ((LayoutGroup)obj).padding = new RectOffset(6, 6, 3, 3); string[] categories = Categories; foreach (string text in categories) { string capture = text; MakeButton(val.transform, text, (text == category) ? Green() : Brown(), (UnityAction)delegate { category = capture; day = 1; Render(root, header); }); } GameObject val2 = AnchoredPanel(parent, "DailyDayGrid", new Color(0f, 0f, 0f, 0.16f), new Vector2(0f, 0.17f), new Vector2(0.43f, 0.88f), new Vector2(8f, 8f), new Vector2(-6f, -6f)); GridLayoutGroup obj2 = val2.AddComponent(); obj2.cellSize = new Vector2(118f, 34f); obj2.spacing = new Vector2(6f, 6f); obj2.constraint = (Constraint)1; obj2.constraintCount = 3; ((LayoutGroup)obj2).padding = new RectOffset(8, 8, 8, 8); for (int num = 1; num <= 28; num++) { int capture2 = num; RewardLine reward = dailyData.Get(num); MakeButton(val2.transform, CompactRewardLabel(num, reward), (Color)((num == day) ? new Color(0.45f, 0.18f, 0.08f, 0.95f) : Brown()), (UnityAction)delegate { day = capture2; Render(root, header); }); } RewardLine rewardLine = dailyData.Get(day); GameObject val3 = AnchoredPanel(parent, "DailySelectedEditor", new Color(0.04f, 0.025f, 0.015f, 0.72f), new Vector2(0.45f, 0.17f), new Vector2(1f, 0.88f), new Vector2(6f, 8f), new Vector2(-8f, -6f)); VerticalLayoutGroup obj3 = val3.AddComponent(); ((HorizontalOrVerticalLayoutGroup)obj3).childControlHeight = false; ((HorizontalOrVerticalLayoutGroup)obj3).childForceExpandHeight = false; ((HorizontalOrVerticalLayoutGroup)obj3).spacing = 6f; ((LayoutGroup)obj3).padding = new RectOffset(12, 12, 10, 10); MakeLabel(val3.transform, category + " Daily Reward Editor", 17, (TextAnchor)3, Color.white); MakeReadOnlyField(val3.transform, "Day", day.ToString()); MakeReadOnlyField(val3.transform, "Display Name", RewardDisplayName(rewardLine)); GameObject obj4 = Row(val3.transform, "IconPreviewRow", 54f, topAnchored: false); MakeLabel(obj4.transform, "Icon Preview", 13, (TextAnchor)3, new Color(0.9f, 0.82f, 0.62f, 1f)); MakeIconPreview(obj4.transform, rewardLine); InputField prefab = MakeLabeledInput(val3.transform, "Prefab", rewardLine.Prefab); InputField amount = MakeLabeledInput(val3.transform, "Amount", rewardLine.Amount.ToString()); InputField quality = MakeLabeledInput(val3.transform, "Quality", rewardLine.Quality.ToString()); InputField variant = MakeLabeledInput(val3.transform, "Variant", rewardLine.Variant.ToString()); GameObject val4 = Row(val3.transform, "PrefabBrowser", 32f, topAnchored: false); MakeLabel(val4.transform, "Prefab Search", 13, (TextAnchor)3, Color.white); InputField prefabFilter = MakeInput(val4.transform, prefabSearch, "type prefab"); MakeButton(val4.transform, "Filter", Brown(), (UnityAction)delegate { prefabSearch = prefabFilter.text; Render(root, header); }); foreach (string item in GetPrefabNames(prefabSearch).Take(3)) { string capturePrefab = item; MakeButton(val4.transform, Short(capturePrefab, 14), Brown(), (UnityAction)delegate { prefab.text = capturePrefab; prefabSearch = capturePrefab; }); } MakeLabel(val3.transform, "Preview: " + RewardPreviewReadable(rewardLine), 12, (TextAnchor)3, Color.yellow); GameObject obj5 = AnchoredPanel(parent, "DailyActionBar", new Color(0f, 0f, 0f, 0.2f), new Vector2(0f, 0f), new Vector2(1f, 0.155f), new Vector2(8f, 8f), new Vector2(-8f, -8f)); GridLayoutGroup obj6 = obj5.AddComponent(); obj6.cellSize = new Vector2(116f, 30f); obj6.spacing = new Vector2(6f, 6f); obj6.constraint = (Constraint)1; obj6.constraintCount = 6; ((LayoutGroup)obj6).padding = new RectOffset(8, 8, 6, 6); MakeButton(obj5.transform, "Apply", Green(), (UnityAction)delegate { DailyManager.Update(category, day, prefab.text, amount.text, quality.text, variant.text); Render(root, header); }); Transform transform = obj5.transform; Color color = Green(); object obj7 = <>c.<>9__24_2; if (obj7 == null) { UnityAction val5 = delegate { DailyManager.AddReward(category, day); Render(root, header); }; <>c.<>9__24_2 = val5; obj7 = (object)val5; } MakeButton(transform, "Add Reward", color, (UnityAction)obj7); Transform transform2 = obj5.transform; Color color2 = Danger(); object obj8 = <>c.<>9__24_3; if (obj8 == null) { UnityAction val6 = delegate { DailyManager.RemoveReward(category, day); Render(root, header); }; <>c.<>9__24_3 = val6; obj8 = (object)val6; } MakeButton(transform2, "Remove", color2, (UnityAction)obj8); Transform transform3 = obj5.transform; Color color3 = Brown(); object obj9 = <>c.<>9__24_4; if (obj9 == null) { UnityAction val7 = delegate { DailyManager.CopyDay(category, day); Render(root, header); }; <>c.<>9__24_4 = val7; obj9 = (object)val7; } MakeButton(transform3, "Copy Day", color3, (UnityAction)obj9); Transform transform4 = obj5.transform; Color color4 = Brown(); object obj10 = <>c.<>9__24_5; if (obj10 == null) { UnityAction val8 = delegate { DailyManager.PasteDay(category, day); Render(root, header); }; <>c.<>9__24_5 = val8; obj10 = (object)val8; } MakeButton(transform4, "Paste Day", color4, (UnityAction)obj10); Transform transform5 = obj5.transform; Color color5 = Brown(); object obj11 = <>c.<>9__24_6; if (obj11 == null) { UnityAction val9 = delegate { DailyManager.CopyWeek(category, day); Render(root, header); }; <>c.<>9__24_6 = val9; obj11 = (object)val9; } MakeButton(transform5, "Copy Week", color5, (UnityAction)obj11); Transform transform6 = obj5.transform; Color color6 = Brown(); object obj12 = <>c.<>9__24_7; if (obj12 == null) { UnityAction val10 = delegate { DailyManager.PasteWeek(category, day); Render(root, header); }; <>c.<>9__24_7 = val10; obj12 = (object)val10; } MakeButton(transform6, "Paste Week", color6, (UnityAction)obj12); Transform transform7 = obj5.transform; Color color7 = Danger(); object obj13 = <>c.<>9__24_8; if (obj13 == null) { UnityAction val11 = delegate { DailyManager.ResetDay(category, day); Render(root, header); }; <>c.<>9__24_8 = val11; obj13 = (object)val11; } MakeButton(transform7, "Reset Day", color7, (UnityAction)obj13); Transform transform8 = obj5.transform; Color color8 = Danger(); object obj14 = <>c.<>9__24_9; if (obj14 == null) { UnityAction val12 = delegate { DailyManager.ResetCategory(category); Render(root, header); }; <>c.<>9__24_9 = val12; obj14 = (object)val12; } MakeButton(transform8, "Reset Cat", color8, (UnityAction)obj14); Transform transform9 = obj5.transform; Color color9 = Brown(); object obj15 = <>c.<>9__24_10; if (obj15 == null) { UnityAction val13 = delegate { DailyManager.Undo(category); Render(root, header); }; <>c.<>9__24_10 = val13; obj15 = (object)val13; } MakeButton(transform9, "Undo", color9, (UnityAction)obj15); Transform transform10 = obj5.transform; Color color10 = Brown(); object obj16 = <>c.<>9__24_11; if (obj16 == null) { UnityAction val14 = delegate { DailyManager.Redo(category); Render(root, header); }; <>c.<>9__24_11 = val14; obj16 = (object)val14; } MakeButton(transform10, "Redo", color10, (UnityAction)obj16); Transform transform11 = obj5.transform; Color color11 = Green(); object obj17 = <>c.<>9__24_12; if (obj17 == null) { UnityAction val15 = delegate { DailyManager.Save(category); Render(root, header); }; <>c.<>9__24_12 = val15; obj17 = (object)val15; } MakeButton(transform11, "Save", color11, (UnityAction)obj17); Transform transform12 = obj5.transform; Color color12 = Brown(); object obj18 = <>c.<>9__24_13; if (obj18 == null) { UnityAction val16 = delegate { DailyManager.Load(category); SetStatus("Reloaded " + category); Render(root, header); }; <>c.<>9__24_13 = val16; obj18 = (object)val16; } MakeButton(transform12, "Reload", color12, (UnityAction)obj18); Transform transform13 = obj5.transform; Color color13 = Brown(); object obj19 = <>c.<>9__24_14; if (obj19 == null) { UnityAction val17 = delegate { ExportFile(DailyManager.PathFor(category), category + "Rewards"); Render(root, header); }; <>c.<>9__24_14 = val17; obj19 = (object)val17; } MakeButton(transform13, "Export", color13, (UnityAction)obj19); } private static void RenderRewardPacks(Transform parent) { //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0056: 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_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Expected O, but got Unknown //IL_008b: 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) //IL_0074: Unknown result type (might be due to invalid IL or missing references) //IL_007a: Expected O, but got Unknown //IL_00c0: Unknown result type (might be due to invalid IL or missing references) //IL_00a4: Unknown result type (might be due to invalid IL or missing references) //IL_00a9: Unknown result type (might be due to invalid IL or missing references) //IL_00af: Expected O, but got Unknown //IL_00d9: Unknown result type (might be due to invalid IL or missing references) //IL_00de: Unknown result type (might be due to invalid IL or missing references) //IL_00e4: Expected O, but got Unknown RewardPackManager.Load(); GameObject obj = Row(parent, "PacksTop", 34f, topAnchored: true); Transform transform = obj.transform; Color color = Green(); object obj2 = <>c.<>9__25_0; if (obj2 == null) { UnityAction val = delegate { RewardPackManager.Create(); Render(root, header); }; <>c.<>9__25_0 = val; obj2 = (object)val; } MakeButton(transform, "Create Pack", color, (UnityAction)obj2); Transform transform2 = obj.transform; Color color2 = Green(); object obj3 = <>c.<>9__25_1; if (obj3 == null) { UnityAction val2 = delegate { RewardPackManager.Save(); Render(root, header); }; <>c.<>9__25_1 = val2; obj3 = (object)val2; } MakeButton(transform2, "Save", color2, (UnityAction)obj3); Transform transform3 = obj.transform; Color color3 = Brown(); object obj4 = <>c.<>9__25_2; if (obj4 == null) { UnityAction val3 = delegate { RewardPackManager.Load(); SetStatus("Reward packs reloaded"); Render(root, header); }; <>c.<>9__25_2 = val3; obj4 = (object)val3; } MakeButton(transform3, "Reload", color3, (UnityAction)obj4); Transform transform4 = obj.transform; Color color4 = Brown(); object obj5 = <>c.<>9__25_3; if (obj5 == null) { UnityAction val4 = delegate { ExportFile(RewardPackManager.Path, "RewardPacks"); Render(root, header); }; <>c.<>9__25_3 = val4; obj5 = (object)val4; } MakeButton(transform4, "Export", color4, (UnityAction)obj5); TextList(parent, RewardPackManager.Describe(), 13); obj.transform.SetAsLastSibling(); } private static void RenderRedeem(Transform parent) { //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Expected O, but got Unknown //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_009a: Unknown result type (might be due to invalid IL or missing references) //IL_007e: Unknown result type (might be due to invalid IL or missing references) //IL_0083: Unknown result type (might be due to invalid IL or missing references) //IL_0089: Expected O, but got Unknown //IL_00cf: Unknown result type (might be due to invalid IL or missing references) //IL_00b3: 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_00be: Expected O, but got Unknown //IL_0104: Unknown result type (might be due to invalid IL or missing references) //IL_00e8: Unknown result type (might be due to invalid IL or missing references) //IL_00ed: Unknown result type (might be due to invalid IL or missing references) //IL_00f3: Expected O, but got Unknown //IL_0139: Unknown result type (might be due to invalid IL or missing references) //IL_011d: Unknown result type (might be due to invalid IL or missing references) //IL_0122: Unknown result type (might be due to invalid IL or missing references) //IL_0128: Expected O, but got Unknown //IL_016e: Unknown result type (might be due to invalid IL or missing references) //IL_0152: Unknown result type (might be due to invalid IL or missing references) //IL_0157: Unknown result type (might be due to invalid IL or missing references) //IL_015d: Expected O, but got Unknown //IL_01a3: Unknown result type (might be due to invalid IL or missing references) //IL_0187: Unknown result type (might be due to invalid IL or missing references) //IL_018c: Unknown result type (might be due to invalid IL or missing references) //IL_0192: Expected O, but got Unknown //IL_01d8: Unknown result type (might be due to invalid IL or missing references) //IL_01bc: Unknown result type (might be due to invalid IL or missing references) //IL_01c1: Unknown result type (might be due to invalid IL or missing references) //IL_01c7: Expected O, but got Unknown //IL_01f1: Unknown result type (might be due to invalid IL or missing references) //IL_01f6: Unknown result type (might be due to invalid IL or missing references) //IL_01fc: Expected O, but got Unknown //IL_024a: Unknown result type (might be due to invalid IL or missing references) //IL_03cb: Unknown result type (might be due to invalid IL or missing references) //IL_03d7: Unknown result type (might be due to invalid IL or missing references) //IL_03e1: Expected O, but got Unknown RedeemAdminManager.Load(); GameObject val = Row(parent, "RedeemTop", 34f, topAnchored: true); InputField search = MakeInput(val.transform, RedeemAdminManager.Search, "Search"); MakeButton(val.transform, "Search", Brown(), (UnityAction)delegate { RedeemAdminManager.Search = search.text; Render(root, header); }); Transform transform = val.transform; Color color = Green(); object obj = <>c.<>9__26_1; if (obj == null) { UnityAction val2 = delegate { RedeemAdminManager.Create(random: false); Render(root, header); }; <>c.<>9__26_1 = val2; obj = (object)val2; } MakeButton(transform, "Create", color, (UnityAction)obj); Transform transform2 = val.transform; Color color2 = Green(); object obj2 = <>c.<>9__26_2; if (obj2 == null) { UnityAction val3 = delegate { RedeemAdminManager.Create(random: true); Render(root, header); }; <>c.<>9__26_2 = val3; obj2 = (object)val3; } MakeButton(transform2, "Random", color2, (UnityAction)obj2); Transform transform3 = val.transform; Color color3 = Brown(); object obj3 = <>c.<>9__26_3; if (obj3 == null) { UnityAction val4 = delegate { RedeemAdminManager.DuplicateFirst(); Render(root, header); }; <>c.<>9__26_3 = val4; obj3 = (object)val4; } MakeButton(transform3, "Duplicate", color3, (UnityAction)obj3); Transform transform4 = val.transform; Color color4 = Brown(); object obj4 = <>c.<>9__26_4; if (obj4 == null) { UnityAction val5 = delegate { RedeemAdminManager.DisableFirst(); Render(root, header); }; <>c.<>9__26_4 = val5; obj4 = (object)val5; } MakeButton(transform4, "Disable", color4, (UnityAction)obj4); Transform transform5 = val.transform; Color color5 = Danger(); object obj5 = <>c.<>9__26_5; if (obj5 == null) { UnityAction val6 = delegate { RedeemAdminManager.DeleteFirst(); Render(root, header); }; <>c.<>9__26_5 = val6; obj5 = (object)val6; } MakeButton(transform5, "Delete", color5, (UnityAction)obj5); Transform transform6 = val.transform; Color color6 = Green(); object obj6 = <>c.<>9__26_6; if (obj6 == null) { UnityAction val7 = delegate { RedeemAdminManager.Save(); Render(root, header); }; <>c.<>9__26_6 = val7; obj6 = (object)val7; } MakeButton(transform6, "Save", color6, (UnityAction)obj6); Transform transform7 = val.transform; Color color7 = Brown(); object obj7 = <>c.<>9__26_7; if (obj7 == null) { UnityAction val8 = delegate { RedeemAdminManager.Load(); SetStatus("Redeem codes reloaded"); Render(root, header); }; <>c.<>9__26_7 = val8; obj7 = (object)val8; } MakeButton(transform7, "Reload", color7, (UnityAction)obj7); Transform transform8 = val.transform; Color color8 = Brown(); object obj8 = <>c.<>9__26_8; if (obj8 == null) { UnityAction val9 = delegate { ExportFile(RedeemAdminManager.Path, "RedeemCodes"); Render(root, header); }; <>c.<>9__26_8 = val9; obj8 = (object)val9; } MakeButton(transform8, "Export", color8, (UnityAction)obj8); RedeemSystem.RedeemCode redeemCode = RedeemAdminManager.FirstFiltered(); if (redeemCode != null) { GameObject val10 = Form(parent, 0f, 0f, 1f, 0.45f); MakeLabel(val10.transform, "Edit first filtered code: " + redeemCode.Code, 15, (TextAnchor)3, Color.white); InputField codeName = MakeInput(val10.transform, redeemCode.Code, "Code"); InputField maxUses = MakeInput(val10.transform, redeemCode.MaxUses.ToString(), "Max Uses (0 unlimited)"); InputField expires = MakeInput(val10.transform, redeemCode.ExpirationUtc ?? "", "Expiration UTC"); InputField allowed = MakeInput(val10.transform, string.Join(";", redeemCode.AllowedSteamIDs ?? new List()), "Allowed SteamIDs ; separated"); Toggle disabled = MakeToggle(val10.transform, "Disabled", redeemCode.Disabled); Toggle oneSteam = MakeToggle(val10.transform, "One Claim Per SteamID", redeemCode.OneTimePerSteamID); RedeemSystem.RedeemReward redeemReward = ((redeemCode.Rewards != null && redeemCode.Rewards.Count > 0) ? redeemCode.Rewards[0] : new RedeemSystem.RedeemReward { Prefab = "Wood", Amount = 10, Quality = 1 }); InputField rewardPrefab = MakeInput(val10.transform, redeemReward.Prefab, "First reward prefab"); InputField rewardAmount = MakeInput(val10.transform, redeemReward.Amount.ToString(), "First reward amount"); MakeButton(Row(val10.transform, "RedeemEditActions", 34f, topAnchored: false).transform, "Apply Code", Green(), (UnityAction)delegate { RedeemAdminManager.UpdateFirst(codeName.text, maxUses.text, expires.text, allowed.text, disabled.isOn, oneSteam.isOn, rewardPrefab.text, rewardAmount.text); Render(root, header); }); } TextList(parent, RedeemAdminManager.Describe(), 12); } private static void RenderAccessManagement(Transform parent) { //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_0061: 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_00d9: Unknown result type (might be due to invalid IL or missing references) //IL_01ab: Unknown result type (might be due to invalid IL or missing references) //IL_01b7: Unknown result type (might be due to invalid IL or missing references) //IL_01c1: Expected O, but got Unknown //IL_01cc: Unknown result type (might be due to invalid IL or missing references) //IL_0164: Unknown result type (might be due to invalid IL or missing references) //IL_015d: Unknown result type (might be due to invalid IL or missing references) //IL_01e5: Unknown result type (might be due to invalid IL or missing references) //IL_01ea: Unknown result type (might be due to invalid IL or missing references) //IL_01f0: Expected O, but got Unknown //IL_0171: Unknown result type (might be due to invalid IL or missing references) //IL_017b: Expected O, but got Unknown //IL_03af: Unknown result type (might be due to invalid IL or missing references) //IL_027f: Unknown result type (might be due to invalid IL or missing references) //IL_0328: Unknown result type (might be due to invalid IL or missing references) //IL_0335: Unknown result type (might be due to invalid IL or missing references) //IL_033f: Expected O, but got Unknown //IL_034a: Unknown result type (might be due to invalid IL or missing references) //IL_0363: Unknown result type (might be due to invalid IL or missing references) //IL_0368: Unknown result type (might be due to invalid IL or missing references) //IL_036e: Expected O, but got Unknown //IL_04aa: Unknown result type (might be due to invalid IL or missing references) //IL_048f: Unknown result type (might be due to invalid IL or missing references) //IL_050f: Unknown result type (might be due to invalid IL or missing references) //IL_051c: Unknown result type (might be due to invalid IL or missing references) //IL_0526: Expected O, but got Unknown //IL_0533: Unknown result type (might be due to invalid IL or missing references) //IL_0540: Unknown result type (might be due to invalid IL or missing references) //IL_054a: Expected O, but got Unknown //IL_04e1: Unknown result type (might be due to invalid IL or missing references) AccessManager.Load(); GameObject val = Form(parent, 0f, 0.58f, 1f, 1f); MakeLabel(val.transform, "Admin & Reward Access", 18, (TextAnchor)3, Color.white); MakeLabel(val.transform, "Manage SteamID64 access for Admin, Premium, Epic, and Legendary rewards.", 13, (TextAnchor)3, new Color(0.9f, 0.82f, 0.62f, 1f)); MakeLabel(val.transform, "SteamID64", 14, (TextAnchor)3, Color.white); InputField steam = MakeInput(val.transform, accessSteamId, "76561198000000000"); LayoutElement component = ((Component)steam).GetComponent(); if ((Object)(object)component != (Object)null) { component.minWidth = 360f; component.preferredWidth = 420f; } MakeLabel(val.transform, "Access Type", 14, (TextAnchor)3, Color.white); GameObject val2 = Row(val.transform, "AccessType", 34f, topAnchored: false); string[] array = new string[4] { "Admin", "Premium", "Epic", "Legendary" }; foreach (string text in array) { string capture = text; MakeButton(val2.transform, text, (text == accessType) ? Green() : Brown(), (UnityAction)delegate { accessSteamId = steam.text; accessType = capture; Render(root, header); }); } GameObject obj = Row(val.transform, "AccessAdd", 34f, topAnchored: false); MakeButton(obj.transform, "Add Access", Green(), (UnityAction)delegate { accessSteamId = steam.text; AccessManager.Add(accessSteamId, accessType); Render(root, header); }); Transform transform = obj.transform; Color color = Brown(); object obj2 = <>c.<>9__27_1; if (obj2 == null) { UnityAction val3 = delegate { AccessManager.Load(); SetStatus("Access lists reloaded"); Render(root, header); }; <>c.<>9__27_1 = val3; obj2 = (object)val3; } MakeButton(transform, "Reload", color, (UnityAction)obj2); if (!string.IsNullOrWhiteSpace(editSteamId)) { AccessRow accessRow = AccessManager.Rows().FirstOrDefault((AccessRow r) => r.SteamID == editSteamId); if (accessRow != null && !accessRow.BuiltIn) { GameObject val4 = Form(parent, 0f, 0.43f, 1f, 0.57f); MakeLabel(val4.transform, "Edit access: " + editSteamId, 14, (TextAnchor)3, Color.white); Toggle admin = MakeToggle(val4.transform, "Admin", accessRow.Admin); Toggle premium = MakeToggle(val4.transform, "Premium", accessRow.Premium); Toggle epic = MakeToggle(val4.transform, "Epic", accessRow.Epic); Toggle legendary = MakeToggle(val4.transform, "Legendary", accessRow.Legendary); GameObject obj3 = Row(val4.transform, "AccessEditActions", 34f, topAnchored: false); MakeButton(obj3.transform, "Save Changes", Green(), (UnityAction)delegate { AccessManager.Update(editSteamId, admin.isOn, premium.isOn, epic.isOn, legendary.isOn); Render(root, header); }); Transform transform2 = obj3.transform; Color color2 = Brown(); object obj4 = <>c.<>9__27_5; if (obj4 == null) { UnityAction val5 = delegate { editSteamId = ""; Render(root, header); }; <>c.<>9__27_5 = val5; obj4 = (object)val5; } MakeButton(transform2, "Cancel", color2, (UnityAction)obj4); } } GameObject obj5 = Form(parent, 0f, 0f, 1f, string.IsNullOrWhiteSpace(editSteamId) ? 0.57f : 0.42f); MakeLabel(obj5.transform, "SteamID64 | Admin | Premium | Epic | Legendary | Action", 13, (TextAnchor)3, Color.yellow); GameObject val6 = ScrollArea(obj5.transform, "AccessScroll"); foreach (AccessRow item in AccessManager.Rows()) { GameObject val7 = Row(val6.transform, "AccessRow_" + item.SteamID, 30f, topAnchored: false); MakeLabel(val7.transform, item.SteamID + " | " + Yes(item.Admin) + " | " + Yes(item.Premium) + " | " + Yes(item.Epic) + " | " + Yes(item.Legendary), 12, (TextAnchor)3, (Color)(item.BuiltIn ? new Color(0.9f, 0.75f, 0.35f, 1f) : Color.white)); if (item.BuiltIn) { MakeLabel(val7.transform, "Built-in Owner", 12, (TextAnchor)4, new Color(0.9f, 0.75f, 0.35f, 1f)); continue; } string capture2 = item.SteamID; MakeButton(val7.transform, "Edit", Brown(), (UnityAction)delegate { editSteamId = capture2; Render(root, header); }); MakeButton(val7.transform, "Remove All", Danger(), (UnityAction)delegate { AccessManager.RemoveAll(capture2); if (editSteamId == capture2) { editSteamId = ""; } Render(root, header); }); } } private static string Yes(bool value) { if (!value) { return "NO"; } return "YES"; } private static void RenderGrant(Transform parent) { //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0110: Unknown result type (might be due to invalid IL or missing references) //IL_011c: Unknown result type (might be due to invalid IL or missing references) //IL_0126: Expected O, but got Unknown //IL_0132: Unknown result type (might be due to invalid IL or missing references) //IL_013e: Unknown result type (might be due to invalid IL or missing references) //IL_0148: Expected O, but got Unknown //IL_0153: Unknown result type (might be due to invalid IL or missing references) //IL_015f: Unknown result type (might be due to invalid IL or missing references) //IL_0169: Expected O, but got Unknown //IL_01b9: Unknown result type (might be due to invalid IL or missing references) //IL_01d2: Unknown result type (might be due to invalid IL or missing references) GameObject val = Form(parent, 0f, 0f, 1f, 1f); MakeLabel(val.transform, "Grant Rewards", 16, (TextAnchor)3, Color.white); InputField target = MakeInput(val.transform, "", "Online player / SteamID"); InputField pack = MakeInput(val.transform, "", "Reward Pack"); InputField prefab = MakeInput(val.transform, "Wood", "Prefab"); InputField amount = MakeInput(val.transform, "1", "Amount"); InputField tokens = MakeInput(val.transform, "0", "Tokens"); Toggle broadcast = MakeToggle(val.transform, "Broadcast", value: false); Toggle notify = MakeToggle(val.transform, "Private notification", value: true); GameObject obj = Row(val.transform, "GrantActions", 34f, topAnchored: false); MakeButton(obj.transform, "Validate", Brown(), (UnityAction)delegate { SetStatus(GrantManager.Validate(prefab.text, amount.text, tokens.text)); Render(root, header); }); MakeButton(obj.transform, "Confirm Grant", Green(), (UnityAction)delegate { GrantManager.Grant(target.text, pack.text, prefab.text, amount.text, tokens.text, broadcast.isOn, notify.isOn); Render(root, header); }); MakeButton(obj.transform, "Grant To Myself", Green(), (UnityAction)delegate { GrantManager.GrantToMyself(pack.text, prefab.text, amount.text, tokens.text, broadcast.isOn, notify.isOn); Render(root, header); }); MakeLabel(val.transform, RewardPreview(new RewardLine { Prefab = prefab.text, Amount = ParseInt(new string[2] { "", amount.text }, 1, 1) }), 12, (TextAnchor)3, Color.yellow); MakeLabel(val.transform, "Remote/offline delivery is logged and prepared for future server RPC expansion; no existing gameplay RPCs were changed.", 12, (TextAnchor)3, Color.yellow); } private static void RenderWebhook(Transform parent) { //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_024c: Unknown result type (might be due to invalid IL or missing references) //IL_0298: Unknown result type (might be due to invalid IL or missing references) //IL_0291: Unknown result type (might be due to invalid IL or missing references) //IL_02c4: Unknown result type (might be due to invalid IL or missing references) //IL_02d0: Unknown result type (might be due to invalid IL or missing references) //IL_02da: Expected O, but got Unknown //IL_02e6: Unknown result type (might be due to invalid IL or missing references) //IL_031b: Unknown result type (might be due to invalid IL or missing references) //IL_02ff: Unknown result type (might be due to invalid IL or missing references) //IL_0304: Unknown result type (might be due to invalid IL or missing references) //IL_030a: Expected O, but got Unknown //IL_034f: Unknown result type (might be due to invalid IL or missing references) //IL_0334: Unknown result type (might be due to invalid IL or missing references) //IL_0339: Unknown result type (might be due to invalid IL or missing references) //IL_033f: Expected O, but got Unknown //IL_0368: Unknown result type (might be due to invalid IL or missing references) //IL_036d: Unknown result type (might be due to invalid IL or missing references) //IL_0373: Expected O, but got Unknown WebhookManager.Load(); WebhookSettings data = WebhookManager.Data; GameObject val = Form(parent, 0f, 0f, 1f, 1f); MakeLabel(val.transform, "Discord Webhook", 18, (TextAnchor)3, Color.white); MakeLabel(val.transform, "Saved URL: " + WebhookManager.MaskedUrl(), 12, (TextAnchor)3, new Color(0.9f, 0.82f, 0.62f, 1f)); InputField url = MakeInput(val.transform, "", "Paste new Discord Webhook URL to replace saved URL"); Toggle enabled = MakeToggle(val.transform, "Enable Webhook", data.EnableWebhook); Toggle store = MakeToggle(val.transform, "Kit Pack Purchase", data.StorePurchases); Toggle daily = MakeToggle(val.transform, "Daily Claim", data.DailyClaims); Toggle premium = MakeToggle(val.transform, "Premium Claim", data.PremiumClaims); Toggle epic = MakeToggle(val.transform, "Epic Claim", data.EpicClaims); Toggle legendary = MakeToggle(val.transform, "Legendary Claim", data.LegendaryClaims); Toggle redeemOk = MakeToggle(val.transform, "Redeem Success", data.RedeemSuccess); Toggle redeemFail = MakeToggle(val.transform, "Redeem Failed", data.RedeemFailed); Toggle grants = MakeToggle(val.transform, "Admin Grant", data.RewardGrants); Toggle admin = MakeToggle(val.transform, "Admin Actions", data.AdminActions); Toggle errors = MakeToggle(val.transform, "Errors", data.Errors); Toggle started = MakeToggle(val.transform, "Server Started", data.ServerStarted); Toggle stopped = MakeToggle(val.transform, "Server Stopped", data.ServerStopped); Toggle future = MakeToggle(val.transform, "Future Event Rewards", data.FutureEventRewards); MakeLabel(val.transform, "Last send status: " + (string.IsNullOrWhiteSpace(data.LastSendStatus) ? "Never sent" : data.LastSendStatus), 12, (TextAnchor)3, Color.yellow); MakeLabel(val.transform, "Last HTTP error: " + (string.IsNullOrWhiteSpace(data.LastHttpError) ? "None" : data.LastHttpError), 12, (TextAnchor)3, string.IsNullOrWhiteSpace(data.LastHttpError) ? Color.white : Color.red); GameObject obj = Row(val.transform, "WebhookActions", 34f, topAnchored: false); MakeButton(obj.transform, "Save", Green(), (UnityAction)delegate { WebhookManager.Update(url.text, enabled.isOn, store.isOn, daily.isOn, premium.isOn, epic.isOn, legendary.isOn, redeemOk.isOn, redeemFail.isOn, grants.isOn, admin.isOn, errors.isOn, started.isOn, stopped.isOn, future.isOn); Render(root, header); }); Transform transform = obj.transform; Color color = Danger(); object obj2 = <>c.<>9__30_1; if (obj2 == null) { UnityAction val2 = delegate { WebhookManager.Clear(); Render(root, header); }; <>c.<>9__30_1 = val2; obj2 = (object)val2; } MakeButton(transform, "Clear", color, (UnityAction)obj2); Transform transform2 = obj.transform; Color color2 = Brown(); object obj3 = <>c.<>9__30_2; if (obj3 == null) { UnityAction val3 = delegate { WebhookManager.Test(); Render(root, header); }; <>c.<>9__30_2 = val3; obj3 = (object)val3; } MakeButton(transform2, "Test Webhook", color2, (UnityAction)obj3); Transform transform3 = obj.transform; Color color3 = Brown(); object obj4 = <>c.<>9__30_3; if (obj4 == null) { UnityAction val4 = delegate { ExportFile(WebhookManager.Path, "Webhook"); Render(root, header); }; <>c.<>9__30_3 = val4; obj4 = (object)val4; } MakeButton(transform3, "Export", color3, (UnityAction)obj4); } private static void RenderHistory(Transform parent) { //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Expected O, but got Unknown //IL_00e4: Unknown result type (might be due to invalid IL or missing references) //IL_00b7: 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_00fd: 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_0108: Expected O, but got Unknown //IL_00c4: Unknown result type (might be due to invalid IL or missing references) //IL_00ce: Expected O, but got Unknown HistoryManager.Load(); GameObject val = Row(parent, "HistoryTop", 34f, topAnchored: true); InputField search = MakeInput(val.transform, HistoryManager.Search, "Search"); MakeButton(val.transform, "Search", Brown(), (UnityAction)delegate { HistoryManager.Search = search.text; Render(root, header); }); string[] array = new string[4] { "Today", "Week", "Month", "All" }; foreach (string text in array) { string capture = text; MakeButton(val.transform, text, (HistoryManager.Filter == text) ? Green() : Brown(), (UnityAction)delegate { HistoryManager.Filter = capture; Render(root, header); }); } Transform transform = val.transform; Color color = Brown(); object obj = <>c.<>9__31_1; if (obj == null) { UnityAction val2 = delegate { ExportFile(HistoryManager.Path, "History"); Render(root, header); }; <>c.<>9__31_1 = val2; obj = (object)val2; } MakeButton(transform, "Export", color, (UnityAction)obj); TextList(parent, HistoryManager.Describe(), 12); } private static void RenderSettings(Transform parent) { //IL_0153: Unknown result type (might be due to invalid IL or missing references) //IL_015f: Unknown result type (might be due to invalid IL or missing references) //IL_0169: Expected O, but got Unknown //IL_0175: Unknown result type (might be due to invalid IL or missing references) //IL_01aa: Unknown result type (might be due to invalid IL or missing references) //IL_018e: Unknown result type (might be due to invalid IL or missing references) //IL_0193: Unknown result type (might be due to invalid IL or missing references) //IL_0199: Expected O, but got Unknown //IL_01de: Unknown result type (might be due to invalid IL or missing references) //IL_01c3: Unknown result type (might be due to invalid IL or missing references) //IL_01c8: Unknown result type (might be due to invalid IL or missing references) //IL_01ce: Expected O, but got Unknown //IL_0216: Unknown result type (might be due to invalid IL or missing references) //IL_01f7: Unknown result type (might be due to invalid IL or missing references) //IL_01fc: Unknown result type (might be due to invalid IL or missing references) //IL_0202: Expected O, but got Unknown SettingsManager.Load(); AdminSettings data = SettingsManager.Data; GameObject val = Form(parent, 0f, 0f, 1f, 1f); InputField tokens = MakeInput(val.transform, data.TokensPerHour.ToString(), "Tokens Per Hour"); Toggle popup = MakeToggle(val.transform, "Reward Popup", data.RewardPopup); InputField duration = MakeInput(val.transform, data.PopupDuration.ToString(), "Popup Duration"); Toggle animations = MakeToggle(val.transform, "Animations", data.Animations); Toggle redeem = MakeToggle(val.transform, "Redeem Enabled", data.RedeemEnabled); Toggle webhook = MakeToggle(val.transform, "Webhook Enabled", data.WebhookEnabled); Toggle autoReload = MakeToggle(val.transform, "Auto Reload", data.AutoReload); Toggle debug = MakeToggle(val.transform, "Debug Logging", data.DebugLogging); Toggle backups = MakeToggle(val.transform, "Config Auto Backup", data.ConfigAutoBackup); GameObject obj = Row(val.transform, "SettingsActions", 34f, topAnchored: false); MakeButton(obj.transform, "Save", Green(), (UnityAction)delegate { SettingsManager.Update(tokens.text, popup.isOn, duration.text, animations.isOn, redeem.isOn, webhook.isOn, autoReload.isOn, debug.isOn, backups.isOn); Render(root, header); }); Transform transform = obj.transform; Color color = Brown(); object obj2 = <>c.<>9__32_1; if (obj2 == null) { UnityAction val2 = delegate { Forteca_ServerRewards.ReloadExternalAssetsFromAdmin(); SetStatus("Custom Themes & Assets reloaded from " + ExternalAssetSystem.RootPath); Render(root, header); }; <>c.<>9__32_1 = val2; obj2 = (object)val2; } MakeButton(transform, "Reload Themes", color, (UnityAction)obj2); Transform transform2 = obj.transform; Color color2 = Brown(); object obj3 = <>c.<>9__32_2; if (obj3 == null) { UnityAction val3 = delegate { ExportAll(); Render(root, header); }; <>c.<>9__32_2 = val3; obj3 = (object)val3; } MakeButton(transform2, "Export All", color2, (UnityAction)obj3); Transform transform3 = obj.transform; Color color3 = Brown(); object obj4 = <>c.<>9__32_3; if (obj4 == null) { UnityAction val4 = delegate { SetStatus("Import prepared: place reviewed JSON/CFG files in " + exportPath + " and reload the relevant page."); Render(root, header); }; <>c.<>9__32_3 = val4; obj4 = (object)val4; } MakeButton(transform3, "Import", color3, (UnityAction)obj4); MakeLabel(val.transform, "Settings UI writes Internal/Settings.json. Editable files are under Editable/; old flat Daily/Redeem/User paths are not supported by Hotfix 2.", 12, (TextAnchor)3, Color.yellow); } private static GameObject AnchoredPanel(Transform parent, string name, Color color, Vector2 anchorMin, Vector2 anchorMax, Vector2 offsetMin, Vector2 offsetMax) { //IL_0002: 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_0016: 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_0025: Unknown result type (might be due to invalid IL or missing references) GameObject obj = Panel(parent, name, color); RectTransform component = obj.GetComponent(); component.anchorMin = anchorMin; component.anchorMax = anchorMax; component.offsetMin = offsetMin; component.offsetMax = offsetMax; return obj; } private static string CompactRewardLabel(int index, RewardLine reward) { if (reward == null) { return index + ". Empty"; } string text = ((reward.Amount > 0) ? (" x" + reward.Amount) : " empty"); return index + ". " + Short(reward.Prefab, 13) + text; } private static InputField MakeLabeledInput(Transform parent, string label, string value) { //IL_0035: Unknown result type (might be due to invalid IL or missing references) GameObject obj = Row(parent, "Field_" + label, 32f, topAnchored: false); LayoutElement component = ((Component)MakeLabel(obj.transform, label, 13, (TextAnchor)3, new Color(0.9f, 0.82f, 0.62f, 1f))).GetComponent(); if ((Object)(object)component != (Object)null) { component.minWidth = 110f; } InputField obj2 = MakeInput(obj.transform, value, label); LayoutElement component2 = ((Component)obj2).GetComponent(); if ((Object)(object)component2 != (Object)null) { component2.minWidth = 220f; component2.flexibleWidth = 1f; } return obj2; } private static void MakeReadOnlyField(Transform parent, string label, string value) { //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Unknown result type (might be due to invalid IL or missing references) GameObject obj = Row(parent, "Readonly_" + label, 28f, topAnchored: false); LayoutElement component = ((Component)MakeLabel(obj.transform, label, 13, (TextAnchor)3, new Color(0.9f, 0.82f, 0.62f, 1f))).GetComponent(); if ((Object)(object)component != (Object)null) { component.minWidth = 110f; } MakeLabel(obj.transform, value ?? "", 13, (TextAnchor)3, Color.white); } private static void MakeIconPreview(Transform parent, RewardLine reward) { //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_0095: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Unknown result type (might be due to invalid IL or missing references) //IL_0113: Unknown result type (might be due to invalid IL or missing references) //IL_00ca: Unknown result type (might be due to invalid IL or missing references) try { GameObject val = Panel(parent, "IconPreview", new Color(0.02f, 0.015f, 0.01f, 0.8f)); LayoutElement obj = val.AddComponent(); obj.minWidth = 52f; obj.minHeight = 52f; obj.preferredWidth = 52f; obj.preferredHeight = 52f; Image component = val.GetComponent(); Sprite val2 = (component.sprite = RewardIcon(reward)); component.preserveAspect = true; ((Graphic)component).color = (Color)(((Object)(object)val2 != (Object)null) ? Color.white : new Color(0.12f, 0.08f, 0.045f, 0.95f)); if ((Object)(object)val2 == (Object)null) { Stretch(((Component)MakeLabel(val.transform, "no icon", 10, (TextAnchor)4, new Color(0.9f, 0.82f, 0.62f, 1f))).GetComponent()); } } catch (Exception ex) { LogsModule.Log("Admin Daily icon preview failed: " + ex.Message); try { LayoutElement component2 = ((Component)MakeLabel(parent, "Icon Preview: unavailable", 12, (TextAnchor)3, Color.yellow)).GetComponent(); if ((Object)(object)component2 != (Object)null) { component2.minHeight = 28f; } } catch { } } } private static string RewardDisplayName(RewardLine reward) { if (reward == null || string.IsNullOrWhiteSpace(reward.Prefab)) { return "No reward selected"; } try { GameObject val = (((Object)(object)ObjectDB.instance != (Object)null) ? ObjectDB.instance.GetItemPrefab(reward.Prefab) : null); val = val ?? (((Object)(object)ZNetScene.instance != (Object)null) ? ZNetScene.instance.GetPrefab(reward.Prefab) : null); ItemDrop val2 = (((Object)(object)val != (Object)null) ? val.GetComponent() : null); if ((Object)(object)val2 != (Object)null && val2.m_itemData != null && val2.m_itemData.m_shared != null && !string.IsNullOrWhiteSpace(val2.m_itemData.m_shared.m_name)) { return (Localization.instance != null) ? Localization.instance.Localize(val2.m_itemData.m_shared.m_name) : val2.m_itemData.m_shared.m_name; } } catch { } return reward.Prefab; } private static Sprite RewardIcon(RewardLine reward) { try { GameObject val = ((reward != null && (Object)(object)ObjectDB.instance != (Object)null) ? ObjectDB.instance.GetItemPrefab(reward.Prefab) : null); val = val ?? ((reward != null && (Object)(object)ZNetScene.instance != (Object)null) ? ZNetScene.instance.GetPrefab(reward.Prefab) : null); ItemDrop val2 = (((Object)(object)val != (Object)null) ? val.GetComponent() : null); if ((Object)(object)val2 != (Object)null && val2.m_itemData != null && val2.m_itemData.m_shared != null && val2.m_itemData.m_shared.m_icons != null && val2.m_itemData.m_shared.m_icons.Length != 0) { return val2.m_itemData.m_shared.m_icons[0]; } } catch { } return null; } private static string RewardPreviewReadable(RewardLine reward) { if (reward == null) { return "No reward selected"; } return "Prefab " + reward.Prefab + ", Amount " + reward.Amount + ", Quality " + reward.Quality + ", Variant " + reward.Variant; } private static GameObject Form(Transform parent, float x0, float y0, float x1, float y1) { //IL_001a: 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_003b: 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) //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_0095: Unknown result type (might be due to invalid IL or missing references) //IL_009f: Expected O, but got Unknown GameObject obj = Panel(parent, "Form", new Color(0.04f, 0.025f, 0.015f, 0.65f)); RectTransform component = obj.GetComponent(); component.anchorMin = new Vector2(x0, y0); component.anchorMax = new Vector2(x1, y1); component.offsetMin = new Vector2(0f, 0f); component.offsetMax = new Vector2(0f, -40f); VerticalLayoutGroup obj2 = obj.AddComponent(); ((HorizontalOrVerticalLayoutGroup)obj2).childControlHeight = false; ((HorizontalOrVerticalLayoutGroup)obj2).childForceExpandHeight = false; ((HorizontalOrVerticalLayoutGroup)obj2).spacing = 6f; ((LayoutGroup)obj2).padding = new RectOffset(10, 10, 10, 10); return obj; } private static void TextList(Transform parent, IEnumerable rows, int size) { ScrollAreaInto(Form(parent, 0f, 0f, 1f, 0.88f).transform, "TextList", rows, size); } private static void ScrollAreaInto(Transform parent, string name, IEnumerable rows, int size) { //IL_0034: Unknown result type (might be due to invalid IL or missing references) GameObject val = ScrollArea(parent, name); foreach (string item in (rows ?? Enumerable.Empty()).Take(200)) { MakeLabel(val.transform, item, size, (TextAnchor)3, Color.white); } } private static GameObject ScrollArea(Transform parent, string name) { //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_00a3: Unknown result type (might be due to invalid IL or missing references) //IL_00bf: 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_00e9: Unknown result type (might be due to invalid IL or missing references) //IL_00fe: Unknown result type (might be due to invalid IL or missing references) //IL_0113: Unknown result type (might be due to invalid IL or missing references) GameObject obj = Panel(parent, name + "Viewport", new Color(0f, 0f, 0f, 0.12f)); RectTransform component = obj.GetComponent(); LayoutElement obj2 = obj.AddComponent(); obj2.minHeight = 120f; obj2.preferredHeight = 260f; obj2.flexibleHeight = 1f; obj.AddComponent().showMaskGraphic = false; ScrollRect val = obj.AddComponent(); val.horizontal = false; val.vertical = true; val.movementType = (MovementType)2; GameObject obj3 = Panel(obj.transform, name + "Content", new Color(0f, 0f, 0f, 0f)); RectTransform component2 = obj3.GetComponent(); component2.anchorMin = new Vector2(0f, 1f); component2.anchorMax = new Vector2(1f, 1f); component2.pivot = new Vector2(0.5f, 1f); component2.offsetMin = new Vector2(0f, 0f); component2.offsetMax = new Vector2(0f, 0f); VerticalLayoutGroup obj4 = obj3.AddComponent(); ((HorizontalOrVerticalLayoutGroup)obj4).childControlHeight = false; ((HorizontalOrVerticalLayoutGroup)obj4).childForceExpandHeight = false; ((HorizontalOrVerticalLayoutGroup)obj4).spacing = 3f; obj3.AddComponent().verticalFit = (FitMode)2; val.viewport = component; val.content = component2; return obj3; } private static GameObject Panel(Transform parent, string name, Color color) { //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_0040: Expected O, but got Unknown GameObject val = new GameObject(name, new Type[2] { typeof(RectTransform), typeof(Image) }); val.transform.SetParent(parent, false); ((Graphic)val.GetComponent()).color = color; return val; } private static GameObject NavGrid(Transform parent, string name, float height) { //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_0086: Unknown result type (might be due to invalid IL or missing references) //IL_009b: Unknown result type (might be due to invalid IL or missing references) //IL_00be: Unknown result type (might be due to invalid IL or missing references) //IL_00c8: Expected O, but got Unknown GameObject obj = Panel(parent, name, new Color(0f, 0f, 0f, 0f)); RectTransform component = obj.GetComponent(); component.anchorMin = new Vector2(0f, 1f); component.anchorMax = new Vector2(1f, 1f); component.pivot = new Vector2(0.5f, 1f); component.sizeDelta = new Vector2(0f, height); GridLayoutGroup obj2 = obj.AddComponent(); obj2.cellSize = new Vector2(128f, 32f); obj2.spacing = new Vector2(6f, 6f); obj2.constraint = (Constraint)1; obj2.constraintCount = 4; ((LayoutGroup)obj2).childAlignment = (TextAnchor)0; ((LayoutGroup)obj2).padding = new RectOffset(8, 8, 4, 4); return obj; } private static GameObject Row(Transform parent, string name, float height, bool topAnchored) { //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_0070: 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_004a: 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) GameObject obj = Panel(parent, name, new Color(0f, 0f, 0f, 0f)); RectTransform component = obj.GetComponent(); if (topAnchored) { component.anchorMin = new Vector2(0f, 1f); component.anchorMax = new Vector2(1f, 1f); component.pivot = new Vector2(0.5f, 1f); } component.sizeDelta = new Vector2(0f, height); HorizontalLayoutGroup obj2 = obj.AddComponent(); ((HorizontalOrVerticalLayoutGroup)obj2).childControlWidth = true; ((HorizontalOrVerticalLayoutGroup)obj2).childForceExpandWidth = true; ((HorizontalOrVerticalLayoutGroup)obj2).spacing = 5f; return obj; } private static Text MakeLabel(Transform parent, string text, int size, TextAnchor anchor, Color color) { //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Expected O, but got Unknown //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Unknown result type (might be due to invalid IL or missing references) GameObject val = new GameObject("Text", new Type[2] { typeof(RectTransform), typeof(Text) }); val.transform.SetParent(parent, false); Text component = val.GetComponent(); component.font = font; component.fontSize = size; component.alignment = anchor; ((Graphic)component).color = color; component.text = text; val.AddComponent().minHeight = Mathf.Max(22f, (float)size + 8f); return component; } private static Button MakeButton(Transform parent, string text, Color color, UnityAction action) { //IL_001b: 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) GameObject obj = Panel(parent, "Button_" + text.Replace(" ", "_"), color); Button val = obj.AddComponent