Decompiled source of SpongePEAKLib v1.0.0
plugins/com.sponge.peaklib.dll
Decompiled 8 hours ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using System.Text; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Configuration; using ExitGames.Client.Photon; using HarmonyLib; using Microsoft.CodeAnalysis; using MonoMod.Utils; using Photon.Pun; using Photon.Realtime; using SpongePEAK.Core.Config; using SpongePEAK.Core.Game; using SpongePEAK.Core.Logging; using SpongePEAK.Core.Patching; using SpongePEAK.Lib.Items; using SpongePEAK.Lib.Mods; using SpongePEAK.Lib.UI; using TMPro; using UnityEngine; using UnityEngine.Events; using UnityEngine.Localization; using UnityEngine.SceneManagement; using UnityEngine.UI; using Zorro.Core; using Zorro.Settings; using Zorro.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("sponge")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyCopyright("Copyright (c) sponge")] [assembly: AssemblyDescription("Modding API tier: plugin base, game event bus and networking helpers.")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0+ddcbf023fcb4c2065ad9b038910633cd4a3a93b0")] [assembly: AssemblyProduct("SpongePEAKLib")] [assembly: AssemblyTitle("com.sponge.peaklib")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.0.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace SpongePEAK.Lib.UI { public sealed class HudBar { private readonly RectTransform _root; private readonly RectTransform _fill; private readonly Image _fillImage; private float _value = 1f; public bool IsValid { get { if ((Object)(object)_root != (Object)null) { return (Object)(object)_fill != (Object)null; } return false; } } public RectTransform Transform => _root; public float Value { get { return _value; } set { //IL_002b: Unknown result type (might be due to invalid IL or missing references) _value = Mathf.Clamp01(value); if ((Object)(object)_fill != (Object)null) { _fill.anchorMax = new Vector2(_value, 1f); } } } public Color Color { get { //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)_fillImage != (Object)null)) { return Color.white; } return ((Graphic)_fillImage).color; } set { //IL_0014: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_fillImage != (Object)null) { ((Graphic)_fillImage).color = value; } } } public static HudBar Create(string name, float width = 120f, float height = 10f) { Transform root = HudRoot.Root; if ((Object)(object)root == (Object)null) { return null; } return new HudBar(name, root, width, height); } private HudBar(string name, Transform parent, float width, float height) { //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Expected O, but got Unknown //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Expected O, but got Unknown //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_0077: Unknown result type (might be due to invalid IL or missing references) //IL_009f: Unknown result type (might be due to invalid IL or missing references) //IL_00a5: Expected O, but got Unknown //IL_00ac: Unknown result type (might be due to invalid IL or missing references) //IL_00b6: Expected O, but got Unknown //IL_00d8: Unknown result type (might be due to invalid IL or missing references) //IL_00f2: Unknown result type (might be due to invalid IL or missing references) //IL_010c: Unknown result type (might be due to invalid IL or missing references) //IL_0126: Unknown result type (might be due to invalid IL or missing references) //IL_0142: Unknown result type (might be due to invalid IL or missing references) GameObject val = new GameObject(name, new Type[1] { typeof(RectTransform) }); _root = (RectTransform)val.transform; ((Transform)_root).SetParent(parent, false); _root.sizeDelta = new Vector2(width, height); Image obj = val.AddComponent<Image>(); ((Graphic)obj).color = new Color(0f, 0f, 0f, 0.55f); ((Graphic)obj).raycastTarget = false; GameObject val2 = new GameObject("Fill", new Type[1] { typeof(RectTransform) }); _fill = (RectTransform)val2.transform; ((Transform)_fill).SetParent((Transform)(object)_root, false); _fill.anchorMin = new Vector2(0f, 0f); _fill.anchorMax = new Vector2(1f, 1f); _fill.offsetMin = new Vector2(1f, 1f); _fill.offsetMax = new Vector2(-1f, -1f); _fillImage = val2.AddComponent<Image>(); ((Graphic)_fillImage).color = Color.white; ((Graphic)_fillImage).raycastTarget = false; } public void SetVisible(bool visible) { if ((Object)(object)_root != (Object)null && ((Component)_root).gameObject.activeSelf != visible) { ((Component)_root).gameObject.SetActive(visible); } } public void Destroy() { if ((Object)(object)_root != (Object)null) { Object.Destroy((Object)(object)((Component)_root).gameObject); } } } public static class HudRoot { private static Transform _root; private static ModLog _log; private const string RootName = "SpongePEAK_HUD"; public static bool IsReady => (Object)(object)_root != (Object)null; public static Transform Root { get { //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Unknown result type (might be due to invalid IL or missing references) //IL_0077: 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_0082: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_008d: 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_00ad: Expected O, but got Unknown if ((Object)(object)_root != (Object)null) { return _root; } GUIManager instance = GUIManager.instance; if ((Object)(object)instance == (Object)null || (Object)(object)instance.hudCanvas == (Object)null) { return null; } RectTransform val = (RectTransform)new GameObject("SpongePEAK_HUD", new Type[1] { typeof(RectTransform) }).transform; ((Transform)val).SetParent(((Component)instance.hudCanvas).transform, false); val.anchorMin = Vector2.zero; val.anchorMax = Vector2.one; val.offsetMin = Vector2.zero; val.offsetMax = Vector2.zero; ((Component)val).gameObject.AddComponent<CanvasGroup>().blocksRaycasts = false; _root = (Transform)val; ModLog log = _log; if (log != null) { log.Debug((object)"HUD root attached to the game's hudCanvas."); } return _root; } } public static void SetLogger(ModLog log) { _log = log; } public static TextMeshProUGUI CreateLabel(string name, UiAnchor anchor = UiAnchor.TopLeft, float fontSize = 18f) { //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Expected O, but got Unknown //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Unknown result type (might be due to invalid IL or missing references) Transform root = Root; if ((Object)(object)root == (Object)null) { return null; } GameObject val = new GameObject(name, new Type[1] { typeof(RectTransform) }); RectTransform val2 = (RectTransform)val.transform; ((Transform)val2).SetParent(root, false); TextMeshProUGUI val3 = val.AddComponent<TextMeshProUGUI>(); ((TMP_Text)val3).fontSize = fontSize; ((Graphic)val3).color = Color.white; ((Graphic)val3).raycastTarget = false; ((TMP_Text)val3).outlineWidth = 0.2f; ((TMP_Text)val3).outlineColor = new Color32((byte)0, (byte)0, (byte)0, byte.MaxValue); ApplyAnchor(val2, val3, anchor); return val3; } private static void ApplyAnchor(RectTransform rect, TextMeshProUGUI text, UiAnchor anchor) { //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0054: 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_008a: Unknown result type (might be due to invalid IL or missing references) //IL_00ab: Unknown result type (might be due to invalid IL or missing references) //IL_00c0: Unknown result type (might be due to invalid IL or missing references) //IL_00e1: Unknown result type (might be due to invalid IL or missing references) //IL_00f6: Unknown result type (might be due to invalid IL or missing references) //IL_0117: Unknown result type (might be due to invalid IL or missing references) //IL_0122: Unknown result type (might be due to invalid IL or missing references) //IL_0143: Unknown result type (might be due to invalid IL or missing references) rect.sizeDelta = new Vector2(600f, 40f); switch (anchor) { case UiAnchor.TopLeft: SetAnchor(rect, new Vector2(0f, 1f)); rect.anchoredPosition = new Vector2(20f, -20f); ((TMP_Text)text).alignment = (TextAlignmentOptions)257; break; case UiAnchor.TopRight: SetAnchor(rect, new Vector2(1f, 1f)); rect.anchoredPosition = new Vector2(-20f, -20f); ((TMP_Text)text).alignment = (TextAlignmentOptions)260; break; case UiAnchor.BottomLeft: SetAnchor(rect, new Vector2(0f, 0f)); rect.anchoredPosition = new Vector2(20f, 20f); ((TMP_Text)text).alignment = (TextAlignmentOptions)1025; break; case UiAnchor.BottomRight: SetAnchor(rect, new Vector2(1f, 0f)); rect.anchoredPosition = new Vector2(-20f, 20f); ((TMP_Text)text).alignment = (TextAlignmentOptions)1028; break; case UiAnchor.Center: SetAnchor(rect, new Vector2(0.5f, 0.5f)); rect.anchoredPosition = Vector2.zero; ((TMP_Text)text).alignment = (TextAlignmentOptions)514; break; case UiAnchor.World: SetAnchor(rect, new Vector2(0.5f, 0.5f)); ((TMP_Text)text).alignment = (TextAlignmentOptions)514; break; } } private static void SetAnchor(RectTransform rect, Vector2 anchor) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) rect.anchorMin = anchor; rect.anchorMax = anchor; rect.pivot = anchor; } public static bool PositionAtWorldPoint(RectTransform rect, Vector3 worldPoint, Camera camera = null) { //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0027: 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_004f: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_007a: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_0082: Unknown result type (might be due to invalid IL or missing references) //IL_008a: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Unknown result type (might be due to invalid IL or missing references) //IL_009d: Unknown result type (might be due to invalid IL or missing references) //IL_00a9: Unknown result type (might be due to invalid IL or missing references) //IL_00b0: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)rect == (Object)null) { return false; } if (camera == null) { camera = Camera.main; } if ((Object)(object)camera == (Object)null) { return false; } Vector3 val = camera.WorldToViewportPoint(worldPoint); if (val.z <= 0f) { return false; } Transform parent = ((Transform)rect).parent; RectTransform val2 = (RectTransform)(object)((parent is RectTransform) ? parent : null); if ((Object)(object)val2 == (Object)null) { return false; } Rect rect2 = val2.rect; Vector2 size = ((Rect)(ref rect2)).size; Vector2 val3 = default(Vector2); ((Vector2)(ref val3))..ctor(0.5f, 0.5f); rect.pivot = val3; Vector2 anchorMin = (rect.anchorMax = val3); rect.anchorMin = anchorMin; rect.anchoredPosition = new Vector2((val.x - 0.5f) * size.x, (val.y - 0.5f) * size.y); return true; } public static void Reset() { _root = null; } } public enum UiAnchor { TopLeft, TopRight, BottomLeft, BottomRight, Center, World } public static class MenuIntegration { private sealed class MenuButtonRequest { public string Label; public Action OnClick; } private static readonly List<MenuButtonRequest> PauseButtons = new List<MenuButtonRequest>(); private static readonly List<MenuButtonRequest> MainMenuButtons = new List<MenuButtonRequest>(); private static ModLog _log; private static bool _patched; public static void SetLogger(ModLog log) { _log = log; PeakStyle.SetLogger(log); } public static void AddPauseMenuButton(string label, Action onClick) { if (!string.IsNullOrEmpty(label) && onClick != null) { PauseButtons.Add(new MenuButtonRequest { Label = label, OnClick = onClick }); ModLog log = _log; if (log != null) { log.Debug((object)("Registered pause menu button '" + label + "'.")); } } } public static void AddMainMenuButton(string label, Action onClick) { if (!string.IsNullOrEmpty(label) && onClick != null) { MainMenuButtons.Add(new MenuButtonRequest { Label = label, OnClick = onClick }); ModLog log = _log; if (log != null) { log.Debug((object)("Registered main menu button '" + label + "'.")); } } } public static void Install(Harmony harmony) { if (_patched || harmony == null) { return; } try { harmony.PatchAll(typeof(MenuIntegrationPatches)); _patched = true; ModLog log = _log; if (log != null) { log.Debug((object)"Menu integration hooks installed."); } } catch (Exception ex) { ModLog log2 = _log; if (log2 != null) { log2.Exception("Failed to install menu integration hooks", ex); } } } internal static void PopulatePauseMenu(PauseMenuMainPage page) { if ((Object)(object)page == (Object)null || PauseButtons.Count == 0) { return; } try { Button resumeButton = page.resumeButton; if ((Object)(object)resumeButton == (Object)null) { return; } Transform parent = ((Component)resumeButton).transform.parent; if ((Object)(object)parent == (Object)null) { return; } foreach (MenuButtonRequest pauseButton in PauseButtons) { CreateOnce(parent, pauseButton); } } catch (Exception ex) { ModLog log = _log; if (log != null) { log.Exception("Failed to populate the pause menu", ex); } } } internal static void PopulateMainMenu(MainMenuMainPage page) { if ((Object)(object)page == (Object)null || MainMenuButtons.Count == 0) { return; } try { Button value = Traverse.Create((object)page).Field("m_settingsButton").GetValue<Button>(); Transform val = (((Object)(object)value != (Object)null) ? ((Component)value).transform.parent : ((Component)page).transform); if ((Object)(object)val == (Object)null) { return; } foreach (MenuButtonRequest mainMenuButton in MainMenuButtons) { CreateOnce(val, mainMenuButton); } } catch (Exception ex) { ModLog log = _log; if (log != null) { log.Exception("Failed to populate the main menu", ex); } } } private static void CreateOnce(Transform parent, MenuButtonRequest request) { string text = "SpongeUI_Button_" + request.Label; for (int i = 0; i < parent.childCount; i++) { if (((Object)parent.GetChild(i)).name == text) { return; } } PeakStyle.CreateButton(request.Label, parent, request.OnClick); } } internal static class MenuIntegrationPatches { [HarmonyPatch(typeof(MainMenu), "Start")] [HarmonyPostfix] private static void MainMenuStarted() { PeakStyle.TryCapture(); } [HarmonyPatch(typeof(MainMenuMainPage), "Start")] [HarmonyPostfix] private static void MainMenuPageStarted(MainMenuMainPage __instance) { PeakStyle.TryCapture(); MenuIntegration.PopulateMainMenu(__instance); } [HarmonyPatch(typeof(PauseMenuMainPage), "OnEnable")] [HarmonyPostfix] private static void PauseMenuPageEnabled(PauseMenuMainPage __instance) { MenuIntegration.PopulatePauseMenu(__instance); } } public sealed class ModalCursorWindow : MenuWindow { private ModLog _log; public Action Closed; public override bool showCursorWhileOpen => true; public override bool blocksPlayerInput => true; public override bool openOnStart => false; public override bool closeOnUICancel => true; public override bool selectOnOpen => false; public void SetLogger(ModLog log) { _log = log; } public void SetOpen(bool open) { try { MethodInfo method = typeof(MenuWindow).GetMethod(open ? "Open" : "Close", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (method == null) { ModLog log = _log; if (log != null) { log.Warning((object)("MenuWindow." + (open ? "Open" : "Close") + " not found; the game may have changed.")); } return; } method.Invoke(this, null); GUIManager instance = GUIManager.instance; if (instance != null) { instance.UpdateWindowStatus(); } } catch (Exception ex) { ModLog log2 = _log; if (log2 != null) { log2.Exception("Could not " + (open ? "open" : "close") + " the window", ex); } } } protected override void OnClose() { ((MenuWindow)this).OnClose(); try { Closed?.Invoke(); } catch (Exception ex) { ModLog log = _log; if (log != null) { log.Exception("A window close handler threw", ex); } } } } public static class PeakStyle { private const string ButtonSourceName = "UI_MainMenuButton_LeaveGame (2)"; private const string SettingsCellName = "SettingsCell"; private static ModLog _log; public static GameObject ButtonTemplate { get; private set; } public static GameObject SettingsCellTemplate { get; private set; } public static bool IsReady => (Object)(object)ButtonTemplate != (Object)null; public static void SetLogger(ModLog log) { _log = log; } public static bool TryCapture() { if (IsReady) { return true; } try { GameObject[] source = Resources.FindObjectsOfTypeAll<GameObject>(); GameObject val = ((IEnumerable<GameObject>)source).FirstOrDefault((Func<GameObject, bool>)((GameObject g) => (Object)(object)g != (Object)null && ((Object)g).name == "UI_MainMenuButton_LeaveGame (2)")); GameObject val2 = ((IEnumerable<GameObject>)source).FirstOrDefault((Func<GameObject, bool>)((GameObject g) => (Object)(object)g != (Object)null && ((Object)g).name == "SettingsCell")); if ((Object)(object)val == (Object)null) { ModLog log = _log; if (log != null) { log.Debug((object)"PeakStyle: button template not present yet."); } return false; } ButtonTemplate = Object.Instantiate<GameObject>(val); ((Object)ButtonTemplate).name = "SpongeUI_ButtonTemplate"; StripTemplate(ButtonTemplate); Object.DontDestroyOnLoad((Object)(object)ButtonTemplate); ButtonTemplate.SetActive(false); if ((Object)(object)val2 != (Object)null) { SettingsCellTemplate = Object.Instantiate<GameObject>(val2); ((Object)SettingsCellTemplate).name = "SpongeUI_SettingsCellTemplate"; StripTemplate(SettingsCellTemplate); Object.DontDestroyOnLoad((Object)(object)SettingsCellTemplate); SettingsCellTemplate.SetActive(false); } ModLog log2 = _log; if (log2 != null) { log2.Info((object)"PeakStyle: captured UI templates from the game."); } return true; } catch (Exception ex) { ModLog log3 = _log; if (log3 != null) { log3.Exception("PeakStyle: failed to capture UI templates", ex); } return false; } } private static void StripTemplate(GameObject template) { LocalizedText[] componentsInChildren = template.GetComponentsInChildren<LocalizedText>(true); for (int i = 0; i < componentsInChildren.Length; i++) { Object.DestroyImmediate((Object)(object)componentsInChildren[i]); } Button[] componentsInChildren2 = template.GetComponentsInChildren<Button>(true); for (int i = 0; i < componentsInChildren2.Length; i++) { ((UnityEventBase)componentsInChildren2[i].onClick).RemoveAllListeners(); } } public static Button CreateButton(string label, Transform parent, Action onClick) { //IL_0080: Unknown result type (might be due to invalid IL or missing references) //IL_008a: Expected O, but got Unknown if (!TryCapture() || (Object)(object)parent == (Object)null) { return null; } GameObject obj = Object.Instantiate<GameObject>(ButtonTemplate, parent, false); ((Object)obj).name = "SpongeUI_Button_" + label; obj.SetActive(true); SetLabel(obj, label); Button componentInChildren = obj.GetComponentInChildren<Button>(true); if ((Object)(object)componentInChildren != (Object)null && onClick != null) { ((UnityEvent)componentInChildren.onClick).AddListener((UnityAction)delegate { try { onClick(); } catch (Exception ex) { ModLog log = _log; if (log != null) { log.Exception("Button '" + label + "' threw", ex); } } }); } return componentInChildren; } public static void SetLabel(GameObject instance, string label) { if ((Object)(object)instance == (Object)null) { return; } TextMeshProUGUI componentInChildren = instance.GetComponentInChildren<TextMeshProUGUI>(true); if ((Object)(object)componentInChildren != (Object)null) { ((TMP_Text)componentInChildren).text = label; return; } Text componentInChildren2 = instance.GetComponentInChildren<Text>(true); if ((Object)(object)componentInChildren2 != (Object)null) { componentInChildren2.text = label; } } public static void Reset() { if ((Object)(object)ButtonTemplate != (Object)null) { Object.Destroy((Object)(object)ButtonTemplate); } if ((Object)(object)SettingsCellTemplate != (Object)null) { Object.Destroy((Object)(object)SettingsCellTemplate); } ButtonTemplate = null; SettingsCellTemplate = null; } } public static class ScrollableList { public static ScrollRect Ensure(Transform content, ModLog log = null, float spacing = 4f) { //IL_0079: Unknown result type (might be due to invalid IL or missing references) //IL_007e: Unknown result type (might be due to invalid IL or missing references) //IL_009b: Unknown result type (might be due to invalid IL or missing references) //IL_00a7: Unknown result type (might be due to invalid IL or missing references) //IL_00b3: Unknown result type (might be due to invalid IL or missing references) //IL_00bf: Unknown result type (might be due to invalid IL or missing references) //IL_00cb: Unknown result type (might be due to invalid IL or missing references) //IL_00d7: Unknown result type (might be due to invalid IL or missing references) //IL_00e3: Unknown result type (might be due to invalid IL or missing references) //IL_0100: Unknown result type (might be due to invalid IL or missing references) //IL_0115: Unknown result type (might be due to invalid IL or missing references) //IL_012a: Unknown result type (might be due to invalid IL or missing references) //IL_0135: Unknown result type (might be due to invalid IL or missing references) //IL_0146: Unknown result type (might be due to invalid IL or missing references) //IL_0150: Unknown result type (might be due to invalid IL or missing references) //IL_0161: Unknown result type (might be due to invalid IL or missing references) //IL_016b: Unknown result type (might be due to invalid IL or missing references) try { RectTransform val = (RectTransform)(object)((content is RectTransform) ? content : null); if (val == null) { return null; } ScrollRect componentInParent = ((Component)content).GetComponentInParent<ScrollRect>(); if ((Object)(object)componentInParent != (Object)null) { return componentInParent; } Transform parent = ((Transform)val).parent; RectTransform val2 = (RectTransform)(object)((parent is RectTransform) ? parent : null); if ((Object)(object)val2 == (Object)null) { return null; } GameObject val3 = new GameObject("SpongeUI_Viewport", new Type[3] { typeof(RectTransform), typeof(RectMask2D), typeof(ScrollRect) }); RectTransform component = val3.GetComponent<RectTransform>(); ((Transform)component).SetParent((Transform)(object)val2, false); ((Transform)component).SetSiblingIndex(((Transform)val).GetSiblingIndex()); component.anchorMin = val.anchorMin; component.anchorMax = val.anchorMax; component.pivot = val.pivot; component.anchoredPosition = val.anchoredPosition; component.sizeDelta = val.sizeDelta; component.offsetMin = val.offsetMin; component.offsetMax = val.offsetMax; ((Transform)val).SetParent((Transform)(object)component, false); val.anchorMin = new Vector2(0f, 1f); val.anchorMax = new Vector2(1f, 1f); val.pivot = new Vector2(0.5f, 1f); val.anchoredPosition = Vector2.zero; val.offsetMin = new Vector2(0f, val.offsetMin.y); val.offsetMax = new Vector2(0f, val.offsetMax.y); if ((Object)(object)((Component)val).GetComponent<LayoutGroup>() == (Object)null) { VerticalLayoutGroup obj = ((Component)val).gameObject.AddComponent<VerticalLayoutGroup>(); ((HorizontalOrVerticalLayoutGroup)obj).childControlHeight = false; ((HorizontalOrVerticalLayoutGroup)obj).childControlWidth = true; ((HorizontalOrVerticalLayoutGroup)obj).childForceExpandHeight = false; ((HorizontalOrVerticalLayoutGroup)obj).childForceExpandWidth = true; ((HorizontalOrVerticalLayoutGroup)obj).spacing = spacing; } ContentSizeFitter obj2 = ((Component)val).GetComponent<ContentSizeFitter>() ?? ((Component)val).gameObject.AddComponent<ContentSizeFitter>(); obj2.verticalFit = (FitMode)2; obj2.horizontalFit = (FitMode)0; ScrollRect component2 = val3.GetComponent<ScrollRect>(); component2.content = val; component2.viewport = component; component2.horizontal = false; component2.vertical = true; component2.movementType = (MovementType)2; component2.scrollSensitivity = 30f; component2.inertia = false; if (log != null) { log.Debug((object)"Added scrolling to a list."); } return component2; } catch (Exception ex) { if (log != null) { log.Exception("Could not make a list scrollable", ex); } return null; } } public static void Refresh(ScrollRect scroll) { try { if (!((Object)(object)((scroll != null) ? scroll.content : null) == (Object)null)) { LayoutRebuilder.ForceRebuildLayoutImmediate(scroll.content); Canvas.ForceUpdateCanvases(); if (scroll.vertical) { scroll.verticalNormalizedPosition = 1f; } } } catch (Exception) { } } } } namespace SpongePEAK.Lib.Plugin { public abstract class SpongePlugin : BaseUnityPlugin { public ModLog Log { get; private set; } public PatchHost Patches { get; private set; } public bool LoadedSuccessfully { get; private set; } protected virtual string DisplayName => ((object)this).GetType().Name; protected abstract void OnLoad(); protected virtual void OnUnload() { } private void Awake() { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Expected O, but got Unknown //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Expected O, but got Unknown Log = new ModLog(DisplayName); Log.Attach(((BaseUnityPlugin)this).Logger); PluginInfo info = ((BaseUnityPlugin)this).Info; object obj; if (info == null) { obj = null; } else { BepInPlugin metadata = info.Metadata; obj = ((metadata != null) ? metadata.GUID : null); } if (obj == null) { obj = DisplayName; } Patches = new PatchHost((string)obj, Log); HudRoot.SetLogger(Log); MenuIntegration.SetLogger(Log); MenuIntegration.Install(Patches.Harmony); ModSettingsTab.SetLogger(Log); ModSettingsTab.Install(Patches.Harmony); ItemCloner.SetLogger(Log); ItemEffectPatches.Install(Patches.Harmony, Log); try { OnLoad(); LoadedSuccessfully = true; Log.Info((object)(DisplayName + " loaded.")); } catch (Exception ex) { LoadedSuccessfully = false; Log.Exception(DisplayName + " failed to load", ex); } } private void OnDestroy() { try { OnUnload(); } catch (Exception ex) { ModLog log = Log; if (log != null) { log.Exception(DisplayName + " threw during unload", ex); } } PatchHost patches = Patches; if (patches != null) { patches.Dispose(); } } } } namespace SpongePEAK.Lib.Platform { public enum HostPlatform { Unknown, Windows, Proton, Linux, MacOS } public static class PlatformInfo { private static bool _detected; private static HostPlatform _platform; private static string _detail; public static HostPlatform Current { get { Detect(); return _platform; } } public static string Detail { get { Detect(); return _detail; } } public static bool IsProton => Current == HostPlatform.Proton; public static bool IsNativeWindows => Current == HostPlatform.Windows; public static bool IsTranslated => Current == HostPlatform.Proton; private static void Detect() { //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Invalid comparison between Unknown and I4 //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Invalid comparison between Unknown and I4 //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Invalid comparison between Unknown and I4 //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Invalid comparison between Unknown and I4 //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Invalid comparison between Unknown and I4 //IL_0073: Unknown result type (might be due to invalid IL or missing references) if (_detected) { return; } _detected = true; _platform = HostPlatform.Unknown; _detail = "undetermined"; try { RuntimePlatform platform = Application.platform; if ((int)platform > 1) { if ((int)platform == 13 || (int)platform == 16) { _platform = HostPlatform.Linux; _detail = "native Linux build"; return; } if ((int)Application.platform != 2 && (int)Application.platform != 7) { _detail = $"unrecognised platform {Application.platform}"; return; } bool flag = false; try { flag = PlatformHelper.Is((Platform)131072); } catch (Exception) { } if (flag) { _platform = HostPlatform.Proton; _detail = DescribeProton(); } else { _platform = HostPlatform.Windows; _detail = "native Windows (no Wine markers)"; } } else { _platform = HostPlatform.MacOS; _detail = "native macOS build"; } } catch (Exception) { _platform = HostPlatform.Unknown; _detail = "detection failed"; } } private static string DescribeProton() { try { if (!string.IsNullOrEmpty(Environment.GetEnvironmentVariable("STEAM_COMPAT_DATA_PATH"))) { return "Proton (Steam compatibility layer)"; } if (!string.IsNullOrEmpty(Environment.GetEnvironmentVariable("WINEPREFIX"))) { return "Wine (WINEPREFIX set)"; } return "Wine/Proton (ntdll wine marker)"; } catch (Exception) { return "Wine/Proton (ntdll wine marker)"; } } } } namespace SpongePEAK.Lib.Net { public sealed class HostRuleSet : IInRoomCallbacks, IMatchmakingCallbacks { private readonly string _propertyKey; private readonly ModLog _log; private readonly Dictionary<string, bool> _defaults = new Dictionary<string, bool>(StringComparer.Ordinal); private readonly Dictionary<string, bool> _values = new Dictionary<string, bool>(StringComparer.Ordinal); private bool _registered; public static bool CanEdit { get { if (PhotonNetwork.InRoom) { return PhotonNetwork.IsMasterClient; } return true; } } public event Action Changed; public HostRuleSet(string propertyKey, ModLog log) { if (string.IsNullOrEmpty(propertyKey)) { throw new ArgumentException("A room property key is required.", "propertyKey"); } _propertyKey = propertyKey; _log = log; } public void Declare(string id, bool defaultValue) { if (!string.IsNullOrEmpty(id)) { _defaults[id] = defaultValue; } } public bool IsOn(string id) { if (_values.TryGetValue(id, out var value)) { return value; } bool value2; return _defaults.TryGetValue(id, out value2) && value2; } public bool Set(string id, bool value) { if (!_defaults.ContainsKey(id)) { ModLog log = _log; if (log != null) { log.Warning((object)("Ignored unknown host rule '" + id + "'.")); } return false; } if (!CanEdit) { ModLog log2 = _log; if (log2 != null) { log2.Debug((object)("Refused to set '" + id + "': not the host.")); } return false; } _values[id] = value; this.Changed?.Invoke(); Publish(); return true; } public void Start() { if (!_registered) { PhotonNetwork.AddCallbackTarget((object)this); _registered = true; } } public void Stop() { if (_registered) { PhotonNetwork.RemoveCallbackTarget((object)this); _registered = false; } } public void Publish() { //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Expected O, but got Unknown //IL_0028: Expected O, but got Unknown if (!PhotonNetwork.InRoom || !PhotonNetwork.IsMasterClient) { return; } try { Hashtable val = new Hashtable(); ((Dictionary<object, object>)val).Add((object)_propertyKey, (object)Serialize()); Hashtable val2 = val; PhotonNetwork.CurrentRoom.SetCustomProperties(val2, (Hashtable)null, (WebFlags)null); ModLog log = _log; if (log != null) { log.Debug((object)$"Published {_values.Count} host rule(s)."); } } catch (Exception ex) { ModLog log2 = _log; if (log2 != null) { log2.Exception("Could not publish host rules", ex); } } } public bool ApplyFromRoom() { if (PhotonNetwork.InRoom) { Room currentRoom = PhotonNetwork.CurrentRoom; if (((currentRoom != null) ? ((RoomInfo)currentRoom).CustomProperties : null) != null) { if (((Dictionary<object, object>)(object)((RoomInfo)PhotonNetwork.CurrentRoom).CustomProperties).TryGetValue((object)_propertyKey, out object value) && value is string payload) { return ApplyRemote(payload); } return ApplyRemote(string.Empty); } } return false; } private bool ApplyRemote(string payload) { Dictionary<string, bool> dictionary = Deserialize(payload); bool flag = dictionary.Count == _values.Count; if (flag) { foreach (KeyValuePair<string, bool> item in dictionary) { if (!_values.TryGetValue(item.Key, out var value) || value != item.Value) { flag = false; break; } } } if (flag) { return false; } _values.Clear(); foreach (KeyValuePair<string, bool> item2 in dictionary) { _values[item2.Key] = item2.Value; } ModLog log = _log; if (log != null) { log.Info((object)$"Applied {_values.Count} host rule(s)."); } this.Changed?.Invoke(); return true; } private string Serialize() { StringBuilder stringBuilder = new StringBuilder(); foreach (KeyValuePair<string, bool> value2 in _values) { if (!_defaults.TryGetValue(value2.Key, out var value) || value != value2.Value) { if (stringBuilder.Length > 0) { stringBuilder.Append(';'); } stringBuilder.Append(value2.Key).Append('=').Append(value2.Value ? '1' : '0'); } } return stringBuilder.ToString(); } private Dictionary<string, bool> Deserialize(string payload) { Dictionary<string, bool> dictionary = new Dictionary<string, bool>(StringComparer.Ordinal); if (string.IsNullOrEmpty(payload)) { return dictionary; } string[] array = payload.Split(';'); foreach (string text in array) { if (string.IsNullOrEmpty(text)) { continue; } int num = text.IndexOf('='); if (num > 0 && num < text.Length - 1) { string key = text.Substring(0, num); if (_defaults.ContainsKey(key)) { dictionary[key] = text[num + 1] == '1'; } } } return dictionary; } public IEnumerable<KeyValuePair<string, bool>> All() { foreach (KeyValuePair<string, bool> @default in _defaults) { yield return new KeyValuePair<string, bool>(@default.Key, IsOn(@default.Key)); } } public void OnRoomPropertiesUpdate(Hashtable propertiesThatChanged) { if (propertiesThatChanged != null && ((Dictionary<object, object>)(object)propertiesThatChanged).ContainsKey((object)_propertyKey) && !PhotonNetwork.IsMasterClient) { ApplyFromRoom(); } } public void OnJoinedRoom() { ApplyFromRoom(); } public void OnMasterClientSwitched(Player newMasterClient) { if (PhotonNetwork.IsMasterClient) { ApplyFromRoom(); Publish(); ModLog log = _log; if (log != null) { log.Info((object)"Promoted to host; keeping the lobby's current rules."); } } } public void OnPlayerEnteredRoom(Player newPlayer) { } public void OnPlayerLeftRoom(Player otherPlayer) { } public void OnPlayerPropertiesUpdate(Player target, Hashtable changedProps) { } public void OnCreatedRoom() { } public void OnCreateRoomFailed(short returnCode, string message) { } public void OnJoinRoomFailed(short returnCode, string message) { } public void OnJoinRandomFailed(short returnCode, string message) { } public void OnLeftRoom() { _values.Clear(); } public void OnFriendListUpdate(List<FriendInfo> friendList) { } } public enum LinkTier { Unknown, Good, Fair, Poor, Bad } public sealed class LinkQuality { private const int WindowSize = 12; private const int ChangeThreshold = 3; private readonly int[] _rtt = new int[12]; private readonly int[] _jitter = new int[12]; private int _count; private int _next; private int _lastResends; private int _resendDelta; private long _lastBytesIn; private long _lastBytesOut; private float _lastThroughputTime; private bool _throughputBaselineSet; private bool _resendBaselineSet; private LinkTier _tier; private LinkTier _pending; private int _pendingCount; private readonly ModLog _log; public LinkTier Tier => _tier; public int SmoothedRtt { get; private set; } public int SmoothedJitter { get; private set; } public int RecentResends => _resendDelta; public int QueuedOutgoing { get; private set; } public int UploadBytesPerSecond { get; private set; } public int DownloadBytesPerSecond { get; private set; } public event Action<LinkTier> TierChanged; public LinkQuality(ModLog log) { _log = log; } public void Sample() { try { LoadBalancingClient networkingClient = PhotonNetwork.NetworkingClient; LoadBalancingPeer val = ((networkingClient != null) ? networkingClient.LoadBalancingPeer : null); if (val == null || !PhotonNetwork.IsConnected) { return; } int roundTripTime = ((PhotonPeer)val).RoundTripTime; int roundTripTimeVariance = ((PhotonPeer)val).RoundTripTimeVariance; if (roundTripTime > 0) { _rtt[_next] = roundTripTime; _jitter[_next] = roundTripTimeVariance; _next = (_next + 1) % 12; if (_count < 12) { _count++; } SmoothedRtt = Average(_rtt); SmoothedJitter = Average(_jitter); int resentReliableCommands = ((PhotonPeer)val).ResentReliableCommands; if (!_resendBaselineSet) { _lastResends = resentReliableCommands; _resendBaselineSet = true; _resendDelta = 0; } else if (resentReliableCommands < _lastResends) { _lastResends = resentReliableCommands; _resendDelta = 0; } else { _resendDelta = resentReliableCommands - _lastResends; _lastResends = resentReliableCommands; } QueuedOutgoing = ((PhotonPeer)val).QueuedOutgoingCommands; SampleThroughput((PhotonPeer)(object)val); Evaluate(Classify()); } } catch (Exception ex) { ModLog log = _log; if (log != null) { log.Exception("Link quality sampling failed", ex); } } } private void SampleThroughput(PhotonPeer peer) { try { if (!peer.TrafficStatsEnabled) { peer.TrafficStatsEnabled = true; } long bytesIn = peer.BytesIn; long bytesOut = peer.BytesOut; float unscaledTime = Time.unscaledTime; if (!_throughputBaselineSet) { _lastBytesIn = bytesIn; _lastBytesOut = bytesOut; _lastThroughputTime = unscaledTime; _throughputBaselineSet = true; return; } float num = unscaledTime - _lastThroughputTime; if (!(num < 0.5f)) { if (bytesIn < _lastBytesIn || bytesOut < _lastBytesOut) { _lastBytesIn = bytesIn; _lastBytesOut = bytesOut; _lastThroughputTime = unscaledTime; } else { DownloadBytesPerSecond = (int)((float)(bytesIn - _lastBytesIn) / num); UploadBytesPerSecond = (int)((float)(bytesOut - _lastBytesOut) / num); _lastBytesIn = bytesIn; _lastBytesOut = bytesOut; _lastThroughputTime = unscaledTime; } } } catch (Exception ex) { ModLog log = _log; if (log != null) { log.Exception("Throughput sampling failed", ex); } } } private LinkTier Classify() { if (_count < 3) { return LinkTier.Unknown; } int smoothedRtt = SmoothedRtt; int smoothedJitter = SmoothedJitter; if (_resendDelta >= 8 || QueuedOutgoing >= 24) { return LinkTier.Bad; } if (smoothedRtt >= 400 || smoothedJitter >= 150) { return LinkTier.Bad; } if (smoothedRtt >= 220 || smoothedJitter >= 90 || _resendDelta >= 3) { return LinkTier.Poor; } if (smoothedRtt >= 110 || smoothedJitter >= 45 || _resendDelta >= 1) { return LinkTier.Fair; } return LinkTier.Good; } private void Evaluate(LinkTier candidate) { if (candidate == LinkTier.Unknown) { return; } if (candidate == _tier) { _pendingCount = 0; return; } if (candidate == _pending) { _pendingCount++; } else { _pending = candidate; _pendingCount = 1; } int num = ((candidate > _tier) ? 2 : 3); if (_pendingCount >= num) { LinkTier tier = _tier; _tier = candidate; _pendingCount = 0; ModLog log = _log; if (log != null) { log.Info((object)($"Connection quality {tier} -> {_tier} " + $"(rtt {SmoothedRtt}ms, jitter {SmoothedJitter}ms, " + $"resends {_resendDelta}, queued {QueuedOutgoing}).")); } this.TierChanged?.Invoke(_tier); } } private int Average(int[] values) { if (_count == 0) { return 0; } long num = 0L; for (int i = 0; i < _count; i++) { num += values[i]; } return (int)(num / _count); } public override string ToString() { return $"{_tier} (rtt {SmoothedRtt}ms, jitter {SmoothedJitter}ms)"; } } public sealed class LinkReporter : IInRoomCallbacks, IMatchmakingCallbacks { public const string PropertyKey = "sponge.link"; private readonly LinkQuality _quality; private readonly ModLog _log; private bool _registered; private LinkTier _published; public event Action Changed; public LinkReporter(LinkQuality quality, ModLog log) { _quality = quality; _log = log; } public void Start() { if (!_registered) { PhotonNetwork.AddCallbackTarget((object)this); _registered = true; if (_quality != null) { _quality.TierChanged += OnLocalTierChanged; } } } public void Stop() { if (_registered) { PhotonNetwork.RemoveCallbackTarget((object)this); _registered = false; if (_quality != null) { _quality.TierChanged -= OnLocalTierChanged; } } } private void OnLocalTierChanged(LinkTier tier) { Publish(); } public void Publish() { //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Expected O, but got Unknown //IL_0042: Expected O, but got Unknown if (!PhotonNetwork.InRoom || _quality == null) { return; } LinkTier tier = _quality.Tier; if (tier == LinkTier.Unknown || tier == _published) { return; } try { Hashtable val = new Hashtable(); ((Dictionary<object, object>)val).Add((object)"sponge.link", (object)(byte)tier); Hashtable val2 = val; PhotonNetwork.LocalPlayer.SetCustomProperties(val2, (Hashtable)null, (WebFlags)null); _published = tier; ModLog log = _log; if (log != null) { log.Debug((object)$"Published link tier {tier}."); } } catch (Exception ex) { ModLog log2 = _log; if (log2 != null) { log2.Exception("Could not publish link tier", ex); } } } public static LinkTier TierOf(Player player) { try { if (((player != null) ? player.CustomProperties : null) != null && ((Dictionary<object, object>)(object)player.CustomProperties).TryGetValue((object)"sponge.link", out object value) && value is byte b && Enum.IsDefined(typeof(LinkTier), (int)b)) { return (LinkTier)b; } } catch (Exception) { } return LinkTier.Unknown; } public static LinkTier WorstReported() { LinkTier linkTier = LinkTier.Unknown; try { Player[] playerList = PhotonNetwork.PlayerList; if (playerList == null) { return linkTier; } Player[] array = playerList; for (int i = 0; i < array.Length; i++) { LinkTier linkTier2 = TierOf(array[i]); if (linkTier2 != LinkTier.Unknown && linkTier2 > linkTier) { linkTier = linkTier2; } } return linkTier; } catch (Exception) { return LinkTier.Unknown; } } public static IEnumerable<KeyValuePair<string, LinkTier>> All() { Player[] playerList = PhotonNetwork.PlayerList; if (playerList != null) { Player[] array = playerList; foreach (Player val in array) { yield return new KeyValuePair<string, LinkTier>(val.NickName ?? "?", TierOf(val)); } } } public void OnPlayerPropertiesUpdate(Player targetPlayer, Hashtable changedProps) { if (changedProps != null && ((Dictionary<object, object>)(object)changedProps).ContainsKey((object)"sponge.link")) { this.Changed?.Invoke(); } } public void OnJoinedRoom() { _published = LinkTier.Unknown; Publish(); } public void OnPlayerEnteredRoom(Player newPlayer) { this.Changed?.Invoke(); } public void OnPlayerLeftRoom(Player otherPlayer) { this.Changed?.Invoke(); } public void OnRoomPropertiesUpdate(Hashtable propertiesThatChanged) { } public void OnMasterClientSwitched(Player newMasterClient) { } public void OnCreatedRoom() { } public void OnCreateRoomFailed(short returnCode, string message) { } public void OnJoinRoomFailed(short returnCode, string message) { } public void OnJoinRandomFailed(short returnCode, string message) { } public void OnLeftRoom() { _published = LinkTier.Unknown; } public void OnFriendListUpdate(List<FriendInfo> friendList) { } } public sealed class ModHandshake : IInRoomCallbacks, IMatchmakingCallbacks { public const string PropertyKey = "sponge.mods"; private const char Separator = ';'; private readonly ModLog _log; private readonly HashSet<string> _localMods = new HashSet<string>(StringComparer.OrdinalIgnoreCase); private readonly Dictionary<int, HashSet<string>> _remoteMods = new Dictionary<int, HashSet<string>>(); private bool _registered; public IReadOnlyCollection<string> LocalMods => _localMods; public event Action<Player> PeerModsChanged; public ModHandshake(ModLog log) { _log = log; } public void Start() { CollectLocalMods(); if (!_registered) { PhotonNetwork.AddCallbackTarget((object)this); _registered = true; } Publish(); } public void Stop() { if (_registered) { PhotonNetwork.RemoveCallbackTarget((object)this); _registered = false; } _remoteMods.Clear(); } private void CollectLocalMods() { _localMods.Clear(); try { foreach (KeyValuePair<string, PluginInfo> pluginInfo in Chainloader.PluginInfos) { PluginInfo value = pluginInfo.Value; object obj; if (value == null) { obj = null; } else { BepInPlugin metadata = value.Metadata; obj = ((metadata != null) ? metadata.GUID : null); } string text = (string)obj; if (!string.IsNullOrEmpty(text)) { _localMods.Add(text); } } } catch (Exception ex) { ModLog log = _log; if (log != null) { log.Exception("Could not enumerate loaded plugins", ex); } } ModLog log2 = _log; if (log2 != null) { log2.Debug((object)$"Advertising {_localMods.Count} loaded mod(s)."); } } public void Publish() { //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Expected O, but got Unknown //IL_0038: Expected O, but got Unknown if (!PhotonNetwork.InRoom || PhotonNetwork.LocalPlayer == null) { return; } try { string value = string.Join(';'.ToString(), _localMods); Hashtable val = new Hashtable(); ((Dictionary<object, object>)val).Add((object)"sponge.mods", (object)value); Hashtable val2 = val; PhotonNetwork.LocalPlayer.SetCustomProperties(val2, (Hashtable)null, (WebFlags)null); } catch (Exception ex) { ModLog log = _log; if (log != null) { log.Exception("Failed to publish the local mod list", ex); } } } public IReadOnlyCollection<string> GetMods(Player player) { if (player == null) { return (IReadOnlyCollection<string>)(object)Array.Empty<string>(); } if (player.IsLocal) { return _localMods; } if (_remoteMods.TryGetValue(player.ActorNumber, out var value)) { return value; } HashSet<string> hashSet = Parse(player); _remoteMods[player.ActorNumber] = hashSet; return hashSet; } public bool PlayerHasMod(Player player, string guid) { if (string.IsNullOrEmpty(guid)) { return false; } foreach (string mod in GetMods(player)) { if (string.Equals(mod, guid, StringComparison.OrdinalIgnoreCase)) { return true; } } return false; } public bool HostHasMod(string guid) { if (PhotonNetwork.OfflineMode || !PhotonNetwork.InRoom) { return true; } Player masterClient = PhotonNetwork.MasterClient; if (masterClient == null) { return false; } if (masterClient.IsLocal) { return _localMods.Contains(guid); } return PlayerHasMod(masterClient, guid); } public bool EveryoneHasMod(string guid) { if (!PhotonNetwork.InRoom) { return false; } Player[] playerList = PhotonNetwork.PlayerList; if (playerList == null || playerList.Length == 0) { return false; } Player[] array = playerList; foreach (Player player in array) { if (!PlayerHasMod(player, guid)) { return false; } } return true; } public IEnumerable<Player> PlayersWithMod(string guid) { if (PhotonNetwork.PlayerList == null) { yield break; } Player[] playerList = PhotonNetwork.PlayerList; foreach (Player val in playerList) { if (PlayerHasMod(val, guid)) { yield return val; } } } private HashSet<string> Parse(Player player) { HashSet<string> hashSet = new HashSet<string>(StringComparer.OrdinalIgnoreCase); try { if (player.CustomProperties != null && ((Dictionary<object, object>)(object)player.CustomProperties).TryGetValue((object)"sponge.mods", out object value) && value is string { Length: >0 } text) { string[] array = text.Split(';'); foreach (string text2 in array) { if (!string.IsNullOrEmpty(text2)) { hashSet.Add(text2); } } } } catch (Exception ex) { ModLog log = _log; if (log != null) { log.Exception("Could not parse the mod list for '" + player.NickName + "'", ex); } } return hashSet; } public void OnPlayerPropertiesUpdate(Player targetPlayer, Hashtable changedProps) { if (targetPlayer == null || changedProps == null || !((Dictionary<object, object>)(object)changedProps).ContainsKey((object)"sponge.mods")) { return; } _remoteMods[targetPlayer.ActorNumber] = Parse(targetPlayer); ModLog log = _log; if (log != null) { log.Debug((object)$"'{targetPlayer.NickName}' advertises {_remoteMods[targetPlayer.ActorNumber].Count} mod(s)."); } try { this.PeerModsChanged?.Invoke(targetPlayer); } catch (Exception ex) { ModLog log2 = _log; if (log2 != null) { log2.Exception("A PeerModsChanged subscriber threw", ex); } } } public void OnPlayerLeftRoom(Player otherPlayer) { if (otherPlayer != null) { _remoteMods.Remove(otherPlayer.ActorNumber); } } public void OnJoinedRoom() { Publish(); } public void OnPlayerEnteredRoom(Player newPlayer) { } public void OnRoomPropertiesUpdate(Hashtable propertiesThatChanged) { } public void OnMasterClientSwitched(Player newMasterClient) { } public void OnFriendListUpdate(List<FriendInfo> friendList) { } public void OnCreatedRoom() { } public void OnCreateRoomFailed(short returnCode, string message) { } public void OnJoinRoomFailed(short returnCode, string message) { } public void OnJoinRandomFailed(short returnCode, string message) { } public void OnLeftRoom() { _remoteMods.Clear(); } } public static class NetInfo { public static bool IsConnected => PhotonNetwork.IsConnected; public static bool InRoom => PhotonNetwork.InRoom; public static bool IsOffline => PhotonNetwork.OfflineMode; public static bool IsHost { get { if (!PhotonNetwork.OfflineMode && PhotonNetwork.InRoom) { return PhotonNetwork.IsMasterClient; } return true; } } public static Player LocalPlayer => PhotonNetwork.LocalPlayer; public static Room CurrentRoom => PhotonNetwork.CurrentRoom; public static int PlayerCount { get { Room currentRoom = PhotonNetwork.CurrentRoom; if (currentRoom == null) { return 0; } return currentRoom.PlayerCount; } } public static int MaxPlayers { get { Room currentRoom = PhotonNetwork.CurrentRoom; if (currentRoom == null) { return 0; } return currentRoom.MaxPlayers; } } public static bool IsMultiplayer { get { if (InRoom) { return PlayerCount > 1; } return false; } } } public enum NetRole { Offline, Client, Host, Solo } public static class NetRoleInfo { public static NetRole Current { get { if (PhotonNetwork.OfflineMode) { return NetRole.Solo; } if (!PhotonNetwork.InRoom) { return NetRole.Offline; } if (PhotonNetwork.CurrentRoom != null && PhotonNetwork.CurrentRoom.PlayerCount <= 1) { return NetRole.Solo; } if (!PhotonNetwork.IsMasterClient) { return NetRole.Client; } return NetRole.Host; } } public static bool HasAuthority => Current != NetRole.Client; public static bool CanActLocally => true; public static bool IsMultiplayer { get { NetRole current = Current; if (current != NetRole.Host) { return current == NetRole.Client; } return true; } } public static bool IsHost => Current == NetRole.Host; public static bool IsClient => Current == NetRole.Client; } public static class PlayerUtil { public const string AirportScene = "Airport"; public static bool InAirport { get { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0005: Unknown result type (might be due to invalid IL or missing references) Scene activeScene = SceneManager.GetActiveScene(); return ((Scene)(ref activeScene)).name == "Airport"; } } public static string GetStableKey(Player player) { if (player == null) { return string.Empty; } if (!string.IsNullOrEmpty(player.UserId)) { return "USERID:" + player.UserId; } if (!string.IsNullOrEmpty(player.NickName)) { return "NICK:" + player.NickName; } return "ACTOR:" + player.ActorNumber; } public static Character FindFurthestFromSummit(Character exclude = null) { //IL_004e: Unknown result type (might be due to invalid IL or missing references) Character result = null; float num = float.MaxValue; List<Character> allCharacters = GameState.AllCharacters; for (int i = 0; i < allCharacters.Count; i++) { Character val = allCharacters[i]; if (!((Object)(object)val == (Object)null) && !((Object)(object)val.data == (Object)null) && !((Object)(object)val == (Object)(object)exclude) && !val.data.dead) { float y = val.Center.y; if (y < num) { num = y; result = val; } } } return result; } public static IEnumerator WaitForCharacter(Player player, Action<Character> onReady, float timeout = 30f, float pollInterval = 0.1f) { float elapsed = 0f; Character character = null; for (; elapsed < timeout; elapsed += pollInterval) { character = GetCharacter(player); if ((Object)(object)character != (Object)null) { break; } yield return (object)new WaitForSeconds(pollInterval); } onReady?.Invoke(character); } public static Character GetCharacter(Player player) { if (player == null) { return null; } try { return PlayerHandler.GetPlayerCharacter(player); } catch { return null; } } public static bool Warp(Character character, Vector3 position) { //IL_002e: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)character == (Object)null || (Object)(object)((MonoBehaviourPun)character).photonView == (Object)null) { return false; } try { ((MonoBehaviourPun)character).photonView.RPC("WarpPlayerRPC", (RpcTarget)0, new object[2] { position, false }); return true; } catch { return false; } } public static bool ReviveAt(Character character, Vector3 position) { //IL_002e: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)character == (Object)null || (Object)(object)((MonoBehaviourPun)character).photonView == (Object)null) { return false; } try { ((MonoBehaviourPun)character).photonView.RPC("RPCA_ReviveAtPosition", (RpcTarget)0, new object[3] { position, false, -1 }); return true; } catch { return false; } } } } namespace SpongePEAK.Lib.Mods { public static class ModLocalization { private const string KeyPrefix = "SPONGE_MOD_"; private const int LanguageColumns = 16; private static readonly Dictionary<string, string> Registered = new Dictionary<string, string>(StringComparer.Ordinal); public static string Register(string id, string text, ModLog log) { string text2 = Sanitize("SPONGE_MOD_" + id); try { if (Registered.TryGetValue(text2, out var value) && value == text) { return text2; } Dictionary<string, List<string>> mainTable = LocalizedText.mainTable; if (mainTable == null) { return text2; } List<string> list = new List<string>(16); for (int i = 0; i < 16; i++) { list.Add(text); } mainTable[text2] = list; Registered[text2] = text; } catch (Exception ex) { if (log != null) { log.Exception("Could not register localisation for '" + text2 + "'", ex); } } return text2; } private static string Sanitize(string raw) { StringBuilder stringBuilder = new StringBuilder(raw.Length); foreach (char c in raw) { if (char.IsLetterOrDigit(c)) { stringBuilder.Append(char.ToUpperInvariant(c)); } else { stringBuilder.Append('_'); } } return stringBuilder.ToString(); } } public sealed class ModSwitch { private readonly ConfigEntryBase _entry; public ModEntry Owner { get; } public string Section => _entry.Definition.Section; public string Key => _entry.Definition.Key; public string Description { get { ConfigDescription description = _entry.Description; return ((description != null) ? description.Description : null) ?? string.Empty; } } public string Id => Owner.Guid + "/" + Section + "/" + Key; public bool IsProtected => Owner.IsProtected; public bool Value { get { try { object boxedValue = _entry.BoxedValue; bool flag = default(bool); int num; if (boxedValue is bool) { flag = (bool)boxedValue; num = 1; } else { num = 0; } return (byte)((uint)num & (flag ? 1u : 0u)) != 0; } catch { return false; } } } internal ModSwitch(ModEntry owner, ConfigEntryBase entry) { Owner = owner; _entry = entry; } public bool TrySet(bool value, ModLog log) { if (IsProtected) { if (log != null) { log.Warning((object)("Refused to change protected setting '" + Id + "'.")); } return false; } try { _entry.BoxedValue = value; return true; } catch (Exception ex) { if (log != null) { log.Exception("Failed to set '" + Id + "'", ex); } return false; } } } public sealed class ModEntry { private readonly List<ModSwitch> _switches = new List<ModSwitch>(); public string Guid { get; } public string Name { get; } public string Version { get; } public bool IsProtected { get; } public string ProtectedReason { get; } public IReadOnlyList<ModSwitch> Switches => _switches; public bool HasSwitches => _switches.Count > 0; internal ModEntry(PluginInfo info, bool isProtected, string protectedReason) { object obj; if (info == null) { obj = null; } else { BepInPlugin metadata = info.Metadata; obj = ((metadata != null) ? metadata.GUID : null); } if (obj == null) { obj = "unknown"; } Guid = (string)obj; object obj2; if (info == null) { obj2 = null; } else { BepInPlugin metadata2 = info.Metadata; obj2 = ((metadata2 != null) ? metadata2.Name : null); } if (obj2 == null) { obj2 = Guid; } Name = (string)obj2; object obj3; if (info == null) { obj3 = null; } else { BepInPlugin metadata3 = info.Metadata; obj3 = ((metadata3 == null) ? null : metadata3.Version?.ToString()); } if (obj3 == null) { obj3 = "?"; } Version = (string)obj3; IsProtected = isProtected; ProtectedReason = protectedReason; } internal void Add(ModSwitch entry) { _switches.Add(entry); } } public static class ModRegistry { private static readonly (string Prefix, string Reason)[] BuiltInProtected = new(string, string)[2] { ("com.sponge.peakcore", "Core library. Everything else depends on it."), ("com.sponge.peaklib", "Provides this settings panel and the shared modding API.") }; private static readonly List<(string Prefix, string Reason)> ExtraProtected = new List<(string, string)>(); private static readonly string[] HiddenPrefixes = new string[4] { "bepinex.", "com.bepis.", "hamunii.", "monodetour." }; private static readonly string[] HiddenExact = new string[1] { "bepinex" }; public static void Protect(string guidPrefix, string reason) { if (string.IsNullOrEmpty(guidPrefix)) { return; } foreach (var item in ExtraProtected) { if (string.Equals(item.Prefix, guidPrefix, StringComparison.OrdinalIgnoreCase)) { return; } } ExtraProtected.Add((guidPrefix, reason ?? "Required by another installed mod.")); } public static IReadOnlyList<ModEntry> Discover(ModLog log) { List<ModEntry> list = new List<ModEntry>(); try { foreach (KeyValuePair<string, PluginInfo> pluginInfo in Chainloader.PluginInfos) { PluginInfo value = pluginInfo.Value; object obj; if (value == null) { obj = null; } else { BepInPlugin metadata = value.Metadata; obj = ((metadata != null) ? metadata.GUID : null); } string text = (string)obj; if (string.IsNullOrEmpty(text) || IsHidden(text)) { continue; } BaseUnityPlugin instance = value.Instance; ConfigFile val = ((instance != null) ? instance.Config : null); if (val == null) { continue; } (bool, string) tuple = Classify(text); bool item = tuple.Item1; string item2 = tuple.Item2; ModEntry modEntry = new ModEntry(value, item, item2); foreach (ConfigDefinition key in val.Keys) { ConfigEntryBase val2; try { val2 = val[key]; } catch { continue; } if (val2 != null && !(val2.SettingType != typeof(bool))) { modEntry.Add(new ModSwitch(modEntry, val2)); } } if (modEntry.HasSwitches) { list.Add(modEntry); } } } catch (Exception ex) { if (log != null) { log.Exception("Failed to enumerate installed mods", ex); } } return list.OrderByDescending((ModEntry m) => m.IsProtected).ThenBy<ModEntry, string>((ModEntry m) => m.Name, StringComparer.OrdinalIgnoreCase).ToList(); } private static (bool, string) Classify(string guid) { (string, string)[] builtInProtected = BuiltInProtected; for (int i = 0; i < builtInProtected.Length; i++) { var (value, item) = builtInProtected[i]; if (guid.StartsWith(value, StringComparison.OrdinalIgnoreCase)) { return (true, item); } } foreach (var (value2, item2) in ExtraProtected) { if (guid.StartsWith(value2, StringComparison.OrdinalIgnoreCase)) { return (true, item2); } } return (false, null); } private static bool IsHidden(string guid) { string[] hiddenExact = HiddenExact; foreach (string value in hiddenExact) { if (guid.Equals(value, StringComparison.OrdinalIgnoreCase)) { return true; } } hiddenExact = HiddenPrefixes; foreach (string value2 in hiddenExact) { if (guid.StartsWith(value2, StringComparison.OrdinalIgnoreCase)) { return true; } } return false; } } public static class ModRestartTracker { private static readonly HashSet<string> Changed = new HashSet<string>(StringComparer.Ordinal); public static bool AnyPending => Changed.Count > 0; public static int PendingCount => Changed.Count; public static void MarkChanged(string id) { if (!string.IsNullOrEmpty(id)) { Changed.Add(id); } } public static bool NeedsRestart(string id) { if (!string.IsNullOrEmpty(id)) { return Changed.Contains(id); } return false; } } public static class ModSettingsTab { private const string TabObjectName = "SpongeUI_ModsTab"; private static ModLog _log; private static bool _installed; private static readonly Dictionary<string, ModToggleSetting> Registered = new Dictionary<string, ModToggleSetting>(StringComparer.Ordinal); internal static SettingsTABSButton ModTab { get; private set; } public static void SetLogger(ModLog log) { _log = log; } public static void Install(Harmony harmony) { if (_installed || harmony == null) { return; } try { harmony.PatchAll(typeof(ModSettingsPatches)); _installed = true; ModLog log = _log; if (log != null) { log.Debug((object)"Mod settings tab hooks installed."); } } catch (Exception ex) { ModLog log2 = _log; if (log2 != null) { log2.Exception("Failed to install the mod settings tab", ex); } } } internal static void SyncSettings() { GameHandler instance = GameHandler.Instance; SettingsHandler val = ((instance != null) ? instance.SettingsHandler : null); if (val == null) { return; } foreach (ModEntry item in ModRegistry.Discover(_log)) { foreach (ModSwitch @switch in item.Switches) { string text = BuildLabel(item, @switch); string displayName = ModLocalization.Register(@switch.Id, text, _log); if (Registered.TryGetValue(@switch.Id, out var value)) { ((Setting)value).Load((ISettingsSaveLoad)null); continue; } ModToggleSetting modToggleSetting = new ModToggleSetting(@switch, displayName, _log); Registered[@switch.Id] = modToggleSetting; try { val.AddSetting((Setting)(object)modToggleSetting); } catch (Exception ex) { ModLog log = _log; if (log != null) { log.Exception("Could not register '" + @switch.Id + "' as a setting", ex); } Registered.Remove(@switch.Id); } } } } private static string BuildLabel(ModEntry mod, ModSwitch entry) { string text = entry.Key; if (!string.IsNullOrEmpty(entry.Section) && !entry.Section.Equals(mod.Name, StringComparison.OrdinalIgnoreCase) && !entry.Section.Equals(entry.Key, StringComparison.OrdinalIgnoreCase)) { text = entry.Section + " / " + entry.Key; } string text2 = mod.Name + " · " + text; if (mod.IsProtected) { text2 += (string.IsNullOrEmpty(mod.ProtectedReason) ? " [required]" : (" [required — " + mod.ProtectedReason + "]")); } else if (ModRestartTracker.NeedsRestart(entry.Id)) { text2 += " [restart to apply]"; } return text2; } internal static void EnsureTab(SettingsTABS tabs) { //IL_0021: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)tabs == (Object)null) { return; } try { foreach (Transform item in ((Component)tabs).transform) { if (((Object)item).name == "SpongeUI_ModsTab") { return; } } SettingsTABSButton val = ((Component)tabs).GetComponentsInChildren<SettingsTABSButton>(true).FirstOrDefault(); if ((Object)(object)val == (Object)null) { ModLog log = _log; if (log != null) { log.Warning((object)"No settings tab to clone; the Mods tab was not added."); } return; } GameObject val2 = Object.Instantiate<GameObject>(((Component)val).gameObject, ((Component)val).transform.parent); ((Object)val2).name = "SpongeUI_ModsTab"; val2.transform.SetAsLastSibling(); LocalizedText[] componentsInChildren = val2.GetComponentsInChildren<LocalizedText>(true); for (int i = 0; i < componentsInChildren.Length; i++) { Object.DestroyImmediate((Object)(object)componentsInChildren[i]); } SettingsTABSButton component = val2.GetComponent<SettingsTABSButton>(); if ((Object)(object)component == (Object)null) { Object.Destroy((Object)(object)val2); return; } if ((Object)(object)((TAB_Button)component).text != (Object)null) { ((TMP_Text)((TAB_Button)component).text).text = "MODS"; } Button component2 = val2.GetComponent<Button>(); if ((Object)(object)component2 != (Object)null) { ((UnityEventBase)component2.onClick).RemoveAllListeners(); } ModTab = component; if (!((TABS<SettingsTABSButton>)(object)tabs).buttons.Contains(component)) { ((TABS<SettingsTABSButton>)(object)tabs).AddButton(component); } ModLog log2 = _log; if (log2 != null) { log2.Debug((object)"Mods tab added to the settings screen."); } } catch (Exception ex) { ModLog log3 = _log; if (log3 != null) { log3.Exception("Failed to add the Mods tab", ex); } } } internal static bool IsOurTab(SettingsTABSButton button) { if ((Object)(object)button != (Object)null && (Object)(object)ModTab != (Object)null) { return button == ModTab; } return false; } internal static void ShowModSettings(SharedSettingsMenu menu) { if ((Object)(object)menu == (Object)null) { return; } try { SyncSettings(); Traverse val = Traverse.Create((object)menu); List<SettingsUICell> value = val.Field("m_spawnedCells").GetValue<List<SettingsUICell>>(); GameObject settingsCellPrefab = menu.m_settingsCellPrefab; Transform settingsContentParent = menu.m_settingsContentParent; if (value == null || (Object)(object)settingsCellPrefab == (Object)null || (Object)(object)settingsContentParent == (Object)null) { ModLog log = _log; if (log != null) { log.Warning((object)"Settings menu internals not available; cannot show mod settings."); } return; } Traverse val2 = val.Field("m_fadeInCoroutine"); Coroutine value2 = val2.GetValue<Coroutine>(); if (value2 != null) { ((MonoBehaviour)menu).StopCoroutine(value2); val2.SetValue((object)null); } foreach (SettingsUICell item in value) { if ((Object)(object)item != (Object)null) { Object.DestroyImmediate((Object)(object)((Component)item).gameObject); } } value.Clear(); GameHandler instance = GameHandler.Instance; SettingsHandler val3 = ((instance != null) ? instance.SettingsHandler : null); if (val3 == null) { return; } List<ModToggleSetting> list = (from s in ISettingsHandlerExtensions.GetSettingsThatImplements<IExposedSetting>((ISettingHandler)(object)val3) where s.GetCategory() == "Mods" select s).OfType<ModToggleSetting>().ToList(); foreach (ModToggleSetting item2 in list) { SettingsUICell component = Object.Instantiate<GameObject>(settingsCellPrefab, settingsContentParent).GetComponent<SettingsUICell>(); if (!((Object)(object)component == (Object)null)) { if (item2.Switch != null && item2.Switch.IsProtected) { component.ShouldntShow(); } value.Add(component); component.Setup<ModToggleSetting>(item2); } } foreach (SettingsUICell item3 in value) { if ((Object)(object)item3 != (Object)null) { item3.FadeIn(); } } EnsureScrollable(settingsContentParent); ModLog log2 = _log; if (log2 != null) { log2.Debug((object)$"Showed {list.Count} mod setting(s)."); } } catch (Exception ex) { ModLog log3 = _log; if (log3 != null) { log3.Exception("Failed to show mod settings", ex); } } } private static void EnsureScrollable(Transform content) { ScrollableList.Refresh(ScrollableList.Ensure(content, _log)); } } internal static class ModSettingsPatches { [HarmonyPatch(typeof(SharedSettingsMenu), "OnEnable")] [HarmonyPrefix] private static void MenuOpening(SharedSettingsMenu __instance) { try { ModSettingsTab.EnsureTab(Traverse.Create((object)__instance).Field("m_tabs").GetValue<SettingsTABS>()); } catch (Exception) { } } [HarmonyPatch(typeof(SettingsTABS), "OnSelected")] [HarmonyPrefix] private static bool TabSelected(SettingsTABS __instance, SettingsTABSButton button) { if (!ModSettingsTab.IsOurTab(button)) { return true; } try { ModSettingsTab.ShowModSettings(__instance.SettingsMenu); } catch (Exception) { } return false; } } public sealed class ModToggleSetting : BoolSetting, IExposedSetting { public const string CategoryName = "Mods"; private readonly ModSwitch _switch; private readonly ModLog _log; private readonly string _displayName; public ModSwitch Switch => _switch; public override LocalizedString OffString => null; public override LocalizedString OnString => null; public ModToggleSetting(ModSwitch modSwitch, string displayName, ModLog log) { _switch = modSwitch; _displayName = displayName; _log = log; ((BoolSetting)this).Value = modSwitch.Value; } public override void ApplyValue() { if (_switch == null) { return; } if (_switch.IsProtected) { ((BoolSetting)this).Value = _switch.Value; } else { if (_switch.Value == ((BoolSetting)this).Value) { return; } if (!_switch.TrySet(((BoolSetting)this).Value, _log)) { ((BoolSetting)this).Value = _switch.Value; return; } ModRestartTracker.MarkChanged(_switch.Id); ModLog log = _log; if (log != null) { log.Info((object)("Mod setting '" + _switch.Id + "' set to " + (((BoolSetting)this).Value ? "on" : "off") + ". Saved; restart the game for it to take effect.")); } } } public override void Load(ISettingsSaveLoad loader) { ((BoolSetting)this).Value = _switch?.Value ?? false; } public override void Save(ISettingsSaveLoad saver) { } protected override bool GetDefaultValue() { return _switch?.Value ?? false; } public string GetDisplayName() { return _displayName; } public string GetCategory() { return "Mods"; } } } namespace SpongePEAK.Lib.Items { public sealed class CookAwareEffects : MonoBehaviour { internal Dictionary<int, List<StatusEffect>> EffectsByCookCount; private Item _item; private void Awake() { _item = ((Component)this).GetComponent<Item>(); } public void ApplyTo(Character character) { //IL_007a: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)character == (Object)null || character.refs == null || EffectsByCookCount == null) { return; } CharacterAfflictions afflictions = character.refs.afflictions; if ((Object)(object)afflictions == (Object)null) { return; } List<StatusEffect> list = ResolveEffects(GetCookCount()); if (list == null) { return; } foreach (StatusEffect item in list) { if (item.Amount >= 0f) { afflictions.AddStatus(item.Status, item.Amount, false, true, true, false); } else { afflictions.SubtractStatus(item.Status, Mathf.Abs(item.Amount), false, false); } } } public int GetCookCount() { if ((Object)(object)_item == (Object)null) { return 0; } try { if (!_item.HasData((DataEntryKey)1)) { return 0; } return _item.GetData<IntItemData>((DataEntryKey)1)?.Value ?? 0; } catch { return 0; } } internal List<StatusEffect> ResolveEffects(int cookCount) { if (EffectsByCookCount == null || EffectsByCookCount.Count == 0) { return null; } if (EffectsByCookCount.TryGetValue(cookCount, out var value)) { return value; } List<StatusEffect> result = null; int num = -1; foreach (KeyValuePair<int, List<StatusEffect>> item in EffectsByCookCount) { if (item.Key <= cookCount && item.Key > num) { num = item.Key; result = item.Value; } } return result; } } public sealed class DynamiteFuse : MonoBehaviour { [SerializeField] private float _fuseSeconds = 30f; [SerializeField] private bool _manualLight = true; private Item _item; private Dynamite _dynamite; private Action _onUsed; public bool IsLit { get { BoolItemData val = default(BoolItemData); if ((Object)(object)_item != (Object)null && _item.data != null && _item.data.TryGetDataEntry<BoolItemData>((DataEntryKey)3, ref val)) { return val.Value; } return false; } } private void Awake() { _item = ((Component)this).GetComponent<Item>(); _dynamite = ((Component)this).GetComponent<Dynamite>(); if (_manualLight && (Object)(object)_item != (Object)null) { _onUsed = Light; _item.OnPrimaryFinishedCast = (Action)Delegate.Combine(_item.OnPrimaryFinishedCast, _onUsed); } } private void OnDestroy() { if ((Object)(object)_item != (Object)null && _onUsed != null) { _item.OnPrimaryFinishedCast = (Action)Delegate.Remove(_item.OnPrimaryFinishedCast, _onUsed); } } public void Light() { if (!((Object)(object)_dynamite == (Object)null) && !IsLit) { _dynamite.LightFlare(); } } internal static bool Apply(GameObject clone, float fuseSeconds, bool manualLight, ModLog log) { Dynamite component = clone.GetComponent<Dynamite>(); if ((Object)(object)component == (Object)null) { if (log != null) { log.Warning((object)"Cannot apply fuse settings: clone has no Dynamite component."); } return false; } component.startingFuseTime = fuseSeconds; if (manualLight) { component.lightFuseRadius = 0f; Item component2 = clone.GetComponent<Item>(); if (component2 != null && component2.UIData != null) { component2.UIData.hasMainInteract = true; ItemLocalization.RegisterRaw("SPONGE_INTERACT_LIGHTFUSE", "Light fuse", log); component2.UIData.mainInteractPrompt = "SPONGE_INTERACT_LIGHTFUSE"; } } DynamiteFuse dynamiteFuse = clone.AddComponent<DynamiteFuse>(); dynamiteFuse._fuseSeconds = fuseSeconds; dynamiteFuse._manualLight = manualLight; if (log != null) { log.Debug((object)string.Format("Fuse set to {0:F0}s ({1} light).", fuseSeconds, manualLight ? "manual" : "proximity")); } return true; } } public sealed class ExplodeOnConsume : MonoBehaviourPun { [SerializeField] private GameObject _explosionPrefab; private bool _exploded; private Item _item; private Action _onConsumed; internal void Configure(GameObject explosionPrefab) { _explosionPrefab = explosionPrefab; } private void Awake() { _item = ((Component)this).GetComponent<Item>(); if (!((Object)(object)_item == (Object)null)) { _onConsumed = OnConsumed; _item.OnConsumed = (Action)Delegate.Combine(_item.OnConsumed, _onConsumed); } } private void OnDestroy() { if ((Object)(object)_item != (Object)null && _onConsumed != null) { _item.OnConsumed = (Action)Delegate.Remove(_item.OnConsumed, _onConsumed); } } private void OnConsumed() { if (!_exploded && !((Object)(object)((MonoBehaviourPun)this).photonView == (Object)null) && ((MonoBehaviourPun)this).photonView.IsMine) { _exploded = true; ((MonoBehaviourPun)this).photonView.RPC("RPC_ConsumeExplode", (RpcTarget)0, Array.Empty<object>()); } } [PunRPC] private void RPC_ConsumeExplode() { //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)_explosionPrefab == (Object)null)) { Object.Instantiate<GameObject>(_explosionPrefab, ((Component)this).transform.position, ((Component)this).transform.rotation); } } internal static bool Attach(GameObject clone, string explosionSourceItem, ModLog log) { GameObject val = FindExplosionPrefab(explosionSourceItem, log); if ((Object)(object)val == (Object)null) { return false; } clone.AddComponent<ExplodeOnConsume>().Configure(val); if (log != null) { log.Debug((object)("Attached consume-explosion sourced from '" + explosionSourceItem + "'.")); } return true; } private static GameObject FindExplosionPrefab(string itemName, ModLog log) { Item val = ItemCloner.FindSourceItem(itemName); if ((Object)(object)val == (Object)null) { if (log != null) { log.Warning((object)("Cannot attach explosion: item '" + itemName + "' not found.")); } return null; } Dynamite componentInChildren = ((Component)val).GetComponentInChildren<Dynamite>(true); if ((Object)(object)componentInChildren == (Object)null || (Object)(object)componentInChildren.explosionPrefab == (Object)null) { if (log != null) { log.Warning((object)("Item '" + itemName + "' has no Dynamite component with an explosion prefab.")); } return null; } return componentInChildren.explosionPrefab; } } internal static class ItemAppearance { private static readonly int TintProperty = Shader.PropertyToID("_Tint"); private static readonly int ColorProperty = Shader.PropertyToID("_Color"); private static readonly int BaseColorProperty = Shader.PropertyToID("_BaseColor"); public static void Apply(GameObject clone, ItemCloneDefinition definition, ModLog log) { Renderer[] componentsInChildren = clone.GetComponentsInChildren<Renderer>(true); if (componentsInChildren == null || componentsInChildren.Length == 0) { return; } Renderer[] array = componentsInChildren; foreach (Renderer val in array) { if ((Object)(object)val == (Object)null) { continue; } Material[] materials = val.materials; foreach (Material val2 in materials) { if (!((Object)(object)val2 == (Object)null)) { if (definition.HueShift.HasValue) { ShiftHue(val2, definition); } if (definition.Variant != SpecialVariant.None) { ApplyVariant(val2, definition.Variant); } } } val.materials = materials; } if (log != null) { log.Debug((object)("Applied appearance to '" + definition.DisplayName + "'.")); } } private static void ShiftHue(Material material, ItemCloneDefinition definition) { //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0063: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Unknown result type (might be due to invalid IL or missing references) //IL_0079: Unknown result type (might be due to invalid IL or missing references) int num = ResolveColorProperty(material); if (num != 0) { Color color = material.GetColor(num); float num2 = default(float); float num3 = default(float); float num4 = default(float); Color.RGBToHSV(color, ref num2, ref num3, ref num4); num2 = Mathf.Repeat(num2 + definition.HueShift.Value / 360f, 1f); num3 = Mathf.Clamp01(num3 * definition.SaturationScale); num4 = Mathf.Clamp01(num4 * definition.BrightnessScale); Color val = Color.HSVToRGB(num2, num3, num4); val.a = color.a; material.SetColor(num, val); } } private static int ResolveColorProperty(Material material) { if (material.HasProperty(TintProperty)) { return TintProperty; } if (material.HasProperty(BaseColorProperty)) { return BaseColorProperty; } if (material.HasProperty(ColorProperty)) { return ColorProperty; } return 0; } private static void ApplyVariant(Material material, SpecialVariant variant) { //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0097: Unknown result type (might be due to invalid IL or missing references) //IL_00d4: Unknown result type (might be due to invalid IL or missing references) //IL_00de: Unknown result type (might be due to invalid IL or missing references) int num = ResolveColorProperty(material); switch (variant) { case SpecialVariant.Golden: if (num != 0) { material.SetColor(num, new Color(1f, 0.84f, 0.25f, material.GetColor(num).a)); } TrySetFloat(material, "_Metallic", 1f); TrySetFloat(material, "_Glossiness", 0.85f); TrySetFloat(material, "_Smoothness", 0.85f); break; case SpecialVariant.Spectral: if (num != 0) { Color val = default(Color); ((Color)(ref val))..ctor(0.6f, 0.85f, 1f, 0.45f); material.SetColor(num, val); } TrySetFloat(material, "_Metallic", 0f); TrySetFloat(material, "_Glossiness", 0.2f); break; case SpecialVariant.Antigrav: if (num != 0) { material.SetColor(num, new Color(0.7f, 0.4f, 1f, material.GetColor(num).a)); } TrySetFloat(material, "_Glossiness", 0.6f); break; } } private static void TrySetFloat(Material material, string property, float value) { if (material.HasProperty(property)) { material.SetFloat(property, value); } } } public sealed class ItemBehaviourSpec { internal List<Type> ComponentsToRemove { get; } = new List<Type>(); internal List<(Type Type, Action<Component> Configure)> ComponentsToAdd { get; } = new List<(Type, Action<Component>)>(); internal bool StripAllActions { get; private set; } internal bool StripAllComponents { get; private set; } internal Action<Item> ConfigureUI { get; private set; } public ItemBehaviourSpec ClearActions() { StripAllActions = true; return this; } public ItemBehaviourSpec ClearComponents() { StripAllComponents = true; return this; } public ItemBehaviourSpec Remove<T>() where T : Component { ComponentsToRemove.Add(typeof(T)); return this; } public ItemBehaviourSpec Add<T>(Action<T> configure = null) where T : Component { ComponentsToAdd.Add((typeof(T), (configure == null) ? null : ((Action<Component>)delegate(Component c) { configure((T)(object)c); }))); return this; } public ItemBehaviourSpec ConfigureUIData(Action<Item> configure) { ConfigureUI = configure; return this; } internal void Apply(GameObject clone, Item item, ModLog log) { if (StripAllActions) { ItemActionBase[] componentsInChildren = clone.GetComponentsInChildren<ItemActionBase>(true); for (int i = 0; i < componentsInChildren.Length; i++) { Object.DestroyImmediate((Object)(object)componentsInChildren[i]); } } if (StripAllComponents) { ItemComponent[] componentsInChildren2 = clone.GetComponentsInChildren<ItemComponent>(true); for (int i = 0; i < componentsInChildren2.Length; i++) { Object.DestroyImmediate((Object)(object)componentsInChildren2[i]); } } foreach (Type item2 in ComponentsToRemove) { Component[] componentsInChildren3 = clone.GetComponentsInChildren(item2, true); for (int i = 0; i < componentsInChildren3.Length; i++) { Object.DestroyImmediate((Object)(object)componentsInChildren3[i]); } } foreach (var (type, action) in ComponentsToAdd) { try { Component obj = clone.AddComponent(type); action?.Invoke(obj); } catch (Exception ex) { if (log != null) { log.Exception("Failed to add component '" + type.Name + "' to '" + ((Object)clone).name + "'", ex); } } } try { ConfigureUI?.Invoke(item); } catch (Exception ex2) { if (log != null) { log.Exception("Failed to configure UI data for '" + ((Object)clone).name + "'", ex2); } } } } public static class ItemCatalog { public static List<(string PrefabName, string DisplayName, ushort Id)> All() { List<(string, string, ushort)> list = new List<(string, string, ushort)>(); ItemDatabase instance = SingletonAsset<ItemDatabase>.Instance; if (instance?.itemLookup == null) { return list; } foreach (KeyValuePair<ushort, Item> item in instance.itemLookup) { Item value = item.Value; if (!((Object)(object)value == (Object)null)) { list.Add((((Object)value).name, value.UIData?.itemName ?? "<none>", item.Key)); } } return list; } public static void Dump(ModLog log, string filter = null) { if (log == null) { return; } List<(string, string, ushort)> list = All(); StringBuilder stringBuilder = new StringBuilder(); stringBuilder.AppendLine($"Item catalog ({list.Count} entries):"); foreach (var (text, text2, num) in list) { if (string.IsNullOrEmpty(filter) || text.IndexOf(filter, StringComparison.OrdinalIgnoreCase) >= 0 || text2.IndexOf(filter, StringComparison.OrdinalIgnoreCase) >= 0) { stringBuilder.AppendLine($" [{num}] prefab='{text}' name='{text2}'"); } } log.Info((object)stringBuilder.ToString()); } public static void DumpMaterials(ModLog log, string itemName) { //IL_019e: Unknown result type (might be due to invalid IL or missing references) if (log == null || string.IsNullOrEmpty(itemName)) { return; } ItemDatabase instance = SingletonAsset<ItemDatabase>.Instance; if (instance?.itemLookup == null) { log.Warning((object)"Item database is not loaded yet."); return; } foreach (KeyValuePair<ushort, Item> item in instance.itemLookup) { Item value = item.Value; if ((Object)(object)value == (Object)null || (!string.Equals(((Object)value).name, itemName, StringComparison.OrdinalIgnoreCase) && (value.UIData == null || !string.Equals(value.UIData.itemName, itemName, StringComparison.OrdinalIgnoreCase)))) { continue; } StringBuilder stringBuilder = new StringBuilder(); stringBuilder.AppendLine($"Materials for '{itemName}' (id {item.Key}):"); Renderer[] componentsInChildren = ((Component)value).GetComponentsInChildren<Renderer>(true); foreach (Renderer val in componentsInChildren) { if ((Object)(object)val == (Object)null) { continue; } Material[] sharedMaterials = val.sharedMaterials; foreach (Material val2 in sharedMaterials) { if ((Object)(object)val2 == (Object)null) { continue; } string[] obj = new string[7] { " renderer='", ((Object)val).name, "' material='", ((Object)val2).name, "' shader='", null, null }; Shader shader = val2.shader; obj[5] = ((shader != null) ? ((Object)shader).name : null); obj[6] = "'"; stringBuilder.AppendLine(string.Concat(obj)); string[] array = new string[3] { "_Tint", "_Color", "_BaseColor" }; foreach (string text in array) { if (val2.HasProperty(text)) { stringBuilder.AppendLine($" {text} = {val2.GetColor(text)}"); } } } } log.Info((object)stringBuilder.ToString()); return; } log.Warning((object)("No item named '" + itemName + "' found.")); } public static void DumpBehaviour(ModLog log, string itemName) { //IL_015f: Unknown result type (might be due to invalid IL or missing references) //IL_016b: Unknown result type (might be due to invalid IL or missing references) if (log == null || string.IsNullOrEmpty(itemName)) { return; } ItemDatabase instance = SingletonAsset<ItemDatabase>.Instance; if (instance?.itemLookup == null) { return; } foreach (KeyValuePair<ushort, Item> item in instance.itemLookup) { Item value = item.Value; if (!((Object)(object)value == (Object)null) && (string.Equals(((Object)value).name, itemName, StringComparison.OrdinalIgnoreCase) || (value.UIData != null && string.Equals(value.UIData.itemName, itemName, StringComparison.OrdinalIgnoreCase)))) { StringBuilder stringBuilder = new StringBuilder(); stringBuilder.AppendLine($"Behaviour for '{itemName}' (id {item.Key}):"); stringBuilder.AppendLine(" Actions:"); ItemActionBase[] componentsInChildren = ((Component)value).GetComponentsInChildren<ItemActionBase>(true); foreach (ItemActionBase val in componentsInChildren) { stringBuilder.AppendLine(" " + ((object)val).GetType().Name); } stringBuilder.AppendLine(" Components:"); ItemComponent[] componentsInChildren2 = ((Component)value).GetComponentsInChildren<ItemComponent>(true); foreach (ItemComponent val2 in componentsInChildren2) { stringBuilder.AppendLine(" " + ((object)val2).GetType().Name); } LootData component = ((Component)value).GetComponent<LootData>(); if ((Object)(object)component != (Object)null) { stringBuilder.AppendLine($" Spawns: {component.spawnLocations} at {component.Rarity}"); } log.Info((object)stringBuilder.ToString()); break; } } } } public sealed class ItemCloneDefinition { public const float MaxScale = 5f; public string SourceItemName { get; } public List<string> AlternateSourceNames { get; } = new List<string>(); public string InternalName { get; } public string DisplayName { get; private set; } public string Description { get; private set; } public float? HueShift { get; private set; } public float SaturationScale { get; private set; } = 1f; public float BrightnessScale { get; private set; } = 1f; public float Scale { get; private set; } = 1f; public SpecialVariant Variant { get; private set; } public Dictionary<int, List<StatusEffect>> EffectsByCookCount { get; } = new Dictionary<int, List<StatusEffect>>(); public ExplosionOverride Explosion { get; private set; } public FuseOverride Fuse { get; private set; } public string ExplodeOnConsumeSource { get; private set; } public SpawnRule Spawning { get; private set; } public ItemBehaviourSpec Behaviour { get; private set; } public Action<GameObject> PostBuild { get; private set; } public ItemCloneDefinition(string sourceItemName, string internalName, string displayName = null) { if (string.IsNullOrWhiteSpace(sourceItemName)) { throw new ArgumentException("Source item name is required.", "sourceItemName"); } if (string.IsNullOrWhiteSpace(internalName)) { throw new ArgumentException("Internal name is required