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 OrbGather v1.1.0
OrbGather.dll
Decompiled 19 hours agousing 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 PickupShare; using RoR2; using RoR2.Artifacts; using RoR2.Navigation; using UnityEngine; using UnityEngine.Networking; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")] [assembly: AssemblyCompany("OrbGather")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.1.0.0")] [assembly: AssemblyInformationalVersion("1.1.0")] [assembly: AssemblyProduct("OrbGather")] [assembly: AssemblyTitle("OrbGather")] [assembly: AssemblyVersion("1.1.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 OrbGather { public enum GatherTrigger { BossDefeated, TeleporterCharged, Either } [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInPlugin("com.majai.orbgather", "OrbGather", "1.1.0")] public class OrbGatherPlugin : BaseUnityPlugin { public const string Guid = "com.majai.orbgather"; public const string Name = "OrbGather"; public const string Version = "1.1.0"; private const string ItemShareGuid = "com.majai.itemshare"; private static readonly string[] StateOwningPlugins = new string[1] { "com.majai.itemshare" }; private static ManualLogSource _log; private static OrbGatherPlugin _instance; private static ConfigEntry<GatherTrigger> _trigger; private static ConfigEntry<float> _delay; private static ConfigEntry<bool> _gatherCommandCubes; private static ConfigEntry<bool> _announce; private static ConfigEntry<int> _maxDrops; private static ConfigEntry<float> _distance; private static ConfigEntry<float> _spacing; private static ConfigEntry<float> _ringSpacing; private static ConfigEntry<float> _heightOffset; private static ConfigEntry<float> _maxSnapDistance; private static int _stageSerial; private static bool _gatherClaimed; private static readonly List<Vector3> Placed = new List<Vector3>(); private static readonly List<NodeIndex> NodeCandidates = new List<NodeIndex>(); private static readonly FieldInfo ConsumedField = typeof(GenericPickupController).GetField("consumed", BindingFlags.Instance | BindingFlags.NonPublic); public void Awake() { _log = ((BaseUnityPlugin)this).Logger; _instance = this; _trigger = ((BaseUnityPlugin)this).Config.Bind<GatherTrigger>("General", "Trigger", GatherTrigger.Either, "When to sweep the stage.\nBossDefeated: the moment the teleporter boss dies, while the teleporter is still charging.\nTeleporterCharged: once charging finishes.\nEither: whichever comes first. Normally the boss dying, with the charge as a fallback in case the boss encounter could not be matched to the teleporter."); _delay = ((BaseUnityPlugin)this).Config.Bind<float>("General", "Delay", 3f, "Seconds to wait after the trigger before sweeping. Boss rewards are thrown out as droplets and only become real pickups once they land, so gathering instantly would miss them."); _gatherCommandCubes = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "GatherCommandCubes", true, "Bring Artifact of Command cubes along with everything else. The Scrapper, printers, Meal Prep, the Hoard, the Solus vendor and Lemurian eggs are never touched."); _announce = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Announce", true, "Post a chat line saying how many drops were brought to the teleporter."); _maxDrops = ((BaseUnityPlugin)this).Config.Bind<int>("General", "MaxDrops", 60, "Safety cap on how many drops one sweep will relocate. Anything past this is left where it is."); _distance = ((BaseUnityPlugin)this).Config.Bind<float>("Placement", "Distance", 15f, "Metres from the teleporter to the ring of drops."); _spacing = ((BaseUnityPlugin)this).Config.Bind<float>("Placement", "Spacing", 3f, "Minimum gap between two gathered drops. Also decides how many fit on one ring."); _ringSpacing = ((BaseUnityPlugin)this).Config.Bind<float>("Placement", "RingSpacing", 4f, "Extra metres of radius for each additional ring, once the first one is full."); _heightOffset = ((BaseUnityPlugin)this).Config.Bind<float>("Placement", "HeightOffset", 1f, "How far above the ground each drop is placed."); _maxSnapDistance = ((BaseUnityPlugin)this).Config.Bind<float>("Placement", "MaxSnapDistance", 6f, "How far a ring slot may be pulled to reach walkable ground. Drops are placed on the game's own navigation graph so they cannot end up behind a wall or off the map; this is how much the ring is allowed to bend to stay on it. Raise it on open stages where drops are being skipped, lower it to keep the ring tighter."); BossGroup.onBossGroupDefeatedServer += OnBossDefeated; TeleporterInteraction.onTeleporterChargedGlobal += OnTeleporterCharged; Stage.onStageStartGlobal += OnStageStart; _log.LogInfo((object)(string.Format("{0} {1} loaded. Trigger={2}, ", "OrbGather", "1.1.0", _trigger.Value) + $"distance={_distance.Value}m, delay={_delay.Value}s.")); } public void OnDestroy() { BossGroup.onBossGroupDefeatedServer -= OnBossDefeated; TeleporterInteraction.onTeleporterChargedGlobal -= OnTeleporterCharged; Stage.onStageStartGlobal -= OnStageStart; } private static void OnStageStart(Stage stage) { _stageSerial++; _gatherClaimed = false; } private static void OnBossDefeated(BossGroup group) { if (_trigger.Value != GatherTrigger.TeleporterCharged) { TeleporterInteraction instance = TeleporterInteraction.instance; if (!((Object)(object)instance == (Object)null) && !((Object)(object)group == (Object)null) && !((Object)(object)instance.bossGroup != (Object)(object)group)) { Schedule("boss defeated"); } } } private static void OnTeleporterCharged(TeleporterInteraction teleporter) { if (_trigger.Value != GatherTrigger.BossDefeated) { Schedule("teleporter charged"); } } private static void Schedule(string reason) { if (NetworkServer.active && !_gatherClaimed && !((Object)(object)_instance == (Object)null) && !((Object)(object)TeleporterInteraction.instance == (Object)null)) { _gatherClaimed = true; ((MonoBehaviour)_instance).StartCoroutine(GatherAfterDelay(_stageSerial, reason)); } } private static IEnumerator GatherAfterDelay(int serial, string reason) { float num = Mathf.Max(0f, _delay.Value); if (num > 0f) { yield return (object)new WaitForSeconds(num); } if (serial == _stageSerial && NetworkServer.active) { Gather(reason); } } private static void Gather(string reason) { //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_00ec: Unknown result type (might be due to invalid IL or missing references) //IL_00fc: 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_0159: Unknown result type (might be due to invalid IL or missing references) //IL_01b5: Unknown result type (might be due to invalid IL or missing references) //IL_01bc: Expected O, but got Unknown TeleporterInteraction instance = TeleporterInteraction.instance; if ((Object)(object)instance == (Object)null || !StateHandoffIsSafe()) { return; } Vector3 position = ((Component)instance).transform.position; if ((Object)(object)SceneInfo.instance == (Object)null || (Object)(object)SceneInfo.instance.groundNodes == (Object)null) { _log.LogWarning((object)"No ground node graph on this stage, so there is no way to tell reachable ground from scenery. Nothing gathered."); return; } List<GenericPickupController> list = CollectOrbs(); List<PickupPickerController> list2 = CollectCubes(); int num = Mathf.Max(0, _maxDrops.Value); int num2 = list.Count + list2.Count; if (num2 == 0) { return; } if (num2 > num) { _log.LogWarning((object)($"{num2} drops on the stage, MaxDrops is {num}. " + "The rest stay where they are.")); } Placed.Clear(); int slot = 0; int num3 = 0; foreach (GenericPickupController item in list) { if (num3 >= num) { break; } if (!((Object)(object)item == (Object)null)) { if (!NextPosition(position, ref slot, out var position2)) { break; } if (RelocateOrb(item, position2)) { num3++; } } } foreach (PickupPickerController item2 in list2) { if (num3 >= num) { break; } if (!((Object)(object)item2 == (Object)null)) { if (!NextPosition(position, ref slot, out var position3)) { break; } if (RelocateCube(item2, position3)) { num3++; } } } _log.LogInfo((object)$"Gathered {num3}/{num2} drops at the teleporter ({reason})."); if (num3 > 0 && _announce.Value) { SimpleChatMessage val = new SimpleChatMessage(); val.baseToken = "<style=cIsUtility>[OrbGather] {0} drops moved to the teleporter.</style>"; val.paramTokens = new string[1] { num3.ToString() }; Chat.SendBroadcastChat((ChatMessageBase)(object)val); } } private static bool StateHandoffIsSafe() { if (PickupShareApi.HasProvider) { return true; } string[] stateOwningPlugins = StateOwningPlugins; foreach (string text in stateOwningPlugins) { if (Chainloader.PluginInfos.ContainsKey(text)) { _log.LogError((object)("'" + text + "' is installed but has not registered with PickupShareApi. Moving drops now would throw away its record of who already collected them and let players collect the same drop twice, so nothing will be gathered. Update it to a version that registers.")); return false; } } return true; } private static List<GenericPickupController> CollectOrbs() { List<GenericPickupController> list = new List<GenericPickupController>(); foreach (GenericPickupController instances in InstanceTracker.GetInstancesList<GenericPickupController>()) { if (!((Object)(object)instances == (Object)null) && !IsConsumed(instances) && !((Object)(object)((Component)instances).GetComponent<PickupPickerController>() != (Object)null)) { list.Add(instances); } } return list; } private static List<PickupPickerController> CollectCubes() { List<PickupPickerController> list = new List<PickupPickerController>(); if (!_gatherCommandCubes.Value || (Object)(object)CommandArtifactManager.commandCubePrefab == (Object)null) { return list; } foreach (PickupPickerController instances in InstanceTracker.GetInstancesList<PickupPickerController>()) { if (!((Object)(object)instances == (Object)null) && PickupClassifier.IsCommandCube(instances) && PickupClassifier.IsRuntimeSpawned((Component)(object)instances) && !((Object)(object)((Component)instances).GetComponent<PickupIndexNetworker>() == (Object)null)) { list.Add(instances); } } return list; } private static bool IsConsumed(GenericPickupController orb) { if (ConsumedField != null) { return (bool)ConsumedField.GetValue(orb); } return false; } private static bool RelocateOrb(GenericPickupController orb, Vector3 position) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_000b: 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_0017: Unknown result type (might be due to invalid IL or missing references) //IL_001f: 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_0071: Unknown result type (might be due to invalid IL or missing references) CreatePickupInfo val = new CreatePickupInfo { position = position, rotation = Quaternion.identity }; ((CreatePickupInfo)(ref val)).pickup = orb.pickup; val.chest = orb.chestGeneratedFrom; val.duplicated = orb.Duplicated; val.recycled = orb.Recycled; GenericPickupController val2 = GenericPickupController.CreatePickup(ref val); if ((Object)(object)val2 == (Object)null) { _log.LogWarning((object)$"CreatePickup returned nothing for {orb.pickup.pickupIndex}; left in place."); return false; } PickupShareApi.TransferOrbState(((Object)orb).GetInstanceID(), ((Object)val2).GetInstanceID()); NetworkServer.Destroy(((Component)orb).gameObject); return true; } private static bool RelocateCube(PickupPickerController cube, Vector3 position) { //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Unknown result type (might be due to invalid IL or missing references) NetworkUIPromptController component = ((Component)cube).GetComponent<NetworkUIPromptController>(); if ((Object)(object)component != (Object)null && (Object)(object)component.currentParticipantMaster != (Object)null) { _log.LogInfo((object)"A Command cube is in use, leaving it where it is."); return false; } PickupIndexNetworker component2 = ((Component)cube).GetComponent<PickupIndexNetworker>(); if ((Object)(object)component2 == (Object)null) { return false; } GameObject val = Object.Instantiate<GameObject>(CommandArtifactManager.commandCubePrefab, position, Quaternion.identity); PickupIndexNetworker component3 = val.GetComponent<PickupIndexNetworker>(); if ((Object)(object)component3 != (Object)null) { component3.NetworkpickupState = component2.pickupState; } PickupPickerController component4 = val.GetComponent<PickupPickerController>(); if ((Object)(object)component4 == (Object)null) { Object.Destroy((Object)(object)val); _log.LogWarning((object)"Command cube prefab has no PickupPickerController; cube left in place."); return false; } component4.chestGeneratedFrom = cube.chestGeneratedFrom; if (cube.options != null) { component4.SetOptionsServer((Option[])cube.options.Clone()); } NetworkServer.Spawn(val); PickupShareApi.TransferPickerState(((Object)cube).GetInstanceID(), ((Object)component4).GetInstanceID()); NetworkServer.Destroy(((Component)cube).gameObject); return true; } private static bool NextPosition(Vector3 center, ref int slot, out Vector3 position) { //IL_0004: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_000c: 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_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_004a: 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_0030: Unknown result type (might be due to invalid IL or missing references) for (int i = 0; i < 512; i++) { Vector3 candidate = SlotPosition(center, slot); slot++; if (ResolveGround(center, candidate, out position) && !TooCloseToPlaced(position)) { Placed.Add(position); return true; } } position = center; return false; } private static Vector3 SlotPosition(Vector3 center, int slot) { //IL_00a6: Unknown result type (might be due to invalid IL or missing references) //IL_00be: Unknown result type (might be due to invalid IL or missing references) //IL_00c3: Unknown result type (might be due to invalid IL or missing references) float num = Mathf.Max(0.5f, _spacing.Value); float num2 = Mathf.Max(0.5f, _ringSpacing.Value); float num3 = Mathf.Max(1f, _distance.Value); int num4 = 0; while (true) { int num5 = Mathf.Max(1, Mathf.FloorToInt((float)Math.PI * 2f * num3 / num)); if (slot < num5) { break; } slot -= num5; num4++; num3 += num2; } int num6 = Mathf.Max(1, Mathf.FloorToInt((float)Math.PI * 2f * num3 / num)); float num7 = 360f / (float)num6; float num8 = ((float)slot * num7 + (float)num4 * num7 * 0.5f) * ((float)Math.PI / 180f); return center + new Vector3(Mathf.Cos(num8) * num3, 0f, Mathf.Sin(num8) * num3); } private static bool ResolveGround(Vector3 center, Vector3 candidate, out Vector3 position) { //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) //IL_004d: 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_008b: Unknown result type (might be due to invalid IL or missing references) //IL_0090: Unknown result type (might be due to invalid IL or missing references) //IL_0093: Unknown result type (might be due to invalid IL or missing references) //IL_009e: Unknown result type (might be due to invalid IL or missing references) //IL_00a5: 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_00b5: Unknown result type (might be due to invalid IL or missing references) //IL_00b6: Unknown result type (might be due to invalid IL or missing references) //IL_00bb: 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) //IL_00f5: 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_010e: Unknown result type (might be due to invalid IL or missing references) //IL_0114: Unknown result type (might be due to invalid IL or missing references) //IL_011e: Unknown result type (might be due to invalid IL or missing references) //IL_0123: Unknown result type (might be due to invalid IL or missing references) //IL_0127: Unknown result type (might be due to invalid IL or missing references) //IL_00ce: Unknown result type (might be due to invalid IL or missing references) //IL_00d0: Unknown result type (might be due to invalid IL or missing references) position = candidate; NodeGraph val = (((Object)(object)SceneInfo.instance != (Object)null) ? SceneInfo.instance.groundNodes : null); if ((Object)(object)val == (Object)null) { return false; } float num = Mathf.Max(1f, _maxSnapDistance.Value); NodeCandidates.Clear(); val.FindNodesInRangeWithFlagConditions(candidate, 0f, num, (HullMask)1, (NodeFlags)0, (NodeFlags)8, false, NodeCandidates); if (NodeCandidates.Count == 0) { return false; } float num2 = float.MaxValue; Vector3 val2 = candidate; bool flag = false; Vector3 val3 = default(Vector3); foreach (NodeIndex nodeCandidate in NodeCandidates) { if (val.GetNodePosition(nodeCandidate, ref val3) && !(val3.y < center.y - 25f)) { Vector3 val4 = val3 - candidate; float sqrMagnitude = ((Vector3)(ref val4)).sqrMagnitude; if (!(sqrMagnitude >= num2)) { num2 = sqrMagnitude; val2 = val3; flag = true; } } } if (!flag) { return false; } position = val2 + Vector3.up * _heightOffset.Value; Vector3 val5 = position; LayerIndex world = LayerIndex.world; return !Physics.CheckSphere(val5, 0.5f, LayerMask.op_Implicit(((LayerIndex)(ref world)).mask), (QueryTriggerInteraction)1); } private static bool TooCloseToPlaced(Vector3 position) { //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0031: 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_0037: Unknown result type (might be due to invalid IL or missing references) float num = Mathf.Max(0.5f, _spacing.Value) * 0.75f; float num2 = num * num; foreach (Vector3 item in Placed) { Vector3 val = item - position; if (((Vector3)(ref val)).sqrMagnitude < num2) { return true; } } return false; } } }