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 FreeUpgradeEveryRound v1.0.4
FreeUpgradeEveryRound.dll
Decompiled 2 months agousing System; using System.Collections.Generic; using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using MenuLib; using MenuLib.MonoBehaviors; using Microsoft.CodeAnalysis; using Photon.Pun; using Photon.Realtime; using REPOUpgradeAPI; using TMPro; using UnityEngine; using UnityEngine.SceneManagement; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: IgnoresAccessChecksTo("")] [assembly: AssemblyCompany("Kai")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("FreeUpgradeEveryRound")] [assembly: AssemblyTitle("FreeUpgradeEveryRound")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.0.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace FreeUpgradeEveryRound { internal static class DraftGenerator { internal static readonly string[] UpgradeKeys = new string[12] { "Stamina", "Health", "Wings", "Launch", "Climb", "Rest", "Speed", "Jump", "Strength", "Range", "Battery", "Map" }; internal static string[] GenerateDraft() { List<string> list = new List<string>(); string[] upgradeKeys = UpgradeKeys; foreach (string text in upgradeKeys) { int weight = UpgradeConfig.GetWeight(text); if (weight > 0) { for (int j = 0; j < weight; j++) { list.Add(text); } } } HashSet<string> hashSet = new HashSet<string>(); while (hashSet.Count < UpgradeConfig.DraftCount.Value && list.Count > 0) { int index = Random.Range(0, list.Count); string chosen = list[index]; hashSet.Add(chosen); list.RemoveAll((string x) => x == chosen); } return new List<string>(hashSet).ToArray(); } } internal static class DraftKeyMap { private static readonly Dictionary<string, string> map = new Dictionary<string, string> { { "Stamina", "energy" }, { "Health", "health" }, { "Wings", "wings" }, { "Launch", "launch" }, { "Climb", "climb" }, { "Rest", "crouch" }, { "Speed", "sprint" }, { "Jump", "jump" }, { "Strength", "grabstr" }, { "Range", "grabrange" }, { "Battery", "battery" }, { "Map", "mapcount" } }; public static string ToAPIKey(string draftKey) { if (draftKey == null) { return string.Empty; } if (map.TryGetValue(draftKey, out string value)) { return value; } FreeUpgradeEveryRound.Logger.LogWarning((object)("[FreeUpgrade] Unknown draft key: " + draftKey)); return draftKey.ToLowerInvariant(); } } [BepInPlugin("Kai.FreeUpgradeEveryRound", "FreeUpgradeEveryRound", "0.1.2")] public class FreeUpgradeEveryRound : BaseUnityPlugin { internal static Dictionary<string, int> FreeSlotsDict = new Dictionary<string, int>(); internal static Dictionary<string, int> LastFreeLevelDict = new Dictionary<string, int>(); internal static readonly Dictionary<string, string[]> RuntimeDrafts = new Dictionary<string, string[]>(); internal static bool HasSyncedFromSave = false; internal static FreeUpgradeEveryRound Instance { get; private set; } = null; internal static ManualLogSource Logger => Instance._logger; private ManualLogSource _logger => ((BaseUnityPlugin)this).Logger; internal Harmony? Harmony { get; set; } private void Awake() { Instance = this; ((Component)this).gameObject.transform.parent = null; ((Object)((Component)this).gameObject).hideFlags = (HideFlags)61; UpgradeConfig.Load(((BaseUnityPlugin)this).Config); UpgradeConfig.Init(((BaseUnityPlugin)this).Config); Patch(); Logger.LogInfo((object)$"{((BaseUnityPlugin)this).Info.Metadata.GUID} v{((BaseUnityPlugin)this).Info.Metadata.Version} has loaded!"); } internal void Patch() { //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Expected O, but got Unknown //IL_0025: Expected O, but got Unknown if (Harmony == null) { Harmony val = new Harmony(((BaseUnityPlugin)this).Info.Metadata.GUID); Harmony val2 = val; Harmony = val; } Harmony.PatchAll(); } internal void Unpatch() { Harmony? harmony = Harmony; if (harmony != null) { harmony.UnpatchSelf(); } } internal static void SyncFreeSlotForPlayer(string steamID, int currentLevel) { if (!FreeSlotsDict.ContainsKey(steamID)) { FreeSlotsDict[steamID] = 0; } if (!LastFreeLevelDict.ContainsKey(steamID)) { LastFreeLevelDict[steamID] = 0; } int num = LastFreeLevelDict[steamID]; int num2 = currentLevel - num; if (num2 > 0) { FreeSlotsDict[steamID] += num2; LastFreeLevelDict[steamID] = currentLevel; Logger.LogInfo((object)$"[FreeUpgrade] steamID={steamID} level jump {num} → {currentLevel}, +{num2} free slots (now={FreeSlotsDict[steamID]})"); } } internal static void SyncFromStatsManager() { StatsManager instance = StatsManager.instance; if ((Object)(object)instance == (Object)null) { Logger.LogWarning((object)"[FreeUpgrade] StatsManager が見つかりませんでした。同期をスキップ"); return; } Dictionary<string, Dictionary<string, int>> dictionaryOfDictionaries = instance.dictionaryOfDictionaries; if (dictionaryOfDictionaries.TryGetValue("FreeUpgrade_freeSlots", out var value)) { FreeSlotsDict = value; } if (dictionaryOfDictionaries.TryGetValue("FreeUpgrade_lastFreeLevel", out var value2)) { LastFreeLevelDict = value2; } Logger.LogInfo((object)"[FreeUpgrade] StatsManager → FreeUpgradeEveryRound 辞書へ同期完了"); HasSyncedFromSave = true; foreach (string key in FreeSlotsDict.Keys) { int levelsCompleted = RunManager.instance.levelsCompleted; SyncFreeSlotForPlayer(key, levelsCompleted); } } internal static void SyncToStatsManager() { StatsManager instance = StatsManager.instance; if ((Object)(object)instance == (Object)null) { Logger.LogWarning((object)"[FreeUpgrade] StatsManager が見つかりませんでした。同期をスキップ"); return; } Dictionary<string, Dictionary<string, int>> dictionaryOfDictionaries = instance.dictionaryOfDictionaries; dictionaryOfDictionaries["FreeUpgrade_freeSlots"] = FreeSlotsDict; dictionaryOfDictionaries["FreeUpgrade_lastFreeLevel"] = LastFreeLevelDict; Logger.LogInfo((object)"[FreeUpgrade] FreeSlots と LastFreeLevel を StatsManager と同期しました"); } } public class FreeUpgradeNet : MonoBehaviourPun { public static FreeUpgradeNet Instance { get; private set; } private void Awake() { Instance = this; } [PunRPC] public void FUE_ReceiveDraft(string steamID, string[] draft) { FreeUpgradeEveryRound.RuntimeDrafts[steamID] = draft; string playerSteamID = PlayerController.instance.playerSteamID; if (playerSteamID != steamID) { return; } if (FreeUpgradeEveryRound.FreeSlotsDict.TryGetValue(steamID, out var value) && value <= 0) { if ((Object)(object)MenuManager.instance != (Object)null) { MenuManager.instance.PageCloseAll(); } } else { MenuManager.instance.PageCloseAll(); FreeUpgrade_InputPatch.OpenUI(steamID); } } [PunRPC] public void FUE_UpdateFreeSlots(string steamID, int newFreeSlots) { FreeUpgradeEveryRound.FreeSlotsDict[steamID] = newFreeSlots; FreeUpgradeEveryRound.Logger.LogInfo((object)$"[FreeUpgrade] Free slots updated for {steamID}: {newFreeSlots}"); if ((Object)(object)PlayerController.instance != (Object)null && PlayerController.instance.playerSteamID == steamID) { if ((Object)(object)MenuManager.instance != (Object)null) { MenuManager.instance.PageCloseAll(); } FreeUpgrade_InputPatch.OpenUI(steamID); } } [PunRPC] public void FUE_SelectUpgrade(string steamID, string typeKey, PhotonMessageInfo info) { if (!PhotonNetwork.IsMasterClient) { return; } if (!FreeUpgradeEveryRound.FreeSlotsDict.TryGetValue(steamID, out var value) || value <= 0) { FreeUpgradeEveryRound.Logger.LogWarning((object)("[FreeUpgrade] Player " + steamID + " has no free slots.")); return; } FreeUpgradeEveryRound.FreeSlotsDict[steamID] = value - 1; ((MonoBehaviourPun)Instance).photonView.RPC("FUE_UpdateFreeSlots", (RpcTarget)0, new object[2] { steamID, FreeUpgradeEveryRound.FreeSlotsDict[steamID] }); string text = DraftKeyMap.ToAPIKey(typeKey); UpgradeAPI.Add(text, 1, steamID); FreeUpgradeEveryRound.Logger.LogInfo((object)$"[FreeUpgrade] {steamID} selected {typeKey} → internal:{text}. Free slots now: {FreeUpgradeEveryRound.FreeSlotsDict[steamID]}"); if (FreeUpgradeEveryRound.FreeSlotsDict[steamID] > 0) { string[] array = DraftGenerator.GenerateDraft(); FreeUpgradeEveryRound.RuntimeDrafts[steamID] = array; if ((Object)(object)Instance == (Object)null || (Object)(object)((MonoBehaviourPun)Instance).photonView == (Object)null) { Debug.LogError((object)"[FreeUpgrade] FreeUpgradeNet.Instance or photonView is null!"); return; } ((MonoBehaviourPun)Instance).photonView.RPC("FUE_ReceiveDraft", (RpcTarget)0, new object[2] { steamID, array }); } else if (FreeUpgradeEveryRound.RuntimeDrafts.ContainsKey(steamID)) { FreeUpgradeEveryRound.RuntimeDrafts.Remove(steamID); } } public static void SendDraftToAll(string steamID, string[] draft) { if (!PhotonNetwork.IsConnected || !PhotonNetwork.InRoom) { FreeUpgradeEveryRound.RuntimeDrafts[steamID] = draft; FreeUpgrade_InputPatch.OpenUI(steamID); } else { ((MonoBehaviourPun)Instance).photonView.RPC("FUE_ReceiveDraft", (RpcTarget)0, new object[2] { steamID, draft }); } } public static void SendSelectToHost(string steamID, string typeKey) { if (!PhotonNetwork.IsConnected || !PhotonNetwork.InRoom) { FreeUpgradeEveryRound.Logger.LogInfo((object)"[FreeUpgrade] SP mode: direct apply"); if (!FreeUpgradeEveryRound.FreeSlotsDict.TryGetValue(steamID, out var value) || value <= 0) { FreeUpgradeEveryRound.Logger.LogWarning((object)("[FreeUpgrade] Player " + steamID + " has no free slots.")); return; } FreeUpgradeEveryRound.FreeSlotsDict[steamID] = value - 1; string text = DraftKeyMap.ToAPIKey(typeKey); UpgradeAPI.Add(text, 1, steamID); if (FreeUpgradeEveryRound.FreeSlotsDict[steamID] > 0) { string[] value2 = DraftGenerator.GenerateDraft(); FreeUpgradeEveryRound.RuntimeDrafts[steamID] = value2; FreeUpgrade_InputPatch.OpenUI(steamID); return; } FreeUpgradeEveryRound.RuntimeDrafts.Remove(steamID); if ((Object)(object)MenuManager.instance != (Object)null) { MenuManager.instance.PageCloseAll(); } } else { ((MonoBehaviourPun)Instance).photonView.RPC("FUE_SelectUpgrade", (RpcTarget)2, new object[2] { steamID, typeKey }); } } } [HarmonyPatch(typeof(PunManager))] public static class FreeUpgradeNetPatcher { [HarmonyPostfix] [HarmonyPatch("Awake")] private static void AttachNet(PunManager __instance) { GameObject gameObject = ((Component)__instance).gameObject; if (!Object.op_Implicit((Object)(object)gameObject.GetComponent<FreeUpgradeNet>())) { gameObject.AddComponent<FreeUpgradeNet>(); } } } [HarmonyPatch(typeof(PlayerController))] internal static class FreeUpgrade_InputPatch { [HarmonyPostfix] [HarmonyPatch("Update")] private static void Postfix(PlayerController __instance) { //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0027: 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) if (!((Object)(object)PlayerController.instance != (Object)(object)__instance) && !((Object)(object)GameDirector.instance == (Object)null)) { KeyCode value = UpgradeConfig.OpenUIKey.Value; if ((int)value != 0 && Input.GetKeyDown(value)) { string playerSteamID = PlayerController.instance.playerSteamID; CustomUI.Open(playerSteamID); } if (Input.GetKeyDown((KeyCode)27) && (Object)(object)StatsUI.instance != (Object)null) { StatsUI.instance.showStatsTimer = 0f; } } } public static void OpenUI(string steamID) { CustomUI.Open(steamID); } } internal static class CustomUI { private static REPOPopupPage page; public static void Open(string steamID) { try { if (!FreeUpgradeEveryRound.RuntimeDrafts.TryGetValue(steamID, out string[] value)) { FreeUpgradeEveryRound.Logger.LogWarning((object)"[FreeUpgrade] No draft available."); return; } if (FreeUpgradeEveryRound.FreeSlotsDict.TryGetValue(steamID, out var value2) && value2 <= 0) { if ((Object)(object)page != (Object)null) { page.ClosePage(false); Object.Destroy((Object)(object)((Component)page).gameObject); page = null; } if ((Object)(object)StatsUI.instance != (Object)null) { StatsUI.instance.showStatsTimer = 0f; } return; } if ((Object)(object)page != (Object)null) { page.ClosePage(false); Object.Destroy((Object)(object)((Component)page).gameObject); page = null; } if ((Object)(object)StatsUI.instance != (Object)null) { StatsUI.instance.Fetch(); StatsUI.instance.showStatsTimer = 999f; } page = MenuAPI.CreateREPOPopupPage("Free Upgrade UI", (PresetSide)1, false, 0f); UpgradeUI.CreateUpgradeSelectionUI(page, steamID, value); page.OpenPage(true); AdjustUIElementPositions((Transform)(object)page.menuScrollBox.scroller); FreeUpgradeEveryRound.Logger.LogInfo((object)"[FreeUpgrade] Custom UI opened."); } catch (Exception arg) { FreeUpgradeEveryRound.Logger.LogError((object)$"Custom UI failed: {arg}"); } } private static void AdjustUIElementPositions(Transform scroller) { //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_0084: Unknown result type (might be due to invalid IL or missing references) RectTransform component = ((Component)scroller).GetComponent<RectTransform>(); component.anchoredPosition = Vector2.zero; REPOButton[] componentsInChildren = ((Component)scroller).GetComponentsInChildren<REPOButton>(); float num = 40f; for (int i = 0; i < componentsInChildren.Length; i++) { RectTransform component2 = ((Component)componentsInChildren[i]).GetComponent<RectTransform>(); component2.anchoredPosition = new Vector2(0f, (float)i * num); } REPOLabel[] componentsInChildren2 = ((Component)scroller).GetComponentsInChildren<REPOLabel>(); REPOLabel[] array = componentsInChildren2; foreach (REPOLabel val in array) { RectTransform component3 = ((Component)val).GetComponent<RectTransform>(); component3.anchoredPosition = new Vector2(0f, (float)componentsInChildren.Length * num + 20f); } } } internal static class UpgradeUI { public static void CreateUpgradeSelectionUI(REPOPopupPage page, string steamID, string[] draft) { CreateFreeSlotLabel(page, steamID); float num = 60f; for (int i = 0; i < draft.Length; i++) { string upgradeKey = draft[i]; CreateUpgradeButton(steamID, upgradeKey, i, page, num * (float)i); } } private static void CreateUpgradeButton(string steamID, string upgradeKey, int index, REPOPopupPage page, float yOffset) { //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Unknown result type (might be due to invalid IL or missing references) string steamID2 = steamID; string upgradeKey2 = upgradeKey; REPOButton val = MenuAPI.CreateREPOButton(upgradeKey2, (Action)delegate { OnUpgradeSelected(steamID2, upgradeKey2); }, (Transform)(object)page.menuScrollBox.scroller, default(Vector2)); RectTransform component = ((Component)val).GetComponent<RectTransform>(); component.anchoredPosition = new Vector2(0f, 0f - yOffset); } private static void CreateFreeSlotLabel(REPOPopupPage page, string steamID) { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Expected O, but got Unknown //IL_006d: Unknown result type (might be due to invalid IL or missing references) int remainingFreeSlots = GetRemainingFreeSlots(steamID); GameObject val = new GameObject("FreeSlotsLabel"); val.transform.SetParent((Transform)(object)page.menuScrollBox.scroller); TextMeshProUGUI val2 = val.AddComponent<TextMeshProUGUI>(); ((TMP_Text)val2).text = $"Free Slots: {remainingFreeSlots}"; ((TMP_Text)val2).fontSize = 24f; ((TMP_Text)val2).alignment = (TextAlignmentOptions)514; RectTransform component = ((Component)val2).GetComponent<RectTransform>(); component.anchoredPosition = new Vector2(0f, 70f); } private static void OnUpgradeSelected(string steamID, string upgradeKey) { FreeUpgradeNet.SendSelectToHost(steamID, upgradeKey); FreeUpgradeEveryRound.Logger.LogInfo((object)("[FreeUpgrade] Upgrade selected: " + upgradeKey + " by " + steamID)); } private static int GetRemainingFreeSlots(string steamID) { if (FreeUpgradeEveryRound.FreeSlotsDict.TryGetValue(steamID, out var value)) { return value; } return 0; } } public static class SceneUtil { private static bool isSceneLoaded; static SceneUtil() { SceneManager.sceneLoaded += OnSceneLoaded; } private static void OnSceneLoaded(Scene scene, LoadSceneMode mode) { isSceneLoaded = true; } public static string GetCurrentLevelName() { if (!isSceneLoaded) { FreeUpgradeEveryRound.Logger.LogWarning((object)"[FreeUpgrade] Waiting for scene to load, skipping level check."); return string.Empty; } RunManager instance = RunManager.instance; if ((Object)(object)instance == (Object)null || (Object)(object)instance.levelCurrent == (Object)null) { return string.Empty; } string text = ((Object)instance.levelCurrent).name.ToLowerInvariant(); FreeUpgradeEveryRound.Logger.LogInfo((object)("[FreeUpgrade] Current Level: " + text)); return text; } public static bool IsGameInProgress() { if (!isSceneLoaded) { FreeUpgradeEveryRound.Logger.LogWarning((object)"[FreeUpgrade] Waiting for scene to load, skipping game progress check."); return false; } RunManager instance = RunManager.instance; if ((Object)(object)instance == (Object)null || (Object)(object)instance.levelCurrent == (Object)null) { return false; } string text = ((Object)instance.levelCurrent).name.ToLowerInvariant(); bool flag = text.Contains("museum") || text.Contains("manor") || text.Contains("arctic") || text.Contains("wizard") || text.Contains("shop") || text.Contains("truck"); FreeUpgradeEveryRound.Logger.LogInfo((object)$"[FreeUpgrade] IsGameInProgress Check: Level={text}, IsInProgress={flag}"); return flag; } } internal static class UpgradeConfig { public static Dictionary<string, ConfigEntry<float>> Entries = new Dictionary<string, ConfigEntry<float>>(); public static Dictionary<string, float> Probabilities = new Dictionary<string, float>(); public static ConfigEntry<int> DraftCount; public static ConfigEntry<int> FreePerLevel; public static ConfigEntry<KeyCode> OpenUIKey; public static ConfigEntry<int> Stamina; public static ConfigEntry<int> Health; public static ConfigEntry<int> Wings; public static ConfigEntry<int> Launch; public static ConfigEntry<int> Climb; public static ConfigEntry<int> Rest; public static ConfigEntry<int> Speed; public static ConfigEntry<int> Jump; public static ConfigEntry<int> Strength; public static ConfigEntry<int> Range; public static ConfigEntry<int> Battery; public static ConfigEntry<int> MapCount; public static Dictionary<string, ConfigEntry<int>> WeightDict; public static void Init(ConfigFile config) { //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Expected O, but got Unknown //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Expected O, but got Unknown //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_0079: Expected O, but got Unknown //IL_0096: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: Expected O, but got Unknown //IL_00bd: Unknown result type (might be due to invalid IL or missing references) //IL_00c7: Expected O, but got Unknown //IL_00e4: Unknown result type (might be due to invalid IL or missing references) //IL_00ee: Expected O, but got Unknown //IL_010b: Unknown result type (might be due to invalid IL or missing references) //IL_0115: Expected O, but got Unknown //IL_0132: Unknown result type (might be due to invalid IL or missing references) //IL_013c: Expected O, but got Unknown //IL_0159: Unknown result type (might be due to invalid IL or missing references) //IL_0163: Expected O, but got Unknown //IL_0180: Unknown result type (might be due to invalid IL or missing references) //IL_018a: Expected O, but got Unknown //IL_01a6: Unknown result type (might be due to invalid IL or missing references) //IL_01b0: Expected O, but got Unknown //IL_01cc: Unknown result type (might be due to invalid IL or missing references) //IL_01d6: Expected O, but got Unknown //IL_02c2: Unknown result type (might be due to invalid IL or missing references) //IL_02cc: Expected O, but got Unknown AcceptableValueRange<int> val = new AcceptableValueRange<int>(0, 100); Stamina = config.Bind<int>("UpgradeWeights", "Stamina", 100, new ConfigDescription("Weight (0–100)", (AcceptableValueBase)(object)val, Array.Empty<object>())); Health = config.Bind<int>("UpgradeWeights", "Health", 100, new ConfigDescription("Weight (0–100)", (AcceptableValueBase)(object)val, Array.Empty<object>())); Wings = config.Bind<int>("UpgradeWeights", "Wings", 100, new ConfigDescription("Weight (0–100)", (AcceptableValueBase)(object)val, Array.Empty<object>())); Launch = config.Bind<int>("UpgradeWeights", "Launch", 100, new ConfigDescription("Weight (0–100)", (AcceptableValueBase)(object)val, Array.Empty<object>())); Climb = config.Bind<int>("UpgradeWeights", "Climb", 100, new ConfigDescription("Weight (0–100)", (AcceptableValueBase)(object)val, Array.Empty<object>())); Rest = config.Bind<int>("UpgradeWeights", "Rest", 100, new ConfigDescription("Weight (0–100)", (AcceptableValueBase)(object)val, Array.Empty<object>())); Speed = config.Bind<int>("UpgradeWeights", "Speed", 100, new ConfigDescription("Weight (0–100)", (AcceptableValueBase)(object)val, Array.Empty<object>())); Jump = config.Bind<int>("UpgradeWeights", "Jump", 100, new ConfigDescription("Weight (0–100)", (AcceptableValueBase)(object)val, Array.Empty<object>())); Strength = config.Bind<int>("UpgradeWeights", "Strength", 100, new ConfigDescription("Weight (0–100)", (AcceptableValueBase)(object)val, Array.Empty<object>())); Range = config.Bind<int>("UpgradeWeights", "Range", 100, new ConfigDescription("Weight (0–100)", (AcceptableValueBase)(object)val, Array.Empty<object>())); Battery = config.Bind<int>("UpgradeWeights", "Battery", 0, new ConfigDescription("Weight (0–100)", (AcceptableValueBase)(object)val, Array.Empty<object>())); MapCount = config.Bind<int>("UpgradeWeights", "Map", 0, new ConfigDescription("Weight (0–100)", (AcceptableValueBase)(object)val, Array.Empty<object>())); WeightDict = new Dictionary<string, ConfigEntry<int>> { { "Stamina", Stamina }, { "Health", Health }, { "Wings", Wings }, { "Launch", Launch }, { "Climb", Climb }, { "Rest", Rest }, { "Speed", Speed }, { "Jump", Jump }, { "Strength", Strength }, { "Range", Range }, { "Battery", Battery }, { "Map", MapCount } }; DraftCount = config.Bind<int>("General", "DraftCount", 4, new ConfigDescription("How many upgrades appear (1-4)", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 4), Array.Empty<object>())); } public static int GetWeight(string upgradeKey) { if (WeightDict.TryGetValue(upgradeKey, out ConfigEntry<int> value)) { return value.Value; } return 0; } internal static void Load(ConfigFile config) { OpenUIKey = config.Bind<KeyCode>("UI", "OpenUIKey", (KeyCode)112, "Key used to reopen the Free Upgrade UI. Set to None to disable."); Refresh(); } internal static void Refresh() { Probabilities.Clear(); foreach (KeyValuePair<string, ConfigEntry<float>> entry in Entries) { Probabilities[entry.Key] = entry.Value.Value; } } } } namespace FreeUpgradeEveryRound.Patchs { [HarmonyPatch(typeof(SemiFunc))] [HarmonyPatch("OnLevelGenDone")] public static class FreeUpgrade_LevelPatch { [HarmonyPostfix] private static void Postfix() { if (!SceneUtil.IsGameInProgress()) { FreeUpgradeEveryRound.Logger.LogWarning((object)"[FreeUpgrade] Game is not in progress, skipping level gen sync."); return; } int levelsCompleted = RunManager.instance.levelsCompleted; FreeUpgradeEveryRound.Logger.LogInfo((object)$"[FreeUpgrade] OnLevelGenDone: levelsCompleted={levelsCompleted}"); foreach (PlayerAvatar player in GameDirector.instance.PlayerList) { if (!((Object)(object)player == (Object)null)) { PhotonView photonView = player.photonView; Player val = (((Object)(object)photonView != (Object)null) ? photonView.Owner : null); int num = ((val != null) ? val.ActorNumber : (-1)); string text = player.steamID; if (string.IsNullOrEmpty(text)) { text = (player.steamID = ((num <= 0) ? $"LOCAL_AVATAR_{((Object)player).GetInstanceID()}" : $"LOCAL_{num}")); FreeUpgradeEveryRound.Logger.LogWarning((object)("[FreeUpgrade] steamID=null → LocalMultiplayer用に割り当て steamID=" + text)); } FreeUpgradeEveryRound.SyncFreeSlotForPlayer(text, levelsCompleted); if (FreeUpgradeEveryRound.FreeSlotsDict.TryGetValue(text, out var value) && value > 0) { string[] array = DraftGenerator.GenerateDraft(); FreeUpgradeEveryRound.RuntimeDrafts[text] = array; FreeUpgradeNet.SendDraftToAll(text, array); } } } } } [HarmonyPatch(typeof(StatsManager))] public static class FreeUpgrade_StatsPatch { [HarmonyPatch("Start")] [HarmonyPostfix] private static void InjectFreeUpgradeDictionaries(StatsManager __instance) { Dictionary<string, Dictionary<string, int>> dictionaryOfDictionaries = __instance.dictionaryOfDictionaries; if (!dictionaryOfDictionaries.ContainsKey("FreeUpgrade_freeSlots")) { dictionaryOfDictionaries.Add("FreeUpgrade_freeSlots", FreeUpgradeEveryRound.FreeSlotsDict); } if (!dictionaryOfDictionaries.ContainsKey("FreeUpgrade_lastFreeLevel")) { dictionaryOfDictionaries.Add("FreeUpgrade_lastFreeLevel", FreeUpgradeEveryRound.LastFreeLevelDict); } FreeUpgradeEveryRound.Logger.LogInfo((object)"[FreeUpgrade] 永続化辞書を StatsManager に登録しました"); } } [HarmonyPatch(typeof(SemiFunc))] [HarmonyPatch("OnSceneSwitch")] public static class FreeUpgrade_SyncPatch { [HarmonyPostfix] private static void AfterSceneSwitch() { if (IsGameInProgress()) { FreeUpgradeEveryRound.SyncFromStatsManager(); } } private static bool IsGameInProgress() { //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) //IL_0075: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Invalid comparison between Unknown and I4 Scene activeScene = SceneManager.GetActiveScene(); string text = ((Scene)(ref activeScene)).name.ToLowerInvariant(); bool flag = text.Contains("museum") || text.Contains("manor") || text.Contains("arctic") || text.Contains("wizard") || text.Contains("shop") || text.Contains("truck"); return (Object)(object)GameDirector.instance != (Object)null && (int)GameDirector.instance.currentState >= 2 && flag; } } }