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 CosmeticBoxSpawner v0.3.0
BepInEx\plugins\CosmeticBoxSpawner.dll
Decompiled a day agousing System; using System.Collections; using System.Diagnostics; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Microsoft.CodeAnalysis; using Photon.Pun; using UnityEngine; [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("bakhusse")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyCopyright("Copyright (c) bakhusse")] [assembly: AssemblyDescription("Configurable cosmetic box spawning for R.E.P.O.")] [assembly: AssemblyFileVersion("0.3.0.0")] [assembly: AssemblyInformationalVersion("0.3.0")] [assembly: AssemblyProduct("Cosmetic Box Spawner")] [assembly: AssemblyTitle("CosmeticBoxSpawner")] [assembly: AssemblyVersion("0.3.0.0")] [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 CosmeticBoxSpawner { [BepInPlugin("maxim.repo.cosmeticboxspawner", "Cosmetic Box Spawner", "0.3.0")] [BepInProcess("REPO.exe")] public sealed class CosmeticBoxSpawnerPlugin : BaseUnityPlugin { private ConfigEntry<KeyCode>[] _keys; private ConfigEntry<float> _distance; private ConfigEntry<float> _height; private ConfigEntry<float> _boxScale; private ConfigEntry<bool> _enabled; internal static ConfigEntry<int> TokenCap; internal static ConfigEntry<bool> RescueTokens; internal static ManualLogSource ModLogger; private static readonly string[] RarityNames = new string[4] { "Common", "Uncommon", "Rare", "Ultra Rare" }; private void Awake() { //IL_00e9: Unknown result type (might be due to invalid IL or missing references) //IL_00f3: Expected O, but got Unknown //IL_0191: Unknown result type (might be due to invalid IL or missing references) ModLogger = ((BaseUnityPlugin)this).Logger; TokenCap = ((BaseUnityPlugin)this).Config.Bind<int>("Rewards", "MaxBoxesPerLevel", 10000, "Number of cosmetic boxes that can count towards rewards in one level (1-100000). 10000 is effectively unlimited."); RescueTokens = ((BaseUnityPlugin)this).Config.Bind<bool>("Rewards", "RescuePendingTokens", true, "At the end of the results screen, credit cosmetic tokens not yet processed by its animations."); _enabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enabled", true, "Enable spawning cosmetic boxes with hotkeys."); _distance = ((BaseUnityPlugin)this).Config.Bind<float>("Placement", "Distance", 2.25f, "Horizontal distance in metres in front of the player."); _height = ((BaseUnityPlugin)this).Config.Bind<float>("Placement", "Height", 1.05f, "Height above the player's feet in metres."); _boxScale = ((BaseUnityPlugin)this).Config.Bind<float>("Placement", "BoxScale", 0.4f, new ConfigDescription("Size of newly spawned cosmetic boxes relative to normal (0.10 - 1.00). Also scales inherited colliders locally. In multiplayer, size is NOT guaranteed to sync to players without a compatible scaling mod. 1.00 means original size.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.1f, 1f), Array.Empty<object>())); _keys = new ConfigEntry<KeyCode>[4] { ((BaseUnityPlugin)this).Config.Bind<KeyCode>("Hotkeys", "Common", (KeyCode)257, "Spawn a Common cosmetic box."), ((BaseUnityPlugin)this).Config.Bind<KeyCode>("Hotkeys", "Uncommon", (KeyCode)258, "Spawn an Uncommon cosmetic box."), ((BaseUnityPlugin)this).Config.Bind<KeyCode>("Hotkeys", "Rare", (KeyCode)259, "Spawn a Rare cosmetic box."), ((BaseUnityPlugin)this).Config.Bind<KeyCode>("Hotkeys", "UltraRare", (KeyCode)260, "Spawn an Ultra Rare cosmetic box.") }; try { new Harmony("maxim.repo.cosmeticboxspawner").PatchAll(typeof(CosmeticBoxSpawnerPlugin).Assembly); ((BaseUnityPlugin)this).Logger.LogInfo((object)("Cosmetic Box Spawner v0.3.0: configurable hotkeys; BoxScale=" + _boxScale.Value + "; extraction limit patch registered (" + Mathf.Clamp(TokenCap.Value, 1, 100000) + " boxes/level).")); } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogError((object)("Reward patches failed to initialize. Spawning may still work: " + ex)); } } private void Update() { //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 (!_enabled.Value || !Application.isFocused) { return; } for (int i = 0; i < _keys.Length; i++) { KeyCode value = _keys[i].Value; if ((int)value != 0 && Input.GetKeyDown(value)) { SpawnBox(i); } } } private unsafe void SpawnBox(int rarityIndex) { //IL_0082: Unknown result type (might be due to invalid IL or missing references) //IL_0088: Invalid comparison between Unknown and I4 //IL_011f: Unknown result type (might be due to invalid IL or missing references) //IL_0124: Unknown result type (might be due to invalid IL or missing references) //IL_018c: Unknown result type (might be due to invalid IL or missing references) //IL_0191: Unknown result type (might be due to invalid IL or missing references) //IL_0195: Unknown result type (might be due to invalid IL or missing references) //IL_019a: Unknown result type (might be due to invalid IL or missing references) //IL_019f: Unknown result type (might be due to invalid IL or missing references) //IL_01a6: Unknown result type (might be due to invalid IL or missing references) //IL_01ab: Unknown result type (might be due to invalid IL or missing references) //IL_01b0: Unknown result type (might be due to invalid IL or missing references) //IL_01b2: Unknown result type (might be due to invalid IL or missing references) //IL_01b7: Unknown result type (might be due to invalid IL or missing references) //IL_0140: Unknown result type (might be due to invalid IL or missing references) //IL_0145: Unknown result type (might be due to invalid IL or missing references) //IL_01cd: Unknown result type (might be due to invalid IL or missing references) //IL_01cf: Unknown result type (might be due to invalid IL or missing references) //IL_0209: Unknown result type (might be due to invalid IL or missing references) //IL_020b: Unknown result type (might be due to invalid IL or missing references) //IL_02e7: Unknown result type (might be due to invalid IL or missing references) //IL_02e9: Unknown result type (might be due to invalid IL or missing references) //IL_027d: Unknown result type (might be due to invalid IL or missing references) //IL_0284: Unknown result type (might be due to invalid IL or missing references) //IL_0289: Unknown result type (might be due to invalid IL or missing references) //IL_0292: Unknown result type (might be due to invalid IL or missing references) //IL_02a0: Unknown result type (might be due to invalid IL or missing references) try { if (!SemiFunc.IsMasterClientOrSingleplayer()) { ((BaseUnityPlugin)this).Logger.LogWarning((object)"Only the host (or singleplayer) can spawn cosmetic boxes."); return; } PlayerAvatar instance = PlayerAvatar.instance; ValuableDirector instance2 = ValuableDirector.instance; GameManager instance3 = GameManager.instance; if ((Object)(object)instance == (Object)null || (Object)(object)instance2 == (Object)null || (Object)(object)instance3 == (Object)null) { ((BaseUnityPlugin)this).Logger.LogWarning((object)"Enter an active level before spawning cosmetic boxes."); return; } int num = -1; if (instance2.cosmeticWorldObjectSetups != null) { for (int i = 0; i < instance2.cosmeticWorldObjectSetups.Count; i++) { CosmeticWorldObjectSetup val = instance2.cosmeticWorldObjectSetups[i]; if (val != null && (int)val.rarity == rarityIndex) { num = i; break; } } } if (num < 0) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("No cosmetic box setup found for " + RarityNames[rarityIndex])); return; } CosmeticWorldObjectSetup val2 = instance2.cosmeticWorldObjectSetups[num]; if (val2 == null || val2.prefab == null || (Object)(object)((PrefabRef<GameObject>)(object)val2.prefab).Prefab == (Object)null) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("No cosmetic box prefab found for " + RarityNames[rarityIndex])); return; } Vector3 forward = ((Component)instance).transform.forward; forward.y = 0f; if (((Vector3)(ref forward)).sqrMagnitude < 0.0001f) { forward = Vector3.forward; } ((Vector3)(ref forward)).Normalize(); float num2 = Mathf.Clamp(_distance.Value, 0.75f, 10f); float num3 = Mathf.Clamp(_height.Value, 0.25f, 4f); Vector3 val3 = ((Component)instance).transform.position + forward * num2 + Vector3.up * num3; Quaternion identity = Quaternion.identity; GameObject val4; if (instance3.gameMode == 0) { val4 = Object.Instantiate<GameObject>(((PrefabRef<GameObject>)(object)val2.prefab).Prefab, val3, identity); } else { if (!PhotonNetwork.InRoom || !PhotonNetwork.IsMasterClient) { ((BaseUnityPlugin)this).Logger.LogWarning((object)"Photon room not ready, or you are not the room host."); return; } val4 = PhotonNetwork.InstantiateRoomObject(((PrefabRef<GameObject>)(object)val2.prefab).ResourcePath, val3, identity, (byte)0, (object[])null); } if ((Object)(object)val4 == (Object)null) { ((BaseUnityPlugin)this).Logger.LogError((object)("Failed to spawn a " + RarityNames[rarityIndex] + " box.")); return; } float num4 = Mathf.Clamp(_boxScale.Value, 0.1f, 1f); if (Mathf.Abs(num4 - 1f) > 0.0001f) { Vector3 val5 = val4.transform.localScale * num4; val4.transform.localScale = val5; val4.AddComponent<SpawnedBoxScaleKeeper>().SetTargetScale(val5); if (instance3.gameMode != 0) { ((BaseUnityPlugin)this).Logger.LogWarning((object)"BoxScale applied locally on host. Unmodded clients may see a different size/collision shape."); } } ManualLogSource logger = ((BaseUnityPlugin)this).Logger; string[] obj = new string[6] { "Spawned ", RarityNames[rarityIndex], " cosmetic box at ", null, null, null }; Vector3 val6 = val3; obj[3] = ((object)(*(Vector3*)(&val6))/*cast due to .constrained prefix*/).ToString(); obj[4] = " with local scale factor "; obj[5] = num4.ToString(); logger.LogInfo((object)string.Concat(obj)); } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogError((object)("Cosmetic box spawn failed: " + ex)); } } } public sealed class SpawnedBoxScaleKeeper : MonoBehaviour { private Vector3 _targetScale; private bool _isInitialized; internal void SetTargetScale(Vector3 target) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Unknown result type (might be due to invalid IL or missing references) _targetScale = target; _isInitialized = true; } private void LateUpdate() { //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) if (_isInitialized && ((Component)this).transform.localScale != _targetScale) { ((Component)this).transform.localScale = _targetScale; } } } [HarmonyPatch(typeof(CosmeticWorldObject), "ExtractRPC")] internal static class CosmeticExtractionWindowPatch { [ThreadStatic] private static int _depth; internal static bool IsExtracting => _depth > 0; [HarmonyPrefix] private static void BeginExtract() { _depth++; } [HarmonyFinalizer] private static Exception EndExtract(Exception __exception) { if (_depth > 0) { _depth--; } return __exception; } } [HarmonyPatch(typeof(ValuableDirector), "CosmeticWorldObjectLevelLoopsClampedGet")] internal static class CosmeticExtractionLimitPatch { private static bool _loggedFirstUse; [HarmonyPostfix] private static void RaiseLimit(ref int __result) { if (CosmeticExtractionWindowPatch.IsExtracting && CosmeticBoxSpawnerPlugin.TokenCap != null) { int num = Mathf.Clamp(CosmeticBoxSpawnerPlugin.TokenCap.Value, 1, 100000); if (!_loggedFirstUse) { _loggedFirstUse = true; CosmeticBoxSpawnerPlugin.ModLogger.LogInfo((object)("Extraction cap override active (" + num + " cosmetic crates/level).")); } if (__result < num) { __result = num; } } } } internal static class PendingTokenRewards { private static bool _working; private static bool _warned; private static readonly FieldInfo IndexField = AccessTools.Field(typeof(ResultScreenUI), "cosmeticIndex"); private static readonly FieldInfo RewardedField = AccessTools.Field(typeof(ResultScreenUI), "cosmeticIndexRewarded"); private static readonly FieldInfo ExtractedField = AccessTools.Field(typeof(RoundDirector), "cosmeticWorldObjectsExtracted"); private static readonly MethodInfo TokenAddMethod = typeof(MetaManager).GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic).FirstOrDefault((MethodInfo m) => m.Name == "CosmeticTokenAdd" && m.GetParameters().Length == 1); internal static void AwardRemaining(string reason) { if (_working || CosmeticBoxSpawnerPlugin.RescueTokens == null || !CosmeticBoxSpawnerPlugin.RescueTokens.Value) { return; } ResultScreenUI instance = ResultScreenUI.instance; RoundDirector instance2 = RoundDirector.instance; MetaManager instance3 = MetaManager.instance; if ((Object)(object)instance == (Object)null || (Object)(object)instance2 == (Object)null || (Object)(object)instance3 == (Object)null) { return; } if (IndexField == null || RewardedField == null || ExtractedField == null || TokenAddMethod == null) { if (!_warned) { _warned = true; CosmeticBoxSpawnerPlugin.ModLogger.LogWarning((object)"Could not find the expected results-screen reward fields in this game version. Automatic payout disabled; extraction limit patch is independent."); } return; } _working = true; try { if (ExtractedField.GetValue(instance2) is IList { Count: not 0 } list) { int num = (int)IndexField.GetValue(instance); bool flag = (bool)RewardedField.GetValue(instance); if (num > 0 && !flag) { num--; } num = Math.Max(0, Math.Min(num, list.Count)); int num2 = 0; for (int i = num; i < list.Count; i++) { TokenAddMethod.Invoke(instance3, new object[1] { list[i] }); IndexField.SetValue(instance, i + 1); RewardedField.SetValue(instance, true); num2++; } if (num2 > 0) { CosmeticBoxSpawnerPlugin.ModLogger.LogInfo((object)("Credited " + num2 + " pending cosmetic token(s): " + reason)); } } } catch (Exception ex) { CosmeticBoxSpawnerPlugin.ModLogger.LogWarning((object)("Pending token payout failed: " + ex)); } finally { _working = false; } } } [HarmonyPatch(typeof(ResultScreenUI), "Disable")] internal static class ResultScreenDisablePatch { [HarmonyPrefix] private static void OnDisable() { PendingTokenRewards.AwardRemaining("results screen closed"); } } [HarmonyPatch(typeof(RunManager), "ChangeLevel")] internal static class ResultChangeLevelPatch { [HarmonyPrefix] private static void OnChangeLevel() { PendingTokenRewards.AwardRemaining("level changed"); } } [HarmonyPatch(typeof(ResultScreenUI), "Update")] internal static class ResultScreenStatePatch { private static bool _wasShowingResults; [HarmonyPostfix] private static void WatchForEnd() { //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Invalid comparison between Unknown and I4 bool flag = (Object)(object)GameDirector.instance != (Object)null && (int)GameDirector.instance.currentState == 4; if (_wasShowingResults && !flag) { PendingTokenRewards.AwardRemaining("results state ended"); } _wasShowingResults = flag; } } }