Decompiled source of New Game Plus v1.0.2
plugins/NewGamePlus.dll
Decompiled 6 hours ago
The result has been truncated due to the large size, download it to view full contents!
using 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 System.Threading; using API; using BepInEx; using BepInEx.Configuration; using HarmonyLib; using JetBrains.Annotations; using Microsoft.CodeAnalysis; using ServerSync; using TMPro; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: AssemblyTitle("NewGamePlus")] [assembly: AssemblyDescription("NewGamePlus")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("NewGamePlus")] [assembly: AssemblyCopyright("Copyright © 2025")] [assembly: AssemblyTrademark("")] [assembly: ComVisible(false)] [assembly: Guid("b8f1a3c4-5dcf-4df6-899e-73f354a55c84")] [assembly: AssemblyFileVersion("1.2.0")] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.2.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.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] [Microsoft.CodeAnalysis.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] [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 radamanto.NG { [HarmonyPatch(typeof(SE_Stats), "ModifyMaxCarryWeight")] internal static class NGPlus_CarryWeightPatch { private static void Postfix(SE_Stats __instance, float baseLimit, ref float limit) { if (((StatusEffect)__instance).m_nameHash == NGPlus_StatusEffect.SE_Hash) { float value = NewGamePlusPlugin.CE_CarryWeightAdd.Value; if (value != 0f) { limit += value; } } } } internal static class NGPlus_EpicMMO { internal const string RPC_EpicMMO_ResetTotalPoints = "NGP_EpicMMO_ResetTotalPoints"; private static bool IsEpicMmoInstalled() { return Type.GetType("EpicMMOSystem.EpicMMOSystem, EpicMMOSystem") != null; } internal static void OnNgPlusActivated(Player player) { //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Expected O, but got Unknown if ((Object)(object)player == (Object)null) { return; } if (!IsEpicMmoInstalled()) { ApplyXpRate(player, isNgPlusActive: false); return; } if (NewGamePlusPlugin.CE_EpicMMO_ResetOnNGPlus.Value && ZRoutedRpc.instance != null) { string text = player.GetPlayerName() ?? ""; if (!string.IsNullOrWhiteSpace(text)) { ZPackage val = new ZPackage(); val.Write(text); long serverPeerID = ZRoutedRpc.instance.GetServerPeerID(); if (serverPeerID != 0) { ZRoutedRpc.instance.InvokeRoutedRPC(serverPeerID, "NGP_EpicMMO_ResetTotalPoints", new object[1] { val }); } } } ApplyXpRate(player, isNgPlusActive: true); } internal static void OnNgPlusDeactivated(Player player) { if (IsEpicMmoInstalled()) { ApplyXpRate(player, isNgPlusActive: false); } } private static void ApplyXpRate(Player player, bool isNgPlusActive) { if (!((Object)(object)player == (Object)null) && !((Object)(object)player != (Object)(object)Player.m_localPlayer)) { float singleRate = (isNgPlusActive ? Mathf.Max(0f, NewGamePlusPlugin.CE_EpicMMO_XpMultiplierNGPlus.Value) : 1f); EpicMMOSystem_API.SetSingleRate(singleRate); } } } [BepInPlugin("radamanto.NewGamePlus", "NewGamePlus", "1.0.2")] [BepInDependency(/*Could not decode attribute arguments.*/)] public class NewGamePlusPlugin : BaseUnityPlugin { [CompilerGenerated] private sealed class <NGP_Reset_RPCRegisterLoop>d__46 : IEnumerator<object>, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; public NewGamePlusPlugin <>4__this; private WaitForSeconds <wait>5__1; private ZNet <znet>5__2; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <NGP_Reset_RPCRegisterLoop>d__46(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <wait>5__1 = null; <znet>5__2 = null; <>1__state = -2; } private bool MoveNext() { //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Expected O, but got Unknown switch (<>1__state) { default: return false; case 0: <>1__state = -1; <wait>5__1 = new WaitForSeconds(2f); break; case 1: <>1__state = -1; break; } try { <>4__this.NGP_TryRegisterResetRPC_Server(); <>4__this.NGP_TryRegisterApplyRPC_Client(); <>4__this.NGP_TryRegisterEpicResetRPC_Server(); <znet>5__2 = ZNet.instance; if ((Object)(object)<znet>5__2 != (Object)null) { if (<znet>5__2.IsServer()) { if (<>4__this._ngpResetRegistered && <>4__this._ngpClientApplyRegistered && <>4__this._epicResetRegistered) { return false; } } else if (<>4__this._ngpClientApplyRegistered) { return false; } } <znet>5__2 = null; } catch { } <>2__current = <wait>5__1; <>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(); } } internal const string ModName = "NewGamePlus"; internal const string ModVersion = "1.0.2"; internal const string Author = "radamanto"; private const string ModGUID = "radamanto.NewGamePlus"; internal const string NGPlusCustomKey = "radamanto.ngplus.active"; internal static ConfigSync Sync; public static ConfigEntry<bool>? ServerConfigLocked; internal static ConfigEntry<bool> CE_Enable; internal static ConfigEntry<string> CE_RequiredPrivateKeys; internal static ConfigEntry<bool> CE_ResetSkillsOnNGPlus; internal static ConfigEntry<float> CE_DamageDonePercent; internal static ConfigEntry<float> CE_DamageTakenPercent; internal static ConfigEntry<float> CE_RegenHealthPercent; internal static ConfigEntry<float> CE_RegenStaminaPercent; internal static ConfigEntry<float> CE_RegenEitrPercent; internal static ConfigEntry<float> CE_CarryWeightAdd; internal static ConfigEntry<bool> CE_ShowOverheadIcon; internal static ConfigEntry<float> CE_OverheadIconHeight; internal static ConfigEntry<float> CE_OverheadIconScale; internal static ConfigEntry<bool> CE_IgnorePortalRestrictionsWithNGPlus; internal static ConfigEntry<bool> CE_EpicMMO_ResetOnNGPlus; internal static ConfigEntry<float> CE_EpicMMO_XpMultiplierNGPlus; private bool _epicResetRegistered = false; private ConfigSync? _configSync; private FileSystemWatcher? _cfgWatcher; private readonly object _cfgLock = new object(); private DateTime _lastCfgEventUtc; private DateTime _lastSettingChangeUtc; private Harmony? _harmony; internal const string RPC_NGPlusResetRequest = "NGP_ResetRequest"; internal const string RPC_NGPlusResetApply = "NGP_ResetApply"; private bool _ngpResetRegistered = false; private bool _ngpClientApplyRegistered = false; internal static NewGamePlusPlugin Instance { get; private set; } private void Awake() { //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Expected O, but got Unknown Instance = this; SetupConfigSync(); BindConfigs(); _harmony = new Harmony("radamanto.NewGamePlus"); _harmony.PatchAll(Assembly.GetExecutingAssembly()); NGPlus_AssetLoader.Init(); NGPlus_StatusEffect.EnsureRegistered(); ((MonoBehaviour)this).StartCoroutine(NGP_Reset_RPCRegisterLoop()); ((BaseUnityPlugin)this).Logger.LogInfo((object)"NewGamePlus 1.0.2 loaded."); } private void OnDestroy() { Harmony? harmony = _harmony; if (harmony != null) { harmony.UnpatchSelf(); } if (_cfgWatcher != null) { try { _cfgWatcher.EnableRaisingEvents = false; _cfgWatcher.Changed -= OnCfgChanged; _cfgWatcher.Created -= OnCfgChanged; _cfgWatcher.Renamed -= OnCfgChanged; _cfgWatcher.Dispose(); } catch { } _cfgWatcher = null; } } private void SetupConfigSync() { if (_configSync == null) { _configSync = new ConfigSync("radamanto.NewGamePlus") { DisplayName = "NewGamePlus", CurrentVersion = "1.0.2", MinimumRequiredVersion = "1.0.2" }; Sync = _configSync; } ServerConfigLocked = Cfg("General", "ServerConfigLocked", value: true, "When true, only the server can change synced settings.\nQuando ativado, apenas o servidor pode alterar as configurações sincronizadas.", synced: true, locking: true); if (_configSync != null && ServerConfigLocked != null) { try { SyncedConfigEntry<bool> syncedConfigEntry = _configSync.AddLockingConfigEntry<bool>(ServerConfigLocked); _configSync.IsLocked = ServerConfigLocked.Value; } catch { SyncedConfigEntry<bool> syncedConfigEntry2 = _configSync.AddConfigEntry<bool>(ServerConfigLocked); syncedConfigEntry2.SynchronizedConfig = true; _configSync.IsLocked = ServerConfigLocked.Value; } } try { EventInfo eventInfo = _configSync?.GetType().GetEvent("ConfigurationSynchronized", BindingFlags.Instance | BindingFlags.Public); if (eventInfo != null && _configSync != null) { EventHandler handler = OnConfigurationSynchronized; eventInfo.AddEventHandler(_configSync, handler); } } catch { } if (_cfgWatcher == null) { string fileName = Path.GetFileName(((BaseUnityPlugin)this).Config.ConfigFilePath); if (!string.IsNullOrEmpty(fileName)) { _cfgWatcher = new FileSystemWatcher(Paths.ConfigPath, fileName) { IncludeSubdirectories = false, NotifyFilter = (NotifyFilters.FileName | NotifyFilters.Size | NotifyFilters.LastWrite | NotifyFilters.CreationTime), EnableRaisingEvents = true }; _cfgWatcher.Changed += OnCfgChanged; _cfgWatcher.Created += OnCfgChanged; _cfgWatcher.Renamed += OnCfgChanged; } } } private void OnCfgChanged(object sender, FileSystemEventArgs e) { DateTime utcNow = DateTime.UtcNow; if (!((utcNow - _lastCfgEventUtc).TotalMilliseconds < 200.0)) { _lastCfgEventUtc = utcNow; ThreadPool.QueueUserWorkItem(delegate { Thread.Sleep(150); ReloadConfigIfChanged(); }); } } private void ReloadConfigIfChanged() { lock (_cfgLock) { try { if (!File.Exists(((BaseUnityPlugin)this).Config.ConfigFilePath)) { return; } using (FileStream stream = new FileStream(((BaseUnityPlugin)this).Config.ConfigFilePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) { using StreamReader streamReader = new StreamReader(stream); if (string.IsNullOrWhiteSpace(streamReader.ReadToEnd())) { return; } } ((BaseUnityPlugin)this).Config.Reload(); if (_configSync != null && ServerConfigLocked != null) { _configSync.IsLocked = ServerConfigLocked.Value; } SafeReparse(); } catch { } } } private void OnConfigurationSynchronized(object? sender, EventArgs e) { try { if (ServerConfigLocked != null && _configSync != null) { _configSync.IsLocked = ServerConfigLocked.Value; } SafeReparse(); } catch (Exception arg) { ((BaseUnityPlugin)this).Logger.LogError((object)$"[NG+] Failed to apply server synchronization: {arg}"); } } private ConfigEntry<T> Cfg<T>(string group, string name, T value, string description = "", bool synced = true, bool locking = false) { //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Expected O, but got Unknown ConfigDescription val = new ConfigDescription(description, (AcceptableValueBase)null, Array.Empty<object>()); ConfigEntry<T> val2 = ((BaseUnityPlugin)this).Config.Bind<T>(group, name, value, val); if (_configSync != null && !locking) { SyncedConfigEntry<T> syncedConfigEntry = _configSync.AddConfigEntry<T>(val2); syncedConfigEntry.SynchronizedConfig = synced; } val2.SettingChanged += delegate { DateTime utcNow = DateTime.UtcNow; if (!((utcNow - _lastSettingChangeUtc).TotalMilliseconds < 100.0)) { _lastSettingChangeUtc = utcNow; try { if (_configSync != null && _configSync.IsLocked && (Object)(object)ZNet.instance != (Object)null && !ZNet.instance.IsServer()) { ((BaseUnityPlugin)this).Config.Reload(); return; } } catch { } SafeReparse(); } }; return val2; } private void SafeReparse() { try { NGPlus_StatusEffect.EnsureRegistered(); } catch (Exception arg) { ((BaseUnityPlugin)this).Logger.LogError((object)$"[NG+] Failed to re-apply NG+ definitions: {arg}"); } } private void BindConfigs() { CE_Enable = Cfg("General", "Enable", value: true, "Enables the NG+ system (buff and its effects).\nAtiva o sistema de NG+ (buff e efeitos)."); CE_RequiredPrivateKeys = Cfg("Key Requirement", "RequiredKeys", "defeated_eikthyr, defeated_gdking, defeated_bonemass, defeated_dragon, defeated_goblinking, defeated_queen, defeated_fader", "Comma-separated list of global keys required to activate NG+.\nThe player must have ALL listed keys.\nLista de global keys necessárias para ativar o NG+.\nO jogador precisa ter TODAS as keys listadas."); CE_ResetSkillsOnNGPlus = Cfg("Skill", "ResetSkillsOnNGPlus", value: false, "If enabled, using /ngplus will reset all skills to level 0.\nQuando ativado, usar /ngplus redefine todas as skills para o nível 0."); CE_IgnorePortalRestrictionsWithNGPlus = Cfg("Portal", "IgnorePortalRestrictionsWithNGPlus", value: false, "When enabled, players with the NG+ buff can use portals while carrying any item.\nQuando ativado, jogadores com o buff de NG+ podem usar portais carregando qualquer item."); CE_DamageDonePercent = Cfg("Effects", "DamageDonePercent", 0f, "Adjustment to damage dealt (in percent).\n0 = no change, 10 = deals +10% damage, -20 = deals -20% damage.\nAjuste no dano causado (em %).\n0 = sem mudança, 10 = causa +10% de dano, -20 = causa -20% de dano."); CE_DamageTakenPercent = Cfg("Effects", "DamageTakenPercent", 0f, "Adjustment to damage taken (in percent).\n0 = no change, 10 = takes +10% damage, -20 = takes -20% damage.\nAjuste no dano recebido (em %).\n0 = sem mudança, 10 = recebe +10% de dano, -20 = recebe -20% de dano."); CE_RegenHealthPercent = Cfg("Effects", "RegenHealthPercent", 0f, "Adjustment to health regeneration (in percent).\n0 = no change, positive values increase regen, negative values reduce it.\nAjuste na regeneração de vida (em %).\n0 = sem mudança, valores positivos aumentam a regeneração, negativos reduzem."); CE_RegenStaminaPercent = Cfg("Effects", "RegenStaminaPercent", 0f, "Adjustment to stamina regeneration (in percent).\n0 = no change, positive values increase regen, negative values reduce it.\nAjuste na regeneração de vigor (em %).\n0 = sem mudança, valores positivos aumentam a regeneração, negativos reduzem."); CE_RegenEitrPercent = Cfg("Effects", "RegenEitrPercent", 0f, "Adjustment to eitr regeneration (in percent).\n0 = no change, positive values increase regen, negative values reduce it.\nAjuste na regeneração de éter (em %).\n0 = sem mudança, valores positivos aumentam a regeneração, negativos reduzem."); CE_CarryWeightAdd = Cfg("Effects", "CarryWeightAdd", 0f, "Flat bonus to carry weight.\n0 = no change, 500 = +500 carry weight, -100 = -100 carry weight.\nBônus direto na capacidade de carga.\n0 = sem mudança, 500 = +500 de peso carregável, -100 = -100 de peso."); CE_ShowOverheadIcon = Cfg("Visual", "ShowOverheadIcon", value: true, "Shows an NG+ icon above players who have the buff.\nExibe um ícone de NG+ acima dos jogadores que possuem o buff."); CE_OverheadIconHeight = Cfg("Visual", "OverheadIconHeight", 2.4f, "Vertical height of the NG+ icon above the player.\nAltura vertical do ícone de NG+ acima do jogador."); CE_OverheadIconScale = Cfg("Visual", "OverheadIconScale", 0.08f, "Base scale of the NG+ icon above the player.\nTamanho base do ícone de NG+ exibido acima do jogador."); CE_EpicMMO_ResetOnNGPlus = Cfg("EpicMMOSystem", "ResetOnNGPlus", value: true, "Se o EpicMMOSystem estiver instalado, ao ativar o NG+ este personagem terá todos os pontos, nível e experiência do EpicMMO resetados (epicmmosystem reset_totalpoints).\nIf EpicMMOSystem is installed, when NG+ is activated this character will have all EpicMMO points, level and experience reset (epicmmosystem reset_totalpoints)."); CE_EpicMMO_XpMultiplierNGPlus = Cfg("EpicMMOSystem", "XpMultiplierNGPlus", 1f, "Se o EpicMMOSystem estiver instalado, multiplicador de XP do EpicMMO enquanto o NG+ estiver ativo para este personagem. 1.0 = XP normal.\nIf EpicMMOSystem is installed, EpicMMO XP multiplier while NG+ is active for this character. 1.0 = normal XP."); } [IteratorStateMachine(typeof(<NGP_Reset_RPCRegisterLoop>d__46))] private IEnumerator NGP_Reset_RPCRegisterLoop() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <NGP_Reset_RPCRegisterLoop>d__46(0) { <>4__this = this }; } private void NGP_TryRegisterResetRPC_Server() { if (_ngpResetRegistered) { return; } ZRoutedRpc instance = ZRoutedRpc.instance; ZNet instance2 = ZNet.instance; if (instance == null || (Object)(object)instance2 == (Object)null || !instance2.IsServer()) { return; } try { instance.Register<ZPackage>("NGP_ResetRequest", (Action<long, ZPackage>)NGP_OnResetRequest_Server); _ngpResetRegistered = true; ((BaseUnityPlugin)this).Logger.LogInfo((object)"[NG+] RPC request registrado (server)."); } catch (ArgumentException) { _ngpResetRegistered = true; } catch (Exception arg) { ((BaseUnityPlugin)this).Logger.LogError((object)$"[NG+] Falha ao registrar RPC request: {arg}"); } } private void NGP_TryRegisterApplyRPC_Client() { if (_ngpClientApplyRegistered) { return; } ZRoutedRpc instance = ZRoutedRpc.instance; if (instance == null) { return; } try { instance.Register<ZPackage>("NGP_ResetApply", (Action<long, ZPackage>)NGP_OnResetApply_Client); _ngpClientApplyRegistered = true; } catch (ArgumentException) { _ngpClientApplyRegistered = true; } catch { } } private void NGP_TryRegisterEpicResetRPC_Server() { if (_epicResetRegistered) { return; } ZRoutedRpc instance = ZRoutedRpc.instance; ZNet instance2 = ZNet.instance; if (instance == null || (Object)(object)instance2 == (Object)null || !instance2.IsServer()) { return; } try { instance.Register<ZPackage>("NGP_EpicMMO_ResetTotalPoints", (Action<long, ZPackage>)NGP_OnEpicReset_Server); _epicResetRegistered = true; ((BaseUnityPlugin)this).Logger.LogInfo((object)"[NG+] RPC EpicMMO reset registrado (server)."); } catch (ArgumentException) { _epicResetRegistered = true; } catch (Exception arg) { ((BaseUnityPlugin)this).Logger.LogError((object)$"[NG+] Falha ao registrar RPC EpicMMO reset: {arg}"); } } private void NGP_OnEpicReset_Server(long sender, ZPackage pkg) { try { if (pkg != null) { string text = ""; ZNet instance = ZNet.instance; ZNetPeer val = ((instance != null) ? instance.GetPeer(sender) : null); if (val != null) { text = val.m_playerName ?? ""; } string text2 = pkg.ReadString(); if (!string.Equals(text, text2, StringComparison.OrdinalIgnoreCase)) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("[NG+] Pedido de Epic reset inválido: '" + text + "' tentou resetar '" + text2 + "'.")); } else if ((Object)(object)Console.instance != (Object)null) { string text3 = "\"" + text2 + "\""; ((Terminal)Console.instance).TryRunCommand("epicmmosystem reset_points " + text3, false, false); ((Terminal)Console.instance).TryRunCommand("epicmmosystem reset_totalpoints " + text3, false, false); ((Terminal)Console.instance).TryRunCommand("epicmmosystem recalc " + text3, false, false); ((BaseUnityPlugin)this).Logger.LogInfo((object)("[NG+] EpicMMO reset aplicado para " + text3 + " (points + totalpoints + recalc).")); } } } catch (Exception arg) { ((BaseUnityPlugin)this).Logger.LogError((object)$"[NG+] Erro NGP_OnEpicReset_Server: {arg}"); } } private void NGP_OnResetRequest_Server(long senderPeerId, ZPackage pkg) { //IL_0167: Unknown result type (might be due to invalid IL or missing references) //IL_016e: Expected O, but got Unknown try { if ((Object)(object)ZNet.instance == (Object)null || !ZNet.instance.IsServer()) { return; } string targetName = (pkg.ReadString() ?? string.Empty).Trim(); if (string.IsNullOrWhiteSpace(targetName)) { return; } ZNetPeer peer = ZNet.instance.GetPeer(senderPeerId); if (peer == null) { return; } ISocket socket = peer.m_rpc.GetSocket(); string text = ((socket != null) ? socket.GetHostName() : null) ?? ""; string text2 = peer.m_playerName ?? ""; string text3 = peer.m_uid.ToString(); if (!ZNet.instance.IsAdmin(text) && !ZNet.instance.IsAdmin(text2) && !ZNet.instance.IsAdmin(text3)) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("[NG+] " + text2 + " tentou ngplus_reset sem admin.")); return; } ZNetPeer val = ZNet.instance.GetPeers()?.FirstOrDefault((Func<ZNetPeer, bool>)((ZNetPeer p) => string.Equals(p.m_playerName, targetName, StringComparison.OrdinalIgnoreCase))); if (val == null) { ((BaseUnityPlugin)this).Logger.LogInfo((object)("[NG+] alvo '" + targetName + "' não está online.")); return; } ZPackage val2 = new ZPackage(); val2.Write(targetName); ZRoutedRpc.instance.InvokeRoutedRPC(val.m_uid, "NGP_ResetApply", new object[1] { val2 }); ((BaseUnityPlugin)this).Logger.LogInfo((object)$"[NG+] Reset aplicado ao alvo '{targetName}' (uid {val.m_uid})."); } catch (Exception arg) { ((BaseUnityPlugin)this).Logger.LogError((object)$"[NG+] Erro OnResetRequest_Server: {arg}"); } } private void NGP_OnResetApply_Client(long _sender, ZPackage pkg) { try { string text = (pkg.ReadString() ?? string.Empty).Trim(); Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null || !localPlayer.GetPlayerName().Equals(text, StringComparison.OrdinalIgnoreCase)) { return; } SEMan sEMan = ((Character)localPlayer).GetSEMan(); if (sEMan != null && sEMan.HaveStatusEffect(NGPlus_StatusEffect.SE_Hash)) { sEMan.RemoveStatusEffect(NGPlus_StatusEffect.SE_Hash, false); } localPlayer.m_customData?.Remove("radamanto.ngplus.active"); ZNetView nview = ((Character)localPlayer).m_nview; if (nview != null) { ZDO zDO = nview.GetZDO(); if (zDO != null) { zDO.Set("radamanto.ngplus.active", 0); } } NGPlus_EpicMMO.OnNgPlusDeactivated(localPlayer); ((Character)localPlayer).Message((MessageType)2, "Seu NG+ foi removido por um administrador.", 0, (Sprite)null); Chat instance = Chat.instance; if (instance != null) { ((Terminal)instance).AddString("<color=orange>[NG+]</color> NG+ removido do jogador <b>" + text + "</b>."); } } catch (Exception arg) { ((BaseUnityPlugin)this).Logger.LogError((object)$"[NG+] Erro OnResetApply_Client: {arg}"); } } } internal static class NGPlus_AssetLoader { private static AssetBundle? _bundle; private const string ResourceName = "NewGamePlus.assets.new_game"; internal static void Init() { LoadBundle(); } private static void LoadBundle() { if ((Object)(object)_bundle != (Object)null) { return; } try { Assembly executingAssembly = Assembly.GetExecutingAssembly(); using Stream stream = executingAssembly.GetManifestResourceStream("NewGamePlus.assets.new_game"); if (stream != null) { byte[] array = new byte[stream.Length]; stream.Read(array, 0, array.Length); _bundle = AssetBundle.LoadFromMemory(array); } } catch { } } internal static Sprite? GetSprite(string name) { LoadBundle(); if ((Object)(object)_bundle == (Object)null) { return null; } try { if (name == "ng_plus_icon") { name = "ngplus_ico"; } return _bundle.LoadAsset<Sprite>(name); } catch { return null; } } } [HarmonyPatch(typeof(Terminal), "InitTerminal")] internal static class NGPlus_Commands { [Serializable] [CompilerGenerated] private sealed class <>c { public static readonly <>c <>9 = new <>c(); public static ConsoleEvent <>9__0_0; public static ConsoleEvent <>9__0_1; internal void <Postfix>b__0_0(ConsoleEventArgs args) { if (!Object.op_Implicit((Object)(object)Player.m_localPlayer)) { return; } Player localPlayer = Player.m_localPlayer; Localization instance = Localization.instance; if (!NewGamePlusPlugin.CE_Enable.Value) { string text = ((instance != null) ? instance.Localize("$ngplus_disabled") : "O sistema NG+ está desativado na configuração do servidor."); string text2 = ((instance != null) ? instance.Localize("$ngplus_chat_disabled") : "<color=yellow>[NG+]</color> O sistema NG+ está desativado na configuração do servidor."); ((Character)localPlayer).Message((MessageType)2, text, 0, (Sprite)null); PrintChat(text2); return; } if (!NGPlus_KeyChecker.HasAllRequiredKeys(NewGamePlusPlugin.CE_RequiredPrivateKeys.Value)) { string text3 = ((instance != null) ? instance.Localize("$ngplus_missing_keys") : "Você ainda não completou todos os chefes necessários para o NG+."); string text4 = ((instance != null) ? instance.Localize("$ngplus_chat_missing_keys") : "<color=yellow>[NG+]</color> Você ainda não completou todos os chefes necessários para o NG+."); ((Character)localPlayer).Message((MessageType)2, text3, 0, (Sprite)null); PrintChat(text4); return; } if (localPlayer.m_customData != null && localPlayer.m_customData.TryGetValue("radamanto.ngplus.active", out var value) && value == "1") { string text5 = ((instance != null) ? instance.Localize("$ngplus_already_active") : "New Game Plus (NG+) já está ativo neste personagem."); string text6 = ((instance != null) ? instance.Localize("$ngplus_chat_already_active") : "<color=yellow>[NG+]</color> NG+ já está ativo neste personagem."); ((Character)localPlayer).Message((MessageType)2, text5, 0, (Sprite)null); PrintChat(text6); return; } NGPlus_SkillReset.ResetIfEnabled(localPlayer); SEMan sEMan = ((Character)localPlayer).GetSEMan(); if (sEMan != null && !sEMan.HaveStatusEffect(NGPlus_StatusEffect.SE_Hash)) { sEMan.AddStatusEffect(NGPlus_StatusEffect.SE_Hash, false, 0, 0f); } NGPlus_EpicMMO.OnNgPlusActivated(localPlayer); if (localPlayer.m_customData != null) { localPlayer.m_customData["radamanto.ngplus.active"] = "1"; } ZNetView nview = ((Character)localPlayer).m_nview; ZDO val = ((nview != null) ? nview.GetZDO() : null); if (val != null) { val.Set("radamanto.ngplus.active", 1); } bool value2 = NewGamePlusPlugin.CE_ResetSkillsOnNGPlus.Value; string text7 = (value2 ? "$ngplus_activated_center" : "$ngplus_activated_center_noskillreset"); string text8 = (value2 ? "$ngplus_chat_activated" : "$ngplus_chat_activated_noskillreset"); string text9 = ((instance != null) ? instance.Localize(text7) : (value2 ? "New Game Plus (NG+) ativado! Todas as suas skills foram resetadas." : "New Game Plus (NG+) ativado.")); string text10 = ((instance != null) ? instance.Localize(text8) : (value2 ? "<color=orange>[NG+]</color> New Game Plus (NG+) ativado! Todas as suas skills foram resetadas." : "<color=orange>[NG+]</color> New Game Plus (NG+) ativado.")); ((Character)localPlayer).Message((MessageType)2, text9, 0, (Sprite)null); PrintChat(text10); } internal void <Postfix>b__0_1(ConsoleEventArgs args) { //IL_0256: Unknown result type (might be due to invalid IL or missing references) //IL_025c: Expected O, but got Unknown //IL_010e: Unknown result type (might be due to invalid IL or missing references) //IL_0115: Expected O, but got Unknown <>c__DisplayClass0_0 CS$<>8__locals0 = new <>c__DisplayClass0_0(); if (args == null || args.Args.Length < 2) { Chat instance = Chat.instance; if (instance != null) { ((Terminal)instance).AddString("<color=yellow>[NG+]</color> Uso: /ngplus.remove <nome>"); } return; } CS$<>8__locals0.target = string.Join(" ", args.Args.Skip(1)).Trim(); if ((Object)(object)ZNet.instance == (Object)null) { Console instance2 = Console.instance; if (instance2 != null) { ((Terminal)instance2).AddString("[NG+] Servidor não disponível."); } return; } if (ZNet.instance.IsServer()) { ZNet instance3 = ZNet.instance; bool flag; if (instance3.IsDedicated()) { string text = (Object.op_Implicit((Object)(object)Player.m_localPlayer) ? Player.m_localPlayer.GetPlayerName() : ""); flag = instance3.IsAdmin(text); } else { flag = true; } if (!flag) { Console instance4 = Console.instance; if (instance4 != null) { ((Terminal)instance4).AddString("[NG+] Apenas administradores podem usar este comando."); } return; } ZPackage val = new ZPackage(); val.Write(CS$<>8__locals0.target); ZNetPeer val2 = instance3.GetPeers()?.FirstOrDefault((Func<ZNetPeer, bool>)((ZNetPeer p) => string.Equals(p.m_playerName, CS$<>8__locals0.target, StringComparison.OrdinalIgnoreCase))); if (val2 != null) { ZRoutedRpc.instance.InvokeRoutedRPC(val2.m_uid, "NGP_ResetApply", new object[1] { val }); Console instance5 = Console.instance; if (instance5 != null) { ((Terminal)instance5).AddString("[NG+] Reset aplicado (host → alvo)."); } } else if (Object.op_Implicit((Object)(object)Player.m_localPlayer) && Player.m_localPlayer.GetPlayerName().Equals(CS$<>8__locals0.target, StringComparison.OrdinalIgnoreCase)) { ZRoutedRpc.instance.InvokeRoutedRPC(ZRoutedRpc.Everybody, "NGP_ResetApply", new object[1] { val }); Console instance6 = Console.instance; if (instance6 != null) { ((Terminal)instance6).AddString("[NG+] Reset aplicado (host → self via broadcast)."); } } else { Console instance7 = Console.instance; if (instance7 != null) { ((Terminal)instance7).AddString("[NG+] Alvo '" + CS$<>8__locals0.target + "' não está online."); } } return; } ZRoutedRpc instance8 = ZRoutedRpc.instance; ZNetPeer serverPeer = ZNet.instance.GetServerPeer(); if (instance8 == null || serverPeer == null) { Console instance9 = Console.instance; if (instance9 != null) { ((Terminal)instance9).AddString("[NG+] Não foi possível contactar o servidor."); } return; } ZPackage val3 = new ZPackage(); val3.Write(CS$<>8__locals0.target); instance8.InvokeRoutedRPC(serverPeer.m_uid, "NGP_ResetRequest", new object[1] { val3 }); Console instance10 = Console.instance; if (instance10 != null) { ((Terminal)instance10).AddString("[NG+] Pedido de reset enviado ao servidor..."); } } } [CompilerGenerated] private sealed class <>c__DisplayClass0_0 { public string target; internal bool <Postfix>b__2(ZNetPeer p) { return string.Equals(p.m_playerName, target, StringComparison.OrdinalIgnoreCase); } } private static void Postfix(Terminal __instance) { //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_0036: 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_0041: Expected O, but got Unknown //IL_009a: 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_008b: Unknown result type (might be due to invalid IL or missing references) //IL_0091: Expected O, but got Unknown if (!Terminal.commands.ContainsKey("ngplus.start")) { object obj = <>c.<>9__0_0; if (obj == null) { ConsoleEvent val = delegate { if (Object.op_Implicit((Object)(object)Player.m_localPlayer)) { Player localPlayer = Player.m_localPlayer; Localization instance11 = Localization.instance; string value; if (!NewGamePlusPlugin.CE_Enable.Value) { string text2 = ((instance11 != null) ? instance11.Localize("$ngplus_disabled") : "O sistema NG+ está desativado na configuração do servidor."); string text3 = ((instance11 != null) ? instance11.Localize("$ngplus_chat_disabled") : "<color=yellow>[NG+]</color> O sistema NG+ está desativado na configuração do servidor."); ((Character)localPlayer).Message((MessageType)2, text2, 0, (Sprite)null); PrintChat(text3); } else if (!NGPlus_KeyChecker.HasAllRequiredKeys(NewGamePlusPlugin.CE_RequiredPrivateKeys.Value)) { string text4 = ((instance11 != null) ? instance11.Localize("$ngplus_missing_keys") : "Você ainda não completou todos os chefes necessários para o NG+."); string text5 = ((instance11 != null) ? instance11.Localize("$ngplus_chat_missing_keys") : "<color=yellow>[NG+]</color> Você ainda não completou todos os chefes necessários para o NG+."); ((Character)localPlayer).Message((MessageType)2, text4, 0, (Sprite)null); PrintChat(text5); } else if (localPlayer.m_customData != null && localPlayer.m_customData.TryGetValue("radamanto.ngplus.active", out value) && value == "1") { string text6 = ((instance11 != null) ? instance11.Localize("$ngplus_already_active") : "New Game Plus (NG+) já está ativo neste personagem."); string text7 = ((instance11 != null) ? instance11.Localize("$ngplus_chat_already_active") : "<color=yellow>[NG+]</color> NG+ já está ativo neste personagem."); ((Character)localPlayer).Message((MessageType)2, text6, 0, (Sprite)null); PrintChat(text7); } else { NGPlus_SkillReset.ResetIfEnabled(localPlayer); SEMan sEMan = ((Character)localPlayer).GetSEMan(); if (sEMan != null && !sEMan.HaveStatusEffect(NGPlus_StatusEffect.SE_Hash)) { sEMan.AddStatusEffect(NGPlus_StatusEffect.SE_Hash, false, 0, 0f); } NGPlus_EpicMMO.OnNgPlusActivated(localPlayer); if (localPlayer.m_customData != null) { localPlayer.m_customData["radamanto.ngplus.active"] = "1"; } ZNetView nview = ((Character)localPlayer).m_nview; ZDO val6 = ((nview != null) ? nview.GetZDO() : null); if (val6 != null) { val6.Set("radamanto.ngplus.active", 1); } bool value2 = NewGamePlusPlugin.CE_ResetSkillsOnNGPlus.Value; string text8 = (value2 ? "$ngplus_activated_center" : "$ngplus_activated_center_noskillreset"); string text9 = (value2 ? "$ngplus_chat_activated" : "$ngplus_chat_activated_noskillreset"); string text10 = ((instance11 != null) ? instance11.Localize(text8) : (value2 ? "New Game Plus (NG+) ativado! Todas as suas skills foram resetadas." : "New Game Plus (NG+) ativado.")); string text11 = ((instance11 != null) ? instance11.Localize(text9) : (value2 ? "<color=orange>[NG+]</color> New Game Plus (NG+) ativado! Todas as suas skills foram resetadas." : "<color=orange>[NG+]</color> New Game Plus (NG+) ativado.")); ((Character)localPlayer).Message((MessageType)2, text10, 0, (Sprite)null); PrintChat(text11); } } }; <>c.<>9__0_0 = val; obj = (object)val; } new ConsoleCommand("ngplus.start", "ngplus.start - Ativa o New Game Plus (NG+).", (ConsoleEvent)obj, false, false, false, false, false, (ConsoleOptionsFetcher)null, false, false, false); } if (Terminal.commands.ContainsKey("ngplus.remove")) { return; } object obj2 = <>c.<>9__0_1; if (obj2 == null) { ConsoleEvent val2 = delegate(ConsoleEventArgs args) { //IL_0256: Unknown result type (might be due to invalid IL or missing references) //IL_025c: Expected O, but got Unknown //IL_010e: Unknown result type (might be due to invalid IL or missing references) //IL_0115: Expected O, but got Unknown if (args == null || args.Args.Length < 2) { Chat instance = Chat.instance; if (instance != null) { ((Terminal)instance).AddString("<color=yellow>[NG+]</color> Uso: /ngplus.remove <nome>"); } } else { string target = string.Join(" ", args.Args.Skip(1)).Trim(); if ((Object)(object)ZNet.instance == (Object)null) { Console instance2 = Console.instance; if (instance2 != null) { ((Terminal)instance2).AddString("[NG+] Servidor não disponível."); } } else if (ZNet.instance.IsServer()) { ZNet instance3 = ZNet.instance; bool flag; if (instance3.IsDedicated()) { string text = (Object.op_Implicit((Object)(object)Player.m_localPlayer) ? Player.m_localPlayer.GetPlayerName() : ""); flag = instance3.IsAdmin(text); } else { flag = true; } if (!flag) { Console instance4 = Console.instance; if (instance4 != null) { ((Terminal)instance4).AddString("[NG+] Apenas administradores podem usar este comando."); } } else { ZPackage val3 = new ZPackage(); val3.Write(target); ZNetPeer val4 = instance3.GetPeers()?.FirstOrDefault((Func<ZNetPeer, bool>)((ZNetPeer p) => string.Equals(p.m_playerName, target, StringComparison.OrdinalIgnoreCase))); if (val4 != null) { ZRoutedRpc.instance.InvokeRoutedRPC(val4.m_uid, "NGP_ResetApply", new object[1] { val3 }); Console instance5 = Console.instance; if (instance5 != null) { ((Terminal)instance5).AddString("[NG+] Reset aplicado (host → alvo)."); } } else if (Object.op_Implicit((Object)(object)Player.m_localPlayer) && Player.m_localPlayer.GetPlayerName().Equals(target, StringComparison.OrdinalIgnoreCase)) { ZRoutedRpc.instance.InvokeRoutedRPC(ZRoutedRpc.Everybody, "NGP_ResetApply", new object[1] { val3 }); Console instance6 = Console.instance; if (instance6 != null) { ((Terminal)instance6).AddString("[NG+] Reset aplicado (host → self via broadcast)."); } } else { Console instance7 = Console.instance; if (instance7 != null) { ((Terminal)instance7).AddString("[NG+] Alvo '" + target + "' não está online."); } } } } else { ZRoutedRpc instance8 = ZRoutedRpc.instance; ZNetPeer serverPeer = ZNet.instance.GetServerPeer(); if (instance8 == null || serverPeer == null) { Console instance9 = Console.instance; if (instance9 != null) { ((Terminal)instance9).AddString("[NG+] Não foi possível contactar o servidor."); } } else { ZPackage val5 = new ZPackage(); val5.Write(target); instance8.InvokeRoutedRPC(serverPeer.m_uid, "NGP_ResetRequest", new object[1] { val5 }); Console instance10 = Console.instance; if (instance10 != null) { ((Terminal)instance10).AddString("[NG+] Pedido de reset enviado ao servidor..."); } } } } }; <>c.<>9__0_1 = val2; obj2 = (object)val2; } new ConsoleCommand("ngplus.remove", "ngplus.remove <NOME> - Remove o NG+ do jogador (apenas admin).", (ConsoleEvent)obj2, false, true, false, false, false, (ConsoleOptionsFetcher)null, false, false, false); } private static void PrintChat(string text) { if ((Object)(object)Chat.instance != (Object)null) { ((Terminal)Chat.instance).AddString(text); return; } Console instance = Console.instance; if (instance != null) { ((Terminal)instance).AddString(text); } } } [HarmonyPatch(typeof(Player), "OnSpawned")] internal static class NGPlus_PlayerOnSpawnedPatch { private static void Postfix(Player __instance) { if ((Object)(object)__instance != (Object)(object)Player.m_localPlayer) { return; } Dictionary<string, string> customData = __instance.m_customData; if (customData != null && customData.TryGetValue("radamanto.ngplus.active", out var value) && !(value != "1")) { SEMan sEMan = ((Character)__instance).GetSEMan(); if (sEMan != null && !sEMan.HaveStatusEffect(NGPlus_StatusEffect.SE_Hash)) { sEMan.AddStatusEffect(NGPlus_StatusEffect.SE_Hash, false, 0, 0f); } } } } [HarmonyPatch] internal static class NGPlus_DamagePatch { [HarmonyPatch(typeof(Character), "Damage", new Type[] { typeof(HitData) })] [HarmonyPrefix] private static void Prefix(Character __instance, ref HitData hit) { if (!NewGamePlusPlugin.CE_Enable.Value) { return; } Player val = (Player)(object)((__instance is Player) ? __instance : null); if (val != null) { SEMan sEMan = ((Character)val).GetSEMan(); if (sEMan != null && sEMan.HaveStatusEffect(NGPlus_StatusEffect.SE_Hash)) { float value = NewGamePlusPlugin.CE_DamageTakenPercent.Value; if (Mathf.Abs(value) > 0.001f) { float multiplier = 1f + value / 100f; ScaleDamage(ref hit, multiplier); } } } Character attacker = hit.GetAttacker(); Player val2 = (Player)(object)((attacker is Player) ? attacker : null); if (!((Object)(object)val2 != (Object)null)) { return; } SEMan sEMan2 = ((Character)val2).GetSEMan(); if (sEMan2 != null && sEMan2.HaveStatusEffect(NGPlus_StatusEffect.SE_Hash)) { float value2 = NewGamePlusPlugin.CE_DamageDonePercent.Value; if (Mathf.Abs(value2) > 0.001f) { float multiplier2 = 1f + value2 / 100f; ScaleDamage(ref hit, multiplier2); } } } private static void ScaleDamage(ref HitData hit, float multiplier) { //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_009f: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: Unknown result type (might be due to invalid IL or missing references) if (!(Mathf.Abs(multiplier - 1f) < 0.001f)) { DamageTypes damage = hit.m_damage; damage.m_blunt *= multiplier; damage.m_slash *= multiplier; damage.m_pierce *= multiplier; damage.m_chop *= multiplier; damage.m_pickaxe *= multiplier; damage.m_fire *= multiplier; damage.m_frost *= multiplier; damage.m_lightning *= multiplier; damage.m_poison *= multiplier; damage.m_spirit *= multiplier; hit.m_damage = damage; } } } internal static class NGPlus_KeyChecker { private const string WapAssemblyName = "VentureValheim.Progression"; private const string WapAltAssemblyName = "World_Advancement_Progression"; private const string WapKeyManagerType = "VentureValheim.Progression.KeyManager"; private static bool _initialized; private static bool _hasWap; private static Type? _keyManagerType; private static PropertyInfo? _instanceProperty; private static MethodInfo? _hasPrivateKeyMethod; public static bool IsUsingPrivateKeys { get { EnsureInit(); return _hasWap; } } private static void EnsureInit() { if (_initialized) { return; } _initialized = true; try { Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies(); foreach (Assembly assembly in assemblies) { string text = assembly.GetName().Name ?? string.Empty; if (!text.Equals("VentureValheim.Progression", StringComparison.OrdinalIgnoreCase) && !text.Equals("World_Advancement_Progression", StringComparison.OrdinalIgnoreCase)) { continue; } _keyManagerType = assembly.GetType("VentureValheim.Progression.KeyManager"); if (!(_keyManagerType == null)) { _instanceProperty = _keyManagerType.GetProperty("Instance", BindingFlags.Static | BindingFlags.Public); _hasPrivateKeyMethod = _keyManagerType.GetMethod("HasPrivateKey", BindingFlags.Instance | BindingFlags.Public, null, new Type[1] { typeof(string) }, null); if (_instanceProperty != null && _hasPrivateKeyMethod != null) { _hasWap = true; break; } } } } catch { _hasWap = false; } } private static bool HasPrivateKey(string key) { EnsureInit(); if (!_hasWap || _keyManagerType == null || _instanceProperty == null || _hasPrivateKeyMethod == null) { return false; } try { object value = _instanceProperty.GetValue(null); if (value == null) { return false; } object obj = _hasPrivateKeyMethod.Invoke(value, new object[1] { key }); bool flag = default(bool); int num; if (obj is bool) { flag = (bool)obj; num = 1; } else { num = 0; } return (byte)((uint)num & (flag ? 1u : 0u)) != 0; } catch { return false; } } private static bool HasGlobalKey(string key) { try { ZoneSystem instance = ZoneSystem.instance; if ((Object)(object)instance == (Object)null) { return false; } return instance.GetGlobalKey(key); } catch { return false; } } private static bool HasKey(string key) { EnsureInit(); if (_hasWap) { return HasPrivateKey(key); } return HasGlobalKey(key); } public static bool HasAllRequiredKeys(string csv) { if (string.IsNullOrWhiteSpace(csv)) { return false; } string[] array = csv.Split(new char[2] { ',', ';' }, StringSplitOptions.RemoveEmptyEntries); bool result = false; string[] array2 = array; foreach (string text in array2) { string text2 = text.Trim(); if (text2.Length != 0) { result = true; if (!HasKey(text2)) { return false; } } } return result; } } internal static class NGPlus_OverheadIcon { private const string IconObjectName = "NGPlus_OverheadIcon"; private const float FadeNearDistance = 1f; private const float FadeFarDistance = 15f; internal static void UpdateForPlayer(Player player, bool hasBuff) { if (!Object.op_Implicit((Object)(object)player)) { return; } Transform val = ((Component)player).transform.Find("NGPlus_OverheadIcon"); if (!hasBuff || !NewGamePlusPlugin.CE_ShowOverheadIcon.Value) { if (Object.op_Implicit((Object)(object)val)) { Object.Destroy((Object)(object)((Component)val).gameObject); } } else if (!Object.op_Implicit((Object)(object)val)) { CreateIcon(player); } } private static void CreateIcon(Player player) { //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Expected O, but got Unknown //IL_0079: Unknown result type (might be due to invalid IL or missing references) //IL_0094: Unknown result type (might be due to invalid IL or missing references) //IL_00c6: Unknown result type (might be due to invalid IL or missing references) Sprite sprite = NGPlus_AssetLoader.GetSprite("star_ico"); if (Object.op_Implicit((Object)(object)sprite)) { float num = Mathf.Max(0.1f, NewGamePlusPlugin.CE_OverheadIconHeight.Value); float num2 = Mathf.Max(0.01f, NewGamePlusPlugin.CE_OverheadIconScale.Value); GameObject val = new GameObject("NGPlus_OverheadIcon"); val.transform.SetParent(((Component)player).transform, false); val.transform.localPosition = new Vector3(0f, num, 0f); Vector3 val2 = default(Vector3); ((Vector3)(ref val2))..ctor(num2, num2, num2); val.transform.localScale = val2; SpriteRenderer val3 = val.AddComponent<SpriteRenderer>(); val3.sprite = sprite; ((Renderer)val3).sortingOrder = 5000; NGPlus_OverheadBillboard nGPlus_OverheadBillboard = val.AddComponent<NGPlus_OverheadBillboard>(); nGPlus_OverheadBillboard.Init(val3, val2, 1f, 15f); } } } internal sealed class NGPlus_OverheadBillboard : MonoBehaviour { private SpriteRenderer? _renderer; private Vector3 _baseScale; private float _fadeNear; private float _fadeFar; public void Init(SpriteRenderer renderer, Vector3 baseScale, float fadeNear, float fadeFar) { //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_000a: Unknown result type (might be due to invalid IL or missing references) _renderer = renderer; _baseScale = baseScale; _fadeNear = fadeNear; _fadeFar = fadeFar; } private void LateUpdate() { //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Unknown result type (might be due to invalid IL or missing references) //IL_0091: Unknown result type (might be due to invalid IL or missing references) //IL_009c: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Unknown result type (might be due to invalid IL or missing references) //IL_0103: Unknown result type (might be due to invalid IL or missing references) //IL_0108: Unknown result type (might be due to invalid IL or missing references) //IL_0118: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_renderer == (Object)null) { return; } Camera main = Camera.main; if (Object.op_Implicit((Object)(object)main)) { Vector3 val = ((Component)main).transform.position - ((Component)this).transform.position; if (((Vector3)(ref val)).sqrMagnitude > 0.001f) { ((Component)this).transform.rotation = Quaternion.LookRotation(-val); } ((Component)this).transform.localScale = _baseScale; float num = Vector3.Distance(((Component)this).transform.position, ((Component)main).transform.position); float a; if (num <= _fadeNear) { a = 0f; } else if (num >= _fadeFar) { a = 1f; } else { float num2 = (num - _fadeNear) / (_fadeFar - _fadeNear); a = Mathf.Clamp01(num2); } Color color = _renderer.color; color.a = a; _renderer.color = color; } } } [HarmonyPatch(typeof(Player), "Update")] internal static class NGPlus_Player_Update_OverheadIcon { private static void Postfix(Player __instance) { if (Object.op_Implicit((Object)(object)__instance) && !((Character)__instance).IsDead()) { SEMan sEMan = ((Character)__instance).GetSEMan(); bool hasBuff = sEMan != null && sEMan.HaveStatusEffect(NGPlus_StatusEffect.SE_Hash); NGPlus_OverheadIcon.UpdateForPlayer(__instance, hasBuff); } } } [HarmonyPatch(typeof(SE_Stats), "Setup")] internal static class NGPlus_RegenerationPatch { private static void Postfix(SE_Stats __instance) { if (((StatusEffect)__instance).m_nameHash == NGPlus_StatusEffect.SE_Hash) { float value = NewGamePlusPlugin.CE_RegenHealthPercent.Value; if (Mathf.Abs(value) > 0.001f) { float num = 1f + value / 100f; __instance.m_healthRegenMultiplier *= num; } float value2 = NewGamePlusPlugin.CE_RegenStaminaPercent.Value; if (Mathf.Abs(value2) > 0.001f) { float num2 = 1f + value2 / 100f; __instance.m_staminaRegenMultiplier *= num2; } float value3 = NewGamePlusPlugin.CE_RegenEitrPercent.Value; if (Mathf.Abs(value3) > 0.001f) { float num3 = 1f + value3 / 100f; __instance.m_eitrRegenMultiplier *= num3; } } } } public class NGPlus_StatusEffect : SE_Stats { [HarmonyPatch(typeof(ObjectDB), "Awake")] private class Patch_ObjectDB_Awake { private static void Postfix(ObjectDB __instance) { EnsureRegistered(); } } [HarmonyPatch(typeof(ObjectDB), "CopyOtherDB")] private class Patch_ObjectDB_CopyOtherDB { private static void Postfix(ObjectDB __instance) { EnsureRegistered(); } } public const string SE_Name = "NG_BossDifficulty"; public static readonly int SE_Hash = StringExtensionMethods.GetStableHashCode("NG_BossDifficulty"); public override string GetIconText() { return ""; } public override string GetTooltipString() { Localization instance = Localization.instance; string text = ((instance != null) ? instance.Localize("$ngplus_se_header") : "Concedido após derrotar os chefes configurados."); float value = NewGamePlusPlugin.CE_DamageDonePercent.Value; float value2 = NewGamePlusPlugin.CE_DamageTakenPercent.Value; float value3 = NewGamePlusPlugin.CE_RegenHealthPercent.Value; float value4 = NewGamePlusPlugin.CE_RegenStaminaPercent.Value; float value5 = NewGamePlusPlugin.CE_RegenEitrPercent.Value; float value6 = NewGamePlusPlugin.CE_CarryWeightAdd.Value; string text2 = BuildPercentLine(value, "$ngplus_se_line_dealt_nochange", "$ngplus_se_line_dealt"); string text3 = BuildPercentLine(value2, "$ngplus_se_line_taken_nochange", "$ngplus_se_line_taken"); string text4 = BuildWeightLine(value6, "$ngplus_se_line_weight_nochange", "$ngplus_se_line_weight"); string text5 = BuildPercentLine(value3, "$ngplus_se_line_regen_hp_nochange", "$ngplus_se_line_regen_hp"); string text6 = BuildPercentLine(value4, "$ngplus_se_line_regen_stamina_nochange", "$ngplus_se_line_regen_stamina"); string text7 = BuildPercentLine(value5, "$ngplus_se_line_regen_eitr_nochange", "$ngplus_se_line_regen_eitr"); string text8 = string.Empty; if (EpicMMOSystem_API.IsInstalled) { float num = Mathf.Max(0f, NewGamePlusPlugin.CE_EpicMMO_XpMultiplierNGPlus.Value); float delta = (num - 1f) * 100f; text8 = BuildPercentLine(delta, "$ngplus_se_line_epicxp_nochange", "$ngplus_se_line_epicxp"); } string text9 = BuildPortalLine(); string text10 = text + "\n\n" + text2 + "\n" + text3 + "\n" + text4 + "\n" + text5 + "\n" + text6 + "\n" + text7; if (!string.IsNullOrEmpty(text8)) { text10 = text10 + "\n" + text8; } if (!string.IsNullOrEmpty(text9)) { text10 = text10 + "\n" + text9; } return text10; } public override void Setup(Character character) { ((SE_Stats)this).Setup(character); try { Player val = (Player)(object)((character is Player) ? character : null); if (val != null && (Object)(object)val == (Object)(object)Player.m_localPlayer && Type.GetType("EpicMMOSystem.EpicMMOSystem, EpicMMOSystem") != null) { float singleRate = Mathf.Max(0f, NewGamePlusPlugin.CE_EpicMMO_XpMultiplierNGPlus.Value); EpicMMOSystem_API.SetSingleRate(singleRate); } } catch { } } public override void Stop() { try { Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer != (Object)null && Type.GetType("EpicMMOSystem.EpicMMOSystem, EpicMMOSystem") != null) { EpicMMOSystem_API.SetSingleRate(1f); } } catch { } ((StatusEffect)this).Stop(); } private static string BuildPercentLine(float delta, string noChangeKey, string lineKey) { Localization instance = Localization.instance; if (Mathf.Abs(delta) < 0.001f) { return (instance != null) ? instance.Localize(noChangeKey) : "Sem alteração"; } string text = Mathf.Abs(delta).ToString("0.#") + "%"; if (delta > 0f) { text = "+" + text; } else if (delta < 0f) { text = "-" + text; } string arg = ((delta > 0f) ? ("<color=orange>" + text + "</color>") : ("<color=red>" + text + "</color>")); string format = ((instance != null) ? instance.Localize(lineKey) : "{0}"); return string.Format(format, arg); } private static string BuildWeightLine(float add, string noChangeKey, string lineKey) { Localization instance = Localization.instance; if (Mathf.Abs(add) < 0.001f) { return (instance != null) ? instance.Localize(noChangeKey) : "Incremento de capacidade de carga: sem alteração"; } string text = Mathf.Abs(add).ToString("0"); if (add > 0f) { text = "+" + text; } else if (add < 0f) { text = "-" + text; } string arg = ((add > 0f) ? ("<color=orange>" + text + "</color>") : ("<color=red>" + text + "</color>")); string format = ((instance != null) ? instance.Localize(lineKey) : "Incremento de capacidade de carga: {0}"); return string.Format(format, arg); } private static string BuildPortalLine() { if (!NewGamePlusPlugin.CE_IgnorePortalRestrictionsWithNGPlus.Value) { return string.Empty; } Localization instance = Localization.instance; return (instance != null) ? instance.Localize("$ngplus_se_line_portal") : "Pode usar portais com qualquer item."; } public static void EnsureRegistered() { if (Object.op_Implicit((Object)(object)ObjectDB.instance) && ObjectDB.instance.m_StatusEffects != null && !ObjectDB.instance.m_StatusEffects.Any((StatusEffect se) => Object.op_Implicit((Object)(object)se) && ((Object)se).name == "NG_BossDifficulty")) { AddSE(ObjectDB.instance); } } private static void AddSE(ObjectDB odb) { NGPlus_StatusEffect nGPlus_StatusEffect = ScriptableObject.CreateInstance<NGPlus_StatusEffect>(); ((Object)nGPlus_StatusEffect).name = "NG_BossDifficulty"; ((StatusEffect)nGPlus_StatusEffect).m_nameHash = SE_Hash; ((StatusEffect)nGPlus_StatusEffect).m_icon = NGPlus_AssetLoader.GetSprite("ng_plus_icon"); ((StatusEffect)nGPlus_StatusEffect).m_name = "NG+"; odb.m_StatusEffects.Add((StatusEffect)(object)nGPlus_StatusEffect); } } internal static class NGPlus_Translations { internal static void Apply() { Localization instance = Localization.instance; if (instance != null) { string text = TryGetLanguage(instance) ?? "English"; string text2 = text.ToLowerInvariant(); bool flag = text2.Contains("portuguese") || text2.Contains("português") || text2.Contains("brazil") || text2 == "pt" || text2.StartsWith("pt-"); instance.AddWord("ngplus_disabled", flag ? "O sistema NG+ está desativado na configuração do servidor." : "The NG+ system is disabled in the server configuration."); instance.AddWord("ngplus_missing_keys", flag ? "Você ainda não completou todos os chefes necessários para o NG+." : "You have not defeated all required bosses for NG+."); instance.AddWord("ngplus_already_active", flag ? "New Game Plus (NG+) já está ativo neste personagem." : "New Game Plus (NG+) is already active on this character."); instance.AddWord("ngplus_activated_center", flag ? "New Game Plus (NG+) ativado! Todas as suas skills foram resetadas." : "New Game Plus (NG+) activated! All your skills were reset."); instance.AddWord("ngplus_removed_center", flag ? "Seu NG+ foi removido por um administrador." : "Your NG+ has been removed by an administrator."); instance.AddWord("ngplus_chat_disabled", flag ? "<color=yellow>[NG+]</color> O sistema NG+ está desativado na configuração do servidor." : "<color=yellow>[NG+]</color> The NG+ system is disabled in the server configuration."); instance.AddWord("ngplus_chat_missing_keys", flag ? "<color=yellow>[NG+]</color> Você ainda não completou todos os chefes necessários para o NG+." : "<color=yellow>[NG+]</color> You have not defeated all required bosses for NG+."); instance.AddWord("ngplus_chat_already_active", flag ? "<color=yellow>[NG+]</color> NG+ já está ativo neste personagem." : "<color=yellow>[NG+]</color> NG+ is already active on this character."); instance.AddWord("ngplus_chat_activated", flag ? "<color=orange>[NG+]</color> New Game Plus (NG+) ativado! Todas as suas skills foram resetadas." : "<color=orange>[NG+]</color> New Game Plus (NG+) activated! All your skills were reset."); instance.AddWord("ngplus_activated_center_noskillreset", flag ? "New Game Plus (NG+) ativado!" : "New Game Plus (NG+) activated!"); instance.AddWord("ngplus_chat_activated_noskillreset", flag ? "<color=orange>[NG+]</color> New Game Plus (NG+) ativado." : "<color=orange>[NG+]</color> New Game Plus (NG+) activated."); instance.AddWord("ngplus_chat_reset_usage", flag ? "<color=yellow>[NG+]</color> Uso correto: <color=white>/ngplus_reset <nome do jogador></color>" : "<color=yellow>[NG+]</color> Correct usage: <color=white>/ngplus_reset <player name></color>"); instance.AddWord("ngplus_chat_player_not_found", flag ? "<color=red>[NG+]</color> Jogador <b>{0}</b> não encontrado." : "<color=red>[NG+]</color> Player <b>{0}</b> not found."); instance.AddWord("ngplus_chat_reset_done", flag ? "<color=orange>[NG+]</color> NG+ removido do jogador <b>{0}</b>." : "<color=orange>[NG+]</color> NG+ removed from player <b>{0}</b>."); instance.AddWord("ngplus_se_name", flag ? "New Game Plus (NG+)" : "New Game Plus (NG+)"); instance.AddWord("ngplus_se_tooltip", flag ? "Ajusta a dificuldade do personagem conforme as configurações do NG+." : "Adjusts character difficulty based on NG+ settings."); instance.AddWord("ngplus_se_header", flag ? "Concedido após derrotar os chefes configurados." : "Granted after defeating the configured bosses."); instance.AddWord("ngplus_se_line_dealt_nochange", flag ? "Dano causado: sem alteração" : "Damage dealt: no change"); instance.AddWord("ngplus_se_line_dealt", flag ? "Dano causado: {0}" : "Damage dealt: {0}"); instance.AddWord("ngplus_se_line_taken_nochange", flag ? "Dano recebido: sem alteração" : "Damage taken: no change"); instance.AddWord("ngplus_se_line_taken", flag ? "Dano recebido: {0}" : "Damage taken: {0}"); instance.AddWord("ngplus_se_line_done_nochange", flag ? "Dano causado: sem mudança" : "Damage dealt: no change"); instance.AddWord("ngplus_se_line_done", flag ? "Dano causado: {0}" : "Damage dealt: {0}"); instance.AddWord("ngplus_se_line_taken_nochange_alt", flag ? "Dano recebido: sem mudança" : "Damage taken: no change"); instance.AddWord("ngplus_se_line_taken_alt", flag ? "Dano recebido: {0}" : "Damage taken: {0}"); instance.AddWord("ngplus_se_line_weight_nochange", flag ? "Incremento de capacidade de carga: sem alteração" : "Carry weight bonus: no change"); instance.AddWord("ngplus_se_line_weight", flag ? "Incremento de capacidade de carga: {0}" : "Carry weight bonus: {0}"); instance.AddWord("ngplus_se_line_regen_hp_nochange", flag ? "Regeneração de vida: sem alteração" : "Health regeneration: no change"); instance.AddWord("ngplus_se_line_regen_hp", flag ? "Regeneração de vida: {0}" : "Health regeneration: {0}"); instance.AddWord("ngplus_se_line_regen_stamina_nochange", flag ? "Regeneração de vigor: sem alteração" : "Stamina regeneration: no change"); instance.AddWord("ngplus_se_line_regen_stamina", flag ? "Regeneração de vigor: {0}" : "Stamina regeneration: {0}"); instance.AddWord("ngplus_se_line_regen_eitr_nochange", flag ? "Regeneração de éter: sem alteração" : "Eitr regeneration: no change"); instance.AddWord("ngplus_se_line_regen_eitr", flag ? "Regeneração de éter: {0}" : "Eitr regeneration: {0}"); instance.AddWord("ngplus_se_line_portal", flag ? "Pode usar portais com qualquer item." : "Can use portals with any item."); instance.AddWord("ngplus_se_line_portal_bypass", flag ? "Portais: restrições ignoradas" : "Portals: restrictions ignored"); instance.AddWord("ngplus_se_line_epicxp_nochange", flag ? "XP (EpicMMO): sem mudança" : "EpicMMO XP: no change"); instance.AddWord("ngplus_se_line_epicxp", flag ? "XP (EpicMMO): {0}" : "EpicMMO XP: {0}"); } } private static string? TryGetLanguage(Localization loc) { Type type = ((object)loc).GetType(); string[] array = new string[3] { "GetSelectedLanguage", "GetLanguage", "GetCurrentLanguage" }; string[] array2 = array; foreach (string name in array2) { MethodInfo method = type.GetMethod(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (method != null && method.ReturnType == typeof(string) && method.GetParameters().Length == 0) { string text = method.Invoke(loc, null) as string; if (!string.IsNullOrEmpty(text)) { return text; } } } FieldInfo field = type.GetField("m_language", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (field != null && field.GetValue(loc) is string text2 && !string.IsNullOrEmpty(text2)) { return text2; } return null; } } [HarmonyPatch(typeof(Localization), "SetupLanguage")] internal static class NGPlus_Translations_Patch { private static void Postfix() { NGPlus_Translations.Apply(); try { NGPlus_StatusEffect.EnsureRegistered(); } catch { } } } [HarmonyPatch(typeof(Inventory), "IsTeleportable")] internal static class NGPlus_PortalBypass { private static void Postfix(Inventory __instance, ref bool __result) { try { if (__result || !NewGamePlusPlugin.CE_IgnorePortalRestrictionsWithNGPlus.Value) { return; } Player localPlayer = Player.m_localPlayer; if (!((Object)(object)localPlayer == (Object)null) && ((Humanoid)localPlayer).GetInventory() == __instance) { SEMan sEMan = ((Character)localPlayer).GetSEMan(); if (sEMan != null && sEMan.HaveStatusEffect(NGPlus_StatusEffect.SE_Hash)) { __result = true; } } } catch { } } } internal static class NGPlus_SkillReset { internal static void ResetIfEnabled(Player player) { //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_0063: Invalid comparison between Unknown and I4 //IL_006e: Unknown result type (might be due to invalid IL or missing references) if (!NewGamePlusPlugin.CE_ResetSkillsOnNGPlus.Value || (Object)(object)player == (Object)null) { return; } Skills skills = player.m_skills; if ((Object)(object)skills == (Object)null) { return; } foreach (SkillType value in Enum.GetValues(typeof(SkillType))) { if ((int)value != 0) { skills.ResetSkill(value); } } } } } namespace API { public static class EpicMMOSystem_API { private enum API_State { NotReady, NotInstalled, Ready } public enum Attribut { Strength, Agility, Intellect, Body, Vigour, Special } private static API_State state; private static MethodInfo? eGetLevel; private static MethodInfo? eAddExp; private static MethodInfo? eGetAttribute; private static MethodInfo? eGetAttributeRusty; private static MethodInfo? eSetSingleRate; public static bool IsInstalled { get { Init(); return state == API_State.Ready; } } public static int GetLevel() { Init(); return (eGetLevel != null) ? ((int)eGetLevel.Invoke(null, null)) : 0; } public static int GetAttribute(Attribut attribute) { Init(); return (eGetAttribute != null) ? ((int)eGetAttribute.Invoke(null, new object[1] { attribute })) : 0; } public static int GetAttributeRusty(string attribute) { Init(); return (eGetAttributeRusty != null) ? ((int)eGetAttributeRusty.Invoke(null, new object[1] { attribute })) : 0; } public static void AddExp(int value) { Init(); eAddExp?.Invoke(null, new object[1] { value }); } public static void SetSingleRate(float rate) { Init(); eSetSingleRate?.Invoke(null, new object[1] { rate }); } private static void Init() { API_State aPI_State = state; if ((uint)(aPI_State - 1) <= 1u) { return; } if (Type.GetType("EpicMMOSystem.EpicMMOSystem, EpicMMOSystem") == null) { state = API_State.NotInstalled; return; } Type type = Type.GetType("API.EMMOS_API, EpicMMOSystem"); if (type == null) { state = API_State.NotInstalled; return; } eGetLevel = type.GetMethod("GetLevel", BindingFlags.Static | BindingFlags.Public); eAddExp = type.GetMethod("AddExp", BindingFlags.Static | BindingFlags.Public); eGetAttribute = type.GetMethod("GetAttribute", BindingFlags.Static | BindingFlags.Public); eGetAttributeRusty = type.GetMethod("GetAttributeRusty", BindingFlags.Static | BindingFlags.Public); eSetSingleRate = type.GetMethod("SetSingleRate", BindingFlags.Static | BindingFlags.Public); state = API_State.Ready; } } } namespace ServerSync { [PublicAPI] internal abstract class OwnConfigEntryBase { public object? LocalBaseValue; public bool SynchronizedConfig = true; public abstract ConfigEntryBase BaseConfig { get; } } [PublicAPI] internal class SyncedConfigEntry<T> : OwnConfigEntryBase { public readonly ConfigEntry<T> SourceConfig; public override ConfigEntryBase BaseConfig => (ConfigEntryBase)(object)SourceConfig; public T Value { get { return SourceConfig.Value; } set { SourceConfig.Value = value; } } public SyncedConfigEntry(ConfigEntry<T> sourceConfig) { SourceConfig = sourceConfig; base..ctor(); } public void AssignLocalValue(T value) { if (LocalBaseValue == null) { Value = value; } else { LocalBaseValue = value; } } } internal abstract class CustomSyncedValueBase { 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; this.ValueChanged?.Invoke(); } } public event Action? ValueChanged; 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] internal sealed class CustomSyncedValue<T> : CustomSyncedValueBase { public T Value { get { return (T)base.BoxedValue; } set { base.BoxedValue = value; } } 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; } } } internal class ConfigurationManagerAttributes { [UsedImplicitly] public bool? ReadOnly = false; } [PublicAPI] internal 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<ZPackage>(configSync2.Name + " ConfigSync", (Action<long, ZPackage>)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<ZNetPeer> 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<string> CurrentList = new List<string>(adminList.GetList()); while (true) { yield return (object)new WaitForSeconds(30f); if (!adminList.GetList().SequenceEqual(CurrentList)) { CurrentList = new List<string>(adminList.GetList()); List<ZNetPeer> adminPeer = 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(); List<ZNetPeer> nonAdminPeer = ZNet.instance.GetPeers().Except(adminPeer).ToList(); SendAdmin(nonAdminPeer, isAdmin: false); SendAdmin(adminPeer, 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<ZPackage>(configSync.Name + " ConfigSync", (Action<ZRpc, ZPackage>)configSync.RPC_FromServerConfigSync); } } } private class ParsedConfigs { public readonly Dictionary<OwnConfigEntryBase, object?> configValues = new Dictionary<OwnConfigEntryBase, object>(); public readonly Dictionary<CustomSyncedValueBase, object?> customValues = new Dictionary<CustomSyncedValueBase, object>(); } [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 : ZPlayFabSocket, ISocket { public volatile bool finished = false; public volatile int versionMatchQueued = -1; public readonly List<ZPackage> Package = new List<ZPackage>(); public readonly ISocket Original; public BufferingSocket(ISocket original) { Original = original; ((ZPlayFabSocket)this)..ctor(); } 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_0057: Unknown result type (might be due to invalid IL or missing references) //IL_005d: 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); } } } [HarmonyPriority(800)] [HarmonyPrefix] private static void Prefix(ref Dictionary<Assembly, BufferingSocket>? __state, ZNet __instance, ZRpc rpc) { //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_007e: Invalid comparison between Unknown and I4 if (!__instance.IsServer()) { return; } BufferingSocket bufferingSocket = new BufferingSocket(rpc.GetSocket()); AccessTools.DeclaredField(typeof(ZRpc), "m_socket").SetValue(rpc, bufferingSocket); 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) { FieldInfo fieldInfo = AccessTools.DeclaredField(typeof(ZNetPeer), "m_socket"); object? value = fieldInfo.GetValue(val); ZPlayFabSocket val2 = (ZPlayFabSocket)((value is ZPlayFabSocket) ? value : null); if (val2 != null) { typeof(ZPlayFabSocket).GetField("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) { ZRpc rpc2 = rpc; ZNet __instance2 = __instance; Dictionary<Assembly, BufferingSocket> __state2 = __state; ZNetPeer peer; if (__instance2.IsServer()) { object obj = AccessTools.DeclaredMethod(typeof(ZNet), "GetPeer", new Type[1] { typeof(ZRpc) }, (Type[])null).Invoke(__instance2, new object[1] { rpc2 }); peer = (ZNetPeer)((obj is ZNetPeer) ? obj : null); if (peer == null) { SendBufferedData(); } else { ((MonoBehaviour)__instance2).StartCoroutine(sendAsync()); } } void SendBufferedData() { if (rpc2.GetSocket() is BufferingSocket bufferingSocket) { AccessTools.DeclaredField(typeof(ZRpc), "m_socket").SetValue(rpc2, bufferingSocket.Original); object? obj2 = AccessTools.DeclaredMethod(typeof(ZNet), "GetPeer", new Type[1] { typeof(ZRpc) }, (Type[])null).Invoke(__instance2, new object[1] { rpc2 }); ZNetPeer val = (ZNetPeer)((obj2 is ZNetPeer) ? obj2 : null); if (val != null) { AccessTools.DeclaredField(typeof(ZNetPeer), "m_socket").SetValue(val, bufferingSocket.Original); } } BufferingSocket bufferingSocket2 = __state2[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<PackageEntry> entries = new List<PackageEntry>(); if (configSync.CurrentVersion != null) { entries.Add(new PackageEntry { section = "Internal", key = "serverversion", type = typeof(string), value = configSync.CurrentVersion }); } MethodInfo listContainsId = AccessTools.DeclaredMethod(typeof(ZNet), "ListContainsId", (Type[])null, (Type[])null); SyncedList adminList = (SyncedList)AccessTools.DeclaredField(typeof(ZNet), "m_adminList").GetValue(ZNet.instance); entries.Add(new PackageEntry { section = "Internal", key = "lockexempt", type = typeof(bool), value = (((object)listContainsId == null) ? ((object)adminList.Contains(rpc2.GetSocket().GetHostName())) : listContainsId.Invoke(ZNet.instance, new object[2] { adminList, rpc2.GetSocket().GetHostName() })) }); ZPackage package = ConfigsToPackage(configSync.allConfigs.Select((OwnConfigEntryBase c) => c.BaseConfig), configSync.allCustomValues, entries, partial: false); yield return ((MonoBehaviour)__instance2).StartCoroutine(configSync.sendZPackage(new List<ZNetPeer> { peer }, package)); } SendBufferedData(); } } } private class PackageEntry { public string section = null; public string key = null; public Type type = null; 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 = null; public string received = null; public string field = ""; } public static bool ProcessingServerUpdate; public readonly string Name; public string? DisplayName; public string? CurrentVersion; public string? MinimumRequiredVersion; public bool ModRequired = false; private bool? forceConfigLocking; private bool isSourceOfTruth = true; private static readonly HashSet<ConfigSync> configSyncs; private readonly HashSet<OwnConfigEntryBase> allConfigs = new HashSet<OwnConfigEntryBase>(); private HashSet<CustomSyncedValueBase> allCustomValues = new HashSet<CustomSyncedValueBase>(); private static bool isServer; private static bool lockExempt; private OwnConfigEntryBase? lockedConfig = null; 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; public bool IsLocked { get { bool? flag = forceConfigLocking; bool num; if (!flag.HasValue) { if (lockedConfig == null) { goto IL_0052; } num = ((IConvertible)lockedConfig.BaseConfig.BoxedValue).ToInt32(CultureInfo.InvariantCulture) != 0; } else { num = flag.GetValueOrDefault(); } if (!num) { goto IL_0052; } int result = ((!lockExempt) ? 1 : 0); goto IL_0053; IL_0053: return (byte)result != 0; IL_0052: result = 0; goto IL_0053; } set { forceConfigLocking = value; } } public bool IsAdmin => lockExempt || isSourceOfTruth; public bool IsSourceOfTruth { get { return isSourceOfTruth; } private set { if (value != isSourceOfTruth) { isSourceOfTruth = value; this.SourceOfTruthChanged?.Invoke(value); } } } public bool InitialSyncDone { get; private set; } = false; public event Action<bool>? SourceOfTruthChanged; private event Action? lockedConfigChanged; static ConfigSync() { ProcessingServerUpdate = false; configSyncs = new HashSet<ConfigSync>(); lockExempt = false; packageCounter = 0L; RuntimeHelpers.RunClassConstructor(typeof(VersionCheck).TypeHandle); } public ConfigSync(string name) { Name = name; configSyncs.Add(this); new VersionCheck(this); } public SyncedConfigEntry<T> AddConfigEntry<T>(ConfigEntry<T> configEntry) { ConfigEntry<T> configEntry2 = configEntry; OwnConfigEntryBase ownConfigEntryBase = configData((ConfigEntryBase)(object)configEntry2); SyncedConfigEntry<T> syncedEntry = ownConfigEntryBase as SyncedConfigEntry<T>; if (syncedEntry == null) { syncedEntry = new SyncedConfigEntry<T>(configEntry2); AccessTools.DeclaredField(typeof(ConfigDescription), "<Tags>k__BackingField").SetValue(((ConfigEntryBase)configEntry2).Description, new object[1] { new ConfigurationManagerAttributes() }.Concat(((ConfigEntryBase)configEntry2).Description.Tags ?? Array.Empty<object>()).Concat(new SyncedConfigEntry<T>[1] { syncedEntry }).ToArray()); configEntry2.SettingChanged += delegate { if (!ProcessingServerUpdate && syncedEntry.SynchronizedConfig) { Broadcast(ZRoutedRpc.Everybody, (ConfigEntryBase)configEntry2); } }; 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) { CustomSyncedValueBase customValue2 = customValue; if (allCustomValues.Select((CustomSyncedValueBase v) => v.Identifier).Concat(new string[1] { "serverversion" }).Contains(customValue2.Identifier)) { throw new Exception("Cannot have multiple settings with the same name or with a reserved name (serverversion)"); } allCustomValues.Add(customValue2); allCustomValues = new HashSet<CustomSyncedValueBase>(allCustomValues.OrderByDescending((CustomSyncedValueBase v) => v.Priority)); customValue2.ValueChanged += delegate { if (!ProcessingServerUpdate) { Broadcast(ZRoutedRpc.Everybody, customValue2); } }; } 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_0076: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Expected O, but got Unknown //IL_0250: Unknown result type (might be due to invalid IL or missing references) //IL_0257: Expected O, but got Unknown //IL_01ea: Unknown result type (might be due to invalid IL or missing references) //IL_01f1: 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<long, string> kv) { if (kv.Key < DateTimeOffset.Now.Ticks) { configValueCache.Remove(kv.Value); return true; } return false; }); byte b = package.ReadByte(); if ((b & 2u) != 0) { long num = package.ReadLong(); string text2 = sender.ToString() + num; if (!configValueCache.TryGetValue(text2, out SortedDictionary<int, byte[]> value)) { value = new SortedDictionary<int, byte[]>(); configValueCache[text2] = value; cacheExpirations.Add(new KeyValuePair<long, string>(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 & 4u) != 0) { byte[] buffer = package.ReadByteArray(); MemoryStream stream = new MemoryStream(buffer); 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) { 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<string, OwnConfigEntryBase> dictionary = allConfigs.Where((OwnConfigEntryBase c) => c.SynchronizedConfig).ToDictionary((OwnConfigEntryBase c) => c.BaseConfig.Definition.Section + "_" + c.BaseConfig.Definition.Key, (OwnConfigEntryBase c) => c); Dictionary<string, CustomSyncedValueBase> dictionary2 = allCustomValues.ToDictionary((CustomSyncedValueBase c) => c.Identifier, (CustomSyncedValueBase c) => c); int num = package.ReadInt(); for (int i = 0; i < num; i++) { 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) { OwnConfigEntryBase config2 = config; ConfigSync configSync = configSyncs.FirstOrDefault((ConfigSync cs) => cs.allConfigs.Contains(config2)); if (configSync == null) { return true; } return configSync.IsSourceOfTruth || !config2.SynchronizedConfig || config2.LocalBaseValue == null || (!configSync.IsLocked && (config2 != configSync.lockedConfig || lockExempt)); } private void serverLockedSettingChanged() { foreach (OwnConfigEntryBase allConfig in allConfigs) { configAttribute<ConfigurationManagerAttributes>(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<bool> distributeConfigToPeers(ZNetPeer peer, ZPackage package) { ZNetPeer peer2 = peer; 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 (peer2.m_socket.IsConnected()) { ZPackage fragmentedPackage = new ZPackage(); fragmentedPackage.Write((byte)2); fragmentedPackage.Write(packageIdentifier); fragmentedPackage.Write(fragment); fragmentedPackage.Write(fragments); fragmentedPackage.Write(data.Skip(250000 * fragment).Take(250000).ToArray()); SendPackage(fragmentedPackage); 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