Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of Runeborn v0.4.2
plugins/RustyHeathensRuneborn/RustyHeathensRuneborn.dll
Decompiled a day ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Text; using BepInEx; using BepInEx.Configuration; using HarmonyLib; using Jotunn.Entities; using Jotunn.Managers; using Jotunn.Utils; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: AssemblyCompany("RustyLaserGaming")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyDescription("Fantasy rune Viking character customization for Valheim.")] [assembly: AssemblyFileVersion("0.1.0.0")] [assembly: AssemblyInformationalVersion("0.1.0")] [assembly: AssemblyProduct("RustyHeathensRuneborn")] [assembly: AssemblyTitle("RustyHeathensRuneborn")] [assembly: AssemblyVersion("0.1.0.0")] namespace RustyHeathensRuneborn; [BepInPlugin("com.rustylasergaming.runeborn", "Rusty Heathens Runeborn", "0.4.2")] [BepInDependency(/*Could not decode attribute arguments.*/)] [NetworkCompatibility(/*Could not decode attribute arguments.*/)] public sealed class RunebornPlugin : BaseUnityPlugin { public const string PluginGuid = "com.rustylasergaming.runeborn"; public const string PluginName = "Rusty Heathens Runeborn"; public const string PluginVersion = "0.4.2"; internal static ConfigEntry<KeyboardShortcut> MenuKey; internal static ConfigEntry<KeyboardShortcut> AdminMenuKey; internal static ConfigEntry<bool> ServerReminderEnabledEntry; internal static ConfigEntry<bool> RaidWarningsEnabledEntry; private Harmony _harmony; private bool _menuOpen; private bool _adminMenuOpen; private Rect _windowRect = new Rect(40f, 80f, 560f, 700f); private Rect _adminWindowRect = new Rect(620f, 80f, 520f, 640f); private Vector2 _scrollPosition = Vector2.zero; private Vector2 _adminScrollPosition = Vector2.zero; private GUISkin _runebornSkin; private GUIStyle _sectionHeaderStyle; private GUIStyle _subHeaderStyle; private GUIStyle _mutedLabelStyle; private GUIStyle _goodLabelStyle; private GUIStyle _warningLabelStyle; private GUIStyle _accentLabelStyle; private GUIStyle _selectedButtonStyle; private GUIStyle _lockedButtonStyle; private GUIStyle _disabledButtonStyle; private GUIStyle _closeButtonStyle; private GUIStyle _hudTitleStyle; private GUIStyle _hudLabelStyle; private readonly List<Texture2D> _guiTextures = new List<Texture2D>(); private bool _showAdminDiagnostics; private int _playerMenuTab; private int _adminMenuTab; private CursorLockMode _previousCursorLock; private bool _previousCursorVisible; internal static RunebornPlugin Instance { get; private set; } private void Awake() { //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Expected O, but got Unknown Instance = this; BindConfig(); RunebornBuffStatusEffects.Register(); _harmony = new Harmony("com.rustylasergaming.runeborn"); _harmony.PatchAll(Assembly.GetExecutingAssembly()); ((BaseUnityPlugin)this).Logger.LogInfo((object)"Rusty Heathens Runeborn 0.4.2 loaded."); } private void OnDestroy() { Harmony harmony = _harmony; if (harmony != null) { harmony.UnpatchSelf(); } if ((Object)(object)_runebornSkin != (Object)null) { Object.Destroy((Object)(object)_runebornSkin); _runebornSkin = null; } foreach (Texture2D guiTexture in _guiTextures) { if ((Object)(object)guiTexture != (Object)null) { Object.Destroy((Object)(object)guiTexture); } } _guiTextures.Clear(); } private void Update() { //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) RunebornAdminEventMessages.EnsureRegistered(); RunebornBuffSlotSyncFoundation.EnsureRegistered(); RunebornBuffSlotSyncFoundation.UpdateLateJoinRequest(); RunebornBuffAvailabilitySync.EnsureRegistered(); RunebornBuffAvailabilitySync.UpdateLateJoinRequest(); RunebornBuffStatusEffects.UpdateLocalPlayerEffects(); KeyboardShortcut value = MenuKey.Value; if (((KeyboardShortcut)(ref value)).IsDown()) { ToggleMenu(); } value = AdminMenuKey.Value; if (((KeyboardShortcut)(ref value)).IsDown()) { if (RunebornAdminTools.IsLocalAdmin()) { ToggleAdminMenu(); } else { ShowLocalCenterMessage("Admin menu is locked."); } } } private void BindConfig() { //IL_001a: 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) MenuKey = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("Controls", "OpenPlayerHelpMenu", new KeyboardShortcut((KeyCode)289, Array.Empty<KeyCode>()), "Open or close the Rusty Heathens player help menu."); AdminMenuKey = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("Controls", "OpenAdminMenu", new KeyboardShortcut((KeyCode)288, Array.Empty<KeyCode>()), "Open or close the Rusty Heathens admin menu. Admin SteamID only."); ServerReminderEnabledEntry = ((BaseUnityPlugin)this).Config.Bind<bool>("Admin Settings", "ServerReminderEnabled", true, "Admin-controlled toggle for the Rusty Heathens server reminder message."); RaidWarningsEnabledEntry = ((BaseUnityPlugin)this).Config.Bind<bool>("Admin Settings", "RaidWarningsEnabled", true, "Admin-controlled toggle for Rusty Heathens raid warning messages."); ApplyAdminSettingsToRuntime(); } internal static void ApplyAdminSettingsToRuntime() { if (ServerReminderEnabledEntry != null) { RunebornServerReminder.ServerReminderEnabled = ServerReminderEnabledEntry.Value; } if (RaidWarningsEnabledEntry != null) { RunebornRaidWarnings.RaidWarningsEnabled = RaidWarningsEnabledEntry.Value; } } private static void ShowLocalCenterMessage(string text) { if ((Object)(object)Player.m_localPlayer == (Object)null) { return; } try { ((Character)Player.m_localPlayer).Message((MessageType)2, text, 0, (Sprite)null); } catch { } } private void ToggleMenu() { _menuOpen = !_menuOpen; ApplyCursorStateForOpenMenus(); } private void ToggleAdminMenu() { _adminMenuOpen = !_adminMenuOpen; ApplyCursorStateForOpenMenus(); } private void ApplyCursorStateForOpenMenus() { //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) if (_menuOpen || _adminMenuOpen) { _previousCursorLock = Cursor.lockState; _previousCursorVisible = Cursor.visible; Cursor.lockState = (CursorLockMode)0; Cursor.visible = true; } else { Cursor.lockState = _previousCursorLock; Cursor.visible = _previousCursorVisible; } } private void OnGUI() { //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Expected O, but got Unknown //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Unknown result type (might be due to invalid IL or missing references) //IL_009a: Expected O, but got Unknown //IL_0095: Unknown result type (might be due to invalid IL or missing references) //IL_009a: Unknown result type (might be due to invalid IL or missing references) GUISkin skin = GUI.skin; EnsureRunebornGuiSkin(); if ((Object)(object)_runebornSkin != (Object)null) { GUI.skin = _runebornSkin; } try { if (_menuOpen) { _windowRect = GUI.Window(928417, _windowRect, new WindowFunction(DrawWindow), "Rusty Heathens", GUI.skin.window); } if (_adminMenuOpen) { if (RunebornAdminTools.IsLocalAdmin()) { _adminWindowRect = GUI.Window(928418, _adminWindowRect, new WindowFunction(DrawAdminWindow), "Rusty Heathens Admin", GUI.skin.window); return; } _adminMenuOpen = false; ApplyCursorStateForOpenMenus(); } } finally { GUI.skin = skin; } } private void DrawActiveBuffHud() { //IL_00d2: Unknown result type (might be due to invalid IL or missing references) //IL_0104: Unknown result type (might be due to invalid IL or missing references) //IL_014f: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)Player.m_localPlayer == (Object)null) { return; } List<string> list = new List<string>(); if (RunebornServerComfort.IsRustyRestedActiveForLocalPlayer()) { list.Add("<color=#D9A441>[R]</color> Rusty Buff"); } if (RunebornServerComfort.IsSeppyBuffActiveForLocalPlayer()) { list.Add("<color=#D9A441>[S]</color> Seppy Buff"); } if (RunebornServerComfort.IsXpertBuffActiveForLocalPlayer()) { list.Add("<color=#D9A441>[X]</color> Xpert Buff"); } if (RunebornServerComfort.IsChaosBringerBuffActiveForLocalPlayer()) { list.Add("<color=#D9A441>[C]</color> Chaos Bringer"); } if (RunebornServerComfort.IsWitchyBuffActiveForLocalPlayer()) { list.Add("<color=#D9A441>[W]</color> Witchy Buff"); } if (list.Count != 0) { float num = 42f + (float)list.Count * 22f; float num2 = (float)Screen.width - 230f - 18f; float num3 = Mathf.Max(18f, (float)Screen.height - num - 18f); float num4 = Mathf.Clamp(220f, 18f, num3); GUI.Box(new Rect(num2, num4, 230f, num), GUIContent.none, GUI.skin.box); GUI.Label(new Rect(num2 + 8f, num4 + 6f, 214f, 24f), "ACTIVE BUFFS", _hudTitleStyle ?? GUI.skin.label); for (int i = 0; i < list.Count; i++) { GUI.Label(new Rect(num2 + 12f, num4 + 34f + (float)i * 22f, 206f, 22f), list[i], _hudLabelStyle ?? GUI.skin.label); } } } private void DrawWindow(int windowId) { //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_0097: 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_00cc: Unknown result type (might be due to invalid IL or missing references) if (GUI.Button(new Rect(((Rect)(ref _windowRect)).width - 34f, 6f, 26f, 22f), "X", _closeButtonStyle ?? GUI.skin.button)) { ToggleMenu(); return; } GUILayout.Space(8f); _scrollPosition = GUILayout.BeginScrollView(_scrollPosition, false, true, (GUILayoutOption[])(object)new GUILayoutOption[2] { GUILayout.Width(((Rect)(ref _windowRect)).width - 28f), GUILayout.Height(((Rect)(ref _windowRect)).height - 52f) }); DrawServerComfortMenuContent(); GUILayout.EndScrollView(); GUI.DragWindow(new Rect(0f, 0f, ((Rect)(ref _windowRect)).width - 42f, 30f)); } private void DrawAdminWindow(int windowId) { //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_0097: 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_00cc: Unknown result type (might be due to invalid IL or missing references) if (GUI.Button(new Rect(((Rect)(ref _adminWindowRect)).width - 34f, 6f, 26f, 22f), "X", _closeButtonStyle ?? GUI.skin.button)) { ToggleAdminMenu(); return; } GUILayout.Space(8f); _adminScrollPosition = GUILayout.BeginScrollView(_adminScrollPosition, false, true, (GUILayoutOption[])(object)new GUILayoutOption[2] { GUILayout.Width(((Rect)(ref _adminWindowRect)).width - 28f), GUILayout.Height(((Rect)(ref _adminWindowRect)).height - 52f) }); DrawAdminMenuContent(); GUILayout.EndScrollView(); GUI.DragWindow(new Rect(0f, 0f, ((Rect)(ref _adminWindowRect)).width - 42f, 30f)); } private void EnsureRunebornGuiSkin() { //IL_0181: Unknown result type (might be due to invalid IL or missing references) //IL_0182: Unknown result type (might be due to invalid IL or missing references) //IL_018c: Unknown result type (might be due to invalid IL or missing references) //IL_018d: Unknown result type (might be due to invalid IL or missing references) //IL_0197: Unknown result type (might be due to invalid IL or missing references) //IL_0198: Unknown result type (might be due to invalid IL or missing references) //IL_01a2: Unknown result type (might be due to invalid IL or missing references) //IL_01a3: Unknown result type (might be due to invalid IL or missing references) //IL_01ad: Unknown result type (might be due to invalid IL or missing references) //IL_01af: Unknown result type (might be due to invalid IL or missing references) //IL_01cd: Unknown result type (might be due to invalid IL or missing references) //IL_01e6: Unknown result type (might be due to invalid IL or missing references) //IL_0207: Unknown result type (might be due to invalid IL or missing references) //IL_020c: Unknown result type (might be due to invalid IL or missing references) //IL_022a: Unknown result type (might be due to invalid IL or missing references) //IL_0243: Unknown result type (might be due to invalid IL or missing references) //IL_0264: Unknown result type (might be due to invalid IL or missing references) //IL_0269: Unknown result type (might be due to invalid IL or missing references) //IL_0287: Unknown result type (might be due to invalid IL or missing references) //IL_028c: Unknown result type (might be due to invalid IL or missing references) //IL_02aa: Unknown result type (might be due to invalid IL or missing references) //IL_02af: Unknown result type (might be due to invalid IL or missing references) //IL_0331: Unknown result type (might be due to invalid IL or missing references) //IL_033e: Unknown result type (might be due to invalid IL or missing references) //IL_034b: Unknown result type (might be due to invalid IL or missing references) //IL_0358: Unknown result type (might be due to invalid IL or missing references) //IL_0365: Unknown result type (might be due to invalid IL or missing references) //IL_0372: Unknown result type (might be due to invalid IL or missing references) //IL_037f: Unknown result type (might be due to invalid IL or missing references) //IL_038c: Unknown result type (might be due to invalid IL or missing references) //IL_03b2: Unknown result type (might be due to invalid IL or missing references) //IL_03bc: Expected O, but got Unknown //IL_03c0: Unknown result type (might be due to invalid IL or missing references) //IL_03ca: Expected O, but got Unknown //IL_0443: Unknown result type (might be due to invalid IL or missing references) //IL_0450: Unknown result type (might be due to invalid IL or missing references) //IL_045d: Unknown result type (might be due to invalid IL or missing references) //IL_046a: Unknown result type (might be due to invalid IL or missing references) //IL_047a: Unknown result type (might be due to invalid IL or missing references) //IL_0484: Expected O, but got Unknown //IL_0488: Unknown result type (might be due to invalid IL or missing references) //IL_0492: Expected O, but got Unknown //IL_04a6: Unknown result type (might be due to invalid IL or missing references) //IL_04c4: Unknown result type (might be due to invalid IL or missing references) //IL_04ce: Expected O, but got Unknown //IL_051a: Unknown result type (might be due to invalid IL or missing references) //IL_0528: Unknown result type (might be due to invalid IL or missing references) //IL_0536: Unknown result type (might be due to invalid IL or missing references) //IL_0544: Unknown result type (might be due to invalid IL or missing references) //IL_0562: Unknown result type (might be due to invalid IL or missing references) //IL_056c: Expected O, but got Unknown //IL_0572: Unknown result type (might be due to invalid IL or missing references) //IL_057c: Expected O, but got Unknown //IL_058e: Unknown result type (might be due to invalid IL or missing references) //IL_0598: Expected O, but got Unknown //IL_05ac: Unknown result type (might be due to invalid IL or missing references) //IL_05ba: Unknown result type (might be due to invalid IL or missing references) //IL_05c8: Unknown result type (might be due to invalid IL or missing references) //IL_05f4: Unknown result type (might be due to invalid IL or missing references) //IL_05fe: Expected O, but got Unknown //IL_061b: Unknown result type (might be due to invalid IL or missing references) //IL_0625: Expected O, but got Unknown //IL_0629: Unknown result type (might be due to invalid IL or missing references) //IL_0633: Expected O, but got Unknown //IL_06bc: Unknown result type (might be due to invalid IL or missing references) //IL_06c6: Expected O, but got Unknown //IL_06e3: Unknown result type (might be due to invalid IL or missing references) //IL_0719: Unknown result type (might be due to invalid IL or missing references) //IL_0723: Expected O, but got Unknown //IL_072d: Unknown result type (might be due to invalid IL or missing references) //IL_0737: Expected O, but got Unknown //IL_0751: Unknown result type (might be due to invalid IL or missing references) //IL_075b: Expected O, but got Unknown //IL_075e: Unknown result type (might be due to invalid IL or missing references) //IL_0768: Expected O, but got Unknown //IL_0773: Unknown result type (might be due to invalid IL or missing references) //IL_079d: Unknown result type (might be due to invalid IL or missing references) //IL_07a7: Expected O, but got Unknown //IL_07aa: Unknown result type (might be due to invalid IL or missing references) //IL_07b4: Expected O, but got Unknown //IL_07bf: Unknown result type (might be due to invalid IL or missing references) //IL_07d6: Unknown result type (might be due to invalid IL or missing references) //IL_07e0: Expected O, but got Unknown //IL_07eb: Unknown result type (might be due to invalid IL or missing references) //IL_0801: Unknown result type (might be due to invalid IL or missing references) //IL_080b: Expected O, but got Unknown //IL_0816: Unknown result type (might be due to invalid IL or missing references) //IL_082c: Unknown result type (might be due to invalid IL or missing references) //IL_0836: Expected O, but got Unknown //IL_0841: Unknown result type (might be due to invalid IL or missing references) //IL_0857: Unknown result type (might be due to invalid IL or missing references) //IL_0861: Expected O, but got Unknown //IL_0890: Unknown result type (might be due to invalid IL or missing references) //IL_08a2: Unknown result type (might be due to invalid IL or missing references) //IL_08b4: Unknown result type (might be due to invalid IL or missing references) //IL_08be: Unknown result type (might be due to invalid IL or missing references) //IL_08c8: Expected O, but got Unknown //IL_08f7: Unknown result type (might be due to invalid IL or missing references) //IL_0909: Unknown result type (might be due to invalid IL or missing references) //IL_091b: Unknown result type (might be due to invalid IL or missing references) //IL_0925: Unknown result type (might be due to invalid IL or missing references) //IL_092f: Expected O, but got Unknown //IL_095e: Unknown result type (might be due to invalid IL or missing references) //IL_0970: Unknown result type (might be due to invalid IL or missing references) //IL_097a: Unknown result type (might be due to invalid IL or missing references) //IL_0984: Expected O, but got Unknown //IL_09c7: Unknown result type (might be due to invalid IL or missing references) //IL_09d1: Expected O, but got Unknown //IL_09d4: Unknown result type (might be due to invalid IL or missing references) //IL_09de: Expected O, but got Unknown //IL_09e9: Unknown result type (might be due to invalid IL or missing references) //IL_0a18: Unknown result type (might be due to invalid IL or missing references) //IL_0a22: Expected O, but got Unknown //IL_0a2d: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)_runebornSkin != (Object)null) && !((Object)(object)GUI.skin == (Object)null)) { _runebornSkin = Object.Instantiate<GUISkin>(GUI.skin); ((Object)_runebornSkin).name = "RustyHeathensValheimSkin"; Color fillColor = default(Color); ((Color)(ref fillColor))..ctor(0.105f, 0.065f, 0.035f, 0.97f); Color fillColor2 = default(Color); ((Color)(ref fillColor2))..ctor(0.175f, 0.105f, 0.052f, 0.97f); Color fillColor3 = default(Color); ((Color)(ref fillColor3))..ctor(0.235f, 0.145f, 0.07f, 1f); Color fillColor4 = default(Color); ((Color)(ref fillColor4))..ctor(0.315f, 0.205f, 0.105f, 1f); Color fillColor5 = default(Color); ((Color)(ref fillColor5))..ctor(0.125f, 0.075f, 0.035f, 1f); Color borderColor = default(Color); ((Color)(ref borderColor))..ctor(0.34f, 0.29f, 0.22f, 1f); Color borderColor2 = default(Color); ((Color)(ref borderColor2))..ctor(0.63f, 0.43f, 0.19f, 1f); Color textColor = default(Color); ((Color)(ref textColor))..ctor(0.89f, 0.84f, 0.72f, 1f); Color textColor2 = default(Color); ((Color)(ref textColor2))..ctor(0.68f, 0.62f, 0.53f, 1f); Color textColor3 = default(Color); ((Color)(ref textColor3))..ctor(0.92f, 0.72f, 0.38f, 1f); Color textColor4 = default(Color); ((Color)(ref textColor4))..ctor(0.58f, 0.8f, 0.48f, 1f); Color textColor5 = default(Color); ((Color)(ref textColor5))..ctor(0.92f, 0.48f, 0.32f, 1f); Texture2D background = CreateFramedTexture(fillColor, borderColor2); Texture2D background2 = CreateFramedTexture(fillColor2, borderColor); Texture2D background3 = CreateFramedTexture(fillColor3, borderColor); Texture2D background4 = CreateFramedTexture(fillColor4, borderColor2); Texture2D background5 = CreateFramedTexture(fillColor5, borderColor2); Texture2D background6 = CreateFramedTexture(new Color(0.16f, 0.28f, 0.12f, 1f), new Color(0.53f, 0.7f, 0.31f, 1f)); Texture2D background7 = CreateFramedTexture(new Color(0.13f, 0.13f, 0.13f, 1f), borderColor); Texture2D background8 = CreateFramedTexture(new Color(0.26f, 0.09f, 0.07f, 1f), new Color(0.62f, 0.22f, 0.16f, 1f)); Texture2D background9 = CreateFramedTexture(new Color(0.22f, 0.13f, 0.055f, 1f), borderColor2); Texture2D background10 = CreateFramedTexture(new Color(0.07f, 0.045f, 0.025f, 1f), borderColor); Texture2D background11 = CreateFramedTexture(new Color(0.31f, 0.2f, 0.1f, 1f), borderColor2); GUIStyle window = _runebornSkin.window; window.normal.background = background; window.hover.background = background; window.active.background = background; window.focused.background = background; window.onNormal.background = background; window.onHover.background = background; window.onActive.background = background; window.onFocused.background = background; window.normal.textColor = textColor3; window.hover.textColor = textColor3; window.active.textColor = textColor3; window.focused.textColor = textColor3; window.onNormal.textColor = textColor3; window.onHover.textColor = textColor3; window.onActive.textColor = textColor3; window.onFocused.textColor = textColor3; window.fontSize = 16; window.fontStyle = (FontStyle)1; window.alignment = (TextAnchor)1; window.padding = new RectOffset(14, 14, 34, 14); window.border = new RectOffset(1, 1, 1, 1); GUIStyle box = _runebornSkin.box; box.normal.background = background2; box.hover.background = background2; box.active.background = background2; box.focused.background = background2; box.onNormal.background = background2; box.onHover.background = background2; box.onActive.background = background2; box.onFocused.background = background2; box.normal.textColor = textColor; box.hover.textColor = textColor; box.active.textColor = textColor; box.focused.textColor = textColor; box.padding = new RectOffset(10, 10, 10, 10); box.border = new RectOffset(1, 1, 1, 1); GUIStyle label = _runebornSkin.label; label.normal.textColor = textColor; label.fontSize = 13; label.wordWrap = true; label.padding = new RectOffset(2, 2, 2, 2); GUIStyle button = _runebornSkin.button; button.normal.background = background3; button.hover.background = background4; button.active.background = background5; button.focused.background = background3; button.normal.textColor = textColor; button.hover.textColor = textColor3; button.active.textColor = textColor3; button.focused.textColor = textColor; button.fontSize = 13; button.alignment = (TextAnchor)4; button.padding = new RectOffset(8, 8, 5, 5); button.margin = new RectOffset(2, 2, 2, 2); button.fixedHeight = 28f; button.border = new RectOffset(1, 1, 1, 1); GUIStyle toggle = _runebornSkin.toggle; toggle.normal.textColor = textColor; toggle.hover.textColor = textColor3; toggle.active.textColor = textColor3; toggle.fontSize = 13; toggle.padding = new RectOffset(toggle.padding.left, toggle.padding.right, 4, 4); GUIStyle scrollView = _runebornSkin.scrollView; scrollView.normal.background = background2; scrollView.padding = new RectOffset(8, 8, 8, 8); scrollView.border = new RectOffset(1, 1, 1, 1); _runebornSkin.verticalScrollbar.normal.background = background10; _runebornSkin.verticalScrollbar.fixedWidth = 14f; _runebornSkin.verticalScrollbarThumb.normal.background = background11; _runebornSkin.verticalScrollbarThumb.hover.background = background4; _runebornSkin.verticalScrollbarThumb.active.background = background5; _runebornSkin.verticalScrollbarThumb.fixedWidth = 12f; _sectionHeaderStyle = new GUIStyle(label); _sectionHeaderStyle.normal.background = background9; _sectionHeaderStyle.normal.textColor = textColor3; _sectionHeaderStyle.fontSize = 15; _sectionHeaderStyle.fontStyle = (FontStyle)1; _sectionHeaderStyle.alignment = (TextAnchor)3; _sectionHeaderStyle.padding = new RectOffset(8, 8, 6, 6); _sectionHeaderStyle.margin = new RectOffset(0, 0, 8, 4); _sectionHeaderStyle.fixedHeight = 30f; _sectionHeaderStyle.border = new RectOffset(1, 1, 1, 1); _subHeaderStyle = new GUIStyle(label); _subHeaderStyle.normal.textColor = textColor3; _subHeaderStyle.fontSize = 14; _subHeaderStyle.fontStyle = (FontStyle)1; _subHeaderStyle.margin = new RectOffset(2, 2, 7, 2); _mutedLabelStyle = new GUIStyle(label); _mutedLabelStyle.normal.textColor = textColor2; _mutedLabelStyle.fontSize = 12; _goodLabelStyle = new GUIStyle(label); _goodLabelStyle.normal.textColor = textColor4; _goodLabelStyle.fontStyle = (FontStyle)1; _warningLabelStyle = new GUIStyle(label); _warningLabelStyle.normal.textColor = textColor5; _warningLabelStyle.fontStyle = (FontStyle)1; _accentLabelStyle = new GUIStyle(label); _accentLabelStyle.normal.textColor = textColor3; _accentLabelStyle.fontStyle = (FontStyle)1; _selectedButtonStyle = new GUIStyle(button); _selectedButtonStyle.normal.background = background6; _selectedButtonStyle.hover.background = background6; _selectedButtonStyle.normal.textColor = textColor; _selectedButtonStyle.hover.textColor = textColor3; _selectedButtonStyle.active.textColor = textColor3; _lockedButtonStyle = new GUIStyle(button); _lockedButtonStyle.normal.background = background7; _lockedButtonStyle.hover.background = background7; _lockedButtonStyle.normal.textColor = textColor; _lockedButtonStyle.hover.textColor = textColor3; _lockedButtonStyle.active.textColor = textColor3; _disabledButtonStyle = new GUIStyle(button); _disabledButtonStyle.normal.background = background8; _disabledButtonStyle.hover.background = background8; _disabledButtonStyle.normal.textColor = textColor5; _disabledButtonStyle.hover.textColor = textColor; _closeButtonStyle = new GUIStyle(button); _closeButtonStyle.fixedWidth = 26f; _closeButtonStyle.fixedHeight = 22f; _closeButtonStyle.fontSize = 12; _closeButtonStyle.fontStyle = (FontStyle)1; _closeButtonStyle.padding = new RectOffset(0, 0, 0, 0); _hudTitleStyle = new GUIStyle(label); _hudTitleStyle.normal.textColor = textColor3; _hudTitleStyle.fontSize = 13; _hudTitleStyle.fontStyle = (FontStyle)1; _hudTitleStyle.alignment = (TextAnchor)4; _hudLabelStyle = new GUIStyle(label); _hudLabelStyle.normal.textColor = textColor; _hudLabelStyle.fontSize = 13; _hudLabelStyle.richText = true; _hudLabelStyle.alignment = (TextAnchor)3; } } private Texture2D CreateFramedTexture(Color fillColor, Color borderColor) { //IL_0004: Unknown result type (might be due to invalid IL or missing references) //IL_000a: Expected O, but got Unknown //IL_0046: 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) Texture2D val = new Texture2D(3, 3, (TextureFormat)4, false); ((Object)val).name = "RustyHeathensGuiTexture"; ((Texture)val).wrapMode = (TextureWrapMode)1; ((Texture)val).filterMode = (FilterMode)0; for (int i = 0; i < 3; i++) { for (int j = 0; j < 3; j++) { bool flag = j == 0 || j == 2 || i == 0 || i == 2; val.SetPixel(j, i, flag ? borderColor : fillColor); } } val.Apply(); _guiTextures.Add(val); return val; } private void DrawSectionHeader(string title) { GUILayout.Label(title, _sectionHeaderStyle ?? GUI.skin.label, Array.Empty<GUILayoutOption>()); } private void DrawSubHeader(string title) { GUILayout.Label(title, _subHeaderStyle ?? GUI.skin.label, Array.Empty<GUILayoutOption>()); } private void DrawMutedLabel(string text) { GUILayout.Label(text, _mutedLabelStyle ?? GUI.skin.label, Array.Empty<GUILayoutOption>()); } private bool DrawRunebornButton(string text) { GUIStyle val = GUI.skin.button; if (text.StartsWith("Selected:") || text.StartsWith("Enabled:")) { val = _selectedButtonStyle ?? GUI.skin.button; } else if (text.StartsWith("Locked:")) { val = _lockedButtonStyle ?? GUI.skin.button; } else if (text.StartsWith("Disabled:")) { val = _disabledButtonStyle ?? GUI.skin.button; } return GUILayout.Button(text, val, Array.Empty<GUILayoutOption>()); } private void DrawSlotLimitButton(int slotCount) { bool num = RunebornServerComfort.GetMaxSelectedBuffs() == slotCount; string text = ((slotCount == 1) ? "1 Slot" : (slotCount + " Slots")); GUIStyle val = (num ? (_selectedButtonStyle ?? GUI.skin.button) : GUI.skin.button); if (GUILayout.Button(text, val, Array.Empty<GUILayoutOption>())) { RunebornServerComfort.SetMaxSelectedBuffs(slotCount); } } private void DrawServerComfortMenuContent() { DrawSectionHeader("PLAYER MENU"); DrawMutedLabel("Rusty Heathens server information and personal settings"); DrawMenuTabs(ref _playerMenuTab, "BUFFS", "SERVER", "HELP"); switch (_playerMenuTab) { case 1: DrawPlayerServerTab(); break; case 2: DrawPlayerHelpTab(); break; default: DrawPlayerBuffsTab(); break; } } private void DrawMenuTabs(ref int selectedTab, params string[] tabLabels) { //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_0053: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Unknown result type (might be due to invalid IL or missing references) GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>()); for (int i = 0; i < tabLabels.Length; i++) { GUIStyle val = ((i == selectedTab) ? (_selectedButtonStyle ?? GUI.skin.button) : GUI.skin.button); if (GUILayout.Button(tabLabels[i], val, Array.Empty<GUILayoutOption>())) { selectedTab = i; _scrollPosition = Vector2.zero; _adminScrollPosition = Vector2.zero; } } GUILayout.EndHorizontal(); GUILayout.Space(6f); } private void DrawPlayerBuffsTab() { DrawSectionHeader("CHOOSE YOUR BUFFS"); int selectedBuffCount = RunebornServerComfort.GetSelectedBuffCount(); int maxSelectedBuffs = RunebornServerComfort.GetMaxSelectedBuffs(); GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>()); GUIStyle val = ((selectedBuffCount > maxSelectedBuffs) ? (_warningLabelStyle ?? GUI.skin.label) : ((selectedBuffCount == maxSelectedBuffs) ? (_accentLabelStyle ?? GUI.skin.label) : (_goodLabelStyle ?? GUI.skin.label))); GUILayout.Label("Selected " + selectedBuffCount + " of " + maxSelectedBuffs, val, Array.Empty<GUILayoutOption>()); GUILayout.FlexibleSpace(); GUILayout.Label("Rested status controls activation", _mutedLabelStyle ?? GUI.skin.label, Array.Empty<GUILayoutOption>()); GUILayout.EndHorizontal(); DrawPlayerBuffChoice("rusty", "Rusty Buff"); DrawPlayerBuffChoice("seppy", "Seppy Buff"); DrawPlayerBuffChoice("xpert", "Xpert Buff"); DrawPlayerBuffChoice("chaos", "Chaos Bringer Buff"); DrawPlayerBuffChoice("witchy", "Witchy Buff"); DrawSectionHeader("SELECTED BUFF DETAILS"); DrawSelectedBuffDetails(); DrawSectionHeader("UTILITY EFFECTS"); DrawUtilityStatusCards(); } private void DrawPlayerBuffChoice(string buffId, string displayName) { if (RunebornServerComfort.IsBuffEnabled(buffId)) { string buffButtonText = RunebornServerComfort.GetBuffButtonText(buffId, displayName); if (DrawRunebornButton(buffButtonText)) { ShowLocalCenterMessage(RunebornServerComfort.ToggleBuffSelection(buffId, displayName)); } } } private bool IsBuffChosenForGui(string buffId, string displayName) { return RunebornServerComfort.GetBuffButtonText(buffId, displayName).StartsWith("Selected:", StringComparison.Ordinal); } private void DrawSelectedBuffDetails() { bool flag = false; if (IsBuffChosenForGui("rusty", "Rusty Buff")) { flag = true; DrawBuffStatusCard("Rusty Buff", RunebornServerComfort.IsRustyRestedActiveForLocalPlayer(), "Requires Rested", "10% less stamina used"); } if (IsBuffChosenForGui("seppy", "Seppy Buff")) { flag = true; DrawBuffStatusCard("Seppy Buff", RunebornServerComfort.IsSeppyBuffActiveForLocalPlayer(), "Requires Rested", "10% less incoming damage", "15% less stamina used while blocking"); } if (IsBuffChosenForGui("xpert", "Xpert Buff")) { flag = true; DrawBuffStatusCard("Xpert Buff", RunebornServerComfort.IsXpertBuffActiveForLocalPlayer(), "Requires Rested and an axe or melee weapon", "10% more melee damage", "10% less weapon stamina used"); } if (IsBuffChosenForGui("chaos", "Chaos Bringer Buff")) { flag = true; DrawBuffStatusCard("Chaos Bringer", RunebornServerComfort.IsChaosBringerBuffActiveForLocalPlayer(), "Requires Rested", "10% faster movement", "20% faster sneak", "12% stronger jump", "15% less dodge and swim stamina"); } if (IsBuffChosenForGui("witchy", "Witchy Buff")) { flag = true; DrawBuffStatusCard("Witchy Buff", RunebornServerComfort.IsWitchyBuffActiveForLocalPlayer(), "Requires Rested", "10% less staff and magic stamina"); } if (!flag) { GUILayout.BeginVertical(GUI.skin.box, Array.Empty<GUILayoutOption>()); DrawMutedLabel("Choose a buff above to see its active effects."); GUILayout.EndVertical(); } } private void DrawBuffStatusCard(string title, bool active, string inactiveRequirement, params string[] effectLines) { GUILayout.BeginVertical(GUI.skin.box, Array.Empty<GUILayoutOption>()); GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>()); GUILayout.Label(title, _subHeaderStyle ?? GUI.skin.label, Array.Empty<GUILayoutOption>()); GUILayout.FlexibleSpace(); GUILayout.Label(active ? "ACTIVE" : "INACTIVE", active ? (_goodLabelStyle ?? GUI.skin.label) : (_warningLabelStyle ?? GUI.skin.label), Array.Empty<GUILayoutOption>()); GUILayout.EndHorizontal(); if (!active) { DrawMutedLabel(inactiveRequirement); } foreach (string text in effectLines) { GUILayout.Label("• " + text, Array.Empty<GUILayoutOption>()); } GUILayout.EndVertical(); } private void DrawUtilityStatusCards() { bool flag = RunebornServerComfort.IsBuildComfortActiveForLocalPlayer(); GUILayout.BeginVertical(GUI.skin.box, Array.Empty<GUILayoutOption>()); GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>()); DrawSubHeader("Build Mode Comfort"); GUILayout.FlexibleSpace(); GUILayout.Label(flag ? "ACTIVE" : "READY", flag ? (_goodLabelStyle ?? GUI.skin.label) : (_mutedLabelStyle ?? GUI.skin.label), Array.Empty<GUILayoutOption>()); GUILayout.EndHorizontal(); DrawMutedLabel(flag ? "50% less stamina used while building" : "Equip a Hammer, Hoe, or Cultivator"); GUILayout.EndVertical(); float bodyRecoverySecondsLeft = RunebornServerComfort.GetBodyRecoverySecondsLeft(); GUILayout.BeginVertical(GUI.skin.box, Array.Empty<GUILayoutOption>()); GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>()); DrawSubHeader("Body Recovery"); GUILayout.FlexibleSpace(); GUILayout.Label((bodyRecoverySecondsLeft > 0f) ? "ACTIVE" : "INACTIVE", (bodyRecoverySecondsLeft > 0f) ? (_goodLabelStyle ?? GUI.skin.label) : (_mutedLabelStyle ?? GUI.skin.label), Array.Empty<GUILayoutOption>()); GUILayout.EndHorizontal(); if (bodyRecoverySecondsLeft > 0f) { DrawMutedLabel(Mathf.CeilToInt(bodyRecoverySecondsLeft / 60f) + " minutes remaining"); GUILayout.Label("• +150 carry weight\n• 35% less stamina used", Array.Empty<GUILayoutOption>()); } else { DrawMutedLabel("Activates for 10 minutes after death"); } GUILayout.EndVertical(); } private void DrawPlayerServerTab() { DrawSectionHeader("SERVER STATUS"); DrawServerStatusCard("Welcome Message", enabled: true, "Shown once after loading into the world."); DrawServerStatusCard("Server Reminder", RunebornServerReminder.ServerReminderEnabled, "Shown once after the welcome message."); DrawServerStatusCard("Raid Warnings", RunebornRaidWarnings.RaidWarningsEnabled, "Warns when raids start, repeat, and clear."); DrawServerStatusCard("Boss Kill Messages", enabled: true, "Shows a Rusty Heathens victory message."); DrawSectionHeader("DEATH COUNTER"); int currentDeathCount = PlayerPrefs.GetInt("RustyHeathensRuneborn.DeathCount", 0); GUILayout.BeginVertical(GUI.skin.box, Array.Empty<GUILayoutOption>()); GUILayout.Label("Deaths: " + currentDeathCount, _subHeaderStyle ?? GUI.skin.label, Array.Empty<GUILayoutOption>()); DrawMutedLabel("Next message: " + RunebornServerComfort.PreviewNextFunnyDeathMessage(currentDeathCount)); GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>()); if (DrawRunebornButton("Show Count")) { ShowLocalCenterMessage("Rusty Heathens Death Count: " + currentDeathCount); } if (DrawRunebornButton("Reset Count")) { PlayerPrefs.SetInt("RustyHeathensRuneborn.DeathCount", 0); PlayerPrefs.Save(); ShowLocalCenterMessage("Rusty Heathens Death Count reset"); } GUILayout.EndHorizontal(); GUILayout.EndVertical(); } private void DrawServerStatusCard(string title, bool enabled, string description) { GUILayout.BeginVertical(GUI.skin.box, Array.Empty<GUILayoutOption>()); GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>()); DrawSubHeader(title); GUILayout.FlexibleSpace(); GUILayout.Label(enabled ? "ON" : "OFF", enabled ? (_goodLabelStyle ?? GUI.skin.label) : (_warningLabelStyle ?? GUI.skin.label), Array.Empty<GUILayoutOption>()); GUILayout.EndHorizontal(); DrawMutedLabel(description); GUILayout.EndVertical(); } private void DrawPlayerHelpTab() { DrawSectionHeader("SERVER RULES & HELP"); DrawMutedLabel("Choose a topic to display it in the center of the screen."); if (DrawRunebornButton("Basic Server Rules")) { ShowLocalCenterMessage("RUSTY HEATHENS RULES\nRespect the crew.\nNo stealing.\nNo boss fights without the group.\nHelp with body recovery when you can.\nCheck Discord for full rules."); } if (DrawRunebornButton("Boss Fight Rules")) { ShowLocalCenterMessage("BOSS FIGHT RULES\nDo not summon bosses alone.\nWait for Rusty and the group.\nRepair gear, bring food, and be ready.\nIf you die, call for recovery."); } if (DrawRunebornButton("Body Recovery Rules")) { ShowLocalCenterMessage("BODY RECOVERY RULES\nDo not run in alone if the area is hot.\nCall out where your body is.\nStay grouped and protect each other.\nRecovery before revenge."); } if (DrawRunebornButton("Discord Reminder")) { ShowLocalCenterMessage("DISCORD REMINDER\nUse Discord for rules, event plans, updates, and stream info.\nMessage RustyLaser if you need help."); } if (DrawRunebornButton("Server Etiquette")) { ShowLocalCenterMessage("SERVER ETIQUETTE\nAsk before taking shared items.\nLabel storage when possible.\nDo not spoil new areas or bosses.\nBuild smart, clean up, and help the crew."); } DrawSectionHeader("SERVER EVENTS"); DrawMutedLabel(RunebornAdminTools.IsLocalAdmin() ? "Event broadcasts are controlled from F7." : "Server-event broadcasts appear automatically."); } private void ShowBuffAvailabilityMessage(string message) { if ((Object)(object)Player.m_localPlayer != (Object)null) { ((Character)Player.m_localPlayer).Message((MessageType)2, message, 0, (Sprite)null); } } private void DrawAdminMenuContent() { DrawSectionHeader("ADMIN MENU"); DrawMutedLabel("Server-owner controls - F7"); DrawMenuTabs(ref _adminMenuTab, "SETTINGS", "EVENTS", "SYSTEM"); switch (_adminMenuTab) { case 1: DrawAdminEventsTab(); break; case 2: DrawAdminSystemTab(); break; default: DrawAdminSettingsTab(); break; } } private void DrawAdminSettingsTab() { DrawSectionHeader("SERVER SETTINGS"); DrawSubHeader("Maximum Buff Slots"); DrawMutedLabel("Choose how many character buffs each player may equip."); GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>()); DrawSlotLimitButton(1); DrawSlotLimitButton(2); DrawSlotLimitButton(3); GUILayout.EndHorizontal(); GUILayout.Label("Admin authority active", _goodLabelStyle ?? GUI.skin.label, Array.Empty<GUILayoutOption>()); DrawSectionHeader("BUFF AVAILABILITY"); DrawAdminBuffAvailabilityButton("rusty", "Rusty Buff"); DrawAdminBuffAvailabilityButton("seppy", "Seppy Buff"); DrawAdminBuffAvailabilityButton("xpert", "Xpert Buff"); DrawAdminBuffAvailabilityButton("chaos", "Chaos Bringer Buff"); DrawAdminBuffAvailabilityButton("witchy", "Witchy Buff"); DrawMutedLabel("Enabled: " + RunebornServerComfort.GetEnabledBuffSummary()); GUILayout.Label("Multiplayer availability sync active", _goodLabelStyle ?? GUI.skin.label, Array.Empty<GUILayoutOption>()); DrawSectionHeader("ADMIN TOGGLES"); DrawAdminSettingToggle("Server Reminder", ServerReminderEnabledEntry, "Server Reminder"); DrawAdminSettingToggle("Raid Warnings", RaidWarningsEnabledEntry, "Raid Warnings"); } private void DrawAdminSettingToggle(string displayName, ConfigEntry<bool> configEntry, string messageName) { bool value = configEntry.Value; string text = (value ? "Enabled: " : "Disabled: ") + displayName + " - click to " + (value ? "disable" : "enable"); if (DrawRunebornButton(text)) { configEntry.Value = !value; ApplyAdminSettingsToRuntime(); ((BaseUnityPlugin)this).Config.Save(); ShowLocalCenterMessage(messageName + " " + (configEntry.Value ? "Enabled" : "Disabled")); } } private void DrawAdminBuffAvailabilityButton(string buffId, string displayName) { string buffEnabledButtonText = RunebornServerComfort.GetBuffEnabledButtonText(buffId, displayName); if (DrawRunebornButton(buffEnabledButtonText)) { ShowBuffAvailabilityMessage(RunebornServerComfort.ToggleBuffEnabledByAdmin(buffId, displayName)); } } private void DrawAdminEventsTab() { DrawSectionHeader("SERVER EVENTS"); DrawMutedLabel("Broadcast a large center-screen message to every player."); if (DrawRunebornButton("Boss Fight Starting Soon")) { RunebornAdminEventMessages.SendAdminBroadcast("BOSS FIGHT STARTING SOON", "Return to base, repair your gear, grab food, and wait for Rusty."); } if (DrawRunebornButton("Return To Base")) { RunebornAdminEventMessages.SendAdminBroadcast("RETURN TO BASE", "Everyone head back to base. Regroup before the chaos gets worse."); } if (DrawRunebornButton("Body Recovery Run")) { RunebornAdminEventMessages.SendAdminBroadcast("BODY RECOVERY RUN", "A Heathen is down. Gear up, stay together, and help recover the body."); } if (DrawRunebornButton("Discord Reminder")) { RunebornAdminEventMessages.SendAdminBroadcast("DISCORD REMINDER", "Check Discord for server rules, event plans, and stream updates."); } if (DrawRunebornButton("Stream Starting Soon")) { RunebornAdminEventMessages.SendAdminBroadcast("STREAM STARTING SOON", "Get ready, Heathens. The stream is about to begin."); } } private void DrawAdminSystemTab() { DrawSectionHeader("SYSTEM STATUS"); GUILayout.BeginVertical(GUI.skin.box, Array.Empty<GUILayoutOption>()); GUILayout.Label("Runeborn v0.4.2", _subHeaderStyle ?? GUI.skin.label, Array.Empty<GUILayoutOption>()); GUILayout.Label("Buff-slot synchronization: " + (RunebornBuffSlotSyncFoundation.WasLastSenderTrusted() ? "TRUSTED" : "ADMIN AUTHORITY"), _goodLabelStyle ?? GUI.skin.label, Array.Empty<GUILayoutOption>()); GUILayout.Label("Availability synchronization: " + (RunebornBuffAvailabilitySync.WasLastSenderTrusted() ? "TRUSTED" : "ADMIN AUTHORITY"), _goodLabelStyle ?? GUI.skin.label, Array.Empty<GUILayoutOption>()); DrawMutedLabel("Late-join request and response synchronization is active."); GUILayout.EndVertical(); DrawSectionHeader("BUFF-SLOT DIAGNOSTICS"); GUILayout.BeginVertical(GUI.skin.box, Array.Empty<GUILayoutOption>()); DrawMutedLabel("Current slot limit: " + RunebornServerComfort.GetMaxSelectedBuffs()); DrawMutedLabel("Last received value: " + RunebornBuffSlotSyncFoundation.GetLastReceivedMaxBuffSlots()); DrawMutedLabel("Last RPC sender: " + RunebornBuffSlotSyncFoundation.GetLastRpcSender()); DrawMutedLabel("Server peer ID: " + RunebornBuffSlotSyncFoundation.GetLastServerPeerId()); DrawMutedLabel("Local peer ID: " + RunebornBuffSlotSyncFoundation.GetLastLocalPeerId()); DrawMutedLabel("Last request sender: " + RunebornBuffSlotSyncFoundation.GetLastRequestSender()); DrawMutedLabel("Live ID equality: " + (RunebornBuffSlotSyncFoundation.DoLastRpcIdsMatch() ? "YES" : "NO")); DrawMutedLabel("Sender hex: " + RunebornBuffSlotSyncFoundation.GetLastRpcSenderHex()); DrawMutedLabel("Server hex: " + RunebornBuffSlotSyncFoundation.GetLastServerPeerIdHex()); GUILayout.EndVertical(); DrawSectionHeader("AVAILABILITY DIAGNOSTICS"); GUILayout.BeginVertical(GUI.skin.box, Array.Empty<GUILayoutOption>()); DrawMutedLabel("Enabled mask: " + RunebornServerComfort.GetEnabledBuffMask()); DrawMutedLabel("Last received mask: " + RunebornBuffAvailabilitySync.GetLastReceivedMask()); DrawMutedLabel("Last RPC sender: " + RunebornBuffAvailabilitySync.GetLastRpcSender()); DrawMutedLabel("Last request sender: " + RunebornBuffAvailabilitySync.GetLastRequestSender()); GUILayout.EndVertical(); DrawSectionHeader("ADMIN ID"); GUILayout.BeginVertical(GUI.skin.box, Array.Empty<GUILayoutOption>()); DrawMutedLabel(RunebornAdminTools.GetLocalAdminDebugText()); GUILayout.EndVertical(); } } public sealed class RunebornRustyStatusEffect : StatusEffect { public override string GetTooltipString() { return "10% less stamina used while Rested."; } } public sealed class RunebornSeppyStatusEffect : StatusEffect { public override string GetTooltipString() { return "10% less incoming damage.\n15% less stamina used while blocking."; } } public sealed class RunebornXpertStatusEffect : StatusEffect { public override string GetTooltipString() { return "10% more melee damage.\n10% less weapon stamina used while Rested with a melee weapon."; } } public sealed class RunebornChaosStatusEffect : StatusEffect { public override string GetTooltipString() { return "10% faster movement.\n20% faster sneak.\n12% stronger jump.\n15% less dodge and swim stamina."; } } public sealed class RunebornWitchyStatusEffect : StatusEffect { public override string GetTooltipString() { return "10% less staff and magic stamina while Rested."; } } public static class RunebornBuffStatusEffects { private const string RustyEffectName = "SE_RustyHeathens_RustyBuff"; private const string SeppyEffectName = "SE_RustyHeathens_SeppyBuff"; private const string XpertEffectName = "SE_RustyHeathens_XpertBuff"; private const string ChaosEffectName = "SE_RustyHeathens_ChaosBringerBuff"; private const string WitchyEffectName = "SE_RustyHeathens_WitchyBuff"; private static readonly int RustyEffectHash = StringExtensionMethods.GetStableHashCode("SE_RustyHeathens_RustyBuff"); private static readonly int SeppyEffectHash = StringExtensionMethods.GetStableHashCode("SE_RustyHeathens_SeppyBuff"); private static readonly int XpertEffectHash = StringExtensionMethods.GetStableHashCode("SE_RustyHeathens_XpertBuff"); private static readonly int ChaosEffectHash = StringExtensionMethods.GetStableHashCode("SE_RustyHeathens_ChaosBringerBuff"); private static readonly int WitchyEffectHash = StringExtensionMethods.GetStableHashCode("SE_RustyHeathens_WitchyBuff"); private static bool _registered; private static CustomStatusEffect _rustyStatusEffect; private static CustomStatusEffect _seppyStatusEffect; private static CustomStatusEffect _xpertStatusEffect; private static CustomStatusEffect _chaosStatusEffect; private static CustomStatusEffect _witchyStatusEffect; public static void Register() { if (!_registered) { Sprite val = LoadIconSprite("RustyBuffIcon_128.png"); Sprite val2 = LoadIconSprite("SeppyBuffIcon_128.png"); Sprite val3 = LoadIconSprite("XpertBuffIcon_128.png"); Sprite val4 = LoadIconSprite("ChaosBringerBuffIcon_128.png"); Sprite val5 = LoadIconSprite("WitchyBuffIcon_128.png"); if (!((Object)(object)val == (Object)null) && !((Object)(object)val2 == (Object)null) && !((Object)(object)val3 == (Object)null) && !((Object)(object)val4 == (Object)null) && !((Object)(object)val5 == (Object)null)) { _rustyStatusEffect = RegisterStatusEffect<RunebornRustyStatusEffect>("SE_RustyHeathens_RustyBuff", "Rusty Buff", val, "10% less stamina used while Rested."); _seppyStatusEffect = RegisterStatusEffect<RunebornSeppyStatusEffect>("SE_RustyHeathens_SeppyBuff", "Seppy Buff", val2, "10% less incoming damage and 15% less blocking stamina."); _xpertStatusEffect = RegisterStatusEffect<RunebornXpertStatusEffect>("SE_RustyHeathens_XpertBuff", "Xpert Buff", val3, "10% more melee damage and 10% less weapon stamina."); _chaosStatusEffect = RegisterStatusEffect<RunebornChaosStatusEffect>("SE_RustyHeathens_ChaosBringerBuff", "Chaos Bringer", val4, "Movement, sneak, jump, dodge, and swim bonuses."); _witchyStatusEffect = RegisterStatusEffect<RunebornWitchyStatusEffect>("SE_RustyHeathens_WitchyBuff", "Witchy Buff", val5, "10% less staff and magic stamina while Rested."); _registered = _rustyStatusEffect != null && _seppyStatusEffect != null && _xpertStatusEffect != null && _chaosStatusEffect != null && _witchyStatusEffect != null; } } } public static void UpdateLocalPlayerEffects() { if (!_registered) { Register(); } Player localPlayer = Player.m_localPlayer; if (!((Object)(object)localPlayer == (Object)null)) { SEMan sEMan = ((Character)localPlayer).GetSEMan(); if (sEMan != null) { SyncStatusEffect(sEMan, RustyEffectHash, RunebornServerComfort.IsRustyRestedActiveForLocalPlayer()); SyncStatusEffect(sEMan, SeppyEffectHash, RunebornServerComfort.IsSeppyBuffActiveForLocalPlayer()); SyncStatusEffect(sEMan, XpertEffectHash, RunebornServerComfort.IsXpertBuffActiveForLocalPlayer()); SyncStatusEffect(sEMan, ChaosEffectHash, RunebornServerComfort.IsChaosBringerBuffActiveForLocalPlayer()); SyncStatusEffect(sEMan, WitchyEffectHash, RunebornServerComfort.IsWitchyBuffActiveForLocalPlayer()); } } } private static CustomStatusEffect RegisterStatusEffect<T>(string effectName, string displayName, Sprite icon, string fallbackTooltip) where T : StatusEffect { //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Expected O, but got Unknown try { T val = ScriptableObject.CreateInstance<T>(); ((Object)(object)val).name = effectName; ((StatusEffect)val).m_name = displayName; ((StatusEffect)val).m_tooltip = fallbackTooltip; ((StatusEffect)val).m_icon = icon; ((StatusEffect)val).m_ttl = 0f; CustomStatusEffect val2 = new CustomStatusEffect((StatusEffect)(object)val, false); ItemManager.Instance.AddStatusEffect(val2); return val2; } catch { return null; } } private static void SyncStatusEffect(SEMan statusManager, int effectHash, bool shouldBeActive) { bool flag = statusManager.HaveStatusEffect(effectHash); if (shouldBeActive && !flag) { statusManager.AddStatusEffect(effectHash, true, 0, 0f); } else if (!shouldBeActive && flag) { statusManager.RemoveStatusEffect(effectHash, false); } } private static Sprite LoadIconSprite(string fileName) { try { string directoryName = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); if (string.IsNullOrEmpty(directoryName)) { return null; } string text = Path.Combine(directoryName, "Assets", fileName); if (!File.Exists(text)) { return null; } return AssetUtils.LoadSpriteFromFile(text); } catch { return null; } } } public static class RunebornBuffSlotSyncFoundation { private const string RpcName = "RustyHeathensRuneborn.BuffSlotSyncFoundation"; private const string RequestRpcName = "RustyHeathensRuneborn.BuffSlotSyncRequest"; private static bool _registered; private static bool _lateJoinRequestSent; private static float _nextLateJoinRequestTime; private static long _requestedServerPeerId = long.MinValue; private static long _lastRequestSender; private static int _lastReceivedMaxBuffSlots; private static long _lastRpcSender; private static long _lastServerPeerId = long.MinValue; private static long _lastLocalPeerId = long.MinValue; private static bool _lastSenderTrusted; public static void EnsureRegistered() { if (_registered || ZRoutedRpc.instance == null) { return; } try { ZRoutedRpc.instance.Register<int>("RustyHeathensRuneborn.BuffSlotSyncFoundation", (Action<long, int>)RPC_BuffSlotSyncFoundation); ZRoutedRpc.instance.Register<int>("RustyHeathensRuneborn.BuffSlotSyncRequest", (Action<long, int>)RPC_BuffSlotSyncRequest); _registered = true; } catch { _registered = true; } } public static long GetLastRequestSender() { return _lastRequestSender; } public static void UpdateLateJoinRequest() { EnsureRegistered(); if (!_registered || ZRoutedRpc.instance == null || RunebornAdminTools.IsLocalAdmin() || (Object)(object)Player.m_localPlayer == (Object)null) { return; } long num = TryGetRoutedRpcId("GetServerPeerID"); if (num == long.MinValue) { return; } if (_requestedServerPeerId != num) { _requestedServerPeerId = num; _lateJoinRequestSent = false; _nextLateJoinRequestTime = 0f; } if (_lateJoinRequestSent || Time.unscaledTime < _nextLateJoinRequestTime) { return; } try { ZRoutedRpc.instance.InvokeRoutedRPC(num, "RustyHeathensRuneborn.BuffSlotSyncRequest", new object[1] { 1 }); _lateJoinRequestSent = true; } catch { _nextLateJoinRequestTime = Time.unscaledTime + 2f; } } public static int GetLastReceivedMaxBuffSlots() { return _lastReceivedMaxBuffSlots; } public static long GetLastRpcSender() { return _lastRpcSender; } public static long GetLastServerPeerId() { return _lastServerPeerId; } public static long GetLastLocalPeerId() { return _lastLocalPeerId; } public static bool WasLastSenderTrusted() { return _lastSenderTrusted; } public static bool DoLastRpcIdsMatch() { if (_lastServerPeerId != long.MinValue) { return _lastRpcSender == _lastServerPeerId; } return false; } public static string GetLastRpcSenderHex() { ulong lastRpcSender = (ulong)_lastRpcSender; return lastRpcSender.ToString("X16"); } public static string GetLastServerPeerIdHex() { ulong lastServerPeerId = (ulong)_lastServerPeerId; return lastServerPeerId.ToString("X16"); } private static long TryGetRoutedRpcId(string methodName) { if (ZRoutedRpc.instance == null) { return long.MinValue; } try { MethodInfo method = typeof(ZRoutedRpc).GetMethod(methodName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (method == null) { return long.MinValue; } object obj = method.Invoke(ZRoutedRpc.instance, null); if (obj == null) { return long.MinValue; } return Convert.ToInt64(obj); } catch { return long.MinValue; } } private static bool IsTrustedServerSender(long sender) { _lastServerPeerId = TryGetRoutedRpcId("GetServerPeerID"); _lastLocalPeerId = TryGetRoutedRpcId("GetUID"); if (_lastServerPeerId == long.MinValue) { return false; } return sender.ToString() == _lastServerPeerId.ToString(); } public static void BroadcastMaxBuffSlots(int maxBuffs) { if (!RunebornAdminTools.IsLocalAdmin()) { return; } EnsureRegistered(); if (ZRoutedRpc.instance == null) { return; } int num = Mathf.Clamp(maxBuffs, 1, 3); try { ZRoutedRpc.instance.InvokeRoutedRPC(ZRoutedRpc.Everybody, "RustyHeathensRuneborn.BuffSlotSyncFoundation", new object[1] { num }); } catch { } } private static void RPC_BuffSlotSyncRequest(long sender, int value) { _lastRequestSender = sender; if (!RunebornAdminTools.IsLocalAdmin() || ZRoutedRpc.instance == null) { return; } int num = Mathf.Clamp(RunebornServerComfort.GetMaxSelectedBuffs(), 1, 3); try { ZRoutedRpc.instance.InvokeRoutedRPC(sender, "RustyHeathensRuneborn.BuffSlotSyncFoundation", new object[1] { num }); } catch { } } private static void RPC_BuffSlotSyncFoundation(long sender, int value) { _lastRpcSender = sender; _lastSenderTrusted = IsTrustedServerSender(sender); if (_lastSenderTrusted) { _lastReceivedMaxBuffSlots = Mathf.Clamp(value, 1, 3); RunebornServerComfort.ApplySyncedMaxSelectedBuffs(_lastReceivedMaxBuffSlots); } } } public static class RunebornBuffAvailabilitySync { private const string ValueRpcName = "RustyHeathensRuneborn.BuffAvailabilitySyncValue"; private const string RequestRpcName = "RustyHeathensRuneborn.BuffAvailabilitySyncRequest"; private const int AllBuffsMask = 31; private static bool _registered; private static bool _lateJoinRequestSent; private static float _nextLateJoinRequestTime; private static long _requestedServerPeerId = long.MinValue; private static int _lastReceivedMask = 31; private static long _lastRpcSender; private static long _lastServerPeerId = long.MinValue; private static long _lastRequestSender; private static bool _lastSenderTrusted; public static void EnsureRegistered() { if (_registered || ZRoutedRpc.instance == null) { return; } try { ZRoutedRpc.instance.Register<int>("RustyHeathensRuneborn.BuffAvailabilitySyncValue", (Action<long, int>)RPC_BuffAvailabilityValue); ZRoutedRpc.instance.Register<int>("RustyHeathensRuneborn.BuffAvailabilitySyncRequest", (Action<long, int>)RPC_BuffAvailabilityRequest); _registered = true; } catch { _registered = true; } } public static void UpdateLateJoinRequest() { EnsureRegistered(); if (!_registered || ZRoutedRpc.instance == null || RunebornAdminTools.IsLocalAdmin() || (Object)(object)Player.m_localPlayer == (Object)null) { return; } long num = TryGetRoutedRpcId("GetServerPeerID"); if (num == long.MinValue) { return; } if (_requestedServerPeerId != num) { _requestedServerPeerId = num; _lateJoinRequestSent = false; _nextLateJoinRequestTime = 0f; } if (_lateJoinRequestSent || Time.unscaledTime < _nextLateJoinRequestTime) { return; } try { ZRoutedRpc.instance.InvokeRoutedRPC(num, "RustyHeathensRuneborn.BuffAvailabilitySyncRequest", new object[1] { 1 }); _lateJoinRequestSent = true; } catch { _nextLateJoinRequestTime = Time.unscaledTime + 2f; } } public static void BroadcastEnabledBuffMask(int enabledMask) { if (!RunebornAdminTools.IsLocalAdmin()) { return; } EnsureRegistered(); if (ZRoutedRpc.instance == null) { return; } int num = enabledMask & 0x1F; try { ZRoutedRpc.instance.InvokeRoutedRPC(ZRoutedRpc.Everybody, "RustyHeathensRuneborn.BuffAvailabilitySyncValue", new object[1] { num }); } catch { } } public static int GetLastReceivedMask() { return _lastReceivedMask; } public static long GetLastRpcSender() { return _lastRpcSender; } public static long GetLastRequestSender() { return _lastRequestSender; } public static bool WasLastSenderTrusted() { return _lastSenderTrusted; } private static void RPC_BuffAvailabilityRequest(long sender, int value) { _lastRequestSender = sender; if (!RunebornAdminTools.IsLocalAdmin() || ZRoutedRpc.instance == null) { return; } int num = RunebornServerComfort.GetEnabledBuffMask() & 0x1F; try { ZRoutedRpc.instance.InvokeRoutedRPC(sender, "RustyHeathensRuneborn.BuffAvailabilitySyncValue", new object[1] { num }); } catch { } } private static void RPC_BuffAvailabilityValue(long sender, int value) { _lastRpcSender = sender; _lastSenderTrusted = IsTrustedServerSender(sender); if (_lastSenderTrusted) { _lastReceivedMask = value & 0x1F; RunebornServerComfort.ApplySyncedEnabledBuffMask(_lastReceivedMask); } } private static bool IsTrustedServerSender(long sender) { _lastServerPeerId = TryGetRoutedRpcId("GetServerPeerID"); if (_lastServerPeerId != long.MinValue) { return sender == _lastServerPeerId; } return false; } private static long TryGetRoutedRpcId(string methodName) { if (ZRoutedRpc.instance == null) { return long.MinValue; } try { MethodInfo method = typeof(ZRoutedRpc).GetMethod(methodName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (method == null) { return long.MinValue; } object obj = method.Invoke(ZRoutedRpc.instance, null); return (obj != null) ? Convert.ToInt64(obj) : long.MinValue; } catch { return long.MinValue; } } } public static class RunebornAdminEventMessages { private const string RpcName = "RustyHeathensRuneborn.AdminEventMessage"; private static bool _registered; public static void EnsureRegistered() { if (_registered || ZRoutedRpc.instance == null) { return; } try { ZRoutedRpc.instance.Register<string>("RustyHeathensRuneborn.AdminEventMessage", (Action<long, string>)RPC_AdminEventMessage); _registered = true; } catch { _registered = true; } } public static void SendAdminBroadcast(string title, string body) { if (!RunebornAdminTools.IsLocalAdmin()) { ShowLocal("Admin event buttons are locked."); return; } EnsureRegistered(); string text = "RUSTY HEATHENS EVENT\n" + title + "\n" + body; if (ZRoutedRpc.instance == null) { ShowLocal(text); return; } try { ZRoutedRpc.instance.InvokeRoutedRPC(ZRoutedRpc.Everybody, "RustyHeathensRuneborn.AdminEventMessage", new object[1] { text }); } catch { ShowLocal(text); } } private static void RPC_AdminEventMessage(long sender, string message) { ShowLocal(message); } private static void ShowLocal(string message) { if ((Object)(object)Player.m_localPlayer == (Object)null) { return; } try { ((Character)Player.m_localPlayer).Message((MessageType)2, message, 0, (Sprite)null); } catch { } } } public static class RunebornAdminTools { private const string RustySteamId = "76561198921017348"; public static bool IsLocalAdmin() { try { return GetLocalAdminDebugText().Contains("76561198921017348"); } catch { return false; } } public static string GetLocalAdminDebugText() { try { List<string> localSteamIdCandidates = GetLocalSteamIdCandidates(); if (localSteamIdCandidates.Count == 0) { return "No SteamID detected"; } return string.Join(", ", localSteamIdCandidates.ToArray()); } catch { return "SteamID debug failed"; } } private static List<string> GetLocalSteamIdCandidates() { List<string> list = new List<string>(); try { Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer != (Object)null) { AddCandidate(list, TryCallNoArgs(localPlayer, "GetPlayerID")); AddCandidate(list, TryCallNoArgs(localPlayer, "GetNetworkUserId")); AddCandidate(list, TryCallNoArgs(localPlayer, "GetSteamID")); AddCandidate(list, GetFieldValue(localPlayer, "m_playerID")); AddCandidate(list, GetFieldValue(localPlayer, "m_steamID")); } object zNetInstance = GetZNetInstance(); if (zNetInstance != null) { AddCandidate(list, TryCallNoArgs(zNetInstance, "GetUID")); AddCandidate(list, TryCallNoArgs(zNetInstance, "GetSteamID")); AddCandidate(list, GetFieldValue(zNetInstance, "m_steamID")); AddCandidate(list, GetFieldValue(zNetInstance, "m_mySteamID")); AddCandidate(list, GetFieldValue(zNetInstance, "m_steamId")); AddCandidate(list, GetFieldValue(zNetInstance, "m_userID")); } AddSteamworksCandidate(list); AddKnownTypeCandidates(list); } catch { } return list; } private static void AddCandidate(List<string> candidates, object value) { if (value == null) { return; } AddCandidateString(candidates, value.ToString()); Type type = value.GetType(); FieldInfo[] fields = type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); foreach (FieldInfo fieldInfo in fields) { string text = fieldInfo.Name.ToLowerInvariant(); if (!text.Contains("id") && !text.Contains("steam")) { continue; } try { object value2 = fieldInfo.GetValue(value); if (value2 != null) { AddCandidateString(candidates, value2.ToString()); } } catch { } } PropertyInfo[] properties = type.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); foreach (PropertyInfo propertyInfo in properties) { string text2 = propertyInfo.Name.ToLowerInvariant(); if ((!text2.Contains("id") && !text2.Contains("steam")) || propertyInfo.GetIndexParameters().Length != 0) { continue; } try { object value3 = propertyInfo.GetValue(value, null); if (value3 != null) { AddCandidateString(candidates, value3.ToString()); } } catch { } } } private static void AddCandidateString(List<string> candidates, string value) { string text = NormalizeSteamId(value); if (!string.IsNullOrEmpty(text) && !candidates.Contains(text)) { candidates.Add(text); } } private static string NormalizeSteamId(string value) { if (string.IsNullOrEmpty(value)) { return string.Empty; } string text = string.Empty; for (int i = 0; i < value.Length; i++) { char c = value[i]; if (char.IsDigit(c)) { text += c; continue; } if (text.Length >= 15) { return text; } text = string.Empty; } if (text.Length >= 15) { return text; } return string.Empty; } private static object GetZNetInstance() { try { Type typeFromHandle = typeof(ZNet); FieldInfo field = typeFromHandle.GetField("instance", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); if (field != null) { object value = field.GetValue(null); if (value != null) { return value; } } PropertyInfo property = typeFromHandle.GetProperty("instance", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); if (property != null) { object value2 = property.GetValue(null, null); if (value2 != null) { return value2; } } return Object.FindObjectOfType(typeFromHandle); } catch { return null; } } private static object GetFieldValue(object target, string fieldName) { if (target == null) { return null; } try { FieldInfo field = target.GetType().GetField(fieldName, BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); return (field != null) ? field.GetValue(target) : null; } catch { return null; } } private static object TryCallNoArgs(object target, string methodName) { if (target == null) { return null; } try { MethodInfo method = target.GetType().GetMethod(methodName, BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic, null, Type.EmptyTypes, null); return (method != null) ? method.Invoke(target, null) : null; } catch { return null; } } private static void AddSteamworksCandidate(List<string> candidates) { try { Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies(); for (int i = 0; i < assemblies.Length; i++) { Type type = assemblies[i].GetType("Steamworks.SteamUser"); if (!(type == null)) { MethodInfo method = type.GetMethod("GetSteamID", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic, null, Type.EmptyTypes, null); if (!(method == null)) { object value = method.Invoke(null, null); AddCandidate(candidates, value); } } } } catch { } } private static void AddKnownTypeCandidates(List<string> candidates) { try { Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies(); for (int i = 0; i < assemblies.Length; i++) { Type[] array = SafeGetTypes(assemblies[i]); foreach (Type type in array) { string text = type.Name.ToLowerInvariant(); if (text.Contains("platform") || text.Contains("steam") || text.Contains("playfab")) { object staticInstance = GetStaticInstance(type); if (staticInstance != null) { AddCandidate(candidates, TryCallNoArgs(staticInstance, "GetLocalUserId")); AddCandidate(candidates, TryCallNoArgs(staticInstance, "GetLocalUserID")); AddCandidate(candidates, TryCallNoArgs(staticInstance, "GetLocalUser")); AddCandidate(candidates, TryCallNoArgs(staticInstance, "GetUserID")); AddCandidate(candidates, TryCallNoArgs(staticInstance, "GetUID")); AddCandidate(candidates, TryCallNoArgs(staticInstance, "GetSteamID")); AddCandidate(candidates, GetFieldValue(staticInstance, "m_steamID")); AddCandidate(candidates, GetFieldValue(staticInstance, "m_userID")); } } } } } catch { } } private static Type[] SafeGetTypes(Assembly assembly) { try { return assembly.GetTypes(); } catch { return new Type[0]; } } private static object GetStaticInstance(Type type) { try { FieldInfo field = type.GetField("instance", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); if (field != null) { object value = field.GetValue(null); if (value != null) { return value; } } PropertyInfo property = type.GetProperty("instance", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); if (property != null) { object value2 = property.GetValue(null, null); if (value2 != null) { return value2; } } } catch { } return null; } } [HarmonyPatch(typeof(Character), "OnDeath")] public static class RunebornBossKillMessagesPatch { private static string _lastBossKey = string.Empty; private static float _lastBossMessageTime; private static void Postfix(Character __instance) { if ((Object)(object)__instance == (Object)null || (Object)(object)Player.m_localPlayer == (Object)null) { return; } string bossDisplayName = GetBossDisplayName(((Object)((Component)__instance).gameObject).name); if (string.IsNullOrEmpty(bossDisplayName)) { return; } string text = bossDisplayName.ToLowerInvariant(); if (_lastBossKey == text && Time.time - _lastBossMessageTime < 8f) { return; } _lastBossKey = text; _lastBossMessageTime = Time.time; ((Character)Player.m_localPlayer).Message((MessageType)2, "The Rusty Heathens defeated " + bossDisplayName + "!\nValhalla heard the victory roar.", 0, (Sprite)null); try { ZLog.Log((object)("[RustyHeathensRuneborn] Boss defeated: " + bossDisplayName)); } catch { } } private static string GetBossDisplayName(string rawName) { if (string.IsNullOrEmpty(rawName)) { return string.Empty; } string text = rawName.ToLowerInvariant(); if (text.Contains("eikthyr")) { return "Eikthyr"; } if (text.Contains("gd_king") || text.Contains("theelder")) { return "The Elder"; } if (text.Contains("bonemass")) { return "Bonemass"; } if (text.Contains("dragon") || text.Contains("moder")) { return "Moder"; } if (text.Contains("goblinking") || text.Contains("yagluth")) { return "Yagluth"; } if (text.Contains("queen") || text.Contains("seekerqueen")) { return "The Queen"; } if (text.Contains("fader")) { return "Fader"; } return string.Empty; } } [HarmonyPatch(typeof(Player), "Awake")] public static class RunebornWelcomeMessageOncePlayerAwakePatch { private static void Postfix(Player __instance) { if (!((Object)(object)__instance == (Object)null) && (Object)(object)((Component)__instance).GetComponent<RunebornWelcomeMessageOnce>() == (Object)null) { ((Component)__instance).gameObject.AddComponent<RunebornWelcomeMessageOnce>(); } } } public sealed class RunebornWelcomeMessageOnce : MonoBehaviour { private static bool _welcomeShownThisGameSession; private Player _player; private bool _shown; private float _showAt; private const string WelcomeText = "Welcome to the Rusty Heathens\nSurvive the chaos. Earn Valhalla."; private void Awake() { _player = ((Component)this).GetComponent<Player>(); _showAt = Time.time + 5f; if (_welcomeShownThisGameSession) { _shown = true; } } private void Update() { if (_shown || (Object)(object)_player == (Object)null || (Object)(object)Player.m_localPlayer != (Object)(object)_player || Time.time < _showAt) { return; } _shown = true; _welcomeShownThisGameSession = true; try { ((Character)_player).Message((MessageType)2, "Welcome to the Rusty Heathens\nSurvive the chaos. Earn Valhalla.", 0, (Sprite)null); } catch { } } } [HarmonyPatch(typeof(Player), "Awake")] public static class RunebornServerReminderPlayerAwakePatch { private static void Postfix(Player __instance) { if (!((Object)(object)__instance == (Object)null) && (Object)(object)((Component)__instance).GetComponent<RunebornServerReminder>() == (Object)null) { ((Component)__instance).gameObject.AddComponent<RunebornServerReminder>(); } } } public sealed class RunebornServerReminder : MonoBehaviour { private static bool _serverReminderShownThisGameSession; private Player _player; private int _messagesShown; private float _nextMessageAt; public static bool ServerReminderEnabled = true; private const int ReminderRepeatCount = 1; private const float ReminderFirstDelay = 16f; private const float ReminderRepeatDelay = 6f; private const string ReminderText = "RUSTY HEATHENS SERVER\n\nRespect the crew.\nNo stealing.\nNo boss fights without the group.\nHelp with body recovery when you can.\nJoin Discord for rules, events, and updates.\n\nSkal, Heathens!"; private void Awake() { _player = ((Component)this).GetComponent<Player>(); _nextMessageAt = Time.time + 16f; if (_serverReminderShownThisGameSession) { _messagesShown = 1; } } private void Update() { if (_messagesShown < 1 && ServerReminderEnabled && !((Object)(object)_player == (Object)null) && !((Object)(object)Player.m_localPlayer != (Object)(object)_player) && !(Time.time < _nextMessageAt)) { try { ((Character)_player).Message((MessageType)2, "RUSTY HEATHENS SERVER\n\nRespect the crew.\nNo stealing.\nNo boss fights without the group.\nHelp with body recovery when you can.\nJoin Discord for rules, events, and updates.\n\nSkal, Heathens!", 0, (Sprite)null); } catch { } _messagesShown++; _serverReminderShownThisGameSession = true; _nextMessageAt = Time.time + 6f; } } } [HarmonyPatch(typeof(Player), "Awake")] public static class RunebornRaidWarningsPlayerAwakePatch { private static void Postfix(Player __instance) { if (!((Object)(object)__instance == (Object)null) && (Object)(object)((Component)__instance).GetComponent<RunebornRaidWarnings>() == (Object)null) { ((Component)__instance).gameObject.AddComponent<RunebornRaidWarnings>(); } } } public sealed class RunebornRaidWarnings : MonoBehaviour { private Player _player; private string _activeRaid = string.Empty; private float _nextCheck; private float _nextRepeatMessage; public static bool RaidWarningsEnabled = true; private void Awake() { _player = ((Component)this).GetComponent<Player>(); } private void Update() { if (!((Object)(object)_player == (Object)null) && !((Object)(object)Player.m_localPlayer != (Object)(object)_player) && RaidWarningsEnabled && !(Time.time < _nextCheck)) { _nextCheck = Time.time + 1f; string currentRaidDisplayName = GetCurrentRaidDisplayName(); if (!string.IsNullOrEmpty(currentRaidDisplayName) && string.IsNullOrEmpty(_activeRaid)) { _activeRaid = currentRaidDisplayName; _nextRepeatMessage = Time.time + 45f; ShowCenter("RAID WARNING\n" + currentRaidDisplayName + "\nThe Rusty Heathens are under attack!"); } else if (!string.IsNullOrEmpty(currentRaidDisplayName) && currentRaidDisplayName == _activeRaid && Time.time >= _nextRepeatMessage) { _nextRepeatMessage = Time.time + 45f; ShowCenter("RAID STILL ACTIVE\n" + currentRaidDisplayName + "\nHold the line, Heathens!"); } else if (string.IsNullOrEmpty(currentRaidDisplayName) && !string.IsNullOrEmpty(_activeRaid)) { ShowCenter("RAID CLEARED\nThe Heathens still stand."); _activeRaid = string.Empty; _nextRepeatMessage = 0f; } } } public static string GetCurrentRaidDisplayName() { object currentRandomEventObject = GetCurrentRandomEventObject(); if (currentRandomEventObject == null) { return string.Empty; } string text = GetStringField(currentRandomEventObject, "m_name"); if (string.IsNullOrEmpty(text)) { text = currentRandomEventObject.ToString(); } return MakeRaidNameFriendly(text); } private static object GetCurrentRandomEventObject() { try { Type type = Type.GetType("RandEventSystem, Assembly-CSharp"); if (type == null) { return null; } object obj = GetStaticField(type, "instance") ?? GetStaticField(type, "m_instance"); if (obj == null) { Object val = Object.FindObjectOfType(type); if (val != (Object)null) { obj = val; } } if (obj == null) { return null; } return GetInstanceField(obj, "m_randomEvent") ?? GetInstanceField(obj, "m_currentRandomEvent") ?? GetInstanceField(obj, "m_event"); } catch { return null; } } private static object GetStaticField(Type type, string fieldName) { FieldInfo field = type.GetField(fieldName, BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); if (!(field != null)) { return null; } return field.GetValue(null); } private static object GetInstanceField(object target, string fieldName) { if (target == null) { return null; } FieldInfo field = target.GetType().GetField(fieldName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (!(field != null)) { return null; } return field.GetValue(target); } private static string GetStringField(object target, string fieldName) { object instanceField = GetInstanceField(target, fieldName); if (instanceField == null) { return string.Empty; } return instanceField.ToString(); } private static string MakeRaidNameFriendly(string rawName) { if (string.IsNullOrEmpty(rawName)) { return "Unknown Raid"; } string text = rawName.ToLowerInvariant(); if (text.Contains("army_eikthyr")) { return "Eikthyr's Herd"; } if (text.Contains("army_theelder") || text.Contains("foresttrolls")) { return "The Forest Moves"; } if (text.Contains("army_bonemass") || text.Contains("skeletons")) { return "Bonemass' Dead"; } if (text.Contains("army_moder") || text.Contains("wolves")) { return "The Mountain Hunt"; } if (text.Contains("army_goblin") || text.Contains("goblin")) { return "The Plains Warband"; } if (text.Contains("army_gjall") || text.Contains("gjall")) { return "Mistlands Terror"; } if (text.Contains("army_charred") || text.Contains("charred")) { return "Ashlands Siege"; } return CleanName(rawName); } private static string CleanName(string rawName) { string text = rawName.Replace("$event_", string.Empty).Replace("event_", string.Empty).Replace("army_", string.Empty) .Replace("_", " ") .Trim(); if (string.IsNullOrEmpty(text)) { return "Unknown Raid"; } StringBuilder stringBuilder = new StringBuilder(text.Length); bool flag = true; string text2 = text; foreach (char c in text2) { if (char.IsWhiteSpace(c)) { stringBuilder.Append(c); flag = true; } else if (flag) { stringBuilder.Append(char.ToUpperInvariant(c)); flag = false; } else { stringBuilder.Append(c); } } return stringBuilder.ToString(); } private void ShowCenter(string text) { if ((Object)(object)_player == (Object)null) { return; } try { ((Character)_player).Message((MessageType)2, text, 0, (Sprite)null); } catch { } } } [HarmonyPatch(typeof(Player), "Awake")] public static class RunebornServerComfortPlayerAwakePatch { private static void Postfix(Player __instance) { if (!((Object)(object)__instance == (Object)null) && (Object)(object)((Component)__instance).GetComponent<RunebornServerComfort>() == (Object)null) { ((Component)__instance).gameObject.AddComponent<RunebornServerComfort>(); } } } [HarmonyPatch(typeof(Player), "GetMaxCarryWeight")] public static class RunebornBodyRecoveryCarryWeightPatch { private static void Postfix(Player __instance, ref float __result) { if (!((Object)(object)__instance == (Object)null) && !((Object)(object)Player.m_localPlayer != (Object)(object)__instance) && RunebornServerComfort.IsBodyRecoveryActiveForLocalPlayer()) { __result += 150f; } } } [HarmonyPatch(typeof(Character), "UseStamina")] public static class RunebornBodyRecoveryStaminaUsePatch { private static void Prefix(Character __instance, ref float stamina) { if (!((Object)(object)__instance == (Object)null) && !((Object)(object)Player.m_localPlayer == (Object)null) && (object)__instance == Player.m_localPlayer) { if (RunebornServerComfort.IsBodyRecoveryActiveForLocalPlayer()) { stamina *= 0.65f; } if (RunebornServerComfort.IsRustyRestedActiveForLocalPlayer()) { stamina *= 0.9f; } if (RunebornServerComfort.IsSeppyBuffActiveForLocalPlayer() && RunebornServerComfort.IsLocalPlayerBlocking()) { stamina *= 0.85f; } if (RunebornServerComfort.IsXpertBuffActiveForLocalPlayer()) { stamina *= 0.9f; } if (RunebornServerComfort.IsLocalPlayerInChaosMovementStaminaState()) { stamina *= 0.85f; } if (RunebornServerComfort.IsWitchyMagicStaminaActiveForLocalPlayer()) { stamina *= 0.9f; } if (RunebornServerComfort.IsBuildComfortActiveForLocalPlayer()) { stamina *= 0.5f; } } } } [HarmonyPatch(typeof(Character), "Damage")] public static class RunebornSeppyBuffDamageReductionPatch { private static void Prefix(Character __instance, HitData hit) { if (!((Object)(object)__instance == (Object)null) && hit != null && !((Object)(object)Player.m_localPlayer == (Object)null) && (object)__instance == Player.m_localPlayer && RunebornServerComfort.IsSeppyBuffActiveForLocalPlayer()) { RunebornServerComfort.ScaleHitDamage(hit, 0.9f); } } } [HarmonyPatch(typeof(Character), "Damage")] public static class RunebornXpertBuffDamageBoostPatch { private static void Prefix(Character __instance, HitData hit) { if (!((Object)(object)__instance == (Object)null) && hit != null && !((Object)(object)Player.m_localPlayer == (Object)null)) { Character val = RunebornServerComfort.TryGetHitAttacker(hit); if (!((Object)(object)val == (Object)null) && (object)val == Player.m_localPlayer && (object)__instance != Player.m_localPlayer && RunebornServerComfort.IsXpertBuffActiveForLocalPlayer()) { RunebornServerComfort.ScaleHitDamage(hit, 1.1f); } } } } [HarmonyPatch(typeof(Player), "Update")] public static class RunebornChaosBringerMovementOnlyPatch { private static void Postfix(Player __instance) { try { RunebornServerComfort.ApplyChaosBringerMovementOnly(__instance); } catch { } } } public sealed class RunebornServerComfort : MonoBehaviour { private const string DeathCountKey = "RustyHeathensRuneborn.DeathCount"; private const string BodyRecoveryExpiresKey = "RustyHeathensRuneborn.BodyRecoveryExpiresUtcTicks"; private const float BodyRecoverySeconds = 600f; private Player _player; private bool _wasDead; private bool _bodyRecoveryNoticeShown; private float _nextCheck; private string _deathMessageRepeatText = string.Empty; private int _deathMessageRepeatsLeft; private float _nextDeathMessageRepeatAt; private const int DefaultMaxSelectedBuffs = 2; private const string MaxSelectedBuffsKey = "RustyHeathensRuneborn.MaxSelectedBuffs"; private const string SelectedBuffsKey = "RustyHeathensRuneborn.SelectedBuffs"; private const string EnabledBuffMaskKey = "RustyHeathensRuneborn.EnabledBuffMask"; private const int RustyBuffBit = 1; private const int SeppyBuffBit = 2; private const int XpertBuffBit = 4; private const int ChaosBuffBit = 8; private const int WitchyBuffBit = 16; private const int AllBuffsMask = 31; private static readonly Dictionary<int, Dictionary<string, float>> ChaosMovementBaseValues = new Dictionary<int, Dictionary<string, float>>(); private static int MaxSelectedBuffs => Mathf.Clamp(PlayerPrefs.GetInt("RustyHeathensRuneborn.MaxSelectedBuffs", 2), 1, 3); private void Awake() { _player = ((Component)this).GetComponent<Player>(); } private void Update() { if (!((Object)(object)_player == (Object)null) && !((Object)(object)Player.m_localPlayer != (Object)(object)_player) && !(Time.time < _nextCheck)) { _nextCheck = Time.time + 0.25f; bool flag = IsPlayerDead(_player); if (flag && !_wasDead) { RegisterLocalDeath(); } if (!flag && _wasDead) { _bodyRecoveryNoticeShown = false; } _wasDead = flag; TryShowBodyRecoveryReminder(flag); TryRepeatDeathMessage(); } } private void RegisterLocalDeath() { int num = PlayerPrefs.GetInt("RustyHeathensRuneborn.DeathCount", 0) + 1; PlayerPrefs.SetInt("RustyHeathensRuneborn.DeathCount", num); PlayerPrefs.SetString("RustyHeathensRuneborn.BodyRecoveryExpiresUtcTicks", DateTime.UtcNow.AddSeconds(600.0).Ticks.ToString()); PlayerPrefs.Save(); string funnyDeathMessage = GetFunnyDeathMessage(num); string text = "Death #" + num + "\n" + funnyDeathMessage + "\nBody Recovery ready for 10 minutes.\n+150 carry weight, less stamina used."; ShowCenter(text); _deathMessageRepeatText = text; _deathMessageRepeatsLeft = 2; _nextDeathMessageRepeatAt = Time.time + 3.5f; try { ZLog.Log((object)("[RustyHeathensRuneborn] Local death count: " + num)); } catch { } } public static string PreviewNextFunnyDeathMessage(int currentDeathCount) { return GetFunnyDeathMessage(currentDeathCount + 1); } private static string GetFunnyDeathMessage(int deathCount) { if (deathCount <= 1) { return "First blood. Valhalla is watching."; } switch (deathCount) { case 10: return "Ten deaths. The Heathens are officially warming up."; case 25: return "Twenty-five deaths. Odin filed a report."; case 50: return "Fifty deaths. The death counter needs a bigger boat."; case 100: return "One hundred deaths. Seppy would be proud."; default: { string[] array = new string[20] { "Another shortcut to Valhalla.", "Odin saw that. So did chat.", "Body recovery team, saddle up.", "The ground won that fight.", "Your gear is now on a side quest.", "The Rusty Heathens death counter demands tribute.", "Not a death, just aggressive fast travel.", "That was tactical. Probably.", "The trolls are taking notes.", "Somebody clip that.", "Valheim said no.", "The corpse run begins.", "Rusty Heathens rule one: do not panic. Too late.", "The swamp sends its regards.", "The mountain claimed another kneecap.", "Ashlands heard you were feeling confident.", "The Plains mosquito has entered the chat.", "Mistlands visibility: zero. Survival odds: also zero.", "A brave death. A questionable plan.", "The gear is fine. The owner, less so." }; int num = Mathf.Abs(deathCount - 2) % array.Length; return array[num]; } } } private void TryRepeatDeathMessage() { if (_deathMessageRepeatsLeft > 0) { if (string.IsNullOrEmpty(_deathMessageRepeatText)) { _deathMessageRepeatsLeft = 0; } else if (!(Time.time < _nextDeathMessageRepeatAt)) { ShowCenter(_deathMessageRepeatText); _deathMessageRepeatsLeft--; _nextDeathMessageRepeatAt = Time.time + 3.5f; } } } private void TryShowBodyRecoveryReminder(bool isDead) { if (!isDead && !_bodyRecoveryNoticeShown) { float bodyRecoverySecondsLeft = GetBodyRecoverySecondsLeft(); if (!(bodyRecoverySecondsLeft <= 0f)) { _bodyRecoveryNoticeShown = true; ShowCenter("Body Recovery Active\n" + Mathf.CeilToInt(bodyRecoverySecondsLeft / 60f) + " minutes to get your gear."); } } } public static bool IsSeppyBuffActiveForLocalPlayer() { if (IsBuffSelected("seppy")) { return IsLocalPlayerRested(); } return false; } public static bool IsLocalPlayerBlocking() { Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null) { return false; } try { MethodInfo method = typeof(Humanoid).GetMethod("IsBlocking", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (method != null) { object obj = method.Invoke(localPlayer, null); if (obj is bool) { return (bool)obj; } } } catch { } return IsShieldEquipped(localPlayer); } private static bool IsShieldEquipped(Player player) { if ((Object)(object)player == (Object)null) { return false; } try { MethodInfo method = typeof(Humanoid).GetMethod("GetLeftItem", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (method == null) { return false; } object obj = method.Invoke(player, null); if (obj == null) { return false; } string text = GetItemSharedName(obj).ToLowerInvariant(); return text.Contains("shield") || text.Contains("buckler") || text.Contains("tower"); } catch { return false; } } public static void ScaleHitDamage(HitData hit, float scale) { if (hit == null) { return; } try { object fieldValue = GetFieldValue(hit, "m_damage"); if (fieldValue != null) { ScaleDamageTypesObject(fieldValue, scale); } } catch { } } private static object GetFieldValue(object target, string fieldName) { if (target == null) { return null; } FieldInfo field = target.GetType().GetField(fieldName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (!(field != null)) { return null; } return field.GetValue(target); } private static void ScaleDamageTypesObject(object damageTypes, float scale) { if (damageTypes == null) { return; } FieldInfo[] fields = damageTypes.GetType().GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); foreach (FieldInfo fieldInfo in fields) { if (!(fieldInfo.FieldType != typeof(float))) { string text = fieldInfo.Name.ToLowerInvariant(); if (text.Contains("damage") || text.Contains("blunt") || text.Contains("slash") || text.Contains("pierce") || text.Contains("chop") || text.Contains("pickaxe") || text.Contains("fire") || text.Contains("frost") || text.Contains("lightning") || text.Contains("poison") || text.Contains("spirit")) { float num = (float)fieldInfo.GetValue(damageTypes); fieldInfo.SetValue(damageTypes, num * scale); } } } } public static bool IsXpertBuffActiveForLocalPlayer() { if (IsBuffSelected("xpert") && IsLocalPlayerRested()) { return IsLocalPlayerUsingBerserkerWeapon(); } return false; } public static bool IsLocalPlayerUsingBerserkerWeapon() { Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null) { return false; } try { MethodInfo method = typeof(Humanoid).GetMethod("GetRightItem", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (method == null) { return false; } object obj = method.Invoke(localPlayer, null); if (obj == null) { return false; } string text = GetItemSharedName(obj).ToLowerInvariant(); return text.Contains("axe") || text.Contains("battleaxe") || text.Contains("sword") || text.Contains("mace") || text.Contains("club") || text.Contains("knife") || text.Contains("atgeir") || text.Contains("spear"); } catch { return false; } } public static Character TryGetHitAttacker(HitData hit) { if (hit == null) { return null; } try { MethodInfo method = ((object)hit).GetType().GetMethod("GetAttacker", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, Type.EmptyTypes, null); if (method == null) { return null; } object? obj = method.Invoke(hit, null); return (Character)((obj is Character) ? obj : null); } catch { return null; } } public static bool IsChaosBringerBuffActiveForLocalPlayer() { if (IsBuffSelected("chaos")) { return IsLocalPlayerRested(); } return false; } public static void ApplyChaosBringerMovementOnly(Player player) { if ((Object)(object)player == (Object)null || (Object)(object)Player.m_localPlayer == (Object)null || player != Player.m_localPlayer) { return; } int instanceID = ((Object)player).GetInstanceID(); bool flag = IsChaosBringerBuffActiveForLocalPlayer(); string[] array = new string[6] { "m_walkSpeed", "m_runSpeed", "m_crouchSpeed", "m_swimSpeed", "m_jumpForce", "m_jumpForceForward" }; if (flag) { if (!ChaosMovementBaseValues.ContainsKey(instanceID)) { ChaosMovementBaseValues[instanceID] = new Dictionary<string, float>(); } Dictionary<string, float> dictionary = ChaosMovementBaseValues[instanceID]; string[] array2 = array; foreach (string text in array2) { FieldInfo fieldInfo = FindChaosFloatField(player, text); if (!(fieldInfo == null)) { if (!dictionary.ContainsKey(text)) { dictionary[text] = (float)fieldInfo.GetValue(player); } float num = 1.1f; if (text == "m_crouchSpeed") { num = 1.2f; } if (text == "m_jumpForce" || text == "m_jumpForceForward") { num = 1.12f; } fieldInfo.SetValue(player, dictionary[text] * num); } } } else { RestoreChaosBringerMovementOnly(player, instanceID); } } private static void RestoreChaosBringerMovementOnly(Player player, int playerKey) { if ((Object)(object)player == (Object)null || !ChaosMovementBaseValues.ContainsKey(playerKey)) { return; } foreach (KeyValuePair<string, float> item in ChaosMovementBaseValues[playerKey]) { FieldInfo fieldInfo = FindChaosFloatField(player, item.Key); if (fieldInfo != null) { fieldInfo.SetValue(player, item.Value); } } ChaosMovementBaseValues.Remove(playerKey); } private static FieldInfo FindChaosFloatField(object target, string fieldName) { if (target == null || string.IsNullOrEmpty(fieldName)) { return null; } Type type = target.GetType(); while (type != null) { FieldInfo field = type.GetField(fieldName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (field != null && field.FieldType == typeof(float)) { return field; } type = type.BaseType; } return null; } public static bool IsLocalPlayerInChaosMovementStaminaState() { if (!IsChaosBringerBuffActiveForLocalPlayer()) { return false; } Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null) { return false; } if (!TryCallChaosBool(localPlayer, "IsSwimming") && !TryCallChaosBool(localPlayer, "InDodge") && !TryCallChaosBool(localPlayer, "IsDodgeInvincible") && !TryGetChaosBoolField(localPlayer, "m_dodgeInvincible")) { return TryGetChaosBoolField(localPlayer, "m_dodging"); } return true; } private static bool TryCallChaosBool(object target, string methodName) { if (target == null || string.IsNullOrEmpty(methodName)) { return false; } Type type = target.GetType(); while (type != null) { MethodInfo method = type.GetMethod(methodName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, Type.EmptyTypes, null); if (method != null && method.ReturnType == typeof(bool)) { return (bool)method.Invoke(target, null); } type = type.BaseType; } return false; } private static bool TryGetChaosBoolField(object target, string fieldName) { if (target == null || string.IsNullOrEmpty(fieldName)) { return false; } Type type = target.GetType(); while (type != null) { FieldInfo field = type.GetField(fieldName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (field != null && field.FieldType == typeof(bool)) { return (bool)field.GetValue(target); } type = type.BaseType; } return false; } public static bool IsWitchyBuffActiveForLocalPlayer() { if (IsBuffSelected("witchy")) { return IsLocalPlayerRested(); } return false; } public static bool IsWitchyMagicStaminaActiveForLocalPlayer() { if (IsWitchyBuffActiveForLocalPlayer()) { return IsLocalPlayerUsingWitchyWeapon(); } return false; } public static bool IsLocalPlayerUsingWitchyWeapon() { Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null) { return false; } try { MethodInfo method = typeof(Humanoid).GetMethod("GetRightItem", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (method == null) { return false; } object obj = method.Invoke(localPlayer, null); if (obj == null) { return false; } string text = GetWitchyItemName(obj).ToLowerInvariant(); return text.Contains("staff") || text.Contains("magic") || text.Contains("eitr") || text.Contains("wand") || text.Contains("scepter") || text.Contains("trollstav") || text.Contains("deadraiser") || text.Contains("protection") || text.Contains("embers") || text.Contains("frost"); } catch { return false; } } private static string GetWitchyItemName(object item) { if (item == null) { return string.Empty; } try { FieldInfo field = item.GetType().GetField("m_shared", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (field == null) { return item.ToString(); } object value = field.GetValue(item); if (value == null) { return item.ToString(); } FieldInfo field2 = value.GetType().GetField("m_name", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (field2 == null) { return value.ToString(); } object value2 = field2.GetValue(value); if (value2 == null) { return string.Empty; } return value2.ToString(); } catch { return string.Empty; } } public static bool IsBuildComfortActiveForLocalPlayer() { Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null) { return false; } try { MethodInfo method = typeof(Humanoid).GetMethod("GetRightItem", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (method == null) { return false; } object obj = method.Invoke(localPlayer, null); if (obj == null) { return false; } string text = GetItemSharedName(obj).ToLowerInvariant(); return text.Contains("hammer") || text.Contains("hoe") || text.Contains("cultivator"); } catch { return false; } } private static string GetItemSharedName(object item) { if (item == null) { return string.Empty; } FieldInfo field = item.GetType().GetField("m_shared", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); object obj = ((field != null) ? field.GetValue(item) : null); if (obj == null) { return string.Empty; } FieldInfo field2 = obj.GetType().GetField("m_name", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); object obj2 = ((field2 != n