Please disclose if your mod was created primarily using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of RPGStatusEffects v1.0.2
plugins/RpgStatusEffects.dll
Decompiled 5 months agousing System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.IO; using System.IO.Compression; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Serialization; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using BepInEx; using BepInEx.Configuration; using HarmonyLib; using Microsoft.CodeAnalysis; using UnityEngine; using UnityEngine.SceneManagement; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: AssemblyTitle("RpgStatusEffects")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("RpgStatusEffects")] [assembly: AssemblyCopyright("Copyright © 2025")] [assembly: AssemblyTrademark("")] [assembly: ComVisible(false)] [assembly: Guid("f0207a1b-c30c-4443-9d71-04c8e6c57b88")] [assembly: AssemblyFileVersion("1.0.0.0")] [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] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.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 RPGStatusEffects { [BepInPlugin("com.Fire.rpgstatuseffects", "RPGStatusEffects", "1.0.1")] public class RPGStatusEffects : BaseUnityPlugin { [HarmonyPatch(typeof(ObjectDB), "Awake")] public static class ObjectDB_Awake_Path { public static void Postfix() { if (IsObjectDBValid()) { AddItems(itemPrefabs); Instance.SetupStatusEffects(); RecipeManager.SetupRecipe(); } } } [HarmonyPatch(typeof(ObjectDB), "CopyOtherDB")] public static class Object_CopyOtherDB_Path { public static void Postfix() { if (!IsObjectDBValid()) { if (Instance.configVerboseLogging.Value) { Debug.LogWarning((object)"RPGStatusEffects: ObjectDB not valid in CopyOtherDB, skipping item addition."); } } else { AddItems(itemPrefabs); Instance.SetupStatusEffects(); } } } [HarmonyPatch(typeof(ZNetScene), "Awake")] public static class ZNetScene_Awake_Path { public static void Prefix(ZNetScene __instance) { if ((Object)(object)__instance == (Object)null) { if (Instance.configVerboseLogging.Value) { Debug.LogWarning((object)"RPGStatusEffects: No ZNetScene found"); } } else { AddPrefabsToZNetScene(__instance); } } } [HarmonyPatch(typeof(MonsterAI), "UpdateAI")] public static class TauntAIUpdatePatch { private static readonly MethodInfo setAlertedMethod = typeof(MonsterAI).GetMethod("SetAlerted", BindingFlags.Instance | BindingFlags.NonPublic); public static void Postfix(MonsterAI __instance, float dt) { if ((Object)(object)__instance == (Object)null) { return; } Character component = ((Component)__instance).GetComponent<Character>(); if ((Object)(object)component == (Object)null || component.IsPlayer()) { return; } SEMan sEMan = component.GetSEMan(); if (sEMan == null) { return; } int stableHashCode = StringExtensionMethods.GetStableHashCode("Taunted"); TauntEffect tauntEffect = sEMan.GetStatusEffect(stableHashCode) as TauntEffect; if ((Object)(object)tauntEffect != (Object)null && (Object)(object)tauntEffect.Taunter != (Object)null && ((StatusEffect)tauntEffect).m_ttl > 0f) { typeof(MonsterAI).GetField("m_targetCreature", BindingFlags.Instance | BindingFlags.NonPublic)?.SetValue(__instance, tauntEffect.Taunter); FieldInfo field = typeof(MonsterAI).GetField("m_fleeIfHurtWhenTargetCantBeReached", BindingFlags.Instance | BindingFlags.NonPublic); FieldInfo field2 = typeof(MonsterAI).GetField("m_fleeIfLowHealth", BindingFlags.Instance | BindingFlags.NonPublic); FieldInfo field3 = typeof(MonsterAI).GetField("m_enableHuntPlayer", BindingFlags.Instance | BindingFlags.NonPublic); if (!originalHuntStates.ContainsKey(component)) { bool flag = field != null && (bool)field.GetValue(__instance); float num = ((field2 != null) ? ((float)field2.GetValue(__instance)) : 0f); bool flag2 = field3 != null && (bool)field3.GetValue(__instance); originalHuntStates[component] = (flag, num > 0f, flag2); if (Instance.configVerboseLogging.Value) { Debug.Log((object)string.Format("{0}: Stored original states for {1}: fleeIfHurt={2}, fleeIfLowHealth={3}, enableHuntPlayer={4}.", "RPGStatusEffects", ((Object)component).name, flag, num > 0f, flag2)); if (field != null) { Debug.Log((object)("RPGStatusEffects: Set fleeIfHurtWhenTargetCantBeReached=false for " + ((Object)component).name + " during taunt.")); } if (field2 != null) { Debug.Log((object)("RPGStatusEffects: Set fleeIfLowHealth=0 for " + ((Object)component).name + " during taunt.")); } if (field3 != null) { Debug.Log((object)("RPGStatusEffects: Set enableHuntPlayer=true for " + ((Object)component).name + " during taunt.")); } if (setAlertedMethod != null) { Debug.Log((object)("RPGStatusEffects: Called SetAlerted(true) for " + ((Object)component).name + " during taunt.")); } Debug.Log((object)string.Format("{0}: Taunt locked enemy {1} to player (remaining: {2:F1}s).", "RPGStatusEffects", ((Object)component).name, ((StatusEffect)tauntEffect).m_ttl)); } lastTauntLogTimes[component] = ((StatusEffect)tauntEffect).m_ttl; } if (field != null) { field.SetValue(__instance, false); } if (field2 != null) { field2.SetValue(__instance, 0f); } if (field3 != null) { field3.SetValue(__instance, true); } if (setAlertedMethod != null) { setAlertedMethod.Invoke(__instance, new object[1] { true }); } } else { if (!lastTauntLogTimes.Remove(component)) { return; } if (originalHuntStates.TryGetValue(component, out (bool, bool, bool) value)) { FieldInfo field4 = typeof(MonsterAI).GetField("m_fleeIfHurtWhenTargetCantBeReached", BindingFlags.Instance | BindingFlags.NonPublic); FieldInfo field5 = typeof(MonsterAI).GetField("m_fleeIfLowHealth", BindingFlags.Instance | BindingFlags.NonPublic); FieldInfo field6 = typeof(MonsterAI).GetField("m_enableHuntPlayer", BindingFlags.Instance | BindingFlags.NonPublic); if (field4 != null) { field4.SetValue(__instance, value.Item1); if (Instance.configVerboseLogging.Value) { Debug.Log((object)string.Format("{0}: Restored fleeIfHurtWhenTargetCantBeReached={1} for {2}.", "RPGStatusEffects", value.Item1, ((Object)component).name)); } } if (field5 != null) { field5.SetValue(__instance, value.Item2 ? 0.2f : 0f); if (Instance.configVerboseLogging.Value) { Debug.Log((object)string.Format("{0}: Restored fleeIfLowHealth={1} for {2}.", "RPGStatusEffects", value.Item2 ? 0.2f : 0f, ((Object)component).name)); } } if (field6 != null) { field6.SetValue(__instance, value.Item3); if (Instance.configVerboseLogging.Value) { Debug.Log((object)string.Format("{0}: Restored enableHuntPlayer={1} for {2}.", "RPGStatusEffects", value.Item3, ((Object)component).name)); } } originalHuntStates.Remove(component); } if (Instance.configVerboseLogging.Value) { Debug.Log((object)("RPGStatusEffects: Taunt ended on " + ((Object)component).name + ".")); } } } } [HarmonyPatch(typeof(Character), "Damage")] public static class SetTauntOnDamagePatch { public static void Prefix(Character __instance, ref HitData hit) { //IL_0035: Unknown result type (might be due to invalid IL or missing references) if (hit == null || ((ZDOID)(ref hit.m_attacker)).IsNone() || __instance.IsPlayer() || hit.m_statusEffectHash != StringExtensionMethods.GetStableHashCode("Taunted")) { return; } GameObject obj = ZNetScene.instance.FindInstance(hit.m_attacker); Character val = ((obj != null) ? obj.GetComponent<Character>() : null); if ((Object)(object)val == (Object)null) { return; } SEMan sEMan = __instance.GetSEMan(); if (sEMan == null) { return; } TauntEffect tauntEffect = sEMan.GetStatusEffect(StringExtensionMethods.GetStableHashCode("Taunted")) as TauntEffect; if ((Object)(object)tauntEffect == (Object)null) { tauntEffect = sEMan.AddStatusEffect(StringExtensionMethods.GetStableHashCode("Taunted"), true, 0, 0f) as TauntEffect; } if (!((Object)(object)tauntEffect != (Object)null)) { return; } tauntEffect.Taunter = val; if (Instance.configVerboseLogging.Value) { Debug.Log((object)("RPGStatusEffects: Applied taunt from player to " + ((Object)__instance).name + ".")); } if (!val.IsPlayer()) { return; } SEMan sEMan2 = val.GetSEMan(); TauntingEffect tauntingEffect = StatusEffectManager.GetEffect("Taunting") as TauntingEffect; if ((Object)(object)tauntingEffect != (Object)null) { tauntingEffect.Duration = tauntEffect.Duration; sEMan2.AddStatusEffect((StatusEffect)(object)tauntingEffect, true, 0, 0f); if (Instance.configVerboseLogging.Value) { Debug.Log((object)string.Format("{0}: Applied Taunting effect to player {1} for {2}s.", "RPGStatusEffects", ((Object)val).name, tauntingEffect.Duration)); } } } } [CompilerGenerated] private sealed class <InitializeStatusEffects>d__24 : IEnumerator<object>, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; public RPGStatusEffects <>4__this; private int <maxAttempts>5__2; private int <attempts>5__3; private float <approximateTimeSpent>5__4; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <InitializeStatusEffects>d__24(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { //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_00ef: Unknown result type (might be due to invalid IL or missing references) //IL_00f9: Expected O, but got Unknown int num = <>1__state; RPGStatusEffects rPGStatusEffects = <>4__this; switch (num) { default: return false; case 0: { <>1__state = -1; Scene activeScene = SceneManager.GetActiveScene(); if (((Scene)(ref activeScene)).name == "start") { if (rPGStatusEffects.configVerboseLogging.Value) { Debug.Log((object)"RPGStatusEffects: Main menu detected, skipping initialization."); } return false; } <maxAttempts>5__2 = 100; <attempts>5__3 = 0; <approximateTimeSpent>5__4 = 0f; break; } case 1: <>1__state = -1; <approximateTimeSpent>5__4 += 0.1f; break; } if (!IsObjectDBValid() || (Object)(object)ZNetScene.instance == (Object)null || ZNetScene.instance.m_prefabs == null || ZNetScene.instance.m_prefabs.Count == 0) { if (rPGStatusEffects.configVerboseLogging.Value) { Debug.Log((object)string.Format("{0}: Waiting for ObjectDB and ZNetScene (attempt {1}/{2})...", "RPGStatusEffects", <attempts>5__3 + 1, <maxAttempts>5__2)); } <attempts>5__3++; if (<approximateTimeSpent>5__4 >= 10f) { Debug.LogError((object)string.Format("{0}: ObjectDB and ZNetScene failed to initialize after {1} attempts.", "RPGStatusEffects", <maxAttempts>5__2)); return false; } <>2__current = (object)new WaitForSeconds(0.1f); <>1__state = 1; return true; } rPGStatusEffects.ValidateConfigs(); rPGStatusEffects.SetupStatusEffects(); RecipeManager.SetupRecipe(); rPGStatusEffects.isInitialized = true; if (rPGStatusEffects.configVerboseLogging.Value) { Debug.Log((object)"RPGStatusEffects: Status effects and recipe initialized."); } return false; } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } public static RPGStatusEffects Instance; private readonly Harmony harmony = new Harmony("com.Fire.rpgstatuseffects"); public const string PluginGUID = "com.Fire.rpgstatuseffects"; public const string PluginName = "RPGStatusEffects"; public const string PluginVersion = "1.0.1"; public ConfigSync configSync; public SyncedConfigEntry<bool> configVerboseLogging; public SyncedConfigEntry<float> configPurityDuration; public SyncedConfigEntry<float> configTauntDuration; public SyncedConfigEntry<string> configTauntHammerRecipe; private bool isInitialized; private bool isShuttingDown; public static AssetBundle assetBundle; public static readonly List<GameObject> itemPrefabs = new List<GameObject>(); public static readonly FieldInfo knownRecipesField = typeof(Player).GetField("m_knownRecipes", BindingFlags.Instance | BindingFlags.NonPublic); private static readonly Dictionary<Character, float> lastTauntLogTimes = new Dictionary<Character, float>(); private static readonly Dictionary<Character, (bool fleeIfHurt, bool fleeIfLowHealth, bool enableHuntPlayer)> originalHuntStates = new Dictionary<Character, (bool, bool, bool)>(); private void Awake() { Instance = this; configSync = new ConfigSync("com.Fire.rpgstatuseffects") { DisplayName = "RPGStatusEffects", CurrentVersion = "1.0.1", MinimumRequiredVersion = "1.0.1" }; configSync.lockedConfigChanged += delegate { if (!isShuttingDown && isInitialized && IsObjectDBValid()) { ValidateConfigs(); SetupStatusEffects(); RecipeManager.SetupRecipe(); if (configVerboseLogging.Value) { Debug.Log((object)"RPGStatusEffects: Config sync triggered status effect and recipe update."); } } }; configVerboseLogging = configSync.AddConfigEntry<bool>(((BaseUnityPlugin)this).Config.Bind<bool>("General", "VerboseLogging", false, "Enable detailed debug logs.")); configPurityDuration = configSync.AddConfigEntry<float>(((BaseUnityPlugin)this).Config.Bind<float>("StatusEffects", "PurityDuration", 10f, "Duration of the Purity status effect in seconds.")); configTauntDuration = configSync.AddConfigEntry<float>(((BaseUnityPlugin)this).Config.Bind<float>("StatusEffects", "TauntDuration", 15f, "Duration of the Taunt effect in seconds.")); configTauntHammerRecipe = configSync.AddConfigEntry<string>(((BaseUnityPlugin)this).Config.Bind<string>("Item_Recipe_TauntHammer", "Recipe", "Wood,10,5,LeatherScraps,5,2,SwordCheat,1,0", "Recipe for TauntHammer_vad (format: ItemName,Amount,AmountPerLevel,...)")); ValidateConfigs(); loadAssets(); harmony.PatchAll(); RegisterConsoleCommands(); ((MonoBehaviour)this).StartCoroutine(InitializeStatusEffects()); if (configVerboseLogging.Value) { Debug.Log((object)"RPGStatusEffects: Initialized version 1.0.1."); } } private void loadAssets() { try { assetBundle = GetAssetBundleFromResources("verdantsascent"); if ((Object)(object)assetBundle == (Object)null) { Debug.LogError((object)"RPGStatusEffects: Failed to load asset bundle!"); return; } if (configVerboseLogging.Value) { string[] allAssetNames = assetBundle.GetAllAssetNames(); Debug.Log((object)("RPGStatusEffects: Available assets in bundle: " + string.Join(", ", allAssetNames))); } LoadItems("Assets/Custom/VAitems/"); } catch (Exception ex) { Debug.LogError((object)("RPGStatusEffects: Error loading assets: " + ex.Message + "\n" + ex.StackTrace)); } } private AssetBundle GetAssetBundleFromResources(string filename) { Assembly executingAssembly = Assembly.GetExecutingAssembly(); string text = executingAssembly.GetManifestResourceNames().SingleOrDefault((string str) => str.EndsWith(filename, StringComparison.OrdinalIgnoreCase)); if (text == null) { Debug.LogError((object)("RPGStatusEffects: No resource found ending with " + filename + ".")); return null; } if (configVerboseLogging.Value) { Debug.Log((object)("RPGStatusEffects: Loading asset bundle from resource: " + text)); } using Stream stream = executingAssembly.GetManifestResourceStream(text); if (stream == null) { Debug.LogError((object)("RPGStatusEffects: Failed to open stream for resource " + text + ".")); return null; } return AssetBundle.LoadFromStream(stream); } private void LoadItems(string mainPath) { string[] obj = new string[1] { "TauntHammer_vad" }; itemPrefabs.Clear(); string[] array = obj; foreach (string text in array) { string text2 = mainPath + "items/" + text + ".prefab"; AssetBundle obj2 = assetBundle; GameObject val = ((obj2 != null) ? obj2.LoadAsset<GameObject>(text2) : null); if ((Object)(object)val == (Object)null) { if (configVerboseLogging.Value) { Debug.LogWarning((object)("RPGStatusEffects: Could not find prefab: " + text2)); } continue; } ItemDrop component = val.GetComponent<ItemDrop>(); if ((Object)(object)component == (Object)null) { if (configVerboseLogging.Value) { Debug.LogError((object)("RPGStatusEffects: " + text + " - ItemDrop component missing!")); } continue; } val.SetActive(true); itemPrefabs.Add(val); if (configVerboseLogging.Value) { Debug.Log((object)("RPGStatusEffects: Loaded prefab: " + text + ", m_dropPrefab: " + (((Object)(object)component.m_itemData.m_dropPrefab != (Object)null) ? ((Object)component.m_itemData.m_dropPrefab).name : "null"))); } } } public static void AddItems(List<GameObject> items) { try { foreach (GameObject item in items) { if ((Object)(object)item == (Object)null) { if (Instance.configVerboseLogging.Value) { Debug.LogWarning((object)"RPGStatusEffects: Null item in list, skipping."); } } else if ((Object)(object)item.GetComponent<ItemDrop>() != (Object)null) { if ((Object)(object)ObjectDB.instance.GetItemPrefab(((Object)item).name) == (Object)null) { ObjectDB.instance.m_items.Add(item); ((Dictionary<int, GameObject>)typeof(ObjectDB).GetField("m_itemByHash", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(ObjectDB.instance))[((Object)item).name.GetHashCode()] = item; if (Instance.configVerboseLogging.Value) { Debug.Log((object)("RPGStatusEffects: Added " + ((Object)item).name + " to ObjectDB.m_items")); } } else if (Instance.configVerboseLogging.Value) { Debug.LogWarning((object)("RPGStatusEffects: " + ((Object)item).name + " already exists in ObjectDB, skipping.")); } } else if (Instance.configVerboseLogging.Value) { Debug.LogError((object)("RPGStatusEffects: " + ((Object)item).name + " - ItemDrop not found on prefab")); } } } catch (Exception ex) { Debug.LogError((object)("RPGStatusEffects: Error adding items to ObjectDB: " + ex.Message)); } } public static void AddPrefabsToZNetScene(ZNetScene zNetScene) { try { foreach (GameObject gm in itemPrefabs) { if ((Object)(object)gm == (Object)null) { if (Instance.configVerboseLogging.Value) { Debug.LogWarning((object)"RPGStatusEffects: Null prefab in itemPrefabs list, skipping."); } } else if ((Object)(object)zNetScene.m_prefabs.Find((GameObject x) => (Object)(object)x != (Object)null && ((Object)x).name == ((Object)gm).name) == (Object)null) { zNetScene.m_prefabs.Add(gm); if (Instance.configVerboseLogging.Value) { Debug.Log((object)("RPGStatusEffects: Added " + ((Object)gm).name + " to ZNetScene.m_prefabs")); } } else if (Instance.configVerboseLogging.Value) { Debug.LogWarning((object)("RPGStatusEffects: Object exists in ZNetScene, skipping: " + ((Object)gm).name)); } } } catch (Exception ex) { Debug.LogError((object)("RPGStatusEffects: Error adding prefabs to ZNetScene: " + ex.Message)); } zNetScene.m_prefabs.RemoveAll((GameObject x) => (Object)(object)x == (Object)null); } private void ValidateConfigs() { List<string> list = configTauntHammerRecipe.Value.Split(new char[1] { ',' }).ToList(); if (list.Count % 3 != 0) { if (configVerboseLogging.Value) { Debug.LogWarning((object)"RPGStatusEffects: Invalid recipe config for TauntHammer_vad - resetting to default."); } configTauntHammerRecipe.Value = configTauntHammerRecipe.DefaultValue.ToString(); } for (int i = 1; i < list.Count; i += 3) { if (!int.TryParse(list[i], out var result) || !int.TryParse(list[i + 1], out result)) { if (configVerboseLogging.Value) { Debug.LogWarning((object)"RPGStatusEffects: Invalid amounts in recipe config for TauntHammer_vad - resetting to default."); } configTauntHammerRecipe.Value = configTauntHammerRecipe.DefaultValue.ToString(); break; } } } [IteratorStateMachine(typeof(<InitializeStatusEffects>d__24))] private IEnumerator InitializeStatusEffects() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <InitializeStatusEffects>d__24(0) { <>4__this = this }; } public void SetupStatusEffects() { if (!IsObjectDBValid()) { if (configVerboseLogging.Value) { Debug.LogWarning((object)"RPGStatusEffects: Skipping SetupStatusEffects - ObjectDB not valid."); } } else { StatusEffectManager.Initialize(); } } private void RegisterConsoleCommands() { //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Expected O, but got Unknown //IL_001f: Unknown result type (might be due to invalid IL or missing references) new ConsoleCommand("va_status_reload", "Reload RPGStatusEffects configs", (ConsoleEvent)delegate { if (!isShuttingDown) { ((BaseUnityPlugin)this).Config.Reload(); RecipeManager.ClearCache(); ValidateConfigs(); if (IsObjectDBValid()) { SetupStatusEffects(); RecipeManager.SetupRecipe(); if (configVerboseLogging.Value) { Debug.Log((object)"RPGStatusEffects: Configs reloaded and status effects/recipe updated."); } } else if (configVerboseLogging.Value) { Debug.LogWarning((object)"RPGStatusEffects: Cannot reload configs, ObjectDB not valid."); } } }, false, false, false, false, false, (ConsoleOptionsFetcher)null, false, false, false); } private void OnDestroy() { isShuttingDown = true; harmony.UnpatchSelf(); if ((Object)(object)assetBundle != (Object)null) { assetBundle.Unload(true); if (configVerboseLogging.Value) { Debug.Log((object)"RPGStatusEffects: Unloaded asset bundle."); } } if (configVerboseLogging.Value) { Debug.Log((object)"RPGStatusEffects: Unloaded."); } } public static bool IsObjectDBValid() { return (Object)(object)ObjectDB.instance != (Object)null; } } public static class AdminSyncing { [HarmonyPatch(typeof(ZNet), "Awake")] private static class AdminStatusSyncPatch { [CompilerGenerated] private sealed class <>c__DisplayClass1_0 { public SyncedList adminList; public Func<ZNetPeer, bool> <>9__0; internal bool <WatchAdminListChanges>b__0(ZNetPeer p) { return adminList.Contains(p.m_rpc.GetSocket().GetHostName()); } } [CompilerGenerated] private sealed class <WatchAdminListChanges>d__1 : IEnumerator<object>, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; private <>c__DisplayClass1_0 <>8__1; private List<string> <currentList>5__2; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <WatchAdminListChanges>d__1(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>8__1 = null; <currentList>5__2 = null; <>1__state = -2; } private bool MoveNext() { //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Expected O, but got Unknown //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Expected O, but got Unknown int num = <>1__state; if (num != 0) { if (num != 1) { return false; } <>1__state = -1; List<string> list = <>8__1.adminList.GetList(); if (!list.SequenceEqual(<currentList>5__2)) { <currentList>5__2 = new List<string>(list); List<ZNetPeer> peers = ZNet.instance.GetPeers(); List<ZNetPeer> list2 = peers.Where((ZNetPeer p) => <>8__1.adminList.Contains(p.m_rpc.GetSocket().GetHostName())).ToList(); SendAdmin(peers.Except(list2).ToList(), isAdmin: false); SendAdmin(list2, isAdmin: true); } } else { <>1__state = -1; <>8__1 = new <>c__DisplayClass1_0(); <>8__1.adminList = (SyncedList)AccessTools.Field(typeof(ZNet), "m_adminList").GetValue(ZNet.instance); <currentList>5__2 = new List<string>(<>8__1.adminList.GetList()); } <>2__current = (object)new WaitForSeconds(30f); <>1__state = 1; return true; } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } [HarmonyPostfix] [HarmonyPriority(700)] private static void Postfix(ZNet __instance) { isServer = __instance.IsServer(); if (!((Object)(object)RPGStatusEffects.Instance == (Object)null)) { if (isServer) { ZRoutedRpc.instance.Register<ZPackage>("RPGStatusEffects AdminStatusSync", (Action<long, ZPackage>)RPC_AdminStatusSync); } else if (!registeredOnClient) { ZRoutedRpc.instance.Register<ZPackage>("RPGStatusEffects AdminStatusSync", (Action<long, ZPackage>)RPC_AdminStatusSync); registeredOnClient = true; } if (isServer) { ((MonoBehaviour)__instance).StartCoroutine(WatchAdminListChanges()); } } } [IteratorStateMachine(typeof(<WatchAdminListChanges>d__1))] private static IEnumerator WatchAdminListChanges() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <WatchAdminListChanges>d__1(0); } private static void SendAdmin(List<ZNetPeer> peers, bool isAdmin) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Expected O, but got Unknown ZPackage val = new ZPackage(); val.Write(isAdmin); ((MonoBehaviour)ZNet.instance).StartCoroutine(SendZPackage(peers, val)); } } [CompilerGenerated] private sealed class <>c__DisplayClass4_0 { public ZPackage package; internal IEnumerator<bool> <SendZPackage>b__1(ZNetPeer p) { return TellPeerAdminStatus(p, package); } } [CompilerGenerated] private sealed class <SendZPackage>d__4 : IEnumerator<object>, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; public ZPackage package; public List<ZNetPeer> peers; private List<IEnumerator<bool>> <writers>5__2; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <SendZPackage>d__4(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <writers>5__2 = null; <>1__state = -2; } private bool MoveNext() { //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Expected O, but got Unknown switch (<>1__state) { default: return false; case 0: { <>1__state = -1; <>c__DisplayClass4_0 CS$<>8__locals0 = new <>c__DisplayClass4_0 { package = package }; if (!Object.op_Implicit((Object)(object)ZNet.instance)) { return false; } byte[] array = CS$<>8__locals0.package.GetArray(); if (array.Length > 10000) { ZPackage val = new ZPackage(); val.Write(4); using MemoryStream memoryStream = new MemoryStream(); using (DeflateStream deflateStream = new DeflateStream(memoryStream, CompressionLevel.Optimal)) { deflateStream.Write(array, 0, array.Length); } val.Write(memoryStream.ToArray()); CS$<>8__locals0.package = val; } <writers>5__2 = (from p in peers where p.IsReady() select TellPeerAdminStatus(p, CS$<>8__locals0.package)).ToList(); <writers>5__2.RemoveAll((IEnumerator<bool> w) => !w.MoveNext()); break; } case 1: <>1__state = -1; <writers>5__2.RemoveAll((IEnumerator<bool> w) => !w.MoveNext()); break; } if (<writers>5__2.Count > 0) { <>2__current = null; <>1__state = 1; return true; } return false; } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } [CompilerGenerated] private sealed class <TellPeerAdminStatus>d__5 : IEnumerator<bool>, IDisposable, IEnumerator { private int <>1__state; private bool <>2__current; public ZPackage package; public ZNetPeer peer; bool IEnumerator<bool>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <TellPeerAdminStatus>d__5(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Expected O, but got Unknown switch (<>1__state) { default: return false; case 0: <>1__state = -1; if (ZRoutedRpc.instance != null) { ZPackage val = new ZPackage(package.GetArray()); if (isServer) { peer.m_rpc.Invoke("RPGStatusEffects AdminStatusSync", new object[1] { val }); } else { ZRoutedRpc.instance.InvokeRoutedRPC(peer.m_server ? 0 : peer.m_uid, "RPGStatusEffects AdminStatusSync", new object[1] { val }); } } <>2__current = false; <>1__state = 1; return true; case 1: <>1__state = -1; return false; } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } private static bool isServer; internal static bool registeredOnClient; private static void RPC_AdminStatusSync(long sender, ZPackage package) { //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Expected O, but got Unknown //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Expected O, but got Unknown bool lockExempt = false; try { lockExempt = package.ReadBool(); } catch { } if (isServer) { ZNetPeer peer = ZNet.instance.GetPeer(sender); SyncedList val = (SyncedList)AccessTools.Field(typeof(ZNet), "m_adminList").GetValue(ZNet.instance); if (peer != null && val.Contains(peer.m_rpc.GetSocket().GetHostName())) { ZPackage val2 = new ZPackage(); val2.Write(true); peer.m_rpc.Invoke("RPGStatusEffects AdminStatusSync", new object[1] { val2 }); } } else { ConfigSync.lockExempt = lockExempt; RPGStatusEffects.Instance?.SetupStatusEffects(); RecipeManager.SetupRecipe(); } } [IteratorStateMachine(typeof(<SendZPackage>d__4))] internal static IEnumerator SendZPackage(List<ZNetPeer> peers, ZPackage package) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <SendZPackage>d__4(0) { peers = peers, package = package }; } [IteratorStateMachine(typeof(<TellPeerAdminStatus>d__5))] private static IEnumerator<bool> TellPeerAdminStatus(ZNetPeer peer, ZPackage package) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <TellPeerAdminStatus>d__5(0) { peer = peer, package = package }; } } public class ConfigSync { [CompilerGenerated] private sealed class <>c__DisplayClass57_0 { public long target; internal bool <SendZPackage>b__0(ZNetPeer p) { if (target != ZRoutedRpc.Everybody) { return p.m_uid == target; } return true; } } [CompilerGenerated] private sealed class <>c__DisplayClass58_0 { public ConfigSync <>4__this; public ZPackage package; internal IEnumerator <SendZPackage>b__1(ZNetPeer p) { return <>4__this.distributeConfigToPeers(p, package); } } [CompilerGenerated] private sealed class <>c__DisplayClass59_0 { public ZNetPeer peer; public ConfigSync <>4__this; } [CompilerGenerated] private sealed class <SendZPackage>d__57 : IEnumerator<object>, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; public long target; public ConfigSync <>4__this; public ZPackage package; private IEnumerator <enumerator>5__2; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <SendZPackage>d__57(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <enumerator>5__2 = null; <>1__state = -2; } private bool MoveNext() { int num = <>1__state; ConfigSync configSync = <>4__this; switch (num) { default: return false; case 0: { <>1__state = -1; <>c__DisplayClass57_0 CS$<>8__locals0 = new <>c__DisplayClass57_0 { target = target }; if (!Object.op_Implicit((Object)(object)ZNet.instance)) { return false; } List<ZNetPeer> peers = ((List<ZNetPeer>)AccessTools.Field(typeof(ZRoutedRpc), "m_peers").GetValue(ZRoutedRpc.instance)).Where((ZNetPeer p) => CS$<>8__locals0.target == ZRoutedRpc.Everybody || p.m_uid == CS$<>8__locals0.target).ToList(); <enumerator>5__2 = configSync.SendZPackage(peers, package); break; } case 1: <>1__state = -1; break; } if (<enumerator>5__2.MoveNext()) { <>2__current = <enumerator>5__2.Current; <>1__state = 1; return true; } return false; } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } [CompilerGenerated] private sealed class <SendZPackage>d__58 : IEnumerator<object>, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; public ConfigSync <>4__this; public ZPackage package; public List<ZNetPeer> peers; private List<IEnumerator> <writers>5__2; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <SendZPackage>d__58(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <writers>5__2 = null; <>1__state = -2; } private bool MoveNext() { //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Expected O, but got Unknown switch (<>1__state) { default: return false; case 0: { <>1__state = -1; <>c__DisplayClass58_0 CS$<>8__locals0 = new <>c__DisplayClass58_0 { <>4__this = <>4__this, package = package }; if (!Object.op_Implicit((Object)(object)ZNet.instance)) { return false; } byte[] array = CS$<>8__locals0.package.GetArray(); if (array.Length > 10000) { ZPackage val = new ZPackage(); val.Write((byte)4); using MemoryStream memoryStream = new MemoryStream(); using (DeflateStream deflateStream = new DeflateStream(memoryStream, CompressionLevel.Optimal)) { deflateStream.Write(array, 0, array.Length); } val.Write(memoryStream.ToArray()); CS$<>8__locals0.package = val; } <writers>5__2 = (from p in peers where p.IsReady() select CS$<>8__locals0.<>4__this.distributeConfigToPeers(p, CS$<>8__locals0.package)).ToList(); <writers>5__2.RemoveAll((IEnumerator w) => !w.MoveNext()); break; } case 1: <>1__state = -1; <writers>5__2.RemoveAll((IEnumerator w) => !w.MoveNext()); break; } if (<writers>5__2.Any()) { <>2__current = null; <>1__state = 1; return true; } return false; } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } [CompilerGenerated] private sealed class <distributeConfigToPeers>d__59 : IEnumerator<object>, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; public ZNetPeer peer; public ConfigSync <>4__this; public ZPackage package; private <>c__DisplayClass59_0 <>8__1; private byte[] <data>5__2; private int <fragments>5__3; private long <packageId>5__4; private int <i>5__5; private IEnumerator<bool> <>7__wrap5; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <distributeConfigToPeers>d__59(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { switch (<>1__state) { case -3: case 1: try { } finally { <>m__Finally1(); } break; case -4: case 3: try { } finally { <>m__Finally2(); } break; } <>8__1 = null; <data>5__2 = null; <>7__wrap5 = null; <>1__state = -2; } private bool MoveNext() { //IL_0137: Unknown result type (might be due to invalid IL or missing references) //IL_013d: Expected O, but got Unknown try { ZPackage val; switch (<>1__state) { default: return false; case 0: <>1__state = -1; <>8__1 = new <>c__DisplayClass59_0(); <>8__1.peer = peer; <>8__1.<>4__this = <>4__this; <data>5__2 = package.GetArray(); if (<data>5__2.Length > 250000) { <fragments>5__3 = (<data>5__2.Length + 249999) / 250000; <packageId>5__4 = ++packageCounter; <i>5__5 = 0; goto IL_01e3; } <>7__wrap5 = waitForQueue().GetEnumerator(); <>1__state = -4; goto IL_0243; case 1: <>1__state = -3; goto IL_0103; case 2: <>1__state = -1; goto IL_01d1; case 3: { <>1__state = -4; goto IL_0243; } IL_0243: if (<>7__wrap5.MoveNext()) { bool current = <>7__wrap5.Current; <>2__current = current; <>1__state = 3; return true; } <>m__Finally2(); <>7__wrap5 = null; SendPackage(package); break; IL_01e3: if (<i>5__5 < <fragments>5__3) { <>7__wrap5 = waitForQueue().GetEnumerator(); <>1__state = -3; goto IL_0103; } break; IL_01d1: <i>5__5++; goto IL_01e3; IL_0103: if (<>7__wrap5.MoveNext()) { bool current2 = <>7__wrap5.Current; <>2__current = current2; <>1__state = 1; return true; } <>m__Finally1(); <>7__wrap5 = null; if (!<>8__1.peer.m_socket.IsConnected()) { break; } val = new ZPackage(); val.Write((byte)2); val.Write(<packageId>5__4); val.Write(<i>5__5); val.Write(<fragments>5__3); val.Write(<data>5__2.Skip(250000 * <i>5__5).Take(250000).ToArray()); SendPackage(val); if (<i>5__5 < <fragments>5__3 - 1) { <>2__current = true; <>1__state = 2; return true; } goto IL_01d1; } return false; } catch { //try-fault ((IDisposable)this).Dispose(); throw; } void SendPackage(ZPackage pkg) { if (isServer) { ((<>c__DisplayClass59_0)this).peer.m_rpc.Invoke(((<>c__DisplayClass59_0)this).<>4__this.Name + " ConfigSync", new object[1] { pkg }); } else { ZRoutedRpc.instance.InvokeRoutedRPC(((<>c__DisplayClass59_0)this).peer.m_server ? 0 : ((<>c__DisplayClass59_0)this).peer.m_uid, ((<>c__DisplayClass59_0)this).<>4__this.Name + " ConfigSync", new object[1] { pkg }); } } [IteratorStateMachine(typeof(<>c__DisplayClass59_0.<<distributeConfigToPeers>g__waitForQueue|0>d))] IEnumerable<bool> waitForQueue() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <>c__DisplayClass59_0.<<distributeConfigToPeers>g__waitForQueue|0>d(-2) { <>4__this = this }; } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } private void <>m__Finally1() { <>1__state = -1; if (<>7__wrap5 != null) { <>7__wrap5.Dispose(); } } private void <>m__Finally2() { <>1__state = -1; if (<>7__wrap5 != null) { <>7__wrap5.Dispose(); } } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } public static bool ProcessingServerUpdate = false; public readonly string Name; public string DisplayName; public string CurrentVersion; public string MinimumRequiredVersion; public bool ModRequired; private bool? forceConfigLocking; private bool isSourceOfTruth = true; public static HashSet<ConfigSync> configSyncs = new HashSet<ConfigSync>(); public HashSet<OwnConfigEntryBase> allConfigs = new HashSet<OwnConfigEntryBase>(); public HashSet<CustomSyncedValueBase> allCustomValues = new HashSet<CustomSyncedValueBase>(); public static bool isServer; public static bool lockExempt = false; private OwnConfigEntryBase lockedConfig; private const byte PARTIAL_CONFIGS = 1; private const byte FRAGMENTED_CONFIG = 2; private const byte COMPRESSED_CONFIG = 4; private readonly Dictionary<string, SortedDictionary<int, byte[]>> configValueCache = new Dictionary<string, SortedDictionary<int, byte[]>>(); private readonly List<KeyValuePair<long, string>> cacheExpirations = new List<KeyValuePair<long, string>>(); private static long packageCounter = 0L; private bool initialSyncDone; public bool IsLocked { get { bool? flag = forceConfigLocking; bool num; if (!flag.HasValue) { OwnConfigEntryBase ownConfigEntryBase = lockedConfig; if (!(((ownConfigEntryBase != null) ? ownConfigEntryBase.BaseConfig.BoxedValue : null) is IConvertible convertible)) { goto IL_0055; } num = convertible.ToInt32(CultureInfo.InvariantCulture) != 0; } else { num = flag.GetValueOrDefault(); } if (num) { return !lockExempt; } goto IL_0055; IL_0055: return false; } set { forceConfigLocking = value; } } public bool IsAdmin { get { if (!lockExempt) { return isSourceOfTruth; } return true; } } public bool IsSourceOfTruth { get { return isSourceOfTruth; } internal set { if (value != isSourceOfTruth) { isSourceOfTruth = value; this.SourceOfTruthChanged?.Invoke(value); } } } public bool InitialSyncDone { get { return initialSyncDone; } internal set { initialSyncDone = value; } } public event Action<bool> SourceOfTruthChanged; public event Action lockedConfigChanged; public ConfigSync(string name) { Name = name; DisplayName = name; configSyncs.Add(this); } public SyncedConfigEntry<T> AddConfigEntry<T>(ConfigEntry<T> configEntry) { SyncedConfigEntry<T> syncedEntry = (configData((ConfigEntryBase)(object)configEntry) as SyncedConfigEntry<T>) ?? new SyncedConfigEntry<T>(configEntry); object[] first = ((ConfigEntryBase)configEntry).Description.Tags?.ToArray() ?? new object[1] { new ConfigurationManagerAttributes() }; first = first.Concat(new object[1] { syncedEntry }).ToArray(); AccessTools.Field(typeof(ConfigDescription), "<Tags>k__BackingField").SetValue(((ConfigEntryBase)configEntry).Description, first); configEntry.SettingChanged += delegate { if (!ProcessingServerUpdate && syncedEntry.SynchronizedConfig) { Broadcast(ZRoutedRpc.Everybody, (ConfigEntryBase)(object)configEntry); } }; allConfigs.Add(syncedEntry); return syncedEntry; } public SyncedConfigEntry<T> AddLockingConfigEntry<T>(ConfigEntry<T> lockingConfig) where T : IConvertible { if (lockedConfig != null) { throw new Exception("Cannot initialize locking ConfigEntry twice"); } lockedConfig = AddConfigEntry<T>(lockingConfig); lockingConfig.SettingChanged += delegate { this.lockedConfigChanged?.Invoke(); }; return (SyncedConfigEntry<T>)lockedConfig; } internal void AddCustomValue(CustomSyncedValueBase customValue) { if (allCustomValues.Any((CustomSyncedValueBase v) => v.Identifier == customValue.Identifier) || customValue.Identifier == "serverversion") { throw new Exception("Cannot have multiple settings with the same name or with a reserved name (serverversion)"); } allCustomValues.Add(customValue); allCustomValues = new HashSet<CustomSyncedValueBase>(allCustomValues.OrderByDescending((CustomSyncedValueBase v) => v.Priority)); customValue.ValueChanged += delegate { if (!ProcessingServerUpdate) { Broadcast(ZRoutedRpc.Everybody, customValue); } }; } private void Broadcast(long target, ConfigEntryBase config) { if (!IsLocked || IsAdmin) { ZPackage package = ConfigsToPackage((IEnumerable<ConfigEntryBase>)(object)new ConfigEntryBase[1] { config }); ZNet instance = ZNet.instance; if (instance != null) { ((MonoBehaviour)instance).StartCoroutine(SendZPackage(target, package)); } } } private void Broadcast(long target, CustomSyncedValueBase customValue) { if (!IsLocked || IsAdmin) { ZPackage package = ConfigsToPackage(null, new CustomSyncedValueBase[1] { customValue }); ZNet instance = ZNet.instance; if (instance != null) { ((MonoBehaviour)instance).StartCoroutine(SendZPackage(target, package)); } } } internal void RPC_FromServerConfigSync(ZRpc rpc, ZPackage package) { lockedConfigChanged += serverLockedSettingChanged; IsSourceOfTruth = false; if (HandleConfigSyncRPC(0L, package, clientUpdate: false)) { InitialSyncDone = true; } } internal void RPC_FromOtherClientConfigSync(long sender, ZPackage package) { HandleConfigSyncRPC(sender, package, clientUpdate: true); } private bool HandleConfigSyncRPC(long sender, ZPackage package, bool clientUpdate) { //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Expected O, but got Unknown //IL_016c: Unknown result type (might be due to invalid IL or missing references) //IL_0173: Expected O, but got Unknown //IL_01c1: Unknown result type (might be due to invalid IL or missing references) //IL_01c8: 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; SyncedList val = (SyncedList)AccessTools.Field(typeof(ZNet), "m_adminList").GetValue(ZNet.instance); if (text != null && !val.Contains(text)) { return false; } } cacheExpirations.RemoveAll((KeyValuePair<long, string> kv) => kv.Key < DateTimeOffset.Now.Ticks && configValueCache.Remove(kv.Value)); byte b = package.ReadByte(); if ((b & 2u) != 0) { long num = package.ReadLong(); string text2 = sender.ToString() + num; if (!configValueCache.TryGetValue(text2, out var value)) { value = new SortedDictionary<int, byte[]>(); configValueCache[text2] = value; cacheExpirations.Add(new KeyValuePair<long, string>(DateTimeOffset.Now.Ticks + 600000000, text2)); } int key = package.ReadInt(); int num2 = package.ReadInt(); value[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 & 4u) != 0) { using MemoryStream stream = new MemoryStream(package.ReadByteArray()); using 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<OwnConfigEntryBase, object> 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; val2.Save(); } foreach (KeyValuePair<CustomSyncedValueBase, object> customValue in parsedConfigs.customValues) { if (!isServer && customValue.Key.LocalBaseValue == null) { customValue.Key.LocalBaseValue = customValue.Key.BoxedValue; } customValue.Key.BoxedValue = customValue.Value; } Debug.Log((object)string.Format("[RPGStatusEffects] Received {0} configs and {1} custom values from {2} for mod {3}", parsedConfigs.configValues.Count, parsedConfigs.customValues.Count, (isServer || clientUpdate) ? $"client {sender}" : "server", DisplayName ?? Name)); if (!isServer) { serverLockedSettingChanged(); } return true; } finally { ProcessingServerUpdate = false; } } private void serverLockedSettingChanged() { foreach (OwnConfigEntryBase allConfig in allConfigs) { configAttribute<ConfigurationManagerAttributes>(allConfig.BaseConfig).ReadOnly = !isWritableConfig(allConfig); } } internal static bool isWritableConfig(OwnConfigEntryBase config) { ConfigSync configSync = configSyncs.FirstOrDefault((ConfigSync cs) => cs.allConfigs.Contains(config)); if (configSync == null || configSync.IsSourceOfTruth || !config.SynchronizedConfig || config.LocalBaseValue == null) { return true; } if (configSync.IsLocked && config == configSync.lockedConfig) { return lockExempt; } return true; } internal void resetConfigsFromServer() { ConfigFile val = null; bool saveOnConfigSet = false; foreach (OwnConfigEntryBase item in allConfigs.Where((OwnConfigEntryBase c) => c.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; val.Save(); } foreach (CustomSyncedValueBase item2 in allCustomValues.Where((CustomSyncedValueBase c) => c.LocalBaseValue != null)) { item2.BoxedValue = item2.LocalBaseValue; item2.LocalBaseValue = null; } lockedConfigChanged -= serverLockedSettingChanged; serverLockedSettingChanged(); } private ParsedConfigs ReadConfigsFromPackage(ZPackage package) { ParsedConfigs parsedConfigs = new ParsedConfigs(); Dictionary<string, OwnConfigEntryBase> dictionary = allConfigs.ToDictionary((OwnConfigEntryBase c) => c.BaseConfig.Definition.Section + "*" + c.BaseConfig.Definition.Key, (OwnConfigEntryBase c) => c); int num = package.ReadInt(); for (int i = 0; i < num; i++) { string text = package.ReadString(); string key = package.ReadString(); string text2 = package.ReadString(); Type type = Type.GetType(text2); if (text2 == "" || type != null) { object obj; try { obj = ((text2 == "") ? null : ReadValueWithTypeFromZPackage(package, type)); } catch (InvalidDeserializationTypeException ex) { Debug.LogWarning((object)("[RPGStatusEffects] Got unexpected struct internal type " + ex.received + " for field " + ex.field + " struct " + text2 + " for " + key + " in section " + text + " for mod " + (DisplayName ?? Name) + ", expecting " + ex.expected)); continue; } OwnConfigEntryBase value; if (text == "Internal") { if (key == "lockexempt" && obj is bool flag) { lockExempt = flag; continue; } CustomSyncedValueBase customSyncedValueBase = allCustomValues.FirstOrDefault((CustomSyncedValueBase v) => v.Identifier == key); if (customSyncedValueBase != null) { if ((text2 == "" && (!customSyncedValueBase.Type.IsValueType || Nullable.GetUnderlyingType(customSyncedValueBase.Type) != null)) || GetZPackageTypeString(customSyncedValueBase.Type) == text2) { parsedConfigs.customValues[customSyncedValueBase] = obj; continue; } Debug.LogWarning((object)("[RPGStatusEffects] Got unexpected type " + text2 + " for internal value " + key + " for mod " + (DisplayName ?? Name) + ", expecting " + customSyncedValueBase.Type.AssemblyQualifiedName)); } } else if (dictionary.TryGetValue(text + "*" + key, out value)) { Type type2 = configType(value.BaseConfig); if ((text2 == "" && (!type2.IsValueType || Nullable.GetUnderlyingType(type2) != null)) || GetZPackageTypeString(type2) == text2) { parsedConfigs.configValues[value] = obj; continue; } Debug.LogWarning((object)("[RPGStatusEffects] Got unexpected type " + text2 + " for " + key + " in section " + text + " for mod " + (DisplayName ?? Name) + ", expecting " + type2.AssemblyQualifiedName)); } else { Debug.LogWarning((object)("[RPGStatusEffects] Received unknown config entry " + key + " in section " + text + " for mod " + (DisplayName ?? Name) + ".")); } continue; } Debug.LogWarning((object)("[RPGStatusEffects] Got invalid type " + text2 + ", abort reading of received configs")); return new ParsedConfigs(); } return parsedConfigs; } 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(type), CultureInfo.InvariantCulture); } else { if (value is ICollection collection) { package.Write(collection.Count); { IEnumerator enumerator = collection.GetEnumerator(); try { while (enumerator.MoveNext()) { AddValueToZPackage(package, enumerator.Current); } return; } finally { IDisposable disposable = enumerator as IDisposable; if (disposable != null) { disposable.Dispose(); } } } } if (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 (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(); Type type2 = typeof(KeyValuePair<, >).MakeGenericType(type.GenericTypeArguments); IDictionary dictionary = (IDictionary)Activator.CreateInstance(type); 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.IsGenericType) { Type type3 = typeof(ICollection<>).MakeGenericType(type.GenericTypeArguments[0]); if (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.Field(typeof(ParameterInfo), "ClassImpl").SetValue(parameterInfo, type); List<object> source = new List<object>(); ZRpc.Deserialize(new ParameterInfo[2] { null, parameterInfo }, package, ref source); return source.First(); } internal ZPackage ConfigsToPackage(IEnumerable<ConfigEntryBase> configs = null, IEnumerable<CustomSyncedValueBase> customValues = null, IEnumerable<PackageEntry> packageEntries = null, bool partial = true) { //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Expected O, but got Unknown List<ConfigEntryBase> list = configs?.Where((ConfigEntryBase c) => configData(c).SynchronizedConfig).ToList() ?? new List<ConfigEntryBase>(); List<CustomSyncedValueBase> list2 = customValues?.ToList() ?? new List<CustomSyncedValueBase>(); List<PackageEntry> list3 = packageEntries?.ToList() ?? new List<PackageEntry>(); ZPackage val = new ZPackage(); val.Write(partial ? ((byte)1) : ((byte)0)); val.Write(list.Count + list2.Count + list3.Count); foreach (PackageEntry item in list3) { val.Write(item.section); val.Write(item.key); val.Write((item.value == null) ? "" : GetZPackageTypeString(item.type)); AddValueToZPackage(val, item.value); } foreach (CustomSyncedValueBase item2 in list2) { val.Write("Internal"); val.Write(item2.Identifier); val.Write(GetZPackageTypeString(item2.Type)); AddValueToZPackage(val, item2.BoxedValue); } foreach (ConfigEntryBase item3 in list) { val.Write(item3.Definition.Section); val.Write(item3.Definition.Key); val.Write(GetZPackageTypeString(configType(item3))); AddValueToZPackage(val, item3.BoxedValue); } return val; } 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); } [IteratorStateMachine(typeof(<SendZPackage>d__57))] internal IEnumerator SendZPackage(long target, ZPackage package) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <SendZPackage>d__57(0) { <>4__this = this, target = target, package = package }; } [IteratorStateMachine(typeof(<SendZPackage>d__58))] internal IEnumerator SendZPackage(List<ZNetPeer> peers, ZPackage package) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <SendZPackage>d__58(0) { <>4__this = this, peers = peers, package = package }; } [IteratorStateMachine(typeof(<distributeConfigToPeers>d__59))] private IEnumerator distributeConfigToPeers(ZNetPeer peer, ZPackage package) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <distributeConfigToPeers>d__59(0) { <>4__this = this, peer = peer, package = package }; } internal static OwnConfigEntryBase configData(ConfigEntryBase config) { return config.Description.Tags?.OfType<OwnConfigEntryBase>().SingleOrDefault(); } private static T configAttribute<T>(ConfigEntryBase config) where T : class { object[] tags = config.Description.Tags; if (tags == null) { return null; } return tags.OfType<T>().FirstOrDefault(); } } public abstract class OwnConfigEntryBase { public readonly ConfigEntryBase BaseConfig; public object LocalBaseValue; public bool SynchronizedConfig = true; protected OwnConfigEntryBase(ConfigEntryBase config) { BaseConfig = config; } } public class SyncedConfigEntry<T> : OwnConfigEntryBase { public T Value { get { if (BaseConfig is ConfigEntry<T> val) { return val.Value; } throw new InvalidOperationException("Cannot cast BaseConfig to ConfigEntry<" + typeof(T).Name + ">"); } set { ((ConfigEntry<T>)(object)BaseConfig).Value = value; } } public T DefaultValue { get { if (BaseConfig is ConfigEntry<T> val) { return (T)((ConfigEntryBase)val).BoxedValue; } throw new InvalidOperationException("Cannot cast BaseConfig to ConfigEntry<" + typeof(T).Name + ">"); } } public SyncedConfigEntry(ConfigEntry<T> config) : base((ConfigEntryBase)(object)config) { } } public class CustomSyncedValueBase { public string Identifier { get; } public Type Type { get; } public object BoxedValue { get; set; } public object LocalBaseValue { get; set; } public int Priority { get; } public event Action ValueChanged; public CustomSyncedValueBase(string identifier, Type type, int priority = 0) { Identifier = identifier; Type = type; Priority = priority; } } public class ConfigurationManagerAttributes { public bool? ReadOnly; } public class ParsedConfigs { public readonly Dictionary<OwnConfigEntryBase, object> configValues = new Dictionary<OwnConfigEntryBase, object>(); public readonly Dictionary<CustomSyncedValueBase, object> customValues = new Dictionary<CustomSyncedValueBase, object>(); } public class PackageEntry { public string section; public string key; public Type type; public object value; } public class InvalidDeserializationTypeException : Exception { public string expected; public string received; public string field = ""; } [HarmonyPatch(typeof(ZRpc), "HandlePackage")] public class SnatchCurrentlyHandlingRPC { public static ZRpc currentRpc; [HarmonyPrefix] private static void Prefix(ZRpc __instance) { currentRpc = __instance; } } [HarmonyPatch(typeof(ZNet), "Awake")] public class RegisterRPCPatch { [HarmonyPostfix] private static void Postfix(ZNet __instance) { ConfigSync.isServer = __instance.IsServer(); foreach (ConfigSync configSync in ConfigSync.configSyncs) { ZRoutedRpc.instance.Register<ZPackage>(configSync.Name + " ConfigSync", (Action<long, ZPackage>)configSync.RPC_FromOtherClientConfigSync); if (ConfigSync.isServer) { Debug.Log((object)("[RPGStatusEffects] Registered '" + configSync.Name + " ConfigSync' RPC")); } } } } [HarmonyPatch(typeof(ZNet), "OnNewConnection")] public class RegisterClientRPCPatch { [HarmonyPostfix] private static void Postfix(ZNet __instance, ZNetPeer peer) { if (__instance.IsServer()) { return; } foreach (ConfigSync configSync in ConfigSync.configSyncs) { peer.m_rpc.Register<ZPackage>(configSync.Name + " ConfigSync", (Action<ZRpc, ZPackage>)configSync.RPC_FromServerConfigSync); } } } [HarmonyPatch(typeof(ConfigEntryBase), "GetSerializedValue")] public class PreventSavingServerInfo { [HarmonyPrefix] private static bool Prefix(ConfigEntryBase __instance, ref string __result) { OwnConfigEntryBase ownConfigEntryBase = ConfigSync.configData(__instance); if (ownConfigEntryBase == null || ConfigSync.isWritableConfig(ownConfigEntryBase)) { return true; } __result = TomlTypeConverter.ConvertToString(ownConfigEntryBase.LocalBaseValue, __instance.SettingType); return false; } } [HarmonyPatch(typeof(ConfigEntryBase), "SetSerializedValue")] public class PreventConfigRereadChangingValues { [HarmonyPrefix] private static bool Prefix(ConfigEntryBase __instance, string value) { OwnConfigEntryBase ownConfigEntryBase = ConfigSync.configData(__instance); if (ownConfigEntryBase != null && ownConfigEntryBase.LocalBaseValue != null) { try { ownConfigEntryBase.LocalBaseValue = TomlTypeConverter.ConvertToValue(value, __instance.SettingType); } catch (Exception ex) { Debug.LogWarning((object)($"[RPGStatusEffects] Config value of setting \"{__instance.Definition}\"" + " could not be parsed and will be ignored. Reason: " + ex.Message + "; Value: " + value)); } return false; } return true; } } [HarmonyPatch(typeof(ZNet), "RPC_PeerInfo")] public class SendConfigsAfterLogin { public class BufferingSocket : ZPlayFabSocket, ISocket { public volatile bool finished; public volatile int versionMatchQueued; public readonly List<ZPackage> Package = new List<ZPackage>(); public readonly ISocket Original; public BufferingSocket(ISocket original) { Original = original; object obj = AccessTools.Field(typeof(ZPlayFabSocket), "m_remotePlayerId")?.GetValue(original); if (obj != null) { AccessTools.Field(typeof(BufferingSocket), "m_remotePlayerId")?.SetValue(this, obj); } } 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); } } } [CompilerGenerated] private sealed class <>c__DisplayClass1_0 { public ZRpc rpc; public ZNet __instance; public Dictionary<Assembly, BufferingSocket> __state; public ZNetPeer peer; } [HarmonyPrefix] [HarmonyPriority(800)] private static void Prefix(ref Dictionary<Assembly, BufferingSocket> __state, ZNet __instance, ZRpc rpc) { //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Expected O, but got Unknown //IL_0071: Unknown result type (might be due to invalid IL or missing references) if (!__instance.IsServer()) { return; } BufferingSocket bufferingSocket = new BufferingSocket(rpc.GetSocket()); AccessTools.Field(typeof(ZRpc), "m_socket").SetValue(rpc, bufferingSocket); ZNetPeer val = (ZNetPeer)AccessTools.Method(typeof(ZNet), "GetPeer", new Type[1] { typeof(ZRpc) }, (Type[])null).Invoke(__instance, new object[1] { rpc }); if (val != null && (int)ZNet.m_onlineBackend != 0) { FieldInfo fieldInfo = AccessTools.Field(typeof(ZNetPeer), "m_socket"); object? value = fieldInfo.GetValue(val); ZPlayFabSocket val2 = (ZPlayFabSocket)((value is ZPlayFabSocket) ? value : null); if (val2 != null) { AccessTools.Field(typeof(BufferingSocket), "m_remotePlayerId")?.SetValue(bufferingSocket, val2.m_remotePlayerId); } fieldInfo.SetValue(val, bufferingSocket); } if (__state == null) { __state = new Dictionary<Assembly, BufferingSocket>(); } __state[Assembly.GetExecutingAssembly()] = bufferingSocket; } [HarmonyPostfix] private static void Postfix(Dictionary<Assembly, BufferingSocket> __state, ZNet __instance, ZRpc rpc) { //IL_006c: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Expected O, but got Unknown <>c__DisplayClass1_0 CS$<>8__locals0 = new <>c__DisplayClass1_0(); CS$<>8__locals0.rpc = rpc; CS$<>8__locals0.__instance = __instance; CS$<>8__locals0.__state = __state; if (CS$<>8__locals0.__instance.IsServer()) { CS$<>8__locals0.peer = (ZNetPeer)AccessTools.Method(typeof(ZNet), "GetPeer", new Type[1] { typeof(ZRpc) }, (Type[])null).Invoke(CS$<>8__locals0.__instance, new object[1] { CS$<>8__locals0.rpc }); if (CS$<>8__locals0.peer == null) { SendBufferedData(); } else { ((MonoBehaviour)CS$<>8__locals0.__instance).StartCoroutine(SendAsync()); } } [IteratorStateMachine(typeof(<>c__DisplayClass1_0.<<Postfix>g__SendAsync|1>d))] IEnumerator SendAsync() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <>c__DisplayClass1_0.<<Postfix>g__SendAsync|1>d(0) { <>4__this = CS$<>8__locals0 }; } void SendBufferedData() { //IL_007e: Unknown result type (might be due to invalid IL or missing references) //IL_0084: Expected O, but got Unknown if (CS$<>8__locals0.rpc.GetSocket() is BufferingSocket bufferingSocket) { AccessTools.Field(typeof(ZRpc), "m_socket").SetValue(CS$<>8__locals0.rpc, bufferingSocket.Original); ZNetPeer val = (ZNetPeer)AccessTools.Method(typeof(ZNet), "GetPeer", new Type[1] { typeof(ZRpc) }, (Type[])null).Invoke(CS$<>8__locals0.__instance, new object[1] { CS$<>8__locals0.rpc }); if (val != null) { AccessTools.Field(typeof(ZNetPeer), "m_socket").SetValue(val, bufferingSocket.Original); } } BufferingSocket bufferingSocket2 = CS$<>8__locals0.__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(); } } } } public static class RecipeManager { private static readonly Dictionary<string, Recipe> _existingRecipes = new Dictionary<string, Recipe>(); private static readonly Dictionary<string, Requirement[]> itemRecipeCache = new Dictionary<string, Requirement[]>(); public static void SetupRecipe() { if ((Object)(object)ObjectDB.instance == (Object)null || ObjectDB.instance.m_recipes == null || (Object)(object)ZNetScene.instance == (Object)null) { return; } _existingRecipes.Clear(); string itemName = "TauntHammer_vad"; GameObject val = ((IEnumerable<GameObject>)RPGStatusEffects.itemPrefabs).FirstOrDefault((Func<GameObject, bool>)((GameObject p) => (Object)(object)p != (Object)null && string.Equals(((Object)p).name, itemName, StringComparison.OrdinalIgnoreCase))); if ((Object)(object)val == (Object)null) { return; } ItemDrop component = val.GetComponent<ItemDrop>(); if ((Object)(object)component == (Object)null) { return; } TauntEffect tauntEffect = StatusEffectManager.GetEffect("Taunted") as TauntEffect; if ((Object)(object)tauntEffect != (Object)null) { component.m_itemData.m_shared.m_attackStatusEffect = (StatusEffect)(object)tauntEffect; component.m_itemData.m_shared.m_attackStatusEffectChance = 1f; if (RPGStatusEffects.Instance.configVerboseLogging.Value) { Debug.Log((object)string.Format("{0}: Assigned Taunt effect to TauntHammer_vad (effect: {1}, duration: {2}s).", "RPGStatusEffects", ((Object)tauntEffect).name, tauntEffect.Duration)); } } GameObject prefab = ZNetScene.instance.GetPrefab("piece_workbench"); CraftingStation val2 = ((prefab != null) ? prefab.GetComponent<CraftingStation>() : null); if ((Object)(object)val2 == (Object)null) { return; } Requirement[] array = ParseRequirements(RPGStatusEffects.Instance.configTauntHammerRecipe.Value, itemName); if (array.Length == 0) { return; } Recipe recipe = ScriptableObject.CreateInstance<Recipe>(); ((Object)recipe).name = "Recipe_" + itemName; recipe.m_item = component; recipe.m_craftingStation = val2; recipe.m_minStationLevel = 1; recipe.m_amount = 1; recipe.m_resources = array; if (!ObjectDB.instance.m_recipes.Any((Recipe r) => ((Object)r).name == ((Object)recipe).name)) { ObjectDB.instance.m_recipes.Add(recipe); _existingRecipes[itemName] = recipe; if (RPGStatusEffects.Instance.configVerboseLogging.Value) { Debug.Log((object)"RPGStatusEffects: Added Recipe_TauntHammer_vad to ObjectDB.m_recipes"); } } if (!((Object)(object)Player.m_localPlayer != (Object)null)) { return; } HashSet<string> hashSet = (HashSet<string>)(RPGStatusEffects.knownRecipesField?.GetValue(Player.m_localPlayer)); if (hashSet != null && !hashSet.Contains(((Object)recipe).name)) { hashSet.Add(((Object)recipe).name); if (RPGStatusEffects.Instance.configVerboseLogging.Value) { Debug.Log((object)"RPGStatusEffects: Added Recipe_TauntHammer_vad to player's known recipes."); } } } public static void ClearCache() { itemRecipeCache.Clear(); } private static Requirement[] ParseRequirements(string configValue, string key) { //IL_0123: Unknown result type (might be due to invalid IL or missing references) //IL_0128: Unknown result type (might be due to invalid IL or missing references) //IL_0130: Unknown result type (might be due to invalid IL or missing references) //IL_0138: Unknown result type (might be due to invalid IL or missing references) //IL_0140: Unknown result type (might be due to invalid IL or missing references) //IL_014c: Expected O, but got Unknown if (itemRecipeCache.TryGetValue(key, out var value)) { return value; } List<Requirement> list = new List<Requirement>(); string[] array = (from s in configValue.Split(new char[1] { ',' }) select s.Trim()).ToArray(); for (int i = 0; i < array.Length && i + 2 < array.Length; i += 3) { string text = array[i]; if (!int.TryParse(array[i + 1], out var result)) { result = 1; } if (!int.TryParse(array[i + 2], out var result2)) { result2 = 0; } ZNetScene instance = ZNetScene.instance; object obj; if (instance == null) { obj = null; } else { GameObject prefab = instance.GetPrefab(text); obj = ((prefab != null) ? prefab.GetComponent<ItemDrop>() : null); } if (obj == null) { ObjectDB instance2 = ObjectDB.instance; if (instance2 == null) { obj = null; } else { GameObject itemPrefab = instance2.GetItemPrefab(text); obj = ((itemPrefab != null) ? itemPrefab.GetComponent<ItemDrop>() : null); } } ItemDrop val = (ItemDrop)obj; if ((Object)(object)val == (Object)null) { if (RPGStatusEffects.Instance.configVerboseLogging.Value) { Debug.LogWarning((object)("RPGStatusEffects: Invalid material '" + text + "' in recipe for " + key + " - skipping.")); } } else { list.Add(new Requirement { m_resItem = val, m_amount = result, m_amountPerLevel = result2, m_recover = true }); } } Requirement[] array2 = list.ToArray(); itemRecipeCache[key] = array2; if (array2.Length == 0 && RPGStatusEffects.Instance.configVerboseLogging.Value) { Debug.LogWarning((object)("RPGStatusEffects: No valid requirements parsed for " + key + " - recipe may fail.")); } return array2; } } public static class StatusEffectManager { private static readonly Dictionary<string, StatusEffect> CustomEffects = new Dictionary<string, StatusEffect>(); public static void Initialize() { if (!RPGStatusEffects.IsObjectDBValid()) { if (RPGStatusEffects.Instance.configVerboseLogging.Value) { Debug.LogWarning((object)"RPGStatusEffects: Skipping StatusEffectManager init - ObjectDB not valid."); } return; } CustomEffects.Clear(); ObjectDB instance = ObjectDB.instance; RegisterPurityEffect(instance); RegisterTauntEffect(instance); RegisterTauntingEffect(instance); if (RPGStatusEffects.Instance.configVerboseLogging.Value) { Debug.Log((object)string.Format("{0}: StatusEffectManager initialized {1} custom effects.", "RPGStatusEffects", CustomEffects.Count)); } } private static void RegisterPurityEffect(ObjectDB objectDB) { StatusEffect val = ((IEnumerable<StatusEffect>)objectDB.m_StatusEffects).FirstOrDefault((Func<StatusEffect, bool>)((StatusEffect se) => ((Object)se).name == "Purify")); if ((Object)(object)val != (Object)null) { objectDB.m_StatusEffects.Remove(val); if (RPGStatusEffects.Instance.configVerboseLogging.Value) { Debug.Log((object)"RPGStatusEffects: Removed existing Purify effect to update duration."); } } PurityEffect purityEffect = ScriptableObject.CreateInstance<PurityEffect>(); ((Object)purityEffect).name = "Purify"; purityEffect.Icon = LoadOrCreateIcon(); purityEffect.Duration = RPGStatusEffects.Instance.configPurityDuration.Value; objectDB.m_StatusEffects.Add((StatusEffect)(object)purityEffect); CustomEffects["Purify"] = (StatusEffect)(object)purityEffect; if (RPGStatusEffects.Instance.configVerboseLogging.Value) { Debug.Log((object)string.Format("{0}: Registered PurityEffect with duration {1}s, Icon: {2}.", "RPGStatusEffects", purityEffect.Duration, ((Object)(object)purityEffect.Icon != (Object)null) ? "Assigned" : "Null")); } } private static void RegisterTauntEffect(ObjectDB objectDB) { StatusEffect val = ((IEnumerable<StatusEffect>)objectDB.m_StatusEffects).FirstOrDefault((Func<StatusEffect, bool>)((StatusEffect se) => ((Object)se).name == "Taunted")); if ((Object)(object)val != (Object)null) { objectDB.m_StatusEffects.Remove(val); if (RPGStatusEffects.Instance.configVerboseLogging.Value) { Debug.Log((object)"RPGStatusEffects: Removed existing Taunted effect to update duration."); } } TauntEffect tauntEffect = ScriptableObject.CreateInstance<TauntEffect>(); ((Object)tauntEffect).name = "Taunted"; tauntEffect.Duration = RPGStatusEffects.Instance.configTauntDuration.Value; tauntEffect.Icon = null; objectDB.m_StatusEffects.Add((StatusEffect)(object)tauntEffect); CustomEffects["Taunted"] = (StatusEffect)(object)tauntEffect; if (RPGStatusEffects.Instance.configVerboseLogging.Value) { Debug.Log((object)string.Format("{0}: Registered TauntEffect with duration {1}s, Icon: {2}.", "RPGStatusEffects", tauntEffect.Duration, ((Object)(object)tauntEffect.Icon != (Object)null) ? "Assigned" : "Null")); } } private static void RegisterTauntingEffect(ObjectDB objectDB) { StatusEffect val = ((IEnumerable<StatusEffect>)objectDB.m_StatusEffects).FirstOrDefault((Func<StatusEffect, bool>)((StatusEffect se) => ((Object)se).name == "Taunting")); if ((Object)(object)val != (Object)null) { objectDB.m_StatusEffects.Remove(val); if (RPGStatusEffects.Instance.configVerboseLogging.Value) { Debug.Log((object)"RPGStatusEffects: Removed existing Taunting effect to update duration."); } } TauntingEffect tauntingEffect = ScriptableObject.CreateInstance<TauntingEffect>(); ((Object)tauntingEffect).name = "Taunting"; tauntingEffect.Duration = RPGStatusEffects.Instance.configTauntDuration.Value; tauntingEffect.Icon = LoadTauntingIcon(); objectDB.m_StatusEffects.Add((StatusEffect)(object)tauntingEffect); CustomEffects["Taunting"] = (StatusEffect)(object)tauntingEffect; if (RPGStatusEffects.Instance.configVerboseLogging.Value) { Debug.Log((object)string.Format("{0}: Registered TauntingEffect with duration {1}s, Icon: {2}.", "RPGStatusEffects", tauntingEffect.Duration, ((Object)(object)tauntingEffect.Icon != (Object)null) ? "Assigned" : "Null")); } } private static Sprite LoadOrCreateIcon() { //IL_010b: Unknown result type (might be due to invalid IL or missing references) //IL_0112: Expected O, but got Unknown //IL_0127: Unknown result type (might be due to invalid IL or missing references) //IL_012c: Unknown result type (might be due to invalid IL or missing references) //IL_0165: Unknown result type (might be due to invalid IL or missing references) //IL_0174: Unknown result type (might be due to invalid IL or missing references) string[] array = new string[5] { "assets/custom/vaitems/icons/purity_icon", "Assets/Custom/VAItems/Icons/purity_icon", "assets/custom/VAitems/icons/purity_icon", "Assets/Custom/VAItems/Icons/Purity_Icon", "assets/custom/vaitems/icons/purity_icon.png" }; Sprite val = null; string[] array2 = array; foreach (string text in array2) { AssetBundle assetBundle = RPGStatusEffects.assetBundle; val = ((assetBundle != null) ? assetBundle.LoadAsset<Sprite>(text) : null); if ((Object)(object)val != (Object)null) { if (RPGStatusEffects.Instance.configVerboseLogging.Value) { Debug.Log((object)("RPGStatusEffects: Loaded purity_icon from asset bundle at " + text + ".")); } break; } } if ((Object)(object)val == (Object)null) { if (RPGStatusEffects.Instance.configVerboseLogging.Value) { Debug.LogWarning((object)("RPGStatusEffects: Failed to load purity_icon from asset bundle. Attempted paths: " + string.Join(", ", array) + ".")); if ((Object)(object)RPGStatusEffects.assetBundle != (Object)null) { Debug.Log((object)("RPGStatusEffects: Available assets in bundle: " + string.Join(", ", RPGStatusEffects.assetBundle.GetAllAssetNames()) + ".")); } Debug.Log((object)"RPGStatusEffects: Falling back to cyan square for Purity icon."); } Texture2D val2 = new Texture2D(64, 64); Color[] array3 = (Color[])(object)new Color[4096]; for (int j = 0; j < array3.Length; j++) { array3[j] = Color.cyan; } val2.SetPixels(array3); val2.Apply(); val = Sprite.Create(val2, new Rect(0f, 0f, 64f, 64f), new Vector2(0.5f, 0.5f)); } return val; } private static Sprite LoadTauntIcon() { return null; } private static Sprite LoadTauntingIcon() { //IL_010b: Unknown result type (might be due to invalid IL or missing references) //IL_0112: Expected O, but got Unknown //IL_0127: Unknown result type (might be due to invalid IL or missing references) //IL_012c: Unknown result type (might be due to invalid IL or missing references) //IL_0165: Unknown result type (might be due to invalid IL or missing references) //IL_0174: Unknown result type (might be due to invalid IL or missing references) string[] array = new string[5] { "assets/custom/vaitems/icons/taunt_icon", "Assets/Custom/VAItems/Icons/taunt_icon", "assets/custom/VAitems/icons/taunt_icon", "Assets/Custom/VAItems/Icons/Taunt_Icon", "assets/custom/vaitems/icons/taunt_icon.png" }; Sprite val = null; string[] array2 = array; foreach (string text in array2) { AssetBundle assetBundle = RPGStatusEffects.assetBundle; val = ((assetBundle != null) ? assetBundle.LoadAsset<Sprite>(text) : null); if ((Object)(object)val != (Object)null) { if (RPGStatusEffects.Instance.configVerboseLogging.Value) { Debug.Log((object)("RPGStatusEffects: Loaded taunt_icon from asset bundle at " + text + ".")); } break; } } if ((Object)(object)val == (Object)null) { if (RPGStatusEffects.Instance.configVerboseLogging.Value) { Debug.LogWarning((object)("RPGStatusEffects: Failed to load taunt_icon from asset bundle. Attempted paths: " + string.Join(", ", array) + ".")); if ((Object)(object)RPGStatusEffects.assetBundle != (Object)null) { Debug.Log((object)("RPGStatusEffects: Available assets in bundle: " + string.Join(", ", RPGStatusEffects.assetBundle.GetAllAssetNames()) + ".")); } Debug.Log((object)"RPGStatusEffects: Falling back to yellow square for Taunting icon."); } Texture2D val2 = new Texture2D(64, 64); Color[] array3 = (Color[])(object)new Color[4096]; for (int j = 0; j < array3.Length; j++) { array3[j] = Color.yellow; } val2.SetPixels(array3); val2.Apply(); val = Sprite.Create(val2, new Rect(0f, 0f, 64f, 64f), new Vector2(0.5f, 0.5f)); } return val; } public static StatusEffect GetEffect(string name) { CustomEffects.TryGetValue(name, out var value); return value; } } public class PurityEffect : StatusEffect { private static readonly HashSet<string> DebuffNames = new HashSet<string> { "Poison", "Burning", "Frost", "Wet", "Smoked", "Tared" }; public Sprite Icon { get; set; } public float Duration { get; set; } = 10f; public override void Setup(Character character) { ((StatusEffect)this).Setup(character); base.m_ttl = Duration; base.m_name = "Purify"; base.m_icon = Icon; Character character2 = base.m_character; Player val = (Player)(object)((character2 is Player) ? character2 : null); if (val == null) { return; } foreach (StatusEffect item in new List<StatusEffect>(((Character)val).GetSEMan().GetStatusEffects())) { if ((Object)(object)item != (Object)(object)this && DebuffNames.Contains(((Object)item).name)) { ((Character)val).GetSEMan().RemoveStatusEffect(item, true); } } ((Character)val).Message((MessageType)2, "All debuffs purified!", 0, (Sprite)null); } } public class TauntEffect : StatusEffect { public Character Taunter { get; set; } public float Duration { get; set; } = 15f; public Sprite Icon { get; set; } public override void Setup(Character character) { ((StatusEffect)this).Setup(character); base.m_ttl = Duration; base.m_name = "Taunted"; base.m_icon = Icon; if ((Object)(object)base.m_character != (Object)null) { base.m_character.Message((MessageType)1, "TAUNTED!", 0, (Sprite)null); if (RPGStatusEffects.Instance.configVerboseLogging.Value) { Debug.Log((object)string.Format("{0}: Setup TauntEffect on {1}, Duration: {2}s, Icon: {3}.", "RPGStatusEffects", ((Object)base.m_character).name, base.m_ttl, ((Object)(object)base.m_icon != (Object)null) ? "Assigned" : "Null")); } } } public override void UpdateStatusEffect(float dt) { ((StatusEffect)this).UpdateStatusEffect(dt); } public override void Stop() { ((StatusEffect)this).Stop(); if ((Object)(object)base.m_character != (Object)null) { base.m_character.Message((MessageType)1, "Taunt ended.", 0, (Sprite)null); } } } public class TauntingEffect : StatusEffect { public float Duration { get; set; } = 15f; public Sprite Icon { get; set; } public override void Setup(Character character) { ((StatusEffect)this).Setup(character); base.m_ttl = Duration; base.m_name = "Taunting"; base.m_icon = Icon; if ((Object)(object)base.m_character != (Object)null && base.m_character.IsPlayer()) { base.m_character.Message((MessageType)1, "Taunting enemy!", 0, (Sprite)null); if (RPGStatusEffects.Instance.configVerboseLogging.Value) { Debug.Log((object)string.Format("{0}: Setup TauntingEffect on player {1}, Duration: {2}s, Icon: {3}.", "RPGStatusEffects", ((Object)base.m_character).name, base.m_ttl, ((Object)(object)base.m_icon != (Object)null) ? "Assigned" : "Null")); } } } public override void UpdateStatusEffect(float dt) { ((StatusEffect)this).UpdateStatusEffect(dt); } public override void Stop() { ((StatusEffect)this).Stop(); if ((Object)(object)base.m_character != (Object)null && base.m_character.IsPlayer()) { base.m_character.Message((MessageType)1, "Taunt expired.", 0, (Sprite)null); } } } }