using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Configuration; using BepInEx.Logging; using Microsoft.CodeAnalysis; using RiskOfOptions; using RiskOfOptions.OptionConfigs; using RiskOfOptions.Options; using RoR2; using UnityEngine; using UnityEngine.AddressableAssets; using UnityEngine.Networking; [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("GuaranteedGasPrinter")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("GuaranteedGasPrinter")] [assembly: AssemblyTitle("GuaranteedGasPrinter")] [assembly: AssemblyVersion("1.0.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 GuaranteedGasPrinter { [BepInPlugin("com.rowan.GuaranteedGasPrinter", "GuaranteedGasPrinter", "1.5.0")] [BepInDependency(/*Could not decode attribute arguments.*/)] public class GuaranteedGasPrinterPlugin : BaseUnityPlugin { public const string GUID = "com.rowan.GuaranteedGasPrinter"; public const string NAME = "GuaranteedGasPrinter"; public const string VERSION = "1.5.0"; internal static ConfigEntry Enabled; internal static ConfigEntry TargetItem; internal static ConfigEntry PrintersPerStage; internal static ConfigEntry SkipSpecialStages; internal static ConfigEntry Announce; internal static ConfigEntry VerboseLog; internal static ConfigEntry SpawnNearPlayer; internal static ConfigEntry MinDistance; internal static ConfigEntry MaxDistance; internal static ConfigEntry PlaceByExistingInteractable; internal static ManualLogSource Log; private static GuaranteedGasPrinterPlugin _instance; public void Awake() { //IL_0077: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Expected O, but got Unknown //IL_0134: Unknown result type (might be due to invalid IL or missing references) //IL_013e: Expected O, but got Unknown //IL_0191: Unknown result type (might be due to invalid IL or missing references) //IL_019b: Expected O, but got Unknown _instance = this; Log = ((BaseUnityPlugin)this).Logger; Enabled = ((BaseUnityPlugin)this).Config.Bind("General", "Enabled", true, "Spawn a guaranteed printer for a chosen item on every stage."); TargetItem = ((BaseUnityPlugin)this).Config.Bind("General", "Item", "Gasoline", "Item the printer should print. Accepts the internal name (Gasoline) or the display name (Gasoline)."); PrintersPerStage = ((BaseUnityPlugin)this).Config.Bind("General", "Printers Per Stage", 1, new ConfigDescription("How many guaranteed printers to add each stage.", (AcceptableValueBase)(object)new AcceptableValueRange(1, 5), Array.Empty())); SkipSpecialStages = ((BaseUnityPlugin)this).Config.Bind("General", "Skip Special Stages", true, "Don't add the printer in the Bazaar, Void Fields, Commencement, or similar non-standard stages."); Announce = ((BaseUnityPlugin)this).Config.Bind("General", "Announce In Chat", true, "Print a chat message when the guaranteed printer spawns."); VerboseLog = ((BaseUnityPlugin)this).Config.Bind("General", "Verbose Log", true, "Write detailed spawn diagnostics to the BepInEx log."); SpawnNearPlayer = ((BaseUnityPlugin)this).Config.Bind("Placement", "Spawn Near Player", true, "Place the guaranteed printer close to the player spawn so it is easy to find. Turn off for a random spot anywhere on the map."); MinDistance = ((BaseUnityPlugin)this).Config.Bind("Placement", "Min Distance", 0f, new ConfigDescription("Closest the printer may spawn to the player (metres).", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 200f), Array.Empty())); PlaceByExistingInteractable = ((BaseUnityPlugin)this).Config.Bind("Placement", "Place Beside Existing Chest", true, "Prefer dropping the printer next to a chest or shrine the game already placed. Those sit where players actually walk, so the printer is easy to find."); MaxDistance = ((BaseUnityPlugin)this).Config.Bind("Placement", "Max Distance", 25f, new ConfigDescription("Furthest the printer may spawn from the player (metres). Keep this small so the printer lands in plain sight at stage start.", (AcceptableValueBase)(object)new AcceptableValueRange(10f, 500f), Array.Empty())); Stage.onStageStartGlobal += OnStageStart; if (Chainloader.PluginInfos.ContainsKey("com.rune580.riskofoptions")) { try { RiskOfOptionsCompat.Init(); } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("RiskOfOptions integration failed: " + ex.Message)); } } ((BaseUnityPlugin)this).Logger.LogInfo((object)"GuaranteedGasPrinter 1.5.0 loaded."); } public void OnDestroy() { Stage.onStageStartGlobal -= OnStageStart; } private static void V(string msg) { if (VerboseLog != null && VerboseLog.Value) { Log.LogInfo((object)("[GGP] " + msg)); } } private static void OnStageStart(Stage stage) { if (!Enabled.Value) { V("disabled in config; skipping"); } else if (!NetworkServer.active) { V("not server; skipping"); } else if ((Object)(object)_instance == (Object)null) { Log.LogWarning((object)"[GGP] no plugin instance"); } else { ((MonoBehaviour)_instance).StartCoroutine(_instance.SpawnRoutine(stage)); } } private IEnumerator SpawnRoutine(Stage stage) { yield return (object)new WaitForSeconds(2f); string text = "unknown"; try { SceneDef val = (((Object)(object)stage != (Object)null) ? stage.sceneDef : null); if ((Object)(object)val == (Object)null) { val = SceneCatalog.GetSceneDefForCurrentScene(); } if ((Object)(object)val != (Object)null) { text = val.baseSceneName ?? val.cachedName ?? "unnamed"; V("stage start: " + text + " (type " + ((object)Unsafe.As(ref val.sceneType)/*cast due to .constrained prefix*/).ToString() + ")"); if (SkipSpecialStages.Value && (int)val.sceneType != 1) { V("scene type is not a normal Stage; skipping (turn off 'Skip Special Stages' to force)"); yield break; } } else { V("no scene def available; continuing anyway"); } } catch (Exception ex) { Log.LogWarning((object)("[GGP] scene check failed: " + ex.Message)); } ItemDef val2 = FindItem(TargetItem.Value); if ((Object)(object)val2 == (Object)null) { Log.LogWarning((object)("[GGP] item '" + TargetItem.Value + "' not found - no printer spawned. Check the spelling in Mod Options.")); yield break; } V("target item resolved: " + ((Object)val2).name + " (tier " + ((object)val2.tier/*cast due to .constrained prefix*/).ToString() + ")"); InteractableSpawnCard printerCard = GetPrinterCard(val2.tier); if ((Object)(object)printerCard == (Object)null) { Log.LogWarning((object)("[GGP] could not load a printer spawn card for tier " + ((object)val2.tier/*cast due to .constrained prefix*/).ToString() + " - no printer spawned.")); yield break; } V("printer card: " + ((Object)printerCard).name); if ((Object)(object)DirectorCore.instance == (Object)null) { Log.LogWarning((object)"[GGP] DirectorCore not ready - no printer spawned."); yield break; } int num = 0; List list = new List(); for (int i = 0; i < PrintersPerStage.Value; i++) { if (SpawnOnePrinter(printerCard, val2, out var distanceFromPlayer)) { num++; list.Add(distanceFromPlayer); } } V("spawned " + num + "/" + PrintersPerStage.Value + " printer(s) on " + text); if (num > 0 && Announce.Value) { string text2 = ""; if (list.Count > 0 && list[0] >= 0f) { text2 = " (~" + Mathf.RoundToInt(list[0]) + "m away)"; } Chat.AddMessage("Guaranteed printer: " + Language.GetString(val2.nameToken) + ((num > 1) ? (" x" + num) : "") + text2); } else if (num == 0) { Log.LogWarning((object)("[GGP] every placement attempt failed on " + text + " (the stage may have no free interactable nodes).")); } } private IEnumerator ReassertPickup(ShopTerminalBehavior terminal, ItemDef item) { PickupIndex pickup = PickupCatalog.FindPickupIndex(item.itemIndex); for (int frame = 0; frame < 3; frame++) { yield return null; if ((Object)(object)terminal == (Object)null) { yield break; } try { terminal.SetPickupIndex(pickup, false); } catch { yield break; } } yield return (object)new WaitForSeconds(1f); if ((Object)(object)terminal != (Object)null) { try { terminal.SetPickupIndex(pickup, false); V("re-asserted printer stock as " + ((Object)item).name); } catch { } } } private static Transform FindPlayerTransform() { try { foreach (PlayerCharacterMasterController instance in PlayerCharacterMasterController.instances) { if (!((Object)(object)instance == (Object)null) && !((Object)(object)instance.master == (Object)null)) { CharacterBody body = instance.master.GetBody(); if ((Object)(object)body != (Object)null) { return ((Component)body).transform; } } } } catch { } return null; } private static bool TryFindNearestInteractable(Vector3 from, out Vector3 position) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_005e: 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) position = Vector3.zero; try { PurchaseInteraction[] array = Object.FindObjectsOfType(); float num = float.MaxValue; bool flag = false; PurchaseInteraction[] array2 = array; foreach (PurchaseInteraction val in array2) { if (!((Object)(object)val == (Object)null) && ((Component)val).gameObject.activeInHierarchy) { float num2 = Vector3.Distance(from, ((Component)val).transform.position); if (num2 < num) { num = num2; position = ((Component)val).transform.position; flag = true; } } } if (flag) { V("anchor: nearest existing interactable is " + Mathf.RoundToInt(num) + "m away"); } else { V("no existing interactables found to anchor to"); } return flag; } catch (Exception ex) { V("interactable scan failed: " + ex.Message); return false; } } private bool SpawnOnePrinter(InteractableSpawnCard card, ItemDef item, out float distanceFromPlayer) { //IL_015e: Unknown result type (might be due to invalid IL or missing references) //IL_0163: Unknown result type (might be due to invalid IL or missing references) //IL_0165: Unknown result type (might be due to invalid IL or missing references) //IL_016f: Expected O, but got Unknown //IL_0196: Unknown result type (might be due to invalid IL or missing references) //IL_019d: Expected O, but got Unknown //IL_01a7: Unknown result type (might be due to invalid IL or missing references) //IL_01ae: Expected O, but got Unknown //IL_00ba: 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_00c1: Unknown result type (might be due to invalid IL or missing references) //IL_00c6: Unknown result type (might be due to invalid IL or missing references) //IL_00cd: Unknown result type (might be due to invalid IL or missing references) //IL_00dd: Unknown result type (might be due to invalid IL or missing references) //IL_00f2: Expected O, but got Unknown //IL_00fd: Unknown result type (might be due to invalid IL or missing references) //IL_0102: Unknown result type (might be due to invalid IL or missing references) //IL_0104: Unknown result type (might be due to invalid IL or missing references) //IL_0109: Unknown result type (might be due to invalid IL or missing references) //IL_0110: Unknown result type (might be due to invalid IL or missing references) //IL_011b: Unknown result type (might be due to invalid IL or missing references) //IL_012b: Expected O, but got Unknown //IL_0136: Unknown result type (might be due to invalid IL or missing references) //IL_013b: Unknown result type (might be due to invalid IL or missing references) //IL_013d: 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) //IL_0144: Unknown result type (might be due to invalid IL or missing references) //IL_0149: Unknown result type (might be due to invalid IL or missing references) //IL_0153: Expected O, but got Unknown //IL_003b: 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_0056: Unknown result type (might be due to invalid IL or missing references) //IL_005b: 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_005d: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Expected O, but got Unknown //IL_020f: Unknown result type (might be due to invalid IL or missing references) //IL_0214: Unknown result type (might be due to invalid IL or missing references) //IL_0246: Unknown result type (might be due to invalid IL or missing references) //IL_0252: Unknown result type (might be due to invalid IL or missing references) //IL_026e: Unknown result type (might be due to invalid IL or missing references) //IL_0273: Unknown result type (might be due to invalid IL or missing references) //IL_029b: Unknown result type (might be due to invalid IL or missing references) //IL_02a6: Unknown result type (might be due to invalid IL or missing references) //IL_02dd: Unknown result type (might be due to invalid IL or missing references) //IL_02e2: Unknown result type (might be due to invalid IL or missing references) distanceFromPlayer = -1f; Transform val = (SpawnNearPlayer.Value ? FindPlayerTransform() : null); List> list = new List>(); if ((Object)(object)val != (Object)null) { if (PlaceByExistingInteractable.Value && TryFindNearestInteractable(val.position, out var position)) { list.Add(new KeyValuePair("beside nearest chest/shrine", new DirectorPlacementRule { placementMode = (PlacementMode)3, position = position })); } list.Add(new KeyValuePair("near player " + MinDistance.Value + "-" + MaxDistance.Value + "m", new DirectorPlacementRule { placementMode = (PlacementMode)1, spawnOnTarget = val, minDistance = MinDistance.Value, maxDistance = MaxDistance.Value })); list.Add(new KeyValuePair("widened 0-200m", new DirectorPlacementRule { placementMode = (PlacementMode)1, spawnOnTarget = val, minDistance = 0f, maxDistance = 200f })); list.Add(new KeyValuePair("nearest node to player", new DirectorPlacementRule { placementMode = (PlacementMode)3, position = val.position })); } list.Add(new KeyValuePair("anywhere (random)", new DirectorPlacementRule { placementMode = (PlacementMode)4 })); foreach (KeyValuePair item2 in list) { try { Xoroshiro128Plus val2 = new Xoroshiro128Plus((ulong)Random.Range(1, int.MaxValue)); DirectorSpawnRequest val3 = new DirectorSpawnRequest((SpawnCard)(object)card, item2.Value, val2); val3.ignoreTeamMemberLimit = true; GameObject val4 = DirectorCore.instance.TrySpawnObject(val3); if ((Object)(object)val4 == (Object)null) { V("placement '" + item2.Key + "' found no spot; trying next"); continue; } ShopTerminalBehavior val5 = val4.GetComponent() ?? val4.GetComponentInChildren(); if ((Object)(object)val5 != (Object)null) { val5.SetPickupIndex(PickupCatalog.FindPickupIndex(item.itemIndex), false); ((MonoBehaviour)this).StartCoroutine(ReassertPickup(val5, item)); } else { V("WARNING: spawned object has no ShopTerminalBehavior"); } if ((Object)(object)val != (Object)null) { distanceFromPlayer = Vector3.Distance(val.position, val4.transform.position); } string text = (((Object)(object)val != (Object)null) ? ((object)val.position/*cast due to .constrained prefix*/).ToString() : "n/a"); float num = (((Object)(object)val != (Object)null) ? (val4.transform.position.y - val.position.y) : 0f); V("printer placed via '" + item2.Key + "' at " + ((object)val4.transform.position/*cast due to .constrained prefix*/).ToString() + " | player at " + text + ((distanceFromPlayer >= 0f) ? (" | " + Mathf.RoundToInt(distanceFromPlayer) + "m away, " + Mathf.RoundToInt(num) + "m vertical") : "") + " | active=" + val4.activeInHierarchy + " | stocked with " + ((Object)item).name); return true; } catch (Exception ex) { Log.LogWarning((object)("[GGP] placement '" + item2.Key + "' threw: " + ex.Message)); } } return false; } private static ItemDef FindItem(string wanted) { if (string.IsNullOrWhiteSpace(wanted)) { return null; } string text = wanted.Trim().ToUpperInvariant(); ItemDef val = null; for (int i = 0; i < ItemCatalog.itemCount; i++) { ItemDef itemDef = ItemCatalog.GetItemDef((ItemIndex)i); if ((Object)(object)itemDef == (Object)null) { continue; } if ((((Object)itemDef).name ?? "").ToUpperInvariant() == text) { return itemDef; } if ((Object)(object)val == (Object)null) { string text2 = ""; try { text2 = Language.GetString(itemDef.nameToken) ?? ""; } catch { } if (text2.ToUpperInvariant() == text) { val = itemDef; } } } return val; } private static InteractableSpawnCard GetPrinterCard(ItemTier tier) { //IL_0000: 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) //IL_0018: Expected I4, but got Unknown //IL_0067: 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_00f4: Unknown result type (might be due to invalid IL or missing references) string[] array = (tier - 1) switch { 0 => new string[1] { "RoR2/Base/DuplicatorLarge/iscDuplicatorLarge.asset" }, 1 => new string[1] { "RoR2/Base/DuplicatorMilitary/iscDuplicatorMilitary.asset" }, 3 => new string[1] { "RoR2/Base/DuplicatorWild/iscDuplicatorWild.asset" }, _ => new string[1] { "RoR2/Base/Duplicator/iscDuplicator.asset" }, }; foreach (string text in array) { try { InteractableSpawnCard val = Addressables.LoadAssetAsync((object)text).WaitForCompletion(); if ((Object)(object)val != (Object)null) { return val; } } catch (Exception ex) { V("addressable '" + text + "' failed: " + ex.Message); } } try { ClassicStageInfo instance = ClassicStageInfo.instance; DirectorCardCategorySelection val2 = (((Object)(object)instance != (Object)null) ? instance.interactableCategories : null); if ((Object)(object)val2 != (Object)null) { Category[] categories = val2.categories; for (int i = 0; i < categories.Length; i++) { DirectorCard[] cards = categories[i].cards; for (int j = 0; j < cards.Length; j++) { SpawnCard spawnCard = cards[j].spawnCard; InteractableSpawnCard val3 = (InteractableSpawnCard)(object)((spawnCard is InteractableSpawnCard) ? spawnCard : null); if ((Object)(object)val3 != (Object)null && (Object)(object)((SpawnCard)val3).prefab != (Object)null && (Object)(object)((SpawnCard)val3).prefab.GetComponentInChildren() != (Object)null) { V("fallback card from stage: " + ((Object)val3).name); return val3; } } } } } catch (Exception ex2) { V("stage-card fallback failed: " + ex2.Message); } return null; } } internal static class RiskOfOptionsCompat { [MethodImpl(MethodImplOptions.NoInlining)] public static void Init() { //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Expected O, but got Unknown //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Expected O, but got Unknown //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0032: 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_0045: Expected O, but got Unknown //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Expected O, but got Unknown //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Expected O, but got Unknown //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Expected O, but got Unknown //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_0077: Expected O, but got Unknown //IL_007c: Unknown result type (might be due to invalid IL or missing references) //IL_0086: Expected O, but got Unknown //IL_008b: Unknown result type (might be due to invalid IL or missing references) //IL_0095: Expected O, but got Unknown //IL_009a: 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_00aa: Unknown result type (might be due to invalid IL or missing references) //IL_00ba: Expected O, but got Unknown //IL_00b5: Unknown result type (might be due to invalid IL or missing references) //IL_00bf: Expected O, but got Unknown //IL_00c4: Unknown result type (might be due to invalid IL or missing references) //IL_00c9: 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_00e4: Expected O, but got Unknown //IL_00df: Unknown result type (might be due to invalid IL or missing references) //IL_00e9: Expected O, but got Unknown ModSettingsManager.SetModDescription("Guarantees a 3D printer for a chosen item on every stage."); ModSettingsManager.AddOption((BaseOption)new CheckBoxOption(GuaranteedGasPrinterPlugin.Enabled)); ModSettingsManager.AddOption((BaseOption)new StringInputFieldOption(GuaranteedGasPrinterPlugin.TargetItem)); ModSettingsManager.AddOption((BaseOption)new IntSliderOption(GuaranteedGasPrinterPlugin.PrintersPerStage, new IntSliderConfig { min = 1, max = 5 })); ModSettingsManager.AddOption((BaseOption)new CheckBoxOption(GuaranteedGasPrinterPlugin.SkipSpecialStages)); ModSettingsManager.AddOption((BaseOption)new CheckBoxOption(GuaranteedGasPrinterPlugin.Announce)); ModSettingsManager.AddOption((BaseOption)new CheckBoxOption(GuaranteedGasPrinterPlugin.VerboseLog)); ModSettingsManager.AddOption((BaseOption)new CheckBoxOption(GuaranteedGasPrinterPlugin.SpawnNearPlayer)); ModSettingsManager.AddOption((BaseOption)new CheckBoxOption(GuaranteedGasPrinterPlugin.PlaceByExistingInteractable)); ModSettingsManager.AddOption((BaseOption)new SliderOption(GuaranteedGasPrinterPlugin.MinDistance, new SliderConfig { min = 0f, max = 200f })); ModSettingsManager.AddOption((BaseOption)new SliderOption(GuaranteedGasPrinterPlugin.MaxDistance, new SliderConfig { min = 10f, max = 500f })); } } }