using System; using System.Buffers.Binary; using System.Collections; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.IO; using System.Linq; using System.Numerics; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Serialization; using System.Runtime.Versioning; using System.Security; using System.Security.Cryptography; using System.Security.Permissions; using System.Text; using System.Threading.Tasks; using AIGraph; using Agents; using Archipelago.MultiClient.Net; using Archipelago.MultiClient.Net.BounceFeatures.DeathLink; using Archipelago.MultiClient.Net.Enums; using Archipelago.MultiClient.Net.Helpers; using Archipelago.MultiClient.Net.MessageLog.Messages; using Archipelago.MultiClient.Net.MessageLog.Parts; using Archipelago.MultiClient.Net.Models; using Archipelago.MultiClient.Net.Packets; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Core.Logging.Interpolation; using BepInEx.Logging; using BepInEx.Unity.IL2CPP; using BoosterImplants; using CellMenu; using ChainedPuzzles; using Clonesoft.Json; using Clonesoft.Json.Converters; using Clonesoft.Json.Serialization; using DropServer.BoosterImplants; using Enemies; using GameData; using Gear; using Globals; using HarmonyLib; using Il2CppInterop.Runtime; using Il2CppInterop.Runtime.Attributes; using Il2CppInterop.Runtime.Injection; using Il2CppInterop.Runtime.InteropTypes; using Il2CppInterop.Runtime.InteropTypes.Arrays; using Il2CppSystem; using Il2CppSystem.Collections; using Il2CppSystem.Collections.Generic; using Il2CppSystem.Threading; using Il2CppSystem.Threading.Tasks; using LevelGeneration; using Localization; using Microsoft.CodeAnalysis; using Newtonsoft.Json.Linq; using Player; using ReTFO.Archipelago.Features; using ReTFO.Archipelago.Features.EventHandlers; using ReTFO.Archipelago.Features.FloatingItems; using ReTFO.Archipelago.Features.ObjectiveHandlers; using ReTFO.Archipelago.Features.Pickups; using ReTFO.Archipelago.Features.Terminals; using ReTFO.Archipelago.FeaturesAPI; using ReTFO.Archipelago.ModdedInstanceData; using ReTFO.Archipelago.ModdedInstanceData.Model; using ReTFO.Archipelago.ModdedInstanceData.Processors; using ReTFO.Archipelago.Patches; using ReTFO.Archipelago.Utilities; using SNetwork; using TMPro; using TheArchive; using TheArchive.Core; using TheArchive.Core.Attributes; using TheArchive.Core.Attributes.Feature; using TheArchive.Core.Attributes.Feature.Members; using TheArchive.Core.Attributes.Feature.Patches; using TheArchive.Core.Attributes.Feature.Settings; using TheArchive.Core.FeaturesAPI; using TheArchive.Core.FeaturesAPI.Components; using TheArchive.Core.FeaturesAPI.Settings; using TheArchive.Core.Localization; using TheArchive.Features.Dev; using TheArchive.Interfaces; using UnityEngine; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")] [assembly: AssemblyCompany("Archipelago")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0+fe65bfd3387da7bbdc46dc6f39b99dc617744c48")] [assembly: AssemblyProduct("Archipelago")] [assembly: AssemblyTitle("Archipelago")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.0.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] [CompilerGenerated] internal sealed class <>z__ReadOnlyArray : IEnumerable, ICollection, IList, IEnumerable, IReadOnlyCollection, IReadOnlyList, ICollection, IList { int ICollection.Count => _items.Length; bool ICollection.IsSynchronized => false; object ICollection.SyncRoot => this; object? IList.this[int index] { get { return _items[index]; } set { throw new NotSupportedException(); } } bool IList.IsFixedSize => true; bool IList.IsReadOnly => true; int IReadOnlyCollection.Count => _items.Length; T IReadOnlyList.this[int index] => _items[index]; int ICollection.Count => _items.Length; bool ICollection.IsReadOnly => true; T IList.this[int index] { get { return _items[index]; } set { throw new NotSupportedException(); } } public <>z__ReadOnlyArray(T[] items) { _items = items; } IEnumerator IEnumerable.GetEnumerator() { return ((IEnumerable)_items).GetEnumerator(); } void ICollection.CopyTo(Array array, int index) { ((ICollection)_items).CopyTo(array, index); } int IList.Add(object? value) { throw new NotSupportedException(); } void IList.Clear() { throw new NotSupportedException(); } bool IList.Contains(object? value) { return ((IList)_items).Contains(value); } int IList.IndexOf(object? value) { return ((IList)_items).IndexOf(value); } void IList.Insert(int index, object? value) { throw new NotSupportedException(); } void IList.Remove(object? value) { throw new NotSupportedException(); } void IList.RemoveAt(int index) { throw new NotSupportedException(); } IEnumerator IEnumerable.GetEnumerator() { return ((IEnumerable)_items).GetEnumerator(); } void ICollection.Add(T item) { throw new NotSupportedException(); } void ICollection.Clear() { throw new NotSupportedException(); } bool ICollection.Contains(T item) { return ((ICollection)_items).Contains(item); } void ICollection.CopyTo(T[] array, int arrayIndex) { ((ICollection)_items).CopyTo(array, arrayIndex); } bool ICollection.Remove(T item) { throw new NotSupportedException(); } int IList.IndexOf(T item) { return ((IList)_items).IndexOf(item); } void IList.Insert(int index, T item) { throw new NotSupportedException(); } void IList.RemoveAt(int index) { throw new NotSupportedException(); } } [CompilerGenerated] internal sealed class <>z__ReadOnlySingleElementList : IEnumerable, ICollection, IList, IEnumerable, IReadOnlyCollection, IReadOnlyList, ICollection, IList { private sealed class Enumerator : IDisposable, IEnumerator, IEnumerator { object IEnumerator.Current => _item; T IEnumerator.Current => _item; public Enumerator(T item) { _item = item; } bool IEnumerator.MoveNext() { if (!_moveNextCalled) { return _moveNextCalled = true; } return false; } void IEnumerator.Reset() { _moveNextCalled = false; } void IDisposable.Dispose() { } } int ICollection.Count => 1; bool ICollection.IsSynchronized => false; object ICollection.SyncRoot => this; object? IList.this[int index] { get { if (index != 0) { throw new IndexOutOfRangeException(); } return _item; } set { throw new NotSupportedException(); } } bool IList.IsFixedSize => true; bool IList.IsReadOnly => true; int IReadOnlyCollection.Count => 1; T IReadOnlyList.this[int index] { get { if (index != 0) { throw new IndexOutOfRangeException(); } return _item; } } int ICollection.Count => 1; bool ICollection.IsReadOnly => true; T IList.this[int index] { get { if (index != 0) { throw new IndexOutOfRangeException(); } return _item; } set { throw new NotSupportedException(); } } public <>z__ReadOnlySingleElementList(T item) { _item = item; } IEnumerator IEnumerable.GetEnumerator() { return new Enumerator(_item); } void ICollection.CopyTo(Array array, int index) { array.SetValue(_item, index); } int IList.Add(object? value) { throw new NotSupportedException(); } void IList.Clear() { throw new NotSupportedException(); } bool IList.Contains(object? value) { return EqualityComparer.Default.Equals(_item, (T)value); } int IList.IndexOf(object? value) { if (!EqualityComparer.Default.Equals(_item, (T)value)) { return -1; } return 0; } void IList.Insert(int index, object? value) { throw new NotSupportedException(); } void IList.Remove(object? value) { throw new NotSupportedException(); } void IList.RemoveAt(int index) { throw new NotSupportedException(); } IEnumerator IEnumerable.GetEnumerator() { return new Enumerator(_item); } void ICollection.Add(T item) { throw new NotSupportedException(); } void ICollection.Clear() { throw new NotSupportedException(); } bool ICollection.Contains(T item) { return EqualityComparer.Default.Equals(_item, item); } void ICollection.CopyTo(T[] array, int arrayIndex) { array[arrayIndex] = _item; } bool ICollection.Remove(T item) { throw new NotSupportedException(); } int IList.IndexOf(T item) { if (!EqualityComparer.Default.Equals(_item, item)) { return -1; } return 0; } void IList.Insert(int index, T item) { throw new NotSupportedException(); } void IList.RemoveAt(int index) { throw new NotSupportedException(); } } namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [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] [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] [Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NativeIntegerAttribute : Attribute { public readonly bool[] TransformFlags; public NativeIntegerAttribute() { TransformFlags = new bool[1] { true }; } public NativeIntegerAttribute(bool[] P_0) { TransformFlags = P_0; } } [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; } } [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Enum | AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class ExtensionMarkerAttribute : Attribute { private readonly string k__BackingField; public string Name => k__BackingField; public ExtensionMarkerAttribute(string name) { k__BackingField = name; } } } namespace ReTFO.Archipelago { [ArchiveModule("RoboRyGuy.BetaArchipelago", "BetaArchipelago", "0.0.5")] public class ArchipelagoArchiveModule : IArchiveModule { private IArchiveLogger? m_logger; public ILocalizationService LocalizationService { get; set; } public IArchiveLogger Logger { get { return m_logger ?? throw new NullReferenceException("Module logger was not initalized!"); } set { m_logger = value; } } public void Init() { if (!Plugin.TryGet(out Plugin plugin)) { Logger.Error("Failed to find Plugin while loading Archipelago Archive Module!"); } else { plugin.ArchiveModule = this; } } } [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct, AllowMultiple = false)] internal class InjectToIl2Cpp : Attribute { public Type[] InterfaceTypes; public InjectToIl2Cpp() { InterfaceTypes = Array.Empty(); } public InjectToIl2Cpp(Type type) { InterfaceTypes = new Type[1] { type }; } public InjectToIl2Cpp(Type[] types) { InterfaceTypes = types; } } [BepInPlugin("RoboRyGuy.BetaArchipelago", "BetaArchipelago", "0.0.5")] [BepInProcess("GTFO.exe")] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] public class Plugin : BasePlugin { public const string Name = "BetaArchipelago"; public const string Author = "RoboRyGuy"; public const string GUID = "RoboRyGuy.BetaArchipelago"; public const string Version = "0.0.5"; private static Plugin? _plugin; protected Harmony harmony = new Harmony("RoboRyGuy.BetaArchipelago"); private ArchipelagoArchiveModule? m_archiveModule; private MidManager m_midManager = new MidManager(); public ArchipelagoArchiveModule ArchiveModule { get { return m_archiveModule ?? (m_archiveModule = ArchiveMod.Modules.OfType().First()); } internal set { m_archiveModule = value; } } public IArchiveLogger Logger => ArchiveModule.Logger; public StateTracker? StateTracker { get; internal set; } public MidManager MidManager { get { return m_midManager; } protected set { m_midManager = value; } } public event Action? LateSetup; public static Plugin Get() { return TryGet() ?? throw new NullReferenceException("Tried to retrieve BetaArchipelago, but it was not loaded!"); } public static Plugin? TryGet() { return _plugin ?? (_plugin = ((BaseChainloader)(object)IL2CPPChainloader.Instance).Plugins.FirstOrDefault((KeyValuePair p) => p.Key == "RoboRyGuy.BetaArchipelago").Value.Instance as Plugin); } public static bool TryGet([NotNullWhen(true)] out Plugin? plugin) { plugin = TryGet(); return plugin != null; } public override void Load() { //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Expected O, but got Unknown _plugin = this; harmony.PatchAll(((object)this).GetType()); IEnumerable types = from t in Assembly.GetExecutingAssembly().GetTypes() where t.DeclaringType == null select t; InjectRecursive(types); PatchRecursive(types); AddProcessors(MidManager); ManualLogSource log = ((BasePlugin)this).Log; bool flag = default(bool); BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(11, 1, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val).AppendFormatted("RoboRyGuy.BetaArchipelago"); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" is loaded!"); } log.LogInfo(val); } public override bool Unload() { harmony.UnpatchSelf(); return true; } private void InjectRecursive(IEnumerable types) { //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_0043: Expected O, but got Unknown foreach (Type type in types) { InjectToIl2Cpp customAttribute = type.GetCustomAttribute(); if (customAttribute != null) { if (type.IsAssignableTo(typeof(Il2CppObjectBase))) { RegisterTypeOptions val = new RegisterTypeOptions(); val.set_Interfaces(Il2CppInterfaceCollection.op_Implicit(customAttribute.InterfaceTypes)); RegisterTypeOptions val2 = val; ClassInjector.RegisterTypeInIl2Cpp(type, val2); } InjectRecursive(type.GetNestedTypes(AccessTools.all)); } } } private void PatchRecursive(IEnumerable types) { foreach (Type type in types) { if (((MemberInfo)type).GetCustomAttribute() != null) { harmony.PatchAll(type); PatchRecursive(type.GetNestedTypes(AccessTools.all)); } } } public static void AddProcessors(MidManager midManager) { Expedition.Processor processor = new Expedition.Processor().SubscribedTo(midManager.GetProcessor()); midManager.RegisterProcessor(processor); Layer.Processor processor2 = new Layer.Processor().SubscribedTo(processor); midManager.RegisterProcessor(processor2); Zone.Processor processor3 = new Zone.Processor().SubscribedTo(processor2); midManager.RegisterProcessor(processor3); Terminal.Processor processor4 = new Terminal.Processor().SubscribedTo(processor3); midManager.RegisterProcessor(processor4); Objective.Processor processor5 = new Objective.Processor().SubscribedTo(processor2); midManager.RegisterProcessor(processor5); Event.Processor processor6 = new Event.Processor(); midManager.RegisterProcessor(processor6); } internal void InvokeLateSetup(SNet_Replicator replicator) { this.LateSetup?.Invoke(replicator); } } } namespace ReTFO.Archipelago.Utilities { public class AsyncItemSpawnWrapper { public ISyncedItem? Item { get; set; } private event Action? OnItemSpawned; public void AddSpawnCallback(Action action) { OnItemSpawned += action; if (Item != null) { this.OnItemSpawned(Item); } } public void QueueDespawn() { AddSpawnCallback(Despawn); static void Despawn(ISyncedItem item) { ((Il2CppObjectBase)item).Cast().ReplicationWrapper.Replicator.Despawn(); } } public void OnSpawn(ISyncedItem item, PlayerAgent _) { Item = item; this.OnItemSpawned?.Invoke(item); } } public sealed class IdConverter : JsonConverter { public override bool CanRead => false; public override bool CanWrite => true; public override bool CanConvert(Type objectType) { if (objectType.IsAssignableTo(typeof(ITagID))) { return true; } Type[] interfaces = objectType.GetInterfaces(); foreach (Type type in interfaces) { if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(IEnumerable<>)) { Type type2 = type.GetGenericArguments()[0]; if (type2.IsAssignableTo(typeof(ITagID))) { return true; } } } return false; } public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer) { //IL_007b: Unknown result type (might be due to invalid IL or missing references) if (value is ITagID tagID) { serializer.Serialize(writer, (object)tagID.ID); return; } if (value is IEnumerable source) { List list = (from ITagID i in source select i.ID).ToList(); serializer.Serialize(writer, (object)list); return; } throw new JsonException("IdConverter cannot convert type " + value?.GetType().FullName); } public override object? ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer) { throw new NotImplementedException("This converter cannot read."); } } public interface IIndex { int AsIndex { get; init; } } public interface IKeyed where T : IComparable, IEquatable { T Key { get; } } [InjectToIl2Cpp] public class Il2CppAction : Object { public Action? WrappedAction; public Il2CppAction(Action action) : base(ClassInjector.DerivedConstructorPointer()) { ClassInjector.DerivedConstructorBody((Il2CppObjectBase)(object)this); WrappedAction = action; } public Il2CppAction(IntPtr pointer) : base(pointer) { } public void Action() { if (WrappedAction != null) { WrappedAction(); } } public static implicit operator Action(Il2CppAction self) { //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Expected O, but got Unknown IntPtr il2CppMethod = IL2CPP.GetIl2CppMethod(((Il2CppObjectBase)self).ObjectClass, false, "Action", typeof(void).FullName, Array.Empty()); return new Action((Object)(object)self, il2CppMethod); } } [InjectToIl2Cpp] public class Il2CppAction_int : Object { public Action? WrappedAction; public Il2CppAction_int(Action action) : base(ClassInjector.DerivedConstructorPointer()) { ClassInjector.DerivedConstructorBody((Il2CppObjectBase)(object)this); WrappedAction = action; } public Il2CppAction_int(IntPtr pointer) : base(pointer) { } public void Action(int value) { if (WrappedAction != null) { WrappedAction(value); } } public static implicit operator Action(Il2CppAction_int self) { IntPtr il2CppMethod = IL2CPP.GetIl2CppMethod(((Il2CppObjectBase)self).ObjectClass, false, "Action", typeof(void).FullName, new string[1] { typeof(int).FullName }); return new Action((Object)(object)self, il2CppMethod); } } [InjectToIl2Cpp(typeof(IEnumerable))] public class Il2CppEnumerable : Object { private IEnumerable? wrappedEnumerable; public Il2CppEnumerable(IntPtr ptr) : base(ptr) { } public Il2CppEnumerable(IEnumerable enumerable) : base(ClassInjector.DerivedConstructorPointer()) { ClassInjector.DerivedConstructorBody((Il2CppObjectBase)(object)this); wrappedEnumerable = enumerable; } public IEnumerator GetEnumerator() { IEnumerator enumerator = wrappedEnumerable?.GetEnumerator() ?? Enumerable.Empty().GetEnumerator(); IEnumerator val = (IEnumerator)((enumerator is IEnumerator) ? enumerator : null); if (val != null) { return val; } return new Il2CppEnumerator(enumerator); } public static implicit operator IEnumerable(Il2CppEnumerable enumerable) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Expected O, but got Unknown return new IEnumerable(((Il2CppObjectBase)enumerable).Pointer); } } [InjectToIl2Cpp(typeof(IEnumerator))] public class Il2CppEnumerator : Object { private IEnumerator? wrappedEnumerator; public Object Current { get { object obj = wrappedEnumerator?.Current; return (Object)((obj is Object) ? obj : null); } } public Il2CppEnumerator(IntPtr ptr) : base(ptr) { } public Il2CppEnumerator(IEnumerator enumerator) : base(ClassInjector.DerivedConstructorPointer()) { ClassInjector.DerivedConstructorBody((Il2CppObjectBase)(object)this); wrappedEnumerator = enumerator; } public bool MoveNext() { return wrappedEnumerator?.MoveNext() ?? false; } public void Reset() { wrappedEnumerator?.Reset(); } public static implicit operator IEnumerator(Il2CppEnumerator enumerable) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Expected O, but got Unknown return new IEnumerator(((Il2CppObjectBase)enumerable).Pointer); } } [InjectToIl2Cpp] public class Il2CppFunc_string : Object { public Func? WrappedFunc; public Il2CppFunc_string(Func action) : base(ClassInjector.DerivedConstructorPointer()) { ClassInjector.DerivedConstructorBody((Il2CppObjectBase)(object)this); WrappedFunc = action; } public Il2CppFunc_string(IntPtr pointer) : base(pointer) { } public string Func() { if (WrappedFunc != null) { return WrappedFunc(); } return null; } public static implicit operator Func(Il2CppFunc_string self) { IntPtr il2CppMethod = IL2CPP.GetIl2CppMethod(((Il2CppObjectBase)self).ObjectClass, false, "Func", typeof(string).FullName, Array.Empty()); return new Func((Object)(object)self, il2CppMethod); } } public static class Il2CppListIter { public static IEnumerable Iter(this List? source) { if (source != null) { Enumerator enumerator = source.GetEnumerator(); while (enumerator.MoveNext()) { yield return enumerator.Current; } } } public static bool Any(this List? source) { return source.Iter().Any(); } public static bool Any(this List source, Func predicate) { return source.Iter().Any(predicate); } public static T First(this List source) { return source.Iter().First(); } public static T First(this List source, Func predicate) { return source.Iter().First(predicate); } public static T? FirstOrDefault(this List source, Func predicate) { return source.Iter().FirstOrDefault(predicate); } public static T? FirstOrDefault(this List source) { return source.Iter().FirstOrDefault(); } public static IEnumerable Select(this List source, Func func) { return source.Iter().Select(func); } public static IEnumerable SelectMany(this List source, Func> func) { return source.Iter().SelectMany(func); } public static IEnumerable Skip(this List source, int count) { return source.Iter().Skip(count); } public static T[] ToArray(this List source) { return source.Iter().ToArray(); } public static List ToList(this List source) { return source.Iter().ToList(); } public static IEnumerable Where(this List source, Func predicate) { return source.Iter().Where(predicate); } } public static class Il2CppQueueIter { public static IEnumerable Iter(this Queue queue) { return from i in Enumerable.Range(queue._head, queue._size) select queue._array[i]; } public static T FromEnd(this Queue queue, int indexFromEnd = 0) { return queue._array[queue._head + queue._size - 1 - indexFromEnd]; } } public sealed class InlineConverter : JsonConverter { public override bool CanRead => false; public override bool CanWrite => true; public Type[] TargetTypes { get; set; } public Type[] InlinedTypes { get; set; } public InlineConverter(Type[] targetTypes, Type[] inlinedTypes) { TargetTypes = targetTypes; InlinedTypes = inlinedTypes; } public override bool CanConvert(Type objectType) { if (!TargetTypes.Any((Type t) => t.IsAssignableFrom(objectType))) { return InlinedTypes.Any((Type t) => t.IsAssignableFrom(objectType)); } return true; } public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer) { //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Invalid comparison between Unknown and I4 //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Expected O, but got Unknown bool flag = (int)writer.WriteState == 2; if (value == null) { if (!flag) { writer.WriteNull(); } return; } bool flag2 = TargetTypes.Any((Type t) => t.IsAssignableFrom(value.GetType())); JsonObjectContract val = (JsonObjectContract)serializer.ContractResolver.ResolveContract(value.GetType()); if (!flag) { writer.WriteStartObject(); } try { foreach (JsonProperty property in (Collection)(object)val.Properties) { if (!property.Ignored && property.Readable) { if (!flag2 || !InlinedTypes.Any((Type t) => t.IsAssignableFrom(property.PropertyType))) { writer.WritePropertyName(property.PropertyName); } serializer.Serialize(writer, property.ValueProvider.GetValue(value)); } } } finally { if (!flag) { writer.WriteEndObject(); } } } public override object? ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer) { throw new NotSupportedException("This converter cannot read."); } } public interface INullable { bool IsNull { get; } } public static class LinqUtils { public static IEnumerable TakeLooped(this IEnumerable source, int count) { if (count < 0) { throw new ArgumentException("Count cannot be negative"); } if (count == 0) { yield break; } IReadOnlyList cache = source as IReadOnlyList; if (cache == null) { List mutableCache = new List(); foreach (T item in source) { mutableCache.Add(item); yield return item; int num = count - 1; count = num; if (num == 0) { break; } } cache = mutableCache; } while (count-- > 0) { foreach (T item2 in cache) { yield return item2; } } } } public sealed class ListConverter : JsonConverter { private class ThisWriter : TextWriter { private JsonWriter writer; public override Encoding Encoding => System.Text.Encoding.Default; public ThisWriter(JsonWriter source) { writer = source; } public override void Write(char value) { writer.WriteRaw(new string(value, 1)); } public override void Write(string? value) { writer.WriteRaw(value); } } public override bool CanRead => false; public override bool CanWrite => true; public int MaxPerLine { get; set; } public ListConverter(int maxPerLine = 20) { MaxPerLine = maxPerLine; } public override bool CanConvert(Type objectType) { return typeof(IEnumerable).IsAssignableFrom(objectType); } public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer) { //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Invalid comparison between Unknown and I4 if (!(value is IEnumerable source)) { throw new ArgumentException("Expected value to be of type " + typeof(List).FullName + ".", "value"); } if ((int)writer.Formatting != 1) { throw new NotSupportedException("ListConverter was either used on a nested conerted list or during an unformatted serialization. Neither are supported!"); } List list = source.Chunk(MaxPerLine).ToList(); ThisWriter thisWriter = new ThisWriter(writer); if (list.Count == 0) { writer.WriteStartArray(); writer.WriteEndArray(); return; } if (list.Count == 1) { writer.WriteStartArray(); writer.WriteRaw(" "); writer.Formatting = (Formatting)0; serializer.Serialize((TextWriter)thisWriter, (object)list.First().First()); foreach (T item in list.First().Skip(1)) { writer.WriteRaw(", "); serializer.Serialize((TextWriter)thisWriter, (object)item); } writer.WriteEndArray(); writer.Formatting = (Formatting)1; return; } writer.WriteStartArray(); foreach (T[] item2 in list) { serializer.Serialize(writer, (object)item2.First()); writer.Formatting = (Formatting)0; foreach (T item3 in item2.Skip(1)) { writer.WriteRaw(", "); serializer.Serialize((TextWriter)thisWriter, (object)item3); } writer.Formatting = (Formatting)1; } writer.WriteEndArray(); } public override object? ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer) { throw new NotImplementedException("This converter cannot read."); } } public class ReadOnlyListDict : IReadOnlyDictionary, IEnumerable>, IEnumerable, IReadOnlyCollection> where I : IIndex, new() { private readonly IReadOnlyList m_list; public T this[I key] => m_list[key.AsIndex]; public IEnumerable Keys => from i in Enumerable.Range(0, m_list.Count) select new I { AsIndex = i }; public IEnumerable Values => m_list; public int Count => m_list.Count; public bool IsReadOnly => true; public ReadOnlyListDict(IReadOnlyList source) { m_list = source; } public bool ContainsKey(I key) { if (key.AsIndex >= 0) { return key.AsIndex < m_list.Count; } return false; } public IEnumerator> GetEnumerator() { return m_list.Select((T v, int i) => new KeyValuePair(new I { AsIndex = i }, v)).GetEnumerator(); } public bool TryGetValue(I key, [MaybeNullWhen(false)] out T value) { (T, bool) obj = (ContainsKey(key) ? (value = m_list[key.AsIndex], true) : (value = default(T), false)); return obj.Item2; } IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } } public static class SerializationHelpers { public static int CalcLengthSize(int value) { if (value != 0) { return Calc7BitEncodedSize(value); } return 1; } public static void WriteLength(Il2CppStructArray bytes, ref int index, int value) { Write7BitEncodedInt(bytes, ref index, value); } public static int ReadLength(Il2CppStructArray bytes, ref int index) { return Read7BitEncodedInt(bytes, ref index); } public static int Calc7BitEncodedSize(long value) { return Calc7BitEncodedSize((ulong)value); } public static int Calc7BitEncodedSize(ulong value) { if ((value & 0xFF00000000000000uL) != 0L) { return 9; } if ((value & 0xFE000000000000L) != 0L) { return 8; } if ((value & 0x1FC0000000000L) != 0L) { return 7; } if ((value & 0x3F800000000L) != 0L) { return 6; } if ((value & 0x7F0000000L) != 0L) { return 5; } if ((value & 0xFE00000) != 0L) { return 4; } if ((value & 0x1FC000) != 0L) { return 3; } if ((value & 0x3F80) != 0L) { return 2; } return 1; } public static int Calc7BitEncodedSize(int value) { return Calc7BitEncodedSize((uint)value); } public static int Calc7BitEncodedSize(uint value) { if ((value & 0xF0000000u) != 0) { return 5; } if ((value & 0xFE00000) != 0) { return 4; } if ((value & 0x1FC000) != 0) { return 3; } if ((value & 0x3F80) != 0) { return 2; } return 1; } public static int Calc7BitEncodedArraySize(ICollection values) { return Calc7BitEncodedArraySize(values.Cast(), values.Count); } public static int Calc7BitEncodedArraySize(ICollection values) { return Calc7BitEncodedArraySize(values, values.Count); } public static int Calc7BitEncodedArraySize(IEnumerable values, int count) { return Calc7BitEncodedArraySize(values.Cast(), count); } public static int Calc7BitEncodedArraySize(IEnumerable values, int count) { return Calc7BitEncodedSize(count) + values.Sum((ulong i) => Calc7BitEncodedSize(i)); } public static int Calc7BitEncodedArraySize(ICollection values) { return Calc7BitEncodedArraySize(values.Cast(), values.Count); } public static int Calc7BitEncodedArraySize(ICollection values) { return Calc7BitEncodedArraySize(values, values.Count); } public static int Calc7BitEncodedArraySize(IEnumerable values, int count) { return Calc7BitEncodedArraySize(values.Cast(), count); } public static int Calc7BitEncodedArraySize(IEnumerable values, int count) { return Calc7BitEncodedSize(count) + values.Sum((uint i) => Calc7BitEncodedSize(i)); } public static int Calc7BitEncodedMultiArraySize(ICollection> values) { return Calc7BitEncodedMultiArraySize(values.Cast>(), values.Count, values.Sum((ICollection arr) => arr.Count)); } public static int Calc7BitEncodedMultiArraySize(ICollection> values) { return Calc7BitEncodedMultiArraySize(values, values.Count, values.Sum((ICollection arr) => arr.Count)); } public static int Calc7BitEncodedMultiArraySize(IEnumerable> values, int arrCount, int valueCount) { return Calc7BitEncodedMultiArraySize(values.Cast>(), arrCount, valueCount); } public static int Calc7BitEncodedMultiArraySize(IEnumerable> values, int arrCount, int valueCount) { arrCount = ((arrCount != 0) ? (arrCount - 1) : 0); return CalcLengthSize(valueCount + arrCount) + arrCount + values.Sum((IEnumerable arr) => arr.Sum((ulong i) => Calc7BitEncodedSize(i))); } public static int Calc7BitEncodedMultiArraySize(ICollection> values) { return Calc7BitEncodedMultiArraySize(values.Cast>(), values.Count, values.Sum((ICollection arr) => arr.Count)); } public static int Calc7BitEncodedMultiArraySize(ICollection> values) { return Calc7BitEncodedMultiArraySize(values, values.Count, values.Sum((ICollection arr) => arr.Count)); } public static int Calc7BitEncodedMultiArraySize(IEnumerable> values, int arrCount, int valueCount) { return Calc7BitEncodedMultiArraySize(values.Cast>(), arrCount, valueCount); } public static int Calc7BitEncodedMultiArraySize(IEnumerable> values, int arrCount, int valueCount) { arrCount = ((arrCount != 0) ? (arrCount - 1) : 0); return CalcLengthSize(valueCount + arrCount) + arrCount + values.Sum((IEnumerable arr) => arr.Sum((uint i) => Calc7BitEncodedSize(i))); } public static void Write7BitEncodedLong(Il2CppStructArray bytes, ref int index, long value) { Write7BitEncodedLong(bytes, ref index, (ulong)value); } public static void Write7BitEncodedLong(Il2CppStructArray bytes, ref int index, ulong value) { for (int i = 0; i < 9; i++) { ((Il2CppArrayBase)(object)bytes)[index++] = (byte)((value & 0x7F) | 0x80); value >>= 7; if (value == 0L) { break; } } if (value == 0L) { ((Il2CppArrayBase)(object)bytes)[index - 1] = (byte)(((Il2CppArrayBase)(object)bytes)[index - 1] & 0x7F); } } public static void Write7BitEncodedInt(Il2CppStructArray bytes, ref int index, int value) { Write7BitEncodedInt(bytes, ref index, (uint)value); } public static void Write7BitEncodedInt(Il2CppStructArray bytes, ref int index, uint value) { for (int i = 0; i < 5; i++) { ((Il2CppArrayBase)(object)bytes)[index++] = (byte)((value & 0x7F) | 0x80); value >>= 7; if (value == 0) { break; } } ((Il2CppArrayBase)(object)bytes)[index - 1] = (byte)(((Il2CppArrayBase)(object)bytes)[index - 1] & 0x7F); } public static long Read7BitEncodedLong(Il2CppStructArray bytes, ref int index) { return (long)Read7BitEncodedULong(bytes, ref index); } public static ulong Read7BitEncodedULong(Il2CppStructArray bytes, ref int index) { ulong num = 0uL; for (int i = 0; i < 56; i += 7) { byte b = ((Il2CppArrayBase)(object)bytes)[index++]; num |= (ulong)((long)(b & 0x7F) << i); if ((0x80 & b) == 0) { return num; } } return num | ((ulong)((Il2CppArrayBase)(object)bytes)[index++] << 56); } public static int Read7BitEncodedInt(Il2CppStructArray bytes, ref int index) { return (int)Read7BitEncodedUInt(bytes, ref index); } public static uint Read7BitEncodedUInt(Il2CppStructArray bytes, ref int index) { uint num = 0u; for (int i = 0; i < 28; i += 7) { byte b = ((Il2CppArrayBase)(object)bytes)[index++]; num |= (uint)((b & 0x7F) << i); if ((0x80 & b) == 0) { return num; } } return num | (uint)(((Il2CppArrayBase)(object)bytes)[index++] << 28); } public static void Write7BitEncodedArray(Il2CppStructArray bytes, ref int index, ICollection values) { Write7BitEncodedArray(bytes, ref index, values, values.Count); } public static void Write7BitEncodedArray(Il2CppStructArray bytes, ref int index, ICollection values) { Write7BitEncodedArray(bytes, ref index, values, values.Count); } public static void Write7BitEncodedArray(Il2CppStructArray bytes, ref int index, IEnumerable values, int count) { Write7BitEncodedArray(bytes, ref index, values.Cast(), count); } public static void Write7BitEncodedArray(Il2CppStructArray bytes, ref int index, IEnumerable values, int count) { WriteLength(bytes, ref index, count); foreach (ulong value in values) { Write7BitEncodedLong(bytes, ref index, value); } } public static void Write7BitEncodedArray(Il2CppStructArray bytes, ref int index, ICollection values) { Write7BitEncodedArray(bytes, ref index, values, values.Count); } public static void Write7BitEncodedArray(Il2CppStructArray bytes, ref int index, ICollection values) { Write7BitEncodedArray(bytes, ref index, values, values.Count); } public static void Write7BitEncodedArray(Il2CppStructArray bytes, ref int index, IEnumerable values, int count) { Write7BitEncodedArray(bytes, ref index, values.Cast(), count); } public static void Write7BitEncodedArray(Il2CppStructArray bytes, ref int index, IEnumerable values, int count) { WriteLength(bytes, ref index, count); foreach (uint value in values) { Write7BitEncodedInt(bytes, ref index, value); } } public static long[] Read7BitEncodedLongArray(Il2CppStructArray bytes, ref int index) { int num = ReadLength(bytes, ref index); long[] array = new long[num]; for (int i = 0; i < num; i++) { array[i] = Read7BitEncodedLong(bytes, ref index); } return array; } public static ulong[] Read7BitEncodedULongArray(Il2CppStructArray bytes, ref int index) { int num = ReadLength(bytes, ref index); ulong[] array = new ulong[num]; for (int i = 0; i < num; i++) { array[i] = Read7BitEncodedULong(bytes, ref index); } return array; } public static int[] Read7BitEncodedIntArray(Il2CppStructArray bytes, ref int index) { int num = ReadLength(bytes, ref index); int[] array = new int[num]; for (int i = 0; i < num; i++) { array[i] = Read7BitEncodedInt(bytes, ref index); } return array; } public static uint[] Read7BitEncodedUIntArray(Il2CppStructArray bytes, ref int index) { int num = ReadLength(bytes, ref index); uint[] array = new uint[num]; for (int i = 0; i < num; i++) { array[i] = Read7BitEncodedUInt(bytes, ref index); } return array; } public static void Write7BitEncodedMultiArray(Il2CppStructArray bytes, ref int index, ICollection> values) { Write7BitEncodedMultiArray(bytes, ref index, values, values.Count, values.Sum((ICollection a) => a.Count)); } public static void Write7BitEncodedMultiArray(Il2CppStructArray bytes, ref int index, ICollection> values) { Write7BitEncodedMultiArray(bytes, ref index, values, values.Count, values.Sum((ICollection a) => a.Count)); } public static void Write7BitEncodedMultiArray(Il2CppStructArray bytes, ref int index, ICollection> values) { Write7BitEncodedMultiArray(bytes, ref index, values, values.Count, values.Sum((ICollection a) => a.Count)); } public static void Write7BitEncodedMultiArray(Il2CppStructArray bytes, ref int index, ICollection> values) { Write7BitEncodedMultiArray(bytes, ref index, values, values.Count, values.Sum((ICollection a) => a.Count)); } public static void Write7BitEncodedMultiArray(Il2CppStructArray bytes, ref int index, ICollection> values, int valuesCount) { Write7BitEncodedMultiArray(bytes, ref index, values.Cast>(), values.Count, valuesCount); } public static void Write7BitEncodedMultiArray(Il2CppStructArray bytes, ref int index, ICollection> values, int valuesCount) { Write7BitEncodedMultiArray(bytes, ref index, values, values.Count, valuesCount); } public static void Write7BitEncodedMultiArray(Il2CppStructArray bytes, ref int index, ICollection> values, int valuesCount) { Write7BitEncodedMultiArray(bytes, ref index, values.Cast>(), values.Count, valuesCount); } public static void Write7BitEncodedMultiArray(Il2CppStructArray bytes, ref int index, ICollection> values, int valuesCount) { Write7BitEncodedMultiArray(bytes, ref index, values, values.Count, valuesCount); } public static void Write7BitEncodedMultiArray(Il2CppStructArray bytes, ref int index, IEnumerable> values, int arrCount, int valuesCount) { Write7BitEncodedMultiArray(bytes, ref index, values.Cast>(), arrCount, valuesCount); } public static void Write7BitEncodedMultiArray(Il2CppStructArray bytes, ref int index, IEnumerable> values, int arrCount, int valuesCount) { Write7BitEncodedArray(bytes, ref index, values.SelectMany((IEnumerable v) => v.Prepend(0uL)).Skip(1), valuesCount + arrCount - 1); } public static void Write7BitEncodedMultiArray(Il2CppStructArray bytes, ref int index, IEnumerable> values, int arrCount, int valuesCount) { Write7BitEncodedMultiArray(bytes, ref index, values.Cast>(), arrCount, valuesCount); } public static void Write7BitEncodedMultiArray(Il2CppStructArray bytes, ref int index, IEnumerable> values, int arrCount, int valuesCount) { Write7BitEncodedArray(bytes, ref index, values.SelectMany((IEnumerable v) => v.Prepend(0u)).Skip(1), valuesCount + arrCount - 1); } public static Memory[] Read7BitEncodedMultiLongArray(Il2CppStructArray bytes, ref int index) { long[] array = Read7BitEncodedLongArray(bytes, ref index); Memory[] array2 = new Memory[1 + array.Count((long i) => i == 0)]; int num = 0; int num2 = 0; for (int num3 = 0; num3 < array.Length; num3++) { if (array[num3] == 0L) { array2[num++] = new Memory(array, num2, num3 - num2); num2 = num3 + 1; } } array2[num] = new Memory(array, num2, array.Length - num2); return array2; } public static Memory[] Read7BitEncodedMultiULongArray(Il2CppStructArray bytes, ref int index) { ulong[] array = Read7BitEncodedULongArray(bytes, ref index); Memory[] array2 = new Memory[1 + array.Count((ulong i) => i == 0)]; int num = 0; int num2 = 0; for (int num3 = 0; num3 < array.Length; num3++) { if (array[num3] == 0L) { array2[num++] = new Memory(array, num2, num3 - num2); num2 = num3 + 1; } } array2[num] = new Memory(array, num2, array.Length - num2); return array2; } public static Memory[] Read7BitEncodedMultiIntArray(Il2CppStructArray bytes, ref int index) { int[] array = Read7BitEncodedIntArray(bytes, ref index); Memory[] array2 = new Memory[1 + array.Count((int i) => i == 0)]; int num = 0; int num2 = 0; for (int num3 = 0; num3 < array.Length; num3++) { if (array[num3] == 0) { array2[num++] = new Memory(array, num2, num3 - num2); num2 = num3 + 1; } } array2[num] = new Memory(array, num2, array.Length - num2); return array2; } public static Memory[] Read7BitEncodedMultiUIntArray(Il2CppStructArray bytes, ref int index) { uint[] array = Read7BitEncodedUIntArray(bytes, ref index); Memory[] array2 = new Memory[1 + array.Count((uint i) => i == 0)]; int num = 0; int num2 = 0; for (int num3 = 0; num3 < array.Length; num3++) { if (array[num3] == 0) { array2[num++] = new Memory(array, num2, num3 - num2); num2 = num3 + 1; } } array2[num] = new Memory(array, num2, array.Length - num2); return array2; } public static int CalcStringArraySize(ICollection strings) { return CalcStringArraySize(strings, strings.Count); } public static int CalcStringArraySize(IEnumerable strings, int arrSize) { return CalcLengthSize(arrSize) + strings.Sum((Func)CalcStringSize); } public static int CalcStringSize(string? value) { return (value?.Length ?? 0) * 2 + 2; } public unsafe static void WriteStringArray(Il2CppStructArray bytes, ref int index, IEnumerable strings) { WriteLength(bytes, ref index, strings.Count()); byte* ptr = (byte*)IntPtr.Add(((Il2CppObjectBase)bytes).Pointer, IntPtr.Size * 4).ToPointer(); foreach (string @string in strings) { @string.AsSpan().CopyTo(new Span(ptr + index, (((Il2CppArrayBase)(object)bytes).Length - index) / 2)); index += 2 * @string.Length; *(short*)(ptr + index) = 0; index += 2; } } public unsafe static void WriteString(Il2CppStructArray bytes, ref int index, string? value) { byte* ptr = (byte*)IntPtr.Add(((Il2CppObjectBase)bytes).Pointer, IntPtr.Size * 4).ToPointer(); if (value == null) { value = string.Empty; } value.AsSpan().CopyTo(new Span(ptr + index, (((Il2CppArrayBase)(object)bytes).Length - index) / 2)); index += 2 * value.Length; *(short*)(ptr + index) = 0; index += 2; } public unsafe static string[] ReadStringArray(Il2CppStructArray bytes, ref int index) { byte* ptr = (byte*)IntPtr.Add(((Il2CppObjectBase)bytes).Pointer, IntPtr.Size * 4).ToPointer(); int num = ReadLength(bytes, ref index); string[] array = new string[num]; for (num = 0; num < array.Length; num++) { int num2 = index; while (*(ushort*)(ptr + index) != 0) { index += 2; } array[num] = new Span(ptr + num2, (index - num2) / 2).ToString(); index += 2; } return array; } public unsafe static string? ReadString(Il2CppStructArray bytes, ref int index) { byte* ptr = (byte*)IntPtr.Add(((Il2CppObjectBase)bytes).Pointer, IntPtr.Size * 4).ToPointer(); int num = index; while (*(ushort*)(ptr + index) != 0) { index += 2; } string result = ((index <= num) ? null : new Span(ptr + num, (index - num) / 2).ToString()); index += 2; return result; } } public static class SetHelpers { public static bool TryIntersect(this IReadOnlySet self, IEnumerable other, out IEnumerable intersection) { intersection = intersectHelper(self, other); return intersection.Any(); static IEnumerable intersectHelper(IReadOnlySet readOnlySet, IEnumerable enumerable) { foreach (T item in enumerable) { if (readOnlySet.Contains(item)) { yield return item; } } } } } public sealed class SimplifiedListConverter : JsonConverter { public override bool CanRead => false; public override bool CanWrite => true; public int MaxPerLine { get; set; } public SimplifiedListConverter(int maxPerLine = 20) { MaxPerLine = maxPerLine; } public override bool CanConvert(Type objectType) { return typeof(IEnumerable).IsAssignableFrom(objectType); } public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer) { //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_0130: Unknown result type (might be due to invalid IL or missing references) if (!(value is IEnumerable source)) { throw new ArgumentException("Expected value to be of type " + typeof(List).FullName + ".", "value"); } List list = source.Chunk(MaxPerLine).ToList(); if (list.Count == 0) { writer.WriteStartArray(); writer.WriteEndArray(); return; } if (list.Count == 1) { writer.WriteStartArray(); Formatting formatting = writer.Formatting; writer.Formatting = (Formatting)0; if (typeof(T) == typeof(string)) { writer.WriteRaw(" " + string.Join(", ", from i in list.First() select $"\"{i}\"") + " "); } else { writer.WriteRaw(" " + string.Join(", ", from i in list.First() select i?.ToString()) + " "); } writer.WriteEndArray(); writer.Formatting = formatting; return; } List> list2 = ((!(typeof(T) == typeof(string))) ? list.Select((T[] set) => set.Select(delegate(T s) { object obj = s?.ToString(); if (obj == null) { obj = "null"; } return (string)obj; }).ToList()).ToList() : list.Select((T[] set) => set.Select((T s) => $"\"{s}\"").ToList()).ToList()); int max = list2.Max((List set) => set.Max((string s) => s.Length)); writer.WriteStartArray(); foreach (List item in list2) { writer.WriteRawValue(string.Join(", ", item.Select((string s) => s.PadLeft(max)))); } writer.WriteEndArray(); } public override object? ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer) { throw new NotImplementedException("This converter cannot read."); } } } namespace ReTFO.Archipelago.Patches { [HarmonyPatch(typeof(CM_SettingsInputField), "OnBtnPressAnywhere")] public static class AutoEnterFeatureSettings { public static void Prefix(CM_SettingsInputField __instance, ref bool __state) { __state = __instance.m_readingActive; } public static void Postfix(CM_SettingsInputField __instance, bool __state) { if (!__instance.m_readingActive && __state) { __instance.SetNewValue(__instance.m_currentValue); } } } [HarmonyPatch] internal static class CatchNetworkSettingsSubmenuPatch { public static SubMenu? NetworkSettingsSubMenu { get; set; } public static IEnumerable TargetMethods() { yield return AccessTools.Constructor(typeof(SubMenu), new Type[2] { typeof(string), typeof(string) }, false); } public static void Postfix(SubMenu __instance, string identifier) { StateTracker stateTracker = StateTracker.Get(); if (((Feature)stateTracker).Identifier == identifier) { NetworkSettingsSubMenu = __instance; } } } [HarmonyPatch] public static class DynamicItemPatches { private class pRepComparer : Comparer { public override int Compare(pReplicator x, pReplicator y) { //IL_0005: 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) return Comparer.Default.Compare(x.keyPlusOne, y.keyPlusOne); } } private static SortedList s_desiredInventory = new SortedList(new pRepComparer()); private static SortedList> s_delayedUpdates = new SortedList>(new pRepComparer()); [HarmonyPatch(typeof(WardenObjectiveManager), "OnPrepareForRecall")] [HarmonyPrefix] private static void PreRecall() { s_desiredInventory.Clear(); s_delayedUpdates.Clear(); } [HarmonyPatch(typeof(PlayerSessionStatusManager), "OnReceiveInventoryItem")] [HarmonyPrefix] public static bool PreReceiveInventoryItem(pItemData_WithOwner inventoryItem) { //IL_0078: 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) //IL_007e: Unknown result type (might be due to invalid IL or missing references) //IL_0083: 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) if (!SNet.Capture.IsRecalling) { return true; } IReplicator val = default(IReplicator); if (((pReplicator)(ref inventoryItem.data.replicatorRef)).TryGetID(ref val)) { SNet_StateReplicator obj = ((Il2CppObjectBase)val.ReplicatorSupplier).TryCast>(); object obj2; if (obj == null) { obj2 = null; } else { iSNet_StateReplicatorProvider provider = obj.m_provider; obj2 = ((provider != null) ? ((Il2CppObjectBase)provider).TryCast() : null); } LG_PickupItem_Sync val2 = (LG_PickupItem_Sync)obj2; if (!((Object)(object)val2 == (Object)null)) { ReplicatedItemWrapper replicationWrapper = val2.item.ReplicationWrapper; if (replicationWrapper == null || !replicationWrapper.m_aboutToBeDestroyed) { goto IL_0090; } } FeatureLogger.Notice("Preventing null object from entering inventory"); s_desiredInventory[inventoryItem.data.replicatorRef] = inventoryItem.owningPlayer; return false; } goto IL_0090; IL_0090: return true; } [HarmonyPatch(typeof(LG_PickupItem_Sync), "OnStateChange")] [HarmonyPrefix] public static bool PreStateChange(LG_PickupItem_Sync __instance, pPickupItemState oldState, pPickupItemState newState, bool isRecall) { //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_0058: 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_0076: 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_0069: Unknown result type (might be due to invalid IL or missing references) if (!SNet.Capture.IsRecalling) { return true; } if (!((Object)(object)__instance == (Object)null) && !((Object)(object)__instance.item == (Object)null)) { ReplicatedItemWrapper replicationWrapper = __instance.item.ReplicationWrapper; if (replicationWrapper == null || !replicationWrapper.m_aboutToBeDestroyed) { return true; } } FeatureLogger.Notice("Delaying state update for non-null object"); pReplicator replicatorRef = __instance.item.pItemData.replicatorRef; if (s_delayedUpdates.TryGetValue(replicatorRef, out List value)) { value.Add(newState); } else { s_delayedUpdates[replicatorRef] = new List(1) { newState }; } return false; } [HarmonyPatch(typeof(SNet_ReplicationManager_Item), "OnSpawn")] [HarmonyPrefix] public static void PreItemSpawned_SNet(ref pItemSpawnData spawnData, ItemReplicator replicator) { //IL_0022: Unknown result type (might be due to invalid IL or missing references) Item item = replicator.Item; if ((Object)(object)((item != null) ? item.ReplicationWrapper : null) == (Object)null) { return; } replicator.Item.Set_pItemData(spawnData.itemData); IReplicator val = default(IReplicator); if (((pReplicator)(ref spawnData.itemData.replicatorRef)).TryGetID(ref val)) { SNet_StateReplicator val2 = ((Il2CppObjectBase)val.ReplicatorSupplier).Cast>(); LG_PickupItem_Sync component = ((Component)replicator.Item).GetComponent(); component.m_stateReplicator = val2; val2.m_provider = ((Il2CppObjectBase)component).Cast>(); } ItemInLevel val3 = ((Il2CppObjectBase)replicator.Item).TryCast(); if (!((Object)(object)val3 != (Object)null)) { return; } AIG_CourseNode courseNode = default(AIG_CourseNode); if (((pCourseNode)(ref spawnData.courseNode)).TryGet(ref courseNode)) { val3.CourseNode = courseNode; } CarryItemPickup_Core val4 = ((Il2CppObjectBase)replicator.Item).TryCast(); if ((Object)(object)val4 != (Object)null) { AIG_CourseNode spawnNode = default(AIG_CourseNode); if (((pCourseNode)(ref spawnData.itemData.originCourseNode)).TryGet(ref spawnNode)) { val4.SpawnNode = spawnNode; } return; } GenericSmallPickupItem_Core val5 = ((Il2CppObjectBase)replicator.Item).TryCast(); AIG_CourseNode spawnNode2 = default(AIG_CourseNode); if ((Object)(object)val5 != (Object)null && ((pCourseNode)(ref spawnData.itemData.originCourseNode)).TryGet(ref spawnNode2)) { val5.SpawnNode = spawnNode2; } } [HarmonyPatch(typeof(SNet_ReplicationManager_Item), "OnSpawn")] [HarmonyPostfix] public static void PostItemSpawned_SNet(pItemSpawnData spawnData, ItemReplicator replicator) { //IL_000d: 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) //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0018: 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_008f: 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_0064: Unknown result type (might be due to invalid IL or missing references) //IL_0065: 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_006d: Unknown result type (might be due to invalid IL or missing references) //IL_0072: 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_0083: Unknown result type (might be due to invalid IL or missing references) //IL_00b4: Unknown result type (might be due to invalid IL or missing references) //IL_00ba: Unknown result type (might be due to invalid IL or missing references) //IL_00ca: Unknown result type (might be due to invalid IL or missing references) if (SNet.Capture.IsRecalling) { pReplicator replicatorRef = spawnData.itemData.replicatorRef; if (s_desiredInventory.TryGetValue(replicatorRef, out var value)) { LG_PickupItem_Sync component = ((Component)replicator.Item).GetComponent(); ((pReplicator)(ref spawnData.itemData.replicatorRef)).SetID(component.m_stateReplicator.Replicator); PlayerManager.Current.PlayerSessionStatusManager.OnReceiveInventoryItem(new pItemData_WithOwner { owningPlayer = value, data = spawnData.itemData }); s_desiredInventory.Remove(replicatorRef); } if (s_delayedUpdates.TryGetValue(replicatorRef, out List value2)) { LG_PickupItem_Sync val = ((Il2CppObjectBase)((Il2CppObjectBase)replicator.Item).Cast().internalSync).Cast(); val.OnStateChange(val.GetCurrentState(), value2.First(), true); s_delayedUpdates.Remove(replicatorRef); } } } [HarmonyPatch(typeof(ItemReplicationManager), "OnItemSpawn")] [HarmonyPostfix] public static void PostOnItemSpawn(pItemSpawnData spawnData, ItemReplicator replicator) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) int num = ItemReplicationManager.m_callBacks.FindEntry(spawnData.callbackID); if (num != -1 && SNet.IsMaster) { ((Il2CppArrayBase>)(object)ItemReplicationManager.m_callBacks.entries)[num].value.Invoke(((Il2CppObjectBase)replicator.Item).Cast(), (PlayerAgent)null); } } [HarmonyPatch(typeof(WardenObjectiveManager), "OnRecallComplete")] [HarmonyPostfix] public static void PostRecallComplete() { //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_004e: Unknown result type (might be due to invalid IL or missing references) //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_0091: 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) IReplicator val = default(IReplicator); SNet_Player val2 = default(SNet_Player); foreach (KeyValuePair item in s_desiredInventory) { pReplicator key = item.Key; string text = ((!((pReplicator)(ref key)).TryGetID(ref val)) ? $"Replicator {item.Key.keyPlusOne}" : val.name); pPlayer value = item.Value; string text2 = ((!((pPlayer)(ref value)).TryGetPlayer(ref val2)) ? $"{(item.Value.IsBot ? "Bot" : "Player")} {item.Value.lookup}" : val2.NickName); FeatureLogger.Warning("Failed to find dynamic inventory item post-recall: " + text + " for " + text2); } } } [HarmonyPatch(typeof(GlobalPopupMessageManager), "ShowPopup")] public static class GlobalPopupPatch { public static void Prefix(GlobalPopupMessageManager __instance, ref PopupMessage message) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Invalid comparison between Unknown and I4 if ((int)message.PopupType == 1) { message.Header = ((Object)MainMenuGuiLayer.Current.PageRundownNew.m_currentRundownData.StorytellingData.Title).ToString(); } } } [HarmonyPatch] internal static class ModifyRundownMenuPatch { [HarmonyPatch(typeof(CM_PageRundown_New), "Intro_RevealRundown")] [HarmonyAfter(new string[] { "com.dak.MTFO" })] public static class AddResetButtonPatch { public static void Postfix(CM_PageRundown_New __instance) { ((RectTransformComp)__instance.m_matchmakeAllButton).SetVisible(true); __instance.m_matchmakeAllButton.SetText("<#F0F>EXIT ARCHIPELAGO"); __instance.m_matchmakeAllButton.OnBtnPressCallback = new Il2CppAction_int(delegate { StateTracker.Get().Reset(); }); } } [HarmonyPatch] public static class RevealJoinLobbyPatch { public static IEnumerable TargetMethods() { yield return AccessTools.Method(typeof(CM_PageRundown_New), "OnCortexDone", (Type[])null, (Type[])null); yield return AccessTools.Method(typeof(CM_PageRundown_New), "SetPageActive", (Type[])null, (Type[])null); } public static void Postfix(CM_PageRundown_New __instance) { __instance.m_selectionIsRevealed = true; } } public static CM_Item AddButton(CM_PageRundown_New __instance, float offset) { //IL_0000: 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_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0048: 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_0074: 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) //IL_007a: Unknown result type (might be due to invalid IL or missing references) Vector3 val = Vector3.down * offset; CM_Item buttonConnect = __instance.m_buttonConnect; GameObject val2 = Object.Instantiate(((Component)buttonConnect).gameObject); val2.transform.parent = ((Component)buttonConnect).transform.parent; CM_Item component = val2.GetComponent(); ((RectTransformComp)component).RectTrans.anchorMin = ((RectTransformComp)buttonConnect).RectTrans.anchorMin; ((RectTransformComp)component).RectTrans.anchorMax = ((RectTransformComp)buttonConnect).RectTrans.anchorMax; ((Transform)((RectTransformComp)component).RectTrans).position = ((Transform)((RectTransformComp)buttonConnect).RectTrans).position + val; ((RectTransformComp)component).Setup(); component.SetupCMItem(); return component; } [HarmonyPatch(typeof(CM_PageRundown_New), "Setup")] [HarmonyPrefix] public static void PreMenuSetup(CM_PageRundown_New __instance) { //IL_0042: Unknown result type (might be due to invalid IL or missing references) CM_Item buttonConnect = __instance.m_buttonConnect; buttonConnect.SetText("Connect to <#F0F>ARCHIPELAGO"); buttonConnect.OnBtnPressCallback += new Il2CppAction_int(delegate { StateTracker.Get().Connect(); }); float offset = ((RectTransformComp)buttonConnect).GetSize().y + 25f; CM_Item val = AddButton(__instance, offset); val.SetText("Server Settings"); val.OnBtnPressCallback += new Il2CppAction_int(delegate { MainMenuGuiLayer.Current.ChangePage((eCM_MenuPage)10, false); SubMenu? networkSettingsSubMenu = CatchNetworkSettingsSubmenuPatch.NetworkSettingsSubMenu; if (networkSettingsSubMenu != null) { networkSettingsSubMenu.Show(); } }); ((Transform)((RectTransformComp)val).RectTrans).SetParent((Transform)(object)((RectTransformComp)buttonConnect).RectTrans, true); } [HarmonyPatch(typeof(CM_PageRundown_New), "Setup")] [HarmonyPostfix] public static void PostMenuSetup(CM_PageRundown_New __instance) { CM_Item buttonConnect = __instance.m_buttonConnect; foreach (Delegate item in (Il2CppArrayBase)(object)((Delegate)buttonConnect.OnBtnPressCallback).GetInvocationList()) { Object target = item.Target; if (((target != null) ? ((Il2CppObjectBase)target).Pointer : IntPtr.Zero) == ((Il2CppObjectBase)__instance).Pointer) { buttonConnect.OnBtnPressCallback -= ((Il2CppObjectBase)item).Cast>(); } } StateTracker.Get().SetupReplication(); } } [HarmonyPatch] internal static class PostLoadGamedataPatch { [HarmonyTargetMethods] public static IEnumerable TargetMethods() { yield return AccessTools.Method(typeof(GameDataInit), "Initialize", (Type[])null, (Type[])null); yield return AccessTools.Method(typeof(GameDataInit), "ReInitialize", (Type[])null, (Type[])null); } [HarmonyPostfix] public static void Postfix() { if (!Plugin.TryGet(out Plugin plugin)) { throw new NotImplementedException("PostLoadGamedataPatch could not access plugin!"); } plugin.MidManager.InvalidateModdedInstanceData(); GameSetupDataBlock val = GameDataBlockBase.GetAllBlocks()[0]; uint num = val.RundownIdsToLoad[0]; val.RundownIdsToLoad = new List(1); val.RundownIdsToLoad.Add(num); } } [HarmonyPatch] [InjectToIl2Cpp] public static class PrivateFeatureSettingsPatch { [AttributeUsage(AttributeTargets.Property)] public class FSOptionallyPrivate : Attribute { } public interface IOptionallyPrivate { bool IsCurrentlyPrivate { get; } } [InjectToIl2Cpp(typeof(iStringInputReceiver))] private class WrappedCustomStringReceiver : Object { [HideFromIl2Cpp] public iStringInputReceiver WrappedReceiver { get; set; } [HideFromIl2Cpp] public Func? IsCurrentlyPrivate { get; set; } public WrappedCustomStringReceiver(IntPtr ptr) : base(ptr) { } public WrappedCustomStringReceiver(iStringInputReceiver wrappedReceiver, Func? isCurrentlyPrivate) : base(ClassInjector.DerivedConstructorPointer()) { ClassInjector.DerivedConstructorBody((Il2CppObjectBase)(object)this); WrappedReceiver = wrappedReceiver; IsCurrentlyPrivate = isCurrentlyPrivate; } public string GetStringValue(eCellSettingID setting) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) return WrappedReceiver.GetStringValue(setting); } public string SetStringValue(eCellSettingID setting, string value) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) return WrappedReceiver.SetStringValue(setting, value); } } [HarmonyPatch] public static class ModSettings__SettingsCreationHelper__CreateStringSetting__Patch { [HarmonyTargetMethods] public static IEnumerable TargetMethods() { Type typeFromHandle = typeof(ModSettings); Type nestedType = typeFromHandle.GetNestedType("SettingsCreationHelper", AccessTools.all); yield return AccessTools.Method(nestedType, "CreateStringSetting", (Type[])null, (Type[])null); yield return AccessTools.Method(nestedType, "CreateNumberSetting", (Type[])null, (Type[])null); } [HarmonyPostfix] public static void Postfix(FeatureSetting setting) { //IL_00b4: Unknown result type (might be due to invalid IL or missing references) //IL_00be: Expected O, but got Unknown FSOptionallyPrivate customAttribute = setting.Prop.GetCustomAttribute(); if (customAttribute == null) { return; } NumberSetting val = (NumberSetting)(object)((setting is NumberSetting) ? setting : null); if (val == null || !val.HasSlider) { object value = AccessTools.Property(typeof(FeatureSetting), "WrappedInstance").GetValue(setting); IOptionallyPrivate unwrappedInstance = value as IOptionallyPrivate; if (unwrappedInstance == null) { throw new NullReferenceException(); } object cM_SettingsItem = setting.CM_SettingsItem; CM_SettingsItem val2 = ((Il2CppObjectBase)((cM_SettingsItem is Object) ? cM_SettingsItem : null)).Cast(); CM_SettingsInputField component = ((Component)val2.m_inputAlign.GetChild(val2.m_inputAlign.childCount - 1)).GetComponent(); WrappedCustomStringReceiver wrappedCustomStringReceiver = new WrappedCustomStringReceiver(component.m_stringReceiver, () => unwrappedInstance.IsCurrentlyPrivate); component.m_stringReceiver = new iStringInputReceiver(((Il2CppObjectBase)wrappedCustomStringReceiver).Pointer); } } } [HarmonyPatch] public static class CM_SettingsInputField__Patch { [HarmonyPatch(typeof(CM_SettingsInputField), "Update")] [HarmonyPostfix] public static void PostUpdate(CM_SettingsInputField __instance) { //IL_0014: Unknown result type (might be due to invalid IL or missing references) if (__instance.m_readingActive) { return; } WrappedCustomStringReceiver wrappedCustomStringReceiver = ((Il2CppObjectBase)new Object(((Il2CppObjectBase)__instance.m_stringReceiver).Pointer)).TryCast(); if (wrappedCustomStringReceiver != null) { Func? isCurrentlyPrivate = wrappedCustomStringReceiver.IsCurrentlyPrivate; if (isCurrentlyPrivate == null || isCurrentlyPrivate()) { ((TMP_Text)__instance.m_text).SetText(new string('*', ((TMP_Text)__instance.m_text).text.Length), true); } else { ((TMP_Text)__instance.m_text).SetText(__instance.m_currentValue, true); } } } } } [HarmonyPatch] public static class R7E1_460_TerminalPatch { [HarmonyTargetMethods] public static IEnumerable TargetMethods() { yield return AccessTools.Method(typeof(GameDataInit), "Initialize", (Type[])null, (Type[])null); yield return AccessTools.Method(typeof(GameDataInit), "ReInitialize", (Type[])null, (Type[])null); } [HarmonyPostfix] public static void Postfix() { LevelLayoutDataBlock block = GameDataBlockBase.GetBlock(1044535672u); if (!(((GameDataBlockBase)(object)block).name != "R7_E1_Reactor_Startup_L1") && block.ZoneAliasStart == 442 && block.Zones.Count == 21) { block.Zones[18].AllowResourceContainerAllocation = false; } } } [HarmonyPatch] public static class R8D1_422_TerminalPatch { [HarmonyTargetMethods] public static IEnumerable TargetMethods() { yield return AccessTools.Method(typeof(GameDataInit), "Initialize", (Type[])null, (Type[])null); yield return AccessTools.Method(typeof(GameDataInit), "ReInitialize", (Type[])null, (Type[])null); } [HarmonyPostfix] public static void Postfix() { LevelLayoutDataBlock block = GameDataBlockBase.GetBlock(1556013495u); if (!(((GameDataBlockBase)(object)block).name != "R8_D1_Empty_L1") && block.ZoneAliasStart == 420 && block.Zones.Count == 10) { block.Zones[2].MarkerSubSeed = 0; } } } } namespace ReTFO.Archipelago.ModdedInstanceData { public class MidManager { public abstract class Processor { public abstract class CallbackBase : Attribute { public abstract Type DataType { get; } public abstract Type DelegateType { get; } } public abstract void UntypedRegisterCallback(Delegate callback); public abstract void UntypedUnregisterCallback(Delegate callback); } public abstract class Processor : Processor where TData : class { [AttributeUsage(AttributeTargets.Method)] public class Callback : CallbackBase { public override Type DataType => typeof(TData); public override Type DelegateType => typeof(Delegate); } public delegate void Delegate(TData data); public abstract void RegisterCallback(Delegate callback); public override void UntypedRegisterCallback(System.Delegate callback) { if (callback is Delegate callback2) { RegisterCallback(callback2); } else { FeatureLogger.Error("Failed to register callback; callback is of wrong delegate type"); } } public abstract void UnregisterCallback(Delegate callback); public override void UntypedUnregisterCallback(System.Delegate callback) { if (callback is Delegate callback2) { UnregisterCallback(callback2); } else { FeatureLogger.Error("Failed to unregister callback; callback is of wrong delegate type"); } } public abstract void Process(TData data); } [DataContract] private struct JsonKeyValue { [DataMember(Name = "id")] public T ID { get; init; } [DataMember(Name = "value")] public U Value { get; init; } public JsonKeyValue(T id, U value) { ID = id; Value = value; } } [DataContract] private struct FloatingItem { [DataMember(Name = "region")] public RegionID Region { get; init; } [DataMember(Name = "item")] public ItemID Item { get; init; } public FloatingItem(RegionID region, ItemID item) { Region = region; Item = item; } public static FloatingItem Make((RegionID, ItemID) pair) { return new FloatingItem(pair.Item1, pair.Item2); } } [DataContract] private struct JsonTag where TID : struct, ITagID { private List>? m_children; [DataMember(Name = "id")] public TID ID { get; private init; } [DataMember(Name = "name")] public string Name { get; private init; } [DataMember(Name = "description")] public string Description { get; private init; } [DataMember(Name = "other_parents", EmitDefaultValue = false)] public TID[]? OtherParents { get; private init; } [DataMember(Name = "children", EmitDefaultValue = false)] public List>? Children { get { return m_children; } private init { m_children = ((value == null || value.Count == 0) ? null : value); } } public JsonTag(TID id, string name, string description, TID[]? otherParents, List>? children) { m_children = null; ID = id; Name = name; Description = description; OtherParents = otherParents; Children = children; } } private struct ExtendedRegionData { public bool IsReachable; public SortedList? UsedItemCounts; public SortedList? UsedCategoryCounts; public ExtendedRegionData() { IsReachable = false; UsedItemCounts = null; UsedCategoryCounts = null; } public ExtendedRegionData(ExtendedRegionData source) { IsReachable = false; UsedItemCounts = null; UsedCategoryCounts = null; IsReachable = source.IsReachable; UsedItemCounts = source.UsedItemCounts; UsedCategoryCounts = source.UsedCategoryCounts; } } public bool IsProcessed { get; protected set; } public bool IsProcessing { get; protected set; } protected Dictionary m_processorLookup { get; set; } = new Dictionary(); protected Game.Data? m_gameData { get; set; } protected Game.Processor m_gameProcessor { get; set; } = new Game.Processor(); protected Dictionary m_namedHashes { get; set; } = new Dictionary { { "xddj0OpT14z2lmo9dBfHD-BSASJtIvF7kAXMww7F0pM=", null } }; private static Guid DownloadsGUID => new Guid("374DE290-123F-4565-9164-39C4925E467B"); public MidManager() { RegisterProcessor(m_gameProcessor); } public void RegisterProcessor(Processor processor) where TData : class { if (!m_processorLookup.TryAdd(typeof(TData), processor)) { Processor processor2 = m_processorLookup[typeof(TData)]; FeatureLogger.Warning($"Cannot add new processor of type: {processor.GetType().Name}; an existing processor of type {processor2.GetType().Name} is already registered for that data type!"); } } public IReadOnlyDictionary GetAllProcessors() { return m_processorLookup; } public Processor GetProcessor() where TData : class { if (m_processorLookup.TryGetValue(typeof(TData), out Processor value)) { if (value is Processor result) { return result; } throw new InvalidCastException("Cannot converted processor of type " + value.GetType().Name + " to " + typeof(Processor).FullName); } throw new KeyNotFoundException("There is no processor for the requested data type: " + typeof(TData).FullName); } public Processor GetProcessor(Type tData) { if (m_processorLookup.TryGetValue(tData, out Processor value)) { Type type = typeof(Processor<>).MakeGenericType(tData); if (type.IsAssignableFrom(value.GetType())) { return value; } throw new InvalidCastException("Cannot converted processor of type " + value.GetType().FullName + " to " + type.FullName); } throw new KeyNotFoundException("There is no processor for the requested data type: " + tData.FullName); } public void AddNamedHash(string hash, string name) { m_namedHashes[hash] = name; } public void InvalidateModdedInstanceData() { if (IsProcessing) { throw new NotSupportedException("Attempted to invalidate modded instance data while it's processing!"); } IsProcessed = false; m_gameData = null; } public Game.Data GetUnprocessedGameData() { if (m_gameData != null) { return m_gameData; } return m_gameData = new Game.Data(this); } public Game.Data GetProcessedGameData() { ProcessData(); return GetUnprocessedGameData(); } public void ProcessData() { if (IsProcessed) { return; } if (IsProcessing) { throw new NotSupportedException("Process data request received while already processing!"); } FeatureLogger.Notice("Beginning MID generation"); IsProcessing = true; Game.Data unprocessedGameData = GetUnprocessedGameData(); Event.Processor processor = Event.get_EventProcessor(unprocessedGameData); m_gameProcessor.Process(unprocessedGameData); unprocessedGameData.CleanUp(); FeatureLogger.Notice("Checking for winability"); if (DoGraphTraversal(unprocessedGameData, doProcessing: true)) { FeatureLogger.Success("Game is beatable!"); } else { FeatureLogger.Fail("Game is not beatable!"); } using SHA256 sHA = SHA256.Create(); byte[] array = new byte[1]; IEnumerable enumerable = Enumerable.Empty().Concat(from r in unprocessedGameData.Regions.GetAllEntries() select r.Value.Name).Concat(from r in unprocessedGameData.Locations.GetAllEntries() select r.Value.Name) .Concat(from r in unprocessedGameData.Items.GetAllEntries() select r.Value.Name) .Concat(from p in unprocessedGameData.GetAllPaths() select p.Value.Name ?? "null"); foreach (string item in enumerable) { byte[] bytes = Encoding.UTF8.GetBytes(item); sHA.TransformBlock(bytes, 0, bytes.Length, null, 0); sHA.TransformBlock(array, 0, array.Length, null, 0); } sHA.TransformFinalBlock(array, 0, 0); string text = Convert.ToBase64String(sHA.Hash).Replace('/', '_').Replace('+', '-'); if (m_namedHashes.TryGetValue(text, out string value)) { unprocessedGameData.Name = value; } else { unprocessedGameData.Name = text.Substring(0, 10); } unprocessedGameData.IsComplete = true; IsProcessing = false; IsProcessed = true; FeatureLogger.Notice("MID generation completed!"); FeatureLogger.Notice("World Hash: " + text); if (unprocessedGameData.Name == null) { FeatureLogger.Notice("World is Vanilla"); } else { FeatureLogger.Notice("World Name: " + unprocessedGameData.Name); } GameDataBlockBase.FileDirty = true; GameDataBlockBase.FileDirty = true; GameDataBlockBase.FileDirty = true; GameDataBlockBase.FileDirty = true; GameDataBlockBase.FileDirty = true; unprocessedGameData.CleanUp(); } [DllImport("shell32", CharSet = CharSet.Unicode, ExactSpelling = true, PreserveSig = false)] private static extern string SHGetKnownFolderPath([MarshalAs(UnmanagedType.LPStruct)] Guid rfid, uint dwFlags, nint hToken = 0); private static JsonKeyValue MakeJsonKeyValue(KeyValuePair source) { return new JsonKeyValue(source.Key, source.Value); } public void ExportMidData(string? directory = null) { //IL_0162: Unknown result type (might be due to invalid IL or missing references) //IL_0167: Unknown result type (might be due to invalid IL or missing references) //IL_016f: Expected O, but got Unknown //IL_0175: Unknown result type (might be due to invalid IL or missing references) //IL_017f: Expected O, but got Unknown Game.Data processedGameData = GetProcessedGameData(); if (directory == null) { directory = SHGetKnownFolderPath(DownloadsGUID, 0u); } string text = System.IO.Path.Combine(directory, (processedGameData.Name == null) ? "GTFO.ini" : ("GTFO-" + processedGameData.Name + ".ini")); DoGraphTraversal(processedGameData, doProcessing: true, logDebugInfo: false); var anon = new { name = processedGameData.Name, version = Version.Parse("0.0.5"), regions = processedGameData.Regions.GetAllEntries().Select(MakeJsonKeyValue), locations = processedGameData.Locations.GetAllEntries().Select(MakeJsonKeyValue), items = processedGameData.Items.GetAllEntries().Select(MakeJsonKeyValue), paths = processedGameData.GetAllPaths().Select(MakeJsonKeyValue), floating_items = processedGameData.GetAllFloatingItems().Select(FloatingItem.Make), options = processedGameData.GetAllOptions().Select(MakeJsonKeyValue) }; JsonSerializerSettings val = new JsonSerializerSettings { Formatting = (Formatting)1 }; val.Converters.Add((JsonConverter)new StringEnumConverter()); val.Converters.Add((JsonConverter)(object)new SimplifiedListConverter()); val.Converters.Add((JsonConverter)(object)new SimplifiedListConverter(15)); val.Converters.Add((JsonConverter)(object)new SimplifiedListConverter(15)); val.Converters.Add((JsonConverter)(object)new IdConverter()); Type[] targetTypes = new Type[10] { typeof(JsonKeyValue.TagEntry>), typeof(JsonKeyValue.TagEntry>), typeof(JsonKeyValue.TagEntry>), typeof(JsonKeyValue), typeof(JsonKeyValue), typeof(TagStorage.TagEntry), typeof(TagStorage.TagEntry), typeof(TagStorage.TagEntry), typeof(Location), typeof(Item) }; Type[] inlinedTypes = new Type[11] { typeof(TagStorage.TagEntry), typeof(TagStorage.TagEntry), typeof(TagStorage.TagEntry), typeof(TagDefinition), typeof(TagDefinition), typeof(TagDefinition), typeof(ReTFO.Archipelago.ModdedInstanceData.Model.Path), typeof(OptionBase), typeof(Region), typeof(ItemData), typeof(LocationData) }; val.Converters.Add((JsonConverter)(object)new InlineConverter(targetTypes, inlinedTypes)); string contents = JsonConvert.SerializeObject((object)anon, val); File.WriteAllText(text, contents); FeatureLogger.Success("MID data saved to: " + text); } public void ExportTagsToCSV(string? filename = null) { if (filename == null) { filename = System.IO.Path.Combine(SHGetKnownFolderPath(DownloadsGUID, 0u), "gtfoTags.csv"); } Game.Data processedGameData = GetProcessedGameData(); IEnumerable contents = Enumerable.Repeat("\"ID\",\"NAME\",\"DESCRIPTION\",\"PARENT\",\"OTHER_PARENTS\"", 1).Concat(processedGameData.Regions.GetAllEntries().Select(FormatEntry)).Concat(processedGameData.Locations.GetAllEntries().Select(FormatEntry)) .Concat(processedGameData.Items.GetAllEntries().Select(FormatEntry)); File.WriteAllLines(filename, contents); FeatureLogger.Success("Tags saved to: " + filename); static string FormatEntry(KeyValuePair.TagEntry> entry) where TID : struct, ITagID { return $"\"{entry.Key.ToString()}\",\"{entry.Value.Name}\",\"{entry.Value.Definition.Description}\",\"{entry.Value.Definition.Parent.ToString()}\",\"{((entry.Value.Definition.OtherParents == null) ? "" : string.Join(", ", entry.Value.Definition.OtherParents.Select((TID p) => p.ToString())))}\""; } } public void ExportTagsToJSON(string? filename = null) { //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_0072: Expected O, but got Unknown if (filename == null) { filename = System.IO.Path.Combine(SHGetKnownFolderPath(DownloadsGUID, 0u), "gtfoTags.json"); } Game.Data processedGameData = GetProcessedGameData(); var anon = new { Regions = MakeJsonList(processedGameData.Regions.GetAllEntries()), Locations = MakeJsonList(processedGameData.Locations.GetAllEntries()), Items = MakeJsonList(processedGameData.Items.GetAllEntries()) }; JsonSerializerSettings val = new JsonSerializerSettings { Formatting = (Formatting)1 }; val.Converters.Add((JsonConverter)(object)new IdConverter()); string contents = JsonConvert.SerializeObject((object)anon, val); File.WriteAllText(filename, contents); FeatureLogger.Success("Tags saved to: " + filename); static List> MakeJsonList(IReadOnlyDictionary.TagEntry> storage) where TID : struct, ITagID { Dictionary> tagsByParent = new Dictionary>(); foreach (KeyValuePair.TagEntry> item in storage) { foreach (TID allParent in item.Value.Definition.AllParents) { if (tagsByParent.TryGetValue(allParent, out List value)) { value.Add(item.Key); } else { tagsByParent.Add(allParent, new List { item.Key }); } } } return MakeJsonRecursive(new TID()); List> MakeJsonRecursive(TID parentTag) { IEnumerable valueOrDefault = tagsByParent.GetValueOrDefault(parentTag, null); return (from id in valueOrDefault ?? Enumerable.Empty() select KeyValuePair.Create(id, storage[id]) into t select new JsonTag(t.Key, t.Value.Name, t.Value.Definition.Description, (t.Value.Definition.OtherParents == null) ? null : t.Value.Definition.AllParents.Where((TID p) => !p.Equals(parentTag)).ToArray(), MakeJsonRecursive(t.Key))).ToList(); } } } public static bool DoGraphTraversal(Game.Data gameData, bool doProcessing = false, bool logDebugInfo = true) { Dictionary itemCounts = new Dictionary(); Dictionary categoryCounts = new Dictionary(); Dictionary growthCounts = new Dictionary(); List regionData = Enumerable.Repeat(new ExtendedRegionData(), gameData.Regions.GetAllEntries().Count).ToList(); List list = new List(); if (doProcessing) { foreach (KeyValuePair.TagEntry> allEntry in gameData.Regions.GetAllEntries()) { gameData.SetRegionReachable(allEntry.Key, isReachable: false); } } foreach (var allFloatingItem in gameData.GetAllFloatingItems()) { collectItem(allFloatingItem.Item2); } setReachable(gameData.Region_Menu); Region region = gameData.Regions.LookUpValue(gameData.Region_Menu); foreach (Location item2 in region.ConnectedLocations.Select(gameData.Locations.LookUpValueChecked)) { if (item2 != null && item2.OwningRegionIDs.Count == 1 && !item2.ItemID.IsNull) { collectItem(item2.ItemID); } } list.AddRange(region.ConnectedPaths); int num = 1; SortedList usedCatsDict; while (num > 0) { num = 0; for (int i = 0; i < list.Count; i++) { ReTFO.Archipelago.ModdedInstanceData.Model.Path path = gameData.LookUpPath(list[i]); if (getReachable(path.EndingRegion)) { list.RemoveAt(i--); } else { if (!path.Reqs.IsNone && !path.Reqs.All(checkTraversable)) { continue; } setReachable(path.EndingRegion); num++; Region region2 = gameData.Regions.LookUpValue(path.EndingRegion); if (!gameData.IsComplete) { ExtendedRegionData value = new ExtendedRegionData(regionData[path.StartingRegion.AsIndex]); if (path.Reqs.Any((ReTFO.Archipelago.ModdedInstanceData.Model.Path.PathReq r) => r.Type == ReTFO.Archipelago.ModdedInstanceData.Model.Path.eType.ItemConsumed)) { value.UsedItemCounts = ((value.UsedItemCounts == null) ? new SortedList(1) : new SortedList(value.UsedItemCounts)); usedCatsDict = (value.UsedCategoryCounts = ((value.UsedCategoryCounts == null) ? new SortedList() : new SortedList(value.UsedCategoryCounts))); foreach (ReTFO.Archipelago.ModdedInstanceData.Model.Path.PathReq item3 in path.Reqs.Where((ReTFO.Archipelago.ModdedInstanceData.Model.Path.PathReq r) => r.Type == ReTFO.Archipelago.ModdedInstanceData.Model.Path.eType.ItemConsumed)) { value.UsedItemCounts[item3.Target] = usedItemCount(path.StartingRegion, item3.Target) + item3.Count; updateUsedRecursive(item3.Target, item3.Count); } } regionData[path.EndingRegion.AsIndex] = value; foreach (ReTFO.Archipelago.ModdedInstanceData.Model.Path.PathReq item4 in path.Reqs.Where((ReTFO.Archipelago.ModdedInstanceData.Model.Path.PathReq r) => r.Type == ReTFO.Archipelago.ModdedInstanceData.Model.Path.eType.ItemGrowing || r.Type == ReTFO.Archipelago.ModdedInstanceData.Model.Path.eType.CategoryGrowing)) { growthCounts[item4.Target] = growthCounts.GetValueOrDefault(item4.Target, 0u) + item4.Count; } if (doProcessing) { gameData.AddPathReq(list[i], path.Reqs.Select((ReTFO.Archipelago.ModdedInstanceData.Model.Path.PathReq r) => new ReTFO.Archipelago.ModdedInstanceData.Model.Path.PathReq(r.Type, r.Target, getUsedCount(path.StartingRegion, r))).ToArray()); } } foreach (Location item5 in region2.ConnectedLocations.Select(gameData.Locations.LookUpValueChecked)) { if (!item5.OwningRegionIDs.Any((RegionID id2) => !getReachable(id2))) { collectItem(item5.ItemID); } } list.AddRange(region2.ConnectedPaths); list.RemoveAt(i--); } bool checkTraversable(ReTFO.Archipelago.ModdedInstanceData.Model.Path.PathReq req) { uint num3 = getCount(req); uint num4 = getUsedCount(path.StartingRegion, req); if (req.Type == ReTFO.Archipelago.ModdedInstanceData.Model.Path.eType.ItemGrowing || req.Type == ReTFO.Archipelago.ModdedInstanceData.Model.Path.eType.CategoryGrowing) { uint valueOrDefault = growthCounts.GetValueOrDefault(req.Target, 0u); if (num3 < req.Count + num4 + valueOrDefault) { return false; } } else if (num3 < req.Count + num4) { return false; } return true; } } } Dictionary dictionary = (from pair in (from pair in gameData.Locations.GetAllEntries() where pair.Value.Value != null && !pair.Value.Value.ItemID.IsNull select (pair.Value.Value.OwningRegionIDs.AsEnumerable(), ItemID: pair.Value.Value.ItemID)).Concat<(IEnumerable, ItemID)>(from pair in gameData.GetAllFloatingItems() select (Enumerable.Repeat(pair.Item1, 1), pair.Item2)) group pair by pair.Item2 into @group where gameData.Items.IsChild(@group.Key, SharedObjectiveHandler_Tags.get_Item_SectorClears(gameData)) select @group).ToDictionary((IGrouping, ItemID)> group) => group.Key, (IGrouping, ItemID)> group) => (uint)group.Count()); foreach (KeyValuePair item6 in itemCounts.Concat(categoryCounts)) { if (dictionary.TryGetValue(item6.Key, out var value2)) { if (value2 > item6.Value) { dictionary[item6.Key] = value2 - item6.Value; } else { dictionary.Remove(item6.Key); } } } if (dictionary.Count == 0) { return true; } if (!logDebugInfo) { return false; } FeatureLogger.Error("Graph traversal failed for game!"); ConsoleManager.SetConsoleColor(ConsoleColor.Yellow); ConsoleManager.ConsoleStream.WriteLine("\n Missing Item" + ((dictionary.Count > 1) ? "s" : "") + " Required for Completion:"); ConsoleManager.SetConsoleColor(ConsoleColor.White); foreach (KeyValuePair item7 in dictionary) { ConsoleManager.ConsoleStream.WriteLine($" - {item7.Value:00}x {gameData.Items.LookUpName(item7.Key)}"); } ConsoleManager.SetConsoleColor(ConsoleColor.Yellow); ConsoleManager.ConsoleStream.WriteLine("\n Regions:"); bool flag = false; foreach (KeyValuePair.TagEntry> allEntry2 in gameData.Regions.GetAllEntries()) { bool flag2 = getReachable(allEntry2.Key); if (flag2) { ConsoleManager.SetConsoleColor(ConsoleColor.Green); } else { ConsoleManager.SetConsoleColor(ConsoleColor.Red); } ConsoleManager.ConsoleStream.WriteLine($" {(flag2 ? "[ Reachable ]" : "[Unreachable]")} [{allEntry2.Key.ID:000}] {allEntry2.Value.Name}"); flag = true; } if (!flag) { ConsoleManager.ConsoleStream.WriteLine("\n NO REGIONS FOUND"); } ConsoleManager.SetConsoleColor(ConsoleColor.Yellow); ConsoleManager.ConsoleStream.WriteLine("\n Blocked paths:"); PathID[] array = new PathID[list.Count]; list.CopyTo(array); Array.Sort(array); flag = false; PathID[] array2 = array; foreach (PathID id in array2) { flag = true; ReTFO.Archipelago.ModdedInstanceData.Model.Path path2 = gameData.LookUpPath(id); ConsoleManager.ConsoleStream.WriteLine(); ConsoleManager.ConsoleStream.WriteLine(" Name: " + (path2.Name ?? "None")); ConsoleManager.SetConsoleColor(ConsoleColor.Green); ConsoleManager.ConsoleStream.WriteLine($" Start: [{path2.StartingRegion.ID:000}] {gameData.Regions.LookUpName(path2.StartingRegion)}"); ConsoleManager.SetConsoleColor(ConsoleColor.Red); ConsoleManager.ConsoleStream.WriteLine($" End: [{path2.EndingRegion.ID:000}] {gameData.Regions.LookUpName(path2.EndingRegion)}"); ConsoleManager.SetConsoleColor(ConsoleColor.Yellow); if (path2.Reqs.IsNone) { ConsoleManager.ConsoleStream.WriteLine(" Reqs: None"); } else { ConsoleManager.ConsoleStream.WriteLine(" Reqs:"); foreach (ReTFO.Archipelago.ModdedInstanceData.Model.Path.PathReq req in path2.Reqs) { ConsoleManager.ConsoleStream.WriteLine($" - {Enum.GetName(req.Type)}: ({getCount(req)}-{getUsedCount(path2.StartingRegion, req)})/{req.Count} {gameData.Items.LookUpName(req.Target)}"); } } bool flag3 = false; ConsoleManager.ConsoleStream.WriteLine("\n Potential unfound items which unblock:"); foreach (KeyValuePair.TagEntry> allEntry3 in gameData.Locations.GetAllEntries()) { KeyValuePair.TagEntry> entry = allEntry3; if (entry.Value.Value == null || entry.Value.Value.ItemID.IsNull || entry.Value.Value.OwningRegionIDs.All(getReachable) || !path2.Reqs.Any(itemMeetsReq)) { continue; } flag3 = true; ConsoleManager.ConsoleStream.WriteLine(); ConsoleManager.ConsoleStream.WriteLine($" Item: [{entry.Value.Value.ItemID.ID}] {gameData.Items.LookUpName(entry.Value.Value.ItemID)}"); ConsoleManager.ConsoleStream.WriteLine($" Loc: [{entry.Key.ID}] {gameData.Locations.LookUpName(entry.Key)}"); ConsoleManager.ConsoleStream.WriteLine(" Regions:"); if (entry.Value.Value.OwningRegionIDs.Count == 0) { ConsoleManager.SetConsoleColor(ConsoleColor.Red); ConsoleManager.ConsoleStream.WriteLine(" LOCATION HAS NO REGIONS AND CANNOT BE DISCOVERED"); } else { foreach (RegionID owningRegionID in entry.Value.Value.OwningRegionIDs) { bool flag4 = getReachable(owningRegionID); if (flag4) { ConsoleManager.SetConsoleColor(ConsoleColor.Green); } else { ConsoleManager.SetConsoleColor(ConsoleColor.Red); } ConsoleManager.ConsoleStream.WriteLine($" {(flag4 ? "[ Reachable ]" : "[Unreachable]")} [{owningRegionID.ID:000}] {gameData.Regions.LookUpName(owningRegionID)}"); } } ConsoleManager.SetConsoleColor(ConsoleColor.Yellow); bool itemMeetsReq(ReTFO.Archipelago.ModdedInstanceData.Model.Path.PathReq req) { return req.Type switch { ReTFO.Archipelago.ModdedInstanceData.Model.Path.eType.Item => req.Target.Equals(entry.Value.Value.ItemID), ReTFO.Archipelago.ModdedInstanceData.Model.Path.eType.ItemConsumed => req.Target.Equals(entry.Value.Value.ItemID), ReTFO.Archipelago.ModdedInstanceData.Model.Path.eType.ItemGrowing => req.Target.Equals(entry.Value.Value.ItemID), ReTFO.Archipelago.ModdedInstanceData.Model.Path.eType.Category => gameData.Items.IsChild(entry.Value.Value.ItemID, req.Target), ReTFO.Archipelago.ModdedInstanceData.Model.Path.eType.CategoryGrowing => gameData.Items.IsChild(entry.Value.Value.ItemID, req.Target), _ => throw new NotSupportedException("Unexpected path req type!"), }; } } if (!flag3) { ConsoleManager.ConsoleStream.WriteLine("\n NO ITEMS FOUND"); } } if (!flag) { ConsoleManager.ConsoleStream.WriteLine("\n NO BLOCKED PATHS FOUND"); } ConsoleManager.ConsoleStream.WriteLine(); return false; uint catsCount(ItemID item) { return categoryCounts.GetValueOrDefault(item, 0u); } void collectItem(ItemID itemID) { if (!itemID.IsNull) { Item item = gameData.Items.LookUpValue(itemID); if (item == null) { FeatureLogger.Error($"Attempted to collect {itemID} during traversal, but this is not an actual item! Item name: {gameData.Items.LookUpName(itemID)}"); } else if (item.RandData.IsProgression) { itemCounts[itemID] = itemCounts.GetValueOrDefault(itemID, 0u) + 1; collectRecursive(itemID); } } } void collectRecursive(ItemID itemID) { if (itemID.IsNull) { return; } categoryCounts[itemID] = categoryCounts.GetValueOrDefault(itemID, 0u) + 1; foreach (ItemID allParent in gameData.Items.LookUpDefinition(itemID).AllParents) { collectRecursive(allParent); } } uint getCount(ReTFO.Archipelago.ModdedInstanceData.Model.Path.PathReq req) { return req.Type switch { ReTFO.Archipelago.ModdedInstanceData.Model.Path.eType.Item => itemCount(req.Target), ReTFO.Archipelago.ModdedInstanceData.Model.Path.eType.ItemConsumed => itemCount(req.Target), ReTFO.Archipelago.ModdedInstanceData.Model.Path.eType.ItemGrowing => itemCount(req.Target), ReTFO.Archipelago.ModdedInstanceData.Model.Path.eType.Category => catsCount(req.Target), ReTFO.Archipelago.ModdedInstanceData.Model.Path.eType.CategoryGrowing => catsCount(req.Target), _ => throw new NotSupportedException($"Unexpected path requirement type: {req.Type}"), }; } bool getReachable(RegionID id2) { if (!doProcessing) { return regionData[id2.AsIndex].IsReachable; } return gameData.Regions.LookUpValue(id2).Reachable; } uint getUsedCount(RegionID region3, ReTFO.Archipelago.ModdedInstanceData.Model.Path.PathReq req) { return req.Type switch { ReTFO.Archipelago.ModdedInstanceData.Model.Path.eType.Item => usedItemCount(region3, req.Target), ReTFO.Archipelago.ModdedInstanceData.Model.Path.eType.ItemConsumed => usedItemCount(region3, req.Target), ReTFO.Archipelago.ModdedInstanceData.Model.Path.eType.ItemGrowing => usedItemCount(region3, req.Target), ReTFO.Archipelago.ModdedInstanceData.Model.Path.eType.Category => usedCatsCount(region3, req.Target), ReTFO.Archipelago.ModdedInstanceData.Model.Path.eType.CategoryGrowing => usedCatsCount(region3, req.Target), _ => throw new NotSupportedException($"Unexpected path requirement type: {req.Type}"), }; } uint itemCount(ItemID item) { return itemCounts.GetValueOrDefault(item, 0u); } void setReachable(RegionID id2) { if (doProcessing) { gameData.SetRegionReachable(id2, isReachable: true); } else { regionData[id2.AsIndex] = new ExtendedRegionData(regionData[id2.AsIndex]) { IsReachable = true }; } } void updateUsedRecursive(ItemID itemID, uint reqCount) { if (itemID.IsNull) { return; } usedCatsDict[itemID] = usedCatsDict.GetValueOrDefault(itemID, 0u) + reqCount; foreach (ItemID allParent2 in gameData.Items.LookUpDefinition(itemID).AllParents) { updateUsedRecursive(allParent2, reqCount); } } uint usedCatsCount(RegionID regionID, ItemID item) { if (!gameData.IsComplete) { return regionData[regionID.AsIndex].UsedCategoryCounts?.GetValueOrDefault(item, 0u) ?? 0; } return 0u; } uint usedItemCount(RegionID regionID, ItemID item) { if (!gameData.IsComplete) { return regionData[regionID.AsIndex].UsedItemCounts?.GetValueOrDefault(item, 0u) ?? 0; } return 0u; } } } } namespace ReTFO.Archipelago.ModdedInstanceData.Processors { public static class Event { private record ScopeData { public List RawEvents { get; init; } public int EventStart { get; set; } public int EventCount { get; set; } public ScopeData(List rawEvents, int eventStart, int eventCount) { RawEvents = rawEvents; EventStart = eventStart; EventCount = eventCount; } } public class Data : Layer.Data, IList, ICollection, IEnumerable, IEnumerable { private readonly ScopeData EventScopeData; private Type? m_eventType; public RegionID Region_Event { get; private init; } protected List RawEvents => EventScopeData.RawEvents; public Type EventType { get { return m_eventType ?? (m_eventType = ((Il2CppArrayBase)(object)((Object)RawEvents).GetIl2CppType().GetGenericArguments())[0]); } init { m_eventType = value; } } public int EventStart { get { return EventScopeData.EventStart; } protected set { EventScopeData.EventStart = value; } } public int EventCount { get { return EventScopeData.EventCount; } protected set { EventScopeData.EventCount = value; } } public string EventName => base.Regions.LookUpName(Region_Event); public IEnumerable Events => from i in Enumerable.Range(EventStart, EventCount) select RawEvents[i]; public int Count => EventCount; public bool IsReadOnly => false; public WardenObjectiveEventData this[int index] { get { if (index < 0 || index >= EventCount) { throw new ArgumentOutOfRangeException("index"); } return RawEvents[EventStart + index]; } set { CheckEntry(value); if (index < 0 || index >= EventCount) { throw new ArgumentOutOfRangeException("index"); } RawEvents[EventStart + index] = value; } } public Data(Layer.Data data, RegionID region, List rawEvents, int eventStart = 0, int eventCount = -1) : base(data) { Region_Event = region; if (base.Regions.LookUpValue(region).RegionData != null) { throw new NotSupportedException("Cannot create new event data wrapping a region which contains data already"); } base.Regions.SetData(region, EventScopeData = new ScopeData(rawEvents, eventStart, (eventCount == -1) ? rawEvents.Count : eventCount)); } public Data(Game.Data data, RegionID region) : base(data, data.Regions.LookUpDefinition(region).Parent) { Region_Event = region; EventScopeData = base.Regions.GetData(region); } public Data(Data other) : base(other) { Region_Event = other.Region_Event; EventScopeData = other.EventScopeData; } private void CheckEntry(WardenObjectiveEventData data) { if (!EventType.IsAssignableFrom(((Object)data).GetIl2CppType())) { throw new ArgumentException("Cannot perform add or modify operation using object of type " + ((Object)data).GetIl2CppType().FullName + " on a list of " + EventType.FullName + "\nConsider using the Event.Data.EventType property to ensure your event data is correctly typed."); } } public int IndexOf(WardenObjectiveEventData item) { return Enumerable.Range(EventStart, EventCount).FirstOrDefault((int i) => RawEvents[i] == item, -1); } public void Insert(int index, WardenObjectiveEventData item) { CheckEntry(item); if (index < 0 || index > EventCount) { throw new ArgumentOutOfRangeException("index"); } RawEvents.Insert(EventStart + index, item); int eventCount = EventCount + 1; EventCount = eventCount; } public void RemoveAt(int index) { if (index < 0 || index >= EventCount) { throw new ArgumentOutOfRangeException("index"); } RawEvents.RemoveAt(EventStart + index); int eventCount = EventCount - 1; EventCount = eventCount; } public void Add(WardenObjectiveEventData item) { CheckEntry(item); RawEvents.Insert(EventStart + EventCount, item); int eventCount = EventCount + 1; EventCount = eventCount; } public void Clear() { RawEvents.RemoveRange(EventStart, EventCount); EventCount = 0; } public bool Contains(WardenObjectiveEventData item) { return Events.Any((WardenObjectiveEventData i) => i == item); } public void CopyTo(WardenObjectiveEventData[] array, int arrayIndex) { for (int i = 0; i < EventCount; i++) { array[arrayIndex + i] = RawEvents[EventStart + i]; } } public bool Remove(WardenObjectiveEventData item) { int num = IndexOf(item); if (num < 0) { return false; } RemoveAt(num); return true; } public IEnumerator GetEnumerator() { return Events.GetEnumerator(); } IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } } public class Wrapper { private readonly Layer.Data layerData; private readonly List events; private int eventStart; private int eventCount; public bool IsDone => eventStart > events.Count; public Wrapper(Layer.Data layerData, List events) { this.layerData = layerData; this.events = events; eventStart = -1; eventCount = 0; Step(); } public Wrapper(Wrapper source) { layerData = source.layerData; events = source.events; eventStart = source.eventStart; eventCount = source.eventCount; } public void Step(bool errorIfHasEvents = false) { //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Invalid comparison between Unknown and I4 if (errorIfHasEvents && eventCount > 0) { FeatureLogger.Error("Performed step for event processing with \"errorIfHasEvents\""); } eventStart += eventCount + 1; eventCount = 0; while (eventStart + eventCount < events.Count && (int)events[eventStart + eventCount].Type != 999) { eventCount++; } } public void Process(RegionID eventRegion, bool extendIfNecessary = false) { //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_0027: Expected O, but got Unknown if (IsDone) { if (!extendIfNecessary) { return; } events.Add(new WardenObjectiveEventData { Type = (eWardenObjectiveEventType)999 }); } Data data = new Data(layerData, eventRegion, events, eventStart, eventCount); get_EventProcessor(layerData).Process(data); eventStart = data.EventStart; eventCount = data.EventCount; Step(); } } [AttributeUsage(AttributeTargets.Method)] public class Callback : MidManager.Processor.Callback { } public class Processor : MidManager.Processor { protected event Delegate? Event; public override void RegisterCallback(Delegate callback) { Event += callback; } public override void UnregisterCallback(Delegate callback) { Event -= callback; } public override void Process(Data data) { this.Event?.Invoke(data); } } [SpecialName] public sealed class $2B8804A94F2EF68DF77A343A46EE5A78 { [SpecialName] public static class $F943E16B16B76A20C49A59C8DF7C8955 { } [ExtensionMarker("$F943E16B16B76A20C49A59C8DF7C8955")] public Processor EventProcessor { [ExtensionMarker("$F943E16B16B76A20C49A59C8DF7C8955")] get { throw new NotSupportedException(); } } } [SpecialName] public sealed class $9DAFA10623A49E693D4D9BEA615A7202 { [SpecialName] public static class $F9136D71CE7F5E8B956EFAA9F642E37E { } [ExtensionMarker("$F9136D71CE7F5E8B956EFAA9F642E37E")] public Wrapper WrapEvents(List events) { throw new NotSupportedException(); } [ExtensionMarker("$F9136D71CE7F5E8B956EFAA9F642E37E")] public Data ProcessEvents(RegionID eventRegion, List events) { throw new NotSupportedException(); } [ExtensionMarker("$F9136D71CE7F5E8B956EFAA9F642E37E")] public Data ProcessEvents(RegionID eventRegion, List events, int eventStart, int eventCount) { throw new NotSupportedException(); } } [SpecialName] public sealed class $E93D81478905A37B27DF6F640623743D { [SpecialName] public static class $0151B882DB6D8E92BCB0A146352EDB96 { } [ExtensionMarker("$0151B882DB6D8E92BCB0A146352EDB96")] public Wrapper WrapOnActivateEvents() { throw new NotSupportedException(); } [ExtensionMarker("$0151B882DB6D8E92BCB0A146352EDB96")] public Wrapper MakeOrWrapOnSolveEvents() { throw new NotSupportedException(); } } public static Processor get_EventProcessor(Game.Data gameData) { return (Processor)gameData.Manager.GetProcessor(); } public static Wrapper WrapEvents(this Layer.Data layerData, List events) { return new Wrapper(layerData, events); } public static Data ProcessEvents(this Layer.Data layerData, RegionID eventRegion, List events) { Data data = new Data(layerData, eventRegion, events); get_EventProcessor(layerData).Process(data); return data; } public static Data ProcessEvents(this Layer.Data layerData, RegionID eventRegion, List events, int eventStart, int eventCount) { Data data = new Data(layerData, eventRegion, events, eventStart, eventCount); get_EventProcessor(layerData).Process(data); return data; } public static Wrapper WrapOnActivateEvents(this Objective.Data objectiveData) { WardenObjectiveDataBlock objective = objectiveData.Objective; return objectiveData.WrapEvents(objective.EventsOnActivate ?? (objective.EventsOnActivate = new List(1))); } public static Wrapper MakeOrWrapOnSolveEvents(this Objective.Data objectiveData) { if (!objectiveData.Objective.OnActivateOnSolveItem) { objectiveData.Objective.OnActivateOnSolveItem = true; objectiveData.Objective.EventsOnActivate?.Clear(); } return objectiveData.WrapOnActivateEvents(); } } public static class Expedition { private record ScopeData { public RundownDataBlock Rundown { get; init; } public eRundownTier ExpeditionTier { get; init; } public int ExpeditionIndex { get; init; } public ScopeData(RundownDataBlock rundown, eRundownTier expeditionTier, int expeditionIndex) { //IL_000e: Unknown result type (might be due to invalid IL or missing references) Rundown = rundown; ExpeditionTier = expeditionTier; ExpeditionIndex = expeditionIndex; } } public class Data : Game.Data { public class Comparer : EqualityComparer { public override bool Equals(Data? x, Data? y) { return x?.Region_Expedition.Equals(y?.Region_Expedition) ?? (y == null); } public override int GetHashCode([DisallowNull] Data obj) { //IL_000c: Unknown result type (might be due to invalid IL or missing references) return (((Il2CppObjectBase)obj.Rundown).Pointer, obj.ExpeditionTier, obj.ExpeditionIndex).GetHashCode(); } } private readonly ScopeData ExpeditionScopeData; public RegionID Region_Expedition { get; private init; } public RundownDataBlock Rundown => ExpeditionScopeData.Rundown; public eRundownTier ExpeditionTier => ExpeditionScopeData.ExpeditionTier; public int ExpeditionIndex => ExpeditionScopeData.ExpeditionIndex; public virtual ExpeditionInTierData Expedition => GetExpeditionFromRundown(Rundown, ExpeditionTier, ExpeditionIndex); public string ExpeditionName => base.Regions.LookUpName(Region_Expedition); public Data(Game.Data data, RundownDataBlock rundown, eRundownTier expeditionTier, int expeditionIndex) : base(data) { //IL_0008: 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_00bb: 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) string text = GetExpeditionFromRundown(rundown, expeditionTier, expeditionIndex).GetShortName(expeditionIndex) ?? ""; Region_Expedition = base.Regions.LookUpOrCreate(data, text, (Game.Data data2) => new TagDefinition("A region for a particular expedition", get_Region_AllExpeditions(data2))); if (!data.Regions.GetDataAllowNull(Region_Expedition, out ExpeditionScopeData)) { data.Regions.SetData(Region_Expedition, ExpeditionScopeData = new ScopeData(rundown, expeditionTier, expeditionIndex)); } else if (((Il2CppObjectBase)Rundown).Pointer != ((Il2CppObjectBase)rundown).Pointer || ExpeditionTier != expeditionTier || ExpeditionIndex != expeditionIndex) { FeatureLogger.Warning("Two expeditions share the same short name: " + text); } } public Data(Game.Data data, RegionID region) : base(data) { Region_Expedition = region; ExpeditionScopeData = data.Regions.GetData(region); } private Data(Game.Data data, RegionID region, ScopeData scope) : base(data) { Region_Expedition = region; ExpeditionScopeData = scope; } public Data(Data other) : base(other) { Region_Expedition = other.Region_Expedition; ExpeditionScopeData = other.ExpeditionScopeData; } public static ExpeditionInTierData GetExpeditionFromRundown(RundownDataBlock rundown, eRundownTier tier, int index) { //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_001c: Expected I4, but got Unknown //IL_0081: Unknown result type (might be due to invalid IL or missing references) return (ExpeditionInTierData)((tier - 1) switch { 0 => rundown.TierA[index], 1 => rundown.TierB[index], 2 => rundown.TierC[index], 3 => rundown.TierD[index], 4 => rundown.TierE[index], _ => throw new NotSupportedException($"Unrecognized expedition tier: {tier}"), }); } public static bool IsRegion(Game.Data data, RegionID region) { ScopeData result; return data.Regions.TryGetData(region, out result); } public static bool TryFromRegion(Game.Data data, RegionID region, [MaybeNullWhen(false)] out Data expedition) { if (data.Regions.TryGetData(region, out ScopeData result)) { expedition = new Data(data, region, result); return true; } expedition = null; return false; } public static Data GetFromCurrentExpedition() { return Plugin.Get().MidManager.GetProcessedGameData().GetCurrentExpeditionData(); } public static bool TryGetFromCurrentExpedition([MaybeNullWhen(false)] out Data result) { return Plugin.Get().MidManager.GetProcessedGameData().TryGetCurrentExpeditionData(out result); } public static Data GetFromExpedition(ExpeditionInTierData expedition) { return Plugin.Get().MidManager.GetProcessedGameData().GetExpeditionData(expedition); } public static bool TryGetFromExpedition(ExpeditionInTierData expedition, [MaybeNullWhen(false)] out Data result) { return Plugin.Get().MidManager.GetProcessedGameData().TryGetExpeditionData(expedition, out result); } } [AttributeUsage(AttributeTargets.Method)] public class Callback : MidManager.Processor.Callback { } public class Processor : MidManager.Processor { protected event Delegate? Event; public override void RegisterCallback(Delegate callback) { Event += callback; } public override void UnregisterCallback(Delegate callback) { Event -= callback; } public override void Process(Data data) { this.Event?.Invoke(data); } public Processor SubscribedTo(MidManager.Processor owner) { owner.RegisterCallback(OnProcessGame); return this; } protected void OnProcessGame(Game.Data data) { //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0168: Unknown result type (might be due to invalid IL or missing references) foreach (var item in ((IEnumerable)GameDataBlockBase.GetAllBlocks()).SelectMany(UnpackExpeditions)) { if (!((GameDataBlockBase)(object)item.Rundown).internalEnabled) { continue; } ExpeditionInTierData expeditionFromRundown = Data.GetExpeditionFromRundown(item.Rundown, item.ExpeditionTier, item.ExpeditionIndex); if (!expeditionFromRundown.Enabled) { continue; } LevelLayoutDataBlock block = GameDataBlockBase.GetBlock(expeditionFromRundown.LevelLayoutData); if (((block == null) ? ((int?)null) : block.Zones?.Count).GetValueOrDefault() != 0) { SortedList sortedList = new SortedList { { "A3", (27u, "Geomorph Tester", "Geo Test - VS") }, { "A5", (27u, "Geomorph Tester", "Geo Test - LF") } }; string shortName = expeditionFromRundown.GetShortName(item.ExpeditionIndex); if (!sortedList.TryGetValue(shortName, out var value) || ((GameDataBlockBase)(object)item.Rundown).persistentID != value.Item1 || !(((GameDataBlockBase)(object)item.Rundown).name == value.Item2) || !(expeditionFromRundown.Descriptive.PublicName == value.Item3)) { expeditionFromRundown.Descriptive.Prefix = shortName; expeditionFromRundown.Descriptive.SkipExpNumberInName = true; get_ExpeditionProcessor(data).Process(new Data(data, item.Rundown, item.ExpeditionTier, item.ExpeditionIndex)); } } } static IEnumerable<(RundownDataBlock Rundown, eRundownTier ExpeditionTier, int ExpeditionIndex)> UnpackExpeditions(RundownDataBlock rundown) { for (int i = 0; i < rundown.TierA.Count; i++) { yield return (Rundown: rundown, ExpeditionTier: (eRundownTier)1, ExpeditionIndex: i); } for (int i = 0; i < rundown.TierB.Count; i++) { yield return (Rundown: rundown, ExpeditionTier: (eRundownTier)2, ExpeditionIndex: i); } for (int i = 0; i < rundown.TierC.Count; i++) { yield return (Rundown: rundown, ExpeditionTier: (eRundownTier)3, ExpeditionIndex: i); } for (int i = 0; i < rundown.TierD.Count; i++) { yield return (Rundown: rundown, ExpeditionTier: (eRundownTier)4, ExpeditionIndex: i); } for (int i = 0; i < rundown.TierE.Count; i++) { yield return (Rundown: rundown, ExpeditionTier: (eRundownTier)5, ExpeditionIndex: i); } } } } private class GetAllExpeditionsEnumerable : IEnumerable, IEnumerable { private class GetAllExpeditionsEnumerator : IEnumerator, IEnumerator, IDisposable { private readonly Game.Data m_data; private IEnumerator m_regions; private Data? m_current; public Data Current => m_current ?? throw new NullReferenceException("GetAllExpeditionsEnumerator was not enumerated correctly!"); object IEnumerator.Current => Current; public GetAllExpeditionsEnumerator(Game.Data data) { m_data = data; m_regions = null; Reset(); } public bool MoveNext() { while (m_regions.MoveNext()) { RegionID current = m_regions.Current; if (Data.TryFromRegion(m_data, current, out Data expedition)) { m_current = expedition; return true; } } m_current = null; return false; } public void Reset() { m_regions = m_data.Regions.GetAllIDs().GetEnumerator(); } public void Dispose() { } } private readonly Game.Data m_data; public GetAllExpeditionsEnumerable(Game.Data data) { m_data = data; } public IEnumerator GetEnumerator() { return new GetAllExpeditionsEnumerator(m_data); } IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } } [SpecialName] public sealed class $2B8804A94F2EF68DF77A343A46EE5A78 { [SpecialName] public static class $55FD246F9BFF39DD56FCB5C25D4DF852 { } [SpecialName] public static class $F943E16B16B76A20C49A59C8DF7C8955 { } [ExtensionMarker("$55FD246F9BFF39DD56FCB5C25D4DF852")] public RegionID Region_AllExpeditions { [ExtensionMarker("$55FD246F9BFF39DD56FCB5C25D4DF852")] get { throw new NotSupportedException(); } } [ExtensionMarker("$F943E16B16B76A20C49A59C8DF7C8955")] public Processor ExpeditionProcessor { [ExtensionMarker("$F943E16B16B76A20C49A59C8DF7C8955")] get { throw new NotSupportedException(); } } [ExtensionMarker("$F943E16B16B76A20C49A59C8DF7C8955")] public bool IsCurrentExpedition(RegionID region) { throw new NotSupportedException(); } [ExtensionMarker("$F943E16B16B76A20C49A59C8DF7C8955")] public bool IsInCurrentExpedition(RegionID region) { throw new NotSupportedException(); } [ExtensionMarker("$F943E16B16B76A20C49A59C8DF7C8955")] public Data GetCurrentExpeditionData() { throw new NotSupportedException(); } [ExtensionMarker("$F943E16B16B76A20C49A59C8DF7C8955")] public bool TryGetCurrentExpeditionData([MaybeNullWhen(false)] out Data result) { throw new NotSupportedException(); } [ExtensionMarker("$F943E16B16B76A20C49A59C8DF7C8955")] public Data GetExpeditionData(ExpeditionInTierData expedition) { throw new NotSupportedException(); } [ExtensionMarker("$F943E16B16B76A20C49A59C8DF7C8955")] public bool TryGetExpeditionData(ExpeditionInTierData expedition, [MaybeNullWhen(false)] out Data result) { throw new NotSupportedException(); } [ExtensionMarker("$F943E16B16B76A20C49A59C8DF7C8955")] public bool TryGetCurrentExpeditionID(out RegionID id) { throw new NotSupportedException(); } [ExtensionMarker("$F943E16B16B76A20C49A59C8DF7C8955")] public bool TryGetExpeditionID(ExpeditionInTierData expedition, out RegionID id) { throw new NotSupportedException(); } [ExtensionMarker("$F943E16B16B76A20C49A59C8DF7C8955")] public IEnumerable GetAllExpeditions() { throw new NotSupportedException(); } } public static RegionID get_Region_AllExpeditions(Game.Data data) { return RegionID.From(data, "All Expeditions", (Game.Data data2) => new TagDefinition("Parent region of all expedition regions", default(RegionID))); } public static Processor get_ExpeditionProcessor(Game.Data gameData) { return (Processor)gameData.Manager.GetProcessor(); } public static bool IsCurrentExpedition(this Game.Data gameData, RegionID region) { if (!gameData.TryGetCurrentExpeditionID(out var id)) { return false; } return region.Equals(id); } public static bool IsInCurrentExpedition(this Game.Data gameData, RegionID region) { if (!gameData.TryGetCurrentExpeditionID(out var id)) { return false; } return gameData.Regions.IsChild(region, id); } public static Data GetCurrentExpeditionData(this Game.Data gameData) { return gameData.GetExpeditionData(RundownManager.ActiveExpedition ?? throw new NullReferenceException("Cannot get current expedition; no expedition is active!")); } public static bool TryGetCurrentExpeditionData(this Game.Data gameData, [MaybeNullWhen(false)] out Data result) { if (RundownManager.ActiveExpedition == null) { result = null; return false; } return gameData.TryGetExpeditionData(RundownManager.ActiveExpedition, out result); } public static Data GetExpeditionData(this Game.Data gameData, ExpeditionInTierData expedition) { if (!gameData.TryGetExpeditionData(expedition, out Data result)) { throw new KeyNotFoundException("Failed to find expedition data from game data. Expedition: " + expedition.Descriptive.Prefix); } return result; } public static bool TryGetExpeditionData(this Game.Data gameData, ExpeditionInTierData expedition, [MaybeNullWhen(false)] out Data result) { if (gameData.TryGetExpeditionID(expedition, out var id)) { result = new Data(gameData, id); return true; } result = null; return false; } public static bool TryGetCurrentExpeditionID(this Game.Data gameData, out RegionID id) { if (RundownManager.ActiveExpedition == null) { id = default(RegionID); return false; } return gameData.TryGetExpeditionID(RundownManager.ActiveExpedition, out id); } public static bool TryGetExpeditionID(this Game.Data gameData, ExpeditionInTierData expedition, out RegionID id) { return gameData.Regions.TryLookUpID(expedition.Descriptive.Prefix, out id); } public static IEnumerable GetAllExpeditions(this Game.Data gameData) { return new GetAllExpeditionsEnumerable(gameData); } } public static class Game { private record ScopeData { public MidManager Manager { get; init; } public bool IsComplete { get; set; } public string? Name { get; set; } public TagStorage RegionStorage { get; init; } = new TagStorage(); public TagStorage LocationStorage { get; init; } = new TagStorage(); public TagStorage ItemStorage { get; init; } = new TagStorage(); public List Paths { get; init; } = new List(); public List<(RegionID, ItemID)> FloatingItems { get; init; } = new List<(RegionID, ItemID)>(); public List Options { get; init; } = new List(); public ScopeData(MidManager manager) { Manager = manager; } } public class Data { public struct RegionStorageView { private readonly Data m_data; public int Count => m_data.RegionStorage.Count; public RegionStorageView(Data data) { m_data = data; } private void RegisterRegion(RegionID id, Region region) { if (m_data.IsComplete) { FeatureLogger.Warning($"Late adding / modifying region: {id} \"{LookUpName(id)}\""); } if (region.ConnectedPaths.Any()) { throw new NotSupportedException($"{id} \"{LookUpName(id)}\" created with a connected path." + "\nAt this time, new regions cannot define connected paths."); } foreach (LocationID connectedLocation in region.ConnectedLocations) { if (!m_data.LocationStorage.ContainsID(connectedLocation)) { throw new NotSupportedException($"{id} \"{LookUpName(id)}\" created with undefined connected location {connectedLocation}." + "\nThe connected locations in a region must be well-defined at all times."); } Location location = m_data.LocationStorage.LookUpValue(connectedLocation); if (location == null) { throw new NotSupportedException($"{id} \"{LookUpName(id)}\" created with null connected location {connectedLocation}." + "\nThe connected locations in a region must be non-null."); } location.AddOwningRegionIDs(id); } } public IEnumerable GetAllIDs() { return m_data.RegionStorage.GetAllIDs(); } public IReadOnlyDictionary.TagEntry> GetAllEntries() { return m_data.RegionStorage.GetAllEntries(); } public IReadOnlyDictionary GetAllValues() { return m_data.RegionStorage.GetAllValues(); } public RegionID Create(string name, TagDefinition definition, Region item = default(Region)) { RegionID regionID = m_data.RegionStorage.Create(name, definition, item); RegisterRegion(regionID, item); return regionID; } public RegionID LookUpOrCreate(string name, Func> definitionFactory, Region item = default(Region)) { TryLookUpOrCreate(out var result, name, definitionFactory, item); return result; } public bool TryLookUpOrCreate(out RegionID result, string name, Func> definitionFactory, Region item = default(Region)) { if (m_data.RegionStorage.TryLookUpOrCreate(out result, name, definitionFactory, item)) { RegisterRegion(result, item); return true; } return false; } public RegionID LookUpOrCreate(string name, Func> definitionFactory, Func valueFactory) { TryLookUpOrCreate(out var result, name, definitionFactory, valueFactory); return result; } public bool TryLookUpOrCreate(out RegionID result, string name, Func> definitionFactory, Func valueFactory) { if (m_data.RegionStorage.TryLookUpOrCreate(out result, name, definitionFactory, valueFactory)) { RegisterRegion(result, m_data.RegionStorage.LookUpValue(result)); return true; } return false; } public RegionID LookUpOrCreate(TData data, string name, Func> definitionFactory, Region item = default(Region)) { TryLookUpOrCreate(out var result, data, name, definitionFactory, item); return result; } public bool TryLookUpOrCreate(out RegionID result, TData data, string name, Func> definitionFactory, Region item = default(Region)) { if (m_data.RegionStorage.TryLookUpOrCreate(out result, data, name, definitionFactory, item)) { RegisterRegion(result, item); return true; } return false; } public RegionID LookUpOrCreate(TData data, string name, Func> definitionFactory, Func valueFactory) where TData : Data { TryLookUpOrCreate(out var result, data, name, definitionFactory, valueFactory); return result; } public bool TryLookUpOrCreate(out RegionID result, TData data, string name, Func> definitionFactory, Func valueFactory) where TData : Data { if (m_data.RegionStorage.TryLookUpOrCreate(out result, data, name, definitionFactory, valueFactory)) { RegisterRegion(result, m_data.RegionStorage.LookUpValue(result)); return true; } return false; } public bool TryLookUpID(string name, out RegionID id) { return m_data.RegionStorage.TryLookUpID(name, out id); } public TagStorage.TagEntry LookUpEntry(RegionID id) { return m_data.RegionStorage.LookUpEntry(id); } public string LookUpName(RegionID id) { return m_data.RegionStorage.LookUpName(id); } public TagDefinition LookUpDefinition(RegionID id) { return m_data.RegionStorage.LookUpDefinition(id); } public Region LookUpValue(RegionID id) { return m_data.RegionStorage.LookUpValue(id); } public void SetData(RegionID id, object? newValue) { Region other = m_data.RegionStorage.LookUpValue(id); if (other.RegionData != null) { FeatureLogger.Warning("Overwriting region data for region: " + LookUpName(id)); } m_data.RegionStorage.SetValue(id, new Region(other) { RegionData = newValue }); } public T GetData(RegionID id) where T : class { return m_data.RegionStorage.LookUpValue(id).GetData(); } public bool GetDataAllowNull(RegionID id, [MaybeNullWhen(false)] out T result) where T : class { return LookUpValue(id).GetDataAllowNull(out result); } public bool TryGetData(RegionID id, [NotNullWhen(true)] out T? result) where T : class { return LookUpValue(id).TryGetData(out result); } public bool ContainsID(RegionID id) { return m_data.RegionStorage.ContainsID(id); } public bool IsChild(RegionID child, RegionID parent) { return m_data.RegionStorage.IsChild(child, parent); } public bool IsChild(RegionID child, IReadOnlyCollection parents) { return m_data.RegionStorage.IsChild(child, parents); } public RegionID[] MakeChain(RegionID id) { return m_data.RegionStorage.MakeChain(id); } public HashSet GetAllParents(IEnumerable ids) { return m_data.RegionStorage.GetAllParents(ids); } } public struct LocationStorageView { private readonly Data m_data; public int Count => m_data.LocationStorage.Count; public LocationStorageView(Data data) { m_data = data; } private void RegisterLocation(LocationID id, Location? location) { if (m_data.IsComplete) { FeatureLogger.Warning($"Late adding / modifying location: {id} \"{LookUpName(id)}\""); } if (location == null) { return; } foreach (RegionID owningRegionID in location.OwningRegionIDs) { if (!m_data.RegionStorage.ContainsID(owningRegionID)) { throw new NotSupportedException($"{id} \"{LookUpName(id)}\" created with undefined owning region {owningRegionID}." + "The owning regions in a location must be well-defined at all times."); } m_data.RegionStorage.SetValue(owningRegionID, m_data.RegionStorage.LookUpValue(owningRegionID).WithAdded(id)); } } public IEnumerable GetAllIDs() { return m_data.LocationStorage.GetAllIDs(); } public IReadOnlyDictionary.TagEntry> GetAllEntries() { return m_data.LocationStorage.GetAllEntries(); } public IReadOnlyDictionary GetAllValues() { return m_data.LocationStorage.GetAllValues(); } public IEnumerable> GetAllValuesNonNull() { return m_data.LocationStorage.GetAllValuesNonNull(); } public LocationID Create(string name, TagDefinition definition, Location? item = null) { LocationID locationID = m_data.LocationStorage.Create(name, definition, item); RegisterLocation(locationID, item); return locationID; } public LocationID Create(string name, TagDefinition definition, RegionList owningRegions, LocationData randData, ItemID itemId = default(ItemID)) { return Create(name, definition, new Location(owningRegions, randData, itemId)); } public LocationID LookUpOrCreate(string name, Func> definitionFactory, Location? item = null) { TryLookUpOrCreate(out var result, name, definitionFactory, item); return result; } public bool TryLookUpOrCreate(out LocationID result, string name, Func> definitionFactory, Location? item = null) { if (m_data.LocationStorage.TryLookUpOrCreate(out result, name, definitionFactory, item)) { RegisterLocation(result, item); return true; } return false; } public LocationID LookUpOrCreate(string name, Func> definitionFactory, Func valueFactory) { TryLookUpOrCreate(out var result, name, definitionFactory, valueFactory); return result; } public bool TryLookUpOrCreate(out LocationID result, string name, Func> definitionFactory, Func valueFactory) { if (m_data.LocationStorage.TryLookUpOrCreate(out result, name, definitionFactory, valueFactory)) { RegisterLocation(result, m_data.LocationStorage.LookUpValue(result)); return true; } return false; } public LocationID LookUpOrCreate(TData data, string name, Func> definitionFactory, Location? item = null) { TryLookUpOrCreate(out var result, data, name, definitionFactory, item); return result; } public bool TryLookUpOrCreate(out LocationID result, TData data, string name, Func> definitionFactory, Location? item = null) { if (m_data.LocationStorage.TryLookUpOrCreate(out result, data, name, definitionFactory, item)) { RegisterLocation(result, item); return true; } return false; } public LocationID LookUpOrCreate(TData data, string name, Func> definitionFactory, Func valueFactory) where TData : Data { TryLookUpOrCreate(out var result, data, name, definitionFactory, valueFactory); return result; } public bool TryLookUpOrCreate(out LocationID result, TData data, string name, Func> definitionFactory, Func valueFactory) where TData : Data { if (m_data.LocationStorage.TryLookUpOrCreate(out result, data, name, definitionFactory, valueFactory)) { RegisterLocation(result, m_data.LocationStorage.LookUpValue(result)); return true; } return false; } public bool TryLookUpID(string name, out LocationID id) { return m_data.LocationStorage.TryLookUpID(name, out id); } public TagStorage.TagEntry LookUpEntry(LocationID id) { return m_data.LocationStorage.LookUpEntry(id); } public string LookUpName(LocationID id) { return m_data.LocationStorage.LookUpName(id); } public TagDefinition LookUpDefinition(LocationID id) { return m_data.LocationStorage.LookUpDefinition(id); } public Location? LookUpValue(LocationID id) { return m_data.LocationStorage.LookUpValue(id); } public Location LookUpValueChecked(LocationID id) { return m_data.LocationStorage.LookUpValueChecked(id); } public void SetValue(LocationID id, Location item) { if (m_data.LocationStorage.LookUpValue(id) != null) { throw new InvalidOperationException("Cannot overwrite location; currently not supported! Location name: " + LookUpName(id)); } if (item == null) { throw new NullReferenceException("Cannot overwrite location with null value; currently not supported! Location name: " + LookUpName(id)); } m_data.LocationStorage.SetValue(id, item); RegisterLocation(id, item); } public void CreateValue(LocationID id, RegionList owningRegions, LocationData randData, ItemID item = default(ItemID)) { SetValue(id, new Location(owningRegions, randData, item)); } public bool ContainsID(LocationID id) { return m_data.LocationStorage.ContainsID(id); } public bool IsChild(LocationID child, LocationID parent) { return m_data.LocationStorage.IsChild(child, parent); } public bool IsChild(LocationID child, IReadOnlyCollection parents) { return m_data.LocationStorage.IsChild(child, parents); } public LocationID[] MakeChain(LocationID id) { return m_data.LocationStorage.MakeChain(id); } public HashSet GetAllParents(IEnumerable ids) { return m_data.LocationStorage.GetAllParents(ids); } } public struct ItemStorageView { private readonly Data m_data; public int Count => m_data.ItemStorage.Count; public ItemStorageView(Data data) { m_data = data; } private void RegisterItem(ItemID id, Item? item) { if (m_data.IsComplete) { FeatureLogger.Warning($"Late adding / modifying item: {id} \"{LookUpName(id)}\""); } } public IEnumerable GetAllIDs() { return m_data.ItemStorage.GetAllIDs(); } public IReadOnlyDictionary.TagEntry> GetAllEntries() { return m_data.ItemStorage.GetAllEntries(); } public IReadOnlyDictionary GetAllValues() { return m_data.ItemStorage.GetAllValues(); } public IEnumerable> GetAllValuesNonNull() { return m_data.ItemStorage.GetAllValuesNonNull(); } public ItemID Create(string name, TagDefinition definition, Item? item = null) { ItemID itemID = m_data.ItemStorage.Create(name, definition, item); RegisterItem(itemID, item); return itemID; } public ItemID LookUpOrCreate(string name, Func> definitionFactory, Item? item = null) { TryLookUpOrCreate(out var result, name, definitionFactory, item); return result; } public bool TryLookUpOrCreate(out ItemID result, string name, Func> definitionFactory, Item? item = null) { if (m_data.ItemStorage.TryLookUpOrCreate(out result, name, definitionFactory, item)) { RegisterItem(result, item); return true; } return false; } public ItemID LookUpOrCreate(string name, Func> definitionFactory, Func valueFactory) { TryLookUpOrCreate(out var result, name, definitionFactory, valueFactory); return result; } public bool TryLookUpOrCreate(out ItemID result, string name, Func> definitionFactory, Func valueFactory) { if (m_data.ItemStorage.TryLookUpOrCreate(out result, name, definitionFactory, valueFactory)) { RegisterItem(result, m_data.ItemStorage.LookUpValue(result)); return true; } return false; } public ItemID LookUpOrCreate(TData data, string name, Func> definitionFactory, Item? item = null) { TryLookUpOrCreate(out var result, data, name, definitionFactory, item); return result; } public bool TryLookUpOrCreate(out ItemID result, TData data, string name, Func> definitionFactory, Item? item = null) { if (m_data.ItemStorage.TryLookUpOrCreate(out result, data, name, definitionFactory, item)) { RegisterItem(result, item); return true; } return false; } public ItemID LookUpOrCreate(TData data, string name, Func> definitionFactory, Func valueFactory) where TData : Data { TryLookUpOrCreate(out var result, data, name, definitionFactory, valueFactory); return result; } public bool TryLookUpOrCreate(out ItemID result, TData data, string name, Func> definitionFactory, Func valueFactory) where TData : Data { if (m_data.ItemStorage.TryLookUpOrCreate(out result, data, name, definitionFactory, valueFactory)) { RegisterItem(result, m_data.ItemStorage.LookUpValue(result)); return true; } return false; } public bool TryLookUpID(string name, out ItemID id) { return m_data.ItemStorage.TryLookUpID(name, out id); } public TagStorage.TagEntry LookUpEntry(ItemID id) { return m_data.ItemStorage.LookUpEntry(id); } public string LookUpName(ItemID id) { return m_data.ItemStorage.LookUpName(id); } public TagDefinition LookUpDefinition(ItemID id) { return m_data.ItemStorage.LookUpDefinition(id); } public Item? LookUpValue(ItemID id) { return m_data.ItemStorage.LookUpValue(id); } public Item LookUpValueChecked(ItemID id) { return m_data.ItemStorage.LookUpValueChecked(id); } public bool ContainsID(ItemID id) { return m_data.ItemStorage.ContainsID(id); } public bool IsChild(ItemID child, ItemID parent) { return m_data.ItemStorage.IsChild(child, parent); } public bool IsChild(ItemID child, IReadOnlyCollection parents) { return m_data.ItemStorage.IsChild(child, parents); } public ItemID[] MakeChain(ItemID id) { return m_data.ItemStorage.MakeChain(id); } public HashSet GetAllParents(IEnumerable ids) { return m_data.ItemStorage.GetAllParents(ids); } } public struct RegionInfo : IEquatable { public RegionID Region; public bool IsBad; public override bool Equals(object? obj) { if (obj is RegionInfo regionInfo) { return Region.Equals(regionInfo); } return false; } public bool Equals(RegionInfo info) { return Region.Equals(info.Region); } public static bool operator ==(RegionInfo left, RegionInfo right) { return left.Equals(right); } public static bool operator !=(RegionInfo left, RegionInfo right) { return !left.Equals(right); } public override int GetHashCode() { return Region.GetHashCode(); } } private readonly ScopeData GameScopeData; public RegionID Region_Menu { get; private init; } public ItemID Item_Empty { get; private init; } public bool IsComplete { get { return GameScopeData.IsComplete; } set { GameScopeData.IsComplete = value; } } public string? Name { get { return GameScopeData.Name; } set { GameScopeData.Name = value; } } public MidManager Manager => GameScopeData.Manager; public RegionStorageView Regions => new RegionStorageView(this); private TagStorage RegionStorage => GameScopeData.RegionStorage; public LocationStorageView Locations => new LocationStorageView(this); public TagStorage LocationStorage => GameScopeData.LocationStorage; public ItemStorageView Items => new ItemStorageView(this); public TagStorage ItemStorage => GameScopeData.ItemStorage; private List Paths => GameScopeData.Paths; private List<(RegionID, ItemID)> FloatingItems => GameScopeData.FloatingItems; private List Options => GameScopeData.Options; public Data(MidManager manager) { GameScopeData = new ScopeData(manager); Region_Menu = Regions.Create("Menu", new TagDefinition("The origin region for GTFO; where the player starts, from which all regions must be reachable", CommonTagsHandler_Tags.get_Region_Always(this)), new Region { RegionData = GameScopeData }); Item_Empty = Items.LookUpOrCreate("Empty", () => new TagDefinition("An item used to balance randomization during fill.", default(ItemID)), () => new Item(new ItemData { IsFiller = true })); } public Data(Data other) { GameScopeData = other.GameScopeData; Region_Menu = other.Region_Menu; Item_Empty = other.Item_Empty; } public void SetRegionReachable(RegionID id, bool isReachable) { RegionStorage.SetValue(id, Regions.LookUpValue(id).WithReachable(isReachable)); } public void SetRegionRandomized(RegionID id, bool isRandomized) { RegionStorage.SetValue(id, Regions.LookUpValue(id).WithRandomized(isRandomized)); } public PathID AddPath(ReTFO.Archipelago.ModdedInstanceData.Model.Path path) { if (IsComplete) { FeatureLogger.Warning("Adding late path: " + (path.Name ?? "NO NAME")); FeatureLogger.Warning(" From: " + Regions.LookUpName(path.StartingRegion)); FeatureLogger.Warning(" To: " + Regions.LookUpName(path.EndingRegion)); } if (!path.Reqs.IsNone && path.Reqs.Any((ReTFO.Archipelago.ModdedInstanceData.Model.Path.PathReq r) => r.Count == 0)) { FeatureLogger.Warning("Added path with at least one requirement which requires 0 items!"); } if (path.StartingRegion.IsNull) { throw new ArgumentNullException("Cannot add path; starting region is null!"); } if (path.EndingRegion.IsNull) { throw new ArgumentNullException("Cannot add path; ending region is null!"); } PathID pathID = new PathID { AsIndex = Paths.Count }; Paths.Add(path); RegionStorage.SetValue(path.StartingRegion, Regions.LookUpValue(path.StartingRegion).WithAdded(pathID)); return pathID; } public IReadOnlyDictionary GetAllPaths() { return new ReadOnlyListDict(Paths); } public bool TryLookUpPath(RegionID start, RegionID end, out ReTFO.Archipelago.ModdedInstanceData.Model.Path path) { path = Regions.LookUpValue(start).ConnectedPaths.Select(LookUpPath).FirstOrDefault((ReTFO.Archipelago.ModdedInstanceData.Model.Path p) => p.EndingRegion.Equals(end)); return !path.IsNull; } public ReTFO.Archipelago.ModdedInstanceData.Model.Path LookUpPath(PathID id) { return Paths[id.AsIndex]; } public void AddPathReq(PathID id, ReTFO.Archipelago.ModdedInstanceData.Model.Path.PathReq newReq) { if (IsComplete) { FeatureLogger.Warning($"Late path req modification: PathID {id.ID}"); } int asIndex = id.AsIndex; Paths[asIndex] = new ReTFO.Archipelago.ModdedInstanceData.Model.Path(Paths[asIndex]) { Reqs = Paths[asIndex].Reqs.WithAdded(newReq) }; } public void AddPathReq(PathID id, params ReTFO.Archipelago.ModdedInstanceData.Model.Path.PathReq[] newReqs) { if (IsComplete) { FeatureLogger.Warning($"Late path req modification: PathID {id.ID}"); } int asIndex = id.AsIndex; Paths[asIndex] = new ReTFO.Archipelago.ModdedInstanceData.Model.Path(Paths[asIndex]) { Reqs = Paths[asIndex].Reqs.WithAdded(newReqs) }; } public void AddFloatingItem(RegionID scope, ItemID item) { FloatingItems.Add((scope, item)); } public IReadOnlyCollection<(RegionID, ItemID)> GetAllFloatingItems() { return FloatingItems; } public OptionID AddOption(OptionBase option) { if (Options.Contains(option)) { throw new ArgumentException("Cannot register duplicate option"); } Options.Add(option); return new OptionID { AsIndex = Options.Count - 1 }; } public IReadOnlyDictionary GetAllOptions() { return new ReadOnlyListDict(Options); } public IEnumerable> UnstuffPlacements(IEnumerable> placements, int neededCount) { if (neededCount == 0) { yield break; } if (!placements.Any()) { FeatureLogger.Error("Failed to unstuff placements: No placements were provided"); yield break; } List> sets = placements.Select((IEnumerable ps) => ps.Distinct().ToHashSet()).ToList(); IEnumerable, HashSet>> enumerable = (from i in Enumerable.Range(0, neededCount) select sets[i % sets.Count]).GroupBy((HashSet s) => s, HashSet.CreateSetComparer()); foreach (IGrouping, HashSet> group in enumerable) { int count = group.Count(); if (count <= 0) { FeatureLogger.Exception(new NotSupportedException("Somehow had 0 placements in placement group!?")); } List list = new List(); foreach (RegionInfo item in group.Key) { if (item.IsBad) { list.Add(item); count--; if (count == 0) { break; } } } foreach (RegionInfo item2 in list) { group.Key.Remove(item2); } foreach (RegionInfo item3 in list) { yield return new List(from info in @group.Key.Append(item3) select info.Region); } while (count-- > 0) { yield return group.Key.Select((RegionInfo info) => info.Region).ToList(); } } } public void CleanUp() { RegionStorage.TrimExcess(); LocationStorage.TrimExcess(); ItemStorage.TrimExcess(); Paths.TrimExcess(); FloatingItems.TrimExcess(); } } [AttributeUsage(AttributeTargets.Method)] public class Callback : MidManager.Processor.Callback { } public class Processor : MidManager.Processor { protected event Delegate? Event; public override void RegisterCallback(Delegate callback) { Event += callback; } public override void UnregisterCallback(Delegate callback) { Event -= callback; } public override void Process(Data data) { this.Event?.Invoke(data); } } [SpecialName] public sealed class $2B8804A94F2EF68DF77A343A46EE5A78 { [SpecialName] public static class $F943E16B16B76A20C49A59C8DF7C8955 { } [ExtensionMarker("$F943E16B16B76A20C49A59C8DF7C8955")] public Processor GameProcessor { [ExtensionMarker("$F943E16B16B76A20C49A59C8DF7C8955")] get { throw new NotSupportedException(); } } } public static Processor get_GameProcessor(Data gameData) { return (Processor)gameData.Manager.GetProcessor(); } } public static class Layer { private record ScopeData { public LayerType LayerType { get; init; } public ScopeData(LayerType layerType) { LayerType = layerType; } } public class Data : Expedition.Data { private readonly ScopeData LayerScopeData; public RegionID Region_Layer { get; private init; } public LayerType LayerType => LayerScopeData.LayerType; public string LayerName => base.Regions.LookUpName(Region_Layer); public virtual LayerData? LayerDatas { get { if (!LayerType.IsMainLayer) { if (!LayerType.IsSecondaryLayer) { if (!LayerType.IsOverloadLayer) { return null; } return Expedition.ThirdLayerData; } return Expedition.SecondaryLayerData; } return Expedition.MainLayerData; } } public virtual BuildLayerFromData? BuildFromData { get { if (!LayerType.IsSecondaryLayer) { if (!LayerType.IsOverloadLayer) { return null; } return Expedition.BuildThirdFrom; } return Expedition.BuildSecondaryFrom; } } public virtual DimensionInExpeditionData? DimensionEntry { get { if (!LayerType.IsReality) { return Expedition.DimensionDatas.FirstOrDefault((DimensionInExpeditionData d) => d.DimensionIndex == LayerType); } return null; } } public virtual DimensionData? DimensionData { get { DimensionInExpeditionData? dimensionEntry = DimensionEntry; DimensionDataBlock block = GameDataBlockBase.GetBlock((dimensionEntry != null) ? dimensionEntry.DimensionData : 0u); if (block == null) { return null; } return block.DimensionData; } } public virtual uint LayoutID { get { if (!LayerType.IsMainLayer) { if (!LayerType.IsSecondaryLayer) { if (!LayerType.IsOverloadLayer) { DimensionData? dimensionData = DimensionData; if (dimensionData == null) { return 0u; } return dimensionData.LevelLayoutData; } return Expedition.ThirdLayout; } return Expedition.SecondaryLayout; } return Expedition.LevelLayoutData; } } public virtual LevelLayoutDataBlock? Layout => GameDataBlockBase.GetBlock(LayoutID); public Data(Expedition.Data data, LayerType layerType) : base(data) { string name = data.ExpeditionName + " (" + layerType.GetName() + ")"; Region_Layer = data.Regions.LookUpOrCreate(data, name, (Expedition.Data data2) => new TagDefinition("A region for a particular layer for an expedition", data2.Region_Expedition)); if (!base.Regions.LookUpValue(Region_Layer).GetDataAllowNull(out LayerScopeData)) { data.Regions.SetData(Region_Layer, LayerScopeData = new ScopeData(layerType)); } } public Data(Game.Data data, RegionID region) : base(data, data.Regions.LookUpDefinition(region).Parent) { Region_Layer = region; LayerScopeData = data.Regions.GetData(region); } public Data(Data other) : base(other) { Region_Layer = other.Region_Layer; LayerScopeData = other.LayerScopeData; } public static Data GetFromLayer(LG_Layer layer) { //IL_000d: 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) Expedition.Data fromCurrentExpedition = ReTFO.Archipelago.ModdedInstanceData.Processors.Expedition.Data.GetFromCurrentExpedition(); return fromCurrentExpedition.GetLayer(new LayerType(layer.m_dimension.DimensionIndex, layer.m_type)); } public static Data GetFromLayerFlattened(LG_Layer layer) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) if ((int)layer.m_dimension.DimensionIndex != 0) { return get_MainLayer(ReTFO.Archipelago.ModdedInstanceData.Processors.Expedition.Data.GetFromCurrentExpedition()); } return GetFromLayer(layer); } public LG_Layer GetLG_Layer() { //IL_0030: 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) if (!ReTFO.Archipelago.ModdedInstanceData.Processors.Expedition.Data.TryGetFromCurrentExpedition(out Expedition.Data result) || !result.Region_Expedition.Equals(base.Region_Expedition)) { throw new NullReferenceException("Cannot fetch LG_Layer; expedition is not loaded!"); } Dimension val = default(Dimension); if (!Dimension.GetDimension((eDimensionIndex)LayerType, ref val)) { throw new NullReferenceException("Failed to fetch layer's dimension from loaded expedition!"); } return val.GetLayer((LG_LayerType)LayerType); } } [AttributeUsage(AttributeTargets.Method)] public class Callback : MidManager.Processor.Callback { } public class Processor : MidManager.Processor { protected event Delegate? Event; public override void RegisterCallback(Delegate callback) { Event += callback; } public override void UnregisterCallback(Delegate callback) { Event -= callback; } public override void Process(Data data) { this.Event?.Invoke(data); } public Processor SubscribedTo(MidManager.Processor owner) { owner.RegisterCallback(OnProcessExpedition); return this; } protected void OnProcessExpedition(Expedition.Data data) { foreach (Data item in get_AllLayers(data)) { Process(item); } } } [SpecialName] public sealed class $2B8804A94F2EF68DF77A343A46EE5A78 { [SpecialName] public static class $F943E16B16B76A20C49A59C8DF7C8955 { } [ExtensionMarker("$F943E16B16B76A20C49A59C8DF7C8955")] public Processor LayerProcessor { [ExtensionMarker("$F943E16B16B76A20C49A59C8DF7C8955")] get { throw new NotSupportedException(); } } } [SpecialName] public sealed class $2833969430CAB23CD70890D67B9ADDD5 { [SpecialName] public static class $BBB780E158DEFBC886C4287C5819176C { } [ExtensionMarker("$BBB780E158DEFBC886C4287C5819176C")] public bool HasMain { [ExtensionMarker("$BBB780E158DEFBC886C4287C5819176C")] get { throw new NotSupportedException(); } } [ExtensionMarker("$BBB780E158DEFBC886C4287C5819176C")] public bool HasSecondary { [ExtensionMarker("$BBB780E158DEFBC886C4287C5819176C")] get { throw new NotSupportedException(); } } [ExtensionMarker("$BBB780E158DEFBC886C4287C5819176C")] public bool HasOverload { [ExtensionMarker("$BBB780E158DEFBC886C4287C5819176C")] get { throw new NotSupportedException(); } } [ExtensionMarker("$BBB780E158DEFBC886C4287C5819176C")] public Data MainLayer { [ExtensionMarker("$BBB780E158DEFBC886C4287C5819176C")] get { throw new NotSupportedException(); } } [ExtensionMarker("$BBB780E158DEFBC886C4287C5819176C")] public IEnumerable RealLayers { [ExtensionMarker("$BBB780E158DEFBC886C4287C5819176C")] get { throw new NotSupportedException(); } } [ExtensionMarker("$BBB780E158DEFBC886C4287C5819176C")] public IEnumerable DimensionLayers { [ExtensionMarker("$BBB780E158DEFBC886C4287C5819176C")] get { throw new NotSupportedException(); } } [ExtensionMarker("$BBB780E158DEFBC886C4287C5819176C")] public IEnumerable AllLayers { [ExtensionMarker("$BBB780E158DEFBC886C4287C5819176C")] get { throw new NotSupportedException(); } } [ExtensionMarker("$BBB780E158DEFBC886C4287C5819176C")] public Data GetLayer(LayerType layerType) { throw new NotSupportedException(); } } public static Processor get_LayerProcessor(Game.Data gameData) { return (Processor)gameData.Manager.GetProcessor(); } public static bool get_HasMain(Expedition.Data expeditionData) { return true; } public static bool get_HasSecondary(Expedition.Data expeditionData) { return expeditionData.Expedition.SecondaryLayerEnabled; } public static bool get_HasOverload(Expedition.Data expeditionData) { return expeditionData.Expedition.ThirdLayerEnabled; } public static Data get_MainLayer(Expedition.Data expeditionData) { return new Data(expeditionData, LayerType.Main); } public static IEnumerable get_RealLayers(Expedition.Data expeditionData) { yield return new Data(expeditionData, LayerType.Main); if (get_HasSecondary(expeditionData)) { yield return new Data(expeditionData, LayerType.Secondary); } if (get_HasOverload(expeditionData)) { yield return new Data(expeditionData, LayerType.Overload); } } public static IEnumerable get_DimensionLayers(Expedition.Data expeditionData) { return from e in expeditionData.Expedition.DimensionDatas where (int)e.DimensionIndex != 22 select new Data(expeditionData, e.DimensionIndex); } public static IEnumerable get_AllLayers(Expedition.Data expeditionData) { return get_RealLayers(expeditionData).Concat(get_DimensionLayers(expeditionData)); } public static Data GetLayer(this Expedition.Data expeditionData, LayerType layerType) { return new Data(expeditionData, layerType); } } public static class Objective { private record ScopeData { public int ObjectiveIndex { get; init; } public ScopeData(int objectiveIndex) { ObjectiveIndex = objectiveIndex; } } public class Data : Layer.Data { private readonly ScopeData ObjectiveScopeData; public RegionID Region_Objective { get; private init; } public int ObjectiveIndex => ObjectiveScopeData.ObjectiveIndex; public string ObjectiveName => base.Regions.LookUpName(Region_Objective); public WardenObjectiveLayerData ObjectiveData { get { if (ObjectiveIndex != 0) { return LayerDatas.ChainedObjectiveData[ObjectiveIndex - 1]; } return LayerDatas.ObjectiveData; } } public virtual WardenObjectiveDataBlock Objective => GameDataBlockBase.GetBlock(ObjectiveData.DataBlockId) ?? throw new NullReferenceException("Failed to find objective datablock for layer: " + base.LayerName); public Data(Layer.Data data, int objectiveIndex) : base(data) { string name = $"{base.LayerName} Objective #{objectiveIndex + 1}"; Region_Objective = base.Regions.LookUpOrCreate(data, name, (Layer.Data data2) => new TagDefinition("A region for a particular objective in a layer", data2.Region_Layer)); if (!base.Regions.GetDataAllowNull(Region_Objective, out ObjectiveScopeData)) { base.Regions.SetData(Region_Objective, ObjectiveScopeData = new ScopeData(objectiveIndex)); } } public Data(Game.Data data, RegionID region) : base(data, data.Regions.LookUpDefinition(region).Parent) { Region_Objective = region; ObjectiveScopeData = base.Regions.GetData(Region_Objective); } public Data(Data other) : base(other) { Region_Objective = other.Region_Objective; ObjectiveScopeData = other.ObjectiveScopeData; } public IWardenObjective GetWardenObjective() { //IL_0006: Unknown result type (might be due to invalid IL or missing references) return WardenObjectiveManager.GetWardenObjectiveBehaviour((LG_LayerType)base.LayerType, ObjectiveIndex); } } [AttributeUsage(AttributeTargets.Method)] public class Callback : MidManager.Processor.Callback { } public class Processor : MidManager.Processor { protected event Delegate? Event; public override void RegisterCallback(Delegate callback) { Event += callback; } public override void UnregisterCallback(Delegate callback) { Event -= callback; } public override void Process(Data data) { this.Event?.Invoke(data); } public Processor SubscribedTo(MidManager.Processor owner) { owner.RegisterCallback(OnProcessLayer); return this; } protected void OnProcessLayer(Layer.Data data) { if (data.LayerDatas == null) { return; } foreach (Data objectiveData in data.GetObjectiveDatas()) { Process(objectiveData); } } } [SpecialName] public sealed class $2B8804A94F2EF68DF77A343A46EE5A78 { [SpecialName] public static class $F943E16B16B76A20C49A59C8DF7C8955 { } [ExtensionMarker("$F943E16B16B76A20C49A59C8DF7C8955")] public Processor ObjectiveProcessor { [ExtensionMarker("$F943E16B16B76A20C49A59C8DF7C8955")] get { throw new NotSupportedException(); } } } [SpecialName] public sealed class $9DAFA10623A49E693D4D9BEA615A7202 { [SpecialName] public static class $F9136D71CE7F5E8B956EFAA9F642E37E { } [ExtensionMarker("$F9136D71CE7F5E8B956EFAA9F642E37E")] public IEnumerable GetObjectiveDatas() { throw new NotSupportedException(); } } public static Processor get_ObjectiveProcessor(Game.Data gameData) { return (Processor)gameData.Manager.GetProcessor(); } public static IEnumerable GetObjectiveDatas(this Layer.Data layerData) { if (layerData.LayerDatas == null) { return Enumerable.Empty(); } return from i in Enumerable.Range(0, 1 + (layerData.LayerDatas.ChainedObjectiveData?.Count ?? 0)) select new Data(layerData, i); } } public static class Terminal { private record ScopeData { public int TerminalIndex { get; init; } public ScopeData(int terminalIndex) { TerminalIndex = terminalIndex; } } public class Data : Zone.Data { private readonly ScopeData TerminalScopeData; public RegionID Region_Terminal { get; private init; } public int TerminalIndex => TerminalScopeData.TerminalIndex; public string TerminalName => base.Regions.LookUpName(Region_Terminal); public bool IsStandardTerminal => TerminalIndex >= 0; public bool IsSpecificTerminal => TerminalIndex < 0; public TerminalPlacementData StandardTerminalData { get { if (IsSpecificTerminal) { throw new ArgumentException("Attempted to retrieve standard terminal data for specific terminal: " + TerminalName); } ExpeditionZoneData? zone = base.Zone; object obj = ((zone != null) ? zone.TerminalPlacements : null); if (obj == null) { DimensionData? dimensionData = DimensionData; obj = ((dimensionData != null) ? dimensionData.StaticTerminalPlacements : null); } List val = (List)obj; if (val == null) { throw new NullReferenceException("Failed to find standard terminal placement list in zone " + base.ZoneName); } if (TerminalIndex < 0 || TerminalIndex >= val.Count) { throw new ArgumentOutOfRangeException($"Terminal {TerminalIndex} does not exist in standard placement list for zone: {base.ZoneName}"); } return val[TerminalIndex]; } } public SpecificTerminalSpawnData SpecificTerminalData { get { if (IsStandardTerminal) { throw new ArgumentException("Attempted to retrieve specific terminal data for specific terminal: " + TerminalName); } ExpeditionZoneData? zone = base.Zone; List val = ((zone != null) ? zone.SpecificTerminalSpawnDatas : null); if (val == null) { throw new NullReferenceException("Failed to find specific terminal placement list in zone " + base.ZoneName); } int num = -1 - TerminalIndex; if (num < 0 || num >= val.Count) { throw new ArgumentOutOfRangeException($"Terminal {TerminalIndex} does not exist in specific placement list for zone: {base.ZoneName}"); } return val[num]; } } public virtual TerminalStartStateData TerminalStartingStateData { get { if (!IsStandardTerminal) { if (!IsSpecificTerminal) { throw new NotImplementedException(); } return SpecificTerminalData.StartingStateData; } return StandardTerminalData.StartingStateData; } } public virtual List TerminalUniqueCommands { get { if (!IsStandardTerminal) { if (!IsSpecificTerminal) { throw new NotImplementedException(); } return SpecificTerminalData.UniqueCommands; } return StandardTerminalData.UniqueCommands; } } public virtual List TerminalLocalLogs { get { if (!IsStandardTerminal) { if (!IsSpecificTerminal) { throw new NotImplementedException(); } return SpecificTerminalData.LocalLogFiles; } return StandardTerminalData.LocalLogFiles; } } public Data(Zone.Data data, int terminalIndex) : base(data) { string name = ((terminalIndex >= 0) ? $"{base.ZoneName} Terminal #{terminalIndex + 1}" : (base.ZoneName + " Terminal (" + data.Zone.SpecificTerminalSpawnDatas[-(terminalIndex + 1)].WorldEventObjectFilter + ")")); Region_Terminal = base.Regions.LookUpOrCreate(data, name, (Zone.Data data2) => new TagDefinition("A region for a particular terminal in a zone", data2.Region_Zone)); if (!base.Regions.GetDataAllowNull(Region_Terminal, out TerminalScopeData)) { base.Regions.SetData(Region_Terminal, TerminalScopeData = new ScopeData(terminalIndex)); } } public Data(Game.Data data, RegionID region) : base(data, data.Regions.LookUpDefinition(region).Parent) { Region_Terminal = region; TerminalScopeData = base.Regions.GetData(Region_Terminal); } public Data(Data other) : base(other) { Region_Terminal = other.Region_Terminal; TerminalScopeData = other.TerminalScopeData; } public static IdentifyingLogHandler.IdentifyTerminalResult FromTerminal(LG_ComputerTerminal terminal) { return IdentifyingLogHandler.RetrieveDataFromLog(terminal); } public LG_ComputerTerminal? GetLG_Terminal() { LG_Zone lG_Zone = GetLG_Zone(); if ((Object)(object)lG_Zone == (Object)null) { return null; } IntPtr test = ((Il2CppObjectBase)TerminalStartingStateData).Pointer; return lG_Zone.TerminalsSpawnedInZone.FirstOrDefault((LG_ComputerTerminal t) => ((Il2CppObjectBase)t.StartStateData).Pointer == test); } } [AttributeUsage(AttributeTargets.Method)] public class Callback : MidManager.Processor.Callback { } public class Processor : MidManager.Processor { protected event Delegate? Event; public override void RegisterCallback(Delegate callback) { Event += callback; } public override void UnregisterCallback(Delegate callback) { Event -= callback; } public override void Process(Data data) { this.Event?.Invoke(data); } public Processor SubscribedTo(MidManager.Processor owner) { owner.RegisterCallback(OnProcessZone); return this; } protected void OnProcessZone(Zone.Data data) { foreach (int item in get_TerminalIndicies(data)) { Process(new Data(data, item)); } } } [SpecialName] public sealed class $9DAFA10623A49E693D4D9BEA615A7202 { [SpecialName] public static class $F9136D71CE7F5E8B956EFAA9F642E37E { } [ExtensionMarker("$F9136D71CE7F5E8B956EFAA9F642E37E")] public Data FindTerminalByPlacement(TerminalZoneSelectionData placement) { throw new NotSupportedException(); } [ExtensionMarker("$F9136D71CE7F5E8B956EFAA9F642E37E")] public IEnumerable> PlacementsToTerminalRegions(List> placements) { throw new NotSupportedException(); } [ExtensionMarker("$F9136D71CE7F5E8B956EFAA9F642E37E")] public IEnumerable> PlacementsToTerminalRegions(List> placements) { throw new NotSupportedException(); } [ExtensionMarker("$F9136D71CE7F5E8B956EFAA9F642E37E")] public IEnumerable> PlacementsToTerminalRegions(IEnumerable> placements) { throw new NotSupportedException(); } [ExtensionMarker("$F9136D71CE7F5E8B956EFAA9F642E37E")] public IEnumerable PlacementsToTerminalRegions(List placements) { throw new NotSupportedException(); } [ExtensionMarker("$F9136D71CE7F5E8B956EFAA9F642E37E")] public IEnumerable PlacementsToTerminalRegions(IEnumerable placements) { throw new NotSupportedException(); } [ExtensionMarker("$F9136D71CE7F5E8B956EFAA9F642E37E")] public IEnumerable PlacementToTerminalRegions(ZonePlacementData placement) { throw new NotSupportedException(); } } [SpecialName] public sealed class $2B8804A94F2EF68DF77A343A46EE5A78 { [SpecialName] public static class $F943E16B16B76A20C49A59C8DF7C8955 { } [ExtensionMarker("$F943E16B16B76A20C49A59C8DF7C8955")] public Processor TerminalProcessor { [ExtensionMarker("$F943E16B16B76A20C49A59C8DF7C8955")] get { throw new NotSupportedException(); } } } [SpecialName] public sealed class $07060F1A014DE32BC9DAE9AB0EFE08B9 { [SpecialName] public static class $B07C7AC0BE7F4EC51D0D0593FF32C3E1 { } [ExtensionMarker("$B07C7AC0BE7F4EC51D0D0593FF32C3E1")] public int StandardTerminalCount { [ExtensionMarker("$B07C7AC0BE7F4EC51D0D0593FF32C3E1")] get { throw new NotSupportedException(); } } [ExtensionMarker("$B07C7AC0BE7F4EC51D0D0593FF32C3E1")] public int SpecificTerminalCount { [ExtensionMarker("$B07C7AC0BE7F4EC51D0D0593FF32C3E1")] get { throw new NotSupportedException(); } } [ExtensionMarker("$B07C7AC0BE7F4EC51D0D0593FF32C3E1")] public IEnumerable TerminalIndicies { [ExtensionMarker("$B07C7AC0BE7F4EC51D0D0593FF32C3E1")] get { throw new NotSupportedException(); } } [ExtensionMarker("$B07C7AC0BE7F4EC51D0D0593FF32C3E1")] public IEnumerable TerminalDatas { [ExtensionMarker("$B07C7AC0BE7F4EC51D0D0593FF32C3E1")] get { throw new NotSupportedException(); } } [ExtensionMarker("$B07C7AC0BE7F4EC51D0D0593FF32C3E1")] public Data GetTerminal(int index) { throw new NotSupportedException(); } } [SpecialName] public sealed class $E93D81478905A37B27DF6F640623743D { [SpecialName] public static class $0151B882DB6D8E92BCB0A146352EDB96 { } [ExtensionMarker("$0151B882DB6D8E92BCB0A146352EDB96")] public IEnumerable> ObjectiveToTerminalRegionSets(int count) { throw new NotSupportedException(); } } public static Data FindTerminalByPlacement(this Layer.Data layerData, TerminalZoneSelectionData placement) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) return new Data(layerData.FindZoneByIndex(placement.LocalIndex), placement.TerminalIndex); } public static IEnumerable> PlacementsToTerminalRegions(this Layer.Data layerData, List> placements) { return placements.Select((List ps) => from p in ps select layerData.FindZoneByIndex(p.LocalIndex).GetTerminal(p.TerminalIndex) into t select new Game.Data.RegionInfo { Region = t.Region_Terminal, IsBad = t.TerminalStartingStateData.PasswordProtected }); } public static IEnumerable> PlacementsToTerminalRegions(this Layer.Data layerData, List> placements) { return layerData.PlacementsToTerminalRegions(placements.Iter>()); } public static IEnumerable> PlacementsToTerminalRegions(this Layer.Data layerData, IEnumerable> placements) { return placements.Select((List ps) => layerData.PlacementsToTerminalRegions(ps)); } public static IEnumerable PlacementsToTerminalRegions(this Layer.Data layerData, List placements) { return layerData.PlacementsToTerminalRegions(placements.Iter()); } public static IEnumerable PlacementsToTerminalRegions(this Layer.Data layerData, IEnumerable placements) { return placements.SelectMany((ZonePlacementData p) => layerData.PlacementToTerminalRegions(p)); } public static IEnumerable PlacementToTerminalRegions(this Layer.Data layerData, ZonePlacementData placement) { return from t in get_TerminalDatas(layerData.FindZoneByPlacement(placement)) select new Game.Data.RegionInfo { Region = t.Region_Terminal, IsBad = t.TerminalStartingStateData.PasswordProtected }; } public static Processor get_TerminalProcessor(Game.Data gameData) { return (Processor)gameData.Manager.GetProcessor(); } public static int get_StandardTerminalCount(Zone.Data zoneData) { if (zoneData.Zone == null) { if (zoneData.DimensionData == null) { throw new NotImplementedException(); } if (!zoneData.DimensionData.ForbidTerminalsInDimension) { return zoneData.DimensionData.StaticTerminalPlacements?.Count ?? 0; } return 0; } if (!zoneData.Zone.ForbidTerminalsInZone) { return zoneData.Zone.TerminalPlacements?.Count ?? 0; } return 0; } public static int get_SpecificTerminalCount(Zone.Data zoneData) { if (zoneData.Zone == null) { if (!zoneData.LayerType.IsDimension) { throw new NotImplementedException(); } return 0; } return zoneData.Zone.SpecificTerminalSpawnDatas?.Count ?? 0; } public static IEnumerable get_TerminalIndicies(Zone.Data zoneData) { return Enumerable.Range(-get_SpecificTerminalCount(zoneData), get_SpecificTerminalCount(zoneData) + get_StandardTerminalCount(zoneData)); } public static IEnumerable get_TerminalDatas(Zone.Data zoneData) { return from i in get_TerminalIndicies(zoneData) select new Data(zoneData, i); } public static Data GetTerminal(this Zone.Data zoneData, int index) { if (index < -get_SpecificTerminalCount(zoneData) || index >= get_StandardTerminalCount(zoneData)) { FeatureLogger.Error($"Terminal index {index} does not exist in zone: {zoneData.ZoneName}"); index = 0; } return new Data(zoneData, index); } public static IEnumerable> ObjectiveToTerminalRegionSets(this Objective.Data objectiveData, int count) { return objectiveData.UnstuffPlacements(objectiveData.PlacementsToTerminalRegions(objectiveData.ObjectiveData.ZonePlacementDatas), count); } } public static class Zone { private record ScopeData { public ExpeditionZoneData? Zone { get; init; } public ScopeData(ExpeditionZoneData? zone) { Zone = zone; } } public class Data : Layer.Data { private readonly ScopeData ZoneScopeData; public RegionID Region_Zone { get; private init; } public ExpeditionZoneData? Zone => ZoneScopeData.Zone; public string ZoneName => base.Regions.LookUpName(Region_Zone); public int ZoneAlias => GetAlias(this, Zone); public string? CustomGeo { get { if (Zone != null) { return Zone.CustomGeomorph; } return DimensionData.DimensionGeomorph; } } public Data(Layer.Data data, ExpeditionZoneData? zone) : base(data) { string name = $"{base.LayerName} ZONE_{GetAlias(this, zone)}"; Region_Zone = base.Regions.LookUpOrCreate(data, name, (Layer.Data data2) => new TagDefinition("A region for a particular zone in a layer", data2.Region_Layer)); if (!base.Regions.LookUpValue(Region_Zone).GetDataAllowNull(out ZoneScopeData)) { base.Regions.SetData(Region_Zone, ZoneScopeData = new ScopeData(zone)); } } public Data(Game.Data data, RegionID region) : base(data, data.Regions.LookUpDefinition(region).Parent) { Region_Zone = region; ZoneScopeData = base.Regions.GetData(Region_Zone); } public Data(Data other) : base(other) { Region_Zone = other.Region_Zone; ZoneScopeData = other.ZoneScopeData; } private static int WithOverride(int alias, int over) { if (over != -1) { return over; } return alias; } private static int GetAlias(Layer.Data layer, ExpeditionZoneData? zone) { //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Expected I4, but got Unknown if (zone == null) { LevelLayoutDataBlock? layout = layer.Layout; int alias = ((layout != null) ? layout.ZoneAliasStart : 0); DimensionData? dimensionData = layer.DimensionData; return WithOverride(alias, (dimensionData != null) ? dimensionData.StaticAliasOverride : 0); } return WithOverride(layer.Layout.ZoneAliasStart + zone.LocalIndex, zone.AliasOverride); } public static Data GetFromZone(LG_Zone zone) { //IL_000e: Unknown result type (might be due to invalid IL or missing references) Layer.Data fromLayer = Layer.Data.GetFromLayer(zone.Layer); return fromLayer.FindZoneByIndex(zone.LocalIndex); } public LG_Zone? GetLG_Zone() { //IL_001a: Unknown result type (might be due to invalid IL or missing references) LG_Layer lG_Layer = GetLG_Layer(); Dictionary zonesByLocalIndex = lG_Layer.m_zonesByLocalIndex; ExpeditionZoneData? zone = Zone; int num = zonesByLocalIndex.FindEntry((eLocalZoneIndex)((zone != null) ? ((int)zone.LocalIndex) : 0)); if (num < 0) { throw new NullReferenceException("Could not fetch LG_Zone: No such zone exists!"); } return ((Il2CppArrayBase>)(object)lG_Layer.m_zonesByLocalIndex.entries)[num].value; } } [AttributeUsage(AttributeTargets.Method)] public class Callback : MidManager.Processor.Callback { } public class Processor : MidManager.Processor { protected event Delegate? Event; public override void RegisterCallback(Delegate callback) { Event += callback; } public override void UnregisterCallback(Delegate callback) { Event -= callback; } public override void Process(Data data) { this.Event?.Invoke(data); } public Processor SubscribedTo(MidManager.Processor owner) { owner.RegisterCallback(OnProcessLayer); return this; } protected void OnProcessLayer(Layer.Data data) { if (data.Layout != null) { Enumerator enumerator = data.Layout.Zones.GetEnumerator(); while (enumerator.MoveNext()) { ExpeditionZoneData current = enumerator.Current; Process(new Data(data, current)); } } else { Process(new Data(data, null)); } } } [SpecialName] public sealed class $2B8804A94F2EF68DF77A343A46EE5A78 { [SpecialName] public static class $F943E16B16B76A20C49A59C8DF7C8955 { } [ExtensionMarker("$F943E16B16B76A20C49A59C8DF7C8955")] public Processor ZoneProcessor { [ExtensionMarker("$F943E16B16B76A20C49A59C8DF7C8955")] get { throw new NotSupportedException(); } } } [SpecialName] public sealed class $2833969430CAB23CD70890D67B9ADDD5 { [SpecialName] public static class $BBB780E158DEFBC886C4287C5819176C { } [ExtensionMarker("$BBB780E158DEFBC886C4287C5819176C")] public Data StartingZone { [ExtensionMarker("$BBB780E158DEFBC886C4287C5819176C")] get { throw new NotSupportedException(); } } [ExtensionMarker("$BBB780E158DEFBC886C4287C5819176C")] public Data FindZoneByEvent(WardenObjectiveEventData ev) { throw new NotSupportedException(); } [ExtensionMarker("$BBB780E158DEFBC886C4287C5819176C")] public Data FindZoneExact(eDimensionIndex dimension, LG_LayerType layer, eLocalZoneIndex zoneIndex) { throw new NotSupportedException(); } [ExtensionMarker("$BBB780E158DEFBC886C4287C5819176C")] public Data FindZoneExact(LayerType layerType, eLocalZoneIndex zoneIndex) { throw new NotSupportedException(); } } [SpecialName] public sealed class $9DAFA10623A49E693D4D9BEA615A7202 { [SpecialName] public static class $F9136D71CE7F5E8B956EFAA9F642E37E { } [ExtensionMarker("$F9136D71CE7F5E8B956EFAA9F642E37E")] public Data FirstZone { [ExtensionMarker("$F9136D71CE7F5E8B956EFAA9F642E37E")] get { throw new NotSupportedException(); } } [ExtensionMarker("$F9136D71CE7F5E8B956EFAA9F642E37E")] public IEnumerable AllZones { [ExtensionMarker("$F9136D71CE7F5E8B956EFAA9F642E37E")] get { throw new NotSupportedException(); } } [ExtensionMarker("$F9136D71CE7F5E8B956EFAA9F642E37E")] public Data FindZoneByPlacement(ZonePlacementData placement) { throw new NotSupportedException(); } [ExtensionMarker("$F9136D71CE7F5E8B956EFAA9F642E37E")] public IEnumerable> PlacementsToZoneRegions(List> placements) { throw new NotSupportedException(); } [ExtensionMarker("$F9136D71CE7F5E8B956EFAA9F642E37E")] public IEnumerable> PlacementsToZoneRegions(IEnumerable> placements) { throw new NotSupportedException(); } [ExtensionMarker("$F9136D71CE7F5E8B956EFAA9F642E37E")] public IEnumerable PlacementsToZoneRegions(List placements) { throw new NotSupportedException(); } [ExtensionMarker("$F9136D71CE7F5E8B956EFAA9F642E37E")] public IEnumerable PlacementsToZoneRegions(IEnumerable placements) { throw new NotSupportedException(); } [ExtensionMarker("$F9136D71CE7F5E8B956EFAA9F642E37E")] public Game.Data.RegionInfo PlacementToZoneRegion(ZonePlacementData placement) { throw new NotSupportedException(); } [ExtensionMarker("$F9136D71CE7F5E8B956EFAA9F642E37E")] public Data FindZoneByIndex(eLocalZoneIndex zoneIndex) { throw new NotSupportedException(); } } [SpecialName] public sealed class $E93D81478905A37B27DF6F640623743D { [SpecialName] public static class $0151B882DB6D8E92BCB0A146352EDB96 { } [ExtensionMarker("$0151B882DB6D8E92BCB0A146352EDB96")] public IEnumerable> ObjectiveToZoneRegionSets(int count) { throw new NotSupportedException(); } } public static Processor get_ZoneProcessor(Game.Data gameData) { return (Processor)gameData.Manager.GetProcessor(); } public static Data get_StartingZone(Expedition.Data expeditionData) { return get_FirstZone(Layer.get_MainLayer(expeditionData)); } public static Data FindZoneByEvent(this Expedition.Data expeditionData, WardenObjectiveEventData ev) { //IL_0002: 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_000e: Unknown result type (might be due to invalid IL or missing references) return expeditionData.FindZoneExact(ev.DimensionIndex, ev.Layer, ev.LocalIndex); } public static Data FindZoneExact(this Expedition.Data expeditionData, eDimensionIndex dimension, LG_LayerType layer, eLocalZoneIndex zoneIndex) { //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_0008: Unknown result type (might be due to invalid IL or missing references) return expeditionData.FindZoneExact(new LayerType(dimension, layer), zoneIndex); } public static Data FindZoneExact(this Expedition.Data expeditionData, LayerType layerType, eLocalZoneIndex zoneIndex) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) return expeditionData.GetLayer(layerType).FindZoneByIndex(zoneIndex); } public static Data get_FirstZone(Layer.Data layerData) { if (layerData.Layout != null) { if ((layerData.Layout.Zones?.Count ?? 0) > 0) { LevelLayoutDataBlock? layout = layerData.Layout; return new Data(layerData, (layout != null) ? layout.Zones[0] : null); } FeatureLogger.Error("Layer has no zones: " + layerData.LayerName); } else if (!layerData.LayerType.IsDimension) { FeatureLogger.Error("Failed to find layout data for layer: " + layerData.LayerName); } return new Data(layerData, null); } public static IEnumerable get_AllZones(Layer.Data layerData) { if (layerData.Layout != null) { return layerData.Layout.Zones.Select((ExpeditionZoneData zone) => new Data(layerData, zone)); } return Enumerable.Repeat(new Data(layerData, null), 1); } public static Data FindZoneByPlacement(this Layer.Data layerData, ZonePlacementData placement) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0019: 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_004f: 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) if (((int)placement.DimensionIndex == 0 && layerData.LayerType.IsReality) || placement.DimensionIndex == layerData.LayerType) { return layerData.FindZoneByIndex(placement.LocalIndex); } return layerData.GetLayer(placement.DimensionIndex).FindZoneByIndex(placement.LocalIndex); } public static IEnumerable> PlacementsToZoneRegions(this Layer.Data layerData, List> placements) { return layerData.PlacementsToZoneRegions(placements.Iter>()); } public static IEnumerable> PlacementsToZoneRegions(this Layer.Data layerData, IEnumerable> placements) { return placements.Select((List ps) => layerData.PlacementsToZoneRegions(ps)); } public static IEnumerable PlacementsToZoneRegions(this Layer.Data layerData, List placements) { return layerData.PlacementsToZoneRegions(placements.Iter()); } public static IEnumerable PlacementsToZoneRegions(this Layer.Data layerData, IEnumerable placements) { return placements.Select((ZonePlacementData p) => layerData.PlacementToZoneRegion(p)); } public static Game.Data.RegionInfo PlacementToZoneRegion(this Layer.Data layerData, ZonePlacementData placement) { //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Invalid comparison between Unknown and I4 Data data = layerData.FindZoneByPlacement(placement); Game.Data.RegionInfo result = new Game.Data.RegionInfo { Region = data.Region_Zone }; ExpeditionZoneData? zone = data.Zone; eProgressionPuzzleType? obj; if (zone == null) { obj = null; } else { ProgressionPuzzleData progressionPuzzleToEnter = zone.ProgressionPuzzleToEnter; obj = ((progressionPuzzleToEnter != null) ? new eProgressionPuzzleType?(progressionPuzzleToEnter.PuzzleType) : ((eProgressionPuzzleType?)null)); } eProgressionPuzzleType? val = obj; result.IsBad = (int)val.GetValueOrDefault() > 0; return result; } public static Data FindZoneByIndex(this Layer.Data layerData, eLocalZoneIndex zoneIndex) { //IL_0007: 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_0016: Unknown result type (might be due to invalid IL or missing references) //IL_0070: 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) if (layerData.Layout == null) { if ((int)zoneIndex != 0) { FeatureLogger.Warning("Attempted to find " + Enum.GetName(zoneIndex) + " in dimension with no layout: " + layerData.LayerName); } return new Data(layerData, null); } ExpeditionZoneData val = layerData.Layout.Zones.FirstOrDefault((ExpeditionZoneData z) => z.LocalIndex == zoneIndex); if (val == null) { FeatureLogger.Error("Failed to find " + Enum.GetName(zoneIndex) + " in layer: " + layerData.LayerName); return get_FirstZone(layerData); } return new Data(layerData, val); } public static IEnumerable> ObjectiveToZoneRegionSets(this Objective.Data objectiveData, int count) { return objectiveData.UnstuffPlacements(objectiveData.PlacementsToZoneRegions(objectiveData.ObjectiveData.ZonePlacementDatas), count); } } } namespace ReTFO.Archipelago.ModdedInstanceData.Model { [DataContract] public class Item { [DataMember(Name = "rand_data")] public ItemData RandData { get; private set; } public Item(ItemData randData) { RandData = randData; } public void UpdateRandomization(bool isWhitelisted, bool isBlacklisted) { RandData = new ItemData(RandData) { IsWhitelisted = isWhitelisted, IsBlacklisted = isBlacklisted }; } public virtual void OnItemObtained(StateTracker stateTracker, LocationID sourceLocationId, PlayerAgent? player, ItemID itemId) { } public virtual void OnItemLost(StateTracker stateTracker, ItemID itemId) { } public virtual void OnStartExpeditionWithItem(StateTracker stateTracker, Expedition.Data data, ItemID itemId) { } public virtual IEnumerable OnRetrieveFromTerminalSystem(StateTracker stateTracker, LG_ComputerTerminal terminal, ItemID itemId) { throw new NotImplementedException(); } } public abstract class ExpeditionItem : Item { public abstract RegionID TargetRegion { get; } public ExpeditionItem(ItemData randData) : base(randData) { } protected bool CheckExpedition(StateTracker stateTracker) { return stateTracker.GameData.IsInCurrentExpedition(TargetRegion); } protected bool CheckExpedition(Expedition.Data data) { return data.Regions.IsChild(TargetRegion, data.Region_Expedition); } public override void OnItemObtained(StateTracker stateTracker, LocationID sourceLocationId, PlayerAgent? player, ItemID itemId) { if (CheckExpedition(stateTracker)) { OnEnteredExpedition(stateTracker, sourceLocationId, player, itemId); } } public override void OnStartExpeditionWithItem(StateTracker stateTracker, Expedition.Data data, ItemID itemId) { if (CheckExpedition(data)) { OnEnteredExpedition(stateTracker, default(LocationID), null, itemId); } } public abstract void OnEnteredExpedition(StateTracker stateTracker, LocationID sourceLocationId, PlayerAgent? player, ItemID itemId); } public abstract class TerminalItem : ExpeditionItem { public TerminalItem(ItemData randData) : base(randData) { } public override void OnEnteredExpedition(StateTracker stateTracker, LocationID sourceLocationId, PlayerAgent? player, ItemID itemId) { stateTracker.AddItemToTerminal(itemId); } } [StructLayout(LayoutKind.Explicit, Size = 4)] [DataContract] public struct ItemID : ITagID, INullable, IIndex, IEquatable, IComparable, IEquatable, IComparable { [FieldOffset(0)] [DataMember(Name = "id")] private readonly uint m_ID; public uint ID { get { return m_ID; } init { m_ID = value; } } public bool IsNull => ID == 0; public int AsIndex { get { return checked((int)ID - 1); } init { ID = (uint)(value + 1); } } public bool Equals(ItemID other) { return ID == other.ID; } public int CompareTo(ItemID other) { return ID.CompareTo(other.ID); } public override string ToString() { return $"ItemID {ID}"; } public static ItemID From(Game.Data data, string name, Func> definitionFactory, Item? item = null) { return data.Items.LookUpOrCreate(name, definitionFactory, item); } public static ItemID From(TData data, string name, Func> definitionFactory, Item? item = null) where TData : Game.Data { return data.Items.LookUpOrCreate(data, name, definitionFactory, item); } } [DataContract] public struct ItemData { [Flags] public enum eType { None = 0, Progression = 1, Useful = 2, Filler = 4, Trap = 8, SkipBalancing = 0x10, Deprioritized = 0x20, RandomLike = 0x40, IsCollectedByDefault = 0x80, IsWhitelisted = 0x100, IsBlacklisted = 0x200 } private readonly eType m_value; [DataMember(Name = "is_progression")] public bool IsProgression { get { return (m_value & eType.Progression) != 0; } init { m_value = (value ? (m_value | eType.Progression) : (m_value & ~eType.Progression)); } } [DataMember(Name = "is_useful")] public bool IsUseful { get { return (m_value & eType.Useful) != 0; } init { m_value = (value ? (m_value | eType.Useful) : (m_value & ~eType.Useful)); } } [DataMember(Name = "is_filler")] public bool IsFiller { get { return (m_value & eType.Filler) != 0; } init { m_value = (value ? (m_value | eType.Filler) : (m_value & ~eType.Filler)); } } [DataMember(Name = "is_trap")] public bool IsTrap { get { return (m_value & eType.Trap) != 0; } init { m_value = (value ? (m_value | eType.Trap) : (m_value & ~eType.Trap)); } } [DataMember(Name = "do_skip_balancing")] public bool DoSkipBalancing { get { return (m_value & eType.SkipBalancing) != 0; } init { m_value = (value ? (m_value | eType.SkipBalancing) : (m_value & ~eType.SkipBalancing)); } } [DataMember(Name = "is_deprioritized")] public bool IsDeprioritized { get { return (m_value & eType.Deprioritized) != 0; } init { m_value = (value ? (m_value | eType.Deprioritized) : (m_value & ~eType.Deprioritized)); } } [DataMember(Name = "is_collected_by_default")] public bool IsCollectedByDefault { get { return (m_value & eType.IsCollectedByDefault) != 0; } init { m_value = (value ? (m_value | eType.IsCollectedByDefault) : (m_value & ~eType.IsCollectedByDefault)); } } [DataMember(Name = "is_randomlike")] public bool IsRandomLike { get { return (m_value & eType.RandomLike) != 0; } init { m_value = (value ? (m_value | eType.RandomLike) : (m_value & ~eType.RandomLike)); } } public bool IsWhitelisted { get { return (m_value & eType.IsWhitelisted) != 0; } init { m_value = (value ? (m_value | eType.IsWhitelisted) : (m_value & ~eType.IsWhitelisted)); } } public bool IsBlacklisted { get { return (m_value & eType.IsBlacklisted) != 0; } init { m_value = (value ? (m_value | eType.IsBlacklisted) : (m_value & ~eType.IsBlacklisted)); } } public bool CanBeRandomized { get { if (IsWhitelisted) { return !IsBlacklisted; } return false; } } public ItemData AsNew => new ItemData(m_value & ~(eType.IsWhitelisted | eType.IsBlacklisted)); public ItemData(eType value = eType.None) { m_value = eType.None; m_value = value; } public ItemData(ItemData source) { m_value = eType.None; m_value = source.m_value; } } public struct LayerType { private int value; public static LayerType Main = (LG_LayerType)0; public static LayerType Secondary = (LG_LayerType)1; public static LayerType Overload = (LG_LayerType)2; public static LayerType Dimension_1 = (eDimensionIndex)1; public static LayerType Dimension_2 = (eDimensionIndex)2; public static LayerType Dimension_3 = (eDimensionIndex)3; public static LayerType Dimension_4 = (eDimensionIndex)4; public static LayerType Dimension_5 = (eDimensionIndex)5; public bool IsReality => !IsDimension; public bool IsMainLayer => this == Main; public bool IsSecondaryLayer => this == Secondary; public bool IsOverloadLayer => this == Overload; public bool IsDimension { get { if (value >= -2) { return value > 0; } return true; } } public LayerType(LG_LayerType layer, eDimensionIndex dimension) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0004: Unknown result type (might be due to invalid IL or missing references) if ((int)dimension == 0) { this = layer; } else { this = dimension; } } public LayerType(eDimensionIndex dimension, LG_LayerType layer) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0004: Unknown result type (might be due to invalid IL or missing references) if ((int)dimension == 0) { this = layer; } else { this = dimension; } } public static implicit operator LayerType(LG_LayerType layerType) { //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unsupported input type for neg. //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Expected I4, but got Unknown return new LayerType { value = 0 - layerType }; } public static implicit operator LG_LayerType(LayerType layerType) { if (layerType.value > 0) { return (LG_LayerType)0; } return (LG_LayerType)(byte)(-layerType.value); } public static implicit operator LayerType(eDimensionIndex dimensionIndex) { //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Expected I4, but got Unknown return new LayerType { value = (int)dimensionIndex }; } public static implicit operator eDimensionIndex(LayerType layerType) { if (layerType.value < 0) { return (eDimensionIndex)0; } return (eDimensionIndex)layerType.value; } public string GetName() { return value switch { 0 => "Main", -1 => "Secondary", -2 => "Overload", _ => $"Dim #{value}", }; } public static bool operator ==(LayerType left, LayerType right) { return left.Equals(right); } public static bool operator !=(LayerType left, LayerType right) { return !left.Equals(right); } public override bool Equals([NotNullWhen(true)] object? obj) { if (obj is LayerType layerType) { return value.Equals(layerType.value); } return false; } public override int GetHashCode() { return value.GetHashCode(); } } [DataContract] public class Location { private RegionID[] m_owningRegionIDs; [DataMember(Name = "owning_regions")] public IReadOnlyList OwningRegionIDs => m_owningRegionIDs; [DataMember(Name = "rand_data")] public LocationData RandData { get; private set; } [DataMember(Name = "item_id")] public ItemID ItemID { get; private set; } public string? ScoutedItemName { get; set; } public string? ScoutedPlayerName { get; set; } public string? ScoutedGameName { get; set; } public Location(RegionList regions, LocationData randData, ItemID item = default(ItemID)) { m_owningRegionIDs = regions; RandData = randData; ItemID = item; } public void AddOwningRegionIDs(params RegionID[] regions) { if (regions.Length != 0) { RegionID[] array = new RegionID[m_owningRegionIDs.Length + regions.Length]; for (int i = 0; i < m_owningRegionIDs.Length; i++) { array[i] = m_owningRegionIDs[i]; } for (int j = 0; j < array.Length; j++) { array[m_owningRegionIDs.Length + j] = regions[j]; } m_owningRegionIDs = array; } } public void UpdateRandomization(bool isReachable, bool isWhitelisted, bool isBlacklisted, bool isRandomized, bool isRandomlike) { if (isRandomized && isRandomlike) { throw new ArgumentException("Cannot set location data to be both randomized and randomlike!"); } RandData = new LocationData(RandData) { IsReachable = isReachable, IsWhitelisted = isWhitelisted, IsBlacklisted = isBlacklisted, IsRandomized = isRandomized, IsRandomlike = isRandomlike }; } public void UpdateReachable(bool isReachable) { RandData = new LocationData(RandData) { IsReachable = isReachable }; } public void UpdateListing(bool isWhitelisted, bool isBlacklisted) { RandData = new LocationData(RandData) { IsWhitelisted = isWhitelisted, IsBlacklisted = isBlacklisted }; } public void UpdateRandomized(bool isRandomized, bool isRandomlike) { if (isRandomized && isRandomlike) { throw new ArgumentException("Cannot set location data to be both randomized and randomlike!"); } RandData = new LocationData(RandData) { IsRandomized = isRandomized, IsRandomlike = isRandomlike }; } public void SetItem(ItemID newItem) { if (!RandData.IsEmpty) { throw new InvalidOperationException("Cannot overwrite item for a non-empty location!"); } ItemID = newItem; } } [DataContract] public struct LocationID : ITagID, INullable, IIndex, IEquatable, IComparable, IEquatable, IComparable { [DataMember(Name = "id")] public uint ID { get; init; } public bool IsNull => ID == 0; public int AsIndex { get { return checked((int)ID - 1); } init { ID = (uint)(value + 1); } } public bool Equals(LocationID other) { return ID == other.ID; } public int CompareTo(LocationID other) { return ID.CompareTo(other.ID); } public override string ToString() { return $"LocationID {ID}"; } public static LocationID From(Game.Data data, string name, Func> definitionFactory, Location? item = null) { return data.Locations.LookUpOrCreate(name, definitionFactory, item); } public static LocationID From(TData data, string name, Func> definitionFactory, Location? item = null) where TData : Game.Data { return data.Locations.LookUpOrCreate(data, name, definitionFactory, item); } public static LocationID From(TData data, string name, Func> definitionFactory, RegionList regions, LocationData randData) where TData : Game.Data { return data.Locations.LookUpOrCreate(data, name, definitionFactory, new Location(regions, randData)); } } [DataContract] public struct LocationData { [Flags] public enum eType { PriorityMask = 3, Default = 0, Priority = 1, Excluded = 2, Trap = 3, AutoDiscover = 4, IsEmpty = 8, IsWhitelisted = 0x10, IsBlacklisted = 0x20, IsReachable = 0x40, IsRandomized = 0x80, IsRandomlike = 0x100 } private readonly eType m_value; [DataMember(Name = "priority_mode")] public eType PriorityMode { get { return m_value & eType.PriorityMask; } init { m_value = (m_value & ~eType.PriorityMask) | value; } } public bool IsDefault => PriorityMode == eType.Default; public bool IsPriority => PriorityMode == eType.Priority; public bool IsExcluded => PriorityMode == eType.Excluded; public bool IsTrap => PriorityMode == eType.PriorityMask; public bool IsAutoDiscovered { get { return (m_value & eType.AutoDiscover) != 0; } init { m_value = (value ? (m_value | eType.AutoDiscover) : (m_value & eType.AutoDiscover)); } } [DataMember(Name = "is_empty")] public bool IsEmpty { get { return (m_value & eType.IsEmpty) != 0; } init { m_value = (value ? (m_value | eType.IsEmpty) : (m_value & eType.IsEmpty)); } } public bool IsWhitelisted { get { return (m_value & eType.IsWhitelisted) != 0; } init { m_value = (value ? (m_value | eType.IsWhitelisted) : (m_value & ~eType.IsWhitelisted)); } } public bool IsBlacklisted { get { return (m_value & eType.IsBlacklisted) != 0; } init { m_value = (value ? (m_value | eType.IsBlacklisted) : (m_value & ~eType.IsBlacklisted)); } } public bool IsReachable { get { return (m_value & eType.IsReachable) != 0; } init { m_value = (value ? (m_value | eType.IsReachable) : (m_value & ~eType.IsReachable)); } } public bool ShouldBeRandomized { get { if (IsReachable && IsWhitelisted) { return !IsBlacklisted; } return false; } } public bool IsRandomized { get { return (m_value & eType.IsRandomized) != 0; } init { m_value = (value ? (m_value | eType.IsRandomized) : (m_value & ~eType.IsRandomized)); } } public bool IsRandomlike { get { return (m_value & eType.IsRandomlike) != 0; } init { m_value = (value ? (m_value | eType.IsRandomlike) : (m_value & ~eType.IsRandomlike)); } } public bool IsTreatedAsRandom { get { if (!IsRandomized) { return IsRandomlike; } return true; } } public LocationData(eType value = eType.Default) { m_value = eType.Default; m_value = value; } public LocationData(LocationData source) { m_value = eType.Default; m_value = source.m_value; } } [DataContract] public struct MidExpeditionData { [DataMember(Name = "name")] public string Name { get; set; } [DataMember(Name = "reachable_regions")] public List ReachableRegions { get; set; } } public static class Option { public enum eType { Toggle, Choice, Range, MultiChoice, ToBool, Not, Or, And, Equals, DoesNotEqual, LessThan, LessThanOrEqual, GreaterThan, GreaterThanOrEqual, Conditional, Negate, Reciprocal, Add, Subtract, Multiply, Divide, GetBit, LinearMap, AddToSet, AddCountToDict, AddAllToDict, RaiseError, IsFakeGeneration, RegionTagOption, LocationTagOption, ItemTagOption } public enum eSetTarget { RegionWhitelist, RegionBlacklist, LocationWhitelist, LocationBlacklist, ItemWhitelist, ItemBlacklist } public enum eDictTarget { GoalItems, StartInventory, StartVouchers, EarlyItems, LocalItems, NonLocalItems, ItemHints, LocationHints, PriorityLocations, ExcludeLocations } public const string DEFAULT_OPTION_CATEGORY = "Randomization Options"; public const string EARLY_WARNING_SUFFIX = "\nNote: GTFO has a limited amount of space for early items. Adding too many early items many result in FILL errors!"; public static string AddLineBreaks(string source, int maxLen = 80) { StringBuilder stringBuilder = new StringBuilder(source.Length); int num = -1; int num2 = 0; bool flag = false; for (int i = 0; i < source.Length; i++) { char c = source[i]; if (c == '"') { flag = !flag; } else if (c == ' ' && !flag) { num = i; } else if (c == '\n') { num2 = i; num = -1; } stringBuilder.Append(c); int num3 = i - num2; if ((flag && num3 > maxLen + 10 && num != -1) || (!flag && num3 > maxLen && num != -1)) { stringBuilder[num] = '\n'; num2 = num; num = -1; } } return stringBuilder.ToString(); } public static uint[] MakeSortKey(Game.Data data, RegionID id) { return IdToUint(data.Regions.MakeChain(id)); } public static uint[] MakeSortKey(Game.Data data, LocationID id) { return IdToUint(data.Locations.MakeChain(id)); } public static uint[] MakeSortKey(Game.Data data, ItemID id) { return IdToUint(data.Items.MakeChain(id)); } private static uint[] IdToUint(TID[] ids) where TID : struct, ITagID { uint[] array = new uint[ids.Length]; MemoryMarshal.Cast(ids.AsSpan()).CopyTo(array); return array; } } [DataContract] public struct OptionID : ITagID, INullable, IIndex, IEquatable, IComparable, IEquatable, IComparable { [DataMember(Name = "id")] public uint ID { get; init; } public bool IsNull => ID == 0; public int AsIndex { get { return checked((int)ID - 1); } init { ID = (uint)(value + 1); } } public bool Equals(OptionID other) { return ID == other.ID; } public int CompareTo(OptionID other) { return ID.CompareTo(other.ID); } public override string ToString() { return $"OptionID {ID}"; } } [DataContract] public struct OptionParameter { public enum eType { Constant, RegionID, LocationID, ItemID, OptionID } [DataMember(Name = "type")] public eType Type { get; init; } [DataMember(Name = "value")] public long Value { get; init; } public static implicit operator OptionParameter(long value) { return new OptionParameter { Type = eType.Constant, Value = value }; } public static implicit operator OptionParameter(RegionID id) { return new OptionParameter { Type = eType.RegionID, Value = id.ID }; } public static implicit operator OptionParameter(LocationID id) { return new OptionParameter { Type = eType.LocationID, Value = id.ID }; } public static implicit operator OptionParameter(ItemID id) { return new OptionParameter { Type = eType.ItemID, Value = id.ID }; } public static implicit operator OptionParameter(OptionID id) { return new OptionParameter { Type = eType.OptionID, Value = id.ID }; } } [DataContract] public abstract class OptionBase { [DataMember(Name = "type")] public abstract Option.eType Type { get; } } [DataContract] public abstract class OptionInput : OptionBase { private string m_description; [DataMember(Name = "display_name")] public string DisplayName { get; init; } [DataMember(Name = "description")] public string Description { get { return m_description; } init { m_description = Option.AddLineBreaks(value); } } [DataMember(Name = "category")] public string Category { get; init; } [DataMember(Name = "category_sort")] public uint[] CategorySort { get; init; } [DataMember(Name = "default_value")] public long DefaultValue { get; init; } [DataMember(Name = "condition")] public OptionID Condition { get; init; } public OptionInput(string displayName, string description, string category, uint[] categorySort, long defaultValue, OptionID condition) { DisplayName = displayName; Description = description; Category = category; CategorySort = categorySort; DefaultValue = defaultValue; Condition = condition; } } [DataContract] public class OptionToggle : OptionInput { public override Option.eType Type => Option.eType.Toggle; public OptionToggle(string displayName, string description, string category, uint[] categorySort, long defaultValue, OptionID condition) : base(displayName, description, category, categorySort, defaultValue, condition) { } } [DataContract] public class OptionChoice : OptionInput { public override Option.eType Type => Option.eType.Choice; [DataMember(Name = "choice_names")] public List ChoiceNames { get; init; } [DataMember(Name = "choice_values")] public List ChoiceValues { get; init; } public OptionChoice(string displayName, string description, string category, uint[] categorySort, long defaultValue, OptionID condition) : base(displayName, description, category, categorySort, defaultValue, condition) { ChoiceNames = new List(); ChoiceValues = new List(); } public OptionChoice(string displayName, string description, string category, uint[] categorySort, long defaultValue, OptionID condition, List choiceNames, List choiceValues) : base(displayName, description, category, categorySort, defaultValue, condition) { ChoiceNames = choiceNames; ChoiceValues = choiceValues; } } [DataContract] public class OptionRange : OptionInput { public override Option.eType Type => Option.eType.Range; [DataMember(Name = "min")] public float Min { get; init; } [DataMember(Name = "max")] public float Max { get; init; } public OptionRange(string displayName, string description, string category, uint[] categorySort, long defaultValue, OptionID condition, float min, float max) : base(displayName, description, category, categorySort, defaultValue, condition) { Min = min; Max = max; } } [DataContract] public class OptionMultiChoice : OptionInput { public override Option.eType Type => Option.eType.MultiChoice; [DataMember(Name = "choice_names")] public List ChoiceNames { get; init; } [DataMember(Name = "choice_values")] public List ChoiceValues { get; init; } public OptionMultiChoice(string displayName, string description, string category, uint[] categorySort, long defaultValue, OptionID condition) : base(displayName, description, category, categorySort, defaultValue, condition) { ChoiceNames = new List(); ChoiceValues = new List(); } public OptionMultiChoice(string displayName, string description, string category, uint[] categorySort, long defaultValue, OptionID condition, List choiceNames, List choiceValues) : base(displayName, description, category, categorySort, defaultValue, condition) { ChoiceNames = choiceNames; ChoiceValues = choiceValues; } } [DataContract] public abstract class OptionOperation : OptionBase { } [DataContract] public abstract class OptionEffect : OptionBase { [DataMember(Name = "condition")] public OptionID Condition { get; init; } public OptionEffect(OptionID condition) { Condition = condition; } } [DataContract] public class OptionAddToSet : OptionEffect { public override Option.eType Type => Option.eType.AddToSet; [DataMember(Name = "target")] public Option.eSetTarget Target { get; init; } [DataMember(Name = "tag")] public OptionParameter Tag { get; init; } public OptionAddToSet(OptionID condition, Option.eSetTarget target, OptionParameter tag) : base(condition) { Target = target; Tag = tag; } } [DataContract] public class OptionAddCount : OptionEffect { public override Option.eType Type => Option.eType.AddCountToDict; [DataMember(Name = "target")] public Option.eDictTarget Target { get; init; } [DataMember(Name = "tag")] public OptionParameter Tag { get; init; } [DataMember(Name = "count")] public OptionParameter Count { get; init; } public OptionAddCount(OptionID condition, Option.eDictTarget target, OptionParameter tag, OptionParameter count) : base(condition) { Target = target; Tag = tag; Count = count; } } [DataContract] public class OptionAddAll : OptionEffect { public override Option.eType Type => Option.eType.AddAllToDict; [DataMember(Name = "target")] public Option.eDictTarget Target { get; init; } [DataMember(Name = "tag")] public OptionParameter Tag { get; init; } public OptionAddAll(OptionID condition, Option.eDictTarget target, OptionParameter tag) : base(condition) { Target = target; Tag = tag; } } [DataContract] public class OptionRaiseError : OptionEffect { public override Option.eType Type => Option.eType.RaiseError; [DataMember(Name = "message")] public string Message { get; init; } public OptionRaiseError(OptionID condition, string message) : base(condition) { Message = message; } } [DataContract] public class OptionIsFakeGeneration : OptionBase { public override Option.eType Type => Option.eType.IsFakeGeneration; } [DataContract] public abstract class OptionTagOption : OptionInput { public const string DESC_SUFFIX = "\nWhitelist: Enables for all unless blacklisted elsewhere.\nBlacklist: Disables for all.\nNone: Defer to other relevant setting(s). If no other relevant setting is set, defaults to blacklisted."; [DataMember(Name = "tag")] public OptionParameter Tag { get; init; } public OptionTagOption(string displayName, string description, string category, uint[] categorySort, long defaultValue, OptionID condition, OptionParameter tag) : base(displayName, description, category, categorySort, defaultValue, condition) { Tag = tag; } } [DataContract] public class OptionRegionTagOption : OptionTagOption { public override Option.eType Type => Option.eType.RegionTagOption; public OptionRegionTagOption(string displayName, string description, string category, uint[] categorySort, long defaultValue, OptionID condition, OptionParameter tag) : base(displayName, description, category, categorySort, defaultValue, condition, tag) { } } [DataContract] public class OptionLocationTagOption : OptionTagOption { public override Option.eType Type => Option.eType.LocationTagOption; public OptionLocationTagOption(string displayName, string description, string category, uint[] categorySort, long defaultValue, OptionID condition, OptionParameter tag) : base(displayName, description, category, categorySort, defaultValue, condition, tag) { } } [DataContract] public class OptionItemTagOption : OptionTagOption { public override Option.eType Type => Option.eType.ItemTagOption; public OptionItemTagOption(string displayName, string description, string category, uint[] categorySort, long defaultValue, OptionID condition, OptionParameter tag) : base(displayName, description, category, categorySort, defaultValue, condition, tag) { } } [DataContract] public abstract class OptionUnaryOperation : OptionOperation { [DataMember(Name = "param")] public OptionParameter Param { get; init; } public OptionUnaryOperation(OptionParameter param) { Param = param; } } public class OptionToBoolOperation : OptionUnaryOperation { public override Option.eType Type => Option.eType.ToBool; public OptionToBoolOperation(OptionParameter param) : base(param) { } } public class OptionNotOperation : OptionUnaryOperation { public override Option.eType Type => Option.eType.Not; public OptionNotOperation(OptionParameter param) : base(param) { } } public class OptionNegateOperation : OptionUnaryOperation { public override Option.eType Type => Option.eType.Negate; public OptionNegateOperation(OptionParameter param) : base(param) { } } public class OptionReciprocalOperation : OptionUnaryOperation { public override Option.eType Type => Option.eType.Reciprocal; public OptionReciprocalOperation(OptionParameter param) : base(param) { } } [DataContract] public abstract class OptionBinaryOperation : OptionOperation { [DataMember(Name = "l_param")] public OptionParameter LParam { get; init; } [DataMember(Name = "r_param")] public OptionParameter RParam { get; init; } public OptionBinaryOperation(OptionParameter lParam, OptionParameter rParam) { LParam = lParam; RParam = rParam; } } public class OptionOrOperation : OptionBinaryOperation { public override Option.eType Type => Option.eType.Or; public OptionOrOperation(OptionParameter lParam, OptionParameter rParam) : base(lParam, rParam) { } } public class OptionAndOperation : OptionBinaryOperation { public override Option.eType Type => Option.eType.And; public OptionAndOperation(OptionParameter lParam, OptionParameter rParam) : base(lParam, rParam) { } } public class OptionEqualsOperation : OptionBinaryOperation { public override Option.eType Type => Option.eType.Equals; public OptionEqualsOperation(OptionParameter lParam, OptionParameter rParam) : base(lParam, rParam) { } } public class OptionDoesNotEqualOperation : OptionBinaryOperation { public override Option.eType Type => Option.eType.DoesNotEqual; public OptionDoesNotEqualOperation(OptionParameter lParam, OptionParameter rParam) : base(lParam, rParam) { } } public class OptionLessThanOperation : OptionBinaryOperation { public override Option.eType Type => Option.eType.LessThan; public OptionLessThanOperation(OptionParameter lParam, OptionParameter rParam) : base(lParam, rParam) { } } public class OptionLessThanOrEqualOperation : OptionBinaryOperation { public override Option.eType Type => Option.eType.LessThanOrEqual; public OptionLessThanOrEqualOperation(OptionParameter lParam, OptionParameter rParam) : base(lParam, rParam) { } } public class OptionGreaterThanOperation : OptionBinaryOperation { public override Option.eType Type => Option.eType.GreaterThan; public OptionGreaterThanOperation(OptionParameter lParam, OptionParameter rParam) : base(lParam, rParam) { } } public class OptionGreaterThanOrEqualOperation : OptionBinaryOperation { public override Option.eType Type => Option.eType.GreaterThanOrEqual; public OptionGreaterThanOrEqualOperation(OptionParameter lParam, OptionParameter rParam) : base(lParam, rParam) { } } public class OptionAddOperation : OptionBinaryOperation { public override Option.eType Type => Option.eType.Add; public OptionAddOperation(OptionParameter lParam, OptionParameter rParam) : base(lParam, rParam) { } } public class OptionSubtractOperation : OptionBinaryOperation { public override Option.eType Type => Option.eType.Subtract; public OptionSubtractOperation(OptionParameter lParam, OptionParameter rParam) : base(lParam, rParam) { } } public class OptionMultiplyOperation : OptionBinaryOperation { public override Option.eType Type => Option.eType.Multiply; public OptionMultiplyOperation(OptionParameter lParam, OptionParameter rParam) : base(lParam, rParam) { } } public class OptionDivideOperation : OptionBinaryOperation { public override Option.eType Type => Option.eType.Divide; public OptionDivideOperation(OptionParameter lParam, OptionParameter rParam) : base(lParam, rParam) { } } public class OptionGetBitOperation : OptionBinaryOperation { public override Option.eType Type => Option.eType.GetBit; public OptionGetBitOperation(OptionParameter lParam, OptionParameter rParam) : base(lParam, rParam) { } } public abstract class OptionTernaryOperation : OptionOperation { [DataMember(Name = "a_param")] public OptionParameter AParam { get; init; } [DataMember(Name = "b_param")] public OptionParameter BParam { get; init; } [DataMember(Name = "c_param")] public OptionParameter CParam { get; init; } public OptionTernaryOperation(OptionParameter aParam, OptionParameter bParam, OptionParameter cParam) { AParam = aParam; BParam = bParam; CParam = cParam; } } public class OptionConditionalOperation : OptionTernaryOperation { public override Option.eType Type => Option.eType.Conditional; public OptionConditionalOperation(OptionParameter aParam, OptionParameter bParam, OptionParameter cParam) : base(aParam, bParam, cParam) { } } public class OptionLinearMapOperation : OptionTernaryOperation { public override Option.eType Type => Option.eType.LinearMap; public OptionLinearMapOperation(OptionParameter aParam, OptionParameter bParam, OptionParameter cParam) : base(aParam, bParam, cParam) { } } [DataContract] public readonly struct Path : INullable { public enum eType { None, Item, ItemConsumed, ItemGrowing, Category, CategoryGrowing, MultiReq } [DataContract] public readonly struct PathReq : INullable { [DataMember(Name = "type")] public readonly eType Type; [DataMember(Name = "target")] public readonly ItemID Target; [DataMember(Name = "count")] public readonly uint Count; public bool IsNull => Type == eType.None; public PathReq(eType type, ItemID target, uint count) { Type = eType.None; Target = default(ItemID); Count = 1u; switch (type) { case eType.MultiReq: throw new InvalidOperationException("Cannot assign a target of type MultiReq to a PathReq!"); case eType.None: throw new InvalidOperationException("A target of type None is pointless for a PathReq!"); } Type = type; Target = target; Count = count; } } public readonly struct MultiPathReq : IEnumerable, IEnumerable { private class Enumerator : IEnumerator, IEnumerator, IDisposable { private PathReq[] source; private int position = -1; public PathReq Current => source[position]; object IEnumerator.Current => Current; public Enumerator(PathReq[] s) { source = s; } public bool MoveNext() { return ++position < source.Length; } public void Reset() { position = -1; } public void Dispose() { } } public readonly eType Type; private readonly ItemID m_target; private readonly uint m_count; private readonly PathReq[] m_reqs; public bool IsNone => Type == eType.None; public PathReq[] Reqs => Type switch { eType.None => Array.Empty(), eType.MultiReq => m_reqs, _ => new PathReq[1] { new PathReq(Type, m_target, m_count) }, }; public MultiPathReq() { m_reqs = null; Type = eType.None; m_target = default(ItemID); m_count = 0u; } public MultiPathReq(eType type, ItemID target, uint count) { m_reqs = null; if (type == eType.MultiReq) { throw new InvalidOperationException("Cannot manually assign a target of type MultiReq to a MultiPathReq!"); } Type = type; m_target = target; m_count = count; } public MultiPathReq(PathReq req) { m_reqs = null; Type = req.Type; m_target = req.Target; m_count = req.Count; } public MultiPathReq(params PathReq[] reqs) { m_target = default(ItemID); m_count = 0u; m_reqs = null; if (reqs.Length == 0) { Type = eType.None; m_target = default(ItemID); m_count = 0u; } else if (reqs.Length == 1) { Type = reqs[0].Type; m_target = reqs[0].Target; m_count = reqs[0].Count; } else { Type = eType.MultiReq; m_reqs = reqs; } } public IEnumerator GetEnumerator() { return new Enumerator(Reqs); } IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } public MultiPathReq WithAdded(PathReq newReq) { if (Type == eType.None) { return new MultiPathReq(newReq.Type, newReq.Target, newReq.Count); } if (Type != eType.MultiReq) { if (m_target.Equals(newReq.Target)) { if (Type != newReq.Type) { throw new ArgumentException("Cannot add newReq to existing MultiPathReq; targets match, but target types don't match!"); } return new MultiPathReq(Type, m_target, m_count + newReq.Count); } return new MultiPathReq(new PathReq(Type, m_target, m_count), newReq); } int i; for (i = 0; i < m_reqs.Length && !m_reqs[i].Target.Equals(newReq.Target); i++) { } if (i < m_reqs.Length) { if (m_reqs[i].Type != newReq.Type) { throw new ArgumentException("Cannot add newReq to existing MultiPathReq; targets match, but target types don't match!"); } PathReq[] array = new PathReq[m_reqs.Length]; m_reqs.CopyTo((Span)array); array[i] = new PathReq(newReq.Type, newReq.Target, m_reqs[i].Count + newReq.Count); return new MultiPathReq(array); } PathReq[] array2 = new PathReq[m_reqs.Length + 1]; m_reqs.CopyTo((Span)array2); m_reqs[i] = newReq; return new MultiPathReq(array2); } public MultiPathReq WithAdded(params PathReq[] newReqs) { if (newReqs.Length == 0) { return this; } if (newReqs.Length == 1) { return WithAdded(newReqs[0]); } for (int i = 1; i < newReqs.Length; i++) { for (int j = 0; j < i; j++) { if (newReqs[i].Target.Equals(newReqs[j].Target)) { throw new ArgumentException("Cannot add multiple reqs which share a target at once to a MultiPathReq!"); } } } if (Type == eType.None) { return new MultiPathReq(newReqs); } if (Type != eType.MultiReq) { return new MultiPathReq(newReqs).WithAdded(new PathReq(Type, m_target, m_count)); } int[] array = new int[newReqs.Length]; int num = Reqs.Length; for (int k = 0; k < newReqs.Length; k++) { array[k] = 0; while (array[k] < Reqs.Length && !newReqs[k].Target.Equals(Reqs[array[k]].Target)) { array[k]++; } if (array[k] == Reqs.Length) { num++; } } PathReq[] array2 = new PathReq[num]; num = Reqs.Length; Reqs.CopyTo((Span)array2); for (int l = 0; l < newReqs.Length; l++) { if (array[l] == Reqs.Length) { array2[num++] = newReqs[l]; continue; } if (newReqs[l].Type != Reqs[array[l]].Type) { throw new ArgumentException("Cannot add newReq to existing MultiPathReq; targets match, but target types don't match!"); } array2[array[l]] = new PathReq(newReqs[l].Type, newReqs[l].Target, Reqs[array[l]].Count + newReqs[l].Count); } return new MultiPathReq(array2); } } public class ByStartingRegionComparer : IComparer { public int Compare(Path x, Path y) { int num = x.StartingRegion.CompareTo(y.StartingRegion); if (num == 0) { num = x.EndingRegion.CompareTo(y.EndingRegion); } return num; } } public class ByEndingRegionComparer : IComparer { public int Compare(Path x, Path y) { int num = x.EndingRegion.CompareTo(y.EndingRegion); if (num == 0) { num = x.StartingRegion.CompareTo(y.StartingRegion); } return num; } } [DataMember(Name = "name")] public string? Name { get; init; } [DataMember(Name = "starting_region")] public RegionID StartingRegion { get; init; } [DataMember(Name = "ending_region")] public RegionID EndingRegion { get; init; } [DataMember(Name = "reqs")] public MultiPathReq Reqs { get; init; } public bool IsNull => StartingRegion.Equals(EndingRegion); public Path() { Name = null; StartingRegion = default(RegionID); EndingRegion = default(RegionID); Reqs = new MultiPathReq(); } public Path(Path source) { Name = null; StartingRegion = default(RegionID); EndingRegion = default(RegionID); Reqs = new MultiPathReq(); Name = source.Name; StartingRegion = source.StartingRegion; EndingRegion = source.EndingRegion; Reqs = source.Reqs; } public override string ToString() { return $"{StartingRegion} => {EndingRegion}"; } } [DataContract] public struct PathID : ITagID, INullable, IIndex, IEquatable, IComparable, IEquatable, IComparable { [DataMember(Name = "id")] public uint ID { get; init; } public bool IsNull => ID == 0; public int AsIndex { get { return checked((int)ID - 1); } init { ID = (uint)(value + 1); } } public bool Equals(PathID other) { return ID == other.ID; } public int CompareTo(PathID other) { return ID.CompareTo(other.ID); } public override string ToString() { return $"PathID {ID}"; } } [DataContract] public readonly struct Region { private enum eData { None, IsReachable, IsRandomized } private readonly eData m_data; private readonly PathID[]? m_connectedPaths; private readonly LocationID[]? m_connectedLocations; [DataMember(Name = "reachable")] public bool Reachable { get { return (m_data & eData.IsReachable) != 0; } init { m_data = (value ? (m_data | eData.IsReachable) : (m_data & (eData)(-2))); } } public bool Randomized { get { return (m_data & eData.IsRandomized) != 0; } init { m_data = (value ? (m_data | eData.IsRandomized) : (m_data & (eData)(-3))); } } public IReadOnlyList ConnectedPaths { get { return m_connectedPaths ?? Array.Empty(); } init { m_connectedPaths = value.ToArray(); } } public IReadOnlyList ConnectedLocations { get { return m_connectedLocations ?? Array.Empty(); } init { m_connectedLocations = value.ToArray(); } } public object? RegionData { get; init; } public Region() { RegionData = null; m_data = eData.None; m_connectedPaths = null; m_connectedLocations = null; } public Region(Region other) { RegionData = null; m_data = eData.None; m_connectedPaths = null; m_connectedLocations = null; m_data = other.m_data; ConnectedPaths = other.ConnectedPaths; ConnectedLocations = other.ConnectedLocations; RegionData = other.RegionData; } public Region WithReachable(bool newValue) { Region result = new Region(this); result.Reachable = newValue; return result; } public Region WithRandomized(bool newValue) { Region result = new Region(this); result.Randomized = newValue; return result; } public Region WithAdded(params PathID[] paths) { if (paths.Length == 0) { return new Region(this); } PathID[]? connectedPaths = m_connectedPaths; int num = ((connectedPaths != null) ? connectedPaths.Length : 0); PathID[] array = new PathID[num + paths.Length]; for (int i = 0; i < num; i++) { array[i] = m_connectedPaths[i]; } for (int j = 0; j < paths.Length; j++) { array[num + j] = paths[j]; } Region result = new Region(this); result.ConnectedPaths = array; return result; } public Region WithAdded(params LocationID[] locations) { if (locations.Length == 0) { return new Region(this); } LocationID[]? connectedLocations = m_connectedLocations; int num = ((connectedLocations != null) ? connectedLocations.Length : 0); LocationID[] array = new LocationID[num + locations.Length]; for (int i = 0; i < num; i++) { array[i] = m_connectedLocations[i]; } for (int j = 0; j < locations.Length; j++) { array[num + j] = locations[j]; } Region result = new Region(this); result.ConnectedLocations = array; return result; } public T GetData() where T : class { return (RegionData as T) ?? throw new NullReferenceException(); } public bool GetDataAllowNull([MaybeNullWhen(false)] out T result) where T : class { if (RegionData == null) { result = null; return false; } result = (RegionData as T) ?? throw new InvalidCastException("Cannot cast region data from " + RegionData.GetType().FullName + " to " + typeof(T).FullName); return true; } public bool TryGetData([NotNullWhen(true)] out T? result) where T : class { (bool, T?) obj = ((RegionData is T val) ? (true, result = val) : (false, result = null)); return obj.Item1; } } [DataContract] public struct RegionID : ITagID, INullable, IIndex, IEquatable, IComparable, IEquatable, IComparable { [DataMember(Name = "id")] public uint ID { get; init; } public bool IsNull => ID == 0; public int AsIndex { get { return checked((int)ID - 1); } init { ID = (uint)(value + 1); } } public bool Equals(RegionID other) { return ID == other.ID; } public int CompareTo(RegionID other) { return ID.CompareTo(other.ID); } public override string ToString() { return $"RegionID {ID}"; } public static RegionID From(Game.Data data, string name, Func> definitionFactory, Region item = default(Region)) { return data.Regions.LookUpOrCreate(name, definitionFactory, item); } public static RegionID From(TData data, string name, Func> definitionFactory, Region item = default(Region)) where TData : Game.Data { return data.Regions.LookUpOrCreate(data, name, definitionFactory, item); } } public struct RegionList : IList, ICollection, IEnumerable, IEnumerable, IList, ICollection, IReadOnlyList, IReadOnlyCollection { private RegionID[] value; public int Count => ((ICollection)value).Count; public bool IsReadOnly => ((ICollection)value).IsReadOnly; public bool IsFixedSize => ((IList)value).IsFixedSize; public bool IsSynchronized => ((ICollection)value).IsSynchronized; public object SyncRoot => ((ICollection)value).SyncRoot; object? IList.this[int index] { get { return ((IList)value)[index]; } set { ((IList)this.value)[index] = value; } } public RegionID this[int index] { get { return ((IList)value)[index]; } set { ((IList)this.value)[index] = value; } } public RegionList(RegionID[] value) { this.value = value; } public static implicit operator RegionList(RegionID r) { return new RegionList(new RegionID[1] { r }); } public static implicit operator RegionList(RegionID[] rs) { return new RegionList(rs); } public static implicit operator RegionList(List rs) { return new RegionList(rs.ToArray()); } public static implicit operator RegionID[](RegionList rs) { return rs.value; } public int IndexOf(RegionID item) { return ((IList)value).IndexOf(item); } public void Insert(int index, RegionID item) { ((IList)value).Insert(index, item); } public void RemoveAt(int index) { ((IList)value).RemoveAt(index); } public void Add(RegionID item) { ((ICollection)value).Add(item); } public void Clear() { ((ICollection)value).Clear(); } public bool Contains(RegionID item) { return ((ICollection)value).Contains(item); } public void CopyTo(RegionID[] array, int arrayIndex) { ((ICollection)value).CopyTo(array, arrayIndex); } public bool Remove(RegionID item) { return ((ICollection)value).Remove(item); } public IEnumerator GetEnumerator() { return ((IEnumerable)value).GetEnumerator(); } IEnumerator IEnumerable.GetEnumerator() { return ((IEnumerable)value).GetEnumerator(); } public int Add(object? value) { return ((IList)this.value).Add(value); } public bool Contains(object? value) { return ((IList)this.value).Contains(value); } public int IndexOf(object? value) { return ((IList)this.value).IndexOf(value); } public void Insert(int index, object? value) { ((IList)this.value).Insert(index, value); } public void Remove(object? value) { ((IList)this.value).Remove(value); } public void CopyTo(Array array, int index) { ((ICollection)value).CopyTo(array, index); } } [DataContract] public readonly record struct TagDefinition where TID : struct, ITagID { [DataMember(Name = "description")] public string Description { get; private init; } public TID Parent { get; private init; } public TID[]? OtherParents { get; private init; } [DataMember(Name = "parents")] public IEnumerable AllParents { get { IEnumerable otherParents = OtherParents; return (otherParents ?? Enumerable.Empty()).Prepend(Parent); } } public TagDefinition(string description, TID parent) { Description = description; Parent = parent; OtherParents = null; } public TagDefinition(string description, TID parent, params TID[] otherParents) { Description = description; Parent = parent; OtherParents = otherParents; } } public readonly record struct Tag where TID : struct, ITagID { public string Name { get; private init; } public TagDefinition Definition { get; private init; } public Tag(string name, TagDefinition definition) { Name = name; Definition = definition; } public Tag(string name, string description, TID parent) { Name = name; Definition = new TagDefinition(description, parent); } public Tag(string name, string description, TID parent, params TID[] otherParents) { Name = name; Definition = new TagDefinition(description, parent, otherParents); } } public interface ITagID : INullable, IIndex, IEquatable, IComparable { uint ID { get; init; } bool INullable.IsNull => ID == 0; int IIndex.AsIndex { get { return checked((int)ID - 1); } init { ID = (uint)(value + 1); } } bool IEquatable.Equals(ITagID? other) { if (other != null) { return ID == other.ID; } return false; } int IComparable.CompareTo(ITagID? other) { return ID.CompareTo(other?.ID ?? 0); } } [DataContract] public struct TagStorage where TID : struct, ITagID { [DataContract] public readonly record struct TagEntry { [DataMember(Name = "name")] public string Name { get; init; } [DataMember(Name = "definition")] public TagDefinition Definition { get; init; } [DataMember(Name = "value")] public TItem Value { [return: MaybeNull] get; [param: AllowNull] init; } public TagEntry(string name, TagDefinition definition, [AllowNull] TItem value) { Name = name; Definition = definition; Value = value; } public TagEntry(TagEntry source) { Name = source.Name; Definition = source.Definition; Value = source.Value; } } private class Adapter : IReadOnlyDictionary, IEnumerable>, IEnumerable, IReadOnlyCollection>, IReadOnlyDictionary, IEnumerable>, IReadOnlyCollection> { private class Enumerator : IEnumerator>, IEnumerator, IDisposable, IEnumerator> { private TagStorage m_storage; private uint m_index; KeyValuePair IEnumerator>.Current { get { TID val = new TID { ID = m_index }; return KeyValuePair.Create(val, m_storage.LookUpEntry(val)); } } KeyValuePair IEnumerator>.Current { get { TID val = new TID { ID = m_index }; return KeyValuePair.Create(val, m_storage.LookUpValue(val)); } } [Obsolete("Please use the type-safe implementation of GenEnumerator; the non-type-safe version is ambiguous")] object IEnumerator.Current { get { throw new NotSupportedException("Please use the type-safe implementation of GenEnumerator; the non-type-safe version is ambiguous"); } } public Enumerator(TagStorage source) { m_storage = source; } public void Dispose() { } public bool MoveNext() { return ++m_index <= m_storage.Count; } public void Reset() { m_index = 0u; } } private readonly TagStorage m_storage; private const string AMIGUOUS_ENUMERATOR_ERROR = "Please use the type-safe implementation of GenEnumerator; the non-type-safe version is ambiguous"; public IEnumerable Keys => m_storage.GetAllIDs(); public int Count => m_storage.Count; IEnumerable IReadOnlyDictionary.Values => m_storage.m_entries; TagEntry IReadOnlyDictionary.this[TID key] => m_storage.LookUpEntry(key); IEnumerable IReadOnlyDictionary.Values => m_storage.m_entries.Select((TagEntry e) => e.Value); TItem IReadOnlyDictionary.this[TID key] => m_storage.LookUpValue(key); public Adapter(TagStorage source) { m_storage = source; } public bool ContainsKey(TID key) { if (key.ID != 0) { return key.ID <= m_storage.Count; } return false; } [Obsolete("Please use the type-safe implementation of GenEnumerator; the non-type-safe version is ambiguous")] IEnumerator IEnumerable.GetEnumerator() { throw new NotSupportedException("Please use the type-safe implementation of GenEnumerator; the non-type-safe version is ambiguous"); } public bool TryGetValue(TID key, out TagEntry value) { (bool, TagEntry) obj = (ContainsKey(key) ? (true, value = m_storage.LookUpEntry(key)) : (false, value = default(TagEntry))); return obj.Item1; } IEnumerator> IEnumerable>.GetEnumerator() { return new Enumerator(m_storage); } public bool TryGetValue(TID key, out TItem value) { (bool, TItem) obj = (ContainsKey(key) ? (true, value = m_storage.LookUpValue(key)) : (false, value = default(TItem))); return obj.Item1; } IEnumerator> IEnumerable>.GetEnumerator() { return new Enumerator(m_storage); } } private class GetAllParents_Helper { public HashSet Result; private readonly TagStorage m_storage; public GetAllParents_Helper(TagStorage storage) { m_storage = storage; Result = new HashSet(); } public void Process(TID id) { if (id.IsNull || !Result.Add(id)) { return; } foreach (TID allParent in m_storage.LookUpDefinition(id).AllParents) { Process(allParent); } } } private readonly Dictionary m_lookup; [DataMember(Name = "entries")] private readonly List m_entries; public TagEntry this[TID id] => new TagEntry(LookUpEntry(id)); public int Count => m_entries.Count; public TagStorage() { m_lookup = new Dictionary(); m_entries = new List(); } static TagStorage() { if (typeof(TItem) == typeof(string)) { throw new NotSupportedException("Tag storage TItem constraint cannot be of type " + typeof(string).FullName); } } public IEnumerable GetAllIDs() { return from i in Enumerable.Range(1, Count) select new TID { ID = (uint)i }; } public IReadOnlyDictionary GetAllEntries() { return new Adapter(this); } public IReadOnlyDictionary GetAllValues() { return new Adapter(this); } public TID Create(string name, TagDefinition definition, [AllowNull] TItem item = default(TItem)) { foreach (TID allParent in definition.AllParents) { if (allParent.ID > Count) { throw new ArgumentOutOfRangeException($"Cannot register tag \"{name}\" with parent {allParent}; no such parent is currently defined!" + "\nTag storage requires all created tags use only existing parent tags to ensure graphs are acyclic and well-defined."); } } TID result = new TID { AsIndex = m_entries.Count }; m_lookup.Add(name, result.ID); m_entries.Add(new TagEntry(name, definition, item)); return result; } public TID LookUpOrCreate(string name, Func> definitionFactory, [AllowNull] TItem item = default(TItem)) { if (TryLookUpID(name, out var id)) { return id; } return Create(name, definitionFactory(), item); } public bool TryLookUpOrCreate(out TID result, string name, Func> definitionFactory, [AllowNull] TItem item = default(TItem)) { if (TryLookUpID(name, out result)) { return false; } result = Create(name, definitionFactory(), item); return true; } public TID LookUpOrCreate(string name, Func> definitionFactory, Func valueFactory) { if (TryLookUpID(name, out var id)) { return id; } return Create(name, definitionFactory(), valueFactory()); } public bool TryLookUpOrCreate(out TID result, string name, Func> definitionFactory, Func valueFactory) { if (TryLookUpID(name, out result)) { return false; } result = Create(name, definitionFactory(), valueFactory()); return true; } public TID LookUpOrCreate(TData data, string name, Func> definitionFactory, [AllowNull] TItem item = default(TItem)) { if (TryLookUpID(name, out var id)) { return id; } return Create(name, definitionFactory(data), item); } public bool TryLookUpOrCreate(out TID result, TData data, string name, Func> definitionFactory, [AllowNull] TItem item = default(TItem)) { if (TryLookUpID(name, out result)) { return false; } result = Create(name, definitionFactory(data), item); return true; } public TID LookUpOrCreate(TData data, string name, Func> definitionFactory, Func valueFactory) where TData : Game.Data { if (TryLookUpID(name, out var id)) { return id; } return Create(name, definitionFactory(data), valueFactory(data)); } public bool TryLookUpOrCreate(out TID result, TData data, string name, Func> definitionFactory, Func valueFactory) where TData : Game.Data { if (TryLookUpID(name, out result)) { return false; } result = Create(name, definitionFactory(data), valueFactory(data)); return true; } public bool TryLookUpID(string name, out TID id) { uint value; (bool, TID) obj = (m_lookup.TryGetValue(name, out value) ? (true, id = new TID { ID = value }) : (false, id = default(TID))); return obj.Item1; } public TagEntry LookUpEntry(TID id) { if (id.IsNull) { throw new NullReferenceException("Attempted to look up tag entry associated with null ID"); } return m_entries[id.AsIndex]; } public string LookUpName(TID id) { return LookUpEntry(id).Name; } public TagDefinition LookUpDefinition(TID id) { return LookUpEntry(id).Definition; } [return: MaybeNull] public TItem LookUpValue(TID id) { return LookUpEntry(id).Value; } [return: NotNull] public TItem LookUpValueChecked(TID id) { TItem value = LookUpEntry(id).Value; if (value == null) { throw new NullReferenceException($"Attempted to look up value but it was null: {id}"); } return value; } public void SetValue(TID id, [AllowNull] TItem item) { m_entries[id.AsIndex] = new TagEntry(LookUpEntry(id)) { Value = item }; } public bool ContainsID(TID id) { if (!id.IsNull) { return id.AsIndex < m_entries.Count; } return false; } public bool IsChild(TID child, TID parent) { if (child.IsNull) { return false; } if (parent.Equals(child)) { return true; } TagDefinition tagDefinition = LookUpDefinition(child); if (IsChild(tagDefinition.Parent, parent)) { return true; } if (tagDefinition.OtherParents != null) { for (int i = 0; i < tagDefinition.OtherParents.Length; i++) { if (IsChild(tagDefinition.OtherParents[i], parent)) { return true; } } } return false; } public bool IsChild(TID child, IReadOnlyCollection parents) { if (child.IsNull) { return false; } if (parents.Contains(child)) { return true; } TagDefinition tagDefinition = LookUpDefinition(child); if (IsChild(tagDefinition.Parent, parents)) { return true; } if (tagDefinition.OtherParents != null) { for (int i = 0; i < tagDefinition.OtherParents.Length; i++) { if (IsChild(tagDefinition.OtherParents[i], parents)) { return true; } } } return false; } public TID[] MakeChain(TID id) { return MakeChain_Helper(id, 0); } private TID[] MakeChain_Helper(TID id, int depth) { if (id.IsNull) { return new TID[depth]; } TID[] array = MakeChain_Helper(LookUpDefinition(id).Parent, ++depth); array[^depth] = id; return array; } public HashSet GetAllParents(IEnumerable ids) { GetAllParents_Helper getAllParents_Helper = new GetAllParents_Helper(this); foreach (TID id in ids) { getAllParents_Helper.Process(id); } return getAllParents_Helper.Result; } public void TrimExcess() { m_entries.TrimExcess(); m_lookup.TrimExcess(); } } public static class TagStorageExtensions { public static IEnumerable> GetAllValuesNonNull(this TagStorage self) where TID : struct, ITagID where TItem : class { return from p in self.GetAllValues() where p.Value != null select p; } } } namespace ReTFO.Archipelago.Features { public static class ArchipelagoFeatureGroups { [SpecialName] public sealed class $FA5CA4C8FB765F09369548ABC9DA4644 { [SpecialName] public static class $5B642FDDEBE75B7890A6FDD81284E91D { } [ExtensionMarker("$5B642FDDEBE75B7890A6FDD81284E91D")] public static FeatureGroup Archipelago { [ExtensionMarker("$5B642FDDEBE75B7890A6FDD81284E91D")] get { throw new NotSupportedException(); } } [ExtensionMarker("$5B642FDDEBE75B7890A6FDD81284E91D")] public static FeatureGroup VanillaHandlers { [ExtensionMarker("$5B642FDDEBE75B7890A6FDD81284E91D")] get { throw new NotSupportedException(); } } [ExtensionMarker("$5B642FDDEBE75B7890A6FDD81284E91D")] public static FeatureGroup FloatingHandlers { [ExtensionMarker("$5B642FDDEBE75B7890A6FDD81284E91D")] get { throw new NotSupportedException(); } } [ExtensionMarker("$5B642FDDEBE75B7890A6FDD81284E91D")] public static FeatureGroup ZoneHandlers { [ExtensionMarker("$5B642FDDEBE75B7890A6FDD81284E91D")] get { throw new NotSupportedException(); } } [ExtensionMarker("$5B642FDDEBE75B7890A6FDD81284E91D")] public static FeatureGroup TerminalHandlers { [ExtensionMarker("$5B642FDDEBE75B7890A6FDD81284E91D")] get { throw new NotSupportedException(); } } [ExtensionMarker("$5B642FDDEBE75B7890A6FDD81284E91D")] public static FeatureGroup PickupHandlers { [ExtensionMarker("$5B642FDDEBE75B7890A6FDD81284E91D")] get { throw new NotSupportedException(); } } [ExtensionMarker("$5B642FDDEBE75B7890A6FDD81284E91D")] public static FeatureGroup EventHandlers { [ExtensionMarker("$5B642FDDEBE75B7890A6FDD81284E91D")] get { throw new NotSupportedException(); } } [ExtensionMarker("$5B642FDDEBE75B7890A6FDD81284E91D")] public static FeatureGroup ObjectiveHandlers { [ExtensionMarker("$5B642FDDEBE75B7890A6FDD81284E91D")] get { throw new NotSupportedException(); } } } public const string ArchipelagoFeatureGroupName = "Archipelago"; public const string VanillaHandlersGroupName = "Vanilla Handlers"; public const string FloatingHandlersGroupName = "Floating Handlers"; public const string ZoneHandlersGroupName = "Zone Handlers"; public const string TerminalHandlersGroupName = "Terminal Handlers"; public const string PickupHandlersGroupName = "Pickup Handlers"; public const string EventHandlersGroupName = "Event Handlers"; public const string ObjectiveHandlersGroupName = "Objective Handlers"; public static FeatureGroup get_Archipelago() { return FeatureGroups.GetOrCreateTopLevelGroup("Archipelago", (GroupLocalization)null); } public static FeatureGroup get_VanillaHandlers() { return get_Archipelago().GetOrCreateSubGroup("Vanilla Handlers", false); } public static FeatureGroup get_FloatingHandlers() { return get_VanillaHandlers().GetOrCreateSubGroup("Floating Handlers", false); } public static FeatureGroup get_ZoneHandlers() { return get_VanillaHandlers().GetOrCreateSubGroup("Zone Handlers", false); } public static FeatureGroup get_TerminalHandlers() { return get_VanillaHandlers().GetOrCreateSubGroup("Terminal Handlers", false); } public static FeatureGroup get_PickupHandlers() { return get_VanillaHandlers().GetOrCreateSubGroup("Pickup Handlers", false); } public static FeatureGroup get_EventHandlers() { return get_VanillaHandlers().GetOrCreateSubGroup("Event Handlers", false); } public static FeatureGroup get_ObjectiveHandlers() { return get_VanillaHandlers().GetOrCreateSubGroup("Objective Handlers", false); } } [EnableFeatureByDefault] public class ChatHandler : ArchipelagoFeature { public class Settings { [FSDisplayName("Hide Non-Randomized Checks")] [FSDescription("If true, prevent messages for unrandomized from appearing locally, including messages for items which cannot be randomized.")] public bool DoHideTrivialChecks { get; set; } = true; [FSDisplayName("Shorten Received Item Messages")] [FSDescription("If true, show a shortened version of all \"X received Y\" messages")] public bool DoShortenReceivedItemMessages { get; set; } = true; [FSDisplayName("Show Only My Received Items")] [FSDescription("If true, only show \"X received Y\" messages if you are the recipient")] public bool DoShowOnlyMyRecievedItemMessages { get; set; } } [ArchivePatch(/*Could not decode attribute arguments.*/)] public static class PlayerChatManager__WantToSentTextMessage__Patch { public static void Postfix(PlayerAgent? fromPlayer, string? message, PlayerAgent? toPlayer) { if (message == null || (Object)(object)toPlayer != (Object)null) { return; } StateTracker stateTracker = StateTracker.Get(); if (stateTracker.ApSession != null) { if (fromPlayer != null && !((Agent)fromPlayer).IsLocallyOwned) { stateTracker.ApSession.Say(fromPlayer.Owner.NickName + ": " + message); } else { stateTracker.ApSession.Say(message); } } } } [ArchivePatch(/*Could not decode attribute arguments.*/)] public static class PlayerChatManager__Setup__Patch { public static void Postfix() { TryRemoveChatLimitations(); } } private static IArchiveLogger? m_featureLogger; private Queue m_messages = new Queue(); private SNet_PacketBufferBytes? m_packet; public override string Name => "Chat Linker"; public override string Description => "Handles chat messages to/from Archipelago. Disabling this disables all chat in and out with Archipelago."; public override FeatureGroup Group => ArchipelagoFeatureGroups.get_Archipelago(); public new static IArchiveLogger FeatureLogger { get { return m_featureLogger ?? Plugin.Get().Logger; } set { m_featureLogger = value; } } [FeatureConfig] public static Settings Config { get; set; } public IEnumerable Messages => m_messages; public override void OnEnable() { //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Expected O, but got Unknown base.OnEnable(); Plugin plugin = Plugin.Get(); if (plugin.StateTracker != null) { plugin.StateTracker.OnStateChange += OnStateChanged; if (plugin.StateTracker.ApSession != null) { plugin.StateTracker.ApSession.MessageLog.OnMessageReceived += new MessageReceivedHandler(OnMessageReceived); } } else { plugin.LateSetup += OnLateSetup; } } public override void OnDisable() { //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Expected O, but got Unknown base.OnDisable(); StateTracker stateTracker = StateTracker.Get(); stateTracker.OnStateChange -= OnStateChanged; if (stateTracker.ApSession != null) { stateTracker.ApSession.MessageLog.OnMessageReceived -= new MessageReceivedHandler(OnMessageReceived); } } protected void OnLateSetup(SNet_Replicator replicator) { Action, BufferData> action = OnSNetPacketReceived; m_packet = replicator.CreatePacketBytes(DelegateSupport.ConvertDelegate, BufferData>>((Delegate)action)); StateTracker.Get().OnStateChange += OnStateChanged; } protected void OnStateChanged(StateTracker stateTracker) { //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Expected O, but got Unknown if (stateTracker.ApSession != null) { stateTracker.ApSession.MessageLog.OnMessageReceived += new MessageReceivedHandler(OnMessageReceived); } } public static string ColorToHex(Color color) { return $"#{((Color)(ref color)).R >> 4:X1}{((Color)(ref color)).G >> 4:X1}{((Color)(ref color)).B >> 4:X1}"; } protected void OnSNetPacketReceived(Il2CppStructArray bytes, BufferData data) { StateTracker stateTracker = StateTracker.Get(); if (stateTracker.ApSession == null) { int index = 0; string text = SerializationHelpers.ReadString(bytes, ref index); if (text != null) { StateTracker.LogForLobby(text, localOnly: true); } } } protected void OnMessageReceived(LogMessage message) { //IL_01e5: Unknown result type (might be due to invalid IL or missing references) //IL_020a: Unknown result type (might be due to invalid IL or missing references) //IL_020f: Unknown result type (might be due to invalid IL or missing references) //IL_0211: Unknown result type (might be due to invalid IL or missing references) //IL_0230: Expected I4, but got Unknown PlayerSpecificLogMessage val = (PlayerSpecificLogMessage)(object)((message is PlayerSpecificLogMessage) ? message : null); if (val != null && val.IsActivePlayer) { return; } ItemSendLogMessage val2 = (ItemSendLogMessage)(object)((message is ItemSendLogMessage) ? message : null); if (val2 != null) { if (Config.DoHideTrivialChecks) { LocationID id = new LocationID { ID = checked((uint)val2.Item.LocationId) }; Game.Data processedGameData = StateTracker.Get().MidManager.GetProcessedGameData(); Location? location = processedGameData.Locations.LookUpValue(id); if (location != null && !location.RandData.IsRandomized) { return; } } if (Config.DoShowOnlyMyRecievedItemMessages && val2.Item.Player.Slot != StateTracker.Get().ApSession.Players.ActivePlayer.Slot) { return; } } HashSet hashSet = new HashSet(); if (((object)message).GetType() == typeof(ItemSendLogMessage) && Config.DoShortenReceivedItemMessages) { hashSet.UnionWith(new <>z__ReadOnlyArray(new int[3] { 3, 4, 5 })); } hashSet.UnionWith(from p in message.Parts.Select((MessagePart p, int i) => (i: i, p: p)) where (int)p.p.Type == 5 where p.p.Text.Contains("unspecified", StringComparison.OrdinalIgnoreCase) select p.i); StringBuilder stringBuilder = new StringBuilder(); for (int num = 0; num < message.Parts.Length; num++) { if (!hashSet.Contains(num)) { MessagePart val3 = message.Parts[num]; StringBuilder stringBuilder2 = stringBuilder; StringBuilder.AppendInterpolatedStringHandler handler = new StringBuilder.AppendInterpolatedStringHandler(2, 1, stringBuilder2); handler.AppendLiteral("<"); handler.AppendFormatted(ColorToHex(val3.Color)); handler.AppendLiteral(">"); stringBuilder2.Append(ref handler); MessagePartType type = val3.Type; switch ((int)type) { case 0: stringBuilder.Append(val3.Text); break; case 1: case 2: case 3: case 4: stringBuilder.Append(""); stringBuilder.Append(val3.Text); stringBuilder.Append(""); break; case 5: stringBuilder.Append(val3.Text); break; } } } stringBuilder.Append(""); m_messages.Enqueue(stringBuilder.ToString()); while (m_messages.Count > 15) { m_messages.Dequeue(); } } public override void Update() { //IL_0044: Unknown result type (might be due to invalid IL or missing references) string result; while (m_messages.TryDequeue(out result)) { StateTracker.LogForLobby(result, localOnly: true); if (SNet.IsMaster) { Il2CppStructArray val = new Il2CppStructArray((long)SerializationHelpers.CalcStringSize(result)); int index = 0; SerializationHelpers.WriteString(val, ref index, result); SNet_PacketBufferBytes? packet = m_packet; if (packet != null) { packet.Send(val, SNet_PacketBufferBytes.GetBufferDataBytes(new BufferData((ushort)1, (byte)0)), (SNet_SendGroup)2, (SNet_SendQuality)2, 4); } } } } public static void TryRemoveChatLimitations() { if ((Object)(object)PlayerChatManager.Current != (Object)null) { PlayerChatManager.Current.m_maxLen = 255; PlayerChatManager.Current.m_forbiddenChars = Il2CppStructArray.op_Implicit(Array.Empty()); } } } public static class CommonTagsHandler_Tags { [SpecialName] public sealed class $2B8804A94F2EF68DF77A343A46EE5A78 { [SpecialName] public static class $55FD246F9BFF39DD56FCB5C25D4DF852 { } [ExtensionMarker("$55FD246F9BFF39DD56FCB5C25D4DF852")] public RegionID Region_Always { [ExtensionMarker("$55FD246F9BFF39DD56FCB5C25D4DF852")] get { throw new NotSupportedException(); } } [ExtensionMarker("$55FD246F9BFF39DD56FCB5C25D4DF852")] public RegionID Region_Never { [ExtensionMarker("$55FD246F9BFF39DD56FCB5C25D4DF852")] get { throw new NotSupportedException(); } } [ExtensionMarker("$55FD246F9BFF39DD56FCB5C25D4DF852")] public LocationID Location_All { [ExtensionMarker("$55FD246F9BFF39DD56FCB5C25D4DF852")] get { throw new NotSupportedException(); } } [ExtensionMarker("$55FD246F9BFF39DD56FCB5C25D4DF852")] public LocationID Location_Always { [ExtensionMarker("$55FD246F9BFF39DD56FCB5C25D4DF852")] get { throw new NotSupportedException(); } } [ExtensionMarker("$55FD246F9BFF39DD56FCB5C25D4DF852")] public LocationID Location_Never { [ExtensionMarker("$55FD246F9BFF39DD56FCB5C25D4DF852")] get { throw new NotSupportedException(); } } [ExtensionMarker("$55FD246F9BFF39DD56FCB5C25D4DF852")] public LocationID Location_Empty { [ExtensionMarker("$55FD246F9BFF39DD56FCB5C25D4DF852")] get { throw new NotSupportedException(); } } [ExtensionMarker("$55FD246F9BFF39DD56FCB5C25D4DF852")] public ItemID Item_All { [ExtensionMarker("$55FD246F9BFF39DD56FCB5C25D4DF852")] get { throw new NotSupportedException(); } } [ExtensionMarker("$55FD246F9BFF39DD56FCB5C25D4DF852")] public ItemID Item_Always { [ExtensionMarker("$55FD246F9BFF39DD56FCB5C25D4DF852")] get { throw new NotSupportedException(); } } [ExtensionMarker("$55FD246F9BFF39DD56FCB5C25D4DF852")] public ItemID Item_Never { [ExtensionMarker("$55FD246F9BFF39DD56FCB5C25D4DF852")] get { throw new NotSupportedException(); } } [ExtensionMarker("$55FD246F9BFF39DD56FCB5C25D4DF852")] public ItemID Item_Scans { [ExtensionMarker("$55FD246F9BFF39DD56FCB5C25D4DF852")] get { throw new NotSupportedException(); } } [ExtensionMarker("$55FD246F9BFF39DD56FCB5C25D4DF852")] public ItemID Item_Warps { [ExtensionMarker("$55FD246F9BFF39DD56FCB5C25D4DF852")] get { throw new NotSupportedException(); } } [ExtensionMarker("$55FD246F9BFF39DD56FCB5C25D4DF852")] public ItemID Item_Codes { [ExtensionMarker("$55FD246F9BFF39DD56FCB5C25D4DF852")] get { throw new NotSupportedException(); } } [ExtensionMarker("$55FD246F9BFF39DD56FCB5C25D4DF852")] public OptionID Option_IsFakeGeneration { [ExtensionMarker("$55FD246F9BFF39DD56FCB5C25D4DF852")] get { throw new NotSupportedException(); } } } public static RegionID get_Region_Always(Game.Data data) { return RegionID.From(data, "Always", () => new TagDefinition("Parent tag of all regions that are always randomized.", default(RegionID))); } public static RegionID get_Region_Never(Game.Data data) { return RegionID.From(data, "Never", () => new TagDefinition("Parent tag of all regions that cannot be randomized.", default(RegionID))); } public static LocationID get_Location_All(Game.Data data) { return LocationID.From(data, "All", () => new TagDefinition("Parent tag of all locations that can be randomized.", default(LocationID))); } public static LocationID get_Location_Always(Game.Data data) { return LocationID.From(data, "Always", () => new TagDefinition("Parent tag of all locations that are always randomized.", default(LocationID))); } public static LocationID get_Location_Never(Game.Data data) { return LocationID.From(data, "Never", () => new TagDefinition("Parent tag of all locations that cannot be randomized.", default(LocationID))); } public static LocationID get_Location_Empty(Game.Data data) { return LocationID.From(data, "Empty Locations", (Game.Data data2) => new TagDefinition("Locations which do not contain an item. Empty locations are used by floating items.", get_Location_All(data2))); } public static ItemID get_Item_All(Game.Data data) { return ItemID.From(data, "All", () => new TagDefinition("Parent tag of all items that can be randomized.", default(ItemID))); } public static ItemID get_Item_Always(Game.Data data) { return ItemID.From(data, "Always", () => new TagDefinition("Parent tag of all items that are always randomized.", default(ItemID))); } public static ItemID get_Item_Never(Game.Data data) { return ItemID.From(data, "Never", () => new TagDefinition("Parent of all items that cannot be randomized.", default(ItemID))); } public static ItemID get_Item_Scans(Game.Data data) { return ItemID.From(data, "Scan Items", (Game.Data data2) => new TagDefinition("Items which trigger scans", get_Item_All(data2))); } public static ItemID get_Item_Warps(Game.Data data) { return ItemID.From(data, "Warp Items", (Game.Data data2) => new TagDefinition("Items which cause players to teleport", get_Item_All(data2))); } public static ItemID get_Item_Codes(Game.Data data) { return ItemID.From(data, "Code Items", (Game.Data data2) => new TagDefinition("Items representing codes of some kind; for example, terminal passwords and reactor codes.", get_Item_All(data2))); } public static OptionID get_Option_IsFakeGeneration(Game.Data data) { return ArchipelagoFeatureHelper.GetFeature().Option_IsFakeGeneration(data); } } [InjectToIl2Cpp] [EnableFeatureByDefault] public class CommonTagsHandler : ArchipelagoFeature { private static IArchiveLogger? m_featureLogger; private OptionID m_isFakeGeneration; public override string Name => "Common Tags Handler"; public override string Description => "Provides a set of common tags and implements options for those tags"; public override FeatureGroup Group => ArchipelagoFeatureGroups.get_VanillaHandlers(); public new static IArchiveLogger FeatureLogger { get { return m_featureLogger ?? Plugin.Get().Logger; } set { m_featureLogger = value; } } public OptionID Option_IsFakeGeneration(Game.Data data) { if (!m_isFakeGeneration.IsNull) { return m_isFakeGeneration; } return m_isFakeGeneration = data.AddOption(new OptionIsFakeGeneration()); } [Game.Callback] public void AddTagOptions(Game.Data data) { CommonTagsHandler_Tags.get_Region_Always(data); CommonTagsHandler_Tags.get_Region_Never(data); CommonTagsHandler_Tags.get_Location_Always(data); CommonTagsHandler_Tags.get_Location_Never(data); CommonTagsHandler_Tags.get_Item_Always(data); CommonTagsHandler_Tags.get_Item_Never(data); LocationID locationID = CommonTagsHandler_Tags.get_Location_Empty(data); data.AddOption(new OptionLocationTagOption("Empty Location Randomization", "Customize the randomization of all supported empty locations.\nOne empty location is added for each \"floating\" item that gets randomized to maintain the item:location balance required by Archipelago.\nEnabling randomization of an empty location makes it available as a candidate for a floating item.\nWhitelist: Enables for all unless blacklisted elsewhere.\nBlacklist: Disables for all.\nNone: Defer to other relevant setting(s). If no other relevant setting is set, defaults to blacklisted.", "Randomization Options", Option.MakeSortKey(data, locationID), 0L, default(OptionID), locationID)); ItemID itemID = CommonTagsHandler_Tags.get_Item_Warps(data); data.AddOption(new OptionItemTagOption("Warp Randomization", "Customize the randomization of all supported warps.\nWhitelist: Enables for all unless blacklisted elsewhere.\nBlacklist: Disables for all.\nNone: Defer to other relevant setting(s). If no other relevant setting is set, defaults to blacklisted.", "Randomization Options", Option.MakeSortKey(data, itemID), 2L, default(OptionID), itemID)); itemID = CommonTagsHandler_Tags.get_Item_Scans(data); data.AddOption(new OptionItemTagOption("Scan Randomization", "Customize the randomization of all supported scans.\nCurrently, this includes event scans and certain objective scans, but not door scans.\nWhitelist: Enables for all unless blacklisted elsewhere.\nBlacklist: Disables for all.\nNone: Defer to other relevant setting(s). If no other relevant setting is set, defaults to blacklisted.", "Randomization Options", Option.MakeSortKey(data, itemID), 2L, default(OptionID), itemID)); itemID = CommonTagsHandler_Tags.get_Item_Codes(data); data.AddOption(new OptionItemTagOption("Code Randomization", "Customize the randomization of all supported codes.\nThis is currently reactor codes and terminal password.\nWhitelist: Enables for all unless blacklisted elsewhere.\nBlacklist: Disables for all.\nNone: Defer to other relevant setting(s). If no other relevant setting is set, defaults to blacklisted.", "Randomization Options", Option.MakeSortKey(data, itemID), 0L, default(OptionID), itemID)); } } [EnableFeatureByDefault] public class CustomObjectiveHandler : ArchipelagoFeature { public enum eObjectiveScope { Expedition, Dimension, Layer, Zone } public class ObjectiveItem { private eObjectiveScope m_scope = eObjectiveScope.Layer; private GlobalZoneIndex m_scopeTarget = new GlobalZoneIndex((eDimensionIndex)0, (LG_LayerType)0, (eLocalZoneIndex)0); private bool m_isActive = true; protected static PUI_GameObjectives GUI => GuiManager.PlayerLayer.WardenObjectives; public int PUI_ID { get; private set; } public bool IsVisible { get; private set; } public int Priority { get; set; } = -100; public eObjectiveScope Scope { get { return m_scope; } set { m_scope = value; CheckScope(TryGetCurrentCourseNode()); } } public GlobalZoneIndex ScopeTarget { get { //IL_0001: Unknown result type (might be due to invalid IL or missing references) return m_scopeTarget; } set { //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) m_scopeTarget = value; CheckScope(TryGetCurrentCourseNode()); } } public bool IsInScope { get; private set; } public bool IsActive { get { return m_isActive; } set { m_isActive = value; Refresh(force: false); } } public bool SkipStyling { get; set; } public bool SkipBlinking { get; set; } public string ObjectiveTag { get; set; } = "CUSTOM"; public string HeaderText { get; set; } = "CUSTOM SUBOBJECTIVE"; public string SubText { get; set; } = "This is a custom sub objective.\n Hello World!"; public virtual void Setup() { CheckScope(TryGetCurrentCourseNode()); Refresh(); } protected static AIG_CourseNode? TryGetCurrentCourseNode() { PlayerAgent val = default(PlayerAgent); if (PlayerManager.TryGetLocalPlayerAgent(ref val)) { return ((Agent)val).CourseNode; } return null; } public string GetHeaderText() { return HeaderText; } public string GetSubText() { return SubText; } public void ShowNow(bool force = true) { if (!((Feature)ArchipelagoFeatureHelper.GetFeature()).Enabled) { HideNow(); return; } if (!IsVisible) { PUI_ID = -4; while (GUI.m_progressionObjectiveMap.FindEntry(PUI_ID) != -1) { int pUI_ID = PUI_ID + 1; PUI_ID = pUI_ID; } } if (!IsVisible || force) { GUI.SetProgressionObjective(PUI_ID, (Func)new Il2CppFunc_string(GetHeaderText), (Func)new Il2CppFunc_string(GetSubText), Priority, SkipStyling, SkipBlinking, ObjectiveTag); } IsVisible = true; } public void HideNow() { if (IsVisible) { GUI.RemoveProgressionObjective(PUI_ID, false); } IsVisible = false; } public virtual void CheckScope(AIG_CourseNode? localNode) { //IL_0036: 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_0041: 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_0069: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Unknown result type (might be due to invalid IL or missing references) //IL_0095: 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_00a0: Unknown result type (might be due to invalid IL or missing references) if (localNode == null && Scope != eObjectiveScope.Expedition) { IsInScope = false; } else { IsInScope = true; if (Scope >= eObjectiveScope.Dimension) { IsInScope = IsInScope && localNode.m_zone.DimensionIndex == ScopeTarget.Dimension; } if (Scope >= eObjectiveScope.Layer) { IsInScope = IsInScope && localNode.LayerType == ScopeTarget.Layer; } if (Scope >= eObjectiveScope.Zone) { IsInScope = IsInScope && localNode.m_zone.LocalIndex == ScopeTarget.Zone; } } Refresh(force: false); } public void Refresh(bool force = true) { if (IsInScope && IsActive) { ShowNow(force); } else { HideNow(); } } } [ArchivePatch(/*Could not decode attribute arguments.*/)] public static class ProgressionObjectivesManager__OnLevelCleanup__Patch { public static void Postfix() { foreach (ObjectiveItem value in s_objectives.Values) { value.HideNow(); } s_objectives.Clear(); FeatureLogger.Debug("Cleared custom progression objectives"); } } [ArchivePatch(/*Could not decode attribute arguments.*/)] public static class PlayerAgent__SetCourseNode__Patch { public static void Postfix(PlayerAgent __instance) { if (!((Agent)__instance).IsLocallyOwned) { return; } foreach (ObjectiveItem value in s_objectives.Values) { value.CheckScope(((Agent)__instance).CourseNode); } } } private static IArchiveLogger? m_featureLogger = null; private static Dictionary s_objectives = new Dictionary(); public override string Name => "Custom Objective Handler"; public override string Description => "Handles the display of custom objective UI. This is used by several handlers, such as the Reactor Startup handler, to display collected items"; public override FeatureGroup Group => ArchipelagoFeatureGroups.get_VanillaHandlers(); public new static IArchiveLogger FeatureLogger { get { return m_featureLogger ?? (m_featureLogger = Plugin.Get().Logger); } set { m_featureLogger = value; } } public override void OnEnable() { base.OnEnable(); AIG_CourseNode localNode = null; PlayerAgent val = default(PlayerAgent); if (PlayerManager.TryGetLocalPlayerAgent(ref val)) { localNode = ((Agent)val).CourseNode; } foreach (KeyValuePair s_objective in s_objectives) { s_objective.Value.CheckScope(localNode); } } public static T GetObjectiveItem(string key) where T : ObjectiveItem, new() { if (s_objectives.TryGetValue(key, out ObjectiveItem value)) { return (T)value; } T val = new T(); s_objectives.Add(key, val); val.Setup(); FeatureLogger.Debug("Registered new objective item: " + key); return val; } } public class DeathLinkHandler : ArchipelagoFeature { public class Settings { [Localized] public enum TriggerType { OnHumanPlayerDowned, OnAnyDowned, OnExpeditionFail } [Localized] public enum EffectType { SpawnTanks, SpawnSnatchers, SpawnNightmareScouts, DealDamage, DeleteResources, DownRandomPlayer, DownRandomHumanPlayer } [FSDisplayName("DeathLink Trigger")] [FSDescription("What in GTFO triggers a DeathLink event to be sent to the multiverse.\n\nOn Human Player Downed\nWhen the number of human (non-bot) players downed meets or multiples the threshold, or on expedition fail.\n\nOn Any Downed\nWhen the number of players (including bots) downed meets or multiples the threshold, or on expedition fail.\n\nOn Expedition Fail\nWhen an expedition ends in failure (not success, not abort).")] public TriggerType Trigger { get; set; } = TriggerType.OnExpeditionFail; [FSDisplayName("DeathLink Trigger Threshold")] [FSDescription("The number of players who must be downed at the same time for the DeathLink to trigger. 1 will trigger anytime someone is downed; 2 on 2, 4, 6, ... downed; 3 on 3, 6, ...; etc ")] public int TriggerThreshold { get; set; } = 2; [FSDisplayName("DeathLink Effect")] [FSDescription("What in GTFO happens when a DeathLink event is received from the multiverse.\n\nSpawn Tanks\nSpawn the supplied number of tanks (immediately aggressive).\n\nSpawn Snatchers\nSpawn the supplied number of snatchers. One is spawned immediately, the rest are chain-spawned in 1-5 minute intervals.\n\nSpawn Nightmare Scouts\nSpawn the supplied number of nightmare scouts (still asleep) in random unoccupied zones.\n\nDeal Damage\nThe supplied percent is dealt as damage to each player, killing them if necessary.\n\nDelete Resources\nThe supplied percent is dealt as damage AND deleted from all gear for each player. If this would kill a player, they are instead left at 1% health.\n\nDown Random Player\nThe supplied number of players are randomly picked and immediately downed.\n\nDown Random Human Player\nThe supplied number of players are immediately downed, randomly picked with a priority for humans.")] public EffectType Effect { get; set; } = EffectType.DownRandomPlayer; [FSDisplayName("DeathLink Effect Number")] [FSDescription("The number used in numerous DeathLink effects. If a percent, scale from 0 to 100.")] public int EffectNumber { get; set; } = 1; [FSDisplayName("DeathLink Cooldown (Seconds)")] [FSDescription("Cooldown after sending or receiving a DeathLink during which another cannot be sent or received.\n\nThis exists because receiving a DeathLink can quickly result in sending a new DeathLink, and because certain DeathLink trigger configs are capable of triggering multiple DeathLinks in quick succession.")] public float Cooldown { get; set; } = 10f; [FSDisplayName("Trigger Now")] [FSDescription("Immediately try to trigger the DeathLink effect. Affects this GTFO lobby only; is restricted by the cooldown")] public FButton TriggerEffectButton { get; set; } = new FButton("Test DeathLink", (string)null, (Action)delegate { //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Expected O, but got Unknown if (!SNet.IsMaster) { StateTracker.LogForLobby("You cannot trigger a death link; you are not host!", localOnly: true); } else { string hostName = HostName; PlayerAgent localPlayerAgent = PlayerManager.GetLocalPlayerAgent(); TryTriggerDeathLink(new DeathLink(hostName, (((localPlayerAgent != null) ? localPlayerAgent.Owner.NickName : null) ?? "Someone") + " hit the \"Test DeathLink\" button.")); } }, false); [FSDisplayName("Show Messages")] [FSDescription("If true, show death messages when sending or receiving a DeathLink event.")] public bool DoShowMessages { get; set; } = true; } [ArchivePatch(/*Could not decode attribute arguments.*/)] public static class Dam_PlayerDamageBase__ReceiveSetDead__Patch { public static void Postfix(Dam_PlayerDamageBase __instance, pSetDeadData data) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) CheckDeath(__instance, data); } } [ArchivePatch(/*Could not decode attribute arguments.*/)] public static class Dam_PlayerDamageLocal__ReceiveSetDead__Patch { public static void Postfix(Dam_PlayerDamageBase __instance, pSetDeadData data) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) CheckDeath(__instance, data); } } [ArchivePatch(/*Could not decode attribute arguments.*/)] public static class GameStateManager__DoChangeState__Patch { public static void Postfix(eGameStateName nextState) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0003: Invalid comparison between Unknown and I4 if ((int)nextState == 15 && Config.Trigger < (Settings.TriggerType)3) { NotifyDied("Team " + HostName + " marked MIA. Objective failed."); } } } [CompilerGenerated] private static class <>O { public static Action <0>__OnStateTrackerStateChange; public static DeathLinkReceivedHandler <1>__TryTriggerDeathLink; } private static IArchiveLogger? m_featureLogger = null; private static DeathLinkService? s_service = null; private static float LastTriggerTime = 0f; private static float LastSnatcherTime = -1000f; public override string Name => "Death Link"; public override string Description => "Handles death link"; public override FeatureGroup Group => ArchipelagoFeatureGroups.get_Archipelago(); public new static IArchiveLogger FeatureLogger { get { return m_featureLogger ?? Plugin.Get().Logger; } set { m_featureLogger = value; } } [FeatureConfig] public static Settings Config { get; set; } = null; public static string HostName { get { ArchipelagoSession? apSession = StateTracker.Get().ApSession; object obj = ((apSession != null) ? apSession.Players.ActivePlayer.Name : null); if (obj == null) { SNet_Player master = SNet.Master; obj = ((master != null) ? master.NickName : null) ?? "Admin"; } if (obj == null) { obj = ""; } return (string)obj; } } public override void OnEnable() { //IL_0070: 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: Expected O, but got Unknown base.OnEnable(); StateTracker stateTracker = StateTracker.Get(); stateTracker.OnStateChange += OnStateTrackerStateChange; DeathLinkService? obj = s_service; if (obj != null) { obj.DisableDeathLink(); } ArchipelagoSession? apSession = stateTracker.ApSession; s_service = ((apSession != null) ? DeathLinkProvider.CreateDeathLinkService(apSession) : null); if (s_service != null) { DeathLinkService? obj2 = s_service; object obj3 = <>O.<1>__TryTriggerDeathLink; if (obj3 == null) { DeathLinkReceivedHandler val = TryTriggerDeathLink; <>O.<1>__TryTriggerDeathLink = val; obj3 = (object)val; } obj2.OnDeathLinkReceived += (DeathLinkReceivedHandler)obj3; DeathLinkService? obj4 = s_service; if (obj4 != null) { obj4.EnableDeathLink(); } } } public override void OnDisable() { base.OnDisable(); StateTracker stateTracker = StateTracker.Get(); stateTracker.OnStateChange -= OnStateTrackerStateChange; DeathLinkService? obj = s_service; if (obj != null) { obj.DisableDeathLink(); } s_service = null; } public static void OnStateTrackerStateChange(StateTracker stateTracker) { //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Expected O, but got Unknown if (Time.realtimeSinceStartup - Config.Cooldown <= LastTriggerTime) { return; } LastTriggerTime = Time.realtimeSinceStartup; DeathLinkService? obj = s_service; if (obj != null) { obj.DisableDeathLink(); } ArchipelagoSession? apSession = stateTracker.ApSession; s_service = ((apSession != null) ? DeathLinkProvider.CreateDeathLinkService(apSession) : null); if (s_service != null) { DeathLinkService? obj2 = s_service; object obj3 = <>O.<1>__TryTriggerDeathLink; if (obj3 == null) { DeathLinkReceivedHandler val = TryTriggerDeathLink; <>O.<1>__TryTriggerDeathLink = val; obj3 = (object)val; } obj2.OnDeathLinkReceived += (DeathLinkReceivedHandler)obj3; DeathLinkService? obj4 = s_service; if (obj4 != null) { obj4.EnableDeathLink(); } } } public static void TryTriggerDeathLink(DeathLink data) { //IL_00ac: Unknown result type (might be due to invalid IL or missing references) //IL_00b1: Unknown result type (might be due to invalid IL or missing references) //IL_00b9: Unknown result type (might be due to invalid IL or missing references) //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_00c6: Unknown result type (might be due to invalid IL or missing references) //IL_00d2: 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_00e4: 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_00f4: Unknown result type (might be due to invalid IL or missing references) //IL_0100: Expected O, but got Unknown //IL_0100: Unknown result type (might be due to invalid IL or missing references) //IL_010c: Expected O, but got Unknown //IL_0131: Unknown result type (might be due to invalid IL or missing references) //IL_0136: Unknown result type (might be due to invalid IL or missing references) //IL_013e: Unknown result type (might be due to invalid IL or missing references) //IL_013f: 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_014b: Unknown result type (might be due to invalid IL or missing references) //IL_0157: Unknown result type (might be due to invalid IL or missing references) //IL_0162: Unknown result type (might be due to invalid IL or missing references) //IL_0169: Unknown result type (might be due to invalid IL or missing references) //IL_0171: Unknown result type (might be due to invalid IL or missing references) //IL_0179: Unknown result type (might be due to invalid IL or missing references) //IL_0185: Expected O, but got Unknown //IL_0185: Unknown result type (might be due to invalid IL or missing references) //IL_01b8: Expected O, but got Unknown //IL_0360: Unknown result type (might be due to invalid IL or missing references) //IL_0367: Expected O, but got Unknown //IL_036b: Unknown result type (might be due to invalid IL or missing references) if (!SNet.IsMaster) { return; } FeatureLogger.Debug("Received DeathLink event"); if (!GameStateManager.IsInExpedition || Time.realtimeSinceStartup + Config.Cooldown <= LastTriggerTime) { return; } LastTriggerTime = Time.realtimeSinceStartup; if (Config.DoShowMessages) { if (data.Cause != null) { StateTracker.LogForLobby("<#F0F>[Death] " + data.Cause, localOnly: false); } else { StateTracker.LogForLobby("<#F0F>[Death] (Unknown cause)", localOnly: false); } } switch (Config.Effect) { case Settings.EffectType.SpawnTanks: { WardenObjectiveEventData val7 = new WardenObjectiveEventData { Type = (eWardenObjectiveEventType)9, EnemyWaveData = new GenericEnemyWaveData { AreaDistance = 2, IntelMessage = LocalizedText.op_Implicit(0u), SpawnDelay = 1f, TriggerAlarm = false, WavePopulation = 16u, WaveSettings = 30u, WorldEventObjectFilterSpawnPoint = null }, Delay = 0f }; for (int num3 = 0; num3 < Config.EffectNumber; num3++) { WorldEventManager.ExecuteEvent(val7, 0f); } break; } case Settings.EffectType.SpawnSnatchers: { WardenObjectiveEventData val5 = new WardenObjectiveEventData { Type = (eWardenObjectiveEventType)9, EnemyWaveData = new GenericEnemyWaveData { AreaDistance = 2, IntelMessage = LocalizedText.op_Implicit(0u), SpawnDelay = 1f, TriggerAlarm = false, WavePopulation = 56u, WaveSettings = 30u, WorldEventObjectFilterSpawnPoint = null }, Delay = MathF.Max(0f, LastSnatcherTime - Time.fixedTime + 60f + Random.Shared.NextSingle() * 240f) }; for (int num2 = 0; num2 < Config.EffectNumber; num2++) { WorldEventManager.ExecuteEvent(val5, 0f); val5.Delay += 60f + Random.Shared.NextSingle() * 240f; } LastSnatcherTime = Time.fixedTime + val5.Delay; break; } case Settings.EffectType.SpawnNightmareScouts: { HashSet hashSet = AIG_CourseNode.s_allNodes.Select((AIG_CourseNode n) => ((Il2CppObjectBase)n).Pointer).ToHashSet(); Enumerator enumerator = SNet.LobbyPlayers.GetEnumerator(); while (enumerator.MoveNext()) { SNet_Player current = enumerator.Current; object obj; if (current == null) { obj = null; } else { SNet_IPlayerAgent playerAgent = current.PlayerAgent; obj = ((playerAgent != null) ? ((Il2CppObjectBase)playerAgent).TryCast() : null); } PlayerAgent agent = (PlayerAgent)obj; PlayerAgent obj2 = agent; if (((obj2 != null) ? ((Agent)obj2).CourseNode : null) == null) { continue; } hashSet.Remove(((Il2CppObjectBase)((Agent)agent).CourseNode).Pointer); foreach (AIG_CourseNode item in ((Agent)agent).CourseNode.m_portals.Select((AIG_CoursePortal p) => p.GetOppositeNode(((Agent)agent).CourseNode))) { hashSet.Remove(((Il2CppObjectBase)item).Pointer); } } int effectNumber3 = Config.EffectNumber; while (effectNumber3-- > 0 && hashSet.Count > 0) { IntPtr intPtr = hashSet.ElementAt(Random.Shared.Next(0, hashSet.Count)); hashSet.Remove(intPtr); AIG_CourseNode val3 = new AIG_CourseNode(intPtr); EnemyAgent.SpawnEnemy(56u, val3.GetRandomPositionInside(), val3, (AgentMode)3); } break; } case Settings.EffectType.DealDamage: { Enumerator enumerator4 = SNet.LobbyPlayers.GetEnumerator(); while (enumerator4.MoveNext()) { SNet_Player current4 = enumerator4.Current; object obj4; if (current4 == null) { obj4 = null; } else { SNet_IPlayerAgent playerAgent3 = current4.PlayerAgent; obj4 = ((playerAgent3 != null) ? ((Il2CppObjectBase)playerAgent3).TryCast() : null); } PlayerAgent val6 = (PlayerAgent)obj4; if (val6 != null) { ((Dam_SyncedDamageBase)val6.Damage).FallDamage((float)Config.EffectNumber * 0.25f); } } break; } case Settings.EffectType.DeleteResources: { Enumerator enumerator3 = SNet.LobbyPlayers.GetEnumerator(); while (enumerator3.MoveNext()) { SNet_Player current3 = enumerator3.Current; object obj3; if (current3 == null) { obj3 = null; } else { SNet_IPlayerAgent playerAgent2 = current3.PlayerAgent; obj3 = ((playerAgent2 != null) ? ((Il2CppObjectBase)playerAgent2).TryCast() : null); } PlayerAgent val4 = (PlayerAgent)obj3; float num = MathF.Min((((val4 != null) ? ((Dam_SyncedDamageBase)val4.Damage).Health : 0f) - 0.25f) * 25f, (float)Config.EffectNumber * 0.25f); if (val4 != null) { ((Dam_SyncedDamageBase)val4.Damage).FallDamage(num); } PlayerBackpack backpack = PlayerBackpackManager.GetBackpack(current3); InventorySlotAmmo standardAmmo = backpack.AmmoStorage.StandardAmmo; standardAmmo.AmmoInPack -= MathF.Min((float)Config.EffectNumber * 4.6f, backpack.AmmoStorage.StandardAmmo.AmmoInPack); InventorySlotAmmo specialAmmo = backpack.AmmoStorage.SpecialAmmo; specialAmmo.AmmoInPack -= MathF.Min((float)Config.EffectNumber * 2.3f, backpack.AmmoStorage.SpecialAmmo.AmmoInPack); InventorySlotAmmo classAmmo = backpack.AmmoStorage.ClassAmmo; classAmmo.AmmoInPack -= MathF.Min((float)Config.EffectNumber * 1.5f, backpack.AmmoStorage.ClassAmmo.AmmoInPack); } break; } case Settings.EffectType.DownRandomPlayer: { List list2 = (from p in SNet.LobbyPlayers select ((Il2CppObjectBase)p.PlayerAgent).Cast() into p where ((Agent)p).Alive select p).ToList(); int effectNumber2 = Config.EffectNumber; while (effectNumber2-- > 0 && list2.Count > 0) { PlayerAgent val2 = list2[Random.Shared.Next(0, list2.Count)]; list2.Remove(val2); ((Dam_SyncedDamageBase)val2.Damage).FallDamage(100000000f); } break; } case Settings.EffectType.DownRandomHumanPlayer: { List list = (from p in SNet.LobbyPlayers where !p.IsBot select ((Il2CppObjectBase)p.PlayerAgent).Cast() into p where ((Agent)p).Alive select p).ToList(); int effectNumber = Config.EffectNumber; while (effectNumber-- > 0 && list.Count > 0) { PlayerAgent val = list[Random.Shared.Next(0, list.Count)]; list.Remove(val); ((Dam_SyncedDamageBase)val.Damage).FallDamage(100000000f); if (effectNumber > 0 && list.Count == 0) { list = (from p in SNet.LobbyPlayers select ((Il2CppObjectBase)p.PlayerAgent).Cast() into p where ((Agent)p).Alive select p).ToList(); } } break; } default: FeatureLogger.Error("Unrecognized DeathLink effect: " + (int)Config.Effect); break; } } public static void NotifyDied(string cause) { //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Expected O, but got Unknown if (SNet.IsMaster && !(Time.realtimeSinceStartup - Config.Cooldown <= LastTriggerTime)) { LastTriggerTime = Time.realtimeSinceStartup; FeatureLogger.Debug("Sending DeathLink event: " + cause); DeathLinkService? obj = s_service; if (obj != null) { obj.SendDeathLink(new DeathLink(HostName, cause)); } if (Config.DoShowMessages) { StateTracker.LogForLobby("<#F0F>[Death] " + cause, localOnly: false); } } } public static void CheckDeath(Dam_PlayerDamageBase __instance, pSetDeadData data) { if (!((Agent)__instance.Owner).Alive) { return; } int num; if (Config.Trigger == Settings.TriggerType.OnAnyDowned) { num = SNet.LobbyPlayers.Where((SNet_Player p) => ((Agent)((Il2CppObjectBase)p.PlayerAgent).Cast()).Alive).Count(); } else { if (Config.Trigger != Settings.TriggerType.OnHumanPlayerDowned || __instance.Owner.Owner.IsBot) { return; } num = SNet.LobbyPlayers.Where((SNet_Player p) => !p.IsBot && ((Agent)((Il2CppObjectBase)p.PlayerAgent).Cast()).Alive).Count(); } if (Config.TriggerThreshold == 0 || num % Config.TriggerThreshold == 0) { NotifyDied("Team " + HostName + " suffering casualties. Objective success compromised."); } } } [EnableFeatureByDefault] [InjectToIl2Cpp] public class EnergyLinkHandler : ArchipelagoFeature { public class Settings { private float m_output = 0.75f; private float m_input = 1f; [FSDisplayName("Output Conversion Rate")] [FSDescription("When sending energy to your team, how much is sent? Higher values increase the amount sent.")] public float OutputConversionRate { get { return m_output; } set { m_output = MathF.Max(value, 0f); } } [FSDisplayName("Input Consumption Rate")] [FSDescription("When consuming energy from the team, how much is consumed? Higher values increase the amount consumed.")] public float InputConsumptionRate { get { return m_input; } set { m_input = MathF.Max(value, 0f); } } } [InjectToIl2Cpp] private class EnergyReplicator : Object { public struct pEnergyPacket { public enum eType : byte { Get, Add, Take, Take_NoCancel, Get_Success, Get_Fail, Take_Success, Take_Fail } public readonly eType Type; public readonly BigInteger Amount; public readonly ulong PlayerLookup; public pEnergyPacket(eType type, BigInteger amount, ulong playerLookup) { Type = type; Amount = amount; PlayerLookup = playerLookup; } public int CalcByteSize() { int byteCount = Amount.GetByteCount(); return 1 + SerializationHelpers.CalcLengthSize(byteCount) + byteCount + SerializationHelpers.Calc7BitEncodedSize(PlayerLookup); } public Il2CppStructArray ToBytes(int offset = 0) { Il2CppStructArray val = new Il2CppStructArray((long)(CalcByteSize() + offset)); WriteToBytes(val, ref offset); return val; } public void WriteToBytes(Il2CppStructArray bytes, ref int index) { byte[] array = Amount.ToByteArray(); ((Il2CppArrayBase)(object)bytes)[index++] = (byte)Type; SerializationHelpers.WriteLength(bytes, ref index, array.Length); for (int i = 0; i < array.Length; i++) { ((Il2CppArrayBase)(object)bytes)[index++] = array[i]; } SerializationHelpers.Write7BitEncodedLong(bytes, ref index, PlayerLookup); } public static pEnergyPacket ReadFromBytes(Il2CppStructArray bytes, ref int index) { long num = SerializationHelpers.ReadLength(bytes, ref index); eType type = (eType)((Il2CppArrayBase)(object)bytes)[index++]; byte[] array = new byte[num]; for (int i = 0; i < num; i++) { array[i] = ((Il2CppArrayBase)(object)bytes)[index++]; } ulong playerLookup = SerializationHelpers.Read7BitEncodedULong(bytes, ref index); return new pEnergyPacket(type, new BigInteger(array), playerLookup); } public static pEnergyPacket ReadFromBytes(Il2CppStructArray bytes) { int index = 0; return ReadFromBytes(bytes, ref index); } } private SNet_PacketBufferBytes? m_packet; private SortedList> m_responseTasks = new SortedList>(); public EnergyReplicator(IntPtr ptr) : base(ptr) { } public EnergyReplicator(SNet_Replicator replicator) : base(ClassInjector.DerivedConstructorPointer()) { ClassInjector.DerivedConstructorBody((Il2CppObjectBase)(object)this); IntPtr il2CppMethod = IL2CPP.GetIl2CppMethod(((Il2CppObjectBase)this).ObjectClass, false, "OnReceive", typeof(void).FullName, new string[2] { typeof(Il2CppStructArray).FullName, typeof(BufferData).FullName }); m_packet = replicator.CreatePacketBytes(new Action, BufferData>((Object)(object)this, il2CppMethod)); } [HideFromIl2Cpp] public Task SendRequest(pEnergyPacket.eType type, BigInteger requestAmount) { //IL_0035: 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) //IL_00a2: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)SNet.Master == (Object)null || ((Il2CppObjectBase)SNet.Master).Pointer == ((Il2CppObjectBase)SNet.LocalPlayer).Pointer) { throw new Exception("Cannot send energy request; master is either null or self!"); } pPlayer val = default(pPlayer); ((pPlayer)(ref val)).SetPlayer(PlayerManager.GetLocalPlayerAgent().Owner); pEnergyPacket pEnergyPacket = new pEnergyPacket(type, requestAmount, val.lookup); ushort num = (ushort)(m_responseTasks.Count + 1); TaskCompletionSource taskCompletionSource = new TaskCompletionSource(); while (m_responseTasks.ContainsKey(num)) { num++; } m_responseTasks.Add(num, taskCompletionSource); m_packet.Send(pEnergyPacket.ToBytes(), SNet_PacketBufferBytes.GetBufferDataBytes(new BufferData(num, (byte)0)), (SNet_SendQuality)2, 0, SNet.Master); return taskCompletionSource.Task; } public void OnReceive(Il2CppStructArray bytes, BufferData data) { //IL_0016: 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_0053: Unknown result type (might be due to invalid IL or missing references) pEnergyPacket pEnergyPacket = pEnergyPacket.ReadFromBytes(bytes); pPlayer val = new pPlayer { lookup = pEnergyPacket.PlayerLookup, IsBot = false }; SNet_Player player = default(SNet_Player); if (!((pPlayer)(ref val)).GetPlayer(ref player)) { FeatureLogger.Error("Received energy request, but could not identify response player!"); return; } ushort requestId = data.bufferID; switch (pEnergyPacket.Type) { case pEnergyPacket.eType.Get: GetCurrentEnergy().ContinueWith(delegate(Task t) { SendResponse(player, requestId, t.IsCompletedSuccessfully ? pEnergyPacket.eType.Get_Success : pEnergyPacket.eType.Get_Fail, t.IsCompletedSuccessfully ? t.Result : ((BigInteger)0)); }); break; case pEnergyPacket.eType.Add: AddEnergy(pEnergyPacket.Amount); break; case pEnergyPacket.eType.Take: RequestEnergy(pEnergyPacket.Amount, allowCancel: true).ContinueWith(delegate(Task t) { SendResponse(player, requestId, t.IsCompletedSuccessfully ? pEnergyPacket.eType.Take_Success : pEnergyPacket.eType.Take_Fail, t.IsCompletedSuccessfully ? t.Result : ((BigInteger)0)); }); break; case pEnergyPacket.eType.Take_NoCancel: RequestEnergy(pEnergyPacket.Amount, allowCancel: false).ContinueWith(delegate(Task t) { SendResponse(player, requestId, t.IsCompletedSuccessfully ? pEnergyPacket.eType.Take_Success : pEnergyPacket.eType.Take_Fail, t.IsCompletedSuccessfully ? t.Result : ((BigInteger)0)); }); break; case pEnergyPacket.eType.Get_Success: case pEnergyPacket.eType.Take_Success: m_responseTasks[requestId].SetResult(pEnergyPacket.Amount); m_responseTasks.Remove(requestId); break; case pEnergyPacket.eType.Get_Fail: case pEnergyPacket.eType.Take_Fail: m_responseTasks[requestId].SetCanceled(); m_responseTasks.Remove(requestId); break; default: throw new NotSupportedException($"Request type {pEnergyPacket.Type} not supported!"); } } [HideFromIl2Cpp] public void SendResponse(SNet_Player toPlayer, ushort id, pEnergyPacket.eType type, BigInteger amount) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Unknown result type (might be due to invalid IL or missing references) pPlayer val = default(pPlayer); PlayerAgent localPlayerAgent = PlayerManager.GetLocalPlayerAgent(); ((pPlayer)(ref val)).SetPlayer((localPlayerAgent != null) ? localPlayerAgent.Owner : null); pEnergyPacket pEnergyPacket = new pEnergyPacket(type, amount, val.lookup); m_packet.Send(pEnergyPacket.ToBytes(), SNet_PacketBufferBytes.GetBufferDataBytes(new BufferData(id, (byte)0)), (SNet_SendQuality)2, 0, SNet.Master); } } private static IArchiveLogger? m_featureLogger; private EnergyReplicator? m_replicator; public override string Name => "Energy Link"; public override string Description => "Handles energy link. This handler controls all energy in/out, but does not add or remove any by itself."; public override FeatureGroup Group => ArchipelagoFeatureGroups.get_Archipelago(); public new static IArchiveLogger FeatureLogger { get { return m_featureLogger ?? Plugin.Get().Logger; } set { m_featureLogger = value; } } [FeatureConfig] public static Settings Config { get; set; } public override void OnEnable() { base.OnEnable(); Plugin.Get().LateSetup += delegate(SNet_Replicator replicator) { m_replicator = new EnergyReplicator(replicator); StateTracker.Get().OnStateChange += delegate(StateTracker st) { ArchipelagoSession? apSession = st.ApSession; if (apSession != null) { apSession.DataStorage[$"EnergyLink{st.ApSession.Players.ActivePlayer.Team}"].Initialize(JToken.op_Implicit(0)); } }; }; } private static BigInteger Multiply(BigInteger value, double conversion) { if (value.Sign < 0) { throw new ArgumentException("Cannot multiply a negative bigint value"); } if (conversion < 0.0) { throw new ArgumentException("Cannot multiply a negative conversion multiplier"); } byte[] array = value.ToByteArray(); BigInteger result = 0; if (Math.Abs(conversion) < 1.0) { result = (BigInteger)(conversion * (double)(ulong)value); for (int i = 8; i < array.Length; i++) { result += (BigInteger)(conversion * (double)((ulong)array[i] << 56)) << 8 * i; } } else { for (int j = 0; j < array.Length; j++) { result += (BigInteger)(conversion * (double)array[j]) << 8 * j; } } return result; } public static async Task GetCurrentEnergy() { StateTracker stateTracker = StateTracker.Get(); if (stateTracker.ApSession != null) { return Multiply(DataStorageElement.op_Implicit(stateTracker.ApSession.DataStorage[$"EnergyLink{stateTracker.ApSession.Players.ActivePlayer.Team}"] + Operation.Max(0)), 1f / Config.InputConsumptionRate); } if (stateTracker.CurrentState == StateTracker.eState.FakeConnect) { FeatureLogger.Debug("Due to fake connect, pretending to have a lot of energy"); return 1234567890000000000L; } EnergyLinkHandler feature = ArchipelagoFeatureHelper.GetFeature(); return await feature.m_replicator.SendRequest(EnergyReplicator.pEnergyPacket.eType.Get, 0); } public static async Task RequestEnergy(BigInteger amount, bool allowCancel) { FeatureLogger.Notice($"Processing energy request for amount: {amount}"); StateTracker stateTracker = StateTracker.Get(); if (stateTracker.ApSession != null) { if (amount.Sign < 0) { throw new ArgumentException("Cannot request less than 0 energy!"); } BigInteger bigInteger = Multiply(amount, Config.InputConsumptionRate); DataStorageElement val = stateTracker.ApSession.DataStorage[$"EnergyLink{stateTracker.ApSession.Players.ActivePlayer.Team}"]; if (allowCancel && bigInteger > DataStorageElement.op_Implicit(val)) { throw new TaskCanceledException(); } stateTracker.ApSession.DataStorage[$"EnergyLink{stateTracker.ApSession.Players.ActivePlayer.Team}"] = val - bigInteger + Operation.Max(0); return Multiply(BigInteger.Min(DataStorageElement.op_Implicit(val), bigInteger), 1f / Config.InputConsumptionRate); } if (stateTracker.CurrentState == StateTracker.eState.FakeConnect) { if (amount.Sign < 0) { throw new ArgumentException("Cannot request less than 0 energy!"); } FeatureLogger.Debug("Due to fake connect, approving energy request"); return amount; } EnergyLinkHandler feature = ArchipelagoFeatureHelper.GetFeature(); EnergyReplicator.pEnergyPacket.eType type = (allowCancel ? EnergyReplicator.pEnergyPacket.eType.Take : EnergyReplicator.pEnergyPacket.eType.Take_NoCancel); return await feature.m_replicator.SendRequest(type, amount); } public static async Task AddEnergy(BigInteger amount) { FeatureLogger.Notice($"Adding energy: {amount}"); StateTracker stateTracker = StateTracker.Get(); if (stateTracker.ApSession != null) { if (amount.Sign < 0) { throw new ArgumentException("Cannot add less than 0 energy!"); } IDataStorageHelper dataStorage = stateTracker.ApSession.DataStorage; string text = $"EnergyLink{stateTracker.ApSession.Players.ActivePlayer.Team}"; dataStorage[text] += Multiply(amount, Config.OutputConversionRate); } else if (stateTracker.CurrentState == StateTracker.eState.FakeConnect) { if (amount.Sign < 0) { throw new ArgumentException("Cannot add less than 0 energy!"); } FeatureLogger.Debug("Due to fake connect, ignoring energy add request"); } else { EnergyLinkHandler feature = ArchipelagoFeatureHelper.GetFeature(); await feature.m_replicator.SendRequest(EnergyReplicator.pEnergyPacket.eType.Add, amount); } } } [EnableFeatureByDefault] public class RundownHandler : ArchipelagoFeature { [ArchivePatch(/*Could not decode attribute arguments.*/)] public static class CM_ExpeditionIcon_New__SetStatus__Patch { public static void Prefix(CM_ExpeditionIcon_New __instance, ref eExpeditionIconStatus status, ref string mainFinishCount, ref string secondFinishCount, ref string thirdFinishCount, ref string allFinishedCount) { //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Invalid comparison between Unknown and I4 StateTracker stateTracker = StateTracker.Get(); if (!Expedition.Data.TryGetFromExpedition(__instance.DataBlock, out Expedition.Data result)) { FeatureLogger.Warning("Failed to overwrite expedition icon status: failed to find expedition"); return; } int valueOrDefault = stateTracker.CollectedItemCounts.GetValueOrDefault(SharedObjectiveHandler_Tags.get_Item_SectorClear_Instance(Layer.get_MainLayer(result)), 0); mainFinishCount = valueOrDefault.ToString(); if ((int)__instance.DataBlock.Accessibility == 2) { if (valueOrDefault > 0) { status = (eExpeditionIconStatus)4; } else { status = (eExpeditionIconStatus)2; } } else { status = (eExpeditionIconStatus)0; } if (Layer.get_HasSecondary(result)) { secondFinishCount = stateTracker.CollectedItemCounts.GetValueOrDefault(SharedObjectiveHandler_Tags.get_Item_SectorClear_Instance(result.GetLayer(LayerType.Secondary)), 0).ToString(); } if (Layer.get_HasOverload(result)) { thirdFinishCount = stateTracker.CollectedItemCounts.GetValueOrDefault(SharedObjectiveHandler_Tags.get_Item_SectorClear_Instance(result.GetLayer(LayerType.Overload)), 0).ToString(); } if (Layer.get_HasSecondary(result) && Layer.get_HasOverload(result)) { allFinishedCount = stateTracker.CollectedItemCounts.GetValueOrDefault(SharedObjectiveHandler_Tags.get_Item_PEClear_Instance(result), 0).ToString(); } } } [ArchivePatch(/*Could not decode attribute arguments.*/)] public static class CM_ExpeditionIcon_New__Setup__Patch { public static void Prefix(CM_ExpeditionIcon_New __instance) { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0036: 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_0045: 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) RectTransform rectTransform = ((TMP_Text)__instance.m_statusText).rectTransform; rectTransform.anchoredPosition3D += Vector3.down * 20f; RectTransform rectTransform2 = ((TMP_Text)__instance.m_hostingFriendsCountText).rectTransform; rectTransform2.anchoredPosition3D += Vector3.down * 20f; } } [ArchivePatch(/*Could not decode attribute arguments.*/)] public static class CM_ExpeditionIcon_New__SetArtifactHeat__Patch { public static bool Prefix(CM_ExpeditionIcon_New __instance) { //IL_01e5: Unknown result type (might be due to invalid IL or missing references) //IL_01ea: 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_0210: Unknown result type (might be due to invalid IL or missing references) //IL_0216: Unknown result type (might be due to invalid IL or missing references) //IL_021b: Unknown result type (might be due to invalid IL or missing references) //IL_023d: Unknown result type (might be due to invalid IL or missing references) //IL_0242: Unknown result type (might be due to invalid IL or missing references) //IL_0263: 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_0297: Unknown result type (might be due to invalid IL or missing references) //IL_02f2: Unknown result type (might be due to invalid IL or missing references) //IL_030c: Unknown result type (might be due to invalid IL or missing references) //IL_0326: Unknown result type (might be due to invalid IL or missing references) StateTracker stateTracker = StateTracker.Get(); Game.Data gameData = stateTracker.GameData; if (!gameData.TryGetExpeditionData(__instance.DataBlock, out Expedition.Data data)) { FeatureLogger.Error("Failed to look up expedition for location count: " + __instance.DataBlock.Descriptive.Prefix); return true; } (LocationID[], ItemID[]) expeditionEntities = GetExpeditionEntities(data); int num = 0; int num2 = 0; int num3 = 0; Dictionary dictionary = new Dictionary(); LocationID[] item = expeditionEntities.Item1; foreach (LocationID id in item) { Location location = data.Locations.LookUpValue(id); if (location == null || !location.RandData.IsRandomized) { continue; } Item item2 = data.Items.LookUpValueChecked(location.ItemID); if (item2.RandData.IsProgression) { num3++; dictionary[location.ItemID] = dictionary.GetValueOrDefault(location.ItemID, 0) + 1; } if (!location.RandData.IsExcluded && !location.RandData.IsTrap) { num++; if (stateTracker.HasLocation(id)) { num2++; } } } num3 += expeditionEntities.Item2.Length; ItemID[] item3 = expeditionEntities.Item2; foreach (ItemID key in item3) { dictionary[key] = dictionary.GetValueOrDefault(key, 0) + 1; } int num4 = dictionary.Sum((KeyValuePair pair) => Math.Min(pair.Value, stateTracker.CollectedItemCounts.GetValueOrDefault(pair.Key, 0))); Dictionary dictionary2 = dictionary.ToDictionary((KeyValuePair keyValuePair) => data.Items.LookUpName(keyValuePair.Key), (KeyValuePair keyValuePair) => stateTracker.CollectedItemCounts.GetValueOrDefault(keyValuePair.Key, 0) - keyValuePair.Value); Color val = default(Color); if (num == 0) { val = Color.grey; } else if (num2 == num) { ((Color)(ref val))..ctor(0f, 1f, 0f); } else { val = Color.white; } Color val2 = default(Color); if (num3 == 0) { val2 = Color.grey; } else if (num4 == num3) { ((Color)(ref val2))..ctor(0f, 1f, 0f); } else { val2 = Color.white; } ((TMP_Text)__instance.m_artifactHeatText).SetText($"<#{(int)(val.r * 255f):X2}{(int)(val.g * 255f):X2}{(int)(val.b * 255f):X2}>Found Locations: {num2} / {num}\n<#{(int)(val2.r * 255f):X2}{(int)(val2.g * 255f):X2}{(int)(val2.b * 255f):X2}>Progression Items: {num4} / {num3}", true); return false; } } [ArchivePatch(/*Could not decode attribute arguments.*/)] public static class RundownManager__OnExpeditionEnded__Patch { public static void Postfix() { UpdateAllCounts(); } } private static IArchiveLogger? m_featureLogger = null; private static SortedList s_entities = new SortedList(); public override string Name => "Rundown Handler"; public override string Description => "Controls the appearance of rundowns, expeditions, and other UI helpers."; public override FeatureGroup Group => ArchipelagoFeatureGroups.get_Archipelago(); public new static IArchiveLogger FeatureLogger { get { return m_featureLogger ?? Plugin.Get().Logger; } set { m_featureLogger = value; } } public override void OnEnable() { base.OnEnable(); StateTracker stateTracker = StateTracker.Get(); if (stateTracker == null) { Plugin.Get().LateSetup += delegate { StateTracker.Get().OnStateChange += TryClearCache; }; } else { stateTracker.OnStateChange += TryClearCache; } } public override void OnDisable() { base.OnDisable(); StateTracker stateTracker = StateTracker.Get(); if (stateTracker != null) { stateTracker.OnStateChange -= TryClearCache; } } private static void TryClearCache(StateTracker st) { if (st.CurrentState == StateTracker.eState.CleanState) { s_entities.Clear(); } } public static void OverwriteRundowns(StateTracker stateTracker) { //IL_0139: Unknown result type (might be due to invalid IL or missing references) //IL_013e: 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_0151: Expected O, but got Unknown //IL_0236: Unknown result type (might be due to invalid IL or missing references) //IL_023b: Unknown result type (might be due to invalid IL or missing references) //IL_0269: Expected O, but got Unknown //IL_026e: Expected O, but got Unknown //IL_02a3: Unknown result type (might be due to invalid IL or missing references) //IL_02a8: Unknown result type (might be due to invalid IL or missing references) //IL_02af: Unknown result type (might be due to invalid IL or missing references) //IL_02b6: Unknown result type (might be due to invalid IL or missing references) //IL_02bd: Unknown result type (might be due to invalid IL or missing references) //IL_02c9: Expected O, but got Unknown //IL_0303: Unknown result type (might be due to invalid IL or missing references) //IL_0308: Unknown result type (might be due to invalid IL or missing references) //IL_0335: Unknown result type (might be due to invalid IL or missing references) //IL_0358: Unknown result type (might be due to invalid IL or missing references) //IL_0379: Unknown result type (might be due to invalid IL or missing references) //IL_0384: Unknown result type (might be due to invalid IL or missing references) //IL_038e: Unknown result type (might be due to invalid IL or missing references) //IL_038f: Unknown result type (might be due to invalid IL or missing references) //IL_0394: Unknown result type (might be due to invalid IL or missing references) //IL_0395: Unknown result type (might be due to invalid IL or missing references) //IL_03a4: Expected O, but got Unknown //IL_03a4: Unknown result type (might be due to invalid IL or missing references) //IL_03c5: Unknown result type (might be due to invalid IL or missing references) //IL_03d0: Unknown result type (might be due to invalid IL or missing references) //IL_03df: Expected O, but got Unknown //IL_083d: Unknown result type (might be due to invalid IL or missing references) //IL_09de: Unknown result type (might be due to invalid IL or missing references) Game.Data gameData = stateTracker.GameData; HashSet allParents = gameData.Regions.GetAllParents(stateTracker.RegionWhitelist.Where((RegionID id) => !gameData.Regions.IsChild(id, stateTracker.RegionBlacklist))); Queue queue = new Queue(); foreach (Expedition.Data allExpedition in gameData.GetAllExpeditions()) { if ((gameData.Regions.IsChild(allExpedition.Region_Expedition, stateTracker.RegionWhitelist) && !gameData.Regions.IsChild(allExpedition.Region_Expedition, stateTracker.RegionBlacklist)) || allParents.Contains(allExpedition.Region_Expedition)) { ExpeditionInTierData val = ((Il2CppObjectBase)((Object)allExpedition.Expedition).MemberwiseClone()).Cast(); val.Descriptive.Prefix = allExpedition.ExpeditionName; val.Descriptive.SkipExpNumberInName = true; val.ExcludeFromMatchmaking = true; val.ExcludeFromProgression = false; val.Descriptive.ProgressionVisualStyle = (eProgressionVisualStyle)0; val.Accessibility = (eExpeditionAccessibility)1; val.HideOnLocked = false; val.UnlockedByExpedition = new ExpeditionIndex { Tier = (eRundownTier)1, Exp = (eBuildAutoExpeditionNumber)0 }; queue.Enqueue(val); } } int numRundowns; if (queue.Count < 12) { numRundowns = 1; } else { numRundowns = (int)Math.Ceiling((double)queue.Count * 0.1); } numRundowns = Math.Min(numRundowns, MainMenuGuiLayer.Current.PageRundownNew.m_rundownSelections.Count); Random random = new Random((int)stateTracker.RootSeed); List list = (from i in Enumerable.Range(1, numRundowns) select GameDataBlockBase.GetBlock($"Archipelago {i}")).ToList(); for (int num = 0; num < numRundowns; num++) { RundownDataBlock val2 = list[num]; if (list[num] == null) { int index = num; RundownDataBlock val3 = new RundownDataBlock(); ((GameDataBlockBase)val3).name = $"Archipelago {num + 1}"; list[index] = val3; GameDataBlockBase.AddBlock(list[num], -1); val2 = list[num]; val2.NeverShowRundownTree = false; val2.UseTierUnlockRequirements = false; val2.VanityItemLayerDropDataBlock = 0u; val2.ReqToReachTierA = new RundownTierProgressionData { AllClearedSectors = 0, MainSectors = 0, SecondarySectors = 0, ThirdSectors = 0 }; val2.ReqToReachTierB = val2.ReqToReachTierA; val2.ReqToReachTierC = val2.ReqToReachTierA; val2.ReqToReachTierD = val2.ReqToReachTierA; val2.ReqToReachTierE = val2.ReqToReachTierA; val2.StorytellingData = new RundownStorytellingData { Title = MakeText(((GameDataBlockBase)(object)val2).name + " - Title", ((GameDataBlockBase)(object)val2).name + "\nMULTIVERSE"), ExternalExpTitle = MakeText(((GameDataBlockBase)(object)val2).name + " - ExpTitle", ((GameDataBlockBase)(object)val2).name), SurfaceDescription = MakeText(((GameDataBlockBase)(object)val2).name + " - Surface Description", "\nWORK WITH FELLOW PRISONERS TO RECOVER SECURE ASSETS AND COMPLETE THE RUNDOWN\n\n-----------------------------------\n\nCOORDINATE ACROSS THE MULTIWORLD TO MINIMIZE CASUALTIES AND ACCELERATE PRIORITIES\n\n-----------------------------------\n\nCOLLECT WARDEN ARTIFACTS TO SUPPLEMENT SUCCESS MARGINS AT THE COST OF EMOTIONAL DURESS"), SurfaceIconPosition = new Vector2(0f, 0f), Visuals = new RundownStorytellingVisualData { ColorBackground = Color.magenta }, TextLog = MakeText(((GameDataBlockBase)(object)val2).name + " - Log", "THIS IS ARCHIPELAGO"), TextLogPos = new Vector2(0f, 0f) }; } RundownDataBlock val4 = val2; (val4.TierA ?? (val4.TierA = new List())).Clear(); val4 = val2; (val4.TierB ?? (val4.TierB = new List())).Clear(); val4 = val2; (val4.TierC ?? (val4.TierC = new List())).Clear(); val4 = val2; (val4.TierD ?? (val4.TierD = new List())).Clear(); val4 = val2; (val4.TierE ?? (val4.TierE = new List())).Clear(); } float middle = (float)numRundowns * 0.5f + 0.5f; List list2 = (from w in Enumerable.Repeat(1f, 1).SelectMany((float w) => from wt in Enumerable.Range(1, 5) select w * MathF.Pow(2f, MathF.Abs((float)wt - 2.5f) * 0.4f)).SelectMany((float w) => from wr in Enumerable.Range(1, numRundowns) select w * MathF.Pow(1.3f, MathF.Abs((float)wr - middle) / middle)) .SelectMany((float w) => from wi in Enumerable.Range(0, 5) select w * MathF.Pow(3f, MathF.Abs((float)wi - 2f) * 0.5f)) select w / 7.7999997f).ToList(); float num2 = list2.Sum(); for (int num3 = queue.Count; num3 < list2.Count; num3++) { float num4 = num2 * random.NextSingle(); float num5 = 0f; for (int num6 = 0; num6 < list2.Count; num6++) { num5 += MathF.Max(list2[num6], 0f); if (num5 > num4) { num2 -= list2[num6]; if (list2[num6] > 0.3f) { list2[num6] = -2f; } else { list2[num6] = -1f; } break; } } } for (int num7 = 0; num7 < 5; num7++) { for (int num8 = 0; num8 < numRundowns; num8++) { for (int num9 = 0; num9 < 5; num9++) { int index2 = num7 * numRundowns * 5 + num8 * 5 + num9; if (list2[index2] > 0f) { ExpeditionInTierData val10 = queue.Dequeue(); switch (num7) { case 0: list[num8].TierA.Add(val10); break; case 1: list[num8].TierB.Add(val10); break; case 2: list[num8].TierC.Add(val10); break; case 3: list[num8].TierD.Add(val10); break; case 4: list[num8].TierE.Add(val10); break; default: throw new NotSupportedException("Attempted to place rundown in a tier outside A-E"); } } } } } if (queue.Count > 0) { throw new NotSupportedException("Failed to populate the correct number of expeditions"); } foreach (var item2 in list.SelectMany(GetVisualData)) { TierVisualData item = item2.Item2; item.Scale = item2.Item1 switch { 0 => 0.4f + 0.4f * random.NextSingle(), 1 => 0.1f, 2 => 0.35f + 0.2f * random.NextSingle(), 3 => 0.5f + 0.22f * random.NextSingle(), 4 => 0.675f + 0.1f * random.NextSingle(), 5 => 0.72f + 0.18f * random.NextSingle(), _ => throw new NotSupportedException("More than 5 expeditions in a single tier!"), }; item2.Item2.Color = Color.HSVToRGB(MathF.Pow(random.NextSingle(), 0.125f), 1f, 1f); } Enumerator enumerator3 = MainMenuGuiLayer.Current.PageRundownNew.m_expIconsAll.GetEnumerator(); while (enumerator3.MoveNext()) { CM_ExpeditionIcon_New current3 = enumerator3.Current; current3.SetStatusTextVisible(true); } List val11 = new List(list.Count); foreach (RundownDataBlock item3 in list) { val11.Add(((GameDataBlockBase)(object)item3).persistentID); } Global.RundownIdToLoad = val11[0]; Global.ActiveRundownIds = ((Il2CppObjectBase)val11.ToArray()).Cast>(); GameDataBlockBase.GetAllBlocks()[0].RundownIdsToLoad = val11; if (MainMenuGuiLayer.Current.PageRundownNew.m_rundownSelections.Count == 8) { string[] array = MainMenuGuiLayer.Current.PageRundownNew.m_rundownSelections.Select((CM_RundownSelection s) => ((CM_Item)s).Name).ToArray(); (CM_RundownSelection, Vector3)[] array2 = (from i in Enumerable.Range(0, 8) select (MainMenuGuiLayer.Current.PageRundownNew.m_rundownSelections[i], ((Il2CppArrayBase)(object)MainMenuGuiLayer.Current.PageRundownNew.m_rundownSelectionPositions)[i])).ToArray(); Array.Sort(array, array2); for (int num10 = 0; num10 < array.Length; num10++) { MainMenuGuiLayer.Current.PageRundownNew.m_rundownSelections[num10] = array2[num10].Item1; ((Il2CppArrayBase)(object)MainMenuGuiLayer.Current.PageRundownNew.m_rundownSelectionPositions)[num10] = array2[num10].Item2; } } for (int num11 = 0; num11 < numRundowns; num11++) { MainMenuGuiLayer.Current.PageRundownNew.UpdateRundownSelectionButton(MainMenuGuiLayer.Current.PageRundownNew.m_rundownSelections[num11], ((GameDataBlockBase)(object)list[num11]).persistentID); } MainMenuGuiLayer.Current.PageRundownNew.m_selectionIsRevealed = false; if (numRundowns == 1) { MainMenuGuiLayer.Current.PageRundownNew.ResetRundownItems(); MainMenuGuiLayer.Current.PageRundownNew.m_currentRundownData = list[0]; MainMenuGuiLayer.Current.PageRundownNew.PlaceRundown(list[0]); MainMenuGuiLayer.Current.PageRundownNew.UpdateHeaderText(); MainMenuGuiLayer.Current.PageRundownNew._Setup_b__102_0(0); } else { MainMenuGuiLayer.Current.PageRundownNew._Setup_b__102_3(0); } static IEnumerable<(int, TierVisualData)> GetVisualData(RundownDataBlock rundown) { yield return (rundown.TierA.Count, rundown.StorytellingData.Visuals.TierAVisuals); yield return (rundown.TierB.Count, rundown.StorytellingData.Visuals.TierBVisuals); yield return (rundown.TierC.Count, rundown.StorytellingData.Visuals.TierCVisuals); yield return (rundown.TierD.Count, rundown.StorytellingData.Visuals.TierDVisuals); yield return (rundown.TierE.Count, rundown.StorytellingData.Visuals.TierEVisuals); } static LocalizedText MakeText(string name, string text) { //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_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Expected O, but got Unknown //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_0020: 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_002e: 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_0040: 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_004e: Unknown result type (might be due to invalid IL or missing references) //IL_0055: 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_0063: Unknown result type (might be due to invalid IL or missing references) //IL_006a: 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_007f: Unknown result type (might be due to invalid IL or missing references) //IL_0086: 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_0094: 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_00a2: Expected O, but got Unknown //IL_00a2: Unknown result type (might be due to invalid IL or missing references) //IL_00a9: Expected O, but got Unknown //IL_00aa: Expected O, but got Unknown //IL_00b2: Unknown result type (might be due to invalid IL or missing references) //IL_00b7: 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) //IL_00ca: Unknown result type (might be due to invalid IL or missing references) //IL_00d2: Expected O, but got Unknown LanguageData val12 = new LanguageData { ShouldTranslate = false, Translation = text }; TextDataBlock val13 = new TextDataBlock { SkipLocalization = true, MachineTranslation = true, English = text, Description = "Text auto-generated by Archipelago", CharacterMetaData = 1u, French = val12, Italian = val12, German = val12, Spanish = val12, Russian = val12, Portuguese_Brazil = val12, Polish = val12, Japanese = val12, Korean = val12, Chinese_Traditional = val12, Chinese_Simplified = val12, ExportVersion = 6, ImportVersion = 6 }; ((GameDataBlockBase)val13).name = name; ((GameDataBlockBase)val13).internalEnabled = true; TextDataBlock val14 = val13; GameDataBlockBase.AddBlock(val14, -1); return new LocalizedText { Id = ((GameDataBlockBase)(object)val14).persistentID, OldId = 0u, UntranslatedText = text }; } } public static (LocationID[], ItemID[]) GetExpeditionEntities(Expedition.Data expedition) { if (s_entities.TryGetValue(expedition.Region_Expedition, out (LocationID[], ItemID[]) value)) { return value; } HashSet regions = new HashSet(); searchRecursive(expedition.Region_Expedition); regions.RemoveWhere((RegionID r) => !expedition.Regions.LookUpValue(r).Reachable); LocationID[] item = regions.SelectMany((RegionID r) => expedition.Regions.LookUpValue(r).ConnectedLocations).Distinct().ToArray(); ItemID[] item2 = (from pair in expedition.GetAllFloatingItems() where regions.Contains(pair.Item1) select (pair.Item2, expedition.Items.LookUpValueChecked(pair.Item2)) into pair where pair.Item2.RandData.IsWhitelisted && !pair.Item2.RandData.IsBlacklisted && pair.Item2.RandData.IsProgression select pair.Item1).ToArray(); s_entities[expedition.Region_Expedition] = (item, item2); return (item, item2); void searchRecursive(RegionID region) { if (regions.Add(region)) { foreach (PathID connectedPath in expedition.Regions.LookUpValue(region).ConnectedPaths) { searchRecursive(expedition.LookUpPath(connectedPath).EndingRegion); } } } } public static void UpdateAllCounts() { //IL_012c: Unknown result type (might be due to invalid IL or missing references) CM_MenuBar[] array = new CM_MenuBar[6]; CM_PageGearDetails pageGearDetails = MainMenuGuiLayer.Current.PageGearDetails; array[0] = ((pageGearDetails != null) ? ((CM_PageBase)pageGearDetails).m_menuBar : null); CM_PageLoadout pageLoadout = MainMenuGuiLayer.Current.PageLoadout; array[1] = ((pageLoadout != null) ? ((CM_PageBase)pageLoadout).m_menuBar : null); CM_PagePlayerDetails pagePlayerDetails = MainMenuGuiLayer.Current.PagePlayerDetails; array[2] = ((pagePlayerDetails != null) ? ((CM_PageBase)pagePlayerDetails).m_menuBar : null); CM_PageRundown pageRundown = MainMenuGuiLayer.Current.PageRundown; array[3] = ((pageRundown != null) ? ((CM_PageBase)pageRundown).m_menuBar : null); CM_PageRundown_New pageRundownNew = MainMenuGuiLayer.Current.PageRundownNew; array[4] = ((pageRundownNew != null) ? ((CM_PageBase)pageRundownNew).m_menuBar : null); CM_PageSettings pageSettings = MainMenuGuiLayer.Current.PageSettings; array[5] = ((pageSettings != null) ? ((CM_PageBase)pageSettings).m_menuBar : null); IEnumerable enumerable = new <>z__ReadOnlyArray((CM_MenuBar[])(object)array); foreach (CM_MenuBar item in enumerable) { object obj; if (item == null) { obj = null; } else { CM_ExpeditionIcon_New expIcon = item.m_expIcon; obj = ((expIcon != null) ? expIcon.DataBlock : null); } if (obj != null) { item.m_expIcon.SetArtifactHeat(1f); } } if (!GameStateManager.IsInExpedition && (Object)(object)MainMenuGuiLayer.Current.PageRundownNew != (Object)null) { Enumerator enumerator2 = MainMenuGuiLayer.Current.PageRundownNew.m_expIconsAll.GetEnumerator(); while (enumerator2.MoveNext()) { CM_ExpeditionIcon_New current2 = enumerator2.Current; current2.SetStatus(current2.Status, "-", "-", "-", "-", 1f); } } } } [ForceDisable("Too much overhead.\nPotential memory leak issues.")] public class StatefulFeatureLogger : Feature { [HarmonyPatch] private static class __OnExecute__Patch { public static IEnumerable GetMethodsRecursive(Type type, Type? featureType = null) { if (type.IsAssignableTo(typeof(ArchipelagoFeature))) { featureType = type; } IEnumerable enumerable = type.GetNestedTypes().SelectMany((Type t) => GetMethodsRecursive(t, featureType)); if (featureType != null) { IEnumerable second = from m in type.GetMethods(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic) where m.CustomAttributes.Any((CustomAttributeData ca) => ca.AttributeType.IsAssignableTo(typeof(MidManager.Processor.CallbackBase))) select m; IEnumerable second2 = (from t in type.GetNestedTypes() where t.CustomAttributes.Any((CustomAttributeData ca) => ca.AttributeType.IsAssignableTo(typeof(ArchivePatch))) select t).SelectMany((Type t) => t.GetMethods(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic)); enumerable = enumerable.Concat(second).Concat(second2); } return enumerable; } [HarmonyTargetMethods] public static IEnumerable TargetMethods() { return AppDomain.CurrentDomain.GetAssemblies().SelectMany(delegate(Assembly a) { try { return a.GetTypes(); } catch (ReflectionTypeLoadException ex) { return ex.Types.OfType(); } }).SelectMany((Type t) => GetMethodsRecursive(t)); } [HarmonyPrefix] public static void Prefix(IArchiveLogger __state, MethodBase __originalMethod) { __state = ReTFO.Archipelago.FeaturesAPI.FeatureLogger.Current; object? value = Search(__originalMethod.DeclaringType).GetValue(null); ReTFO.Archipelago.FeaturesAPI.FeatureLogger.Current = (IArchiveLogger)((value is IArchiveLogger) ? value : null); static PropertyInfo Search(Type type) { return type.GetProperty("FeatureLogger", BindingFlags.DeclaredOnly | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic) ?? Search(type.DeclaringType); } } [HarmonyPostfix] public static void Postfix(IArchiveLogger __state, MethodBase __originalMethod) { ReTFO.Archipelago.FeaturesAPI.FeatureLogger.Current = __state; } } private static IArchiveLogger? m_featureLogger; private Harmony? m_harmony; public override string Name => "Stateful Feature Logging"; public override string Description => "Modifies Archipelago features to track which is executing.\nMakes some logs (errors, warnings, etc) appear to come from the currently executing feature."; public override FeatureGroup Group => ArchipelagoFeatureGroups.get_Archipelago(); public static IArchiveLogger FeatureLogger { get { return m_featureLogger ?? (m_featureLogger = Plugin.Get().Logger); } set { m_featureLogger = value; } } public Harmony Harmony { get { //IL_000f: Unknown result type (might be due to invalid IL or missing references) return (Harmony)(((object)m_harmony) ?? ((object)new Harmony("RoboRyGuy.BetaArchipelago.StatefulFeatureLogger"))); } protected set { m_harmony = value; } } public override void OnEnable() { Harmony.PatchAll(typeof(__OnExecute__Patch)); } public override void OnDisable() { Harmony.UnpatchSelf(); } } [EnableFeatureByDefault] [AutomatedFeature] [InjectToIl2Cpp] public class StateTracker : ArchipelagoFeature { public enum eState { CleanState, HostConnecting, HostConnected, HostReconnecting, FakeConnect, ConnectedClient, ProxyClient } public class Settings : PrivateFeatureSettingsPatch.IOptionallyPrivate { public bool IsCurrentlyPrivate => HideConnectionDetails; [FSDisplayName("Use Debug Mode")] [FSDescription("Skip connecting to Archipelago and start in debug mode.")] public bool UseDebugMode { get; set; } [FSDisplayName("Hide Connection Details")] [FSDescription("For streamers. Hides connection details while not editing them. Also prevents them from being logged.")] public bool HideConnectionDetails { get; set; } = true; [FSDisplayName("Server Address")] [FSDescription("Address of the server to connect to.\nSupports IPv4 and IPv6 addresses, as well as domain names.")] [PrivateFeatureSettingsPatch.FSOptionallyPrivate] public string ServerAddress { get; set; } = "localhost"; [FSDisplayName("Server Port")] [FSDescription("Port of the server\nValid port numbers are in the 16-bit range (0-65535)\nArchipelago defaults to using port 38281")] [PrivateFeatureSettingsPatch.FSOptionallyPrivate] public ushort Port { get; set; } = 38281; [FSDisplayName("Slot Name")] [FSDescription("Slot in the server to try to connect to.")] [PrivateFeatureSettingsPatch.FSOptionallyPrivate] public string Username { get; set; } = "admin"; [FSDisplayName("Use Password")] [FSDescription("If true, will attempt to authenticate to Archipelago using the below password\nIf false, will try to skip password authentication")] public bool HasPassword { get; set; } [FSDisplayName("Password")] [FSDescription("The password to use when connecting to Archipelago")] [PrivateFeatureSettingsPatch.FSOptionallyPrivate] public string Password { get; set; } = "Password"; [FSDisplayName("Empty Trash")] [FSDescription("Unmark any trash items, revealing their checks in the expedition location counts.")] public FButton EmptyTrashButton { get; set; } = new FButton("Empty Trash", (string)null, (Action)delegate { StateTracker stateTracker = Get(); stateTracker.m_trashedLocations.Clear(); stateTracker.SendInteraction(pArchipelagoInteraction.eType.EmptyTrash, 0u, 0); }, false); [FSDisplayName("Export MID Data")] [FSDescription("Export the MID data file to your Downloads folder. The MID data file is a \".ini\" file which can be used to create APWorlds for modded rundowns.\nTo use the MID file, place it into the Players folder (the same folder you normally place YAMLs) and restart the launcher. This will add a new GTFO world which can then be used to play your modded game. This sub-world can be reused by any players running the same mods as you, and should be left in the Players folder at least until your game is generated.")] public FButton ExportMidDataButton { get; set; } = new FButton("Export", (string)null, (Action)delegate { Get().MidManager.ExportMidData(); }, false); [FSDisplayName("Export Tags to CSV")] [FSDescription("Export all tag data as a CSV file to your Downloads folder.\nThe CSV export is for an Excel-style viewing of tags, and is easier to parse programmatically.")] public FButton ExportTagsToCSVButton { get; set; } = new FButton("Export", (string)null, (Action)delegate { Get().MidManager.ExportTagsToCSV(); }, false); [FSDisplayName("Export Tags to JSON")] [FSDescription("Export all tag data as a JSON file to your Downloads folder.\nThe JSON export is for hierarchal viewing of the tags, and can make viewing tags easier if you have a good JSON viewer (such as VS Code). Several websites also have good JSON viewers available for free online without needing to download or install anything.")] public FButton ExportTagsToJSONButton { get; set; } = new FButton("Export", (string)null, (Action)delegate { Get().MidManager.ExportTagsToJSON(); }, false); [FSDisplayName("Reactivate State Tracker")] [FSDescription("Certain errors will cause State Tracker to stop updating. This is currently out of my control. Press this button to turn it back on.")] public FButton RestartButton { get; set; } = new FButton("Reactivate", (string)null, (Action)delegate { FeatureManager.DisableAutomatedFeature(typeof(StateTracker)); FeatureManager.EnableAutomatedFeature(typeof(StateTracker)); }, false); } [ArchivePatch(/*Could not decode attribute arguments.*/)] public static class PUI_GameEventLog__OnLevelCleanup__Patch { public static bool Prefix() { return false; } } [ArchivePatch(/*Could not decode attribute arguments.*/)] public static class WardenObjectiveManager__OnLocalPlayerStartExpedition__Patch { public static void Postfix() { StateTracker feature = ArchipelagoFeatureHelper.GetFeature(); ArchipelagoSession? apSession = feature.ApSession; if (apSession != null) { apSession.SetClientState((ArchipelagoClientState)20); } if (!Expedition.Data.TryGetFromCurrentExpedition(out Expedition.Data result)) { FeatureLogger.Error("Failed to identify expedition on drop; skipping relevant events"); } else { FeatureLogger.Notice("Started expedition: " + result.ExpeditionName); } feature.ItemsInTerminalSystem.Clear(); Game.Data gameData = feature.GameData; if (result != null) { foreach (ItemID item in feature.m_collectedItemCounts.SelectMany((KeyValuePair pair) => Enumerable.Repeat(pair.Key, pair.Value))) { gameData.Items.LookUpValue(item)?.OnStartExpeditionWithItem(feature, result, item); } return; } FeatureLogger.Error(" -> Items not added to terminal system!"); } } public struct pArchipelagoInitState { public string? GameName; public long RootSeed; public uint[] RegionWhitelist; public uint[] RegionBlacklist; public uint[] LocationWhitelist; public uint[] LocationBlacklist; public uint[] ItemWhitelist; public uint[] ItemBlacklist; private uint[][] MultiArray => new uint[6][] { RegionWhitelist, RegionBlacklist, LocationWhitelist, LocationBlacklist, ItemWhitelist, ItemBlacklist }; public int CalcByteSize() { return SerializationHelpers.CalcStringSize(GameName) + SerializationHelpers.Calc7BitEncodedSize((RootSeed == 0L) ? 1 : RootSeed) + SerializationHelpers.Calc7BitEncodedMultiArraySize(MultiArray); } public Il2CppStructArray ToBytes(int offset = 0) { Il2CppStructArray val = new Il2CppStructArray((long)(CalcByteSize() + offset)); WriteToBytes(val, ref offset); return val; } public void WriteToBytes(Il2CppStructArray bytes, ref int index) { SerializationHelpers.WriteString(bytes, ref index, GameName); SerializationHelpers.Write7BitEncodedLong(bytes, ref index, RootSeed); SerializationHelpers.Write7BitEncodedMultiArray(bytes, ref index, MultiArray); } public static pArchipelagoInitState ReadFromBytes(Il2CppStructArray bytes, ref int index) { pArchipelagoInitState result = new pArchipelagoInitState { GameName = SerializationHelpers.ReadString(bytes, ref index), RootSeed = SerializationHelpers.Read7BitEncodedLong(bytes, ref index) }; Memory[] array = SerializationHelpers.Read7BitEncodedMultiUIntArray(bytes, ref index); if (array.Length != result.MultiArray.Length) { throw new NotSupportedException("Received incorrect number of int arrays for AP State from network"); } result.RegionWhitelist = new uint[array[0].Length]; array[0].CopyTo(result.RegionWhitelist); result.RegionBlacklist = new uint[array[1].Length]; array[1].CopyTo(result.RegionBlacklist); result.LocationWhitelist = new uint[array[0].Length]; array[2].CopyTo(result.LocationWhitelist); result.LocationBlacklist = new uint[array[1].Length]; array[3].CopyTo(result.LocationBlacklist); result.ItemWhitelist = new uint[array[0].Length]; array[4].CopyTo(result.ItemWhitelist); result.ItemBlacklist = new uint[array[1].Length]; array[5].CopyTo(result.ItemBlacklist); return result; } public static pArchipelagoInitState FromBytes(Il2CppStructArray bytes) { int index = 0; return ReadFromBytes(bytes, ref index); } } public struct pArchipelagoScoutingUpdate { public string[] SlotLookup; public uint[] LocationIDs; public uint[] SlotIds; public string[] ItemDisplayNames; private uint[][] MultiArray => new uint[2][] { LocationIDs, SlotIds }; public int CalcByteSize() { return SerializationHelpers.CalcStringArraySize(SlotLookup) + SerializationHelpers.Calc7BitEncodedMultiArraySize(MultiArray) + SerializationHelpers.CalcStringArraySize(ItemDisplayNames); } public Il2CppStructArray ToBytes(int offset = 0) { Il2CppStructArray val = new Il2CppStructArray((long)(offset + CalcByteSize())); WriteToBytes(val, ref offset); return val; } public void WriteToBytes(Il2CppStructArray bytes, ref int index) { SerializationHelpers.WriteStringArray(bytes, ref index, SlotLookup); SerializationHelpers.Write7BitEncodedMultiArray(bytes, ref index, MultiArray); SerializationHelpers.WriteStringArray(bytes, ref index, ItemDisplayNames); } public static pArchipelagoScoutingUpdate FromBytes(Il2CppStructArray bytes, ref int index) { pArchipelagoScoutingUpdate result = default(pArchipelagoScoutingUpdate); result.SlotLookup = SerializationHelpers.ReadStringArray(bytes, ref index); Memory[] array = SerializationHelpers.Read7BitEncodedMultiUIntArray(bytes, ref index); result.LocationIDs = new uint[array[0].Length]; array[0].CopyTo(result.LocationIDs); result.SlotIds = new uint[array[1].Length]; array[1].CopyTo(result.SlotIds); result.ItemDisplayNames = SerializationHelpers.ReadStringArray(bytes, ref index); return result; } public static pArchipelagoScoutingUpdate FromBytes(Il2CppStructArray bytes) { int index = 0; return FromBytes(bytes, ref index); } } public struct pArchipelagoGeneralState { public uint[] FoundLocations; public uint[] TrashedLocations; public uint[] ItemIds; public uint[] ItemsInTerminalSystem; private uint[][] MultiArray => new uint[4][] { FoundLocations, TrashedLocations, ItemIds, ItemsInTerminalSystem }; public int CalcByteSize() { return SerializationHelpers.Calc7BitEncodedMultiArraySize(MultiArray); } public Il2CppStructArray ToBytes(int offset = 0) { Il2CppStructArray val = new Il2CppStructArray((long)(offset + CalcByteSize())); WriteToBytes(val, ref offset); return val; } public void WriteToBytes(Il2CppStructArray bytes, ref int index) { SerializationHelpers.Write7BitEncodedMultiArray(bytes, ref index, MultiArray); } public static pArchipelagoGeneralState FromBytes(Il2CppStructArray bytes, ref int index) { Memory[] array = SerializationHelpers.Read7BitEncodedMultiUIntArray(bytes, ref index); pArchipelagoGeneralState result = new pArchipelagoGeneralState { FoundLocations = new uint[array[0].Length] }; array[0].CopyTo(result.FoundLocations); result.TrashedLocations = new uint[array[1].Length]; array[1].CopyTo(result.TrashedLocations); result.ItemIds = new uint[array[2].Length]; array[2].CopyTo(result.ItemIds); result.ItemsInTerminalSystem = new uint[array[3].Length]; array[3].CopyTo(result.ItemsInTerminalSystem); return result; } public static pArchipelagoGeneralState FromBytes(Il2CppStructArray bytes) { int index = 0; return FromBytes(bytes, ref index); } } [StructLayout(LayoutKind.Explicit, Size = 12)] public struct pArchipelagoInteraction { public enum eType : ushort { CheckRegion, CheckLocation, ScoutLocation, MarkTrash, EmptyTrash, CollectItem } [FieldOffset(0)] public eType Type; [FieldOffset(2)] public ushort Count; [FieldOffset(4)] public uint Value; public pArchipelagoInteraction(eType type, uint value = 0u, ushort count = 0) { Type = type; Value = value; Count = count; } public pArtifactInventoryState ToBytes() { //IL_0048: Unknown result type (might be due to invalid IL or missing references) byte[] array = new byte[12]; BinaryPrimitives.WriteUInt16LittleEndian(array.AsSpan(0, 2), (ushort)Type); BinaryPrimitives.WriteUInt16LittleEndian(array.AsSpan(2, 2), Count); BinaryPrimitives.WriteInt64LittleEndian(array.AsSpan(4, 8), Value); return MemoryMarshal.Read((ReadOnlySpan)array); } public static pArchipelagoInteraction FromBytes(pArtifactInventoryState input) { byte[] array = MemoryMarshal.AsBytes(MemoryMarshal.CreateReadOnlySpan(in input, 1)).ToArray(); pArchipelagoInteraction result = default(pArchipelagoInteraction); result.Type = (eType)BinaryPrimitives.ReadUInt16LittleEndian(array.AsSpan(0, 2)); result.Count = BinaryPrimitives.ReadUInt16LittleEndian(array.AsSpan(2, 2)); result.Value = BinaryPrimitives.ReadUInt32LittleEndian(array.AsSpan(4, 8)); return result; } } [InjectToIl2Cpp(new Type[] { typeof(IReplicatorSupplier), typeof(ICaptureCallbackObject) })] private class ArchipelagoStateReplicator : Object { private const string s_name = "State Tracker Replicator"; private GameObject m_gameObject = new GameObject("State Tracker Replicator"); private SNet_Replicator m_replicator; private StateTracker m_owner; private SNet_PacketBufferBytes m_initStatePacket; private SNet_PacketBufferBytes m_scoutingUpdatePacket; private SNet_PacketBufferBytes m_generalStatePacket; private SNet_PacketBufferBytes m_recallStatePacket; private SNet_Packet m_interactionPacket; private SNet_PacketBufferBytes m_logPacket; public GameObject gameObject => m_gameObject; public string name => "State Tracker Replicator"; public IReplicator Replicator => ((Il2CppObjectBase)m_replicator).Cast(); public SNet_Replicator ConcreteReplicator => m_replicator; public ArchipelagoStateReplicator(IntPtr ptr) : base(ptr) { }//IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Expected O, but got Unknown public ArchipelagoStateReplicator(StateTracker owner) : base(ClassInjector.DerivedConstructorPointer()) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Expected O, but got Unknown //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Expected O, but got Unknown //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Expected O, but got Unknown ClassInjector.DerivedConstructorBody((Il2CppObjectBase)(object)this); m_owner = owner; m_replicator = ((Il2CppObjectBase)SNet_Replication.AddManagerReplicator(new IReplicatorSupplier(((Il2CppObjectBase)this).Pointer))).Cast(); SNet_SyncManager.RegisterCaptureCallback(new ICaptureCallbackObject(((Il2CppObjectBase)this).Pointer)); IntPtr il2CppMethod = IL2CPP.GetIl2CppMethod(((Il2CppObjectBase)this).ObjectClass, false, "OnReceiveInitState", typeof(void).FullName, new string[2] { typeof(Il2CppStructArray).FullName, typeof(BufferData).FullName }); m_initStatePacket = m_replicator.CreatePacketBytes(new Action, BufferData>((Object)(object)this, il2CppMethod)); il2CppMethod = IL2CPP.GetIl2CppMethod(((Il2CppObjectBase)this).ObjectClass, false, "OnReceiveScoutingUpdate", typeof(void).FullName, new string[2] { typeof(Il2CppStructArray).FullName, typeof(BufferData).FullName }); m_scoutingUpdatePacket = m_replicator.CreatePacketBytes(new Action, BufferData>((Object)(object)this, il2CppMethod)); il2CppMethod = IL2CPP.GetIl2CppMethod(((Il2CppObjectBase)this).ObjectClass, false, "OnReceiveGeneralState", typeof(void).FullName, new string[2] { typeof(Il2CppStructArray).FullName, typeof(BufferData).FullName }); m_generalStatePacket = m_replicator.CreatePacketBytes(new Action, BufferData>((Object)(object)this, il2CppMethod)); il2CppMethod = IL2CPP.GetIl2CppMethod(((Il2CppObjectBase)this).ObjectClass, false, "OnReceiveRecallState", typeof(void).FullName, new string[2] { typeof(Il2CppStructArray).FullName, typeof(BufferData).FullName }); m_recallStatePacket = m_replicator.CreatePacketBytes(new Action, BufferData>((Object)(object)this, il2CppMethod)); il2CppMethod = IL2CPP.GetIl2CppMethod(((Il2CppObjectBase)this).ObjectClass, false, "OnReceiveInteraction", typeof(void).FullName, new string[1] { typeof(pArtifactInventoryState).FullName }); m_interactionPacket = m_replicator.CreatePacket(new Action((Object)(object)this, il2CppMethod), (Action)null); il2CppMethod = IL2CPP.GetIl2CppMethod(((Il2CppObjectBase)this).ObjectClass, false, "OnReceiveLog", typeof(void).FullName, new string[2] { typeof(Il2CppStructArray).FullName, typeof(BufferData).FullName }); m_logPacket = m_replicator.CreatePacketBytes(new Action, BufferData>((Object)(object)this, il2CppMethod)); } public IReplicator GetReplicator() { return ((Il2CppObjectBase)m_replicator).Cast(); } public void OnStateCapture() { //IL_0056: Unknown result type (might be due to invalid IL or missing references) Il2CppStructArray val = m_owner.MakeGeneralState().ToBytes(6); Il2CppStructArray keyBytes = ((SNet_Packet)m_recallStatePacket).Replicator.KeyBytes; ((Il2CppArrayBase)(object)val)[0] = ((Il2CppArrayBase)(object)keyBytes)[0]; ((Il2CppArrayBase)(object)val)[1] = ((Il2CppArrayBase)(object)keyBytes)[1]; ((Il2CppArrayBase)(object)val)[2] = ((SNet_Packet)m_recallStatePacket).Index; keyBytes = SNet_PacketBufferBytes.GetBufferDataBytes(new BufferData((ushort)1, (byte)0)); ((Il2CppArrayBase)(object)val)[3] = ((Il2CppArrayBase)(object)keyBytes)[0]; ((Il2CppArrayBase)(object)val)[4] = ((Il2CppArrayBase)(object)keyBytes)[1]; ((Il2CppArrayBase)(object)val)[5] = ((Il2CppArrayBase)(object)keyBytes)[2]; SNet.Capture.PrimedBuffer.GetPass((eCapturePass)0).Add(val); } public pStateReplicatorProvider GetProviderSyncStruct() { //IL_0002: 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_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) pReplicator pRep = default(pReplicator); ((pReplicator)(ref pRep)).SetID(Replicator); return new pStateReplicatorProvider { pRep = pRep }; } private void OnReceiveInitState(Il2CppStructArray bytes, BufferData data) { pArchipelagoInitState state = pArchipelagoInitState.FromBytes(bytes); m_owner.ReceiveInitState(state); } private void OnReceiveScoutingUpdate(Il2CppStructArray bytes, BufferData data) { pArchipelagoScoutingUpdate update = pArchipelagoScoutingUpdate.FromBytes(bytes); m_owner.ReceiveScoutingUpdate(update); } private void OnReceiveGeneralState(Il2CppStructArray bytes, BufferData data) { pArchipelagoGeneralState state = pArchipelagoGeneralState.FromBytes(bytes); m_owner.ReceiveGeneralState(state, isRecall: false); } private void OnReceiveRecallState(Il2CppStructArray bytes, BufferData data) { pArchipelagoGeneralState state = pArchipelagoGeneralState.FromBytes(bytes); m_owner.ReceiveGeneralState(state, isRecall: true); } private void OnReceiveInteraction(pArtifactInventoryState bytes) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) pArchipelagoInteraction interaction = pArchipelagoInteraction.FromBytes(bytes); m_owner.ReceiveInteraction(interaction); } private void OnReceiveLog(Il2CppStructArray bytes, BufferData data) { int index = 0; string text = SerializationHelpers.ReadString(bytes, ref index); if (text != null) { LogForLobby(text, localOnly: true); } } public void SendInit(SNet_Player? player = null) { //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)player == (Object)null) { m_initStatePacket.Send(m_owner.MakeInitState().ToBytes(), SNet_PacketBufferBytes.GetBufferDataBytes(new BufferData((ushort)1, (byte)0)), (SNet_SendGroup)2, (SNet_SendQuality)2, 0); } else { m_initStatePacket.Send(m_owner.MakeInitState().ToBytes(), SNet_PacketBufferBytes.GetBufferDataBytes(new BufferData((ushort)1, (byte)0)), (SNet_SendQuality)2, 0, player); } } public void SendScouting(pArchipelagoScoutingUpdate? update = null, SNet_Player? player = null) { //IL_0081: 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) pArchipelagoScoutingUpdate valueOrDefault = update.GetValueOrDefault(); if (!update.HasValue) { valueOrDefault = m_owner.MakeScoutingUpdate(); update = valueOrDefault; } if (update.Value.LocationIDs.Length != 0) { if ((Object)(object)player == (Object)null) { m_scoutingUpdatePacket.Send(update.Value.ToBytes(), SNet_PacketBufferBytes.GetBufferDataBytes(new BufferData((ushort)1, (byte)0)), (SNet_SendGroup)2, (SNet_SendQuality)2, 0); } else { m_scoutingUpdatePacket.Send(update.Value.ToBytes(), SNet_PacketBufferBytes.GetBufferDataBytes(new BufferData((ushort)1, (byte)0)), (SNet_SendQuality)2, 0, player); } } } public void SendGeneral(SNet_Player? player = null) { //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)player == (Object)null) { m_generalStatePacket.Send(m_owner.MakeGeneralState().ToBytes(), SNet_PacketBufferBytes.GetBufferDataBytes(new BufferData((ushort)1, (byte)0)), (SNet_SendGroup)2, (SNet_SendQuality)2, 0); } else { m_generalStatePacket.Send(m_owner.MakeGeneralState().ToBytes(), SNet_PacketBufferBytes.GetBufferDataBytes(new BufferData((ushort)1, (byte)0)), (SNet_SendQuality)2, 0, player); } } public void SendInteraction(pArchipelagoInteraction interaction) { //IL_0008: Unknown result type (might be due to invalid IL or missing references) m_interactionPacket.Send(interaction.ToBytes(), (SNet_ChannelType)0, (SNet_SendQuality)3, (SNet_Player)null); } public void SendLog(string message, SNet_Player? player = null) { //IL_0046: 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) Il2CppStructArray val = new Il2CppStructArray((long)SerializationHelpers.CalcStringSize(message)); int index = 0; SerializationHelpers.WriteString(val, ref index, message); if ((Object)(object)player == (Object)null) { m_logPacket.Send(val, SNet_PacketBufferBytes.GetBufferDataBytes(new BufferData((ushort)1, (byte)0)), (SNet_SendGroup)2, (SNet_SendQuality)2, 4); } else { m_logPacket.Send(val, SNet_PacketBufferBytes.GetBufferDataBytes(new BufferData((ushort)1, (byte)0)), (SNet_SendQuality)2, 4, player); } } } private class UpdateStateEnumerator : IEnumerator { private StateTracker m_owner; public object Current => (object)new WaitForSecondsRealtime(60f); public UpdateStateEnumerator(StateTracker owner) { m_owner = owner; } public bool MoveNext() { if (m_owner.CurrentState == eState.HostConnected || m_owner.CurrentState == eState.FakeConnect) { m_owner.m_stateReplicator.SendGeneral(); } return true; } public void Reset() { } } [ArchivePatch(/*Could not decode attribute arguments.*/)] public static class SNet_SessionHub__AddPlayerToSession__Patch { public static void Prefix(SNet_SessionHub __instance, SNet_Player player) { if (SNet.IsMaster && !player.IsBot && !SNet.SessionHub.PlayersInSession.Any((SNet_Player p) => ((Il2CppObjectBase)p).Pointer == ((Il2CppObjectBase)player).Pointer)) { FeatureLogger.Notice("New player is joining session; sending init packet: " + player.NickName); Get().m_stateReplicator?.SendInit(player); } } } [ArchivePatch(/*Could not decode attribute arguments.*/)] public static class SNet_SessionHub__OnJoinedLobby__Patch { public static void Postfix(SNet_SessionHub __instance, SNet_Player player) { if (!SNet.IsMaster || player.IsBot) { return; } StateTracker stateTracker = Get(); if (stateTracker.ApSession != null) { FeatureLogger.Notice("Adding new player to session; sending sync packets: " + player.NickName); stateTracker.m_stateReplicator?.SendGeneral(player); ArchipelagoStateReplicator? stateReplicator = stateTracker.m_stateReplicator; if (stateReplicator != null) { stateReplicator.SendScouting(null, player); } } } } [ArchivePatch(/*Could not decode attribute arguments.*/)] public static class SNet_SessionHub__OnMasterSessionAnswer__Patch { public static bool Prefix(SNet_SessionHub __instance, pMasterAnswer data) { //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_004b: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) StateTracker stateTracker = Get(); if ((int)stateTracker.m_cachedMasterAnswer.answer == 0) { FeatureLogger.Notice("Client connection allowed!"); stateTracker.m_cachedMasterAnswer = new pMasterAnswer { answer = (pMasterSessionAnswerType)1 }; return true; } FeatureLogger.Notice("Received master answer; caching and blocking for now"); stateTracker.m_cachedMasterAnswer = data; return false; } } [ArchivePatch(/*Could not decode attribute arguments.*/)] public static class SNet_MasterManager__SearchForMigrationMaster__Patch { public static bool Prefix(SNet_Player masterPlayer) { if (((Il2CppObjectBase)masterPlayer).Pointer != ((Il2CppObjectBase)SNet.LocalPlayer).Pointer) { return true; } return Get().ApSession != null; } } private static IArchiveLogger? m_featureLogger = null; private Plugin? m_plugin; public static Version APVersion = new Version(1, 0, 0); private List GameTags = new List(2) { "DeathLink", "EnergyLink" }; protected Dictionary> m_queuedItemReplacements = new Dictionary>(); protected SortedList m_locationCheckContinuity = new SortedList(); private ArchipelagoStateReplicator? m_stateReplicator; public override string Name => "Archipelago Settings"; public override string Description => "Controls AP many import Archipelago settings."; public override FeatureGroup Group => ArchipelagoFeatureGroups.get_Archipelago(); public new static IArchiveLogger FeatureLogger { get { return m_featureLogger ?? ReTFO.Archipelago.Plugin.Get().Logger; } set { m_featureLogger = value; } } public Plugin Plugin { get { return m_plugin ?? (m_plugin = ReTFO.Archipelago.Plugin.Get()); } protected set { m_plugin = value; } } public MidManager MidManager => Plugin.MidManager; public Game.Data GameData => MidManager.GetProcessedGameData(); public ArchipelagoSession? ApSession { get; protected set; } public Guid SessionGuid { get; protected set; } protected Task? ConnectTask { get; set; } protected Task? LoginTask { get; set; } public long RootSeed { get; protected set; } protected HashSet m_regionWhitelist { get; set; } = new HashSet(); protected HashSet m_regionBlacklist { get; set; } = new HashSet(); protected HashSet m_locationWhitelist { get; set; } = new HashSet(); protected HashSet m_locationBlacklist { get; set; } = new HashSet(); protected HashSet m_itemWhitelist { get; set; } = new HashSet(); protected HashSet m_itemBlacklist { get; set; } = new HashSet(); protected List<(LocationID, ItemID)> m_filledEmptyLocations { get; set; } = new List<(LocationID, ItemID)>(); protected SortedList m_goalItemCounts { get; set; } = new SortedList(); public int SkippableGoalCount { get; protected set; } public IReadOnlySet RegionWhitelist => m_regionWhitelist; public IReadOnlySet RegionBlacklist => m_regionBlacklist; public IReadOnlySet LocationWhitelist => m_locationWhitelist; public IReadOnlySet LocationBlacklist => m_locationBlacklist; public IReadOnlySet ItemWhitelist => m_itemWhitelist; public IReadOnlySet ItemBlacklist => m_itemBlacklist; public IReadOnlyList<(LocationID, ItemID)> FilledEmptyLocations => m_filledEmptyLocations; public IReadOnlyDictionary GoalItemCounts => m_goalItemCounts; protected HashSet m_foundRegion { get; init; } = new HashSet(); protected HashSet m_foundUnusedRegions { get; init; } = new HashSet(); protected HashSet m_foundLocations { get; init; } = new HashSet(); protected HashSet m_trashedLocations { get; init; } = new HashSet(); protected Dictionary m_collectedItemCounts { get; init; } = new Dictionary(); protected Dictionary m_sessionItemCounts { get; init; } = new Dictionary(); public List<(ItemID, string)> ItemsInTerminalSystem { get; init; } = new List<(ItemID, string)>(); public IReadOnlySet FoundRegion => m_foundRegion; public IReadOnlySet FoundUnusedRegions => m_foundUnusedRegions; public IReadOnlySet FoundLocations => m_foundLocations; public IReadOnlySet TrashedLocations => m_trashedLocations; public IReadOnlyDictionary CollectedItemCounts => m_collectedItemCounts; public IReadOnlyDictionary SessionItemCounts => m_sessionItemCounts; public IReadOnlyDictionary> QueuedItemReplacements => m_queuedItemReplacements; public eState CurrentState { get; set; } [FeatureConfig] public static Settings Config { get; set; } = null; private pMasterAnswer m_cachedMasterAnswer { get; set; } = new pMasterAnswer { answer = (pMasterSessionAnswerType)1 }; public event Action? OnStateChange; public static StateTracker Get() { return ReTFO.Archipelago.Plugin.Get().StateTracker; } public override void OnEnable() { base.OnEnable(); Plugin.StateTracker = this; } public void FakeConnect() { if (CurrentState != eState.CleanState) { LogErrorForLobby("Cannot start fake connection; already in state: " + Enum.GetName(CurrentState)); return; } Game.Data data = GameData; CurrentState = eState.FakeConnect; RootSeed = 0L; m_regionWhitelist = new HashSet { Expedition.get_Region_AllExpeditions(data) }; m_regionBlacklist = new HashSet(); m_locationWhitelist = new HashSet { CommonTagsHandler_Tags.get_Location_All(data) }; m_locationBlacklist = new HashSet(); m_itemWhitelist = new HashSet { CommonTagsHandler_Tags.get_Item_All(data) }; m_itemBlacklist = new HashSet { CommonTagsHandler_Tags.get_Item_Scans(data), UnlockExpeditionHandler_Tags.get_Item_FloatingExpeditionUnlocks(data), LockLobbySlotsHandler_Tags.get_Item_LobbySlotUnlocks(data) }; m_goalItemCounts = new SortedList(); SkippableGoalCount = 0; foreach (KeyValuePair allValue in data.Locations.GetAllValues()) { Location value = allValue.Value; if (value != null && value.RandData.IsEmpty) { allValue.Value.SetItem(default(ItemID)); } } HashSet reachableRegions = (from r in data.Regions.GetAllValues().Where(regionTest) select r.Key).ToHashSet(); Queue queue = new Queue(from pair in data.GetAllFloatingItems().Where(itemTest) select pair.Item2); reachableRegions.RemoveWhere((RegionID r) => !data.Regions.LookUpValue(r).Reachable); List locations = (from l in data.Locations.GetAllValuesNonNull().Where(locationTest) select l.Key).ToList(); m_filledEmptyLocations = DistributeItems(locations, queue); SetupMultiworld(); if (queue.Count > 0) { LogErrorForLobby($"Insufficient empty locations for selected floating items. Granting {queue.Count} free items!"); foreach (ItemID item in queue) { CollectItem(item); } } foreach (KeyValuePair item2 in data.Locations.GetAllValuesNonNull()) { if (!item2.Value.ItemID.IsNull && data.Items.IsChild(item2.Value.ItemID, SharedObjectiveHandler_Tags.get_Item_SectorClears(data))) { m_goalItemCounts[item2.Value.ItemID] = m_goalItemCounts.GetValueOrDefault(item2.Value.ItemID, 0) + 1; } } FeatureLogger.Notice("Due to fake connect, removing all expedition locks."); UnlockExpeditionHandler.UnlockAll(); bool itemTest((RegionID, ItemID) item) { if (reachableRegions.Contains(item.Item1) && data.Items.IsChild(item.Item2, m_itemWhitelist)) { return !data.Items.IsChild(item.Item2, m_itemBlacklist); } return false; } bool locationTest(KeyValuePair l) { if (l.Value.RandData.IsEmpty && l.Value.OwningRegionIDs.All(reachableRegions.Contains) && data.Locations.IsChild(l.Key, m_locationWhitelist)) { return !data.Locations.IsChild(l.Key, m_locationBlacklist); } return false; } bool regionTest(KeyValuePair r) { if (data.Regions.IsChild(r.Key, m_regionWhitelist)) { return !data.Regions.IsChild(r.Key, m_regionBlacklist); } return false; } } public void ClientConnect(pArchipelagoInitState state) { //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_0018: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0238: Unknown result type (might be due to invalid IL or missing references) if ((int)m_cachedMasterAnswer.answer != 0) { FeatureLogger.Notice("Ignoring init packet; master answer was " + Enum.GetName(m_cachedMasterAnswer.answer)); return; } if (CurrentState == eState.ConnectedClient || CurrentState == eState.ProxyClient) { FeatureLogger.Notice("Ignoring init packet; already set up as a client"); return; } if (state.GameName != GameData.Name) { FeatureLogger.Error("Cannot connect as client; the host is playing with different mods than us!"); return; } FeatureLogger.Notice("Received init packet. Preparing to join as client..."); if (CurrentState == eState.CleanState) { FeatureLogger.Notice("Joining as proxy client..."); RootSeed = state.RootSeed; m_regionWhitelist = state.RegionWhitelist.Select((uint i) => new RegionID { ID = i }).ToHashSet(); m_regionBlacklist = state.RegionBlacklist.Select((uint i) => new RegionID { ID = i }).ToHashSet(); m_locationWhitelist = state.LocationWhitelist.Select((uint i) => new LocationID { ID = i }).ToHashSet(); m_locationBlacklist = state.LocationBlacklist.Select((uint i) => new LocationID { ID = i }).ToHashSet(); m_itemWhitelist = state.ItemWhitelist.Select((uint i) => new ItemID { ID = i }).ToHashSet(); m_itemBlacklist = state.ItemBlacklist.Select((uint i) => new ItemID { ID = i }).ToHashSet(); CurrentState = eState.ProxyClient; SetupMultiworld(); } else { FeatureLogger.Notice("Joining as a connected client..."); if (RootSeed != state.RootSeed) { FeatureLogger.Error("Refused to join as client; root seeds do not match! This indicates the host is connected to a different slot or server."); return; } CurrentState = eState.ConnectedClient; } SNet.SessionHub.OnMasterSessionAnswer(m_cachedMasterAnswer); FeatureLogger.Success("Successfully joined!"); } public void Connect() { //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Expected O, but got Unknown if (Config.UseDebugMode) { FakeConnect(); return; } if (CurrentState != eState.CleanState) { LogErrorForLobby("Cannot start new connection; already in state: " + Enum.GetName(CurrentState)); return; } if (ConnectTask != null) { LogWarningForLobby("Cannot start new connection; currently waiting to connect to Archipelago"); return; } CurrentState = eState.HostConnecting; SessionGuid = Guid.NewGuid(); ApSession = ArchipelagoSessionFactory.CreateSession(Config.ServerAddress, (int)Config.Port); ApSession.Locations.CheckedLocationsUpdated += (CheckedLocationsUpdatedHandler)delegate(ReadOnlyCollection locs) { foreach (long loc in locs) { m_foundLocations.Add(new LocationID { ID = checked((uint)loc) }); } RundownHandler.UpdateAllCounts(); }; ConnectTask = ApSession.ConnectAsync(); } protected void HandleFailedConnection(string debugName, Exception? exception) { LogErrorForLobby("Failed to " + debugName + " to Archipelago Host!"); if (exception != null) { LogForLobby("View the log for details.", localOnly: true); FeatureLogger.Error("Encountered the following exception:"); FeatureLogger.Exception(exception); } if (CurrentState == eState.HostConnecting) { ApSession = null; CurrentState = eState.CleanState; } else if (CurrentState == eState.HostReconnecting) { ConnectTask = ReconnectDelayed(); } else { LogErrorForLobby(" -> Failed to " + debugName + " while not in connecting state?"); } } protected async Task ReconnectDelayed(int delay = 2500) { FeatureLogger.Notice("Attempting to reconnect to Archipelago Host..."); await Task.Delay(delay).ConfigureAwait(continueOnCapturedContext: false); return await ApSession.ConnectAsync().ConfigureAwait(continueOnCapturedContext: false); } public void HandleConnectionResult(Task connectResult) { ConnectTask = null; if (!connectResult.IsCompletedSuccessfully) { ArchipelagoSession? apSession = ApSession; string text = ((apSession != null) ? apSession.Socket.Uri.ToString() : null) ?? "null!"; HandleFailedConnection("connect", Config.HideConnectionDetails ? new Exception("Exception hidden because HideConnectionDetails is enabled!") : connectResult.Exception); if (Config.HideConnectionDetails) { LogErrorForLobby("Connection debug hidden due to HideConnectionDetails"); return; } LogErrorForLobby($"Address: {Config.ServerAddress}:{Config.Port}"); LogErrorForLobby("Calculated URI: " + text); } else { string name = GameData.Name; LoginTask = ApSession.LoginAsync((name == null) ? "GTFO" : ("GTFO (" + name + ")"), Config.Username, (ItemsHandlingFlags)7, (Version)null, GameTags.ToArray(), SessionGuid.ToString(), Config.HasPassword ? Config.Password : null, true); } } protected void HandleLoginResult(Task loginTask) { LoginTask = null; if (!loginTask.IsCompletedSuccessfully) { HandleFailedConnection("login", Config.HideConnectionDetails ? new Exception("Exception hidden because HideConnectionDetails is enabled!") : loginTask.Exception); return; } LoginResult result = loginTask.Result; if (ApSession == null) { throw new NullReferenceException("ApSession"); } checked { if (result.Successful) { LoginSuccessful val = (LoginSuccessful)(object)((result is LoginSuccessful) ? result : null); if (val != null) { ApSession.SetClientState((ArchipelagoClientState)20); try { RootSeed = (long)(val.SlotData.GetValueOrDefault("root_seed", null) ?? throw new NullReferenceException("Failed to retrieve root_seed from slot data")); object valueOrDefault = val.SlotData.GetValueOrDefault("region_whitelist", null); object obj = ((valueOrDefault is JArray) ? valueOrDefault : null); m_regionWhitelist = new HashSet(((obj == null) ? null : ((JToken)obj).ToObject>()?.Select((long l) => new RegionID { ID = (uint)l })) ?? throw new NullReferenceException("Failed to retrieve region_whitelist from slot data")); object valueOrDefault2 = val.SlotData.GetValueOrDefault("region_blacklist", null); object obj2 = ((valueOrDefault2 is JArray) ? valueOrDefault2 : null); m_regionBlacklist = new HashSet(((obj2 == null) ? null : ((JToken)obj2).ToObject>()?.Select((long l) => new RegionID { ID = (uint)l })) ?? throw new NullReferenceException("Failed to retrieve region_blacklist from slot data")); object valueOrDefault3 = val.SlotData.GetValueOrDefault("location_whitelist", null); object obj3 = ((valueOrDefault3 is JArray) ? valueOrDefault3 : null); m_locationWhitelist = new HashSet(((obj3 == null) ? null : ((JToken)obj3).ToObject>()?.Select((long l) => new LocationID { ID = (uint)l })) ?? throw new NullReferenceException("Failed to retrieve location_whitelist from slot data")); object valueOrDefault4 = val.SlotData.GetValueOrDefault("location_blacklist", null); object obj4 = ((valueOrDefault4 is JArray) ? valueOrDefault4 : null); m_locationBlacklist = new HashSet(((obj4 == null) ? null : ((JToken)obj4).ToObject>()?.Select((long l) => new LocationID { ID = (uint)l })) ?? throw new NullReferenceException("Failed to retrieve location_blacklist from slot data")); object valueOrDefault5 = val.SlotData.GetValueOrDefault("item_whitelist", null); object obj5 = ((valueOrDefault5 is JArray) ? valueOrDefault5 : null); m_itemWhitelist = new HashSet(((obj5 == null) ? null : ((JToken)obj5).ToObject>()?.Select((long l) => new ItemID { ID = (uint)l })) ?? throw new NullReferenceException("Failed to retrieve item_whitelist from slot data")); object valueOrDefault6 = val.SlotData.GetValueOrDefault("item_blacklist", null); object obj6 = ((valueOrDefault6 is JArray) ? valueOrDefault6 : null); m_itemBlacklist = new HashSet(((obj6 == null) ? null : ((JToken)obj6).ToObject>()?.Select((long l) => new ItemID { ID = (uint)l })) ?? throw new NullReferenceException("Failed to retrieve item_blacklist from slot data")); object valueOrDefault7 = val.SlotData.GetValueOrDefault("filled_empty_locations", null); object obj7 = ((valueOrDefault7 is JArray) ? valueOrDefault7 : null); m_filledEmptyLocations = ((obj7 == null) ? null : ((JToken)obj7).ToObject>>()?.Select((List l) => (new LocationID { ID = (uint)l[0] }, new ItemID { ID = (uint)l[1] }))?.ToList()) ?? throw new NullReferenceException("Failed to retrieve filled_empty_locations from slot data"); object valueOrDefault8 = val.SlotData.GetValueOrDefault("goal_items", null); object obj8 = ((valueOrDefault8 is JArray) ? valueOrDefault8 : null); IEnumerable<(ItemID, long)> enumerable = ((obj8 == null) ? null : ((JToken)obj8).ToObject>>()?.Select((List l) => (new ItemID { ID = (uint)l[0] }, l[1]))) ?? throw new NullReferenceException("Failed to retrieve goal_items from slot data"); m_goalItemCounts = new SortedList(); foreach (var item in enumerable) { m_goalItemCounts[item.Item1] = (int)item.Item2; } SkippableGoalCount = unchecked((int)(long)(val.SlotData.GetValueOrDefault("skippable_goal_count", null) ?? throw new NullReferenceException("Failed to retrieve skippable_goal_count from slot data"))); if (m_goalItemCounts.Sum((KeyValuePair pair) => pair.Value) <= SkippableGoalCount) { ApSession.SetClientState((ArchipelagoClientState)30); FeatureLogger.Success("Congratulations, you have won the game!"); } } catch (Exception ex) { LogForLobby("Encountered error while retrieving slot data; view log for exception details.", localOnly: true); FeatureLogger.Error("Encountered error while retrieving slot data:"); FeatureLogger.Exception(ex); Reset(); return; } if (CurrentState == eState.HostConnecting) { CurrentState = eState.HostConnected; SetupMultiworld(); ApSession.SetClientState((ArchipelagoClientState)10); } else if (CurrentState == eState.HostReconnecting) { m_sessionItemCounts.Clear(); CurrentState = eState.HostConnected; ApSession.SetClientState((ArchipelagoClientState)20); LogForLobby("<#0F0>Sucessfully reconnected!", localOnly: false); } m_foundLocations.UnionWith(ApSession.Locations.AllLocationsChecked.Select((long v) => new LocationID { ID = (uint)v })); return; } } HandleFailedConnection("authenticate", null); if (Config.HideConnectionDetails) { FeatureLogger.Error("Connection debug is hidden because HideConnectionDetails is enabled."); return; } LoginFailure val2 = (LoginFailure)(object)((result is LoginFailure) ? result : null); if (val2 != null) { string[] errors = val2.Errors; foreach (string text in errors) { FeatureLogger.Error(" -> Error response: " + text); } } FeatureLogger.Error("Tried to connect with following information:"); FeatureLogger.Error("Username: " + Config.Username); FeatureLogger.Error(Config.HasPassword ? ("Password: " + Config.Password) : "No password"); string name = GameData.Name; FeatureLogger.Error("Game: " + ((name == null) ? "GTFO" : ("GTFO (" + name + ")"))); } } protected void SetupMultiworld() { Game.Data data = GameData; m_regionWhitelist.Add(CommonTagsHandler_Tags.get_Region_Always(data)); m_regionBlacklist.Add(CommonTagsHandler_Tags.get_Region_Never(data)); m_locationWhitelist.Add(CommonTagsHandler_Tags.get_Location_Always(data)); m_locationBlacklist.Add(CommonTagsHandler_Tags.get_Location_Never(data)); m_itemWhitelist.Add(CommonTagsHandler_Tags.get_Item_Always(data)); m_itemBlacklist.Add(CommonTagsHandler_Tags.get_Item_Never(data)); RundownHandler.OverwriteRundowns(this); m_foundRegion.Clear(); m_foundUnusedRegions.Clear(); m_foundLocations.Clear(); m_trashedLocations.Clear(); m_collectedItemCounts.Clear(); m_sessionItemCounts.Clear(); ItemsInTerminalSystem.Clear(); m_queuedItemReplacements.Clear(); foreach (RegionID allID in data.Regions.GetAllIDs()) { data.SetRegionRandomized(allID, isRandomized: false); } HashSet hashSet = new HashSet(); foreach (RegionID item4 in m_regionWhitelist) { if (!data.Regions.IsChild(item4, m_regionBlacklist)) { hashSet.Add(item4); data.SetRegionRandomized(item4, isRandomized: true); } } foreach (RegionID allID2 in data.Regions.GetAllIDs()) { if (data.Regions.LookUpDefinition(allID2).AllParents.Any(hashSet.Contains) && !m_regionBlacklist.Contains(allID2)) { hashSet.Add(allID2); data.SetRegionRandomized(allID2, isRandomized: true); } } hashSet.RemoveWhere((RegionID r) => !data.Regions.LookUpValue(r).Reachable); HashSet reachableRegionIDs = (from p in data.Regions.GetAllValues() where p.Value.Reachable && data.Regions.IsChild(p.Key, m_regionWhitelist) && !data.Regions.IsChild(p.Key, m_regionBlacklist) select p.Key).ToHashSet(); List> list = (from l in data.Locations.GetAllValuesNonNull() where l.Value.OwningRegionIDs.All((RegionID id) => reachableRegionIDs.Contains(id)) select l).ToList(); foreach (KeyValuePair item5 in data.Items.GetAllValuesNonNull()) { item5.Value.UpdateRandomization(data.Items.IsChild(item5.Key, m_itemWhitelist), data.Items.IsChild(item5.Key, m_itemBlacklist)); } foreach (KeyValuePair item6 in data.Locations.GetAllValuesNonNull()) { if (item6.Value.RandData.IsEmpty) { item6.Value.SetItem(default(ItemID)); } else if (item6.Value.ItemID.IsNull) { FeatureLogger.Error($"Found non-empty location with null item: [{item6.Key}] {data.Locations.LookUpName(item6.Key)}"); } item6.Value.UpdateRandomization(isReachable: false, data.Locations.IsChild(item6.Key, m_locationWhitelist), data.Locations.IsChild(item6.Key, m_locationBlacklist), isRandomized: false, isRandomlike: false); } foreach (var filledEmptyLocation in m_filledEmptyLocations) { Location location = data.Locations.LookUpValue(filledEmptyLocation.Item1); if (location == null) { FeatureLogger.Error("Received filled location ID points to a null location!"); } else if (!location.RandData.IsEmpty) { FeatureLogger.Error("Received filled location ID points to a non-empty location!"); } else { location.SetItem(filledEmptyLocation.Item2); } } foreach (KeyValuePair item7 in list) { item7.Value.UpdateReachable(isReachable: true); if (item7.Value.ItemID.IsNull) { continue; } Item item = data.Items.LookUpValueChecked(item7.Value.ItemID); bool flag = (item7.Value.RandData.IsWhitelisted || item.RandData.IsWhitelisted) && !item7.Value.RandData.IsBlacklisted && !item.RandData.IsBlacklisted; item7.Value.UpdateRandomized(flag, !flag && item.RandData.IsRandomLike); if (item.RandData.IsCollectedByDefault && !item7.Value.RandData.IsEmpty) { if (item7.Value.RandData.IsTreatedAsRandom) { item.OnItemLost(this, item7.Value.ItemID); } else { m_collectedItemCounts[item7.Value.ItemID] = m_collectedItemCounts.GetValueOrDefault(item7.Value.ItemID, 0) + 1; } } } foreach (var allFloatingItem in data.GetAllFloatingItems()) { ItemID item2 = allFloatingItem.Item2; if (item2.IsNull) { FeatureLogger.Error($"Floating item ID is null, but should not be! {allFloatingItem.Item1}"); continue; } Item item3 = data.Items.LookUpValueChecked(allFloatingItem.Item2); if (item3.RandData.IsCollectedByDefault) { bool flag2 = data.Regions.IsChild(allFloatingItem.Item1, m_regionWhitelist) && !data.Regions.IsChild(allFloatingItem.Item1, m_regionBlacklist); if (item3.RandData.CanBeRandomized || !flag2) { item3.OnItemLost(this, allFloatingItem.Item2); } else { m_collectedItemCounts[allFloatingItem.Item2] = m_collectedItemCounts.GetValueOrDefault(allFloatingItem.Item2, 0) + 1; } } } if (ApSession != null) { List> list2 = list.Where((KeyValuePair l) => l.Value.RandData.IsRandomized).ToList(); long[] array = new long[list2.Count]; for (int num = 0; num < list2.Count; num++) { array[num] = list2[num].Key.ID; } ApSession.Locations.ScoutLocationsAsync((HintCreationPolicy)0, array).ContinueWith(OnLocationsScouted); } NotifyFoundRegion(data.Region_Menu, PlayerManager.GetLocalPlayerAgent()); this.OnStateChange?.Invoke(this); } public void Reset() { ArchipelagoSession? apSession = ApSession; if (apSession != null) { apSession.Socket.DisconnectAsync(); } ApSession = null; ConnectTask = null; LoginTask = null; SNet.Lobbies.LeaveLobby(); uint num = ((Il2CppArrayBase)(object)Global.ActiveRundownIds)[0]; Global.ActiveRundownIds = new Il2CppStructArray(1L); ((Il2CppArrayBase)(object)Global.ActiveRundownIds)[0] = num; MainMenuGuiLayer.Current.PageRundownNew.m_isRevealing = false; MainMenuGuiLayer.Current.PageRundownNew.m_rundownIsRevealed = false; MainMenuGuiLayer.Current.PageRundownNew.m_selectionIsRevealed = false; MainMenuGuiLayer.Current.PageRundownNew.m_dataIsSetup = false; MainMenuGuiLayer.Current.PageRundownNew.m_rundownIntroIsDone = false; MainMenuGuiLayer.Current.PageRundownNew.m_cortexIntroIsDone = false; MainMenuGuiLayer.Current.PageRundownNew.m_selectRundownButton.OnBtnPressCallback.Invoke(0); ((CM_PageBase)MainMenuGuiLayer.Current.PageRundownNew).PostSetup(); MainMenuGuiLayer.Current.ChangePage((eCM_MenuPage)9, false); MainMenuGuiLayer.Current.PageRundownNew.m_selectionIsRevealed = true; Game.Data gameData = GameData; foreach (ItemID item3 in CollectedItemCounts.SelectMany((KeyValuePair pair) => Enumerable.Repeat(pair.Key, pair.Value))) { Item item = gameData.Items.LookUpValue(item3); if (item != null && !item.RandData.IsCollectedByDefault) { item.OnItemLost(this, item3); } } foreach (var allFloatingItem in gameData.GetAllFloatingItems()) { Item item2 = gameData.Items.LookUpValueChecked(allFloatingItem.Item2); if (item2.RandData.IsCollectedByDefault) { int valueOrDefault = m_collectedItemCounts.GetValueOrDefault(allFloatingItem.Item2, 0); if (valueOrDefault > 0) { m_collectedItemCounts[allFloatingItem.Item2] = valueOrDefault - 1; } else { CollectItem(allFloatingItem.Item2); } } } m_collectedItemCounts.Clear(); m_sessionItemCounts.Clear(); CurrentState = eState.CleanState; this.OnStateChange?.Invoke(this); } public bool IsItemRandomized(RegionID owningRegion, ItemID item) { Game.Data gameData = GameData; if (!gameData.Regions.IsChild(owningRegion, m_regionWhitelist) || gameData.Regions.IsChild(owningRegion, m_regionBlacklist)) { return false; } Item item2 = gameData.Items.LookUpValue(item); if (item2 == null) { if (gameData.Items.IsChild(item, m_itemWhitelist)) { return !gameData.Items.IsChild(item, m_itemBlacklist); } return false; } return item2.RandData.CanBeRandomized; } public void NotifyFoundRegion(string name, PlayerAgent? player, bool skipInteraction = false) { Game.Data gameData = GameData; if (!gameData.Regions.TryLookUpID(name, out var id)) { if (!m_foundUnusedRegions.Add(name)) { FeatureLogger.Debug("Ignoring region because it is not registered: " + name); } } else { NotifyFoundRegion(id, player, skipInteraction); } } public void NotifyFoundRegion(RegionID regionId, PlayerAgent? player, bool skipInteraction = false) { Game.Data data = GameData; Region region = data.Regions.LookUpValue(regionId); if (m_foundRegion.Add(regionId)) { FeatureLogger.Debug($"Discovered region [{regionId.ID}] {data.Regions.LookUpName(regionId)}"); LocationID[] array = region.ConnectedLocations.Where(isFoundLocation).ToArray(); if (array.Length != 0) { NotifyFoundLocations(array, player); } } bool isFoundLocation(LocationID locID) { if (m_foundLocations.Contains(locID)) { return false; } Location location = data.Locations.LookUpValueChecked(locID); if (!location.RandData.IsAutoDiscovered) { return false; } if (location.OwningRegionIDs.Any((RegionID r) => !m_foundRegion.Contains(r))) { return false; } return true; } } public Location NotifyFoundLocation(LocationID id, PlayerAgent? player, bool force = false, bool skipInteraction = false) { Game.Data gameData = GameData; Location location = gameData.Locations.LookUpValueChecked(id); if (!m_foundLocations.Add(id)) { return location; } FeatureLogger.Debug($"Discovered Location: [{id.ID}] {gameData.Locations.LookUpName(id)}"); if (!skipInteraction) { SendInteraction(pArchipelagoInteraction.eType.CheckLocation, id.ID, 0); } if (CurrentState == eState.FakeConnect && location.RandData.IsTreatedAsRandom) { CollectItem(location.ItemID, id, player); LogForLobby("Collected item " + gameData.Items.LookUpName(location.ItemID) + " from FakeConnect", localOnly: false); RundownHandler.UpdateAllCounts(); } else if ((Object)(object)player != (Object)null && location.RandData.IsRandomlike) { m_locationCheckContinuity.Add(id, player); } if (ApSession != null) { ApSession.Locations.CompleteLocationChecksAsync(new long[1] { id.ID }).ContinueWith(OnLocationChecksCompleted); } RundownHandler.UpdateAllCounts(); return location; } public void NotifyFoundLocations(IEnumerable ids, PlayerAgent? player, bool force = false, bool skipInteraction = false) { Game.Data gameData = GameData; List list = new List(); foreach (LocationID id in ids) { Location location = gameData.Locations.LookUpValueChecked(id); if (!(!m_foundLocations.Add(id) || force)) { FeatureLogger.Debug($"Discovered Location: [{id.ID}] {gameData.Locations.LookUpName(id)}"); if (!skipInteraction) { SendInteraction(pArchipelagoInteraction.eType.CheckLocation, id.ID, 0); } if (location.RandData.IsTreatedAsRandom && CurrentState == eState.FakeConnect) { CollectItem(location.ItemID, id, player); LogForLobby("Collected item " + gameData.Items.LookUpName(location.ItemID) + " from FakeConnect", localOnly: false); } else if ((Object)(object)player != (Object)null && location.RandData.IsRandomlike) { m_locationCheckContinuity.Add(id, player); } if (ApSession != null) { list.Add(id.ID); } } } if (ApSession != null && list.Count > 0) { ApSession.Locations.CompleteLocationChecksAsync(list.ToArray()).ContinueWith(OnLocationChecksCompleted); } RundownHandler.UpdateAllCounts(); } public void ScoutLocation(LocationID id, HintCreationPolicy hintType = (HintCreationPolicy)2) { //IL_001f: Unknown result type (might be due to invalid IL or missing references) SendInteraction(pArchipelagoInteraction.eType.ScoutLocation, id.ID, 0); ArchipelagoSession? apSession = ApSession; if (apSession != null) { apSession.Locations.ScoutLocationsAsync(hintType, new long[1] { id.ID }); } } public void ScoutLocations(IEnumerable ids, HintCreationPolicy hintType = (HintCreationPolicy)2) { //IL_0043: Unknown result type (might be due to invalid IL or missing references) foreach (LocationID id in ids) { SendInteraction(pArchipelagoInteraction.eType.ScoutLocation, id.ID, 0); } ArchipelagoSession? apSession = ApSession; if (apSession != null) { apSession.Locations.ScoutLocationsAsync(hintType, ids.Select((Func)((LocationID id) => id.ID)).ToArray()); } } public void MarkAsTrash(IEnumerable ids, PlayerAgent? player, bool skipInteraction = false) { foreach (LocationID id in ids) { if (m_trashedLocations.Add(id) && !skipInteraction) { SendInteraction(pArchipelagoInteraction.eType.MarkTrash, id.ID, 0); } } RundownHandler.UpdateAllCounts(); } protected List<(LocationID, ItemID)> DistributeItems(IReadOnlyList locations, Queue items) { if (items.Count == 0) { return new List<(LocationID, ItemID)>(); } Game.Data gameData = GameData; double num = 0.2; double num2 = ((items.Count >= locations.Count) ? 1.0 : ((double)items.Count / (double)locations.Count)); long num3 = locations.Count; List<(LocationID, ItemID)> list = new List<(LocationID, ItemID)>(); for (long num4 = 0L; num4 < num3; num4++) { num += num2; if (num >= 1.0) { int index = (int)((num4 + Math.Abs(RootSeed)) % num3); LocationID locationID = locations[index]; ItemID itemID = items.Dequeue(); gameData.Locations.LookUpValueChecked(locationID).SetItem(itemID); list.Add((locationID, itemID)); num -= 1.0; } } return list; } protected void OnLocationChecksCompleted(Task task) { if (!task.IsCompletedSuccessfully) { FeatureLogger.Error("Failed to complete location checks! Retry not currently implemented..."); } } public void RescoutLocations() { Game.Data gameData = GameData; long[] array = (from pair in gameData.Locations.GetAllValuesNonNull() where pair.Value.RandData.IsReachable select pair).Select((Func, long>)((KeyValuePair l) => l.Key.ID)).ToArray(); FeatureLogger.Debug($"Sending location scout request for {array.Length} locations"); ApSession.Locations.ScoutLocationsAsync((HintCreationPolicy)0, array).ContinueWith(OnLocationsScouted); } protected void OnLocationsScouted(Task> task) { Game.Data gameData = GameData; if (!task.IsCompletedSuccessfully) { FeatureLogger.Error("Failed to scout locations!"); RescoutLocations(); return; } FeatureLogger.Debug($"Successfully scouted {task.Result.Count} locations"); foreach (KeyValuePair item in task.Result) { Location location = gameData.Locations.LookUpValueChecked(new LocationID { ID = checked((uint)((ItemInfo)item.Value).LocationId) }); location.ScoutedItemName = ((ItemInfo)item.Value).ItemDisplayName; location.ScoutedPlayerName = item.Value.Player.Name; location.ScoutedGameName = ((ItemInfo)item.Value).ItemGame; } m_stateReplicator.SendScouting(FormatScoutingUpdate(task.Result.Select, LocationID>((KeyValuePair pair) => new LocationID { ID = (uint)((ItemInfo)pair.Value).LocationId }))); } public bool HasLocation(string name, bool includeTrash = true) { if (GameData.Locations.TryLookUpID(name, out var id)) { return HasLocation(id, includeTrash); } return false; } public bool HasLocation(LocationID id, bool includeTrash = true) { if (!m_foundLocations.Contains(id)) { if (includeTrash) { return m_trashedLocations.Contains(id); } return false; } return true; } public void CollectItem(ItemID id, LocationID sourceLocationId = default(LocationID), PlayerAgent? player = null, bool skipInteraction = false) { Game.Data gameData = GameData; if (m_queuedItemReplacements.TryGetValue(id, out Queue value)) { if (value.Count < 1) { throw new NotSupportedException(); } if (value.Count == 1) { m_queuedItemReplacements.Remove(id); } id = value.Dequeue(); } int num = m_collectedItemCounts.GetValueOrDefault(id, 0) + 1; m_collectedItemCounts[id] = num; Item item = gameData.Items.LookUpValue(id); if (item == null) { FeatureLogger.Error($"Collecting null item: {id} {gameData.Items.LookUpName(id)}"); } else { FeatureLogger.Debug($"Collecting item [{id.ID}] {gameData.Items.LookUpName(id)}"); item.OnItemObtained(this, sourceLocationId, player, id); } if (SNet.IsMaster && m_goalItemCounts.ContainsKey(id)) { m_goalItemCounts[id]--; if (m_goalItemCounts.Sum((KeyValuePair pair) => pair.Value) <= SkippableGoalCount) { ArchipelagoSession? apSession = ApSession; if (apSession != null) { apSession.SetClientState((ArchipelagoClientState)30); } FeatureLogger.Success("Congratulations, you have won the game!"); } } if (!skipInteraction) { SendInteraction(pArchipelagoInteraction.eType.CollectItem, id.ID, (ushort)num); } } public void ReplaceItem(ItemID sourceItem, ItemID targetItem) { if (m_queuedItemReplacements.TryGetValue(targetItem, out Queue value)) { value.Enqueue(sourceItem); } else { value = new Queue(); value.Enqueue(sourceItem); m_queuedItemReplacements[targetItem] = value; } UncollectItem(sourceItem); CollectItem(targetItem, default(LocationID), null, skipInteraction: true); } public void UncollectItem(ItemID id) { int valueOrDefault = m_collectedItemCounts.GetValueOrDefault(id, 0); if (valueOrDefault <= 0) { FeatureLogger.Error($"Cannot uncollect item; it is not currently collected! {id} {GameData.Items.LookUpName(id)}"); } else { m_collectedItemCounts[id] = valueOrDefault - 1; GameData.Items.LookUpValue(id)?.OnItemLost(this, id); } } public void AddItemToTerminal(ItemID item) { Random random = new Random((RootSeed, item).GetHashCode()); string newCode; do { newCode = $"{r()}{r()}{r()}-{r()}{r()}{r()}-{r()}{r()}{r()}"; } while (ItemsInTerminalSystem.Any<(ItemID, string)>(((ItemID, string) pair) => pair.Item2 == newCode)); ItemsInTerminalSystem.Add((item, newCode)); char r() { int num = random.Next(35); return (char)((num >= 10) ? (65 + (num - 10)) : (48 + num)); } } public override void Update() { if (Input.GetKeyDown((KeyCode)106)) { RundownHandler.UpdateAllCounts(); } Task? connectTask = ConnectTask; if (connectTask != null && connectTask.IsCompleted) { HandleConnectionResult(ConnectTask); } Task? loginTask = LoginTask; if (loginTask != null && loginTask.IsCompleted) { HandleLoginResult(LoginTask); } if (ApSession == null) { return; } if (!ApSession.Socket.Connected && ConnectTask == null) { LogErrorForLobby("Disconnected from Archipelago! Attempting reconnect..."); CurrentState = eState.HostReconnecting; ConnectTask = ApSession.ConnectAsync(); } if (!ApSession.Items.Any()) { return; } while (ApSession.Items.Any()) { try { ItemInfo val = ApSession.Items.DequeueItem(); ItemID itemID = new ItemID { ID = checked((uint)val.ItemId) }; if (itemID.IsNull) { FeatureLogger.Error("Received null item id from Archipelago server!"); continue; } int num = m_sessionItemCounts.GetValueOrDefault(itemID, 0) + 1; m_sessionItemCounts[itemID] = num; if (num <= m_collectedItemCounts.GetValueOrDefault(itemID, 0)) { continue; } LocationID locationID = default(LocationID); PlayerAgent value = null; if (val.Player.Slot == ApSession.Players.ActivePlayer.Slot) { locationID = new LocationID { ID = checked((uint)val.LocationId) }; if (m_locationCheckContinuity.TryGetValue(locationID, out value)) { m_locationCheckContinuity.Remove(locationID); } } CollectItem(itemID, locationID, value); } catch (Exception ex) { FeatureLogger.Notice("Encountered unexpected exception while receiving items from Archipelago:"); FeatureLogger.Exception(ex); } } RundownHandler.UpdateAllCounts(); } public static void LogForLobby(string message, bool localOnly) { IEnumerable source = Enumerable.Empty(); CM_PageLoadout pageLoadout = MainMenuGuiLayer.Current.PageLoadout; IEnumerable source2 = source.Append((pageLoadout != null) ? pageLoadout.m_gameEventLog : null); CM_PageMap pageMap = MainMenuGuiLayer.Current.PageMap; IEnumerable source3 = source2.Append((pageMap != null) ? pageMap.m_gameEventLog : null); PlayerGuiLayer playerLayer = GuiManager.PlayerLayer; IEnumerable enumerable = source3.Append((playerLayer != null) ? playerLayer.m_gameEventLog : null); foreach (PUI_GameEventLog item in enumerable) { if (!((Object)(object)item == (Object)null)) { item.AddLogItem(message, (eGameEventChatLogType)2); item.UpdateHeightOffset(); } } if (!localOnly) { Get().m_stateReplicator?.SendLog(message); } } protected static void LogWarningForLobby(string message) { FeatureLogger.Warning(message); LogForLobby("<#FF0>" + message + "", localOnly: true); } protected static void LogErrorForLobby(string message) { FeatureLogger.Error(message); LogForLobby("<#F00>" + message + "", localOnly: true); } public void SetupReplication() { if (m_stateReplicator == null) { if (m_stateReplicator == null) { m_stateReplicator = new ArchipelagoStateReplicator(this); } Plugin.InvokeLateSetup(m_stateReplicator.ConcreteReplicator); ((MonoBehaviour)SNet.Current).StartCoroutine((IEnumerator)new Il2CppEnumerator(new UpdateStateEnumerator(this))); } } public pArchipelagoInitState MakeInitState() { pArchipelagoInitState result = new pArchipelagoInitState { GameName = MidManager.GetProcessedGameData().Name, RootSeed = RootSeed }; int num = 0; result.RegionWhitelist = new uint[m_regionWhitelist.Count]; foreach (RegionID item in m_regionWhitelist) { result.RegionWhitelist[num++] = item.ID; } num = 0; result.RegionBlacklist = new uint[m_regionBlacklist.Count]; foreach (RegionID item2 in m_regionBlacklist) { result.RegionBlacklist[num++] = item2.ID; } num = 0; result.LocationWhitelist = new uint[m_locationWhitelist.Count]; foreach (LocationID item3 in m_locationWhitelist) { result.LocationWhitelist[num++] = item3.ID; } num = 0; result.LocationBlacklist = new uint[m_locationBlacklist.Count]; foreach (LocationID item4 in m_locationBlacklist) { result.LocationBlacklist[num++] = item4.ID; } num = 0; result.ItemWhitelist = new uint[m_itemWhitelist.Count]; foreach (ItemID item5 in m_itemWhitelist) { result.ItemWhitelist[num++] = item5.ID; } num = 0; result.ItemBlacklist = new uint[m_itemBlacklist.Count]; foreach (ItemID item6 in m_itemBlacklist) { result.ItemBlacklist[num++] = item6.ID; } return result; } public pArchipelagoGeneralState MakeGeneralState() { int num = 0; pArchipelagoGeneralState result = default(pArchipelagoGeneralState); result.FoundLocations = new uint[m_foundLocations.Count]; foreach (LocationID foundLocation in m_foundLocations) { result.FoundLocations[num++] = foundLocation.ID; } num = 0; result.TrashedLocations = new uint[m_trashedLocations.Count]; foreach (LocationID trashedLocation in m_trashedLocations) { result.TrashedLocations[num++] = trashedLocation.ID; } num = 0; result.ItemsInTerminalSystem = new uint[ItemsInTerminalSystem.Count]; foreach (var item in ItemsInTerminalSystem) { uint[] itemsInTerminalSystem = result.ItemsInTerminalSystem; int num2 = num++; var (itemID, _) = item; itemsInTerminalSystem[num2] = itemID.ID; } num = 0; result.ItemIds = new uint[CollectedItemCounts.Sum((KeyValuePair pair) => pair.Value)]; foreach (KeyValuePair collectedItemCount in CollectedItemCounts) { for (int num3 = 0; num3 < collectedItemCount.Value; num3++) { result.ItemIds[num++] = collectedItemCount.Key.ID; } } return result; } public pArchipelagoScoutingUpdate MakeScoutingUpdate() { return FormatScoutingUpdate(from i in MidManager.GetProcessedGameData().Locations.GetAllEntries() where i.Value.Value?.ScoutedItemName != null select i.Key); } public pArchipelagoScoutingUpdate FormatScoutingUpdate(IEnumerable locations) { if (ApSession == null) { throw new NullReferenceException("Cannot format scouting update; no AP session"); } Dictionary dictionary = new Dictionary(); pArchipelagoScoutingUpdate result = default(pArchipelagoScoutingUpdate); result.SlotLookup = new string[ApSession.Players.AllPlayers.Count() * 2]; int num = 0; foreach (PlayerInfo allPlayer in ApSession.Players.AllPlayers) { result.SlotLookup[2 * num] = allPlayer.Name; result.SlotLookup[2 * num + 1] = allPlayer.Game; dictionary.Add(allPlayer.Name, num++); } Game.Data processedGameData = MidManager.GetProcessedGameData(); result.LocationIDs = locations.Select((LocationID locationID) => locationID.ID).ToArray(); result.SlotIds = new uint[result.LocationIDs.Length]; result.ItemDisplayNames = new string[result.LocationIDs.Length]; for (int num2 = 0; num2 < result.LocationIDs.Length; num2++) { LocationID id = new LocationID { ID = result.LocationIDs[num2] }; Location location = processedGameData.Locations.LookUpValueChecked(id); result.SlotIds[num2] = checked((uint)dictionary[location.ScoutedPlayerName]); result.ItemDisplayNames[num2] = location.ScoutedItemName ?? throw new NullReferenceException("Expected scouted item name, got null!"); } return result; } protected void SendInteraction(pArchipelagoInteraction.eType type, uint value = 0u, ushort count = 0) { if (!SNet.Capture.IsRecalling) { m_stateReplicator.SendInteraction(new pArchipelagoInteraction(type, value, count)); } } public void ReceiveInitState(pArchipelagoInitState state) { ClientConnect(state); } public void ReceiveScoutingUpdate(pArchipelagoScoutingUpdate update) { if (ApSession != null) { FeatureLogger.Debug("Ignoring scouting update; we are connected to AP!"); return; } FeatureLogger.Debug("Received a scouting update."); Game.Data processedGameData = MidManager.GetProcessedGameData(); for (int i = 0; i < update.LocationIDs.Length; i++) { LocationID id = new LocationID { ID = update.LocationIDs[i] }; Location location = processedGameData.Locations.LookUpValueChecked(id); long num = update.SlotIds[i]; location.ScoutedItemName = update.ItemDisplayNames[i]; location.ScoutedPlayerName = update.SlotLookup[2 * num]; location.ScoutedGameName = update.SlotLookup[2 * num + 1]; } } public void ReceiveGeneralState(pArchipelagoGeneralState state, bool isRecall) { if (!isRecall) { if (ApSession != null) { FeatureLogger.Debug("Ignoring GeneralState packet because we're connected to AP"); return; } if (CurrentState == eState.FakeConnect) { FeatureLogger.Debug("Ignoring GeneralState packet because we're using FakeConnect"); return; } } Game.Data processedGameData = MidManager.GetProcessedGameData(); m_foundLocations.UnionWith(state.FoundLocations.Select((uint id) => new LocationID { ID = id })); m_trashedLocations.UnionWith(state.TrashedLocations.Select((uint id) => new LocationID { ID = id })); ItemsInTerminalSystem.Clear(); uint[] itemsInTerminalSystem = state.ItemsInTerminalSystem; foreach (uint iD in itemsInTerminalSystem) { AddItemToTerminal(new ItemID { ID = iD }); } Dictionary dictionary = (from i in state.ItemIds group i by i).ToDictionary((IGrouping g) => new ItemID { ID = g.Key }, (IGrouping g) => g.Count()); foreach (ItemID item in m_collectedItemCounts.Keys.Union(dictionary.Keys)) { int valueOrDefault = m_collectedItemCounts.GetValueOrDefault(item, 0); int valueOrDefault2 = dictionary.GetValueOrDefault(item, 0); if (isRecall) { for (int num2 = valueOrDefault2; num2 < valueOrDefault; num2++) { processedGameData.Items.LookUpValueChecked(item).OnItemObtained(this, default(LocationID), null, item); } } else { for (int num3 = valueOrDefault; num3 < valueOrDefault2; num3++) { CollectItem(item, default(LocationID), null, skipInteraction: true); } } } } public void ReceiveInteraction(pArchipelagoInteraction interaction) { PlayerAgent player = null; SNet_Player val = default(SNet_Player); if (SNet.Replication.TryGetLastSender(ref val, false)) { SNet_IPlayerAgent playerAgent = val.PlayerAgent; player = ((playerAgent != null) ? ((Il2CppObjectBase)playerAgent).TryCast() : null); } switch (interaction.Type) { case pArchipelagoInteraction.eType.CollectItem: if (ApSession == null && CurrentState != eState.FakeConnect) { ItemID itemID = new ItemID { ID = interaction.Value }; int num = (ushort)m_collectedItemCounts.GetValueOrDefault(itemID, 0); while (num++ < interaction.Count) { CollectItem(itemID, default(LocationID), null, skipInteraction: true); } } break; case pArchipelagoInteraction.eType.CheckLocation: { LocationID id = new LocationID { ID = interaction.Value }; NotifyFoundLocation(id, player, force: false, skipInteraction: true); break; } case pArchipelagoInteraction.eType.ScoutLocation: { LocationID element = new LocationID { ID = interaction.Value }; ScoutLocations(Enumerable.Repeat(element, 1), (HintCreationPolicy)2); break; } case pArchipelagoInteraction.eType.MarkTrash: { LocationID item = new LocationID { ID = interaction.Value }; MarkAsTrash(new <>z__ReadOnlySingleElementList(item), player, skipInteraction: true); break; } case pArchipelagoInteraction.eType.EmptyTrash: m_trashedLocations.Clear(); break; case pArchipelagoInteraction.eType.CheckRegion: { RegionID regionId = new RegionID { ID = interaction.Value }; NotifyFoundRegion(regionId, player, skipInteraction: true); break; } default: FeatureLogger.Error($"Received unknown interaction type: {interaction.Type}"); break; } } } } namespace ReTFO.Archipelago.Features.ZoneHandlers { public static class DimensionPortalHandler_Tags { [SpecialName] public sealed class $2B8804A94F2EF68DF77A343A46EE5A78 { [SpecialName] public static class $55FD246F9BFF39DD56FCB5C25D4DF852 { } [ExtensionMarker("$55FD246F9BFF39DD56FCB5C25D4DF852")] public LocationID Location_DimensionPortalScans { [ExtensionMarker("$55FD246F9BFF39DD56FCB5C25D4DF852")] get { throw new NotSupportedException(); } } [ExtensionMarker("$55FD246F9BFF39DD56FCB5C25D4DF852")] public ItemID Item_DimensionPortalScans { [ExtensionMarker("$55FD246F9BFF39DD56FCB5C25D4DF852")] get { throw new NotSupportedException(); } } [ExtensionMarker("$55FD246F9BFF39DD56FCB5C25D4DF852")] public LocationID Location_DimensionPortalWarps { [ExtensionMarker("$55FD246F9BFF39DD56FCB5C25D4DF852")] get { throw new NotSupportedException(); } } [ExtensionMarker("$55FD246F9BFF39DD56FCB5C25D4DF852")] public ItemID Item_DimensionPortalWarps { [ExtensionMarker("$55FD246F9BFF39DD56FCB5C25D4DF852")] get { throw new NotSupportedException(); } } } [SpecialName] public sealed class $07060F1A014DE32BC9DAE9AB0EFE08B9 { [SpecialName] public static class $A55646E979CA6A3D946ACF0E8F38FB8D { } [ExtensionMarker("$A55646E979CA6A3D946ACF0E8F38FB8D")] public RegionID Region_PortalKeyInserted { [ExtensionMarker("$A55646E979CA6A3D946ACF0E8F38FB8D")] get { throw new NotSupportedException(); } } [ExtensionMarker("$A55646E979CA6A3D946ACF0E8F38FB8D")] public RegionID Region_PortalScanCompleted { [ExtensionMarker("$A55646E979CA6A3D946ACF0E8F38FB8D")] get { throw new NotSupportedException(); } } [ExtensionMarker("$A55646E979CA6A3D946ACF0E8F38FB8D")] public LocationID Location_DimensionPortalScan_Instance { [ExtensionMarker("$A55646E979CA6A3D946ACF0E8F38FB8D")] get { throw new NotSupportedException(); } } [ExtensionMarker("$A55646E979CA6A3D946ACF0E8F38FB8D")] public ItemID Item_DimensionPortalScan_Instance { [ExtensionMarker("$A55646E979CA6A3D946ACF0E8F38FB8D")] get { throw new NotSupportedException(); } } [ExtensionMarker("$A55646E979CA6A3D946ACF0E8F38FB8D")] public LocationID Location_DimensionPortalWarp_Instance { [ExtensionMarker("$A55646E979CA6A3D946ACF0E8F38FB8D")] get { throw new NotSupportedException(); } } [ExtensionMarker("$A55646E979CA6A3D946ACF0E8F38FB8D")] public ItemID Item_DimensionPortalWarp_Instance { [ExtensionMarker("$A55646E979CA6A3D946ACF0E8F38FB8D")] get { throw new NotSupportedException(); } } } public static LocationID get_Location_DimensionPortalScans(Game.Data data) { return LocationID.From(data, "Dimension Portal Scan Locations", (Game.Data data2) => new TagDefinition("Locations checked by powering up a dimension portal (ie R6B1)", CommonTagsHandler_Tags.get_Location_All(data2))); } public static ItemID get_Item_DimensionPortalScans(Game.Data data) { return ItemID.From(data, "Dimension Portal Scans", (Game.Data data2) => new TagDefinition("The scan in dimension portal rooms (ie R6B1) which trigger a dimension warp", CommonTagsHandler_Tags.get_Item_Scans(data2))); } public static LocationID get_Location_DimensionPortalWarps(Game.Data data) { return LocationID.From(data, "Dimension Portal Warp Locations", (Game.Data data2) => new TagDefinition("Locations checked by triggering a dimension warp using a dimension portal (ie R6B1)", CommonTagsHandler_Tags.get_Location_All(data2))); } public static ItemID get_Item_DimensionPortalWarps(Game.Data data) { return ItemID.From(data, "Dimension Portal Warps", (Game.Data data2) => new TagDefinition("A warp normally triggerd by a dimension portal room (ie R6B1)", CommonTagsHandler_Tags.get_Item_Warps(data2))); } public static RegionID get_Region_PortalKeyInserted(Zone.Data data) { return RegionID.From(data, data.ZoneName + " Dimension Portal Key Inserted", (Zone.Data data2) => new TagDefinition("Region entered when the MWP is put into a particular dimension portal", data2.Region_Zone)); } public static RegionID get_Region_PortalScanCompleted(Zone.Data data) { return RegionID.From(data, data.ZoneName + " Dimension Portal Scan Completed", (Zone.Data data2) => new TagDefinition("Region entered by completing the scan for a particular dimension portal", data2.Region_Zone)); } public static LocationID get_Location_DimensionPortalScan_Instance(Zone.Data data) { return LocationID.From(data, data.ZoneName + " Dimension Portal Scan Location", (Zone.Data data2) => new TagDefinition("The location of a particular dimension portal's scan", get_Location_DimensionPortalScans(data2))); } public static ItemID get_Item_DimensionPortalScan_Instance(Zone.Data data) { return ItemID.From(data, data.ZoneName + " Dimension Portal Scan", (Zone.Data data2) => new TagDefinition("A particular dimension portal's scan", get_Item_DimensionPortalScans(data2)), new DimensionPortalHandler.DimensionPortal_ScanItem(data.Region_Zone)); } public static LocationID get_Location_DimensionPortalWarp_Instance(Zone.Data data) { return LocationID.From(data, data.ZoneName + " Dimension Portal Warp Location", (Zone.Data data2) => new TagDefinition("A particular dimension portal warp location", get_Location_DimensionPortalWarps(data2))); } public static ItemID get_Item_DimensionPortalWarp_Instance(Zone.Data data) { return ItemID.From(data, data.ZoneName + " Dimension Portal Warp", (Zone.Data data2) => new TagDefinition("A warp triggered by a particular dimension portal", get_Item_DimensionPortalWarps(data2)), new DimensionPortalHandler.DimensionPortal_WarpItem(data.Region_Zone)); } } [EnableFeatureByDefault] [AutomatedFeature] public class DimensionPortalHandler : ArchipelagoFeature { public class DimensionPortal_ScanItem : TerminalItem { public RegionID ZoneRegion { get; private init; } public override RegionID TargetRegion => ZoneRegion; public DimensionPortal_ScanItem(RegionID zone) : base(new ItemData { IsProgression = true }) { ZoneRegion = zone; } public override IEnumerable OnRetrieveFromTerminalSystem(StateTracker stateTracker, LG_ComputerTerminal terminal, ItemID itemId) { Zone.Data data = new Zone.Data(stateTracker.GameData, ZoneRegion); LG_Zone lG_Zone = data.GetLG_Zone(); LG_DimensionPortalRoom val = null; foreach (LG_Area item in ((lG_Zone != null) ? lG_Zone.m_areas.Iter() : null) ?? Enumerable.Empty()) { object obj; if (item == null) { obj = null; } else { LG_Geomorph geomorph = item.m_geomorph; obj = ((geomorph != null) ? ((Component)geomorph).GetComponent() : null); } val = (LG_DimensionPortalRoom)obj; if ((Object)(object)val != (Object)null) { break; } } LG_DimensionPortal portal = ((val != null) ? val.m_core : null); yield return delegate { terminal.AddLine((TerminalLineType)2, "Initiating Dimension Portal Scan", 2f); }; yield return delegate { if ((Object)(object)portal != (Object)null) { terminal.AddLine("Scan commencing. Enjoy?", true); portal.m_portalChainPuzzleInstance.AttemptInteract((eChainedPuzzleInteraction)0); portal.OnPortalKeyInsertSequenceDone?.Invoke(portal); } else { terminal.AddLine("<#F00>Failed to find dimension portal! Item returned to terminal.", true); stateTracker.AddItemToTerminal(itemId); } }; } } public class DimensionPortal_WarpItem : TerminalItem { public RegionID ZoneRegion { get; private init; } public override RegionID TargetRegion => ZoneRegion; public DimensionPortal_WarpItem(RegionID zone) : base(new ItemData { IsProgression = true }) { ZoneRegion = zone; } public override IEnumerable OnRetrieveFromTerminalSystem(StateTracker stateTracker, LG_ComputerTerminal terminal, ItemID itemId) { Zone.Data data = new Zone.Data(stateTracker.GameData, ZoneRegion); LG_Zone lG_Zone = data.GetLG_Zone(); LG_DimensionPortalRoom val = null; foreach (LG_Area item in ((lG_Zone != null) ? lG_Zone.m_areas.Iter() : null) ?? Enumerable.Empty()) { object obj; if (item == null) { obj = null; } else { LG_Geomorph geomorph = item.m_geomorph; obj = ((geomorph != null) ? ((Component)geomorph).GetComponent() : null); } val = (LG_DimensionPortalRoom)obj; if ((Object)(object)val != (Object)null) { break; } } LG_DimensionPortal portal = ((val != null) ? val.m_core : null); yield return delegate { terminal.AddLine((TerminalLineType)2, "Initiating Dimension Portal Warp", 2f); }; yield return delegate { if ((Object)(object)portal != (Object)null) { terminal.AddLine("Initiating Dimension Warp via Dimension Portal. Goodbye!", true); portal._Setup_b__61_0(); stateTracker.AddItemToTerminal(itemId); } else { terminal.AddLine("<#F00>Failed to find dimension portal! Item returned to terminal.", true); stateTracker.AddItemToTerminal(itemId); } }; } } [ArchivePatch(/*Could not decode attribute arguments.*/)] public static class LG_DimensionPortal__PortalKeyInsertSequenceDone__Patch { public static bool Prefix(LG_DimensionPortal __instance) { Zone.Data fromZone = Zone.Data.GetFromZone(__instance.SpawnNode.m_zone); LocationID id = DimensionPortalHandler_Tags.get_Location_DimensionPortalScan_Instance(fromZone); Location location = StateTracker.Get().NotifyFoundLocation(id, null); return !location.RandData.IsTreatedAsRandom; } } [ArchivePatch(/*Could not decode attribute arguments.*/)] public static class LG_DimensionPortal__Setup__Patch { public static void Postfix(LG_DimensionPortal __instance) { Zone.Data fromZone = Zone.Data.GetFromZone(__instance.SpawnNode.m_zone); LocationID id = DimensionPortalHandler_Tags.get_Location_DimensionPortalWarp_Instance(fromZone); Location location = fromZone.Locations.LookUpValueChecked(id); if (location.RandData.IsTreatedAsRandom) { Action action = delegate { StateTracker.Get().NotifyFoundLocation(id, null); }; __instance.m_portalChainPuzzleInstance.OnPuzzleSolved = new Il2CppAction(action); } } } private static IArchiveLogger? m_featureLogger; public override string Name => "Dimension Portal Handler"; public override string Description => "Handles dimension warps triggered by portals (which require MWPs)\nFor example, this handles the dimension warp in R6B1.\nDimension portals include the warp scan and the actual warp itself as separate items."; public override FeatureGroup Group => ArchipelagoFeatureGroups.get_ZoneHandlers(); public new static IArchiveLogger FeatureLogger { get { return m_featureLogger ?? Plugin.Get().Logger; } set { m_featureLogger = value; } } [Zone.Callback] public void AddZoneWarps(Zone.Data data) { //IL_006d: 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) string? customGeo = data.CustomGeo; if (customGeo != null && customGeo.Contains("_portal_", StringComparison.OrdinalIgnoreCase)) { Zone.Data data2 = Zone.get_FirstZone(data.GetLayer(LayerType.Dimension_1)); ComplexResourceSetDataBlock block = GameDataBlockBase.GetBlock(data.Expedition.Expedition.ComplexResourceData); GameObject val = ((block != null) ? block.GetCustomGeomorph(data.CustomGeo) : null); LG_DimensionPortal val2 = ((val != null) ? val.GetComponentInChildren() : null); if ((Object)(object)val2 != (Object)null) { data2 = data.FindZoneExact(val2.m_targetDimension, val2.m_targetZone) ?? throw new NullReferenceException("Failed to find portal target despite finding portal asset"); } else { FeatureLogger.Warning(data.ZoneName + ": Using default portal location for presumed DimensionPortal"); } RegionID regionID = DimensionPortalHandler_Tags.get_Region_PortalKeyInserted(data); data.AddPath(new ReTFO.Archipelago.ModdedInstanceData.Model.Path { StartingRegion = data.Region_Zone, EndingRegion = regionID, Reqs = new ReTFO.Archipelago.ModdedInstanceData.Model.Path.MultiPathReq(ReTFO.Archipelago.ModdedInstanceData.Model.Path.eType.ItemConsumed, BigPickupHandler_Tags.get_Item_BigPickup_MWP(data), 1u) }); ItemID itemID = DimensionPortalHandler_Tags.get_Item_DimensionPortalScan_Instance(data); data.Locations.CreateValue(DimensionPortalHandler_Tags.get_Location_DimensionPortalScan_Instance(data), regionID, default(LocationData), itemID); RegionID regionID2 = DimensionPortalHandler_Tags.get_Region_PortalScanCompleted(data); data.AddPath(new ReTFO.Archipelago.ModdedInstanceData.Model.Path { StartingRegion = regionID, EndingRegion = regionID2, Reqs = new ReTFO.Archipelago.ModdedInstanceData.Model.Path.MultiPathReq(ReTFO.Archipelago.ModdedInstanceData.Model.Path.eType.Item, itemID, 1u) }); ItemID itemID2 = DimensionPortalHandler_Tags.get_Item_DimensionPortalWarp_Instance(data); data.Locations.CreateValue(DimensionPortalHandler_Tags.get_Location_DimensionPortalWarp_Instance(data), regionID2, default(LocationData), itemID2); data.AddPath(new ReTFO.Archipelago.ModdedInstanceData.Model.Path { StartingRegion = regionID2, EndingRegion = data2.Region_Zone, Reqs = new ReTFO.Archipelago.ModdedInstanceData.Model.Path.MultiPathReq(ReTFO.Archipelago.ModdedInstanceData.Model.Path.eType.ItemConsumed, itemID2, 1u) }); } } } public static class SecDoorHandler_Tags { [SpecialName] public sealed class $07060F1A014DE32BC9DAE9AB0EFE08B9 { [SpecialName] public static class $A55646E979CA6A3D946ACF0E8F38FB8D { } [ExtensionMarker("$A55646E979CA6A3D946ACF0E8F38FB8D")] public RegionID Region_OnApproachEvents { [ExtensionMarker("$A55646E979CA6A3D946ACF0E8F38FB8D")] get { throw new NotSupportedException(); } } [ExtensionMarker("$A55646E979CA6A3D946ACF0E8F38FB8D")] public RegionID Region_OnUnlockDoorEvents { [ExtensionMarker("$A55646E979CA6A3D946ACF0E8F38FB8D")] get { throw new NotSupportedException(); } } [ExtensionMarker("$A55646E979CA6A3D946ACF0E8F38FB8D")] public RegionID Region_OnDoorScanStartEvents { [ExtensionMarker("$A55646E979CA6A3D946ACF0E8F38FB8D")] get { throw new NotSupportedException(); } } [ExtensionMarker("$A55646E979CA6A3D946ACF0E8F38FB8D")] public RegionID Region_OnDoorScanDoneEvents { [ExtensionMarker("$A55646E979CA6A3D946ACF0E8F38FB8D")] get { throw new NotSupportedException(); } } [ExtensionMarker("$A55646E979CA6A3D946ACF0E8F38FB8D")] public RegionID Region_OnDoorOpenedEvents { [ExtensionMarker("$A55646E979CA6A3D946ACF0E8F38FB8D")] get { throw new NotSupportedException(); } } } public static RegionID get_Region_OnApproachEvents(Zone.Data data) { return RegionID.From(data, data.ZoneName + " Door Approached", (Zone.Data data2) => new TagDefinition("Region entered by looking at a sec door's interact", data2.Region_Zone)); } public static RegionID get_Region_OnUnlockDoorEvents(Zone.Data data) { return RegionID.From(data, data.ZoneName + " Door Unlocked", (Zone.Data data2) => new TagDefinition("Region entered by unlocking a particular zone door", data2.Region_Zone)); } public static RegionID get_Region_OnDoorScanStartEvents(Zone.Data data) { return RegionID.From(data, data.ZoneName + " Door Scan Started", (Zone.Data data2) => new TagDefinition("Region entered by starting a scan to unlock a particular zone door", data2.Region_Zone)); } public static RegionID get_Region_OnDoorScanDoneEvents(Zone.Data data) { return RegionID.From(data, data.ZoneName + " Door Scan Completed", (Zone.Data data2) => new TagDefinition("Region entered by completing a scan to unlock a particular zone door", data2.Region_Zone)); } public static RegionID get_Region_OnDoorOpenedEvents(Zone.Data data) { return RegionID.From(data, data.ZoneName + " Door Opened", (Zone.Data data2) => new TagDefinition("Region entered by opening a particular zone door", data2.Region_Zone)); } } [EnableFeatureByDefault] [AutomatedFeature] public class SecDoorHandler : ArchipelagoFeature { private struct RegionEventPair { public unsafe readonly delegate* RegionFactory; public readonly List? EventList; public unsafe RegionEventPair(delegate* regionFactory, List? eventList) { RegionFactory = regionFactory; EventList = eventList; } } [ArchivePatch(/*Could not decode attribute arguments.*/)] public static class PlayerAgent__SetCourseNode__Patch { public static void Postfix(PlayerAgent __instance) { Zone.Data fromZone = Zone.Data.GetFromZone(((Agent)__instance).CourseNode.m_zone); StateTracker.Get().NotifyFoundRegion(fromZone.Region_Zone, __instance); } } private static IArchiveLogger? m_featureLogger; public override string Name => "Sec Door Handler"; public override string Description => "Adds sec doors as parths and applies locks to them"; public override FeatureGroup Group => ArchipelagoFeatureGroups.get_ZoneHandlers(); public new static IArchiveLogger FeatureLogger { get { return m_featureLogger ?? Plugin.Get().Logger; } set { m_featureLogger = value; } } [Expedition.Callback] public void AddExpeditionEntrace(Expedition.Data data) { data.AddPath(new ReTFO.Archipelago.ModdedInstanceData.Model.Path { StartingRegion = data.Region_Expedition, EndingRegion = Zone.get_FirstZone(Layer.get_MainLayer(data)).Region_Zone }); } [Zone.Callback] public unsafe void AddZoneEntrances(Zone.Data data) { //IL_00da: Unknown result type (might be due to invalid IL or missing references) //IL_00ea: 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_00bb: Unknown result type (might be due to invalid IL or missing references) //IL_0106: Unknown result type (might be due to invalid IL or missing references) //IL_0240: Unknown result type (might be due to invalid IL or missing references) //IL_0246: Invalid comparison between Unknown and I4 //IL_020b: Unknown result type (might be due to invalid IL or missing references) //IL_0271: Unknown result type (might be due to invalid IL or missing references) //IL_0277: Invalid comparison between Unknown and I4 //IL_02a2: Unknown result type (might be due to invalid IL or missing references) //IL_02a8: Invalid comparison between Unknown and I4 //IL_02d0: Unknown result type (might be due to invalid IL or missing references) //IL_0304: Unknown result type (might be due to invalid IL or missing references) if (data.Layout == null || data.Zone == null) { return; } bool flag = ((Il2CppObjectBase)data.Zone).Pointer == ((Il2CppObjectBase)data.Layout.Zones[0]).Pointer; if ((data.LayerType.IsMainLayer || data.LayerType.IsDimension) && flag) { return; } Layer.Data data2; Zone.Data data3; if (flag) { data2 = data.GetLayer(data.BuildFromData.LayerType); data3 = data2.FindZoneByIndex(data.BuildFromData.Zone); } else { data2 = data; data3 = ((data.Zone.BuildFromLocalIndex != data.Zone.LocalIndex) ? data2.FindZoneByIndex(data.Zone.BuildFromLocalIndex) : Zone.get_FirstZone(data2)); } RegionID startingRegion = data3.Region_Zone; List eventsOnApproachDoor = data.Zone.EventsOnApproachDoor; if (eventsOnApproachDoor != null && eventsOnApproachDoor.Any()) { RegionID regionID = SecDoorHandler_Tags.get_Region_OnApproachEvents(data); data.ProcessEvents(regionID, data.Zone.EventsOnApproachDoor); data.AddPath(new ReTFO.Archipelago.ModdedInstanceData.Model.Path { StartingRegion = startingRegion, EndingRegion = regionID }); startingRegion = regionID; } ReTFO.Archipelago.ModdedInstanceData.Model.Path.PathReq req = default(ReTFO.Archipelago.ModdedInstanceData.Model.Path.PathReq); LayerData layerDatas = data.LayerDatas; if (flag) { req = ((data2.LayerDatas.BulkheadDoorControllerPlacements.FirstOrDefault((BulkheadDoorPlacementData p) => p.ZoneIndex == data.BuildFromData.Zone) == null) ? new ReTFO.Archipelago.ModdedInstanceData.Model.Path.PathReq(ReTFO.Archipelago.ModdedInstanceData.Model.Path.eType.Category, UnlockEventHandler_Tags.get_Item_DoorUnlockEvent_ByZone(data), 1u) : new ReTFO.Archipelago.ModdedInstanceData.Model.Path.PathReq(ReTFO.Archipelago.ModdedInstanceData.Model.Path.eType.ItemConsumed, BulkheadKeyHandler_Tags.get_Item_BulkheadKey_Instance(data), 1u)); } else if (layerDatas != null && layerDatas.ZonesWithBulkheadEntrance.Contains(data.Zone.LocalIndex)) { req = new ReTFO.Archipelago.ModdedInstanceData.Model.Path.PathReq(ReTFO.Archipelago.ModdedInstanceData.Model.Path.eType.ItemConsumed, BulkheadKeyHandler_Tags.get_Item_BulkheadKey_Instance(data), 1u); } else if ((int)data.Zone.ProgressionPuzzleToEnter.PuzzleType == 1) { req = new ReTFO.Archipelago.ModdedInstanceData.Model.Path.PathReq(ReTFO.Archipelago.ModdedInstanceData.Model.Path.eType.Item, ColoredKeyHandler_Tags.get_Item_ColoredKey_Instance(data), 1u); } else if ((int)data.Zone.ProgressionPuzzleToEnter.PuzzleType == 2) { req = new ReTFO.Archipelago.ModdedInstanceData.Model.Path.PathReq(ReTFO.Archipelago.ModdedInstanceData.Model.Path.eType.ItemConsumed, BigPickupHandler_Tags.get_Item_BigPickup_Cell(data), 1u); } else if ((int)data.Zone.ProgressionPuzzleToEnter.PuzzleType == 3) { req = new ReTFO.Archipelago.ModdedInstanceData.Model.Path.PathReq(ReTFO.Archipelago.ModdedInstanceData.Model.Path.eType.Category, UnlockEventHandler_Tags.get_Item_DoorUnlockEvent_ByZone(data), 1u); } else if ((int)data.Zone.ProgressionPuzzleToEnter.PuzzleType != 0) { FeatureLogger.Error($"Unknown progression puzzle type {data.Zone.ProgressionPuzzleToEnter.PuzzleType}! Zone: {data.ZoneName}"); } RegionEventPair[] array = new RegionEventPair[4] { new RegionEventPair((delegate*)(&SecDoorHandler_Tags.get_Region_OnUnlockDoorEvents), data.Zone.EventsOnUnlockDoor), new RegionEventPair((delegate*)(&SecDoorHandler_Tags.get_Region_OnDoorScanStartEvents), data.Zone.EventsOnDoorScanStart), new RegionEventPair((delegate*)(&SecDoorHandler_Tags.get_Region_OnDoorScanDoneEvents), data.Zone.EventsOnDoorScanDone), new RegionEventPair((delegate*)(&SecDoorHandler_Tags.get_Region_OnDoorOpenedEvents), data.Zone.EventsOnOpenDoor) }; RegionEventPair[] array2 = array; for (int num = 0; num < array2.Length; num++) { RegionEventPair regionEventPair = array2[num]; List? eventList = regionEventPair.EventList; if (eventList != null && eventList.Any()) { RegionID regionID2 = regionEventPair.RegionFactory(data); data.ProcessEvents(regionID2, regionEventPair.EventList); data.AddPath(new ReTFO.Archipelago.ModdedInstanceData.Model.Path { StartingRegion = startingRegion, EndingRegion = regionID2, Reqs = new ReTFO.Archipelago.ModdedInstanceData.Model.Path.MultiPathReq(req) }); if (req.Type != ReTFO.Archipelago.ModdedInstanceData.Model.Path.eType.None && req.Type != ReTFO.Archipelago.ModdedInstanceData.Model.Path.eType.Category) { data.AddPath(new ReTFO.Archipelago.ModdedInstanceData.Model.Path { StartingRegion = startingRegion, EndingRegion = regionID2, Reqs = new ReTFO.Archipelago.ModdedInstanceData.Model.Path.MultiPathReq(ReTFO.Archipelago.ModdedInstanceData.Model.Path.eType.Category, UnlockEventHandler_Tags.get_Item_DoorUnlockEvent_ByZone(data), 1u) }); } req = default(ReTFO.Archipelago.ModdedInstanceData.Model.Path.PathReq); startingRegion = regionID2; } } data.AddPath(new ReTFO.Archipelago.ModdedInstanceData.Model.Path { StartingRegion = startingRegion, EndingRegion = data.Region_Zone, Reqs = new ReTFO.Archipelago.ModdedInstanceData.Model.Path.MultiPathReq(req) }); if (req.Type != ReTFO.Archipelago.ModdedInstanceData.Model.Path.eType.None && req.Type != ReTFO.Archipelago.ModdedInstanceData.Model.Path.eType.Category) { data.AddPath(new ReTFO.Archipelago.ModdedInstanceData.Model.Path { StartingRegion = startingRegion, EndingRegion = data.Region_Zone, Reqs = new ReTFO.Archipelago.ModdedInstanceData.Model.Path.MultiPathReq(ReTFO.Archipelago.ModdedInstanceData.Model.Path.eType.Category, UnlockEventHandler_Tags.get_Item_DoorUnlockEvent_ByZone(data), 1u) }); } } } public static class TriggerEventsHandler_Tags { [SpecialName] public sealed class $07060F1A014DE32BC9DAE9AB0EFE08B9 { [SpecialName] public static class $A55646E979CA6A3D946ACF0E8F38FB8D { } [ExtensionMarker("$A55646E979CA6A3D946ACF0E8F38FB8D")] public RegionID Region_OnTriggerEvents(string trigger) { throw new NotSupportedException(); } } public static RegionID Region_OnTriggerEvents(this Zone.Data data, string trigger) { return RegionID.From(data, data.ZoneName + " OnTrigger (" + trigger + ")", (Zone.Data data2) => new TagDefinition("Region entered by trigger a particular WorldEventObject trigger", data2.Region_Zone)); } } [EnableFeatureByDefault] [AutomatedFeature] public class TriggerEventsHandler : ArchipelagoFeature { private static IArchiveLogger? m_featureLogger = null; private static Dictionary WorldEventObjectOverrides = new Dictionary { { "Evt_Shuttlebox_Interact_R8A1", (LayerType.Main, (eLocalZoneIndex)4) }, { "WE_Hearsay_Interact_02", (LayerType.Main, (eLocalZoneIndex)7) } }; private static Dictionary> PathReqsOverride = new Dictionary> { { "Evt_Shuttlebox_Interact_R8A1", (Zone.Data data) => data.GetObjectiveDatas().ElementAt(0).Item_BigRetrieval_Instance(1) }, { "WE_Dataextractor_Interact", (Zone.Data data) => data.Item_BigPickup_Instance(181u) }, { "Evt_Shuttlebox_Interact_R7B1", (Zone.Data data) => data.Item_BigPickup_Instance(173u) } }; public override string Name => "Trigger Events Handler"; public override string Description => "Triggers processing of trigger eventsTrigger events are the most versatile event type in GTFO, which are activated by world event triggers. These include invisible trigger hitboxes and certain special interactions"; public override FeatureGroup Group => ArchipelagoFeatureGroups.get_ZoneHandlers(); public new static IArchiveLogger FeatureLogger { get { return m_featureLogger ?? Plugin.Get().Logger; } set { m_featureLogger = value; } } [Zone.Callback] public void AddTriggerEvents(Zone.Data data) { //IL_0152: Unknown result type (might be due to invalid IL or missing references) //IL_0235: Unknown result type (might be due to invalid IL or missing references) //IL_023a: Unknown result type (might be due to invalid IL or missing references) //IL_0242: Unknown result type (might be due to invalid IL or missing references) //IL_0255: Unknown result type (might be due to invalid IL or missing references) //IL_0268: Unknown result type (might be due to invalid IL or missing references) //IL_027b: Unknown result type (might be due to invalid IL or missing references) //IL_028e: Unknown result type (might be due to invalid IL or missing references) //IL_02a1: Unknown result type (might be due to invalid IL or missing references) //IL_02b4: Unknown result type (might be due to invalid IL or missing references) //IL_02c7: Unknown result type (might be due to invalid IL or missing references) //IL_02da: Unknown result type (might be due to invalid IL or missing references) //IL_02ed: Unknown result type (might be due to invalid IL or missing references) //IL_02f6: Unknown result type (might be due to invalid IL or missing references) //IL_0300: Unknown result type (might be due to invalid IL or missing references) //IL_0313: Unknown result type (might be due to invalid IL or missing references) //IL_0326: Unknown result type (might be due to invalid IL or missing references) //IL_0339: Unknown result type (might be due to invalid IL or missing references) //IL_034c: Unknown result type (might be due to invalid IL or missing references) //IL_035f: Unknown result type (might be due to invalid IL or missing references) //IL_0372: Unknown result type (might be due to invalid IL or missing references) //IL_037b: Unknown result type (might be due to invalid IL or missing references) //IL_0385: Unknown result type (might be due to invalid IL or missing references) //IL_038e: Unknown result type (might be due to invalid IL or missing references) //IL_0398: Unknown result type (might be due to invalid IL or missing references) //IL_03a1: Unknown result type (might be due to invalid IL or missing references) //IL_03ab: Unknown result type (might be due to invalid IL or missing references) //IL_03be: Unknown result type (might be due to invalid IL or missing references) //IL_03d1: Unknown result type (might be due to invalid IL or missing references) //IL_03e4: Unknown result type (might be due to invalid IL or missing references) //IL_03f7: Unknown result type (might be due to invalid IL or missing references) //IL_040a: Unknown result type (might be due to invalid IL or missing references) //IL_041d: Unknown result type (might be due to invalid IL or missing references) //IL_0426: Unknown result type (might be due to invalid IL or missing references) //IL_0430: Unknown result type (might be due to invalid IL or missing references) //IL_0439: Unknown result type (might be due to invalid IL or missing references) //IL_0443: Unknown result type (might be due to invalid IL or missing references) //IL_044c: Unknown result type (might be due to invalid IL or missing references) //IL_0456: Unknown result type (might be due to invalid IL or missing references) //IL_045f: Unknown result type (might be due to invalid IL or missing references) //IL_0469: Unknown result type (might be due to invalid IL or missing references) //IL_047c: Unknown result type (might be due to invalid IL or missing references) //IL_048f: Unknown result type (might be due to invalid IL or missing references) //IL_04a7: Expected O, but got Unknown if (data.Zone == null || data.Zone.EventsOnTrigger == null || data.Zone.EventsOnTrigger.Count == 0) { return; } List val = new List(data.Zone.EventsOnTrigger.Count); foreach (WorldEventFromSourceData item in (from e in data.Zone.EventsOnTrigger.Iter() group e by e.WorldEventTriggerObjectFilter).SelectMany((IGrouping g) => g)) { val.Add((WardenObjectiveEventData)(object)item); } data.Zone.EventsOnTrigger.Clear(); int num = 0; for (int num2 = 1; num2 <= val.Count; num2++) { WorldEventFromSourceData val2 = ((Il2CppObjectBase)val[num]).Cast(); WorldEventFromSourceData val3 = ((num2 == val.Count) ? null : ((Il2CppObjectBase)val[num2]).Cast()); if (val2.WorldEventTriggerObjectFilter == ((val3 != null) ? val3.WorldEventTriggerObjectFilter : null)) { continue; } string worldEventTriggerObjectFilter = val2.WorldEventTriggerObjectFilter; if (worldEventTriggerObjectFilter != null) { Zone.Data data2 = data; if (WorldEventObjectOverrides.TryGetValue(worldEventTriggerObjectFilter, out var value)) { data2 = data.FindZoneExact(value.Item1, value.Item2) ?? throw new Exception("Warden Event Trigger has zone override, but the override zone could not be found"); } ReTFO.Archipelago.ModdedInstanceData.Model.Path.MultiPathReq reqs = new ReTFO.Archipelago.ModdedInstanceData.Model.Path.MultiPathReq(); if (PathReqsOverride.TryGetValue(worldEventTriggerObjectFilter, out Func value2)) { reqs = new ReTFO.Archipelago.ModdedInstanceData.Model.Path.MultiPathReq(ReTFO.Archipelago.ModdedInstanceData.Model.Path.eType.ItemConsumed, value2(data), 1u); } RegionID regionID = data.Region_OnTriggerEvents(worldEventTriggerObjectFilter); data.AddPath(new ReTFO.Archipelago.ModdedInstanceData.Model.Path { StartingRegion = data2.Region_Zone, EndingRegion = regionID, Reqs = reqs }); Event.Data data3 = data.ProcessEvents(regionID, val, num, num2 - num); num = data3.EventStart; num2 = data3.EventStart + data3.EventCount; } for (int num3 = num; num3 < num2; num3++) { WorldEventFromSourceData val4 = ((Il2CppObjectBase)val[num3]).TryCast(); if (val4 != null) { data.Zone.EventsOnTrigger.Add(val4); continue; } data.Zone.EventsOnTrigger.Add(new WorldEventFromSourceData { WorldEventTriggerObjectFilter = worldEventTriggerObjectFilter, AchievementKey = val[num3].AchievementKey, ChainPuzzle = val[num3].ChainPuzzle, ClearDimension = val[num3].ClearDimension, Condition = val[num3].Condition, Count = val[num3].Count, CustomSubObjective = val[num3].CustomSubObjective, CustomSubObjectiveHeader = val[num3].CustomSubObjectiveHeader, Delay = val[num3].Delay, DialogueID = val[num3].DialogueID, DimensionIndex = val[num3].DimensionIndex, Duration = val[num3].Duration, Enabled = val[num3].Enabled, EnemyID = val[num3].EnemyID, EnemyWaveData = val[num3].EnemyWaveData, FogSetting = val[num3].FogSetting, FogTransitionDuration = val[num3].FogTransitionDuration, Layer = val[num3].Layer, LocalIndex = val[num3].LocalIndex, Position = val[num3].Position, SoundID = val[num3].SoundID, SoundSubtitle = val[num3].SoundSubtitle, SustainedEventDelay = val[num3].SustainedEventDelay, SustainedEventSlotIndex = val[num3].SustainedEventSlotIndex, SustainedEventStateCount = val[num3].SustainedEventStateCount, SustainedEventStateDuration = val[num3].SustainedEventStateDuration, TerminalCommand = val[num3].TerminalCommand, TerminalCommandRule = val[num3].TerminalCommandRule, Trigger = val[num3].Trigger, Type = val[num3].Type, UseStaticBioscanPoints = val[num3].UseStaticBioscanPoints, WardenIntel = val[num3].WardenIntel, WorldEventObjectFilter = val[num3].WorldEventObjectFilter }); } num = num2; } } } public static class ZoneEventsHandler_Tags { [SpecialName] public sealed class $07060F1A014DE32BC9DAE9AB0EFE08B9 { [SpecialName] public static class $A55646E979CA6A3D946ACF0E8F38FB8D { } [ExtensionMarker("$A55646E979CA6A3D946ACF0E8F38FB8D")] public RegionID Region_OnBossDeathEvents { [ExtensionMarker("$A55646E979CA6A3D946ACF0E8F38FB8D")] get { throw new NotSupportedException(); } } [ExtensionMarker("$A55646E979CA6A3D946ACF0E8F38FB8D")] public RegionID Region_OnPortalWarpEvents { [ExtensionMarker("$A55646E979CA6A3D946ACF0E8F38FB8D")] get { throw new NotSupportedException(); } } [ExtensionMarker("$A55646E979CA6A3D946ACF0E8F38FB8D")] public RegionID Region_OnTerminalDeactivateAlarmEvents { [ExtensionMarker("$A55646E979CA6A3D946ACF0E8F38FB8D")] get { throw new NotSupportedException(); } } } public static RegionID get_Region_OnBossDeathEvents(Zone.Data data) { return RegionID.From(data, data.ZoneName + " OnBossDeath", (Zone.Data data2) => new TagDefinition("Region entered by killing a boss in a particular zone", data2.Region_Zone)); } public static RegionID get_Region_OnPortalWarpEvents(Zone.Data data) { return RegionID.From(data, data.ZoneName + " OnPortalWarp", (Zone.Data data2) => new TagDefinition("Region entered by trigger a dimsion portal's warp in a particular zone", data2.Region_Zone)); } public static RegionID get_Region_OnTerminalDeactivateAlarmEvents(Zone.Data data) { return RegionID.From(data, data.ZoneName + " OnTerminalDeactivateAlarm", (Zone.Data data2) => new TagDefinition("Region entered by executing the DEACTIVATE_ALARMS command associated with a particular zone door's error alarm", data2.Region_Zone)); } } [EnableFeatureByDefault] [AutomatedFeature] public class ZoneEventsHandler : ArchipelagoFeature { private struct RegionEventPair { public unsafe readonly delegate* RegionFactory; public readonly List? EventList; public unsafe RegionEventPair(delegate* regionFactory, List? eventList) { RegionFactory = regionFactory; EventList = eventList; } } private static IArchiveLogger? m_featureLogger; public override string Name => "Zone Events Handler"; public override string Description => "Triggers processing of several zone-based eventsIncludes the following events:\n - OnBossDeath\n - OnDoorScanDone\n - OnDoorScanStart\n - OnOpenDoor\n - OnPortalWarp\n - OnTerminalDeactivateAlarm\n - OnUnlockDoor"; public override FeatureGroup Group => ArchipelagoFeatureGroups.get_ZoneHandlers(); public new static IArchiveLogger FeatureLogger { get { return m_featureLogger ?? Plugin.Get().Logger; } set { m_featureLogger = value; } } [Zone.Callback] public unsafe void AddZoneEvents(Zone.Data data) { if (data.Zone != null) { RegionEventPair[] array = new RegionEventPair[3] { new RegionEventPair((delegate*)(&ZoneEventsHandler_Tags.get_Region_OnBossDeathEvents), data.Zone.EventsOnBossDeath), new RegionEventPair((delegate*)(&ZoneEventsHandler_Tags.get_Region_OnPortalWarpEvents), data.Zone.EventsOnPortalWarp), new RegionEventPair((delegate*)(&ZoneEventsHandler_Tags.get_Region_OnTerminalDeactivateAlarmEvents), data.Zone.EventsOnTerminalDeactivateAlarm) }; RegionEventPair[] array2 = array; for (int i = 0; i < array2.Length; i++) { RegionEventPair regionEventPair = array2[i]; List? eventList = regionEventPair.EventList; if (eventList != null && eventList.Any()) { RegionID regionID = regionEventPair.RegionFactory(data); data.AddPath(new ReTFO.Archipelago.ModdedInstanceData.Model.Path { StartingRegion = data.Region_Zone, EndingRegion = regionID }); data.ProcessEvents(regionID, regionEventPair.EventList); } } } else if (data.DimensionData != null && data.DimensionData.EventsOnBossDeath.Any()) { RegionID regionID2 = ZoneEventsHandler_Tags.get_Region_OnBossDeathEvents(data); data.AddPath(new ReTFO.Archipelago.ModdedInstanceData.Model.Path { StartingRegion = data.Region_Zone, EndingRegion = regionID2 }); data.ProcessEvents(regionID2, data.DimensionData.EventsOnBossDeath); } } } } namespace ReTFO.Archipelago.Features.Terminals { public static class APCommandExtractHandler_Tags { [SpecialName] public sealed class $2B8804A94F2EF68DF77A343A46EE5A78 { [SpecialName] public static class $55FD246F9BFF39DD56FCB5C25D4DF852 { } [ExtensionMarker("$55FD246F9BFF39DD56FCB5C25D4DF852")] public LocationID Location_TerminalExtractions { [ExtensionMarker("$55FD246F9BFF39DD56FCB5C25D4DF852")] get { throw new NotSupportedException(); } } } [SpecialName] public sealed class $63BA103E62A55F64C05B172EF249EC99 { [SpecialName] public static class $DE04A58E69D058D9CEE64C49EAD6305E { } [ExtensionMarker("$DE04A58E69D058D9CEE64C49EAD6305E")] public LocationID Location_TerminalExtraction_Instance(int count) { throw new NotSupportedException(); } } public static LocationID get_Location_TerminalExtractions(Game.Data data) { return LocationID.From(data, "Terminal Extraction Locations", (Game.Data data2) => new TagDefinition("Locations checked by performing the extract and release commands on terminals", CommonTagsHandler_Tags.get_Location_Empty(data2))); } public static LocationID Location_TerminalExtraction_Instance(this Terminal.Data data, int count) { return LocationID.From(data, $"{data.TerminalName} Extraction Location #{count}", (Terminal.Data data2) => new TagDefinition("A particular terminal extraction location", get_Location_TerminalExtractions(data2))); } } [EnableFeatureByDefault] [AutomatedFeature] public class APCommandExtractHandler : ArchipelagoFeature { private class ExtractCommand : APCommandHandler.SubCommand { public override string HelpText => "EXTRACT high-security item codes from this terminal\nEach terminal contains unique high-security codes\nUse the RELEASE command with high-security item codes to RELEASE items to the MULTIWORLD"; public ExtractCommand() { base.SubCommandName = "EXTRACT"; } public override void Execute(LG_ComputerTerminal terminal, string fullLine, string subCommand, string param2) { terminal.m_command.AddOutput((TerminalLineType)2, "Extracting codes", 3.5f, (TerminalSoundType)0, (TerminalSoundType)2); StateTracker stateTracker = StateTracker.Get(); Game.Data gameData = stateTracker.MidManager.GetProcessedGameData(); IEnumerable<(string, LocationID)> enumerable = MakeItemCodes(stateTracker, terminal); bool flag = false; foreach (var item in enumerable) { Location location = gameData.Locations.LookUpValueChecked(item.Item2); bool flag2 = IsEmpty(stateTracker, item.Item2, location); terminal.AddLine("\n |--------------| " + (flag2 ? "" : (" Item: " + itemName())), false); terminal.AddLine(" | " + item.Item1 + " | " + (flag2 ? "-- MODULE EMPTY --" : ("World: " + itemGame())), false); terminal.AddLine(" |--------------| " + (flag2 ? "" : ("Owner: " + itemPlayer())), false); flag = true; string itemGame() { return location.ScoutedGameName ?? "DEBUG"; } string itemName() { return location.ScoutedItemName ?? gameData.Items.LookUpName(location.ItemID); } string itemPlayer() { return location.ScoutedPlayerName ?? StateTracker.Config.Username; } } if (flag) { stateTracker.ScoutLocations(enumerable.Select(((string, LocationID) pair) => pair.Item2), (HintCreationPolicy)2); terminal.AddLine("\n -- END OF LIST --", true); } else { terminal.AddLine("\n -- NOTHING TO EXTRACT --", true); } } } private class ReleaseCommand : APCommandHandler.SubCommand { public override string HelpText => "Use a high-security item code from EXTRACT to release an item to the MULTIWORLD\nExample: `AP RELEASE XXXX-XX-XXXX`"; public ReleaseCommand() { base.SubCommandName = "RELEASE"; } public override void Execute(LG_ComputerTerminal terminal, string fullLine, string subCommand, string param2) { StateTracker stateTracker = StateTracker.Get(); (string, LocationID) pair = MakeItemCodes(stateTracker, terminal).FirstOrDefault<(string, LocationID)>(((string, LocationID) p) => string.Compare(p.Item1, param2, StringComparison.OrdinalIgnoreCase) == 0, (string.Empty, default(LocationID))); Game.Data processedGameData = stateTracker.MidManager.GetProcessedGameData(); if (pair.Item2.IsNull) { terminal.m_command.AddOutput((TerminalLineType)3, "Releasing item " + param2.ToUpper(), 2.5f, (TerminalSoundType)0, (TerminalSoundType)3); terminal.AddLine("<#F00>Incorrect item code!", true); return; } terminal.m_command.AddOutput((TerminalLineType)2, "Releasing item " + param2.ToUpper(), 2.5f, (TerminalSoundType)0, (TerminalSoundType)2); Location location = stateTracker.GameData.Locations.LookUpValueChecked(pair.Item2); if (location.ItemID.IsNull) { terminal.AddLine("No item to release.", true); return; } terminal.AddLine("Item released successfully: " + location.ScoutedItemName, true); LG_ComputerTerminalCommandInterpreter command = terminal.m_command; command.OnEndOfQueue += (Action)new Il2CppAction(delegate { StateTracker.Get().NotifyFoundLocation(pair.Item2, terminal.m_syncedInteractionSource); }); } } private class TrashCommand : APCommandHandler.SubCommand { public override string HelpText => "Mark all items found using the EXTRACT command as trash.\nThis marks them as found in the menu, but does not release them to the multiworld."; public TrashCommand() { base.SubCommandName = "TRASH"; } public override void Execute(LG_ComputerTerminal terminal, string fullLine, string subCommand, string param2) { StateTracker stateTracker = StateTracker.Get(); List list = (from pair in MakeItemCodes(stateTracker, terminal) where !IsEmpty(stateTracker, pair.Item2) select pair.Item2).ToList(); stateTracker.MarkAsTrash(list, terminal.m_syncedInteractionSource); terminal.m_command.AddOutput($"You have marked {list.Count} item{((list.Count == 1) ? "" : "s")} as <#F00>TRASH", true); } } [ArchivePatch(/*Could not decode attribute arguments.*/)] public static class LG_ComputerTerminalCommandInterpreter__AddInitialTerminalOutput__Patch { public static void Postfix(LG_ComputerTerminalCommandInterpreter __instance) { if (!__instance.m_terminal.m_isSetup) { return; } IdentifyingLogHandler.IdentifyTerminalResult identifyTerminalResult = Terminal.Data.FromTerminal(__instance.m_terminal); if (identifyTerminalResult.Data == null) { if (!identifyTerminalResult.IsReactorTerminal) { FeatureLogger.Error("Failed to lookup terminal data: " + __instance.m_terminal.ItemKey); } return; } Terminal.Data data = identifyTerminalResult.Data; StateTracker stateTracker = StateTracker.Get(); Game.Data processedGameData = stateTracker.MidManager.GetProcessedGameData(); int num = 0; for (int i = 0; i < 3; i++) { LocationID id = data.Location_TerminalExtraction_Instance(i + 1); Location location = data.Locations.LookUpValueChecked(id); if (!location.ItemID.IsNull && !stateTracker.HasLocation(id)) { num++; } } if (num == 1) { __instance.AddOutput("There is 1 available item on this terminal", false); } else { __instance.AddOutput($"There are {num} available items on this terminal", false); } Queue outputQueue = __instance.m_outputQueue; int num2 = (outputQueue._head + outputQueue.Count - 1) % outputQueue._array.Count; for (int j = 0; j < 5; j++) { int num3 = num2 - 1; if (num3 < 0) { num3 = outputQueue._array.Count - 1; } TerminalLine val = outputQueue._array[num3]; outputQueue._array[num3] = outputQueue._array[num2]; outputQueue._array[num2] = val; num2 = num3; } } } [ArchivePatch(/*Could not decode attribute arguments.*/)] public static class LG_ComputerTerminal___Setup_b__117_0__Patch { public static void Postfix(LG_ComputerTerminal __instance, List __result) { __result.Add(string.Empty); int i; for (i = 1; i < __result.Count && !__result[i].StartsWith("---------"); i++) { } StateTracker stateTracker = StateTracker.Get(); IEnumerable<(string, LocationID)> enumerable = from pair in MakeItemCodes(stateTracker, __instance) where !IsEmpty(stateTracker, pair.Item2) select pair; __result.Insert(i++, "AVAILABLE EXTRACTIONS:"); if (!enumerable.Any()) { __result.Insert(i++, " -- NO EXTRACTIONS FOUND --"); return; } foreach (var item in enumerable) { Location location = stateTracker.GameData.Locations.LookUpValueChecked(item.Item2); __result.Insert(i++, " (" + location.ScoutedPlayerName + ") " + location.ScoutedItemName); } __result.Insert(i++, " -- END OF LIST --"); stateTracker.ScoutLocations(enumerable.Select(((string, LocationID) pair) => pair.Item2), (HintCreationPolicy)2); } } private static IArchiveLogger? m_featureLogger; public const int ItemsPerTerminal = 3; public const float ExtractDelay = 3.5f; public const float ReleaseDelay = 2.5f; private ExtractCommand? m_extractCommand; private ReleaseCommand? m_releaseCommand; private TrashCommand? m_trashCommand; public override string Name => "AP Extract Command"; public override string Description => "Adds the EXTRACT, RELEASE, and TRASH subcommands to the AP command"; public override FeatureGroup Group => ArchipelagoFeatureGroups.get_TerminalHandlers(); public new static IArchiveLogger FeatureLogger { get { return m_featureLogger ?? Plugin.Get().Logger; } set { m_featureLogger = value; } } public override void OnEnable() { base.OnEnable(); APCommandHandler.RegisterCommand(m_extractCommand ?? (m_extractCommand = new ExtractCommand())); APCommandHandler.RegisterCommand(m_releaseCommand ?? (m_releaseCommand = new ReleaseCommand())); APCommandHandler.RegisterCommand(m_trashCommand ?? (m_trashCommand = new TrashCommand())); } public override void OnDisable() { base.OnDisable(); APCommandHandler.UnregisterCommand(m_extractCommand ?? (m_extractCommand = new ExtractCommand())); APCommandHandler.UnregisterCommand(m_releaseCommand ?? (m_releaseCommand = new ReleaseCommand())); APCommandHandler.UnregisterCommand(m_trashCommand ?? (m_trashCommand = new TrashCommand())); } private static IEnumerable<(string, LocationID)> MakeItemCodes(StateTracker stateTracker, LG_ComputerTerminal terminal) { Terminal.Data data = Terminal.Data.FromTerminal(terminal).Data; if (data == null) { return Enumerable.Empty<(string, LocationID)>(); } SHA256 sHA = SHA256.Create(); Span destination = stackalloc byte[8]; BinaryPrimitives.WriteInt64LittleEndian(destination, stateTracker.RootSeed); sHA.TransformBlock(destination.ToArray(), 0, 8, null, 0); byte[] bytes = Encoding.UTF8.GetBytes(data.TerminalName); sHA.TransformFinalBlock(bytes, 0, bytes.Length); bytes = sHA.Hash; int num = 0; for (int i = 0; i < bytes.Length; i += 4) { num ^= BinaryPrimitives.ReadInt32LittleEndian(bytes.AsSpan(i, 4)); } Random random = new Random(num); Game.Data processedGameData = stateTracker.MidManager.GetProcessedGameData(); (string, LocationID)[] array = new(string, LocationID)[3]; for (int j = 0; j < 3; j++) { array[j] = ($"{r()}{r()}{r()}{r()}-{r()}{r()}-{r()}{r()}{r()}{r()}", data.Location_TerminalExtraction_Instance(j + 1)); } return array; char r() { int num2 = (int)(36.0 * random.NextDouble()); return (char)((num2 >= 10) ? (65 + (num2 - 10)) : (48 + num2)); } } private static bool IsEmpty(StateTracker stateTracker, LocationID id) { return IsEmpty(stateTracker, id, stateTracker.GameData.Locations.LookUpValueChecked(id)); } private static bool IsEmpty(StateTracker stateTracker, LocationID id, Location loc) { if (!id.IsNull && !loc.ItemID.IsNull) { return stateTracker.HasLocation(id, includeTrash: false); } return true; } [Terminal.Callback] public void AddTerminalItems(Terminal.Data data) { for (int i = 1; i <= 3; i++) { data.Locations.CreateValue(data.Location_TerminalExtraction_Instance(i), data.Region_Terminal, new LocationData { IsEmpty = true }); } } } [EnableFeatureByDefault] [AutomatedFeature] public class APCommandHandler : ArchipelagoFeature { public abstract class SubCommand { public string SubCommandName { get; init; } = ""; public abstract string HelpText { get; } public abstract void Execute(LG_ComputerTerminal terminal, string fullLine, string subCommand, string param2); } [ArchivePatch(/*Could not decode attribute arguments.*/)] public static class LG_ComputerTerminalCommandInterpreter__SetupCommands__Patch { public static void Postfix(LG_ComputerTerminalCommandInterpreter __instance) { //IL_00f2: Unknown result type (might be due to invalid IL or missing references) //IL_00f7: Unknown result type (might be due to invalid IL or missing references) //IL_0103: Unknown result type (might be due to invalid IL or missing references) //IL_010a: Unknown result type (might be due to invalid IL or missing references) //IL_0117: Expected O, but got Unknown //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Expected O, but got Unknown //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Expected O, but got Unknown //IL_0028: 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_0036: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Expected O, but got Unknown //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_0072: 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_0085: Unknown result type (might be due to invalid IL or missing references) //IL_0088: Expected O, but got Unknown //IL_008d: Expected O, but got Unknown TextDataBlock val = GameDataBlockBase.GetBlock("Archipelago - Command Help"); if (val == null) { TextDataBlock val2 = new TextDataBlock(); ((GameDataBlockBase)val2).internalEnabled = true; ((GameDataBlockBase)val2).name = "Archipelago - Command Help"; val2.SkipLocalization = false; val2.MachineTranslation = true; val2.English = "ARCHIPELAGO utility tool. Run `AP HELP` for more details"; val2.Description = ""; val2.CharacterMetaData = 1u; val2.ImportVersion = 1; val2.ExportVersion = 1; val = val2; TextDataBlock obj = val; TextDataBlock obj2 = val; TextDataBlock obj3 = val; TextDataBlock obj4 = val; TextDataBlock obj5 = val; TextDataBlock obj6 = val; TextDataBlock obj7 = val; TextDataBlock obj8 = val; TextDataBlock obj9 = val; TextDataBlock obj10 = val; TextDataBlock obj11 = val; LanguageData val3 = new LanguageData { Translation = val.English, ShouldTranslate = true }; LanguageData val4 = val3; obj11.Chinese_Simplified = val3; LanguageData val5 = (obj10.Chinese_Traditional = val4); LanguageData val7 = (obj9.Korean = val5); LanguageData val9 = (obj8.Japanese = val7); LanguageData val11 = (obj7.Polish = val9); LanguageData val13 = (obj6.Portuguese_Brazil = val11); LanguageData val15 = (obj5.Russian = val13); LanguageData val17 = (obj4.Spanish = val15); LanguageData val19 = (obj3.German = val17); LanguageData french = (obj2.Italian = val19); obj.French = french; GameDataBlockBase.AddBlock(val, -1); } LocalizedText val22 = new LocalizedText { Id = ((GameDataBlockBase)(object)val).persistentID, OldId = 0u, UntranslatedText = val.English }; __instance.AddCommand((TERM_Command)42, "AP", val22, (TERM_CommandRule)0); } } [ArchivePatch(/*Could not decode attribute arguments.*/)] public static class LG_ComputerTerminalCommandInterpreter__ReceiveCommand__Patch { public static bool Prefix(LG_ComputerTerminalCommandInterpreter __instance, TERM_Command cmd, string inputLine, string param1, string param2) { if (!inputLine.StartsWith("AP")) { return true; } __instance.ResetLinesSinceCommand(); __instance.AddOutput(__instance.NewLineStart() + inputLine, false); string text = param1?.ToUpper() ?? string.Empty; if (m_subCommands.TryGetValue(text, out SubCommand value)) { value.Execute(__instance.m_terminal, inputLine, text, param2); } else { if (text.Length > 0) { __instance.AddOutput("<#F00>Sub-commmand not recognized: " + text + "", true); } __instance.AddOutput("Use the command <#FF0>AP HELP to see a list of commands.", true); } return false; } } private static IArchiveLogger? m_featureLogger = null; public const TERM_Command CommandSlot = (TERM_Command)42; public const float CommandDelay = 3f; private static Dictionary m_subCommands = new Dictionary(); public override string Name => "AP Command"; public override string Description => "Adds the AP command to terminals, and allows other handlers to add subcommands to AP"; public override FeatureGroup Group => ArchipelagoFeatureGroups.get_TerminalHandlers(); public new static IArchiveLogger FeatureLogger { get { return m_featureLogger ?? Plugin.Get().Logger; } set { m_featureLogger = value; } } public static IReadOnlyDictionary SubCommands => m_subCommands; public override void OnEnable() { base.OnEnable(); LG_ComputerTerminalManager current = LG_ComputerTerminalManager.Current; ValueCollection val = ((current == null) ? null : current.m_terminals?.values); if (val != null) { Enumerator enumerator = val.GetEnumerator(); while (enumerator.MoveNext()) { LG_ComputerTerminal current2 = enumerator.Current; LG_ComputerTerminalCommandInterpreter__SetupCommands__Patch.Postfix(current2.m_command); } } } public override void OnDisable() { base.OnDisable(); LG_ComputerTerminalManager current = LG_ComputerTerminalManager.Current; ValueCollection val = ((current == null) ? null : current.m_terminals?.values); if (val != null) { Enumerator enumerator = val.GetEnumerator(); while (enumerator.MoveNext()) { LG_ComputerTerminal current2 = enumerator.Current; current2.TrySyncSetCommandHidden((TERM_Command)42); } } } public static void RegisterCommand(SubCommand command) { if (!m_subCommands.TryAdd(command.SubCommandName.ToUpper(), command)) { FeatureLogger.Error("Failed to add duplicate command with name \"" + command.SubCommandName + "\""); } } public static void UnregisterCommand(SubCommand command) { if (!m_subCommands.Remove(command.SubCommandName.ToUpper())) { FeatureLogger.Warning("Could not to remove subcommand \"" + command.SubCommandName + "\" because it was not registered"); } } } [EnableFeatureByDefault] [AutomatedFeature] public class APCommandHelpHandler : ArchipelagoFeature { private class HelpCommand : APCommandHandler.SubCommand { public override string HelpText => "Shows this menu"; public HelpCommand() { base.SubCommandName = "HELP"; } public override void Execute(LG_ComputerTerminal terminal, string fullLine, string subCommand, string param2) { terminal.AddLine("AP is an ARCHIPELAGO utility tool for accessing MUTLTIWORLD items.", true); terminal.AddLine("Available SUBCOMMANDs:", true); foreach (KeyValuePair subCommand2 in APCommandHandler.SubCommands) { terminal.m_command.AddOutputWithPrefixAndTabbedIndentation(subCommand2.Key, subCommand2.Value.HelpText, true); } } } private static IArchiveLogger? m_featureLogger; private HelpCommand? m_helpCommand; public override string Name => "AP Help Command"; public override string Description => "Adds the HELP subcommand to the AP command"; public override FeatureGroup Group => ArchipelagoFeatureGroups.get_TerminalHandlers(); public new static IArchiveLogger FeatureLogger { get { return m_featureLogger ?? Plugin.Get().Logger; } set { m_featureLogger = value; } } public override void OnEnable() { base.OnEnable(); APCommandHandler.RegisterCommand(m_helpCommand ?? (m_helpCommand = new HelpCommand())); } public override void OnDisable() { base.OnDisable(); APCommandHandler.UnregisterCommand(m_helpCommand ?? (m_helpCommand = new HelpCommand())); } } [EnableFeatureByDefault] [AutomatedFeature] public class APCommandItemsHandler : ArchipelagoFeature { private class ClaimItemsHelper { public Action thisAction; public LG_ComputerTerminal terminal; public int currentIndex; public List claimActions = new List(); public ClaimItemsHelper() { thisAction = new Il2CppAction(DoWork); } public void DoWork() { while (currentIndex < claimActions.Count) { claimActions[currentIndex++](); if (terminal.m_command.m_outputQueue.Count > 0) { break; } } if (currentIndex >= claimActions.Count) { LG_ComputerTerminalCommandInterpreter command = terminal.m_command; command.OnEndOfQueue -= thisAction; } } } private class ItemsCommand : APCommandHandler.SubCommand { public override string HelpText => "List the items currently available to YOU. You may optionally provide a single text filter, which is matched by name.\nNote: Available items will vary by expedition"; public ItemsCommand() { base.SubCommandName = "ITEMS"; } public override void Execute(LG_ComputerTerminal terminal, string fullLine, string subCommand, string param2) { LG_ComputerTerminalCommandInterpreter command = terminal.m_command; string text = param2; command.AddOutput((TerminalLineType)2, "Fetching currently available items" + ((text != null && text.Length == 0) ? "" : (" matching filter \"" + param2 + "\"")), 2.5f, (TerminalSoundType)0, (TerminalSoundType)2); StateTracker stateTracker = StateTracker.Get(); Game.Data gameData = stateTracker.MidManager.GetProcessedGameData(); string text2 = param2; IEnumerable<(ItemID, string)> enumerable = ((text2 != null && text2.Length != 0) ? stateTracker.ItemsInTerminalSystem.Where<(ItemID, string)>(((ItemID, string) pair) => gameData.Items.LookUpName(pair.Item1).Contains(param2, StringComparison.OrdinalIgnoreCase)) : stateTracker.ItemsInTerminalSystem); if (!enumerable.Any()) { terminal.AddLine(string.Empty, true); terminal.AddLine(" -- NO ITEMS FOUND --", true); return; } terminal.AddLine(string.Empty, true); terminal.AddLine(" ITEM CODE ITEM NAME", false); foreach (var item in enumerable) { terminal.AddLine(item.Item2 + " " + gameData.Items.LookUpName(item.Item1), false); } terminal.AddLine(string.Empty, true); } } private class ClaimCommand : APCommandHandler.SubCommand { public override string HelpText => "Retrieve all of YOUR items. Can optionally include a filter\nExample: `AP CLAIM KEY` will claim all items with \"KEY\" in their name"; public ClaimCommand() { base.SubCommandName = "CLAIM"; } public override void Execute(LG_ComputerTerminal terminal, string fullLine, string subCommand, string param2) { StateTracker stateTracker = StateTracker.Get(); Game.Data gameData = stateTracker.MidManager.GetProcessedGameData(); List<(ItemID, string)> source = stateTracker.ItemsInTerminalSystem.Where(predicate).ToList(); string firstMessage = ((param2 == null || param2.Trim().Length == 0) ? "Preparing all items to be claimed" : ("Collecting items to be claimed using filter \"" + param2.ToUpper() + "\"")); if (!source.Any()) { terminal.m_command.AddOutput((TerminalLineType)3, firstMessage, 3f, (TerminalSoundType)0, (TerminalSoundType)3); if (param2 == null || param2.Trim().Length == 0) { terminal.m_command.AddOutput("<#F00>No items available to be claimed!", true); } else { terminal.m_command.AddOutput("<#F00>No items matching filter!", true); } return; } List list = source.SelectMany(((ItemID, string) p) => gameData.Items.LookUpValueChecked(p.Item1).OnRetrieveFromTerminalSystem(stateTracker, terminal, p.Item1)).ToList(); stateTracker.ItemsInTerminalSystem.RemoveAll(predicate); Action onEndOfQueue = terminal.m_command.OnEndOfQueue; IEnumerable enumerable = (IEnumerable)((onEndOfQueue != null) ? ((Delegate)onEndOfQueue).GetInvocationList() : null); foreach (Delegate item in enumerable ?? Enumerable.Empty()) { Il2CppAction il2CppAction = ((Il2CppObjectBase)item.Target).TryCast(); if (il2CppAction != null && il2CppAction.WrappedAction?.Target is ClaimItemsHelper claimItemsHelper) { claimItemsHelper.claimActions.AddRange(list.Prepend(postMessage)); return; } } postMessage(); ClaimItemsHelper claimItemsHelper2 = new ClaimItemsHelper { terminal = terminal, currentIndex = 0, claimActions = list }; LG_ComputerTerminalCommandInterpreter command = terminal.m_command; command.OnEndOfQueue += claimItemsHelper2.thisAction; void postMessage() { terminal.m_command.AddOutput((TerminalLineType)2, firstMessage, 3f, (TerminalSoundType)0, (TerminalSoundType)2); } bool predicate((ItemID, string) pair) { if (param2 != null) { return gameData.Items.LookUpName(pair.Item1).Contains(param2, StringComparison.OrdinalIgnoreCase); } return true; } } } private class CACommand : ClaimCommand { public override string HelpText => "Alias for CLAIM"; public CACommand() { base.SubCommandName = "CA"; } } private class ClaimCode : APCommandHandler.SubCommand { public override string HelpText => "Claim one of YOUR currently-held items using its code.\nUseful when you want to retrieve exactly one item when items share names."; public ClaimCode() { base.SubCommandName = "CLAIM_CODE"; } public override void Execute(LG_ComputerTerminal terminal, string fullLine, string subCommand, string param2) { StateTracker stateTracker = StateTracker.Get(); (ItemID, string) item = stateTracker.ItemsInTerminalSystem.FirstOrDefault<(ItemID, string)>(((ItemID, string) pair) => string.Compare(pair.Item2, param2, StringComparison.OrdinalIgnoreCase) == 0, (default(ItemID), string.Empty)); if (item.Item1.IsNull) { terminal.m_command.AddOutput((TerminalLineType)3, "Searching for item " + param2.ToUpper(), 2f, (TerminalSoundType)0, (TerminalSoundType)3); terminal.m_command.AddOutput("<#F00>Incorrect item code!", true); return; } terminal.m_command.AddOutput((TerminalLineType)2, "Searching for item " + param2.ToUpper(), 2f, (TerminalSoundType)0, (TerminalSoundType)2); ClaimItemsHelper claimItemsHelper = new ClaimItemsHelper { terminal = terminal.m_command.m_terminal, currentIndex = 0, claimActions = stateTracker.MidManager.GetProcessedGameData().Items.LookUpValueChecked(item.Item1).OnRetrieveFromTerminalSystem(stateTracker, terminal, item.Item1).ToList() }; LG_ComputerTerminalCommandInterpreter command = terminal.m_command; command.OnEndOfQueue += claimItemsHelper.thisAction; stateTracker.ItemsInTerminalSystem.Remove(item); } } [ArchivePatch(/*Could not decode attribute arguments.*/)] private static class DontUnscubscribeMePatch { public static void Prefix(LG_ComputerTerminalCommandInterpreter __instance, ref ClaimItemsHelper? __state) { __state = null; if ((Delegate)(object)__instance.OnEndOfQueue == (Delegate)null) { return; } foreach (Delegate item in (Il2CppArrayBase)(object)((Delegate)__instance.OnEndOfQueue).GetInvocationList()) { Il2CppAction il2CppAction = ((Il2CppObjectBase)item.Target).TryCast(); if (il2CppAction != null && il2CppAction.WrappedAction?.Target is ClaimItemsHelper claimItemsHelper) { __state = claimItemsHelper; break; } } } public static void Postfix(LG_ComputerTerminalCommandInterpreter __instance, ClaimItemsHelper? __state) { if (__state != null && __state.currentIndex < __state.claimActions.Count && __instance.OnEndOfQueue == null) { __instance.OnEndOfQueue += __state.thisAction; } } } private static IArchiveLogger? m_featureLogger; private const float ItemsDelay = 2.5f; private const float ClaimDelay = 2f; private const float ClaimAllDelay = 3f; private ItemsCommand? m_itemsCommand; private ClaimCommand? m_claimCommand; private CACommand? m_caCommand; private ClaimCode? m_claimCodeCommand; public override string Name => "AP Item Commands"; public override string Description => "Adds the ITEMS, CLAIM, CA, and CLAIM_CODE subcommands to the AP command"; public override FeatureGroup Group => ArchipelagoFeatureGroups.get_TerminalHandlers(); public new static IArchiveLogger FeatureLogger { get { return m_featureLogger ?? Plugin.Get().Logger; } set { m_featureLogger = value; } } public override void OnEnable() { base.OnEnable(); APCommandHandler.RegisterCommand(m_itemsCommand ?? (m_itemsCommand = new ItemsCommand())); APCommandHandler.RegisterCommand(m_claimCommand ?? (m_claimCommand = new ClaimCommand())); APCommandHandler.RegisterCommand(m_caCommand ?? (m_caCommand = new CACommand())); APCommandHandler.RegisterCommand(m_claimCodeCommand ?? (m_claimCodeCommand = new ClaimCode())); } public override void OnDisable() { base.OnDisable(); APCommandHandler.UnregisterCommand(m_itemsCommand ?? (m_itemsCommand = new ItemsCommand())); APCommandHandler.UnregisterCommand(m_claimCommand ?? (m_claimCommand = new ClaimCommand())); APCommandHandler.UnregisterCommand(m_caCommand ?? (m_caCommand = new CACommand())); APCommandHandler.UnregisterCommand(m_claimCodeCommand ?? (m_claimCodeCommand = new ClaimCode())); } } [InjectToIl2Cpp] [EnableFeatureByDefault] [AutomatedFeature] public class IdentifyingLogHandler : ArchipelagoFeature { public struct IdentifyTerminalResult { public bool IsReactorTerminal; public Terminal.Data? Data; public IdentifyTerminalResult(bool isReactor, Terminal.Data? data) { IsReactorTerminal = isReactor; Data = data; } } [InjectToIl2Cpp] private class IdentifyingLogTextDataBlock : TextDataBlock { [HideFromIl2Cpp] public RegionID TerminalRegion { get; init; } public IdentifyingLogTextDataBlock() : base(ClassInjector.DerivedConstructorPointer()) { ClassInjector.DerivedConstructorBody((Il2CppObjectBase)(object)this); } public IdentifyingLogTextDataBlock(IntPtr ptr) : base(ptr) { } } private static IArchiveLogger? m_featureLogger; private const string IdentifyingLogName = "TERMINAL_NAME.LOG"; public override string Name => "Identifying Log Handler"; public override string Description => "Adds identifying logs to terminals. Used by other handlers to identify the terminal during play"; public override FeatureGroup Group => ArchipelagoFeatureGroups.get_TerminalHandlers(); public new static IArchiveLogger FeatureLogger { get { return m_featureLogger ?? Plugin.Get().Logger; } set { m_featureLogger = value; } } public static IdentifyTerminalResult RetrieveDataFromLog(LG_ComputerTerminal terminal) { if ((Object)(object)terminal.ConnectedReactor != (Object)null) { return new IdentifyTerminalResult(isReactor: true, null); } int num = terminal.m_localLogs.FindEntry("TERMINAL_NAME.LOG"); if (num < 0) { AIG_CourseNode spawnNode = terminal.SpawnNode; Zone.Data obj = (((Object)(object)((spawnNode != null) ? spawnNode.m_zone : null) == (Object)null) ? null : Zone.Data.GetFromZone(terminal.SpawnNode.m_zone)); FeatureLogger.Warning("Failed to find identifying log from " + terminal.ItemKey + " in " + (obj?.ZoneName ?? "ZONE_NULL")); return new IdentifyTerminalResult(isReactor: false, null); } Entry val = ((Il2CppArrayBase>)(object)terminal.m_localLogs.entries)[num]; TextDataBlock block = GameDataBlockBase.GetBlock(val.value.FileContent.Id); IdentifyingLogTextDataBlock identifyingLogTextDataBlock = ((block != null) ? ((Il2CppObjectBase)block).TryCast() : null); if (identifyingLogTextDataBlock == null) { Zone.Data fromZone = Zone.Data.GetFromZone(terminal.SpawnNode.m_zone); FeatureLogger.Warning("Failed to retrieving identifying data from log for terminal in zone: " + fromZone.ZoneName); return new IdentifyTerminalResult(isReactor: false, null); } return new IdentifyTerminalResult(isReactor: false, new Terminal.Data(StateTracker.Get().GameData, identifyingLogTextDataBlock.TerminalRegion)); } [Terminal.Callback] public void AddIdentifyingLog(Terminal.Data data) { //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_0099: Unknown result type (might be due to invalid IL or missing references) //IL_00a1: Expected O, but got Unknown //IL_016f: Unknown result type (might be due to invalid IL or missing references) //IL_0174: Unknown result type (might be due to invalid IL or missing references) //IL_017f: Unknown result type (might be due to invalid IL or missing references) //IL_0186: Unknown result type (might be due to invalid IL or missing references) //IL_0187: 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_0198: 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_01b0: Expected O, but got Unknown //IL_01b0: 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_01be: Unknown result type (might be due to invalid IL or missing references) //IL_01ca: Expected O, but got Unknown if (data.TerminalLocalLogs.Count <= 0 || !data.TerminalLocalLogs.Any((TerminalLogFileData l) => l.FileName == "TERMINAL_NAME.LOG")) { string name = data.TerminalName + " Identifying Log"; LanguageData val = new LanguageData { Translation = $"[{data.TerminalIndex}] {data.TerminalName}", ShouldTranslate = false }; IdentifyingLogTextDataBlock obj = new IdentifyingLogTextDataBlock { internalEnabled = true, name = name }; ((TextDataBlock)obj).SkipLocalization = true; ((TextDataBlock)obj).MachineTranslation = true; ((TextDataBlock)obj).English = val.Translation; ((TextDataBlock)obj).Description = ""; ((TextDataBlock)obj).CharacterMetaData = 1u; ((TextDataBlock)obj).ImportVersion = 1; ((TextDataBlock)obj).ExportVersion = 1; obj.TerminalRegion = data.Region_Terminal; ((TextDataBlock)obj).French = val; ((TextDataBlock)obj).Italian = val; ((TextDataBlock)obj).German = val; ((TextDataBlock)obj).Spanish = val; ((TextDataBlock)obj).Russian = val; ((TextDataBlock)obj).Portuguese_Brazil = val; ((TextDataBlock)obj).Polish = val; ((TextDataBlock)obj).Japanese = val; ((TextDataBlock)obj).Korean = val; ((TextDataBlock)obj).Chinese_Traditional = val; ((TextDataBlock)obj).Chinese_Simplified = val; IdentifyingLogTextDataBlock identifyingLogTextDataBlock = obj; GameDataBlockBase.AddBlock((TextDataBlock)(object)identifyingLogTextDataBlock, -1); data.TerminalLocalLogs.Capacity = data.TerminalLocalLogs.Count + 1; data.TerminalLocalLogs.Insert(0, new TerminalLogFileData { FileName = "TERMINAL_NAME.LOG", FileContentOriginalLanguage = (Language)1, FileContent = new LocalizedText { Id = ((GameDataBlockBase)(object)identifyingLogTextDataBlock).persistentID, OldId = 0u, UntranslatedText = ((TextDataBlock)identifyingLogTextDataBlock).English }, AttachedAudioByteSize = 0, AttachedAudioFile = 0u, PlayerDialogToTriggerAfterAudio = 0u }); } } } public static class TerminalLogHelper_Tags { [SpecialName] public sealed class $2B8804A94F2EF68DF77A343A46EE5A78 { [SpecialName] public static class $F943E16B16B76A20C49A59C8DF7C8955 { } [ExtensionMarker("$F943E16B16B76A20C49A59C8DF7C8955")] public LocationID Location_TerminalLogs { [ExtensionMarker("$F943E16B16B76A20C49A59C8DF7C8955")] get { throw new NotSupportedException(); } } [ExtensionMarker("$F943E16B16B76A20C49A59C8DF7C8955")] public ItemID Item_TerminalLogs { [ExtensionMarker("$F943E16B16B76A20C49A59C8DF7C8955")] get { throw new NotSupportedException(); } } } public static LocationID get_Location_TerminalLogs(Game.Data gameData) { return LocationID.From(gameData, "Terminal Log Locations", (Game.Data data) => new TagDefinition("Locations checked by reading specific terminal logs", CommonTagsHandler_Tags.get_Location_All(data))); } public static ItemID get_Item_TerminalLogs(Game.Data gameData) { return ItemID.From(gameData, "Terminal Log Items", (Game.Data data) => new TagDefinition("Items typically obtained by reading specific terminal logs", CommonTagsHandler_Tags.get_Item_All(data))); } } [InjectToIl2Cpp] [AutomatedFeature] [EnableFeatureByDefault] public class TerminalLogHelper : ArchipelagoFeature { public abstract class TerminalLogLocation : Location { public TerminalLogLocation(RegionList regions, LocationData randData, ItemID itemId) : base(regions, randData, itemId) { } public abstract void OnNotRandomized(StateTracker stateTracker, LG_ComputerTerminal terminal); } [InjectToIl2Cpp] private class ContainsLocationLogComp : MonoBehaviour { public SortedList StoredLocations = new SortedList(); } [ArchivePatch(/*Could not decode attribute arguments.*/)] public static class LG_ComputerTerminalCommandInterpreter__ReadLog__Patch { public static void Postfix(LG_ComputerTerminalCommandInterpreter __instance, string param1, string param2) { ContainsLocationLogComp component = ((Component)__instance.m_terminal).GetComponent(); if (!((Object)(object)component == (Object)null) && component.StoredLocations.TryGetValue(param1.ToUpper(), out var value)) { StateTracker stateTracker = StateTracker.Get(); Location location = stateTracker.NotifyFoundLocation(value, __instance.m_terminal.m_syncedInteractionSource); if (!location.RandData.IsTreatedAsRandom && location is TerminalLogLocation terminalLogLocation) { terminalLogLocation.OnNotRandomized(stateTracker, __instance.m_terminal); } } } } private static IArchiveLogger? m_featureLogger; public override string Name => "Terminal Log Helper"; public override string Description => "Helper for other handlers\nAssociates terminal logs with locations, so when they're checked that location is checked"; public override FeatureGroup Group => ArchipelagoFeatureGroups.get_TerminalHandlers(); public new static IArchiveLogger FeatureLogger { get { return m_featureLogger ?? Plugin.Get().Logger; } set { m_featureLogger = value; } } public static void AssociateLog(LG_ComputerTerminal terminal, string logName, LocationID locationId, bool overwriteLog = true) { //IL_01a9: Unknown result type (might be due to invalid IL or missing references) //IL_01ae: Unknown result type (might be due to invalid IL or missing references) //IL_01f8: Unknown result type (might be due to invalid IL or missing references) //IL_01ff: Unknown result type (might be due to invalid IL or missing references) //IL_020b: Expected O, but got Unknown logName = logName.ToUpper(); StateTracker stateTracker = StateTracker.Get(); Game.Data gameData = stateTracker.GameData; ContainsLocationLogComp containsLocationLogComp = ((Component)terminal).GetComponent() ?? ((Component)terminal).gameObject.AddComponent(); if (containsLocationLogComp.StoredLocations.TryGetValue(logName, out var value)) { int count = Math.Max(value.ID.ToString().Length, locationId.ID.ToString().Length); string text = new string('0', count); FeatureLogger.Error($"Overwriting location stored in log!\n Old Location: [{value.ID.ToString(text)}] {gameData.Locations.LookUpName(value)} New Location: [{locationId.ID.ToString(text)}] {gameData.Locations.LookUpName(locationId)}"); } containsLocationLogComp.StoredLocations[logName] = locationId; int num = terminal.m_localLogs.FindEntry(logName); if (num == -1) { FeatureLogger.Warning("Failed to look up and overwrite local log while associating log: " + logName); return; } Location location = gameData.Locations.LookUpValueChecked(locationId); if (location.RandData.IsTreatedAsRandom && overwriteLog) { TerminalLogFileData value2 = ((Il2CppArrayBase>)(object)terminal.m_localLogs.entries)[num].value; value2.FileContent = new LocalizedText { UntranslatedText = "Congratulations! By viewing this log, you have obtained the following item(s):\n " + (location.ScoutedItemName ?? (location.ItemID.IsNull ? "None" : gameData.Items.LookUpName(location.ItemID))), OldId = 0u, Id = 0u }; } } } public static class TerminalPasswordHandler_Tags { [SpecialName] public sealed class $2B8804A94F2EF68DF77A343A46EE5A78 { [SpecialName] public static class $F943E16B16B76A20C49A59C8DF7C8955 { } [ExtensionMarker("$F943E16B16B76A20C49A59C8DF7C8955")] public LocationID Location_TerminalPasswords { [ExtensionMarker("$F943E16B16B76A20C49A59C8DF7C8955")] get { throw new NotSupportedException(); } } [ExtensionMarker("$F943E16B16B76A20C49A59C8DF7C8955")] public ItemID Item_TerminalPasswords { [ExtensionMarker("$F943E16B16B76A20C49A59C8DF7C8955")] get { throw new NotSupportedException(); } } } [SpecialName] public sealed class $63BA103E62A55F64C05B172EF249EC99 { [SpecialName] public static class $DE04A58E69D058D9CEE64C49EAD6305E { } [ExtensionMarker("$DE04A58E69D058D9CEE64C49EAD6305E")] public LocationID Location_TerminalPasswords_ByTerminal { [ExtensionMarker("$DE04A58E69D058D9CEE64C49EAD6305E")] get { throw new NotSupportedException(); } } [ExtensionMarker("$DE04A58E69D058D9CEE64C49EAD6305E")] public ItemID Item_TerminalPasswords_ByTerminal { [ExtensionMarker("$DE04A58E69D058D9CEE64C49EAD6305E")] get { throw new NotSupportedException(); } } [ExtensionMarker("$DE04A58E69D058D9CEE64C49EAD6305E")] public LocationID Location_TerminalPasswords_Instance(int count) { throw new NotSupportedException(); } [ExtensionMarker("$DE04A58E69D058D9CEE64C49EAD6305E")] public ItemID Item_TerminalPasswords_Instance(int count) { throw new NotSupportedException(); } } public static LocationID get_Location_TerminalPasswords(Game.Data gameData) { return LocationID.From(gameData, "Terminal Password Part Locations", (Game.Data data) => new TagDefinition("Locations checked by opening logs containing terminal password parts", TerminalLogHelper_Tags.get_Location_TerminalLogs(data))); } public static ItemID get_Item_TerminalPasswords(Game.Data gameData) { return ItemID.From(gameData, "Terminal Password Part Item", (Game.Data data) => new TagDefinition("A part of a terminal password", CommonTagsHandler_Tags.get_Item_Codes(data))); } public static LocationID get_Location_TerminalPasswords_ByTerminal(Terminal.Data data) { return LocationID.From(data, data.TerminalName + " Password Locations", (Terminal.Data gameData) => new TagDefinition("Password part locations for a specific terminal", get_Location_TerminalPasswords(gameData))); } public static ItemID get_Item_TerminalPasswords_ByTerminal(Terminal.Data data) { return ItemID.From(data, data.TerminalName + " Password Parts", (Terminal.Data gameData) => new TagDefinition("Password parts for a specific terminal", get_Item_TerminalPasswords(gameData))); } public static LocationID Location_TerminalPasswords_Instance(this Terminal.Data data, int count) { return LocationID.From(data, $"{data.TerminalName} Password Location #{count}", (Terminal.Data data2) => new TagDefinition("A particular password part's location", get_Location_TerminalPasswords_ByTerminal(data2))); } public static ItemID Item_TerminalPasswords_Instance(this Terminal.Data data, int count) { return ItemID.From(data, $"{data.TerminalName} Password Part #{count}", (Terminal.Data data2) => new TagDefinition("A particular password part", get_Item_TerminalPasswords_ByTerminal(data2)), new TerminalPasswordHandler.TerminalPasswordPartItem(data.Region_Terminal, count)); } } [EnableFeatureByDefault] [AutomatedFeature] [InjectToIl2Cpp] public class TerminalPasswordHandler : ArchipelagoFeature { public class TerminalPasswordPartItem : TerminalItem { public RegionID TerminalRegion { get; private init; } public int PartNumber { get; private init; } public override RegionID TargetRegion => TerminalRegion; public TerminalPasswordPartItem(RegionID terminal, int count) : base(new ItemData { IsProgression = true }) { TerminalRegion = terminal; PartNumber = count; } public override void OnEnteredExpedition(StateTracker stateTracker, LocationID sourceLocationId, PlayerAgent? player, ItemID itemId) { base.OnEnteredExpedition(stateTracker, sourceLocationId, player, itemId); Terminal.Data data = new Terminal.Data(stateTracker.GameData, TerminalRegion); LG_ComputerTerminal lG_Terminal = data.GetLG_Terminal(); if ((Object)(object)lG_Terminal == (Object)null) { FeatureLogger.Error("Failed to identify spawned terminal while giving password part!"); } else { ProgressionObjective_TerminalPassword.NotifyFoundCode(lG_Terminal, PartNumber); } } public override IEnumerable OnRetrieveFromTerminalSystem(StateTracker stateTracker, LG_ComputerTerminal terminal, ItemID itemId) { Terminal.Data data = new Terminal.Data(stateTracker.GameData, TerminalRegion); LG_ComputerTerminal passwordTerminal = data.GetLG_Terminal(); if ((Object)(object)passwordTerminal == (Object)null) { FeatureLogger.Error("Failed to identify spawned terminal while giving password part!"); } yield return delegate { stateTracker.AddItemToTerminal(itemId); terminal.AddLine((TerminalLineType)2, "Retrieving password", 2f); if ((Object)(object)passwordTerminal == (Object)null) { terminal.AddLine("<#F00>Failed to find password terminal instance! No password to grant.", true); } else { string arg = ProgressionObjective_TerminalPassword.MakePasswordHint(passwordTerminal); terminal.AddLine(string.Format(((Feature)ArchipelagoFeatureHelper.GetFeature()).Localization.Get(1431221909u), arg), true); } }; } } [ArchivePatch(/*Could not decode attribute arguments.*/)] public static class LG_TerminalPasswordLinkerJob__Build__Patch { public static void Postfix(LG_TerminalPasswordLinkerJob __instance) { IdentifyingLogHandler.IdentifyTerminalResult identifyTerminalResult = Terminal.Data.FromTerminal(__instance.m_lockedTerminal); Terminal.Data data = identifyTerminalResult.Data; if (data == null) { if (identifyTerminalResult.IsReactorTerminal) { FeatureLogger.Error("A reactor terminal is password locked; Archipelago can't currently support this!"); } else { FeatureLogger.Error("Null terminal data for password link job!"); } return; } for (int i = 0; i < __instance.m_terminalsWithPasswordParts.Count; i++) { LG_ComputerTerminal val = __instance.m_terminalsWithPasswordParts[i]; LocationID locationID = data.Location_TerminalPasswords_Instance(i + 1); List> list = ((IEnumerable>)val.m_localLogs.entries).Where(delegate(Entry e) { bool? obj; if (e == null) { obj = null; } else { TerminalLogFileData value = e.value; obj = ((value == null) ? ((bool?)null) : value.FileName?.StartsWith("KEY", StringComparison.OrdinalIgnoreCase)); } bool? flag = obj; return flag == true; }).ToList(); if (list.Count == 0) { FeatureLogger.Error("Failed to find any logs for password part location: " + data.Locations.LookUpName(locationID)); } else { TerminalLogHelper.AssociateLog(val, list[0].value.FileName, locationID); } if (list.Count > 1) { FeatureLogger.Warning("Found multiple possible logs for password part location, using first: " + data.Locations.LookUpName(locationID)); } } } } [ArchivePatch(/*Could not decode attribute arguments.*/)] public static class LG_ComputerTerminalCommandInterpreter__TryUnlockingTerminal__Patch { public static void Postfix(LG_ComputerTerminalCommandInterpreter __instance) { LG_ComputerTerminal terminal = __instance.m_terminal; if (terminal.IsPasswordProtected) { return; } IdentifyingLogHandler.IdentifyTerminalResult identifyTerminalResult = Terminal.Data.FromTerminal(terminal); Terminal.Data data = identifyTerminalResult.Data; if (data == null) { if (!identifyTerminalResult.IsReactorTerminal) { FeatureLogger.Error("Unlocked unknown terminal!"); } } else { StateTracker.Get().NotifyFoundRegion(data.TerminalName, terminal.m_syncedInteractionSource); ProgressionObjective_TerminalPassword.Update(terminal); } } } [ArchivePatch(/*Could not decode attribute arguments.*/)] public static class LG_ComputerTerminal__OnFactoryBuildDone__Patch { public static void Postfix(LG_ComputerTerminal __instance) { if (Object.op_Implicit((Object)(object)__instance) && __instance.IsPasswordProtected) { ProgressionObjective_TerminalPassword.Setup(__instance); } } } [ArchivePatch(/*Could not decode attribute arguments.*/)] public static class LG_ComputerTerminal__OnPostRecall__Patch { public static void Postfix(LG_ComputerTerminal __instance) { if (!__instance.IsPasswordProtected) { return; } IdentifyingLogHandler.IdentifyTerminalResult identifyTerminalResult = Terminal.Data.FromTerminal(__instance); if (identifyTerminalResult.Data == null) { FeatureLogger.Error("Failed to update terminal UI post reload; failed to find terminal data!"); return; } for (int i = 1; i <= __instance.m_passwordLinkerJob.m_passwordParts; i++) { LocationID id = identifyTerminalResult.Data.Location_TerminalPasswords_Instance(i); Location location = identifyTerminalResult.Data.Locations.LookUpValueChecked(id); if (!location.RandData.IsTreatedAsRandom) { ProgressionObjective_TerminalPassword.ResetCode(__instance, i); } } ProgressionObjective_TerminalPassword.Update(__instance); } } public class ProgressionObjective_TerminalPassword : CustomObjectiveHandler.ObjectiveItem { private BitArray? m_foundParts; public static string MakeKey(LG_ComputerTerminal terminal) { return ((Il2CppObjectBase)terminal).Pointer.ToString(); } public static void Setup(LG_ComputerTerminal terminal) { CustomObjectiveHandler.GetObjectiveItem(MakeKey(terminal)).SetupWithData(terminal); } public static void Update(LG_ComputerTerminal terminal) { CustomObjectiveHandler.GetObjectiveItem(MakeKey(terminal)).UpdateInternal(terminal); } public static void NotifyFoundCode(LG_ComputerTerminal terminal, int count) { CustomObjectiveHandler.GetObjectiveItem(MakeKey(terminal)).NotifyFoundCodeInternal(terminal, count); } public static void ResetCode(LG_ComputerTerminal terminal, int count) { CustomObjectiveHandler.GetObjectiveItem(MakeKey(terminal)).ResetCodeInternal(terminal, count); } public static string MakePasswordHint(LG_ComputerTerminal terminal) { return CustomObjectiveHandler.GetObjectiveItem(MakeKey(terminal)).MakePasswordHintInternal(terminal); } public override void Setup() { base.IsActive = false; base.Scope = CustomObjectiveHandler.eObjectiveScope.Zone; base.ObjectiveTag = "PASSWORD"; base.HeaderText = "TERMINAL PASSWORD OBJECTIVE"; base.SubText = "Retrieving data..."; base.Setup(); } public void SetupWithData(LG_ComputerTerminal terminal) { //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_0072: 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_0087: Unknown result type (might be due to invalid IL or missing references) if (terminal.m_passwordLinkerJob == null) { m_foundParts = new BitArray(1); m_foundParts[0] = true; } else { LG_TerminalPasswordLinkerJob passwordLinkerJob = terminal.m_passwordLinkerJob; m_foundParts = new BitArray((passwordLinkerJob == null) ? 1 : passwordLinkerJob.m_passwordParts); } base.HeaderText = terminal.m_terminalItem.TerminalItemKey + " Password"; base.ScopeTarget = new GlobalZoneIndex(terminal.SpawnNode.m_zone.DimensionIndex, terminal.SpawnNode.LayerType, terminal.SpawnNode.m_zone.LocalIndex); UpdateInternal(terminal); } public void UpdateInternal(LG_ComputerTerminal terminal) { base.IsActive = terminal.IsPasswordProtected; base.SubText = "Current known password: " + MakePasswordHintInternal(terminal); Refresh(); } public void NotifyFoundCodeInternal(LG_ComputerTerminal terminal, int count) { if (m_foundParts == null) { throw new NullReferenceException("Terminal UI was not properly set up"); } if (count < 1 || count > m_foundParts.Count) { throw new ArgumentOutOfRangeException("Terminal UI notified of a code which was out of bounds"); } m_foundParts[count - 1] = true; UpdateInternal(terminal); } public void ResetCodeInternal(LG_ComputerTerminal terminal, int count) { if (m_foundParts == null) { throw new NullReferenceException("Terminal UI was not properly set up"); } if (count < 1 || count > m_foundParts.Count) { throw new ArgumentOutOfRangeException("Terminal UI notified of a code which was out of bounds"); } m_foundParts[count - 1] = false; UpdateInternal(terminal); } public string MakePasswordHintInternal(LG_ComputerTerminal terminal) { string password = terminal.m_password; LG_TerminalPasswordLinkerJob passwordLinkerJob = terminal.m_passwordLinkerJob; int num = ((passwordLinkerJob != null) ? passwordLinkerJob.m_passwordParts : 0); if (num == 0) { return password; } int perPartCount = password.Length / num; int remainingCount = password.Length % num; if (m_foundParts == null || m_foundParts.Length < num) { throw new InvalidOperationException("Attempted to generate password hint before being set up!"); } IEnumerable values = (from i in Enumerable.Range(1, num) select m_foundParts[i - 1]).Select((bool o, int i) => (!o) ? hide(i) : reveal(i)); return string.Join("", values); string hide(int i) { return new string('–', len(i)); } int len(int i) { if (i >= remainingCount) { return perPartCount; } return perPartCount + 1; } string reveal(int i) { return password.Substring(start(i), len(i)); } int start(int i) { return perPartCount * i + Math.Min(remainingCount, i); } } public override void CheckScope(AIG_CourseNode? localNode = null) { base.CheckScope(localNode); if (base.IsInScope && base.Scope == CustomObjectiveHandler.eObjectiveScope.Zone) { base.Scope = CustomObjectiveHandler.eObjectiveScope.Layer; base.IsActive = true; } } } private static IArchiveLogger? m_featureLogger; public override string Name => "Terminal Password Handler"; public override string Description => "Adds passwords to terminals\nMarks terminal password logs so that the correct location is checked when they're opened"; public override FeatureGroup Group => ArchipelagoFeatureGroups.get_TerminalHandlers(); public new static IArchiveLogger FeatureLogger { get { return m_featureLogger ?? Plugin.Get().Logger; } set { m_featureLogger = value; } } [Terminal.Callback] public void AddPasswordPartItems(Terminal.Data data) { if (!data.TerminalStartingStateData.PasswordProtected) { return; } if (data.TerminalStartingStateData.TerminalZoneSelectionDatas.Count == 0) { FeatureLogger.Warning("Terminal has no placement positions for password parts: " + data.TerminalName); ItemID itemID = data.Item_TerminalPasswords_Instance(1); return; } IEnumerable> enumerable = data.UnstuffPlacements(data.PlacementsToTerminalRegions(data.TerminalStartingStateData.TerminalZoneSelectionDatas), data.TerminalStartingStateData.PasswordPartCount); int num = 0; foreach (List item in enumerable) { num++; data.Locations.CreateValue(data.Location_TerminalPasswords_Instance(num), item, default(LocationData), data.Item_TerminalPasswords_Instance(num)); } } } public static class UniqueCommandsHandler_Tags { [SpecialName] public sealed class $63BA103E62A55F64C05B172EF249EC99 { [SpecialName] public static class $DE04A58E69D058D9CEE64C49EAD6305E { } [ExtensionMarker("$DE04A58E69D058D9CEE64C49EAD6305E")] public RegionID Region_TerminalCommand(CustomTerminalCommand command) { throw new NotSupportedException(); } } public static RegionID Region_TerminalCommand(this Terminal.Data data, CustomTerminalCommand command) { return RegionID.From(data, data.TerminalName + " " + command.Command, (Terminal.Data data2) => new TagDefinition("Region entered by executing a particular custom command on a terminal", data2.Region_Terminal)); } } [EnableFeatureByDefault] [AutomatedFeature] public class UniqueCommandsHandler : ArchipelagoFeature { [ArchivePatch(/*Could not decode attribute arguments.*/)] public static class LG_ComputerTerminalCommandInterpreter__ReceiveCommand__Patch { public static void Postfix(LG_ComputerTerminalCommandInterpreter __instance, TERM_Command cmd, bool __runOriginal) { //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Invalid comparison between Unknown and I4 //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Invalid comparison between Unknown and I4 //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Expected I4, but got Unknown if (!__runOriginal) { return; } IdentifyingLogHandler.IdentifyTerminalResult identifyTerminalResult = Terminal.Data.FromTerminal(__instance.m_terminal); Terminal.Data data = identifyTerminalResult.Data; if (data == null) { if (!identifyTerminalResult.IsReactorTerminal) { FeatureLogger.Error("Null terminal data for unique command detection!"); } } else if ((int)cmd >= 38 && (int)cmd <= 42) { StateTracker.Get().NotifyFoundRegion(data.Region_TerminalCommand(data.TerminalUniqueCommands[cmd - 38]), __instance.m_terminal.m_syncedInteractionSource); } } } private static IArchiveLogger? m_featureLogger; public override string Name => "Unique Command Handler"; public override string Description => "Adds unique terminal commands and events triggered by those commands to Archipelago"; public override FeatureGroup Group => ArchipelagoFeatureGroups.get_TerminalHandlers(); public new static IArchiveLogger FeatureLogger { get { return m_featureLogger ?? Plugin.Get().Logger; } set { m_featureLogger = value; } } [Terminal.Callback] public void AddUniqueCommandEvents(Terminal.Data data) { Enumerator enumerator = data.TerminalUniqueCommands.GetEnumerator(); while (enumerator.MoveNext()) { CustomTerminalCommand current = enumerator.Current; RegionID regionID = data.Region_TerminalCommand(current); CustomTerminalCommand val = current; data.ProcessEvents(regionID, val.CommandEvents ?? (val.CommandEvents = new List(1))); data.AddPath(new ReTFO.Archipelago.ModdedInstanceData.Model.Path { StartingRegion = data.Region_Terminal, EndingRegion = regionID }); } } } public static class UseTerminalHandler_Tags { } [EnableFeatureByDefault] [AutomatedFeature] public class UseTerminalHandler : ArchipelagoFeature { [ArchivePatch(/*Could not decode attribute arguments.*/)] public static class LG_ComputerTerminal__OnInteract__Patch { public static void Postfix(LG_ComputerTerminal __instance) { if (__instance.IsPasswordProtected) { return; } IdentifyingLogHandler.IdentifyTerminalResult identifyTerminalResult = Terminal.Data.FromTerminal(__instance); Terminal.Data data = identifyTerminalResult.Data; if (data == null) { if (!identifyTerminalResult.IsReactorTerminal) { FeatureLogger.Error("Entered unknown terminal!"); } } else { StateTracker.Get().NotifyFoundRegion(data.TerminalName, __instance.m_syncedInteractionSource); } } } private static IArchiveLogger? m_featureLogger; public override string Name => "Terminal Region Handler"; public override string Description => "Identifies when a terminal region is accessed during play and connects terminal regions to the graph"; public override FeatureGroup Group => ArchipelagoFeatureGroups.get_TerminalHandlers(); public new static IArchiveLogger FeatureLogger { get { return m_featureLogger ?? Plugin.Get().Logger; } set { m_featureLogger = value; } } [Terminal.Callback] public void AddTerminalRegions(Terminal.Data data) { ReTFO.Archipelago.ModdedInstanceData.Model.Path path = new ReTFO.Archipelago.ModdedInstanceData.Model.Path(); path.StartingRegion = data.Region_Zone; path.EndingRegion = data.Region_Terminal; ReTFO.Archipelago.ModdedInstanceData.Model.Path path2 = path; if (data.TerminalStartingStateData.PasswordProtected && data.TerminalStartingStateData.TerminalZoneSelectionDatas.Count > 0) { path = new ReTFO.Archipelago.ModdedInstanceData.Model.Path(path2); path.Reqs = new ReTFO.Archipelago.ModdedInstanceData.Model.Path.MultiPathReq(ReTFO.Archipelago.ModdedInstanceData.Model.Path.eType.Category, TerminalPasswordHandler_Tags.get_Item_TerminalPasswords_ByTerminal(data), (uint)data.TerminalStartingStateData.PasswordPartCount); path2 = path; } data.AddPath(path2); } } } namespace ReTFO.Archipelago.Features.Pickups { public static class BigPickupHandler_Tags { [SpecialName] public sealed class $2833969430CAB23CD70890D67B9ADDD5 { [SpecialName] public static class $5667123F7013DAD37BB214B248F3E5D2 { } [ExtensionMarker("$5667123F7013DAD37BB214B248F3E5D2")] public ItemID Item_BigPickup_Cell { [ExtensionMarker("$5667123F7013DAD37BB214B248F3E5D2")] get { throw new NotSupportedException(); } } [ExtensionMarker("$5667123F7013DAD37BB214B248F3E5D2")] public ItemID Item_BigPickup_MWP { [ExtensionMarker("$5667123F7013DAD37BB214B248F3E5D2")] get { throw new NotSupportedException(); } } [ExtensionMarker("$5667123F7013DAD37BB214B248F3E5D2")] public ItemID Item_BigPickup_Instance(uint itemDatablockId) { throw new NotSupportedException(); } [ExtensionMarker("$5667123F7013DAD37BB214B248F3E5D2")] public ItemID Item_BigPickup_Instance(ItemDataBlock item) { throw new NotSupportedException(); } } public static ItemID Item_BigPickup_Instance(this Expedition.Data data, uint itemDatablockId) { return data.Item_BigPickup_Instance(GameDataBlockBase.GetBlock(itemDatablockId)); } public static ItemID Item_BigPickup_Instance(this Expedition.Data data, ItemDataBlock item) { return ItemID.From(data, $"{data.ExpeditionName} Item #{((GameDataBlockBase)(object)item).persistentID} ({item.publicName})", (Expedition.Data gameData) => new TagDefinition("A particualr big pickup item", PickupHelper_Tags.get_Item_BigPickups(gameData)), new BigPickupHandler.BigPickupItem(data.Region_Expedition, item)); } public static ItemID get_Item_BigPickup_Cell(Expedition.Data data) { return data.Item_BigPickup_Instance(BigPickupHandler.CellItemID); } public static ItemID get_Item_BigPickup_MWP(Expedition.Data data) { return data.Item_BigPickup_Instance(BigPickupHandler.MatterWaveProjectorID); } } [EnableFeatureByDefault] [AutomatedFeature] public class BigPickupHandler : ArchipelagoFeature { public class BigPickupItem : TerminalItem { public RegionID ExpeditionRegion { get; private init; } public ItemDataBlock ItemDataBlock { get; private init; } public override RegionID TargetRegion => ExpeditionRegion; public BigPickupItem(RegionID expedition, ItemDataBlock item) : base(MakeRandData(item)) { ExpeditionRegion = expedition; ItemDataBlock = item; } public static ItemData MakeRandData(ItemDataBlock? item) { return new ItemData { IsProgression = true, IsRandomLike = ((((GameDataBlockBase)(object)item)?.persistentID ?? 0) == CellItemID) }; } protected virtual AsyncItemSpawnWrapper TrySpawnAsync() { //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_0041: 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_0069: Unknown result type (might be due to invalid IL or missing references) //IL_006e: 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_0088: 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_0092: Unknown result type (might be due to invalid IL or missing references) //IL_0094: Unknown result type (might be due to invalid IL or missing references) //IL_0095: Unknown result type (might be due to invalid IL or missing references) //IL_00a8: Unknown result type (might be due to invalid IL or missing references) //IL_00ad: Unknown result type (might be due to invalid IL or missing references) AsyncItemSpawnWrapper asyncItemSpawnWrapper = new AsyncItemSpawnWrapper(); AIG_CourseNode originNode = AIG_CourseNode.s_allNodes[0]; pCourseNode originCourseNode = default(pCourseNode); ((pCourseNode)(ref originCourseNode)).Set(originNode); pItemData val = new pItemData { custom = default(pItemData_Custom), itemID_gearCRC = ((GameDataBlockBase)(object)ItemDataBlock).persistentID, originCourseNode = originCourseNode, originLayer = originNode.LayerType, replicatorRef = default(pReplicator), slot = ItemDataBlock.inventorySlot }; ItemReplicationManager.SpawnItem(val, delItemCallback.op_Implicit((Action)asyncItemSpawnWrapper.OnSpawn), (ItemMode)2, Vector3.zero, Quaternion.identity, originNode, (PlayerAgent)null); asyncItemSpawnWrapper.AddSpawnCallback(delegate(ISyncedItem item) { CarryItemPickup_Core obj = ((Il2CppObjectBase)item).TryCast(); if (obj != null) { ((C_SpecialRenderableObject)obj.ItemCuller).OnFactoryCullingSetupDone(originNode.m_cullNode); } }); return asyncItemSpawnWrapper; } public override void OnItemObtained(StateTracker stateTracker, LocationID sourceLocationId, PlayerAgent? player, ItemID itemId) { if (CheckExpedition(stateTracker)) { if ((Object)(object)player != (Object)null) { AsyncItemSpawnWrapper asyncItemSpawnWrapper = TrySpawnAsync(); asyncItemSpawnWrapper.AddSpawnCallback(AttemptPickup); } else { stateTracker.AddItemToTerminal(itemId); } } void AttemptPickup(ISyncedItem item) { //IL_0019: 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_0022: 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_002b: 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) ((Il2CppObjectBase)item).Cast().m_sync.AttemptPickupInteraction((ePickupItemInteractionType)0, player.Owner, default(pItemData_Custom), default(Vector3), default(Quaternion), (AIG_CourseNode)null, false, false); } } public override IEnumerable OnRetrieveFromTerminalSystem(StateTracker stateTracker, LG_ComputerTerminal terminal, ItemID itemId) { AsyncItemSpawnWrapper wrapper = TrySpawnAsync(); DefaultInterpolatedStringHandler defaultInterpolatedStringHandler = new DefaultInterpolatedStringHandler(15, 2); defaultInterpolatedStringHandler.AppendLiteral("Big Pickup #"); defaultInterpolatedStringHandler.AppendFormatted(((GameDataBlockBase)(object)ItemDataBlock)?.persistentID ?? 0); defaultInterpolatedStringHandler.AppendLiteral(" \""); ItemDataBlock itemDataBlock = ItemDataBlock; defaultInterpolatedStringHandler.AppendFormatted(((itemDataBlock != null) ? itemDataBlock.publicName : null) ?? "null"); defaultInterpolatedStringHandler.AppendLiteral("\""); string itemName = defaultInterpolatedStringHandler.ToStringAndClear(); AIG_CourseNode node = terminal.SpawnNode; PlayerAgent player = terminal.m_syncedInteractionSource; (Vector3, Quaternion) trans = CalcBigObjectPointNearTerminal(terminal); yield return delegate { terminal.AddLine((TerminalLineType)2, "Retrieving " + itemName, 2f); }; yield return delegate { //IL_0092: Unknown result type (might be due to invalid IL or missing references) //IL_0098: 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) ISyncedItem? item = wrapper.Item; CarryItemPickup_Core val = ((item != null) ? ((Il2CppObjectBase)item).TryCast() : null); if ((Object)(object)val == (Object)null) { wrapper.QueueDespawn(); FeatureLogger.Error("Failed to spawn " + itemName + "!"); stateTracker.AddItemToTerminal(itemId); terminal.AddLine("<#F00>Failed to retrieve " + itemName + "! It has been re-added to terminal system.", true); } else { val.m_sync.AttemptPickupInteraction((ePickupItemInteractionType)1, player.Owner, default(pItemData_Custom), trans.Item1, trans.Item2, node, true, true); val.m_navMarkerPlacer.SetMarkerVisible(true); val.m_terminalItem.PlayPing(); terminal.AddLine(itemName + " has been placed somewhere nearby", true); } }; } } private static IArchiveLogger? m_featureLogger; public override string Name => "Big Pickups Handler"; public override string Description => "Provides utilites used by other features to manage big pickups"; public override FeatureGroup Group => ArchipelagoFeatureGroups.get_PickupHandlers(); public new static IArchiveLogger FeatureLogger { get { return m_featureLogger ?? Plugin.Get().Logger; } set { m_featureLogger = value; } } public static uint CellItemID => 131u; public static uint MatterWaveProjectorID => 166u; public static (Vector3, Quaternion) CalcBigObjectPointNearTerminal(LG_ComputerTerminal terminal, int? randSeed = null) { //IL_0044: 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_004e: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0066: 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_00a3: Unknown result type (might be due to invalid IL or missing references) //IL_00a8: Unknown result type (might be due to invalid IL or missing references) //IL_00ad: Unknown result type (might be due to invalid IL or missing references) //IL_00b2: Unknown result type (might be due to invalid IL or missing references) //IL_00b9: 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_00c0: Unknown result type (might be due to invalid IL or missing references) //IL_00c2: Unknown result type (might be due to invalid IL or missing references) //IL_00c7: 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_00ce: Unknown result type (might be due to invalid IL or missing references) //IL_00e5: Unknown result type (might be due to invalid IL or missing references) //IL_00ea: Unknown result type (might be due to invalid IL or missing references) //IL_010a: Unknown result type (might be due to invalid IL or missing references) //IL_010b: 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_00f8: 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) Random random = ((!randSeed.HasValue) ? new Random(default(Guid).GetHashCode()) : new Random(randSeed.Value)); Quaternion item = Quaternion.AngleAxis(random.NextSingle() * 2f * (float)Math.PI, Vector3.up); Vector3 val = terminal.m_CameraAlign.TransformDirection(Vector3.down); RaycastHit val2 = default(RaycastHit); Vector3 item2; if (Physics.Raycast(new Ray(terminal.m_CameraAlign.position, val), ref val2, 5f)) { float num = random.NextSingle() * 0.625f; float num2 = random.NextSingle() * 2f * (float)Math.PI; Vector3 val3 = Quaternion.AngleAxis(num2, Vector3.up) * Vector3.forward * num; item2 = val2.m_Point + val3; } else if ((Object)(object)terminal.m_syncedInteractionSource != (Object)null) { item2 = ((Agent)terminal.m_syncedInteractionSource).Position; } else { Interact_ComputerTerminal componentInChildren = ((Component)terminal).GetComponentInChildren(); item2 = ((componentInChildren != null) ? ((Component)componentInChildren).transform.position : terminal.m_position); } return (item2, item); } } public static class BigPickupZoneDistributionsHandler_Tags { [SpecialName] public sealed class $2B8804A94F2EF68DF77A343A46EE5A78 { [SpecialName] public static class $F943E16B16B76A20C49A59C8DF7C8955 { } [ExtensionMarker("$F943E16B16B76A20C49A59C8DF7C8955")] public LocationID Location_BigPickupZoneDistributions { [ExtensionMarker("$F943E16B16B76A20C49A59C8DF7C8955")] get { throw new NotSupportedException(); } } } [SpecialName] public sealed class $07060F1A014DE32BC9DAE9AB0EFE08B9 { [SpecialName] public static class $A55646E979CA6A3D946ACF0E8F38FB8D { } [ExtensionMarker("$A55646E979CA6A3D946ACF0E8F38FB8D")] public LocationID Location_BigPickupZoneDistribution_Instance(int count) { throw new NotSupportedException(); } } public static LocationID get_Location_BigPickupZoneDistributions(Game.Data gameData) { return LocationID.From(gameData, "Big Pickup Zone Distribution Locations", (Game.Data data) => new TagDefinition("Locations created by misc big pickup items spawned inside a specific zone", PickupHelper_Tags.get_Location_BigPickups(data))); } public static LocationID Location_BigPickupZoneDistribution_Instance(this Zone.Data data, int count) { return LocationID.From(data, $"{data.ZoneName} Big Pickup #{count}", (Zone.Data gameData) => new TagDefinition("A big pickup location spawned randomly in a zone", get_Location_BigPickupZoneDistributions(gameData))); } } [EnableFeatureByDefault] [AutomatedFeature] public class BigPickupZoneDistributionsHandler : ArchipelagoFeature { [ArchivePatch(/*Could not decode attribute arguments.*/)] public static class LG_PopulateFunctionMarkersInZoneJob__BuildPickupItems__Patch { public static void Prefix(LG_PopulateFunctionMarkersInZoneJob __instance) { //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Invalid comparison between Unknown and I4 //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Invalid comparison between Unknown and I4 Queue itemQueue = __instance.m_distributionData.PickupItems.m_itemQueue; if (itemQueue._head != 0 || itemQueue.Count == 0) { return; } Zone.Data fromZone = Zone.Data.GetFromZone(__instance.m_zone); int num = 0; foreach (LG_DistributePickUpItem item in __instance.m_distributionData.PickupItems.m_itemQueue.Iter()) { if ((int)item.m_type == 3 && (int)((LG_DistributeItem)item).m_function == 12 && item.m_bigPickupData != null) { LocationID locationId = fromZone.Location_BigPickupZoneDistribution_Instance(++num); PickupHelper.AssociateDistributionWithLocation(item, locationId); } } } } private static IArchiveLogger? m_featureLogger; public override string Name => "Big Pickups Zone Distributions"; public override string Description => "Handles items spawned via Big Pickup Zone Distributions.\nThis is the system which spawns most big pickups. The other two major big pickup spawning systems are Warden Objectives (which can spawn big pickups based on the objective type) and Cells spawned as part of Zone Progression Puzzles"; public override FeatureGroup Group => ArchipelagoFeatureGroups.get_PickupHandlers(); public new static IArchiveLogger FeatureLogger { get { return m_featureLogger ?? Plugin.Get().Logger; } set { m_featureLogger = value; } } [Zone.Callback] public void AddBigPickups(Zone.Data data) { int num = 0; ExpeditionZoneData? zone = data.Zone; int num2; if (zone == null) { DimensionData? dimensionData = data.DimensionData; num2 = (int)((dimensionData != null) ? dimensionData.StaticBigPickupDistributionInZone : 0); } else { num2 = (int)zone.BigPickupDistributionInZone; } uint num3 = (uint)num2; BigPickupDistributionDataBlock block = GameDataBlockBase.GetBlock(num3); if (block != null) { float num4 = 0f; int num5 = 0; while (num4 + block.SpawnData[num5].Weight <= (float)block.SpawnsPerZone) { num++; data.Locations.CreateValue(data.Location_BigPickupZoneDistribution_Instance(num), data.Region_Zone, default(LocationData), data.Item_BigPickup_Instance(block.SpawnData[num5].ItemID)); num4 += block.SpawnData[num5].Weight; num5 = (num5 + 1) % block.SpawnData.Count; } } ExpeditionZoneData? zone2 = data.Zone; List val = ((zone2 != null) ? zone2.SpecificPickupSpawningDatas : null); if (val == null) { return; } Enumerator enumerator = val.GetEnumerator(); while (enumerator.MoveNext()) { SpecificPickupSpawnData current = enumerator.Current; if (current.WorldEventObjectFilter != null && current.PickupToSpawn != 0) { num++; data.Locations.CreateValue(data.Location_BigPickupZoneDistribution_Instance(num), data.Region_Zone, default(LocationData), data.Item_BigPickup_Instance(current.PickupToSpawn)); } } } } public static class BulkheadKeyHandler_Tags { [SpecialName] public sealed class $2B8804A94F2EF68DF77A343A46EE5A78 { [SpecialName] public static class $F943E16B16B76A20C49A59C8DF7C8955 { } [ExtensionMarker("$F943E16B16B76A20C49A59C8DF7C8955")] public LocationID Location_BulkheadKeys { [ExtensionMarker("$F943E16B16B76A20C49A59C8DF7C8955")] get { throw new NotSupportedException(); } } [ExtensionMarker("$F943E16B16B76A20C49A59C8DF7C8955")] public ItemID Item_BulkheadKeys { [ExtensionMarker("$F943E16B16B76A20C49A59C8DF7C8955")] get { throw new NotSupportedException(); } } } [SpecialName] public sealed class $2833969430CAB23CD70890D67B9ADDD5 { [SpecialName] public static class $5667123F7013DAD37BB214B248F3E5D2 { } [ExtensionMarker("$5667123F7013DAD37BB214B248F3E5D2")] public ItemID Item_BulkheadKey_Instance { [ExtensionMarker("$5667123F7013DAD37BB214B248F3E5D2")] get { throw new NotSupportedException(); } } } [SpecialName] public sealed class $9DAFA10623A49E693D4D9BEA615A7202 { [SpecialName] public static class $70E40AF8BA672009D4689E0A70FAB84A { } [ExtensionMarker("$70E40AF8BA672009D4689E0A70FAB84A")] public LocationID Location_BulkheadKey_ByLayer { [ExtensionMarker("$70E40AF8BA672009D4689E0A70FAB84A")] get { throw new NotSupportedException(); } } [ExtensionMarker("$70E40AF8BA672009D4689E0A70FAB84A")] public LocationID Location_BulkheadKey_Instance(int count) { throw new NotSupportedException(); } } public static LocationID get_Location_BulkheadKeys(Game.Data gameData) { return LocationID.From(gameData, "Bulkhead Key Locations", (Game.Data data) => new TagDefinition("Locations checked by picking up bulkhead keys", PickupHelper_Tags.get_Location_SmallPickups(data))); } public static ItemID get_Item_BulkheadKeys(Game.Data gameData) { return ItemID.From(gameData, "Bulkhead Key Items", (Game.Data data) => new TagDefinition("The bulkhead key item itself", PickupHelper_Tags.get_Item_SmallPickups(data))); } public static ItemID get_Item_BulkheadKey_Instance(Expedition.Data data) { return ItemID.From(data, data.ExpeditionName + " Bulkhead Key", (Expedition.Data gameData) => new TagDefinition("The bulkhead key for a particular expedition", get_Item_BulkheadKeys(gameData)), new BulkheadKeyHandler.BulkheadKeyItem(data.Region_Expedition)); } public static LocationID get_Location_BulkheadKey_ByLayer(Layer.Data data) { return LocationID.From(data, data.LayerName + " Bulkhead Key Locations", (Layer.Data gameData) => new TagDefinition("Bulkhead key locations in a particular layer of a particular expedition", get_Location_BulkheadKeys(gameData))); } public static LocationID Location_BulkheadKey_Instance(this Layer.Data data, int count) { return LocationID.From(data, $"{data.LayerName} Bulkhead Key Location #{count}", (Layer.Data data2) => new TagDefinition("A particular bulkhead key spawn location", get_Location_BulkheadKey_ByLayer(data2))); } } [EnableFeatureByDefault] [AutomatedFeature] public class BulkheadKeyHandler : ArchipelagoFeature { public class BulkheadKeyItem : TerminalItem { public RegionID ExpeditionRegion { get; private init; } public override RegionID TargetRegion => ExpeditionRegion; public BulkheadKeyItem(RegionID expedition) : base(new ItemData { IsProgression = true, IsRandomLike = true }) { ExpeditionRegion = expedition; } private AsyncItemSpawnWrapper SpawnItemAsync() { //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0034: 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) AsyncItemSpawnWrapper asyncItemSpawnWrapper = new AsyncItemSpawnWrapper(); if (SNet.IsMaster) { ItemReplicationManager.SpawnItem(new pItemData { itemID_gearCRC = 146u }, delItemCallback.op_Implicit((Action)asyncItemSpawnWrapper.OnSpawn), (ItemMode)2, Vector3.zero, Quaternion.identity, (AIG_CourseNode)null, (PlayerAgent)null); } return asyncItemSpawnWrapper; } public override void OnItemObtained(StateTracker stateTracker, LocationID sourceLocationId, PlayerAgent? player = null, ItemID itemId = default(ItemID)) { if (!CheckExpedition(stateTracker)) { return; } if (base.RandData.IsRandomLike && (Object)(object)player != (Object)null) { AsyncItemSpawnWrapper asyncItemSpawnWrapper = SpawnItemAsync(); asyncItemSpawnWrapper.AddSpawnCallback(delegate(ISyncedItem item) { //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0021: 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_002a: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) KeyItemPickup_Core val = ((Il2CppObjectBase)item).Cast(); val.m_sync.AttemptPickupInteraction((ePickupItemInteractionType)0, player.Owner, default(pItemData_Custom), default(Vector3), default(Quaternion), (AIG_CourseNode)null, false, false); }); } else { stateTracker.AddItemToTerminal(itemId); } } public override IEnumerable OnRetrieveFromTerminalSystem(StateTracker stateTracker, LG_ComputerTerminal terminal, ItemID itemId = default(ItemID)) { AsyncItemSpawnWrapper wrapper = SpawnItemAsync(); SNet_Player player = terminal.m_syncedInteractionSource.Owner; yield return delegate { terminal.AddLine((TerminalLineType)2, "Retrieving bulkhead key", 2f); }; yield return delegate { //IL_0074: 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_007d: Unknown result type (might be due to invalid IL or missing references) //IL_0083: Unknown result type (might be due to invalid IL or missing references) //IL_0086: 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) ISyncedItem? item = wrapper.Item; KeyItemPickup_Core val = ((item != null) ? ((Il2CppObjectBase)item).TryCast() : null); if ((Object)(object)val == (Object)null) { if (SNet.IsMaster) { stateTracker.AddItemToTerminal(itemId); wrapper.QueueDespawn(); FeatureLogger.Error("Failed to spawn key item while spawning bulkhead keycard!"); terminal.AddLine("<#F00>Failed to retrieve key! It has been re-added to terminal system.", true); } } else { val.m_sync.AttemptPickupInteraction((ePickupItemInteractionType)0, player, default(pItemData_Custom), default(Vector3), default(Quaternion), (AIG_CourseNode)null, false, false); terminal.AddLine("Key \"" + ((Item)val).PublicName + "\" has been given to " + player.NickName, true); } }; } } [ArchivePatch(/*Could not decode attribute arguments.*/)] public static class LG_Distribute_ProgressionPuzzles__CreateKeyItemDistribution__Patch { public static void Postfix(LG_Distribute_ProgressionPuzzles __instance, GateKeyItem keyItem, ZonePlacementData placementData) { if (__instance.m_layer.m_buildData.m_layerGameData == null) { return; } Layer.Data fromLayer = Layer.Data.GetFromLayer(__instance.m_layer); for (int i = 0; i < __instance.m_layer.m_buildData.m_layerGameData.BulkheadKeyPlacements.Count; i++) { if (__instance.m_layer.m_buildData.m_layerGameData.BulkheadKeyPlacements[i].Any((ZonePlacementData p) => ((Il2CppObjectBase)p).Pointer == ((Il2CppObjectBase)placementData).Pointer)) { LocationID locationId = fromLayer.Location_BulkheadKey_Instance(i + 1); PickupHelper.AssociateItem((ItemInLevel)(object)keyItem.keyPickupCore, locationId); return; } } if (keyItem.PublicName.Contains("bulkhead", StringComparison.OrdinalIgnoreCase)) { FeatureLogger.Error("Failed to identify placement for bulkhead key!"); } } } private static IArchiveLogger? m_featureLogger; private const uint BULKHEAD_KEY_ID = 146u; public override string Name => "Bulkhead Key Handler"; public override string Description => "Handles processing, despawning, and spawning bulkhead keys as part of randomization"; public override FeatureGroup Group => ArchipelagoFeatureGroups.get_PickupHandlers(); public new static IArchiveLogger FeatureLogger { get { return m_featureLogger ?? (m_featureLogger = Plugin.Get().Logger); } set { m_featureLogger = value; } } [Layer.Callback] public void AddBulkheadKeys(Layer.Data data) { if (data.LayerDatas == null) { return; } ItemID item = BulkheadKeyHandler_Tags.get_Item_BulkheadKey_Instance(data); for (int i = 0; i < data.LayerDatas.BulkheadKeyPlacements.Count; i++) { if (data.LayerDatas.BulkheadKeyPlacements[i].Any()) { data.Locations.CreateValue(data.Location_BulkheadKey_Instance(i + 1), (from regionInfo in data.PlacementsToZoneRegions(data.LayerDatas.BulkheadKeyPlacements[i]) select regionInfo.Region).ToArray(), default(LocationData), item); } } } [Game.Callback] public void AddOptions(Game.Data data) { ItemID itemID = BulkheadKeyHandler_Tags.get_Item_BulkheadKeys(data); data.AddOption(new OptionItemTagOption("Bulkhead Key Randomization", "Enables randomization of bulkhead key cards.\nWhitelist: Enables for all unless blacklisted elsewhere.\nBlacklist: Disables for all.\nNone: Defer to other relevant setting(s). If no other relevant setting is set, defaults to blacklisted.", "Pickups", Option.MakeSortKey(data, itemID), 1L, default(OptionID), itemID)); } } public static class ColoredKeyHandler_Tags { [SpecialName] public sealed class $2B8804A94F2EF68DF77A343A46EE5A78 { [SpecialName] public static class $55FD246F9BFF39DD56FCB5C25D4DF852 { } [ExtensionMarker("$55FD246F9BFF39DD56FCB5C25D4DF852")] public LocationID Location_ColoredKeys { [ExtensionMarker("$55FD246F9BFF39DD56FCB5C25D4DF852")] get { throw new NotSupportedException(); } } [ExtensionMarker("$55FD246F9BFF39DD56FCB5C25D4DF852")] public ItemID Item_ColoredKeys { [ExtensionMarker("$55FD246F9BFF39DD56FCB5C25D4DF852")] get { throw new NotSupportedException(); } } } [SpecialName] public sealed class $07060F1A014DE32BC9DAE9AB0EFE08B9 { [SpecialName] public static class $A55646E979CA6A3D946ACF0E8F38FB8D { } [ExtensionMarker("$A55646E979CA6A3D946ACF0E8F38FB8D")] public LocationID Location_ColoredKey_Instance { [ExtensionMarker("$A55646E979CA6A3D946ACF0E8F38FB8D")] get { throw new NotSupportedException(); } } [ExtensionMarker("$A55646E979CA6A3D946ACF0E8F38FB8D")] public ItemID Item_ColoredKey_Instance { [ExtensionMarker("$A55646E979CA6A3D946ACF0E8F38FB8D")] get { throw new NotSupportedException(); } } } public static LocationID get_Location_ColoredKeys(Game.Data data) { return LocationID.From(data, "Colored Key Locations", (Game.Data gameData) => new TagDefinition("Locations checked by picking up colored keys", PickupHelper_Tags.get_Location_SmallPickups(gameData))); } public static ItemID get_Item_ColoredKeys(Game.Data data) { return ItemID.From(data, "Colored Key Items", (Game.Data gameData) => new TagDefinition("Parent of all colored key items", PickupHelper_Tags.get_Item_SmallPickups(gameData))); } public static LocationID get_Location_ColoredKey_Instance(Zone.Data data) { return LocationID.From(data, data.ZoneName + " Colored Key Location", (Zone.Data data2) => new TagDefinition("A particular zone's colored key's spawn location", get_Location_ColoredKeys(data2))); } public static ItemID get_Item_ColoredKey_Instance(Zone.Data data) { return ItemID.From(data, data.ZoneName + " Colored Key", (Zone.Data data2) => new TagDefinition("A particular zone's colored key", get_Item_ColoredKeys(data2)), new ColoredKeyHandler.ColoredKeyItem(data.Region_Zone)); } } [EnableFeatureByDefault] [AutomatedFeature] public class ColoredKeyHandler : ArchipelagoFeature { public class Settings { [Localized] public enum eRetrievalType { ToTerminal, ToHost, ToRandom, ToDoor } [FSDisplayName("Retrieval Type")] [FSDescription("Determines what happens when receiving a Colored Key from the Multiworld.\n\nTo Terminal\nPlace the key in the relevant terminal system, from which it can be retrieved at any time.\n\nTo Host\nGive the key directly to the host, either immediately when receiving it or when the level starts.\n\nTo Random\nGive the key directly to a randomly-chosen non-bot player.\n\nTo Door\nImmediately unlock the associated door.")] public eRetrievalType RetrievalType { get; set; } } public class ColoredKeyItem : ExpeditionItem { public RegionID ZoneRegion { get; private init; } public override RegionID TargetRegion => ZoneRegion; public ColoredKeyItem(RegionID zone) : base(new ItemData { IsProgression = true }) { ZoneRegion = zone; } public AsyncItemSpawnWrapper TrySpawnKey(Game.Data data) { //IL_0061: 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) //IL_008d: Unknown result type (might be due to invalid IL or missing references) //IL_0092: Unknown result type (might be due to invalid IL or missing references) AsyncItemSpawnWrapper asyncItemSpawnWrapper = new AsyncItemSpawnWrapper(); Zone.Data data2 = new Zone.Data(data, ZoneRegion); LG_Zone lG_Zone = data2.GetLG_Zone(); if ((Object)(object)lG_Zone == (Object)null) { FeatureLogger.Error("Failed to retrieve zone while spawning colored keycard!"); } else { LG_Gate sourceGate = lG_Zone.m_sourceGate; LG_SecurityDoor val = ((sourceGate != null) ? ((Il2CppObjectBase)sourceGate.SpawnedDoor).TryCast() : null); if (SNet.IsMaster && (Object)(object)val != (Object)null) { ItemReplicationManager.SpawnItem(new pItemData { itemID_gearCRC = val.m_keyItem.DataBlockID }, delItemCallback.op_Implicit((Action)asyncItemSpawnWrapper.OnSpawn), (ItemMode)2, Vector3.zero, Quaternion.identity, (AIG_CourseNode)null, (PlayerAgent)null); } else if ((Object)(object)val == (Object)null) { FeatureLogger.Error("Failed to identify sec door while spawning colored keycard!"); } } return asyncItemSpawnWrapper; } public override void OnEnteredExpedition(StateTracker stateTracker, LocationID sourceLocationId, PlayerAgent? player, ItemID itemId) { switch (Config.RetrievalType) { case Settings.eRetrievalType.ToTerminal: StateTracker.Get().AddItemToTerminal(itemId); break; case Settings.eRetrievalType.ToHost: TrySpawnKey(stateTracker.GameData).AddSpawnCallback(delegate(ISyncedItem item) { //IL_001e: 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_0027: Unknown result type (might be due to invalid IL or missing references) //IL_002d: 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: Unknown result type (might be due to invalid IL or missing references) KeyItemPickup_Core val2 = ((Il2CppObjectBase)item).TryCast(); if ((Object)(object)val2 != (Object)null) { val2.m_sync.AttemptPickupInteraction((ePickupItemInteractionType)0, SNet.Master, default(pItemData_Custom), default(Vector3), default(Quaternion), (AIG_CourseNode)null, false, false); } else if (SNet.IsMaster) { FeatureLogger.Error("Failed to give keycard directly to host. Adding to terminal!"); StateTracker.Get().AddItemToTerminal(itemId); } }); break; case Settings.eRetrievalType.ToRandom: TrySpawnKey(stateTracker.GameData).AddSpawnCallback(delegate(ISyncedItem item) { //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0065: 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_006e: 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_0077: Unknown result type (might be due to invalid IL or missing references) List list = SNet.LobbyPlayers.Where((SNet_Player p) => !p.IsBot).ToList(); KeyItemPickup_Core val2 = ((Il2CppObjectBase)item).TryCast(); if ((Object)(object)val2 != (Object)null) { val2.m_sync.AttemptPickupInteraction((ePickupItemInteractionType)0, list[Random.Shared.Next(0, list.Count)], default(pItemData_Custom), default(Vector3), default(Quaternion), (AIG_CourseNode)null, false, false); } else if (SNet.IsMaster) { FeatureLogger.Error("Failed to give keycard directly to random human. Adding to terminal!"); StateTracker.Get().AddItemToTerminal(itemId); } }); break; case Settings.eRetrievalType.ToDoor: { LG_Zone lG_Zone = new Zone.Data(stateTracker.GameData, ZoneRegion).GetLG_Zone(); object obj; if (lG_Zone == null) { obj = null; } else { LG_Gate sourceGate = lG_Zone.m_sourceGate; obj = ((sourceGate != null) ? ((Il2CppObjectBase)sourceGate.SpawnedDoor).TryCast() : null); } LG_SecurityDoor val = (LG_SecurityDoor)obj; if ((Object)(object)val == (Object)null) { FeatureLogger.Error("Failed to retrieve zone door while unlocking colored keycard door!"); } else if (SNet.IsMaster) { val.AttemptOpenCloseInteraction(true); } break; } } } public override IEnumerable OnRetrieveFromTerminalSystem(StateTracker stateTracker, LG_ComputerTerminal terminal, ItemID itemId) { AsyncItemSpawnWrapper wrapper = TrySpawnKey(stateTracker.GameData); SNet_Player player = terminal.m_syncedInteractionSource.Owner; yield return delegate { terminal.AddLine((TerminalLineType)2, "Retrieving colored key", 2f); }; yield return delegate { //IL_0074: 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_007d: Unknown result type (might be due to invalid IL or missing references) //IL_0083: Unknown result type (might be due to invalid IL or missing references) //IL_0086: 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) ISyncedItem? item = wrapper.Item; KeyItemPickup_Core val = ((item != null) ? ((Il2CppObjectBase)item).TryCast() : null); if ((Object)(object)val == (Object)null) { if (SNet.IsMaster) { stateTracker.AddItemToTerminal(itemId); FeatureLogger.Error("Failed to spawn key item while spawning colored keycard!"); terminal.AddLine("<#F00>Failed to retrieve key! It has been re-added to terminal system.", true); wrapper.QueueDespawn(); } } else { val.m_sync.AttemptPickupInteraction((ePickupItemInteractionType)0, player, default(pItemData_Custom), default(Vector3), default(Quaternion), (AIG_CourseNode)null, false, false); terminal.AddLine("Key \"" + ((Item)val).PublicName + "\" has been given to " + player.NickName, true); } }; } } [ArchivePatch(/*Could not decode attribute arguments.*/)] public static class LG_SecurityDoor__SetupKeyItemLock__Patch { public static void Postfix(LG_SecurityDoor __instance, GateKeyItem keyItem) { Zone.Data fromZone = Zone.Data.GetFromZone(((LG_ZoneExpander)__instance.Gate).m_linksTo.m_zone); PickupHelper.AssociateItem((ItemInLevel)(object)__instance.m_keyItem.keyPickupCore, ColoredKeyHandler_Tags.get_Location_ColoredKey_Instance(fromZone)); } } private static IArchiveLogger? m_featureLogger; public override string Name => "Colored Key Handler"; public override string Description => "Handles processing, despawning, and spawning colored keys as part of randomization"; public override FeatureGroup Group => ArchipelagoFeatureGroups.get_PickupHandlers(); public new static IArchiveLogger FeatureLogger { get { return m_featureLogger ?? (m_featureLogger = Plugin.Get().Logger); } set { m_featureLogger = value; } } [FeatureConfig] public static Settings Config { get; set; } [Game.Callback] public void AddOptions(Game.Data data) { ItemID itemID = ColoredKeyHandler_Tags.get_Item_ColoredKeys(data); data.AddOption(new OptionItemTagOption("Colored Keys Randomization", "Enables randomization of colored key cards.\nWhitelist: Enables for all unless blacklisted elsewhere.\nBlacklist: Disables for all.\nNone: Defer to other relevant setting(s). If no other relevant setting is set, defaults to blacklisted.", "Pickups", Option.MakeSortKey(data, itemID), 1L, default(OptionID), itemID)); } [Zone.Callback] public void AddColoredKeys(Zone.Data data) { //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Invalid comparison between Unknown and I4 if (data.Zone != null && (int)data.Zone.ProgressionPuzzleToEnter.PuzzleType == 1) { RegionList regionList = (from i in data.PlacementsToZoneRegions(data.Zone.ProgressionPuzzleToEnter.ZonePlacementData) select i.Region).Distinct().ToArray(); data.Locations.CreateValue(ColoredKeyHandler_Tags.get_Location_ColoredKey_Instance(data), (from i in data.PlacementsToZoneRegions(data.Zone.ProgressionPuzzleToEnter.ZonePlacementData) select i.Region).ToArray(), default(LocationData), ColoredKeyHandler_Tags.get_Item_ColoredKey_Instance(data)); } } } public static class GenericItemInElevatorHandler_Tags { [SpecialName] public sealed class $2B8804A94F2EF68DF77A343A46EE5A78 { [SpecialName] public static class $F943E16B16B76A20C49A59C8DF7C8955 { } [ExtensionMarker("$F943E16B16B76A20C49A59C8DF7C8955")] public LocationID Location_GenericBigInElevator { [ExtensionMarker("$F943E16B16B76A20C49A59C8DF7C8955")] get { throw new NotSupportedException(); } } } [SpecialName] public sealed class $2833969430CAB23CD70890D67B9ADDD5 { [SpecialName] public static class $5667123F7013DAD37BB214B248F3E5D2 { } [ExtensionMarker("$5667123F7013DAD37BB214B248F3E5D2")] public LocationID Location_GenericBigInElevator_Instance { [ExtensionMarker("$5667123F7013DAD37BB214B248F3E5D2")] get { throw new NotSupportedException(); } } } public static LocationID get_Location_GenericBigInElevator(Game.Data gameData) { return LocationID.From(gameData, "Generic Big in Elevator Locations", (Game.Data data) => new TagDefinition("Location checked by picking up a special type of item spawned in the elevator cage", PickupHelper_Tags.get_Location_BigPickups(data))); } public static LocationID get_Location_GenericBigInElevator_Instance(Expedition.Data data) { return LocationID.From(data, data.ExpeditionName + " Generic Big in Elevator Location", (Expedition.Data gameData) => new TagDefinition("The generic big in elevator location for a particular expedition", get_Location_GenericBigInElevator(gameData))); } } [EnableFeatureByDefault] [AutomatedFeature] public class GenericItemInElevatorHandler : ArchipelagoFeature { [ArchivePatch(/*Could not decode attribute arguments.*/)] public static class LG_Factory__FactoryDone__Patch { public static void Postfix() { Objective.Data data = Layer.get_MainLayer(Expedition.Data.GetFromCurrentExpedition()).GetObjectiveDatas().First(); if (data.Objective.GenericItemFromStart == 0) { return; } LocationID locationId = GenericItemInElevatorHandler_Tags.get_Location_GenericBigInElevator_Instance(data); CarryItemPickup_Core componentInChildren = ((Component)ElevatorCage.Current.m_cargoCage.m_itemsToMoveToCargo[0]).GetComponentInChildren(); if ((Object)(object)componentInChildren == (Object)null) { FeatureLogger.Error("Failed to find generic item in elevator during build!"); return; } if (((GameDataBlockBase)(object)((Item)componentInChildren).ItemDataBlock).persistentID != data.Objective.GenericItemFromStart) { FeatureLogger.Warning("Associated incorrect item type with generic item from start!"); } PickupHelper.AssociateItem((ItemInLevel)(object)componentInChildren, locationId); } } private static IArchiveLogger? m_featureLogger; public override string Name => "Generic Item in Elevator"; public override string Description => "Handles items spawned via the Generic-Item-in-Elevator system.\nThis system allows prisoners to start with one non-objective-related Big Pickup in the elevator, which is often used to perform a required part of the mission. It is most commonly used to provide a Matter Wave Projecter at the start of an expedition."; public override FeatureGroup Group => ArchipelagoFeatureGroups.get_PickupHandlers(); public new static IArchiveLogger FeatureLogger { get { return m_featureLogger ?? Plugin.Get().Logger; } set { m_featureLogger = value; } } [Expedition.Callback] public void AddGenericItemInElevator(Expedition.Data data) { Objective.Data data2 = Layer.get_MainLayer(data).GetObjectiveDatas().First(); if (data2.Objective.GenericItemFromStart != 0) { data.Locations.CreateValue(GenericItemInElevatorHandler_Tags.get_Location_GenericBigInElevator_Instance(data), Zone.get_StartingZone(data).Region_Zone, default(LocationData), data.Item_BigPickup_Instance(data2.Objective.GenericItemFromStart)); } } } public static class PickupHelper_Tags { [SpecialName] public sealed class $2B8804A94F2EF68DF77A343A46EE5A78 { [SpecialName] public static class $F943E16B16B76A20C49A59C8DF7C8955 { } [ExtensionMarker("$F943E16B16B76A20C49A59C8DF7C8955")] public LocationID Location_Pickups { [ExtensionMarker("$F943E16B16B76A20C49A59C8DF7C8955")] get { throw new NotSupportedException(); } } [ExtensionMarker("$F943E16B16B76A20C49A59C8DF7C8955")] public LocationID Location_SmallPickups { [ExtensionMarker("$F943E16B16B76A20C49A59C8DF7C8955")] get { throw new NotSupportedException(); } } [ExtensionMarker("$F943E16B16B76A20C49A59C8DF7C8955")] public LocationID Location_BigPickups { [ExtensionMarker("$F943E16B16B76A20C49A59C8DF7C8955")] get { throw new NotSupportedException(); } } [ExtensionMarker("$F943E16B16B76A20C49A59C8DF7C8955")] public LocationID Location_ResourcePickups { [ExtensionMarker("$F943E16B16B76A20C49A59C8DF7C8955")] get { throw new NotSupportedException(); } } [ExtensionMarker("$F943E16B16B76A20C49A59C8DF7C8955")] public LocationID Location_ConsumablePickups { [ExtensionMarker("$F943E16B16B76A20C49A59C8DF7C8955")] get { throw new NotSupportedException(); } } [ExtensionMarker("$F943E16B16B76A20C49A59C8DF7C8955")] public LocationID Location_ArtifactPickups { [ExtensionMarker("$F943E16B16B76A20C49A59C8DF7C8955")] get { throw new NotSupportedException(); } } [ExtensionMarker("$F943E16B16B76A20C49A59C8DF7C8955")] public ItemID Item_Pickups { [ExtensionMarker("$F943E16B16B76A20C49A59C8DF7C8955")] get { throw new NotSupportedException(); } } [ExtensionMarker("$F943E16B16B76A20C49A59C8DF7C8955")] public ItemID Item_SmallPickups { [ExtensionMarker("$F943E16B16B76A20C49A59C8DF7C8955")] get { throw new NotSupportedException(); } } [ExtensionMarker("$F943E16B16B76A20C49A59C8DF7C8955")] public ItemID Item_BigPickups { [ExtensionMarker("$F943E16B16B76A20C49A59C8DF7C8955")] get { throw new NotSupportedException(); } } [ExtensionMarker("$F943E16B16B76A20C49A59C8DF7C8955")] public ItemID Item_ResourcePickups { [ExtensionMarker("$F943E16B16B76A20C49A59C8DF7C8955")] get { throw new NotSupportedException(); } } [ExtensionMarker("$F943E16B16B76A20C49A59C8DF7C8955")] public ItemID Item_ConsumablePickups { [ExtensionMarker("$F943E16B16B76A20C49A59C8DF7C8955")] get { throw new NotSupportedException(); } } [ExtensionMarker("$F943E16B16B76A20C49A59C8DF7C8955")] public ItemID Item_ArtifactPickups { [ExtensionMarker("$F943E16B16B76A20C49A59C8DF7C8955")] get { throw new NotSupportedException(); } } } public static LocationID get_Location_Pickups(Game.Data gameData) { return LocationID.From(gameData, "Pickup Locations", (Game.Data data) => new TagDefinition("Locations checked when items are picked up (keys, cells, artifacts, etc)", CommonTagsHandler_Tags.get_Location_All(data))); } public static LocationID get_Location_SmallPickups(Game.Data gameData) { return LocationID.From(gameData, "Small Pickup Locations", (Game.Data data) => new TagDefinition("Location checked when small items are picked up (keys, IDs, GLPS, etc)", get_Location_Pickups(data))); } public static LocationID get_Location_BigPickups(Game.Data gameData) { return LocationID.From(gameData, "Big Pickup Locations", (Game.Data data) => new TagDefinition("Location checked when big items are picked up (cells, fog turbines, babies, etc)", get_Location_Pickups(data))); } public static LocationID get_Location_ResourcePickups(Game.Data gameData) { return LocationID.From(gameData, "Resource Pickup Locations", (Game.Data data) => new TagDefinition("Location checked when resources are picked up (ammo, med, tool, disinfect)", get_Location_Pickups(data))); } public static LocationID get_Location_ConsumablePickups(Game.Data gameData) { return LocationID.From(gameData, "Consumable Pickup Locations", (Game.Data data) => new TagDefinition("Location checked when consumables are picked up (glowsticks, flashlights, c-foam grenades, etc)", get_Location_Pickups(data))); } public static LocationID get_Location_ArtifactPickups(Game.Data gameData) { return LocationID.From(gameData, "Artifact Pickup Locations", (Game.Data data) => new TagDefinition("Location checked when artifacts are picked up (muted, bold, aggressive)", get_Location_Pickups(data))); } public static ItemID get_Item_Pickups(Game.Data gameData) { return ItemID.From(gameData, "Pickup Items", (Game.Data data) => new TagDefinition("All items which are picked up (keys, cells, artifacts, etc)", CommonTagsHandler_Tags.get_Item_All(data))); } public static ItemID get_Item_SmallPickups(Game.Data gameData) { return ItemID.From(gameData, "Small Pickup Items", (Game.Data data) => new TagDefinition("All small pickup items which end up in the left-side menu (keys, IDs, GLPS, etc)", get_Item_Pickups(data))); } public static ItemID get_Item_BigPickups(Game.Data gameData) { return ItemID.From(gameData, "Big Pickup Items", (Game.Data data) => new TagDefinition("All big pickup items (cells, fog turbines, babies, etc)", get_Item_Pickups(data))); } public static ItemID get_Item_ResourcePickups(Game.Data gameData) { return ItemID.From(gameData, "Resource Pickup Items", (Game.Data data) => new TagDefinition("All resource pickups (ammo, med, tool, disinfect)", get_Item_Pickups(data))); } public static ItemID get_Item_ConsumablePickups(Game.Data gameData) { return ItemID.From(gameData, "Consumable Pickup Items", (Game.Data data) => new TagDefinition("All consumable pickups (glowsticks, flashlights, c-foam grenades, etc)", get_Item_Pickups(data))); } public static ItemID get_Item_ArtifactPickups(Game.Data gameData) { return ItemID.From(gameData, "Artifact Pickup Items", (Game.Data data) => new TagDefinition("All artifact picksup (muted, bold, aggressive)", get_Item_Pickups(data))); } } [InjectToIl2Cpp] [EnableFeatureByDefault] public class PickupHelper : ArchipelagoFeature { [InjectToIl2Cpp] private class ContainsLocationPickupComp : MonoBehaviour { public LocationID StoredLocation; public ContainsLocationPickupComp(IntPtr ptr) : base(ptr) { } } [InjectToIl2Cpp] private class This_ConsumablesData : ConsumableDistributionDataBlock { public LocationID StoredLocation; public This_ConsumablesData(IntPtr ptr) : base(ptr) { } public This_ConsumablesData(LocationID id, ConsumableDistributionDataBlock? original) : base(ClassInjector.DerivedConstructorPointer()) { ClassInjector.DerivedConstructorBody((Il2CppObjectBase)(object)this); if (original == null) { original = ((IEnumerable)GameDataBlockBase.GetAllBlocks()).First(); } StoredLocation = id; ((ConsumableDistributionDataBlock)this).ChanceToSpawnInResourceContainer = original.ChanceToSpawnInResourceContainer; ((ConsumableDistributionDataBlock)this).SpawnData = original.SpawnData; ((ConsumableDistributionDataBlock)this).SpawnsPerZone = original.SpawnsPerZone; ((GameDataBlockBase)this).Index = ((GameDataBlockBase)(object)original).Index; ((GameDataBlockBase)this).internalEnabled = ((GameDataBlockBase)(object)original).internalEnabled; ((GameDataBlockBase)this).name = ((GameDataBlockBase)(object)original).name; ((GameDataBlockBase)this).persistentID = 0u; } } [ArchivePatch(/*Could not decode attribute arguments.*/)] public static class LG_DistributionJobUtils__TryGetExistingZoneFunctionDistribution__Patch { public static LG_DistributeItem? lastFetchedItem; public static void Postfix(ref LG_DistributeItem foundDist) { lastFetchedItem = foundDist; } } [ArchivePatch(/*Could not decode attribute arguments.*/)] public static class LG_Distribute_PickupItemsPerZone__Build__Patch { public static void Prefix(LG_Distribute_PickupItemsPerZone __instance) { LG_DistributionJobUtils__TryGetExistingZoneFunctionDistribution__Patch.lastFetchedItem = null; } public static void Postfix(LG_Distribute_PickupItemsPerZone __instance) { if (__instance.m_consumableDistributionData == null) { return; } LG_DistributeItem? lastFetchedItem = LG_DistributionJobUtils__TryGetExistingZoneFunctionDistribution__Patch.lastFetchedItem; LG_DistributeResourceContainer val = ((lastFetchedItem != null) ? ((Il2CppObjectBase)lastFetchedItem).TryCast() : null); if (val != null && val.m_packs.Count > 0) { ResourceContainerSpawnData val2 = val.m_packs[val.m_packs.Count - 1]; if (val2.m_consumableData != null && ((Il2CppObjectBase)val2.m_consumableData).Pointer != ((Il2CppObjectBase)__instance.m_consumableDistributionData).Pointer) { FeatureLogger.Warning("Overwriting consumable data during consumable forwarding!"); } val2.m_consumableData = __instance.m_consumableDistributionData; } } } [ArchivePatch(/*Could not decode attribute arguments.*/)] public static class LG_PickupItemBuilder__SetupFunctionGO__Patch { public static void Postfix(LG_PickupItemBuilder __instance, LG_LayerType layer, GameObject GO) { ConsumableDistributionDataBlock consumableData = __instance.m_consumableData; This_ConsumablesData this_ConsumablesData = ((consumableData != null) ? ((Il2CppObjectBase)consumableData).TryCast() : null); if (this_ConsumablesData != null) { ItemInLevel componentInChildren = GO.GetComponentInChildren(); if ((Object)(object)componentInChildren == (Object)null) { throw new NullReferenceException(); } AssociateItem(componentInChildren, this_ConsumablesData.StoredLocation); } } } [ArchivePatch(/*Could not decode attribute arguments.*/)] public static class LG_ResourceContainer_Storage__PlaceSmallGenericPickup__Patch { public static void Postfix(LG_ResourceContainer_Storage __instance, ResourceContainerSpawnData pack, Transform align, int randomSeed) { ConsumableDistributionDataBlock consumableData = pack.m_consumableData; This_ConsumablesData this_ConsumablesData = ((consumableData != null) ? ((Il2CppObjectBase)consumableData).TryCast() : null); if (this_ConsumablesData != null) { ItemInLevel componentInChildren = ((Component)align).GetComponentInChildren(); if ((Object)(object)componentInChildren == (Object)null) { throw new NullReferenceException(); } AssociateItem(componentInChildren, this_ConsumablesData.StoredLocation); } } } [ArchivePatch(/*Could not decode attribute arguments.*/)] public static class LG_PickupItem_Sync__AttemptPickupInteraction__Patch { public static void Prefix(LG_PickupItem_Sync __instance, ref pPickupItemInteraction interaction) { //IL_0001: 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) if ((int)interaction.type != 0) { return; } Item item = __instance.item; object obj; if (item == null) { obj = null; } else { Interact_Base pickupInteraction = item.PickupInteraction; obj = ((pickupInteraction != null) ? ((Component)pickupInteraction).GetComponent() : null); } ContainsLocationPickupComp containsLocationPickupComp = (ContainsLocationPickupComp)obj; if ((Object)(object)containsLocationPickupComp == (Object)null) { return; } StateTracker stateTracker = StateTracker.Get(); SNet_Player val = default(SNet_Player); Location location = stateTracker.NotifyFoundLocation(player: (!((pPlayer)(ref interaction.pPlayer)).TryGetPlayer(ref val)) ? null : ((Il2CppObjectBase)val.PlayerAgent).TryCast(), id: containsLocationPickupComp.StoredLocation); if (location.RandData.IsTreatedAsRandom) { CarryItemPickup_Core val2 = ((Il2CppObjectBase)__instance.item).TryCast(); GenericSmallPickupItem_Core val3 = ((Il2CppObjectBase)__instance.item).TryCast(); if ((Object)(object)val2 != (Object)null) { val2.m_isWardenObjective = false; } else if ((Object)(object)val3 != (Object)null) { val3.m_isWardenObjective = false; } ((pPlayer)(ref interaction.pPlayer)).SetPlayer((SNet_Player)null); ((Component)__instance).gameObject.transform.position = new Vector3(0f, -10000f, 0f); ReplicatedItemWrapper replicationWrapper = __instance.item.ReplicationWrapper; if (replicationWrapper != null) { replicationWrapper.Replicator.Despawn(); } ((Il2CppObjectBase)__instance.GetReplicator()).Cast().Despawn(); } Object.Destroy((Object)(object)containsLocationPickupComp); } } [ArchivePatch(/*Could not decode attribute arguments.*/)] public static class LG_PickupItem_Sync__SetCurrentState_NoSync__Patch { public static void Postfix(LG_PickupItem_Sync __instance) { Item item = __instance.item; object obj; if (item == null) { obj = null; } else { Interact_Base pickupInteraction = item.PickupInteraction; obj = ((pickupInteraction != null) ? ((Component)pickupInteraction).GetComponent() : null); } ContainsLocationPickupComp containsLocationPickupComp = (ContainsLocationPickupComp)obj; if ((Object)(object)containsLocationPickupComp == (Object)null) { return; } Item item2 = __instance.item; Interact_Pickup_PickupItem val = ((item2 != null) ? ((Il2CppObjectBase)item2.PickupInteraction).TryCast() : null); if ((Object)(object)val == (Object)null) { return; } Game.Data processedGameData = StateTracker.Get().MidManager.GetProcessedGameData(); Location loc = processedGameData.Locations.LookUpValueChecked(containsLocationPickupComp.StoredLocation); if (loc.RandData.IsRandomized) { string backupName = processedGameData.Items.LookUpName(loc.ItemID); val.SetName((Func)new Il2CppFunc_string(() => loc.ScoutedItemName ?? backupName)); } } } [InjectToIl2Cpp] public class KeyItemTerminalItemCallback : Object { public KeyItemPickup_Core KeyItem { get; private init; } public KeyItemTerminalItemCallback(IntPtr ptr) : base(ptr) { KeyItem = null; } public KeyItemTerminalItemCallback(KeyItemPickup_Core item) : base(ClassInjector.DerivedConstructorPointer()) { ClassInjector.DerivedConstructorBody((Il2CppObjectBase)(object)this); KeyItem = item; } public List OnWantDetailedInfo(List defaultDetails) { defaultDetails = __c.__9__11_0.Invoke(defaultDetails); ModifyTerminalDetailInfo((ItemInLevel)(object)KeyItem, defaultDetails); return defaultDetails; } public Func, List> GetDelegate() { IntPtr il2CppMethod = IL2CPP.GetIl2CppMethod(((Il2CppObjectBase)this).ObjectClass, false, "OnWantDetailedInfo", typeof(List).FullName, new string[1] { typeof(List).FullName }); return new Func, List>((Object)(object)this, il2CppMethod); } } [ArchivePatch(/*Could not decode attribute arguments.*/)] public static class KeyItemPickup_Core__KeyItem__Patch { public static void Postfix(KeyItemPickup_Core __instance) { __instance.m_terminalItem.OnWantDetailedInfo = new KeyItemTerminalItemCallback(__instance).GetDelegate(); } } [ArchivePatch(/*Could not decode attribute arguments.*/)] public static class CarryItemPickup_Core____c__DisplayClass30_0___Setup_b__0__Patch { public static void Postfix(__c__DisplayClass30_0 __instance, List __result) { ModifyTerminalDetailInfo((ItemInLevel)(object)__instance.__4__this, __result); } } [InjectToIl2Cpp] public class GenericSmallItemTerminalItemCallback : Object { public GenericSmallPickupItem_Core SmallItem { get; private init; } public __c__DisplayClass22_0 OriginalCallback { get; private init; } public GenericSmallItemTerminalItemCallback(IntPtr ptr) : base(ptr) { SmallItem = null; OriginalCallback = null; } public GenericSmallItemTerminalItemCallback(GenericSmallPickupItem_Core item, __c__DisplayClass22_0 original) : base(ClassInjector.DerivedConstructorPointer()) { ClassInjector.DerivedConstructorBody((Il2CppObjectBase)(object)this); SmallItem = item; OriginalCallback = original; } public List OnWantDetailedInfo(List defaultDetails) { defaultDetails = OriginalCallback._SetupPersonnelId_b__0(defaultDetails); ModifyTerminalDetailInfo((ItemInLevel)(object)SmallItem, defaultDetails); return defaultDetails; } public Func, List> GetDelegate() { IntPtr il2CppMethod = IL2CPP.GetIl2CppMethod(((Il2CppObjectBase)this).ObjectClass, false, "OnWantDetailedInfo", typeof(List).FullName, new string[1] { typeof(List).FullName }); return new Func, List>((Object)(object)this, il2CppMethod); } } [ArchivePatch(/*Could not decode attribute arguments.*/)] public static class GenericSmallPickupItem_Core__SetupPersonnelId__Patch { public static void Postfix(GenericSmallPickupItem_Core __instance) { Object target = ((Delegate)__instance.m_terminalItem.OnWantDetailedInfo).Target; __c__DisplayClass22_0 val = ((target != null) ? ((Il2CppObjectBase)target).TryCast<__c__DisplayClass22_0>() : null); if (val != null) { GenericSmallItemTerminalItemCallback genericSmallItemTerminalItemCallback = new GenericSmallItemTerminalItemCallback(__instance, val); __instance.m_terminalItem.OnWantDetailedInfo = genericSmallItemTerminalItemCallback.GetDelegate(); } } } [ArchivePatch(/*Could not decode attribute arguments.*/)] public static class GenericSmallPickupItem_Core__SetupGeneric__Patch { public static void Postfix(GenericSmallPickupItem_Core __instance, List __result) { ModifyTerminalDetailInfo((ItemInLevel)(object)__instance, __result); } } private static IArchiveLogger? m_featureLogger; public const string PICKUPS_OPTION_CATEGORY = "Pickups"; public override string Name => "Pickups Helper"; public override string Description => "Provides utilites used by other features to manage pickups (including big pickups)"; public override FeatureGroup Group => ArchipelagoFeatureGroups.get_PickupHandlers(); public new static IArchiveLogger FeatureLogger { get { return m_featureLogger ?? Plugin.Get().Logger; } set { m_featureLogger = value; } } [Game.Callback] public void AddEventScanOptions(Game.Data data) { ItemID itemID = PickupHelper_Tags.get_Item_Pickups(data); data.AddOption(new OptionItemTagOption("Randomize All Pickups", "Randomize all supported pickups.\nWhitelist: Enables for all unless blacklisted elsewhere.\nBlacklist: Disables for all.\nNone: Defer to other relevant setting(s). If no other relevant setting is set, defaults to blacklisted.", "Pickups", Option.MakeSortKey(data, itemID), 0L, default(OptionID), itemID)); itemID = PickupHelper_Tags.get_Item_SmallPickups(data); data.AddOption(new OptionItemTagOption("Randomize Small Pickups", "Randomize all supported small pickups. This includes colored keys, bulkhead keys, and objective pickups (ie IDs).\nWhitelist: Enables for all unless blacklisted elsewhere.\nBlacklist: Disables for all.\nNone: Defer to other relevant setting(s). If no other relevant setting is set, defaults to blacklisted.", "Pickups", Option.MakeSortKey(data, itemID), 1L, default(OptionID), itemID)); itemID = PickupHelper_Tags.get_Item_BigPickups(data); data.AddOption(new OptionItemTagOption("Randomize Big Pickups", "Randomize all supported big pickups. This includes normal spawns and objective spawns, but not in-level spawns (if there are any).\nWhitelist: Enables for all unless blacklisted elsewhere.\nBlacklist: Disables for all.\nNone: Defer to other relevant setting(s). If no other relevant setting is set, defaults to blacklisted.", "Pickups", Option.MakeSortKey(data, itemID), 1L, default(OptionID), itemID)); } public static void AssociateItem(ItemInLevel item, LocationID locationId, bool despawnIfFound = true) { //IL_01e2: Unknown result type (might be due to invalid IL or missing references) //IL_01e8: Unknown result type (might be due to invalid IL or missing references) //IL_01ec: Unknown result type (might be due to invalid IL or missing references) //IL_01f2: Unknown result type (might be due to invalid IL or missing references) //IL_01f6: Unknown result type (might be due to invalid IL or missing references) //IL_01fc: Unknown result type (might be due to invalid IL or missing references) StateTracker stateTracker = StateTracker.Get(); Game.Data gameData = stateTracker.GameData; ContainsLocationPickupComp containsLocationPickupComp = ((Component)((Item)item).PickupInteraction).GetComponent(); if ((Object)(object)containsLocationPickupComp == (Object)null) { containsLocationPickupComp = ((Component)((Item)item).PickupInteraction).gameObject.AddComponent(); } else if (!containsLocationPickupComp.StoredLocation.IsNull) { int count = Math.Max(containsLocationPickupComp.StoredLocation.ID.ToString().Length, locationId.ID.ToString().Length); string text = new string('0', count); FeatureLogger.Error($"Overwriting location on pickup!\n Old Location: [{containsLocationPickupComp.StoredLocation.ID.ToString(text)}] {gameData.Locations.LookUpName(containsLocationPickupComp.StoredLocation)} New Location: [{locationId.ID.ToString(text)}] {gameData.Locations.LookUpName(locationId)}"); } containsLocationPickupComp.StoredLocation = locationId; Location loc = gameData.Locations.LookUpValueChecked(locationId); if (despawnIfFound && loc.RandData.IsTreatedAsRandom && stateTracker.HasLocation(locationId)) { if ((Object)(object)((Item)item).ReplicationWrapper != (Object)null) { ReplicatedItemWrapper replicationWrapper = ((Item)item).ReplicationWrapper; if (replicationWrapper != null) { replicationWrapper.Replicator.Despawn(); } } else { item.internalSync.AttemptPickupInteraction((ePickupItemInteractionType)0, (SNet_Player)null, default(pItemData_Custom), default(Vector3), default(Quaternion), (AIG_CourseNode)null, false, false); if (item.CanWarp) { Dimension.RemoveWarpable(((Il2CppObjectBase)item).Cast()); } } } else { if (!loc.RandData.IsRandomized) { return; } Interact_Pickup_PickupItem val = ((Il2CppObjectBase)((Item)item).PickupInteraction).TryCast(); if ((Object)(object)val != (Object)null) { string backupName = gameData.Items.LookUpName(loc.ItemID); val.SetName((Func)new Il2CppFunc_string(() => loc.ScoutedItemName ?? backupName)); ((Interact_Timed)val).OnInteractionSelected += DelegateSupport.ConvertDelegate>((Delegate)(Action)delegate { StateTracker.Get().ScoutLocation(locationId, (HintCreationPolicy)2); }); } } } public static void AssociateDistributionWithLocation(LG_Distribute_PickupItemsPerZone distribution, LocationID locationId) { if (((Feature)ArchipelagoFeatureHelper.GetFeature()).Enabled) { ConsumableDistributionDataBlock consumableDistributionData = distribution.m_consumableDistributionData; This_ConsumablesData this_ConsumablesData = ((consumableDistributionData != null) ? ((Il2CppObjectBase)consumableDistributionData).TryCast() : null); if (this_ConsumablesData != null) { FeatureLogger.Error($"Distribution already has location associated with it! Old ID: {this_ConsumablesData.StoredLocation}, New ID: {locationId}"); } else { distribution.m_consumableDistributionData = (ConsumableDistributionDataBlock)(object)new This_ConsumablesData(locationId, distribution.m_consumableDistributionData); } } } public static void AssociateDistributionWithLocation(LG_DistributePickUpItem distribution, LocationID locationId) { if (((Feature)ArchipelagoFeatureHelper.GetFeature()).Enabled) { ConsumableDistributionDataBlock consumableData = distribution.m_consumableData; This_ConsumablesData this_ConsumablesData = ((consumableData != null) ? ((Il2CppObjectBase)consumableData).TryCast() : null); if (this_ConsumablesData != null) { FeatureLogger.Error($"Distribution already has location associated with it! Old ID: {this_ConsumablesData.StoredLocation}, New ID: {locationId}"); } else { distribution.m_consumableData = (ConsumableDistributionDataBlock)(object)new This_ConsumablesData(locationId, distribution.m_consumableData); } } } public static void ModifyTerminalDetailInfo(ItemInLevel item, List detailedData, bool scout = true) { int i; for (i = 1; i < detailedData.Count && !detailedData[i].StartsWith("----"); i++) { } ContainsLocationPickupComp component = ((Component)((Item)item).PickupInteraction).GetComponent(); if ((Object)(object)component == (Object)null) { detailedData.Insert(i++, "MULTIWORLD ITEM: -- NONE --"); return; } StateTracker stateTracker = StateTracker.Get(); Location location = stateTracker.GameData.Locations.LookUpValueChecked(component.StoredLocation); detailedData.Insert(i++, "MULTIWORLD ITEM: (" + location.ScoutedPlayerName + ") " + location.ScoutedItemName); if (scout) { stateTracker.ScoutLocation(component.StoredLocation, (HintCreationPolicy)2); } } } public static class ProgressionCellHandler_Tags { [SpecialName] public sealed class $2B8804A94F2EF68DF77A343A46EE5A78 { [SpecialName] public static class $F943E16B16B76A20C49A59C8DF7C8955 { } [ExtensionMarker("$F943E16B16B76A20C49A59C8DF7C8955")] public LocationID Location_ProgressionCellSpawns { [ExtensionMarker("$F943E16B16B76A20C49A59C8DF7C8955")] get { throw new NotSupportedException(); } } } [SpecialName] public sealed class $07060F1A014DE32BC9DAE9AB0EFE08B9 { [SpecialName] public static class $A55646E979CA6A3D946ACF0E8F38FB8D { } [ExtensionMarker("$A55646E979CA6A3D946ACF0E8F38FB8D")] public LocationID Location_ProgressionCellSpawns_ByZone { [ExtensionMarker("$A55646E979CA6A3D946ACF0E8F38FB8D")] get { throw new NotSupportedException(); } } [ExtensionMarker("$A55646E979CA6A3D946ACF0E8F38FB8D")] public LocationID Location_ProgressionCellSpawn_Instance(int count) { throw new NotSupportedException(); } } public static LocationID get_Location_ProgressionCellSpawns(Game.Data gameData) { return LocationID.From(gameData, "Progression Cell Locations", (Game.Data data) => new TagDefinition("Locations checked by picking up cells specifically spawned by the game's progression puzzle system", PickupHelper_Tags.get_Location_BigPickups(data))); } public static LocationID get_Location_ProgressionCellSpawns_ByZone(Zone.Data data) { return LocationID.From(data, data.ZoneName + " Progression Cell Locations", (Zone.Data gameData) => new TagDefinition("Progresion cell locations spawned for a specific zone's progression puzzle", get_Location_ProgressionCellSpawns(gameData))); } public static LocationID Location_ProgressionCellSpawn_Instance(this Zone.Data data, int count) { return LocationID.From(data, $"{data.ZoneName} Progression Cell Location #{count}", (Zone.Data data2) => new TagDefinition("A particular progression cell spawn location", get_Location_ProgressionCellSpawns_ByZone(data2))); } } [EnableFeatureByDefault] [AutomatedFeature] public class ProgressionCellHandler : ArchipelagoFeature { [ArchivePatch(/*Could not decode attribute arguments.*/)] public static class LG_Distribute_ProgressionPuzzles__Build__Patch { public static void Postfix(LG_Distribute_ProgressionPuzzles __instance) { //IL_00f4: Unknown result type (might be due to invalid IL or missing references) //IL_00fa: Invalid comparison between Unknown and I4 Queue jobs = ((Il2CppArrayBase)(object)LG_Factory.Current.m_batches)[16].Jobs; Layer.Data layerData = Layer.Data.GetFromLayer(__instance.m_layer); if (layerData.LayoutID == 0) { return; } IEnumerator<(Zone.Data, int)> enumerator = (from z in __instance.m_layer.m_buildData.m_zoneBuildDatas where (int)z.ProgressionPuzzleToEnter.PuzzleType == 2 select layerData.FindZoneByIndex(z.LocalIndex)).SelectMany((Zone.Data z) => from i in Enumerable.Range(1, z.Zone.ProgressionPuzzleToEnter.PlacementCount) select (Zone: z, Count: i)).GetEnumerator(); Enumerator enumerator2 = jobs.GetEnumerator(); while (enumerator2.MoveNext()) { LG_FactoryJob current = enumerator2.Current; LG_Distribute_PickupItemsPerZone val = ((Il2CppObjectBase)current).TryCast(); if (val != null && !(((Il2CppObjectBase)val.m_zone.m_layer).Pointer != ((Il2CppObjectBase)__instance.m_layer).Pointer) && (int)val.m_pickupType == 3 && val.m_bigPickupDistributionData == null) { if (val.m_genericItemId != BigPickupHandler.CellItemID) { FeatureLogger.Error("Expected distribution to be a cell, but it wasn't!"); } else if (enumerator.MoveNext()) { (Zone.Data, int) current2 = enumerator.Current; PickupHelper.AssociateDistributionWithLocation(val, current2.Item1.Location_ProgressionCellSpawn_Instance(current2.Item2)); } else { FeatureLogger.Error("Had more cells than progression puzzle cells!"); } } } if (enumerator.MoveNext()) { FeatureLogger.Error("Not all cell locations associated during layer build: " + layerData.LayerName); } } } private static IArchiveLogger? m_featureLogger; public override string Name => "Progression Cell Handler"; public override string Description => "Handles specifically cells spawned as part of progression puzzles\nProgression puzzles are blockers for entering a zone. In this case, any zone that requires a specific generator to be powered to enter"; public override FeatureGroup Group => ArchipelagoFeatureGroups.get_PickupHandlers(); public new static IArchiveLogger FeatureLogger { get { return m_featureLogger ?? Plugin.Get().Logger; } set { m_featureLogger = value; } } [Zone.Callback] public void AddProgressionCells(Zone.Data data) { //IL_0012: Unknown result type (might be due to invalid IL or missing references) ExpeditionZoneData? zone = data.Zone; if (((zone != null) ? ((int)zone.ProgressionPuzzleToEnter.PuzzleType) : 0) == 2) { ItemID item = BigPickupHandler_Tags.get_Item_BigPickup_Cell(data); RegionID[] array = (from i in data.PlacementsToZoneRegions(data.Zone.ProgressionPuzzleToEnter.ZonePlacementData) select i.Region).Distinct().ToArray(); for (int num = 1; num <= data.Zone.ProgressionPuzzleToEnter.PlacementCount; num++) { data.Locations.CreateValue(data.Location_ProgressionCellSpawn_Instance(num), array, default(LocationData), item); } } } } } namespace ReTFO.Archipelago.Features.ObjectiveHandlers { public static class CollectHSUHandler_Tags { [SpecialName] public sealed class $2B8804A94F2EF68DF77A343A46EE5A78 { [SpecialName] public static class $55FD246F9BFF39DD56FCB5C25D4DF852 { } [ExtensionMarker("$55FD246F9BFF39DD56FCB5C25D4DF852")] public LocationID Location_HSUScans { [ExtensionMarker("$55FD246F9BFF39DD56FCB5C25D4DF852")] get { throw new NotSupportedException(); } } [ExtensionMarker("$55FD246F9BFF39DD56FCB5C25D4DF852")] public ItemID Item_HSUScans { [ExtensionMarker("$55FD246F9BFF39DD56FCB5C25D4DF852")] get { throw new NotSupportedException(); } } } [SpecialName] public sealed class $E93D81478905A37B27DF6F640623743D { [SpecialName] public static class $66441969E171E5CA8C86F896EE40E940 { } [ExtensionMarker("$66441969E171E5CA8C86F896EE40E940")] public RegionID Region_HSUScanStarted { [ExtensionMarker("$66441969E171E5CA8C86F896EE40E940")] get { throw new NotSupportedException(); } } [ExtensionMarker("$66441969E171E5CA8C86F896EE40E940")] public RegionID Region_HSUScanCompleted { [ExtensionMarker("$66441969E171E5CA8C86F896EE40E940")] get { throw new NotSupportedException(); } } [ExtensionMarker("$66441969E171E5CA8C86F896EE40E940")] public LocationID Location_HSUScan_Instance { [ExtensionMarker("$66441969E171E5CA8C86F896EE40E940")] get { throw new NotSupportedException(); } } [ExtensionMarker("$66441969E171E5CA8C86F896EE40E940")] public ItemID Item_HSUScan_Instance { [ExtensionMarker("$66441969E171E5CA8C86F896EE40E940")] get { throw new NotSupportedException(); } } } public static LocationID get_Location_HSUScans(Game.Data data) { return LocationID.From(data, "HSU Scan Locations", (Game.Data data2) => new TagDefinition("Locations checked by starting HSU scans", CommonTagsHandler_Tags.get_Location_All(data2))); } public static ItemID get_Item_HSUScans(Game.Data data) { return ItemID.From(data, "HSU Scan Items", (Game.Data data2) => new TagDefinition("Items which start HSU scans", CommonTagsHandler_Tags.get_Item_Scans(data2))); } private static Objective.Data Checked(Objective.Data data) { //IL_0006: 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) if ((int)data.Objective.Type != 0) { FeatureLogger.Warning("Fetched an ID for the wrong objective type. Desired: " + Enum.GetName((eWardenObjectiveType)0) + ", actual: " + Enum.GetName(data.Objective.Type)); } return data; } public static RegionID get_Region_HSUScanStarted(Objective.Data data) { return RegionID.From(Checked(data), data.ObjectiveName + " HSU Scan Started", (Objective.Data data2) => new TagDefinition("Region entered when the HSU scan is started", data2.Region_Objective)); } public static RegionID get_Region_HSUScanCompleted(Objective.Data data) { return RegionID.From(Checked(data), data.ObjectiveName + " HSU Scan Completed", (Objective.Data data2) => new TagDefinition("Region entered when the HSU scan is completed", data2.Region_Objective)); } public static LocationID get_Location_HSUScan_Instance(Objective.Data data) { return LocationID.From(Checked(data), data.ObjectiveName + " HSU Scan Location", (Objective.Data data2) => new TagDefinition("Location checked by starting a particular HSU scan", get_Location_HSUScans(data2))); } public static ItemID get_Item_HSUScan_Instance(Objective.Data data) { return ItemID.From(Checked(data), data.ObjectiveName + " HSU Scan", (Objective.Data data2) => new TagDefinition("Item which triggers a particular HSU scan", get_Item_HSUScans(data2)), new CollectHSUHandler.CollectHSU_ScanItem(data.Region_Objective)); } } [EnableFeatureByDefault] [AutomatedFeature] public class CollectHSUHandler : ArchipelagoFeature { public class CollectHSU_ScanItem : TerminalItem { public RegionID ObjectiveRegion { get; private init; } public override RegionID TargetRegion => ObjectiveRegion; public CollectHSU_ScanItem(RegionID objective) : base(new ItemData { IsProgression = true }) { ObjectiveRegion = objective; } public override IEnumerable OnRetrieveFromTerminalSystem(StateTracker stateTracker, LG_ComputerTerminal terminal, ItemID itemId) { yield return delegate { terminal.AddLine((TerminalLineType)2, "Initiating HSU Scan", 2f); terminal.AddLine("Scan will start in 3 seconds. Enjoy :)", true); }; yield return delegate { Objective.Data data = new Objective.Data(stateTracker.GameData, ObjectiveRegion); WO_HSUFindTakeSample val = ((Il2CppObjectBase)data.GetWardenObjective()).Cast(); val.m_hsu.m_puzzle.AttemptInteract((eChainedPuzzleInteraction)0); }; } } [ArchivePatch(/*Could not decode attribute arguments.*/)] public static class OnHSUSetup { public static void Postfix(LG_HSUScannerJob __instance) { //IL_0030: Unknown result type (might be due to invalid IL or missing references) LocationID id; if (__instance.m_hsu.m_isWardenObjective) { Objective.Data data = Expedition.Data.GetFromCurrentExpedition().GetLayer(__instance.m_hsu.OriginLayer).GetObjectiveDatas() .ElementAt(__instance.m_hsu.WardenObjectiveChainIndex); id = CollectHSUHandler_Tags.get_Location_HSUScan_Instance(data); __instance.m_hsu.m_pickupSampleInteraction.OnInteractionTriggered = DelegateSupport.ConvertDelegate>((Delegate)new Action(OnInteract)); } void OnInteract(PlayerAgent player) { if (!StateTracker.Get().NotifyFoundLocation(id, player).RandData.IsTreatedAsRandom) { __instance.m_hsu._Setup_b__14_2(player); } } } } private static IArchiveLogger? m_featureLogger; public override string Name => "Collect HSU Handler"; public override string Description => "Handles the Collect DNA Sample objective type.\nExample: R1A1"; public override FeatureGroup Group => ArchipelagoFeatureGroups.get_ObjectiveHandlers(); public new static IArchiveLogger FeatureLogger { get { return m_featureLogger ?? (m_featureLogger = Plugin.Get().Logger); } set { m_featureLogger = value; } } [Objective.Callback] public void HandleCollectHSUSample(Objective.Data data) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) if ((int)data.Objective.Type == 0) { ItemID itemID = CollectHSUHandler_Tags.get_Item_HSUScan_Instance(data); data.Locations.CreateValue(CollectHSUHandler_Tags.get_Location_HSUScan_Instance(data), (from info in data.PlacementsToZoneRegions(data.ObjectiveData.ZonePlacementDatas[0]) select info.Region).ToList(), default(LocationData), itemID); RegionID regionID = CollectHSUHandler_Tags.get_Region_HSUScanStarted(data); data.AddPath(new ReTFO.Archipelago.ModdedInstanceData.Model.Path { StartingRegion = data.Region_Objective, EndingRegion = regionID, Reqs = new ReTFO.Archipelago.ModdedInstanceData.Model.Path.MultiPathReq(ReTFO.Archipelago.ModdedInstanceData.Model.Path.eType.Item, itemID, 1u) }); data.MakeOrWrapOnSolveEvents().Process(regionID); RegionID regionID2 = CollectHSUHandler_Tags.get_Region_HSUScanCompleted(data); data.AddPath(new ReTFO.Archipelago.ModdedInstanceData.Model.Path { StartingRegion = regionID, EndingRegion = regionID2 }); SharedObjectiveHandler.AddObjectiveCompleteItem(data, regionID2); } } } public static class ReactorStartupHandler_Tags { [SpecialName] public sealed class $2B8804A94F2EF68DF77A343A46EE5A78 { [SpecialName] public static class $55FD246F9BFF39DD56FCB5C25D4DF852 { } [ExtensionMarker("$55FD246F9BFF39DD56FCB5C25D4DF852")] public LocationID Location_ReactorStartupReactors { [ExtensionMarker("$55FD246F9BFF39DD56FCB5C25D4DF852")] get { throw new NotSupportedException(); } } [ExtensionMarker("$55FD246F9BFF39DD56FCB5C25D4DF852")] public LocationID Location_ReactorStartupCodes { [ExtensionMarker("$55FD246F9BFF39DD56FCB5C25D4DF852")] get { throw new NotSupportedException(); } } [ExtensionMarker("$55FD246F9BFF39DD56FCB5C25D4DF852")] public LocationID Location_ReactorStartupSkips { [ExtensionMarker("$55FD246F9BFF39DD56FCB5C25D4DF852")] get { throw new NotSupportedException(); } } [ExtensionMarker("$55FD246F9BFF39DD56FCB5C25D4DF852")] public ItemID Item_ReactorStartupReactors { [ExtensionMarker("$55FD246F9BFF39DD56FCB5C25D4DF852")] get { throw new NotSupportedException(); } } [ExtensionMarker("$55FD246F9BFF39DD56FCB5C25D4DF852")] public ItemID Item_ReactorStartupCodes { [ExtensionMarker("$55FD246F9BFF39DD56FCB5C25D4DF852")] get { throw new NotSupportedException(); } } [ExtensionMarker("$55FD246F9BFF39DD56FCB5C25D4DF852")] public ItemID Item_ReactorStartupSkips { [ExtensionMarker("$55FD246F9BFF39DD56FCB5C25D4DF852")] get { throw new NotSupportedException(); } } } [SpecialName] public sealed class $E93D81478905A37B27DF6F640623743D { [SpecialName] public static class $66441969E171E5CA8C86F896EE40E940 { } [ExtensionMarker("$66441969E171E5CA8C86F896EE40E940")] public LocationID Location_ReactorStartupReactors_PerObjective { [ExtensionMarker("$66441969E171E5CA8C86F896EE40E940")] get { throw new NotSupportedException(); } } [ExtensionMarker("$66441969E171E5CA8C86F896EE40E940")] public LocationID Location_ReactorStartupSkips_PerObjective { [ExtensionMarker("$66441969E171E5CA8C86F896EE40E940")] get { throw new NotSupportedException(); } } [ExtensionMarker("$66441969E171E5CA8C86F896EE40E940")] public LocationID Location_ReactorStartupCodes_PerObjective { [ExtensionMarker("$66441969E171E5CA8C86F896EE40E940")] get { throw new NotSupportedException(); } } [ExtensionMarker("$66441969E171E5CA8C86F896EE40E940")] public ItemID Item_ReactorStartupReactors_PerObjective { [ExtensionMarker("$66441969E171E5CA8C86F896EE40E940")] get { throw new NotSupportedException(); } } [ExtensionMarker("$66441969E171E5CA8C86F896EE40E940")] public ItemID Item_ReactorStartupCodes_PerObjective { [ExtensionMarker("$66441969E171E5CA8C86F896EE40E940")] get { throw new NotSupportedException(); } } [ExtensionMarker("$66441969E171E5CA8C86F896EE40E940")] public ItemID Item_ReactorStartupSkips_PerObjective { [ExtensionMarker("$66441969E171E5CA8C86F896EE40E940")] get { throw new NotSupportedException(); } } [ExtensionMarker("$66441969E171E5CA8C86F896EE40E940")] public RegionID Region_ReactorStartupFoundReactor() { throw new NotSupportedException(); } [ExtensionMarker("$66441969E171E5CA8C86F896EE40E940")] public RegionID Region_ReactorStartupSurvivedWave(int count) { throw new NotSupportedException(); } [ExtensionMarker("$66441969E171E5CA8C86F896EE40E940")] public RegionID Region_ReactorStartupCompletedStartup(int count = 1) { throw new NotSupportedException(); } [ExtensionMarker("$66441969E171E5CA8C86F896EE40E940")] public LocationID Location_ReactorStartupReactor_Instance(int count) { throw new NotSupportedException(); } [ExtensionMarker("$66441969E171E5CA8C86F896EE40E940")] public LocationID Location_ReactorStartupCode_Instance(int count) { throw new NotSupportedException(); } [ExtensionMarker("$66441969E171E5CA8C86F896EE40E940")] public LocationID Location_ReactorStartupSkip_Instance(int count) { throw new NotSupportedException(); } [ExtensionMarker("$66441969E171E5CA8C86F896EE40E940")] public ItemID Item_ReactorStartupReactor_Instance(int count) { throw new NotSupportedException(); } [ExtensionMarker("$66441969E171E5CA8C86F896EE40E940")] public ItemID Item_ReactorStartupCode_Instance(int count) { throw new NotSupportedException(); } [ExtensionMarker("$66441969E171E5CA8C86F896EE40E940")] public ItemID Item_ReactorStartupSkip_Instance(int count) { throw new NotSupportedException(); } } public static LocationID get_Location_ReactorStartupReactors(Game.Data data) { return LocationID.From(data, "Reactor Startup Reactor Locations", (Game.Data data2) => new TagDefinition("Locations checked by entering zones with Reactor Startup reactors (as opposed to Reactor Shutdown reactors)", CommonTagsHandler_Tags.get_Location_Never(data2))); } public static LocationID get_Location_ReactorStartupCodes(Game.Data data) { return LocationID.From(data, "Reactor Startup Code Locations", (Game.Data gameData) => new TagDefinition("Locations checked by finding Reactor Startup codes. Includes \"free\" codes", TerminalLogHelper_Tags.get_Location_TerminalLogs(gameData))); } public static LocationID get_Location_ReactorStartupSkips(Game.Data data) { return LocationID.From(data, "Reactor Startup Skip Locations", (Game.Data data2) => new TagDefinition("Location checked when a reactor wave is survived used to grant wave skip items", CommonTagsHandler_Tags.get_Location_Never(data2))); } public static ItemID get_Item_ReactorStartupReactors(Game.Data data) { return ItemID.From(data, "Reactor Startup Reactors", (Game.Data data2) => new TagDefinition("Reactor item indicating a reactor startup can be performed", CommonTagsHandler_Tags.get_Item_Never(data2))); } public static ItemID get_Item_ReactorStartupCodes(Game.Data data) { return ItemID.From(data, "Reactor Startup Codes", (Game.Data data2) => new TagDefinition("Reactor item indicating the player has found a reactor code", CommonTagsHandler_Tags.get_Item_Codes(data2))); } public static ItemID get_Item_ReactorStartupSkips(Game.Data data) { return ItemID.From(data, "Reactor Startup Skips", (Game.Data data2) => new TagDefinition("Reactor items allowing players to skip to a particular wave", CommonTagsHandler_Tags.get_Item_Never(data2))); } public static Objective.Data Checked(Objective.Data data) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Invalid comparison between Unknown and I4 //IL_0024: Unknown result type (might be due to invalid IL or missing references) if ((int)data.Objective.Type != 1) { FeatureLogger.Warning("Fetched an ID for the wrong objective type. Desired: " + Enum.GetName((eWardenObjectiveType)1) + ", actual: " + Enum.GetName(data.Objective.Type)); } return data; } public static RegionID Region_ReactorStartupFoundReactor(this Objective.Data data) { return RegionID.From(Checked(data), data.ObjectiveName + " Found Reactor", (Objective.Data data2) => new TagDefinition("Region entered when at least one reactor startup reactor is found", data2.Region_Objective)); } public static RegionID Region_ReactorStartupSurvivedWave(this Objective.Data data, int count) { return RegionID.From(Checked(data), $"{data.ObjectiveName} Survived Wave #{count}", (Objective.Data data2) => new TagDefinition("Region entered when a particular reactor startup wave is survived", data2.Region_Objective)); } public static RegionID Region_ReactorStartupCompletedStartup(this Objective.Data data, int count = 1) { return RegionID.From(Checked(data), $"{data.ObjectiveName} Completed Reactor Startup #{count}", (Objective.Data data2) => new TagDefinition("Region entered when a particular number of reactor startups are completed", data2.Region_Objective)); } public static LocationID get_Location_ReactorStartupReactors_PerObjective(Objective.Data data) { return LocationID.From(Checked(data), data.ObjectiveName + " Reactor Startup Reactor Locations", (Objective.Data data2) => new TagDefinition("Locations checked by entering zones iwth Reactor Startup reactors for a particular objective", get_Location_ReactorStartupReactors(data2))); } public static LocationID get_Location_ReactorStartupSkips_PerObjective(Objective.Data data) { return LocationID.From(Checked(data), data.ObjectiveName + " Reactor Startup Skip Locations", (Objective.Data data2) => new TagDefinition("Location checked when a reactor wave is survived used to grant wave skip items for a particular objective", get_Location_ReactorStartupSkips(data2))); } public static LocationID get_Location_ReactorStartupCodes_PerObjective(Objective.Data data) { return LocationID.From(Checked(data), data.ObjectiveName + " Reactor Startup Codes", (Objective.Data data2) => new TagDefinition("Reactor code locations for a particular objective", get_Location_ReactorStartupCodes(data2))); } public static ItemID get_Item_ReactorStartupReactors_PerObjective(Objective.Data data) { return ItemID.From(Checked(data), data.ObjectiveName + " Reactor Startup Reactors", (Objective.Data data2) => new TagDefinition("Reactor item indicating a reactor startup can be performed for a particular objective", get_Item_ReactorStartupReactors(data2))); } public static ItemID get_Item_ReactorStartupCodes_PerObjective(Objective.Data data) { return ItemID.From(Checked(data), data.ObjectiveName + " Reactor Startup Codes", (Objective.Data data2) => new TagDefinition("Reactor item indicating the player has found a reactor code for a particular objective", get_Item_ReactorStartupCodes(data2))); } public static ItemID get_Item_ReactorStartupSkips_PerObjective(Objective.Data data) { return ItemID.From(Checked(data), data.ObjectiveName + " Reactor Startup Skip", (Objective.Data data2) => new TagDefinition("Reactor items allowing players to skip to a particular wave for a particular objective", get_Item_ReactorStartupSkips(data2))); } public static LocationID Location_ReactorStartupReactor_Instance(this Objective.Data data, int count) { return LocationID.From(Checked(data), $"{data.ObjectiveName} Reactor Startup Reactor Location #{count}", (Objective.Data data2) => new TagDefinition("A particular reactor startup reactor location", get_Location_ReactorStartupReactors_PerObjective(data2))); } public static LocationID Location_ReactorStartupCode_Instance(this Objective.Data data, int count) { return LocationID.From(Checked(data), $"{data.ObjectiveName} Reactor Startup Code #{count}", (Objective.Data data2) => new TagDefinition("A particular reactor code's location", get_Location_ReactorStartupCodes_PerObjective(data2))); } public static LocationID Location_ReactorStartupSkip_Instance(this Objective.Data data, int count) { return LocationID.From(Checked(data), $"{data.ObjectiveName} Reactor Startup Skip Location #{count}", (Objective.Data data2) => new TagDefinition("A particular reactor skip item's location", get_Location_ReactorStartupSkips_PerObjective(data2))); } public static ItemID Item_ReactorStartupReactor_Instance(this Objective.Data data, int count) { return ItemID.From(Checked(data), $"{data.ObjectiveName} Reactor Startup Reactor #{count}", (Objective.Data data2) => new TagDefinition("A particular reactor startup reactor", get_Item_ReactorStartupReactors_PerObjective(data2)), new ReactorStartupHandler.ReactorStartup_ReactorItem(data.Region_Objective, count)); } public static ItemID Item_ReactorStartupCode_Instance(this Objective.Data data, int count) { return ItemID.From(Checked(data), $"{data.ObjectiveName} Reactor Startup Code #{count}", (Objective.Data data2) => new TagDefinition("A particular reactor startup code", get_Item_ReactorStartupCodes_PerObjective(data2)), new ReactorStartupHandler.ReactorStartup_CodeItem(data.Region_Objective, count)); } public static ItemID Item_ReactorStartupSkip_Instance(this Objective.Data data, int count) { return ItemID.From(Checked(data), $"{data.ObjectiveName} Reactor Startup Skip #{count}", (Objective.Data data2) => new TagDefinition("A particular reactor startup skip item", get_Item_ReactorStartupSkips_PerObjective(data2)), new ReactorStartupHandler.ReactorStartup_SkipItem(data.Region_Objective, count)); } } [EnableFeatureByDefault] [AutomatedFeature] public class ReactorStartupHandler : ArchipelagoFeature { public class ReactorStartup_CodeLocation : TerminalLogHelper.TerminalLogLocation { public LG_WardenObjective_Reactor? Reactor { get; set; } public int CodeCount { get; private init; } public ReactorStartup_CodeLocation(RegionList regions, LocationData randData, ItemID itemId, int codeCount) : base(regions, randData, itemId) { CodeCount = codeCount; } public override void OnNotRandomized(StateTracker stateTracker, LG_ComputerTerminal terminal) { if ((Object)(object)Reactor == (Object)null) { FeatureLogger.Warning("Failed to update reactor UI: Location was not associated with reactor"); } else { ProgressionObjective_ReactorStartup.NotifyFoundCode(Reactor, CodeCount - 1); } } } public class ReactorStartup_ReactorItem : Item { public RegionID ObjectiveRegion { get; private init; } public int Count { get; private init; } public ReactorStartup_ReactorItem(RegionID objective, int count) : base(new ItemData { IsProgression = true }) { ObjectiveRegion = objective; Count = count; } } public class ReactorStartup_CodeItem : ExpeditionItem { public RegionID ObjectiveRegion { get; private init; } public int Index { get; private init; } public override RegionID TargetRegion => ObjectiveRegion; public ReactorStartup_CodeItem(RegionID objective, int count) : base(new ItemData { IsProgression = true }) { ObjectiveRegion = objective; Index = count - 1; } private List GetReactors(StateTracker stateTracker) { Objective.Data data = new Objective.Data(stateTracker.GameData, ObjectiveRegion); List list = (from r in (IEnumerable)Object.FindObjectsOfType(Il2CppType.Of()) select ((Il2CppObjectBase)r).Cast() into r where r.m_isWardenObjective where r.OriginLayer == data.LayerType where r.WardenObjectiveChainIndex == data.ObjectiveIndex select r).ToList(); if (list.Count == 0) { FeatureLogger.Error("Failed to find valid reactor while granting reactor code item"); } return list; } public override void OnEnteredExpedition(StateTracker stateTracker, LocationID sourceLocationId, PlayerAgent? player, ItemID itemId) { //IL_0031: Unknown result type (might be due to invalid IL or missing references) stateTracker.AddItemToTerminal(itemId); foreach (LG_WardenObjective_Reactor reactor in GetReactors(stateTracker)) { ProgressionObjective_ReactorStartup.NotifyFoundCode(reactor, Index); if (reactor.m_stateReplicator.State.stateCount == Index + 1) { reactor.CurrentStateOverrideCode = ((Il2CppArrayBase)(object)reactor.GetOverrideCodes())[Index]; } } } public override IEnumerable OnRetrieveFromTerminalSystem(StateTracker stateTracker, LG_ComputerTerminal terminal, ItemID itemId) { LG_WardenObjective_Reactor reactor = GetReactors(stateTracker).FirstOrDefault(); stateTracker.AddItemToTerminal(itemId); yield return delegate { terminal.AddLine((TerminalLineType)2, "Retrieving " + StateTracker.Get().GameData.Items.LookUpName(itemId), 2f); if ((Object)(object)reactor != (Object)null) { terminal.AddLine(string.Format(((Feature)ArchipelagoFeatureHelper.GetFeature()).Localization.Get(182408469u), ((Il2CppArrayBase)(object)reactor.GetOverrideCodes())[Index]), true); } else { terminal.AddLine("<#F00>Failed to find any reactors to pull codes from!", true); } }; } } public class ReactorStartup_SkipItem : Item { public RegionID ObjectiveRegion { get; private init; } public int Count { get; private init; } public ReactorStartup_SkipItem(RegionID objective, int count) : base(new ItemData { IsUseful = true, IsRandomLike = true }) { ObjectiveRegion = objective; Count = count; } } [ArchivePatch(/*Could not decode attribute arguments.*/)] public static class LG_WardenObjective_Reactor__OnBuildDone__Patch { public static void Postfix(LG_WardenObjective_Reactor __instance) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Invalid comparison between Unknown and I4 //IL_00f2: Unknown result type (might be due to invalid IL or missing references) //IL_00f9: Expected O, but got Unknown Objective.Data data = Expedition.Data.GetFromCurrentExpedition().GetLayer(__instance.OriginLayer).GetObjectiveDatas() .ElementAt(__instance.WardenObjectiveChainIndex); if ((int)data.Objective.Type != 1) { return; } int num = 0; Enumerator enumerator = data.Objective.ReactorWaves.GetEnumerator(); while (enumerator.MoveNext()) { ReactorWaveData current = enumerator.Current; num++; if (current.HasVerificationTerminal) { LocationID locationID = data.Location_ReactorStartupCode_Instance(num); if (!(data.Locations.LookUpValueChecked(locationID) is ReactorStartup_CodeLocation reactorStartup_CodeLocation)) { FeatureLogger.Error("Failed to update reactor startup log location with reactor instance!"); } else { reactorStartup_CodeLocation.Reactor = __instance; } int num2 = LG_LevelInteractionManager.Current.m_terminalItemsByKeyString.FindEntry(current.VerificationTerminalSerial); if (num2 == -1) { FeatureLogger.Error("Failed to identify reactor terminal log."); continue; } Entry val = ((Il2CppArrayBase>)(object)LG_LevelInteractionManager.Current.m_terminalItemsByKeyString.entries)[num2]; Component val2 = new Component(((Il2CppObjectBase)val.value).Pointer); LG_ComputerTerminal component = val2.GetComponent(); TerminalLogHelper.AssociateLog(component, current.VerificationTerminalFileName, locationID); } } ProgressionObjective_ReactorStartup.Setup(__instance); } } [ArchivePatch(/*Could not decode attribute arguments.*/)] public static class LG_WardenObjective_Reactor__TryGetCurrentWaveData__Patch { public static void Postfix(LG_WardenObjective_Reactor __instance, ref string overrideCode) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Invalid comparison between Unknown and I4 //IL_003b: Unknown result type (might be due to invalid IL or missing references) Objective.Data data = Expedition.Data.GetFromCurrentExpedition().GetLayer(__instance.OriginLayer).GetObjectiveDatas() .ElementAt(__instance.WardenObjectiveChainIndex); if ((int)data.Objective.Type == 1) { int count = Math.Max(__instance.m_stateReplicator.State.stateCount, 1); LocationID id = data.Location_ReactorStartupCode_Instance(count); Location location = data.Locations.LookUpValueChecked(id); StateTracker stateTracker = StateTracker.Get(); if (stateTracker.CollectedItemCounts.GetValueOrDefault(location.ItemID, 0) <= 0 && location.RandData.IsTreatedAsRandom) { overrideCode = "––-–"; } ProgressionObjective_ReactorStartup.Update(__instance); } } } [ArchivePatch(/*Could not decode attribute arguments.*/)] public static class LG_WardenObjective_Reactor__AttemptInteract__Patch { public static void Postfix(LG_WardenObjective_Reactor __instance, pReactorInteraction interaction) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Invalid comparison between Unknown and I4 //IL_00b1: Unknown result type (might be due to invalid IL or missing references) //IL_00b2: Unknown result type (might be due to invalid IL or missing references) //IL_00b8: Invalid comparison between Unknown and I4 //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) if ((int)interaction.type == 2) { Objective.Data data = Expedition.Data.GetFromCurrentExpedition().GetLayer(__instance.OriginLayer).GetObjectiveDatas() .ElementAt(__instance.WardenObjectiveChainIndex); StateTracker stateTracker = StateTracker.Get(); int stateCount = __instance.m_stateReplicator.State.stateCount; stateTracker.NotifyFoundRegion(data.Region_ReactorStartupSurvivedWave(stateCount), null); LocationID id = data.Location_ReactorStartupSkip_Instance(stateCount); stateTracker.NotifyFoundLocation(id, null); if (!data.Objective.ReactorWaves[stateCount - 1].VerifyInOtherZone) { id = data.Location_ReactorStartupCode_Instance(stateCount); if (!stateTracker.NotifyFoundLocation(id, null).RandData.IsTreatedAsRandom) { ProgressionObjective_ReactorStartup.NotifyFoundCode(__instance, stateCount - 1); } } } else if ((int)interaction.type == 5) { ProgressionObjective_ReactorStartup.Update(__instance); } } } [ArchivePatch(/*Could not decode attribute arguments.*/)] public static class LG_ComputerTerminal__OnPostRecall__Patch { public static void Postfix(LG_ComputerTerminal __instance) { if (!((Object)(object)__instance.ConnectedReactor == (Object)null) && __instance.ConnectedReactor.m_isWardenObjective) { ProgressionObjective_ReactorStartup.Update(__instance.ConnectedReactor); } } } private class SkipToWaveSubcommand : APCommandHandler.SubCommand { public override string HelpText => "Skips to a specific reactor wave. Must be used on a reactor terminal. Only skips forward.\nNote: Immediately executes all events related to completing the waves you skip. This may include enemy spawns.\nNote: You can unlock the ability to skip to a wave by surviving a wave.\n For example, surviving wave #1 will unlock the ability to skip to the start of wave #1.\n You do not need to enter the verification code, you only need to survive the wave."; public SkipToWaveSubcommand() { base.SubCommandName = "SKIPTOWAVE"; } public override void Execute(LG_ComputerTerminal terminal, string fullLine, string subCommand, string param2) { //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_00b9: 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_01d5: Unknown result type (might be due to invalid IL or missing references) //IL_01f3: Unknown result type (might be due to invalid IL or missing references) //IL_0200: Unknown result type (might be due to invalid IL or missing references) //IL_0202: Unknown result type (might be due to invalid IL or missing references) //IL_020f: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)terminal.ConnectedReactor == (Object)null) { terminal.AddLine("This sub-command must be used on a reactor terminal!", true); return; } StateTracker stateTracker = StateTracker.Get(); Objective.Data data = Expedition.Data.GetFromCurrentExpedition().GetLayer(terminal.ConnectedReactor.OriginLayer).GetObjectiveDatas() .ElementAt(terminal.ConnectedReactor.WardenObjectiveChainIndex); int stateCount = terminal.ConnectedReactor.m_stateReplicator.State.stateCount; if (param2 != null && param2.Length != 0 && int.TryParse(param2, out var result)) { if (result < 2) { terminal.AddLine("You cannot skip to a wave before wave #2", true); } else if (result <= stateCount && (int)terminal.ConnectedReactor.m_stateReplicator.State.status != 0) { terminal.AddLine($"You can only skip forward using this command. Current wave: {stateCount}", true); } else if (result > terminal.ConnectedReactor.m_waveCountMax) { terminal.AddLine($"This reactor only has {terminal.ConnectedReactor.m_waveCountMax} waves; cannot skip past that!", true); } else { if (hasSkipForWave(result)) { for (int i = Math.Max(stateCount, 1); i < result; i++) { WorldEventManager.ExecuteEvents(data.Objective.ReactorWaves[i - 1].Events, 0f); } pReactorState state = new pReactorState { stateCount = result, stateProgress = 0f, status = (eReactorStatus)2, verifyFailed = false }; terminal.ConnectedReactor.m_stateReplicator.State = state; terminal.AddLine($"Jumping to reactor wave #{result}", true); return; } terminal.AddLine($"Skipping to reactor wave #{result} has not been unlocked!", true); } } IEnumerable enumerable = Enumerable.Range(stateCount + 1, terminal.ConnectedReactor.m_waveCountMax - stateCount).Where(hasSkipForWave); if (enumerable.Any()) { terminal.AddLine("Waves you may currently skip to: " + string.Join(", ", enumerable), true); } else { terminal.AddLine("Waves you may currently skip to: None", true); } bool hasSkipForWave(int count) { ItemID key = data.Item_ReactorStartupSkip_Instance(count); return StateTracker.Get().CollectedItemCounts.GetValueOrDefault(key, 0) > 0; } } } public class ProgressionObjective_ReactorStartup : CustomObjectiveHandler.ObjectiveItem { private BitArray? m_obtainedCodes; public static string MakeKey(LG_WardenObjective_Reactor reactor) { return ((Il2CppObjectBase)reactor).Pointer.ToString(); } public static void Setup(LG_WardenObjective_Reactor reactor) { CustomObjectiveHandler.GetObjectiveItem(MakeKey(reactor)).SetupInternal(reactor); } public static void Update(LG_WardenObjective_Reactor reactor) { CustomObjectiveHandler.GetObjectiveItem(MakeKey(reactor)).UpdateInternal(reactor); } public static void NotifyFoundCode(LG_WardenObjective_Reactor reactor, int codeIndex) { CustomObjectiveHandler.GetObjectiveItem(MakeKey(reactor)).NotifyFoundCodeInternal(reactor, codeIndex); } public override void Setup() { base.IsActive = false; base.Scope = CustomObjectiveHandler.eObjectiveScope.Layer; base.ObjectiveTag = "CODES"; base.HeaderText = "REACTOR STARTUP OBJECTIVE"; base.SubText = "Retrieving data..."; base.Setup(); } public void SetupInternal(LG_WardenObjective_Reactor reactor) { //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_0073: 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) m_obtainedCodes = new BitArray(reactor.m_waveCountMax); LayerType layerType = reactor.OriginLayer; int value = reactor.WardenObjectiveChainIndex + 1; base.HeaderText = $"{layerType.GetName()} Objective #{value} (Reactor Startup)"; base.ScopeTarget = new GlobalZoneIndex((eDimensionIndex)layerType, (LG_LayerType)layerType, (eLocalZoneIndex)0); Refresh(); } public void UpdateInternal(LG_WardenObjective_Reactor reactor) { //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_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_0024: Invalid comparison between Unknown and I4 base.IsActive = (int)reactor.m_stateReplicator.State.status != 0 && (int)reactor.m_stateReplicator.State.status != 5; base.SubText = MakeFormattedText(reactor); Refresh(); } public void NotifyFoundCodeInternal(LG_WardenObjective_Reactor reactor, int codeIndex) { if (m_obtainedCodes == null) { FeatureLogger.Error("Cannot update reactor startup UI; it is not yet set up!"); } else if (codeIndex < 0 || codeIndex >= m_obtainedCodes.Count) { FeatureLogger.Warning("Failed to update reactor startup UI; code count is out of bounds!"); } else { m_obtainedCodes[codeIndex] = true; } UpdateInternal(reactor); } private string MakeFormattedText(LG_WardenObjective_Reactor reactor) { //IL_0014: Unknown result type (might be due to invalid IL or missing references) int currentWave = Math.Max(reactor.m_stateReplicator.State.stateCount, 1); int waveCountMax = reactor.m_waveCountMax; List codes = ((IEnumerable)CustomExtensions.RangeSubset((Il2CppArrayBase)(object)reactor.GetOverrideCodes(), 0, waveCountMax)).Select(formatCode).ToList(); int num = currentWave; IEnumerable values = ((waveCountMax < 6) ? codes : ((num < 4) ? (from i in Enumerable.Range(0, 4) select codes[i]).Append(" ···") : ((waveCountMax - num >= 3) ? (from i in Enumerable.Range(num - 2, 3) select codes[i]).Prepend(" ···").Append(" ···") : (from i in Enumerable.Range(waveCountMax - 4, 4) select codes[i]).Prepend(" ···")))); return string.Join("\n> ", values); string formatCode(string code, int index) { string value = ((m_obtainedCodes != null && m_obtainedCodes[index]) ? code : "––-–"); return $"Wave #{index + 1} Code: {value}{((index + 1 == currentWave) ? " <" : "")}"; } } } private static IArchiveLogger? m_featureLogger; private SkipToWaveSubcommand? m_skipToWaveCommand; private const string NotACode = "––-–"; public override string Name => "Reactor Startup Handler"; public override string Description => "Handles the Reactor Startup objective type.\nExample: R1C1"; public override FeatureGroup Group => ArchipelagoFeatureGroups.get_ObjectiveHandlers(); public new static IArchiveLogger FeatureLogger { get { return m_featureLogger ?? (m_featureLogger = Plugin.Get().Logger); } set { m_featureLogger = value; } } public override void OnEnable() { base.OnEnable(); APCommandHandler.RegisterCommand(m_skipToWaveCommand ?? (m_skipToWaveCommand = new SkipToWaveSubcommand())); } public override void OnDisable() { base.OnDisable(); APCommandHandler.UnregisterCommand(m_skipToWaveCommand ?? (m_skipToWaveCommand = new SkipToWaveSubcommand())); } [Objective.Callback] public void HandleReactorStartupObjective(Objective.Data data) { //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Invalid comparison between Unknown and I4 //IL_02d3: Unknown result type (might be due to invalid IL or missing references) if ((int)data.Objective.Type != 1) { return; } int count = 0; foreach (ZonePlacementData item2 in data.ObjectiveData.ZonePlacementDatas.SelectMany((List ps) => ps.Iter())) { Zone.Data data2 = data.FindZoneByPlacement(item2); if (data2 == null) { FeatureLogger.Error("Failed to find reactor zone by placement: " + data.ObjectiveName); } else { addReactor(data2); } } if (count == 0) { foreach (Zone.Data item3 in Zone.get_AllZones(data)) { if (item3.CustomGeo != null && !item3.CustomGeo.Contains("hall", StringComparison.OrdinalIgnoreCase) && item3.CustomGeo.Contains("reactor", StringComparison.OrdinalIgnoreCase)) { FeatureLogger.Debug("Using geomorph for reactor objective: " + data.ObjectiveName); addReactor(item3); break; } } if (count == 0) { FeatureLogger.Error("No reactor placements: " + data.ObjectiveName); } } RegionID startingRegion = data.Region_Objective; ReTFO.Archipelago.ModdedInstanceData.Model.Path.MultiPathReq reqs = new ReTFO.Archipelago.ModdedInstanceData.Model.Path.MultiPathReq(ReTFO.Archipelago.ModdedInstanceData.Model.Path.eType.Category, ReactorStartupHandler_Tags.get_Item_ReactorStartupReactors_PerObjective(data), 1u); count = 0; foreach (ReactorWaveData item4 in data.Objective.ReactorWaves.Iter()) { int num = count + 1; count = num; RegionID regionID = data.Region_ReactorStartupSurvivedWave(count); data.AddPath(new ReTFO.Archipelago.ModdedInstanceData.Model.Path { StartingRegion = startingRegion, EndingRegion = regionID, Reqs = reqs }); startingRegion = regionID; Objective.Data layerData = data; ReactorWaveData val = item4; layerData.ProcessEvents(regionID, val.Events ?? (val.Events = new List(1))); ItemID item = data.Item_ReactorStartupSkip_Instance(count); data.Locations.CreateValue(data.Location_ReactorStartupSkip_Instance(count), regionID, default(LocationData), item); ItemID itemID = data.Item_ReactorStartupCode_Instance(count); reqs = new ReTFO.Archipelago.ModdedInstanceData.Model.Path.MultiPathReq(ReTFO.Archipelago.ModdedInstanceData.Model.Path.eType.Category, itemID, 1u); if (item4.VerifyInOtherZone) { Zone.Data zoneData = data.FindZoneByIndex(item4.ZoneForVerification) ?? throw new NullReferenceException("Failed to find zone for reactor code placement!"); data.Locations.SetValue(data.Location_ReactorStartupCode_Instance(count), new ReactorStartup_CodeLocation((from t in Terminal.get_TerminalDatas(zoneData) select t.Region_Terminal).ToArray(), default(LocationData), itemID, count)); } else { data.Locations.CreateValue(data.Location_ReactorStartupCode_Instance(count), regionID, default(LocationData), data.Item_ReactorStartupCode_Instance(count)); } } Event.Wrapper wrapper = data.MakeOrWrapOnSolveEvents(); count = 0; while (!wrapper.IsDone) { int num = count + 1; count = num; RegionID regionID2 = data.Region_ReactorStartupCompletedStartup(count); data.AddPath(new ReTFO.Archipelago.ModdedInstanceData.Model.Path { StartingRegion = startingRegion, EndingRegion = regionID2, Reqs = reqs }); reqs = new ReTFO.Archipelago.ModdedInstanceData.Model.Path.MultiPathReq(ReTFO.Archipelago.ModdedInstanceData.Model.Path.eType.Category, ReactorStartupHandler_Tags.get_Item_ReactorStartupReactors_PerObjective(data), (uint)(count + 1)); startingRegion = regionID2; wrapper.Process(regionID2); } if (!data.Objective.DoNotSolveObjectiveOnReactorComplete) { SharedObjectiveHandler.AddObjectiveCompleteItem(data, data.Region_ReactorStartupCompletedStartup()); } void addReactor(Zone.Data zone) { int num2 = count + 1; count = num2; data.Locations.CreateValue(data.Location_ReactorStartupReactor_Instance(count), zone.Region_Zone, new LocationData { IsAutoDiscovered = true }, data.Item_ReactorStartupReactor_Instance(count)); } } } public static class ReactorShutdownHandler_Tags { [SpecialName] public sealed class $2B8804A94F2EF68DF77A343A46EE5A78 { [SpecialName] public static class $55FD246F9BFF39DD56FCB5C25D4DF852 { } [ExtensionMarker("$55FD246F9BFF39DD56FCB5C25D4DF852")] public LocationID Location_ReactorShutdownReactors { [ExtensionMarker("$55FD246F9BFF39DD56FCB5C25D4DF852")] get { throw new NotSupportedException(); } } [ExtensionMarker("$55FD246F9BFF39DD56FCB5C25D4DF852")] public ItemID Item_ReactorShutdownReactors { [ExtensionMarker("$55FD246F9BFF39DD56FCB5C25D4DF852")] get { throw new NotSupportedException(); } } } [SpecialName] public sealed class $E93D81478905A37B27DF6F640623743D { [SpecialName] public static class $66441969E171E5CA8C86F896EE40E940 { } [ExtensionMarker("$66441969E171E5CA8C86F896EE40E940")] public LocationID Location_ReactorShutdownReactors_PerObjective { [ExtensionMarker("$66441969E171E5CA8C86F896EE40E940")] get { throw new NotSupportedException(); } } [ExtensionMarker("$66441969E171E5CA8C86F896EE40E940")] public ItemID Item_ReactorShutdownReactors_PerObjective { [ExtensionMarker("$66441969E171E5CA8C86F896EE40E940")] get { throw new NotSupportedException(); } } [ExtensionMarker("$66441969E171E5CA8C86F896EE40E940")] public RegionID Region_CompletedShutdown(int count) { throw new NotSupportedException(); } [ExtensionMarker("$66441969E171E5CA8C86F896EE40E940")] public LocationID Location_ReactorShutdownReactor_Instance(int count) { throw new NotSupportedException(); } [ExtensionMarker("$66441969E171E5CA8C86F896EE40E940")] public ItemID Item_ReactorShutdownReactor_Instance(int count) { throw new NotSupportedException(); } } public static LocationID get_Location_ReactorShutdownReactors(Game.Data data) { return LocationID.From(data, "Reactor Shutdown Reactor Locations", (Game.Data data2) => new TagDefinition("Locations checked by finding a reactor shutdown reactor", CommonTagsHandler_Tags.get_Location_Never(data2))); } public static ItemID get_Item_ReactorShutdownReactors(Game.Data data) { return ItemID.From(data, "Reactor Shutdown Reactor Items", (Game.Data data2) => new TagDefinition("Items representing a reactor used for a reactor shutdown objective", CommonTagsHandler_Tags.get_Item_Never(data2))); } public static Objective.Data Checked(Objective.Data data) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Invalid comparison between Unknown and I4 //IL_0024: Unknown result type (might be due to invalid IL or missing references) if ((int)data.Objective.Type != 2) { FeatureLogger.Warning("Fetched an ID for the wrong objective type. Desired: " + Enum.GetName((eWardenObjectiveType)2) + ", actual: " + Enum.GetName(data.Objective.Type)); } return data; } public static RegionID Region_CompletedShutdown(this Objective.Data data, int count) { return RegionID.From(data, $"{data.ObjectiveName} Completed {count} Reactor Startup", (Objective.Data data2) => new TagDefinition("Region entered when a certain count of reactor shutdowns are completed", data2.Region_Objective)); } public static LocationID get_Location_ReactorShutdownReactors_PerObjective(Objective.Data data) { return LocationID.From(data, data.ObjectiveName + " Reactor Shutdown Reactor Locations", (Objective.Data data2) => new TagDefinition("Locations checked by finding a reactor shutdown reactor for a particular objective", get_Location_ReactorShutdownReactors(data2))); } public static ItemID get_Item_ReactorShutdownReactors_PerObjective(Objective.Data data) { return ItemID.From(data, data.ObjectiveName + " Reactor Shutdown Reactor Items", (Objective.Data data2) => new TagDefinition("Items representing a reactor used for a particular reactor shutdown objective", get_Item_ReactorShutdownReactors(data2))); } public static LocationID Location_ReactorShutdownReactor_Instance(this Objective.Data data, int count) { return LocationID.From(data, $"{data.ObjectiveName} Reactor Shutdown Reactor Locations #{count}", (Objective.Data data2) => new TagDefinition("A particular reactor shutdown reactor location", get_Location_ReactorShutdownReactors_PerObjective(data2))); } public static ItemID Item_ReactorShutdownReactor_Instance(this Objective.Data data, int count) { return ItemID.From(data, $"{data.ObjectiveName} Reactor Shutdown Reactor Items #{count}", (Objective.Data data2) => new TagDefinition("A particular reactor shutdown reactor", get_Item_ReactorShutdownReactors_PerObjective(data2)), new ReactorShutdownHandler.ReactorShutdownReactorItem(data.Region_Objective, count)); } } [EnableFeatureByDefault] [AutomatedFeature] public class ReactorShutdownHandler : ArchipelagoFeature { private static class This { public const eWardenObjectiveType ObjectiveType = (eWardenObjectiveType)2; public static string ObjectiveSummary(Objective.Data data) { CheckIsCorrectObjective(data); return "Reactor Shutdown"; } public static bool IsCorrectObjective(Objective.Data data) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Invalid comparison between Unknown and I4 return (int)data.Objective.Type == 2; } public static void CheckIsCorrectObjective(Objective.Data data) { //IL_0044: Unknown result type (might be due to invalid IL or missing references) if (!IsCorrectObjective(data)) { FeatureLogger.Error($"Wrong objective type! Expected {Enum.GetName((eWardenObjectiveType)2)}, got {data.Objective.Type}"); } } } public class ReactorShutdownReactorItem : Item { public RegionID ObjectiveRegion { get; private init; } public int Count { get; private init; } public ReactorShutdownReactorItem(RegionID objective, int count) : base(new ItemData { IsProgression = true }) { ObjectiveRegion = objective; Count = count; } } private static IArchiveLogger? m_featureLogger; public override string Name => "Reactor Shutdown Handler"; public override string Description => "Handles the Reactor Shutdown Startup objective type.\nExample: R1D1"; public override FeatureGroup Group => ArchipelagoFeatureGroups.get_ObjectiveHandlers(); public new static IArchiveLogger FeatureLogger { get { return m_featureLogger ?? (m_featureLogger = Plugin.Get().Logger); } set { m_featureLogger = value; } } [Objective.Callback] public void HandleReactorShutdownObjective(Objective.Data data) { if (!This.IsCorrectObjective(data)) { return; } int count = 0; foreach (ZonePlacementData item in data.ObjectiveData.ZonePlacementDatas.SelectMany((List ps) => ps.Iter())) { Zone.Data data2 = data.FindZoneByPlacement(item); if (data2 == null) { FeatureLogger.Error("Failed to find reactor zone by placement: " + data.ObjectiveName); } else { addReactor(data2); } } if (count == 0) { foreach (Zone.Data item2 in Zone.get_AllZones(data)) { string? customGeo = item2.CustomGeo; if (customGeo != null && customGeo.Contains("_reactor_", StringComparison.OrdinalIgnoreCase)) { FeatureLogger.Debug("Using geomorph for reactor objective: " + data.ObjectiveName); addReactor(item2); break; } } if (count == 0) { FeatureLogger.Error("No reactor placements: " + data.ObjectiveName); } } if (!data.Objective.OnActivateOnSolveItem) { data.Objective.OnActivateOnSolveItem = true; data.Objective.EventsOnActivate?.Clear(); } ItemID target = ReactorShutdownHandler_Tags.get_Item_ReactorShutdownReactors_PerObjective(data); Event.Wrapper wrapper = data.MakeOrWrapOnSolveEvents(); count = 0; while (!wrapper.IsDone) { int num = count + 1; count = num; RegionID regionID = data.Region_CompletedShutdown(count); data.AddPath(new ReTFO.Archipelago.ModdedInstanceData.Model.Path { StartingRegion = data.Region_Objective, EndingRegion = regionID, Reqs = new ReTFO.Archipelago.ModdedInstanceData.Model.Path.MultiPathReq(ReTFO.Archipelago.ModdedInstanceData.Model.Path.eType.Category, target, (uint)count) }); wrapper.Process(regionID); } if (!data.Objective.DoNotSolveObjectiveOnReactorComplete) { SharedObjectiveHandler.AddObjectiveCompleteItem(data, data.Region_CompletedShutdown(1)); } void addReactor(Zone.Data zone) { int num2 = count + 1; count = num2; data.Locations.CreateValue(data.Location_ReactorShutdownReactor_Instance(count), zone.Region_Zone, new LocationData { IsAutoDiscovered = true }, data.Item_ReactorShutdownReactor_Instance(count)); } } } public static class GatherSmallItemsHandler_Tags { [SpecialName] public sealed class $2B8804A94F2EF68DF77A343A46EE5A78 { [SpecialName] public static class $55FD246F9BFF39DD56FCB5C25D4DF852 { } [ExtensionMarker("$55FD246F9BFF39DD56FCB5C25D4DF852")] public LocationID Location_GatherItems { [ExtensionMarker("$55FD246F9BFF39DD56FCB5C25D4DF852")] get { throw new NotSupportedException(); } } [ExtensionMarker("$55FD246F9BFF39DD56FCB5C25D4DF852")] public ItemID Item_GatherItems { [ExtensionMarker("$55FD246F9BFF39DD56FCB5C25D4DF852")] get { throw new NotSupportedException(); } } } [SpecialName] public sealed class $E93D81478905A37B27DF6F640623743D { [SpecialName] public static class $66441969E171E5CA8C86F896EE40E940 { } [ExtensionMarker("$66441969E171E5CA8C86F896EE40E940")] public LocationID Location_GatherItems_PerObjective { [ExtensionMarker("$66441969E171E5CA8C86F896EE40E940")] get { throw new NotSupportedException(); } } [ExtensionMarker("$66441969E171E5CA8C86F896EE40E940")] public ItemID Item_GatherItems_PerObjective { [ExtensionMarker("$66441969E171E5CA8C86F896EE40E940")] get { throw new NotSupportedException(); } } [ExtensionMarker("$66441969E171E5CA8C86F896EE40E940")] public RegionID Region_GatheredItems(int count) { throw new NotSupportedException(); } [ExtensionMarker("$66441969E171E5CA8C86F896EE40E940")] public LocationID Location_GatherItems_Instance(int count) { throw new NotSupportedException(); } [ExtensionMarker("$66441969E171E5CA8C86F896EE40E940")] public ItemID Item_GatherItems_Instance(int count) { throw new NotSupportedException(); } } public static LocationID get_Location_GatherItems(Game.Data data) { return LocationID.From(data, "Small Objective Items Spawn Locations", (Game.Data gameData) => new TagDefinition("Locations checked by picking up small objective items (for example, PIDs)", PickupHelper_Tags.get_Location_SmallPickups(gameData))); } public static ItemID get_Item_GatherItems(Game.Data data) { return ItemID.From(data, "Small Objective Items", (Game.Data gameData) => new TagDefinition("Items granting progress toward a \"Gather Small Items\" objective", PickupHelper_Tags.get_Item_SmallPickups(gameData))); } public static Objective.Data Checked(Objective.Data data) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Invalid comparison between Unknown and I4 //IL_0024: Unknown result type (might be due to invalid IL or missing references) if ((int)data.Objective.Type != 3) { FeatureLogger.Warning("Fetched an ID for the wrong objective type. Desired: " + Enum.GetName((eWardenObjectiveType)3) + ", actual: " + Enum.GetName(data.Objective.Type)); } return data; } public static RegionID Region_GatheredItems(this Objective.Data data, int count) { return RegionID.From(Checked(data), $"{data.ObjectiveName} Found {count} Items", (Objective.Data data2) => new TagDefinition("Region enetered when a certain number of small objective items are found", data2.Region_Objective)); } public static LocationID get_Location_GatherItems_PerObjective(Objective.Data data) { return LocationID.From(Checked(data), data.ObjectiveName + " Small Objective Locations", (Objective.Data data2) => new TagDefinition("Gather Items locations for a particular objective", get_Location_GatherItems(data2))); } public static ItemID get_Item_GatherItems_PerObjective(Objective.Data data) { return ItemID.From(Checked(data), data.ObjectiveName + " Small Objective Items", (Objective.Data data2) => new TagDefinition("Items granting progress toward a particular objective", get_Item_GatherItems(data2))); } public static LocationID Location_GatherItems_Instance(this Objective.Data data, int count) { return LocationID.From(Checked(data), $"{data.ObjectiveName} Small Objective Location #{count}", (Objective.Data data2) => new TagDefinition("A particular Gather Items locations", get_Location_GatherItems_PerObjective(data2))); } public static ItemID Item_GatherItems_Instance(this Objective.Data data, int count) { return ItemID.From(Checked(data), $"{data.ObjectiveName} Small Objective Item #{count}", (Objective.Data data2) => new TagDefinition("A particular Gather Items item", get_Item_GatherItems_PerObjective(data2)), new GatherSmallItemsHandler.GatherSmall_Item(data.Region_Objective, count)); } } [EnableFeatureByDefault] [AutomatedFeature] [InjectToIl2Cpp] public class GatherSmallItemsHandler : ArchipelagoFeature { public class GatherSmall_Item : TerminalItem { public RegionID ObjectiveRegion { get; private init; } public int Count { get; private init; } public override RegionID TargetRegion => ObjectiveRegion; public GatherSmall_Item(RegionID objective, int count) : base(new ItemData { IsProgression = true }) { ObjectiveRegion = objective; Count = count; } public override void OnEnteredExpedition(StateTracker stateTracker, LocationID sourceLocationId, PlayerAgent? player, ItemID itemId) { Objective.Data data = new Objective.Data(stateTracker.GameData, ObjectiveRegion); List placements; uint num = CalcEmptySpots(data, out placements); if (Count > num) { base.OnEnteredExpedition(stateTracker, sourceLocationId, player, itemId); } } public override IEnumerable OnRetrieveFromTerminalSystem(StateTracker stateTracker, LG_ComputerTerminal terminal, ItemID itemId) { AsyncItemSpawnWrapper wrapper = new AsyncItemSpawnWrapper(); Objective.Data data = new Objective.Data(stateTracker.GameData, ObjectiveRegion); pItemData val = new pItemData { itemID_gearCRC = data.Objective.Gather_ItemId, originCourseNode = default(pCourseNode), originLayer = data.LayerType }; ((pCourseNode)(ref val.originCourseNode)).Set(data.GetLG_Layer().m_zones[0].m_courseNodes[0]); if (SNet.IsMaster) { ItemReplicationManager.SpawnItem(val, delItemCallback.op_Implicit((Action)wrapper.OnSpawn), (ItemMode)2, Vector3.zero, Quaternion.identity, (AIG_CourseNode)null, (PlayerAgent)null); } SNet_Player player = terminal.m_syncedInteractionSource.Owner; yield return delegate { terminal.AddLine((TerminalLineType)2, "Retrieving your small pickup...", 2f); }; yield return delegate { //IL_00a3: 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_00ac: Unknown result type (might be due to invalid IL or missing references) //IL_00b2: 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_00bb: Unknown result type (might be due to invalid IL or missing references) ISyncedItem? item = wrapper.Item; GenericSmallPickupItem_Core val2 = ((item != null) ? ((Il2CppObjectBase)item).TryCast() : null); if ((Object)(object)val2 == (Object)null) { if (SNet.IsMaster) { stateTracker.AddItemToTerminal(itemId); FeatureLogger.Error("Failed to spawn small pickup!"); terminal.AddLine("<#F00>Failed to retrieve small pickup! It has been re-added to terminal system.", true); wrapper.QueueDespawn(); } } else { val2.SetupFromLevelgen(0, true); val2._SpawnNode_k__BackingField = data.GetLG_Layer().m_zones[0].m_courseNodes[0]; val2.m_sync.AttemptPickupInteraction((ePickupItemInteractionType)0, player, default(pItemData_Custom), default(Vector3), default(Quaternion), (AIG_CourseNode)null, false, false); terminal.AddLine("Pickup \"" + ((Item)val2).PublicName + "\" has been given to " + player.NickName, true); } }; } } private class ZonePlacementEqualityComparer : IEqualityComparer { public bool Equals(ZonePlacementData? x, ZonePlacementData? y) { //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0067: 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_0090: 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) if (((x != null) ? new eLocalZoneIndex?(x.LocalIndex) : ((eLocalZoneIndex?)null)) == ((y != null) ? new eLocalZoneIndex?(y.LocalIndex) : ((eLocalZoneIndex?)null))) { return ((x != null) ? new eDimensionIndex?(x.DimensionIndex) : ((eDimensionIndex?)null)) == ((y != null) ? new eDimensionIndex?(y.DimensionIndex) : ((eDimensionIndex?)null)); } return false; } public int GetHashCode(ZonePlacementData obj) { //IL_0001: 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) return (obj.LocalIndex, obj.DimensionIndex).GetHashCode(); } } [InjectToIl2Cpp] private class GatherSmall_FreeLcoationsComp : MonoBehaviour { public List LocationIDs = new List(0); public GatherSmall_FreeLcoationsComp(IntPtr ptr) : base(ptr) { } } [ArchivePatch(/*Could not decode attribute arguments.*/)] public static class LG_Distribute_WardenObjective__BuildWardenObjective__Patch { public static void Postfix(LG_Distribute_WardenObjective __instance, int chainIndex) { //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Invalid comparison between Unknown and I4 //IL_01e0: Unknown result type (might be due to invalid IL or missing references) //IL_01e7: Expected O, but got Unknown Objective.Data data = Layer.Data.GetFromLayer(__instance.m_layer).GetObjectiveDatas().ElementAt(chainIndex); if ((int)data.Objective.Type != 3) { return; } Dictionary dictionary = new Dictionary(); int num = 0; CalcEmptySpots(data, out List placements); foreach (ZonePlacementData item in placements) { LG_Zone lG_Zone = data.FindZoneByPlacement(item).GetLG_Zone(); dictionary.Add(((Il2CppObjectBase)lG_Zone).Pointer, (num++, 0)); } int gather_MaxPerZone = __instance.m_dataBlockData.Gather_MaxPerZone; int num2 = placements.Count * gather_MaxPerZone; int gather_SpawnCount = __instance.m_dataBlockData.Gather_SpawnCount; Queue jobQueue = LG_Factory.Current.m_currentBatch.Jobs; int start = jobQueue._head + jobQueue._size - gather_SpawnCount; IEnumerable enumerable = from i in Enumerable.Range(start, gather_SpawnCount) select jobQueue._array[i]; foreach (LG_FactoryJob item2 in enumerable) { LG_Distribute_PickupItemsPerZone val = ((Il2CppObjectBase)item2).Cast(); (int, int) tuple = dictionary[((Il2CppObjectBase)val.m_zone).Pointer]; tuple = (dictionary[((Il2CppObjectBase)val.m_zone).Pointer] = (tuple.Item1, tuple.Item2 + 1)); num = ((tuple.Item2 <= gather_MaxPerZone) ? (tuple.Item1 * gather_MaxPerZone + tuple.Item2) : (++num2)); PickupHelper.AssociateDistributionWithLocation(val, data.Location_GatherItems_Instance(num)); } foreach (KeyValuePair item3 in dictionary) { if (item3.Value.Item2 < gather_MaxPerZone) { LG_Zone val2 = new LG_Zone(item3.Key); num = item3.Value.Item2; GatherSmall_FreeLcoationsComp gatherSmall_FreeLcoationsComp = ((Component)val2).gameObject.AddComponent(); gatherSmall_FreeLcoationsComp.LocationIDs = new List(gather_MaxPerZone - num); while (num++ < gather_MaxPerZone) { gatherSmall_FreeLcoationsComp.LocationIDs.Add(data.Location_GatherItems_Instance(item3.Value.Item1 * gather_MaxPerZone + num)); } } } } } [ArchivePatch(/*Could not decode attribute arguments.*/)] public static class PlayerAgent__SetCourseNode__Patch { public static void Prefix(PlayerAgent __instance, AIG_CourseNode courseNode) { IntPtr? obj; if (__instance == null) { obj = null; } else { AIG_CourseNode courseNode2 = ((Agent)__instance).CourseNode; if (courseNode2 == null) { obj = null; } else { LG_Zone zone = courseNode2.m_zone; obj = ((zone != null) ? new IntPtr?(((Il2CppObjectBase)zone).Pointer) : ((IntPtr?)null)); } } IntPtr intPtr = obj ?? IntPtr.Zero; IntPtr? obj2; if (courseNode == null) { obj2 = null; } else { LG_Zone zone2 = courseNode.m_zone; obj2 = ((zone2 != null) ? new IntPtr?(((Il2CppObjectBase)zone2).Pointer) : ((IntPtr?)null)); } if (intPtr != (obj2 ?? IntPtr.Zero)) { object obj3; if (courseNode == null) { obj3 = null; } else { LG_Zone zone3 = courseNode.m_zone; obj3 = ((zone3 != null) ? ((Component)zone3).GetComponent() : null); } GatherSmall_FreeLcoationsComp gatherSmall_FreeLcoationsComp = (GatherSmall_FreeLcoationsComp)obj3; if ((Object)(object)gatherSmall_FreeLcoationsComp != (Object)null) { StateTracker.Get().NotifyFoundLocations(gatherSmall_FreeLcoationsComp.LocationIDs, __instance); Object.Destroy((Object)(object)gatherSmall_FreeLcoationsComp); } } } } private static IArchiveLogger? m_featureLogger; public override string Name => "Gather Small Pickups Handler"; public override string Description => "Handles the GatherSmallItems objective type.\nExample: R1B1"; public override FeatureGroup Group => ArchipelagoFeatureGroups.get_ObjectiveHandlers(); public new static IArchiveLogger FeatureLogger { get { return m_featureLogger ?? (m_featureLogger = Plugin.Get().Logger); } set { m_featureLogger = value; } } public static uint CalcEmptySpots(Objective.Data data, out List placements) { //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Expected O, but got Unknown if (data.ObjectiveData.ZonePlacementDatas.Count == 0) { placements = new List(1) { new ZonePlacementData() }; } else { placements = data.ObjectiveData.ZonePlacementDatas.SelectMany((List ps) => ps.Iter()).Distinct(new ZonePlacementEqualityComparer()).ToList(); } if (data.Objective.Gather_MaxPerZone <= 0) { throw new ArgumentException($"{data.ObjectiveName}: Expected positive MaxPerZone, got {data.Objective.Gather_MaxPerZone}"); } int num = placements.Count * data.Objective.Gather_MaxPerZone; int num2 = num - data.Objective.Gather_SpawnCount; if (num2 < 0) { num2 = 0; } return (uint)num2; } [Objective.Callback] public void HandleGatherSmallItemsObjective(Objective.Data data) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Invalid comparison between Unknown and I4 if ((int)data.Objective.Type != 3) { return; } List placements; uint num = CalcEmptySpots(data, out placements); int num2 = 0; foreach (ZonePlacementData item in placements) { RegionID region_Zone = data.FindZoneByPlacement(item).Region_Zone; for (int i = 0; i < data.Objective.Gather_MaxPerZone; i++) { num2++; data.Locations.CreateValue(data.Location_GatherItems_Instance(num2), region_Zone, default(LocationData), data.Item_GatherItems_Instance(num2)); } } if (num2 < data.Objective.Gather_SpawnCount) { RegionList owningRegions = (from info in ((Layer.Data)data).PlacementsToZoneRegions((IEnumerable)placements) select info.Region).ToList(); while (num2 < data.Objective.Gather_SpawnCount) { num2++; data.Locations.CreateValue(data.Location_GatherItems_Instance(num2), owningRegions, default(LocationData), data.Item_GatherItems_Instance(num2)); } } RegionID regionID = data.Region_GatheredItems(0); ItemID target = GatherSmallItemsHandler_Tags.get_Item_GatherItems_PerObjective(data); data.AddPath(new ReTFO.Archipelago.ModdedInstanceData.Model.Path { StartingRegion = data.Region_Objective, EndingRegion = regionID, Reqs = ((num == 0) ? new ReTFO.Archipelago.ModdedInstanceData.Model.Path.MultiPathReq() : new ReTFO.Archipelago.ModdedInstanceData.Model.Path.MultiPathReq(ReTFO.Archipelago.ModdedInstanceData.Model.Path.eType.Category, target, num)) }); Event.Wrapper wrapper = data.MakeOrWrapOnSolveEvents(); RegionID startingRegion = regionID; for (int num3 = 1; num3 <= data.Objective.Gather_SpawnCount; num3++) { regionID = data.Region_GatheredItems(num3); data.AddPath(new ReTFO.Archipelago.ModdedInstanceData.Model.Path { StartingRegion = startingRegion, EndingRegion = regionID, Reqs = new ReTFO.Archipelago.ModdedInstanceData.Model.Path.MultiPathReq(ReTFO.Archipelago.ModdedInstanceData.Model.Path.eType.Category, target, num + (uint)num3) }); startingRegion = regionID; if (num3 == data.Objective.Gather_RequiredCount) { SharedObjectiveHandler.AddObjectiveCompleteItem(data, regionID); } wrapper.Process(regionID, extendIfNecessary: true); } } } public static class ClearAPathHandler_Tags { [SpecialName] public sealed class $E93D81478905A37B27DF6F640623743D { [SpecialName] public static class $66441969E171E5CA8C86F896EE40E940 { } [ExtensionMarker("$66441969E171E5CA8C86F896EE40E940")] public RegionID Region_PathCleared { [ExtensionMarker("$66441969E171E5CA8C86F896EE40E940")] get { throw new NotSupportedException(); } } } public static Objective.Data Checked(Objective.Data data) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Invalid comparison between Unknown and I4 //IL_0024: Unknown result type (might be due to invalid IL or missing references) if ((int)data.Objective.Type != 4) { FeatureLogger.Warning("Fetched an ID for the wrong objective type. Desired: " + Enum.GetName((eWardenObjectiveType)4) + ", actual: " + Enum.GetName(data.Objective.Type)); } return data; } public static RegionID get_Region_PathCleared(Objective.Data data) { return RegionID.From(Checked(data), data.ObjectiveName + " Path Cleared", (Objective.Data data2) => new TagDefinition("Region entered when extraction is reached for the ClearAPath objective type", data2.Region_Objective)); } } [EnableFeatureByDefault] [AutomatedFeature] public class ClearAPathHandler : ArchipelagoFeature { private static class ThisRegions { public static string PathCleared(Objective.Data data) { return data.ObjectiveName + " Path Cleared"; } } private static IArchiveLogger? m_featureLogger; public override string Name => "Clear a Path Handler"; public override string Description => "Handles the ClearAPath objective type.\nExample: R2B1"; public override FeatureGroup Group => ArchipelagoFeatureGroups.get_ObjectiveHandlers(); public new static IArchiveLogger FeatureLogger { get { return m_featureLogger ?? (m_featureLogger = Plugin.Get().Logger); } set { m_featureLogger = value; } } [Objective.Callback] public void HandleClearAPathObjective(Objective.Data data) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Invalid comparison between Unknown and I4 if ((int)data.Objective.Type == 4) { RegionID regionID = ClearAPathHandler_Tags.get_Region_PathCleared(data); data.AddPath(new ReTFO.Archipelago.ModdedInstanceData.Model.Path { StartingRegion = data.Region_Objective, EndingRegion = regionID, Reqs = new ReTFO.Archipelago.ModdedInstanceData.Model.Path.MultiPathReq(ReTFO.Archipelago.ModdedInstanceData.Model.Path.eType.Item, ExtractionHandler_Tags.get_Item_Extraction_Instance(data), 1u) }); SharedObjectiveHandler.AddObjectiveCompleteItem(data, regionID); } } } public static class SpecialTerminalCommandHandler_Tags { [SpecialName] public sealed class $2B8804A94F2EF68DF77A343A46EE5A78 { [SpecialName] public static class $55FD246F9BFF39DD56FCB5C25D4DF852 { } [ExtensionMarker("$55FD246F9BFF39DD56FCB5C25D4DF852")] public LocationID Location_SpecialCommands { [ExtensionMarker("$55FD246F9BFF39DD56FCB5C25D4DF852")] get { throw new NotSupportedException(); } } [ExtensionMarker("$55FD246F9BFF39DD56FCB5C25D4DF852")] public ItemID Item_SpecialCommands { [ExtensionMarker("$55FD246F9BFF39DD56FCB5C25D4DF852")] get { throw new NotSupportedException(); } } } [SpecialName] public sealed class $E93D81478905A37B27DF6F640623743D { [SpecialName] public static class $66441969E171E5CA8C86F896EE40E940 { } [ExtensionMarker("$66441969E171E5CA8C86F896EE40E940")] public RegionID Region_SpecialCommandExecuted { [ExtensionMarker("$66441969E171E5CA8C86F896EE40E940")] get { throw new NotSupportedException(); } } [ExtensionMarker("$66441969E171E5CA8C86F896EE40E940")] public LocationID Location_SpecialCommand_Instance { [ExtensionMarker("$66441969E171E5CA8C86F896EE40E940")] get { throw new NotSupportedException(); } } [ExtensionMarker("$66441969E171E5CA8C86F896EE40E940")] public ItemID Item_SpecialCommand_Instance { [ExtensionMarker("$66441969E171E5CA8C86F896EE40E940")] get { throw new NotSupportedException(); } } } public static LocationID get_Location_SpecialCommands(Game.Data data) { return LocationID.From(data, "Special Command Locations", (Game.Data data2) => new TagDefinition("Locations checked by executing special command objectives' commands", CommonTagsHandler_Tags.get_Location_Never(data2))); } public static ItemID get_Item_SpecialCommands(Game.Data data) { return ItemID.From(data, "Special Command Items", (Game.Data data2) => new TagDefinition("Items awarded for executing special command objectives' commands", CommonTagsHandler_Tags.get_Item_Never(data2))); } public static Objective.Data Checked(Objective.Data data) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Invalid comparison between Unknown and I4 //IL_0024: Unknown result type (might be due to invalid IL or missing references) if ((int)data.Objective.Type != 5) { FeatureLogger.Warning("Fetched an ID for the wrong objective type. Desired: " + Enum.GetName((eWardenObjectiveType)5) + ", actual: " + Enum.GetName(data.Objective.Type)); } return data; } public static RegionID get_Region_SpecialCommandExecuted(Objective.Data data) { return RegionID.From(data, data.ObjectiveName + " Command Executed", (Objective.Data data2) => new TagDefinition("Region entered by executing the objective's special command", data2.Region_Objective)); } public static LocationID get_Location_SpecialCommand_Instance(Objective.Data data) { return LocationID.From(data, data.ObjectiveName + " Special Command Location", (Objective.Data data2) => new TagDefinition("A special command location for a particular objective", get_Location_SpecialCommands(data2))); } public static ItemID get_Item_SpecialCommand_Instance(Objective.Data data) { return ItemID.From(data, data.ObjectiveName + " Special Command Item", (Objective.Data data2) => new TagDefinition("A special command item for a particular objective", get_Item_SpecialCommands(data2)), new SpecialTerminalCommandHandler.STCItem(data.Region_Objective)); } } [EnableFeatureByDefault] [AutomatedFeature] public class SpecialTerminalCommandHandler : ArchipelagoFeature { public class STCItem : Item { public RegionID ObjectiveRegion { get; private init; } public STCItem(RegionID objective) : base(new ItemData { IsProgression = true }) { ObjectiveRegion = objective; } } private static IArchiveLogger? m_featureLogger; public override string Name => "Special Terminal Command Handler"; public override string Description => "Handles the SpecialTerminalCommand objective type.\nThis objective type refers only to when you need to enter a single special command.\nExamples: R5A1 Main, R8E1 secondary"; public override FeatureGroup Group => ArchipelagoFeatureGroups.get_ObjectiveHandlers(); public new static IArchiveLogger FeatureLogger { get { return m_featureLogger ?? (m_featureLogger = Plugin.Get().Logger); } set { m_featureLogger = value; } } [Objective.Callback] public void HandleSpecialTerminalCommandObjective(Objective.Data data) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Invalid comparison between Unknown and I4 //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Expected O, but got Unknown if ((int)data.Objective.Type == 5) { IEnumerable placements = data.ObjectiveData.ZonePlacementDatas.FirstOrDefault>()?.Iter() ?? Enumerable.Repeat(new ZonePlacementData(), 1); IEnumerable source = from info in data.PlacementsToTerminalRegions(placements) select info.Region; ItemID itemID = SpecialTerminalCommandHandler_Tags.get_Item_SpecialCommand_Instance(data); data.Locations.CreateValue(SpecialTerminalCommandHandler_Tags.get_Location_SpecialCommand_Instance(data), source.ToArray(), new LocationData { IsAutoDiscovered = true }, itemID); RegionID regionID = SpecialTerminalCommandHandler_Tags.get_Region_SpecialCommandExecuted(data); data.AddPath(new ReTFO.Archipelago.ModdedInstanceData.Model.Path { StartingRegion = data.Region_Objective, EndingRegion = regionID, Reqs = new ReTFO.Archipelago.ModdedInstanceData.Model.Path.MultiPathReq(ReTFO.Archipelago.ModdedInstanceData.Model.Path.eType.Item, itemID, 1u) }); Event.Wrapper wrapper = data.WrapOnActivateEvents(); wrapper.Process(regionID); SharedObjectiveHandler.AddObjectiveCompleteItem(data, regionID); } } } public static class RetrieveBigItemsHandler_Tags { [SpecialName] public sealed class $2B8804A94F2EF68DF77A343A46EE5A78 { [SpecialName] public static class $55FD246F9BFF39DD56FCB5C25D4DF852 { } [ExtensionMarker("$55FD246F9BFF39DD56FCB5C25D4DF852")] public LocationID Location_BigRetrievals { [ExtensionMarker("$55FD246F9BFF39DD56FCB5C25D4DF852")] get { throw new NotSupportedException(); } } [ExtensionMarker("$55FD246F9BFF39DD56FCB5C25D4DF852")] public ItemID Item_BigRetrievals { [ExtensionMarker("$55FD246F9BFF39DD56FCB5C25D4DF852")] get { throw new NotSupportedException(); } } } [SpecialName] public sealed class $E93D81478905A37B27DF6F640623743D { [SpecialName] public static class $66441969E171E5CA8C86F896EE40E940 { } [ExtensionMarker("$66441969E171E5CA8C86F896EE40E940")] public LocationID Location_BigRetrievals_ByObjective { [ExtensionMarker("$66441969E171E5CA8C86F896EE40E940")] get { throw new NotSupportedException(); } } [ExtensionMarker("$66441969E171E5CA8C86F896EE40E940")] public ItemID Item_BigRetrievals_ByObjective { [ExtensionMarker("$66441969E171E5CA8C86F896EE40E940")] get { throw new NotSupportedException(); } } [ExtensionMarker("$66441969E171E5CA8C86F896EE40E940")] public RegionID Region_RetrievedItem(int count) { throw new NotSupportedException(); } [ExtensionMarker("$66441969E171E5CA8C86F896EE40E940")] public LocationID Location_BigRetrieval_Instance(int count) { throw new NotSupportedException(); } [ExtensionMarker("$66441969E171E5CA8C86F896EE40E940")] public ItemID Item_BigRetrieval_Instance(int count) { throw new NotSupportedException(); } } public static LocationID get_Location_BigRetrievals(Game.Data data) { return LocationID.From(data, "Big Retrieval Locations", (Game.Data gameData) => new TagDefinition("Locations checked by picking up big retrieval objective items, IE in R2A1", PickupHelper_Tags.get_Location_BigPickups(gameData))); } public static ItemID get_Item_BigRetrievals(Game.Data data) { return ItemID.From(data, "Big Retrieval Items", (Game.Data gameData) => new TagDefinition("Big pickup items marked as retrieval objective items, IE the cargos in R2A1", PickupHelper_Tags.get_Item_BigPickups(gameData))); } public static Objective.Data Checked(Objective.Data data) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Invalid comparison between Unknown and I4 //IL_0024: Unknown result type (might be due to invalid IL or missing references) if ((int)data.Objective.Type != 6) { FeatureLogger.Warning("Fetched an ID for the wrong objective type. Desired: " + Enum.GetName((eWardenObjectiveType)6) + ", actual: " + Enum.GetName(data.Objective.Type)); } return data; } public static RegionID Region_RetrievedItem(this Objective.Data data, int count) { return RegionID.From(Checked(data), $"{data.ObjectiveName} {count} Big Items Retrieved", (Objective.Data data2) => new TagDefinition("Region entered when a particular big objective item is retrieved (picked up)", data2.Region_Objective)); } public static LocationID get_Location_BigRetrievals_ByObjective(Objective.Data data) { return LocationID.From(Checked(data), data.ObjectiveName + " Big Retrieval Locations", (Objective.Data data2) => new TagDefinition("Locations checked by picking up big retrieval items for a particular objective", get_Location_BigRetrievals(data2))); } public static ItemID get_Item_BigRetrievals_ByObjective(Objective.Data data) { return ItemID.From(Checked(data), data.ObjectiveName + " Big Retrieval Items", (Objective.Data data2) => new TagDefinition("Big pickup items marked as big retrieval items for a particular objective", get_Item_BigRetrievals(data2))); } public static LocationID Location_BigRetrieval_Instance(this Objective.Data data, int count) { return LocationID.From(Checked(data), $"{data.ObjectiveName} Big Retrieval Location #{count}", (Objective.Data data2) => new TagDefinition("A particular big retrieval item's location", get_Location_BigRetrievals_ByObjective(data2))); } public static ItemID Item_BigRetrieval_Instance(this Objective.Data data, int count) { return ItemID.From(Checked(data), $"{data.ObjectiveName} Big Retrieval Item #{count}", (Objective.Data data2) => new TagDefinition("A particular big retrieval item", get_Item_BigRetrievals_ByObjective(data2)), new RetrieveBigItemsHandler.BigRetrieval_Item(data, count)); } } [EnableFeatureByDefault] [AutomatedFeature] public class RetrieveBigItemsHandler : ArchipelagoFeature { public class BigRetrieval_Item : BigPickupHandler.BigPickupItem { public RegionID ObjectiveRegion { get; private init; } public int ItemIndex { get; private init; } public override RegionID TargetRegion => ObjectiveRegion; public BigRetrieval_Item(Objective.Data objective, int count) : base(objective.Region_Expedition, GameDataBlockBase.GetBlock(objective.Objective.Retrieve_Items[count - 1])) { ObjectiveRegion = objective.Region_Objective; ItemIndex = count - 1; } protected override AsyncItemSpawnWrapper TrySpawnAsync() { AsyncItemSpawnWrapper asyncItemSpawnWrapper = base.TrySpawnAsync(); asyncItemSpawnWrapper.AddSpawnCallback(SetupObjectiveCarryItem); return asyncItemSpawnWrapper; void SetupObjectiveCarryItem(ISyncedItem item) { //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_0074: 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) //IL_008e: Unknown result type (might be due to invalid IL or missing references) Objective.Data data = new Objective.Data(StateTracker.Get().GameData, ObjectiveRegion); CarryItemPickup_Core val = ((Il2CppObjectBase)item).Cast(); val.SpawnNode = data.GetLG_Layer().m_zones[0].m_courseNodes[0]; ((Item)val).Set_pItemData(new pItemData { itemID_gearCRC = ((Item)val).pItemData.itemID_gearCRC, originLayer = data.LayerType }); val.m_isWardenObjective = true; List items = WardenObjectiveManager.GetObjectiveItemCollection((LG_LayerType)data.LayerType, data.ObjectiveIndex); CP_Bioscan_Core val2 = ((WardenObjectiveManager.m_customGeoExitWinConditionItem == null) ? ((Il2CppObjectBase)((Il2CppArrayBase)(object)((Il2CppObjectBase)WardenObjectiveManager.m_elevatorExitWinConditionItem).Cast().m_puzzle.m_chainedPuzzleCores)[0]).TryCast() : ((Il2CppObjectBase)((Il2CppArrayBase)(object)((Il2CppObjectBase)WardenObjectiveManager.m_customGeoExitWinConditionItem).Cast().m_puzzle.m_chainedPuzzleCores)[0]).TryCast()); if ((Object)(object)val2 != (Object)null && val2.m_reqItems.Any((iWardenObjectiveItem i) => ((Il2CppObjectBase)i).Pointer == ((Il2CppObjectBase)items[ItemIndex]).Pointer)) { Il2CppReferenceArray val3 = new Il2CppReferenceArray(1L) { [0] = items[ItemIndex] }; Il2CppReferenceArray val4 = new Il2CppReferenceArray(1L) { [0] = ((Il2CppObjectBase)val).Cast() }; WardenObjectiveManager.RemoveObjectiveItemAsRequiredForExitScan(val3); WardenObjectiveManager.AddObjectiveItemAsRequiredForExitScan(true, val4); } val.IsRegistered = items[ItemIndex].IsRegistered; val.ObjectiveItemSolved = items[ItemIndex].ObjectiveItemSolved; val.ObjectiveItemSolvedHasBeenHandled = items[ItemIndex].ObjectiveItemSolvedHasBeenHandled; val.WardenObjectiveChainIndex = items[ItemIndex].WardenObjectiveChainIndex; items[ItemIndex] = ((Il2CppObjectBase)val).Cast(); } } } [ArchivePatch(/*Could not decode attribute arguments.*/)] public static class LG_Distribute_WardenObjective____c__DisplayClass8_1___DistributePickupItems_b__0__Patch { public static void Postfix(__c__DisplayClass8_1 __instance, LG_Zone zone) { //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Invalid comparison between Unknown and I4 Objective.Data data = Layer.Data.GetFromLayerFlattened(zone.Layer).GetObjectiveDatas().ElementAt(__instance.field_Public___c__DisplayClass8_0_0.chainIndex); if ((int)data.Objective.Type == 6) { PickupHelper.AssociateDistributionWithLocation(((Il2CppObjectBase)LG_Factory.Current.m_currentBatch.Jobs.FromEnd()).Cast(), data.Location_BigRetrieval_Instance(__instance.i + 1)); } } } [ArchivePatch(/*Could not decode attribute arguments.*/)] public static class WardenObjectiveManager__OnStateChange__Patch { public static void Prefix(ref pWardenObjectiveState newState, bool isRecall) { if (isRecall) { for (int i = 0; i < ((Il2CppArrayBase)(object)newState.RequiredObjectiveItems).Length; i++) { ((Il2CppArrayBase)(object)newState.RequiredObjectiveItems)[i] = byte.MaxValue; } } } } private static IArchiveLogger? m_featureLogger; public override string Name => "Retrieve Big Items Handler"; public override string Description => "Handles the RetrieveBigItems objective type.\nExample: R2A1"; public override FeatureGroup Group => ArchipelagoFeatureGroups.get_ObjectiveHandlers(); public new static IArchiveLogger FeatureLogger { get { return m_featureLogger ?? (m_featureLogger = Plugin.Get().Logger); } set { m_featureLogger = value; } } [Objective.Callback] public void HandleRetrieveBigItemsObjective(Objective.Data data) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Invalid comparison between Unknown and I4 if ((int)data.Objective.Type == 6) { List> list = data.ObjectiveToZoneRegionSets(data.Objective.Retrieve_Items.Count).ToList(); Event.Wrapper wrapper = data.MakeOrWrapOnSolveEvents(); ItemID target = RetrieveBigItemsHandler_Tags.get_Item_BigRetrievals_ByObjective(data); RegionID regionID = data.Region_Objective; for (int i = 1; i <= data.Objective.Retrieve_Items.Count; i++) { data.Locations.CreateValue(data.Location_BigRetrieval_Instance(i), list[i - 1], default(LocationData), data.Item_BigRetrieval_Instance(i)); RegionID regionID2 = data.Region_RetrievedItem(i); data.AddPath(new ReTFO.Archipelago.ModdedInstanceData.Model.Path { StartingRegion = regionID, EndingRegion = regionID2, Reqs = new ReTFO.Archipelago.ModdedInstanceData.Model.Path.MultiPathReq(ReTFO.Archipelago.ModdedInstanceData.Model.Path.eType.Category, target, (uint)i) }); regionID = regionID2; wrapper.Process(regionID2); } SharedObjectiveHandler.AddObjectiveCompleteItem(data, regionID); } } } public static class PowerCellDistributionHandler_Tags { [SpecialName] public sealed class $2B8804A94F2EF68DF77A343A46EE5A78 { [SpecialName] public static class $55FD246F9BFF39DD56FCB5C25D4DF852 { } [ExtensionMarker("$55FD246F9BFF39DD56FCB5C25D4DF852")] public LocationID Location_PowerCellDistributionCells { [ExtensionMarker("$55FD246F9BFF39DD56FCB5C25D4DF852")] get { throw new NotSupportedException(); } } [ExtensionMarker("$55FD246F9BFF39DD56FCB5C25D4DF852")] public LocationID Location_PowerCellDistributionGens { [ExtensionMarker("$55FD246F9BFF39DD56FCB5C25D4DF852")] get { throw new NotSupportedException(); } } [ExtensionMarker("$55FD246F9BFF39DD56FCB5C25D4DF852")] public ItemID Item_PowerCellDistributionGens { [ExtensionMarker("$55FD246F9BFF39DD56FCB5C25D4DF852")] get { throw new NotSupportedException(); } } } [SpecialName] public sealed class $E93D81478905A37B27DF6F640623743D { [SpecialName] public static class $66441969E171E5CA8C86F896EE40E940 { } [ExtensionMarker("$66441969E171E5CA8C86F896EE40E940")] public LocationID Location_PowerCellDistributionCells_PerObjective { [ExtensionMarker("$66441969E171E5CA8C86F896EE40E940")] get { throw new NotSupportedException(); } } [ExtensionMarker("$66441969E171E5CA8C86F896EE40E940")] public LocationID Location_PowerCellDistributionGens_PerObjective { [ExtensionMarker("$66441969E171E5CA8C86F896EE40E940")] get { throw new NotSupportedException(); } } [ExtensionMarker("$66441969E171E5CA8C86F896EE40E940")] public ItemID Item_PowerCellDistributionGens_PerObjective { [ExtensionMarker("$66441969E171E5CA8C86F896EE40E940")] get { throw new NotSupportedException(); } } [ExtensionMarker("$66441969E171E5CA8C86F896EE40E940")] public RegionID Region_PowercellDistributionGeneratorPowered(int count) { throw new NotSupportedException(); } [ExtensionMarker("$66441969E171E5CA8C86F896EE40E940")] public LocationID Location_PowerCellDistributionCell_Instance(int count) { throw new NotSupportedException(); } [ExtensionMarker("$66441969E171E5CA8C86F896EE40E940")] public LocationID Location_PowerCellDistributionGen_Instance(int count) { throw new NotSupportedException(); } [ExtensionMarker("$66441969E171E5CA8C86F896EE40E940")] public ItemID Item_PowerCellDistributionGen_Instance(int count) { throw new NotSupportedException(); } } public static LocationID get_Location_PowerCellDistributionCells(Game.Data data) { return LocationID.From(data, "PowerCell Distribution Cell Locations", (Game.Data gameData) => new TagDefinition("Locations checked by picking up cells spawned for the PowerCell Distribution objective (always in the starting lift, if spawned)", PickupHelper_Tags.get_Location_BigPickups(gameData))); } public static LocationID get_Location_PowerCellDistributionGens(Game.Data data) { return LocationID.From(data, "PowerCell Distribution Gen Locations", (Game.Data data2) => new TagDefinition("Locations checked by finding generators for the PowerCell Distribution objective", CommonTagsHandler_Tags.get_Location_Never(data2))); } public static ItemID get_Item_PowerCellDistributionGens(Game.Data data) { return ItemID.From(data, "PowerCell Distribution Gen Items", (Game.Data data2) => new TagDefinition("Items indicating access to a PowerCell Distribution generator", CommonTagsHandler_Tags.get_Item_Never(data2))); } public static Objective.Data Checked(Objective.Data data) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Invalid comparison between Unknown and I4 //IL_0024: Unknown result type (might be due to invalid IL or missing references) if ((int)data.Objective.Type != 7) { FeatureLogger.Warning("Fetched an ID for the wrong objective type. Desired: " + Enum.GetName((eWardenObjectiveType)7) + ", actual: " + Enum.GetName(data.Objective.Type)); } return data; } public static RegionID Region_PowercellDistributionGeneratorPowered(this Objective.Data data, int count) { return RegionID.From(data, $"{data.ObjectiveName} Powered {count} Generators", (Objective.Data data2) => new TagDefinition("Region entered by powering a specific number of cells during a powercell distribution objective", data2.Region_Objective)); } public static LocationID get_Location_PowerCellDistributionCells_PerObjective(Objective.Data data) { return LocationID.From(Checked(data), data.ObjectiveName + " PowerCell Distribution Cell Locations", (Objective.Data data2) => new TagDefinition("Locations checked by picking up cells spawned for a particular objective", get_Location_PowerCellDistributionCells(data2))); } public static LocationID get_Location_PowerCellDistributionGens_PerObjective(Objective.Data data) { return LocationID.From(Checked(data), data.ObjectiveName + " PowerCell Distribution Gen Locations", (Objective.Data data2) => new TagDefinition("Locations checked by finding generators for a particular objective", get_Location_PowerCellDistributionGens(data2))); } public static ItemID get_Item_PowerCellDistributionGens_PerObjective(Objective.Data data) { return ItemID.From(Checked(data), data.ObjectiveName + " PowerCell Distribution Gen Items", (Objective.Data data2) => new TagDefinition("Items indicating access to a PowerCell Distribution generator for a particular objective", get_Item_PowerCellDistributionGens(data2))); } public static LocationID Location_PowerCellDistributionCell_Instance(this Objective.Data data, int count) { return LocationID.From(Checked(data), $"{data.ObjectiveName} PowerCell Distribution Cell Location #{count}", (Objective.Data data2) => new TagDefinition("Locations checked by picking up a particular cell", get_Location_PowerCellDistributionCells_PerObjective(data2))); } public static LocationID Location_PowerCellDistributionGen_Instance(this Objective.Data data, int count) { return LocationID.From(Checked(data), $"{data.ObjectiveName} PowerCell Distribution Gen Location #{count}", (Objective.Data data2) => new TagDefinition("Locations checked by finding a particular generator", get_Location_PowerCellDistributionGens_PerObjective(data2))); } public static ItemID Item_PowerCellDistributionGen_Instance(this Objective.Data data, int count) { return ItemID.From(Checked(data), $"{data.ObjectiveName} PowerCell Distribution Gen #{count}", (Objective.Data data2) => new TagDefinition("Item indicating access to a particular PowerCell Distribution generator", get_Item_PowerCellDistributionGens_PerObjective(data2)), new PowerCellDistributionHandler.PowerCellDistribution_GenItem(data.Region_Objective, count)); } } [EnableFeatureByDefault] [AutomatedFeature] public class PowerCellDistributionHandler : ArchipelagoFeature { public class PowerCellDistribution_GenItem : Item { public RegionID ObjectiveRegion { get; private init; } public int Count { get; private init; } public PowerCellDistribution_GenItem(RegionID objective, int count) : base(new ItemData { IsProgression = true }) { ObjectiveRegion = objective; Count = count; } } [ArchivePatch(/*Could not decode attribute arguments.*/)] public static class LG_Factory__FactoryDone__Patch { public static void Postfix() { //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Invalid comparison between Unknown and I4 Objective.Data data = Layer.get_MainLayer(Expedition.Data.GetFromCurrentExpedition()).GetObjectiveDatas().First(); if ((int)data.Objective.Type != 7) { return; } IEnumerable enumerable = ElevatorCage.Current.m_cargoCage.m_itemsToMoveToCargo.Iter(); if (data.Objective.GenericItemFromStart != 0) { enumerable = enumerable.Skip(1); } int num = 0; foreach (Transform item in enumerable) { CarryItemPickup_Core componentInChildren = ((Component)item).GetComponentInChildren(); if (((GameDataBlockBase)(object)((Item)componentInChildren).ItemDataBlock).persistentID != BigPickupHandler.CellItemID) { FeatureLogger.Warning("Associated a non-cell item with distribution objective starting cell location!"); } PickupHelper.AssociateItem((ItemInLevel)(object)componentInChildren, data.Location_PowerCellDistributionCell_Instance(++num)); } } } private static IArchiveLogger? m_featureLogger; public override string Name => "Powercell Distribution Handler"; public override string Description => "Handles the PowerCellDistribution objective type.\nExample: R2B2"; public override FeatureGroup Group => ArchipelagoFeatureGroups.get_ObjectiveHandlers(); public new static IArchiveLogger FeatureLogger { get { return m_featureLogger ?? (m_featureLogger = Plugin.Get().Logger); } set { m_featureLogger = value; } } [Objective.Callback] public void HandlePowerCellDistributionObjective(Objective.Data data) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Invalid comparison between Unknown and I4 if ((int)data.Objective.Type != 7) { return; } ItemID itemID = BigPickupHandler_Tags.get_Item_BigPickup_Cell(data); if (data.LayerType.IsMainLayer) { RegionID region_Zone = Zone.get_FirstZone(data).Region_Zone; for (int i = 1; i <= data.Objective.PowerCellsToDistribute; i++) { data.Locations.CreateValue(data.Location_PowerCellDistributionCell_Instance(i), region_Zone, default(LocationData), itemID); } } List> list = data.ObjectiveToZoneRegionSets(data.Objective.PowerCellsToDistribute).ToList(); Event.Wrapper wrapper = data.MakeOrWrapOnSolveEvents(); ItemID target = PowerCellDistributionHandler_Tags.get_Item_PowerCellDistributionGens_PerObjective(data); RegionID regionID = data.Region_Objective; for (int j = 1; j <= data.Objective.PowerCellsToDistribute; j++) { ItemID item = data.Item_PowerCellDistributionGen_Instance(j); data.Locations.CreateValue(data.Location_PowerCellDistributionGen_Instance(j), list[j - 1], new LocationData { IsAutoDiscovered = true }, item); RegionID regionID2 = data.Region_PowercellDistributionGeneratorPowered(j); data.AddPath(new ReTFO.Archipelago.ModdedInstanceData.Model.Path { StartingRegion = regionID, EndingRegion = regionID2, Reqs = new ReTFO.Archipelago.ModdedInstanceData.Model.Path.MultiPathReq(new ReTFO.Archipelago.ModdedInstanceData.Model.Path.PathReq(ReTFO.Archipelago.ModdedInstanceData.Model.Path.eType.ItemConsumed, itemID, 1u), new ReTFO.Archipelago.ModdedInstanceData.Model.Path.PathReq(ReTFO.Archipelago.ModdedInstanceData.Model.Path.eType.Category, target, (uint)j)) }); regionID = regionID2; wrapper.Process(regionID2); } SharedObjectiveHandler.AddObjectiveCompleteItem(data, regionID); } } public static class TerminalUplinkHandler_Tags { [SpecialName] public sealed class $2B8804A94F2EF68DF77A343A46EE5A78 { [SpecialName] public static class $55FD246F9BFF39DD56FCB5C25D4DF852 { } [ExtensionMarker("$55FD246F9BFF39DD56FCB5C25D4DF852")] public LocationID Location_TerminalUplinkTerminals { [ExtensionMarker("$55FD246F9BFF39DD56FCB5C25D4DF852")] get { throw new NotSupportedException(); } } [ExtensionMarker("$55FD246F9BFF39DD56FCB5C25D4DF852")] public LocationID Location_TerminalUplinkCompletions { [ExtensionMarker("$55FD246F9BFF39DD56FCB5C25D4DF852")] get { throw new NotSupportedException(); } } [ExtensionMarker("$55FD246F9BFF39DD56FCB5C25D4DF852")] public ItemID Item_TerminalUplinkTerminals { [ExtensionMarker("$55FD246F9BFF39DD56FCB5C25D4DF852")] get { throw new NotSupportedException(); } } [ExtensionMarker("$55FD246F9BFF39DD56FCB5C25D4DF852")] public ItemID Item_TerminalUplinkCompletions { [ExtensionMarker("$55FD246F9BFF39DD56FCB5C25D4DF852")] get { throw new NotSupportedException(); } } } [SpecialName] public sealed class $E93D81478905A37B27DF6F640623743D { [SpecialName] public static class $66441969E171E5CA8C86F896EE40E940 { } [ExtensionMarker("$66441969E171E5CA8C86F896EE40E940")] public LocationID Location_TerminalUplinkTerminals_ByObjective { [ExtensionMarker("$66441969E171E5CA8C86F896EE40E940")] get { throw new NotSupportedException(); } } [ExtensionMarker("$66441969E171E5CA8C86F896EE40E940")] public LocationID Location_TerminalUplinkCompletions_ByObjective { [ExtensionMarker("$66441969E171E5CA8C86F896EE40E940")] get { throw new NotSupportedException(); } } [ExtensionMarker("$66441969E171E5CA8C86F896EE40E940")] public ItemID Item_TerminalUplinkTerminals_ByObjective { [ExtensionMarker("$66441969E171E5CA8C86F896EE40E940")] get { throw new NotSupportedException(); } } [ExtensionMarker("$66441969E171E5CA8C86F896EE40E940")] public ItemID Item_TerminalUplinkCompletions_ByObjective { [ExtensionMarker("$66441969E171E5CA8C86F896EE40E940")] get { throw new NotSupportedException(); } } [ExtensionMarker("$66441969E171E5CA8C86F896EE40E940")] public RegionID Region_StandardUplinkTerminalFound(int count) { throw new NotSupportedException(); } [ExtensionMarker("$66441969E171E5CA8C86F896EE40E940")] public RegionID Region_StandardUplinkCompleted(int count) { throw new NotSupportedException(); } [ExtensionMarker("$66441969E171E5CA8C86F896EE40E940")] public LocationID Location_TerminalUplinkTerminal_Instance(int count) { throw new NotSupportedException(); } [ExtensionMarker("$66441969E171E5CA8C86F896EE40E940")] public LocationID Location_TerminalUplinkCompletion_Instance(int count) { throw new NotSupportedException(); } [ExtensionMarker("$66441969E171E5CA8C86F896EE40E940")] public ItemID Item_TerminalUplinkTerminal_Instance(int count) { throw new NotSupportedException(); } [ExtensionMarker("$66441969E171E5CA8C86F896EE40E940")] public ItemID Item_TerminalUplinkCompletion_Instance(int count) { throw new NotSupportedException(); } } public static LocationID get_Location_TerminalUplinkTerminals(Game.Data data) { return LocationID.From(data, "Standard Uplink Terminal Locations", (Game.Data data2) => new TagDefinition("Locations checked by finding an uplink terminal", CommonTagsHandler_Tags.get_Location_Never(data2))); } public static LocationID get_Location_TerminalUplinkCompletions(Game.Data data) { return LocationID.From(data, "Standard Uplink Locations", (Game.Data data2) => new TagDefinition("Locations checked by completing a standard uplink", CommonTagsHandler_Tags.get_Location_Never(data2))); } public static ItemID get_Item_TerminalUplinkTerminals(Game.Data data) { return ItemID.From(data, "Standard Uplink Terminal Items", (Game.Data data2) => new TagDefinition("Items indicating an uplink terminal is reachable", CommonTagsHandler_Tags.get_Item_Never(data2))); } public static ItemID get_Item_TerminalUplinkCompletions(Game.Data data) { return ItemID.From(data, "Standard Uplink Completion Items", (Game.Data data2) => new TagDefinition("Items indicating an uplink is completed", CommonTagsHandler_Tags.get_Item_Never(data2))); } public static Objective.Data Checked(Objective.Data data) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Invalid comparison between Unknown and I4 //IL_0024: Unknown result type (might be due to invalid IL or missing references) if ((int)data.Objective.Type != 8) { FeatureLogger.Warning("Fetched an ID for the wrong objective type. Desired: " + Enum.GetName((eWardenObjectiveType)8) + ", actual: " + Enum.GetName(data.Objective.Type)); } return data; } public static RegionID Region_StandardUplinkTerminalFound(this Objective.Data data, int count) { return RegionID.From(Checked(data), $"{data.ObjectiveName} Found {count} Terminal{((count == 1) ? "" : "s")}", (Objective.Data data2) => new TagDefinition("Region entered by finding a number of uplink terminals", data2.Region_Objective)); } public static RegionID Region_StandardUplinkCompleted(this Objective.Data data, int count) { return RegionID.From(Checked(data), $"{data.ObjectiveName} Completed {count} Uplink{((count == 1) ? "" : "s")}", (Objective.Data data2) => new TagDefinition("Region entered by completing a number of terminal uplinks", data2.Region_Objective)); } public static LocationID get_Location_TerminalUplinkTerminals_ByObjective(Objective.Data data) { return LocationID.From(Checked(data), data.ObjectiveName + " Standard Uplink Terminal Locations", (Objective.Data data2) => new TagDefinition("Locations checked by finding an uplink terminal for a particular objective", get_Location_TerminalUplinkTerminals(data2))); } public static LocationID get_Location_TerminalUplinkCompletions_ByObjective(Objective.Data data) { return LocationID.From(Checked(data), data.ObjectiveName + " Standard Uplink Locations", (Objective.Data data2) => new TagDefinition("Locations checked by completing a standard uplink for a particular objective", get_Location_TerminalUplinkCompletions(data2))); } public static ItemID get_Item_TerminalUplinkTerminals_ByObjective(Objective.Data data) { return ItemID.From(Checked(data), data.ObjectiveName + " Standard Uplink Terminal Items", (Objective.Data data2) => new TagDefinition("Items indicating an uplink terminal is reachable for a particular objective", get_Item_TerminalUplinkTerminals(data2))); } public static ItemID get_Item_TerminalUplinkCompletions_ByObjective(Objective.Data data) { return ItemID.From(Checked(data), data.ObjectiveName + " Standard Uplink Completion Items", (Objective.Data data2) => new TagDefinition("Items indicating an uplink is completed for a particular objective", get_Item_TerminalUplinkCompletions(data2))); } public static LocationID Location_TerminalUplinkTerminal_Instance(this Objective.Data data, int count) { return LocationID.From(Checked(data), $"{data.ObjectiveName} Standard Uplink Terminal Location #{count}", (Objective.Data data2) => new TagDefinition("Locations checked by finding an uplink terminal for a particular objective", get_Location_TerminalUplinkTerminals_ByObjective(data2))); } public static LocationID Location_TerminalUplinkCompletion_Instance(this Objective.Data data, int count) { return LocationID.From(Checked(data), $"{data.ObjectiveName} Standard Uplink Location #{count}", (Objective.Data data2) => new TagDefinition("Locations checked by completing a standard uplink for a particular objective", get_Location_TerminalUplinkCompletions_ByObjective(data2))); } public static ItemID Item_TerminalUplinkTerminal_Instance(this Objective.Data data, int count) { return ItemID.From(Checked(data), $"{data.ObjectiveName} Standard Uplink Terminal #{count}", (Objective.Data data2) => new TagDefinition("Items indicating an uplink terminal is reachable for a particular objective", get_Item_TerminalUplinkTerminals_ByObjective(data2)), new TerminalUplinkHandler.TerminalUplink_TerminalItem(data.Region_Objective, count)); } public static ItemID Item_TerminalUplinkCompletion_Instance(this Objective.Data data, int count) { return ItemID.From(Checked(data), $"{data.ObjectiveName} Standard Uplink Completion #{count}", (Objective.Data data2) => new TagDefinition("Items indicating an uplink is completed for a particular objective", get_Item_TerminalUplinkCompletions_ByObjective(data2)), new TerminalUplinkHandler.TerminalUplink_CompletionItem(data.Region_Objective, count)); } } [EnableFeatureByDefault] [AutomatedFeature] public class TerminalUplinkHandler : ArchipelagoFeature { public class TerminalUplink_TerminalItem : Item { public RegionID ObjectiveRegion { get; private init; } public int Count { get; private init; } public TerminalUplink_TerminalItem(RegionID objective, int count) : base(new ItemData { IsProgression = true }) { ObjectiveRegion = objective; Count = count; } } public class TerminalUplink_CompletionItem : Item { public RegionID ObjectiveRegion { get; private init; } public int Count { get; private init; } public TerminalUplink_CompletionItem(RegionID objective, int count) : base(new ItemData { IsProgression = true }) { ObjectiveRegion = objective; Count = count; } } private static IArchiveLogger? m_featureLogger; public override string Name => "Standard Uplink Handler"; public override string Description => "Handles the TerminalUplink objective type.\nThis handles specifically only the standard uplink and not the corrupted or \"dual\" uplinkExample: R2B3"; public override FeatureGroup Group => ArchipelagoFeatureGroups.get_ObjectiveHandlers(); public new static IArchiveLogger FeatureLogger { get { return m_featureLogger ?? (m_featureLogger = Plugin.Get().Logger); } set { m_featureLogger = value; } } [Objective.Callback] public void HandleTerminalUplinkObjective(Objective.Data data) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Invalid comparison between Unknown and I4 if ((int)data.Objective.Type == 8) { List> list = data.ObjectiveToTerminalRegionSets(data.Objective.Uplink_NumberOfTerminals).ToList(); ItemID target = TerminalUplinkHandler_Tags.get_Item_TerminalUplinkTerminals_ByObjective(data); ItemID target2 = TerminalUplinkHandler_Tags.get_Item_TerminalUplinkCompletions_ByObjective(data); Event.Wrapper wrapper = data.MakeOrWrapOnSolveEvents(); RegionID regionID = data.Region_Objective; for (int i = 1; i <= data.Objective.Uplink_NumberOfTerminals; i++) { data.Locations.CreateValue(data.Location_TerminalUplinkTerminal_Instance(i), list[i - 1], new LocationData { IsAutoDiscovered = true }, data.Item_TerminalUplinkTerminal_Instance(i)); RegionID regionID2 = data.Region_StandardUplinkTerminalFound(i); data.AddPath(new ReTFO.Archipelago.ModdedInstanceData.Model.Path { StartingRegion = regionID, EndingRegion = regionID2, Reqs = new ReTFO.Archipelago.ModdedInstanceData.Model.Path.MultiPathReq(ReTFO.Archipelago.ModdedInstanceData.Model.Path.eType.Category, target, (uint)i) }); data.Locations.CreateValue(data.Location_TerminalUplinkCompletion_Instance(i), regionID2, new LocationData { IsAutoDiscovered = true }, data.Item_TerminalUplinkCompletion_Instance(i)); RegionID regionID3 = data.Region_StandardUplinkCompleted(i); data.AddPath(new ReTFO.Archipelago.ModdedInstanceData.Model.Path { StartingRegion = regionID2, EndingRegion = regionID3, Reqs = new ReTFO.Archipelago.ModdedInstanceData.Model.Path.MultiPathReq(ReTFO.Archipelago.ModdedInstanceData.Model.Path.eType.Category, target2, (uint)i) }); regionID = regionID3; wrapper.Process(regionID3); } SharedObjectiveHandler.AddObjectiveCompleteItem(data, regionID); } } } public static class CentralGenClusterHandler_Tags { [SpecialName] public sealed class $2B8804A94F2EF68DF77A343A46EE5A78 { [SpecialName] public static class $55FD246F9BFF39DD56FCB5C25D4DF852 { } [ExtensionMarker("$55FD246F9BFF39DD56FCB5C25D4DF852")] public LocationID Location_CentralGenCells { [ExtensionMarker("$55FD246F9BFF39DD56FCB5C25D4DF852")] get { throw new NotSupportedException(); } } [ExtensionMarker("$55FD246F9BFF39DD56FCB5C25D4DF852")] public LocationID Location_CentralGenClusters { [ExtensionMarker("$55FD246F9BFF39DD56FCB5C25D4DF852")] get { throw new NotSupportedException(); } } [ExtensionMarker("$55FD246F9BFF39DD56FCB5C25D4DF852")] public ItemID Item_CentralGenClusters { [ExtensionMarker("$55FD246F9BFF39DD56FCB5C25D4DF852")] get { throw new NotSupportedException(); } } [ExtensionMarker("$55FD246F9BFF39DD56FCB5C25D4DF852")] public LocationID Location_CentralGenScans { [ExtensionMarker("$55FD246F9BFF39DD56FCB5C25D4DF852")] get { throw new NotSupportedException(); } } [ExtensionMarker("$55FD246F9BFF39DD56FCB5C25D4DF852")] public ItemID Item_CentralGenScans { [ExtensionMarker("$55FD246F9BFF39DD56FCB5C25D4DF852")] get { throw new NotSupportedException(); } } } [SpecialName] public sealed class $E93D81478905A37B27DF6F640623743D { [SpecialName] public static class $66441969E171E5CA8C86F896EE40E940 { } [ExtensionMarker("$66441969E171E5CA8C86F896EE40E940")] public RegionID Region_FoundGenCluster { [ExtensionMarker("$66441969E171E5CA8C86F896EE40E940")] get { throw new NotSupportedException(); } } [ExtensionMarker("$66441969E171E5CA8C86F896EE40E940")] public RegionID Region_CompletedCentralGenScan { [ExtensionMarker("$66441969E171E5CA8C86F896EE40E940")] get { throw new NotSupportedException(); } } [ExtensionMarker("$66441969E171E5CA8C86F896EE40E940")] public LocationID Location_CentralGenCells_ByObjective { [ExtensionMarker("$66441969E171E5CA8C86F896EE40E940")] get { throw new NotSupportedException(); } } [ExtensionMarker("$66441969E171E5CA8C86F896EE40E940")] public LocationID Location_CentralGenCluster_Instance { [ExtensionMarker("$66441969E171E5CA8C86F896EE40E940")] get { throw new NotSupportedException(); } } [ExtensionMarker("$66441969E171E5CA8C86F896EE40E940")] public ItemID Item_CentralGenCluster_Instance { [ExtensionMarker("$66441969E171E5CA8C86F896EE40E940")] get { throw new NotSupportedException(); } } [ExtensionMarker("$66441969E171E5CA8C86F896EE40E940")] public LocationID Location_CentralGenScan_Instance { [ExtensionMarker("$66441969E171E5CA8C86F896EE40E940")] get { throw new NotSupportedException(); } } [ExtensionMarker("$66441969E171E5CA8C86F896EE40E940")] public ItemID Item_CentralGenScan_Instance { [ExtensionMarker("$66441969E171E5CA8C86F896EE40E940")] get { throw new NotSupportedException(); } } [ExtensionMarker("$66441969E171E5CA8C86F896EE40E940")] public RegionID Region_PoweredCentralGenerator(int count) { throw new NotSupportedException(); } [ExtensionMarker("$66441969E171E5CA8C86F896EE40E940")] public LocationID Location_CentralGenCell_Instance(int count) { throw new NotSupportedException(); } } public static LocationID get_Location_CentralGenCells(Game.Data data) { return LocationID.From(data, "Central Gen Cell Locations", (Game.Data gameData) => new TagDefinition("Locations checked by picking up cells spawned for central gen cluster objectives", PickupHelper_Tags.get_Location_BigPickups(gameData))); } public static LocationID get_Location_CentralGenClusters(Game.Data data) { return LocationID.From(data, "Central Gen Cluster Locations", (Game.Data data2) => new TagDefinition("Locations checked by finding central gen clusters", CommonTagsHandler_Tags.get_Location_Never(data2))); } public static ItemID get_Item_CentralGenClusters(Game.Data data) { return ItemID.From(data, "Central Gen Cluster Items", (Game.Data data2) => new TagDefinition("Items representing central gen clusters", CommonTagsHandler_Tags.get_Item_Never(data2))); } public static LocationID get_Location_CentralGenScans(Game.Data data) { return LocationID.From(data, "Central Gen Scan Locations", (Game.Data data2) => new TagDefinition("Locations checked by fully powering a central gen cluster", CommonTagsHandler_Tags.get_Location_All(data2))); } public static ItemID get_Item_CentralGenScans(Game.Data data) { return ItemID.From(data, "Central Gen Scan Items", (Game.Data data2) => new TagDefinition("Items which start the final gen cluster scan (which normally occurs when it's fully powered)", CommonTagsHandler_Tags.get_Item_Scans(data2))); } public static Objective.Data Checked(Objective.Data data) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Invalid comparison between Unknown and I4 //IL_0026: Unknown result type (might be due to invalid IL or missing references) if ((int)data.Objective.Type != 9) { FeatureLogger.Warning("Fetched an ID for the wrong objective type. Desired: " + Enum.GetName((eWardenObjectiveType)9) + ", actual: " + Enum.GetName(data.Objective.Type)); } return data; } public static RegionID get_Region_FoundGenCluster(Objective.Data data) { return RegionID.From(Checked(data), data.ObjectiveName + " Found Gen Cluster", (Objective.Data data2) => new TagDefinition("Region entered when a central gen cluster is found", data2.Region_Objective)); } public static RegionID Region_PoweredCentralGenerator(this Objective.Data data, int count) { return RegionID.From(Checked(data), $"{data.ObjectiveName} Powered Generator #{count}", (Objective.Data data2) => new TagDefinition("Region entered when a central generator is powered", data2.Region_Objective)); } public static RegionID get_Region_CompletedCentralGenScan(Objective.Data data) { return RegionID.From(Checked(data), data.ObjectiveName + " Completed Scan", (Objective.Data data2) => new TagDefinition("Region entered when a central gen cluster's scan is completed", data2.Region_Objective)); } public static LocationID get_Location_CentralGenCells_ByObjective(Objective.Data data) { return LocationID.From(Checked(data), data.ObjectiveName + " Central Gen Cell Locations", (Objective.Data data2) => new TagDefinition("Locations for cells for a particular objective", get_Location_CentralGenCells(data2))); } public static LocationID Location_CentralGenCell_Instance(this Objective.Data data, int count) { return LocationID.From(Checked(data), $"{data.ObjectiveName} Central Gen Cell Location #{count}", (Objective.Data data2) => new TagDefinition("Location of a particular central gen cell", get_Location_CentralGenCells_ByObjective(data2))); } public static LocationID get_Location_CentralGenCluster_Instance(Objective.Data data) { return LocationID.From(Checked(data), data.ObjectiveName + " Central Gen Cluster Location", (Objective.Data data2) => new TagDefinition("The location of a particular central gen cluster", get_Location_CentralGenClusters(data2))); } public static ItemID get_Item_CentralGenCluster_Instance(Objective.Data data) { return ItemID.From(Checked(data), data.ObjectiveName + " Central Gen Cluster", (Objective.Data data2) => new TagDefinition("A particular central gen cluster", get_Item_CentralGenClusters(data2)), new CentralGenClusterHandler.GenCluster_ClusterItem(data.Region_Objective)); } public static LocationID get_Location_CentralGenScan_Instance(Objective.Data data) { return LocationID.From(data, data.ObjectiveName + " Central Gen Scan Location", (Objective.Data data2) => new TagDefinition("A particular gen cluster scan's location", get_Location_CentralGenScans(data2))); } public static ItemID get_Item_CentralGenScan_Instance(Objective.Data data) { return ItemID.From(data, data.ObjectiveName + " Central Gen Scan Items", (Objective.Data data2) => new TagDefinition("A particular gen cluster scan", get_Item_CentralGenScans(data2)), new CentralGenClusterHandler.GenCluster_ScanItem(data.Region_Objective)); } } [EnableFeatureByDefault] [AutomatedFeature] public class CentralGenClusterHandler : ArchipelagoFeature { public class GenCluster_ClusterItem : Item { public RegionID ObjectiveRegion { get; private init; } public GenCluster_ClusterItem(RegionID objective) : base(new ItemData { IsProgression = true }) { ObjectiveRegion = objective; } } public class GenCluster_ScanItem : TerminalItem { public RegionID ObjectiveRegion { get; private init; } public override RegionID TargetRegion => ObjectiveRegion; public GenCluster_ScanItem(RegionID objective) : base(new ItemData { IsProgression = true }) { ObjectiveRegion = objective; } public override IEnumerable OnRetrieveFromTerminalSystem(StateTracker stateTracker, LG_ComputerTerminal terminal, ItemID itemId) { Objective.Data data = new Objective.Data(stateTracker.GameData, ObjectiveRegion); List objectiveItemCollection = WardenObjectiveManager.GetObjectiveItemCollection((LG_LayerType)data.LayerType, data.ObjectiveIndex); LG_PowerGeneratorCluster cluster = ((Il2CppObjectBase)objectiveItemCollection[0]).TryCast(); yield return delegate { terminal.AddLine((TerminalLineType)2, "Initiating Gen Cluster Scan", 2f); }; yield return delegate { if ((Object)(object)cluster != (Object)null) { terminal.AddLine("Scan will start in 3 seconds. Enjoy :)", true); ((MonoBehaviour)cluster).StartCoroutine(cluster.ObjectiveEndSequence()); cluster.SetFogIndex(cluster.m_currentFogStepIndex + 1); } else { terminal.AddLine("<#F00>Failed to find generator cluster! Item returned to terminal.", true); stateTracker.AddItemToTerminal(itemId); } }; } } [ArchivePatch(/*Could not decode attribute arguments.*/)] public static class LG_PowerGeneratorCluster___Setup_b__15_1__Patch { public static bool Prefix(LG_PowerGeneratorCluster __instance) { Objective.Data data = Layer.Data.GetFromLayer(__instance.SpawnNode.m_zone.Layer).GetObjectiveDatas().ElementAt(__instance.WardenObjectiveChainIndex); if (__instance.m_currentFogStepIndex == data.Objective.CentralPowerGenClustser_NumberOfGenerators - 2) { Location location = StateTracker.Get().NotifyFoundLocation(CentralGenClusterHandler_Tags.get_Location_CentralGenScan_Instance(data), null); if (location.RandData.IsTreatedAsRandom) { return false; } } return true; } } [ArchivePatch(/*Could not decode attribute arguments.*/)] public static class LG_Distribute_WardenObjective____c__DisplayClass8_1___DistributePickupItems_b__0__Patch { public static void Postfix(__c__DisplayClass8_1 __instance, LG_Zone zone) { //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Invalid comparison between Unknown and I4 Objective.Data data = Layer.Data.GetFromLayerFlattened(zone.Layer).GetObjectiveDatas().ElementAt(__instance.field_Public___c__DisplayClass8_0_0.chainIndex); if ((int)data.Objective.Type == 9) { PickupHelper.AssociateDistributionWithLocation(((Il2CppObjectBase)LG_Factory.Current.m_currentBatch.Jobs.FromEnd()).Cast(), data.Location_CentralGenCell_Instance(__instance.i + 1)); } } } private static IArchiveLogger? m_featureLogger; public override string Name => "Central Generator Cluster Handler"; public override string Description => "Handles the CentralGenCluster objective type.\nExample: R2D1"; public override FeatureGroup Group => ArchipelagoFeatureGroups.get_ObjectiveHandlers(); public new static IArchiveLogger FeatureLogger { get { return m_featureLogger ?? (m_featureLogger = Plugin.Get().Logger); } set { m_featureLogger = value; } } [Objective.Callback] public void HandleCentralGenGlusterObjective(Objective.Data data) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Invalid comparison between Unknown and I4 if ((int)data.Objective.Type != 9) { return; } ItemID itemID = BigPickupHandler_Tags.get_Item_BigPickup_Cell(data); List> list = (from ps in data.PlacementsToZoneRegions(data.ObjectiveData.ZonePlacementDatas) select ps.Select((Game.Data.RegionInfo i) => i.Region).ToList()).TakeLooped(data.Objective.CentralPowerGenClustser_NumberOfPowerCells).ToList(); for (int num = 1; num <= data.Objective.CentralPowerGenClustser_NumberOfPowerCells; num++) { data.Locations.CreateValue(data.Location_CentralGenCell_Instance(num), list[num - 1], default(LocationData), itemID); } Zone.Data data2 = null; foreach (Zone.Data item in Zone.get_AllZones(data)) { ExpeditionZoneData? zone = item.Zone; if (((zone != null && zone.GeneratorClustersInZone != 0) ? 1 : 0) > (false ? 1 : 0)) { data2 = item; break; } } if (data2 == null) { FeatureLogger.Warning("Failed to find gen cluster for objective: " + data.ObjectiveName); data2 = Zone.get_FirstZone(data); } ItemID itemID2 = CentralGenClusterHandler_Tags.get_Item_CentralGenCluster_Instance(data); data.Locations.CreateValue(CentralGenClusterHandler_Tags.get_Location_CentralGenCluster_Instance(data), data2.Region_Zone, new LocationData { IsAutoDiscovered = true }, itemID2); RegionID regionID = CentralGenClusterHandler_Tags.get_Region_FoundGenCluster(data); data.AddPath(new ReTFO.Archipelago.ModdedInstanceData.Model.Path { StartingRegion = data.Region_Objective, EndingRegion = regionID, Reqs = new ReTFO.Archipelago.ModdedInstanceData.Model.Path.MultiPathReq(ReTFO.Archipelago.ModdedInstanceData.Model.Path.eType.Item, itemID2, 1u) }); Event.Wrapper wrapper = data.MakeOrWrapOnSolveEvents(); RegionID regionID2 = regionID; for (int num2 = 1; num2 <= data.Objective.CentralPowerGenClustser_NumberOfGenerators; num2++) { RegionID regionID3 = data.Region_PoweredCentralGenerator(num2); data.AddPath(new ReTFO.Archipelago.ModdedInstanceData.Model.Path { StartingRegion = regionID2, EndingRegion = regionID3, Reqs = new ReTFO.Archipelago.ModdedInstanceData.Model.Path.MultiPathReq(ReTFO.Archipelago.ModdedInstanceData.Model.Path.eType.ItemConsumed, itemID, 1u) }); regionID2 = regionID3; wrapper.Process(regionID3, extendIfNecessary: true); } ItemID itemID3 = CentralGenClusterHandler_Tags.get_Item_CentralGenScan_Instance(data); data.Locations.CreateValue(CentralGenClusterHandler_Tags.get_Location_CentralGenScan_Instance(data), regionID2, default(LocationData), itemID3); RegionID regionID4 = CentralGenClusterHandler_Tags.get_Region_CompletedCentralGenScan(data); data.AddPath(new ReTFO.Archipelago.ModdedInstanceData.Model.Path { StartingRegion = regionID2, EndingRegion = regionID4, Reqs = new ReTFO.Archipelago.ModdedInstanceData.Model.Path.MultiPathReq(ReTFO.Archipelago.ModdedInstanceData.Model.Path.eType.Item, itemID3, 1u) }); SharedObjectiveHandler.AddObjectiveCompleteItem(data, regionID4); } } public static class ProcessItemHandler_Tags { [SpecialName] public sealed class $2B8804A94F2EF68DF77A343A46EE5A78 { [SpecialName] public static class $55FD246F9BFF39DD56FCB5C25D4DF852 { } [ExtensionMarker("$55FD246F9BFF39DD56FCB5C25D4DF852")] public LocationID Location_ProcessItemCages { [ExtensionMarker("$55FD246F9BFF39DD56FCB5C25D4DF852")] get { throw new NotSupportedException(); } } [ExtensionMarker("$55FD246F9BFF39DD56FCB5C25D4DF852")] public LocationID Location_ProcessItemProcessors { [ExtensionMarker("$55FD246F9BFF39DD56FCB5C25D4DF852")] get { throw new NotSupportedException(); } } [ExtensionMarker("$55FD246F9BFF39DD56FCB5C25D4DF852")] public ItemID Item_ProcessItemProcessors { [ExtensionMarker("$55FD246F9BFF39DD56FCB5C25D4DF852")] get { throw new NotSupportedException(); } } } [SpecialName] public sealed class $E93D81478905A37B27DF6F640623743D { [SpecialName] public static class $66441969E171E5CA8C86F896EE40E940 { } [ExtensionMarker("$66441969E171E5CA8C86F896EE40E940")] public RegionID Region_ProcessItemProcessed { [ExtensionMarker("$66441969E171E5CA8C86F896EE40E940")] get { throw new NotSupportedException(); } } [ExtensionMarker("$66441969E171E5CA8C86F896EE40E940")] public LocationID Location_ProcessItemCage_Instance { [ExtensionMarker("$66441969E171E5CA8C86F896EE40E940")] get { throw new NotSupportedException(); } } [ExtensionMarker("$66441969E171E5CA8C86F896EE40E940")] public LocationID Location_ProcessItemProcessor_Instance { [ExtensionMarker("$66441969E171E5CA8C86F896EE40E940")] get { throw new NotSupportedException(); } } [ExtensionMarker("$66441969E171E5CA8C86F896EE40E940")] public ItemID Item_ProcessItemProcessor_Instance { [ExtensionMarker("$66441969E171E5CA8C86F896EE40E940")] get { throw new NotSupportedException(); } } } public static LocationID get_Location_ProcessItemCages(Game.Data data) { return LocationID.From(data, "Process Item Cage Locations", (Game.Data gameData) => new TagDefinition("Locations checked by picking up the start item for Process Item objectives (if it spawned in the elevator cage)", PickupHelper_Tags.get_Location_BigPickups(gameData))); } public static LocationID get_Location_ProcessItemProcessors(Game.Data data) { return LocationID.From(data, "Process Item Processor Locations", (Game.Data data2) => new TagDefinition("Locations containing the processor for a Process Item objective", CommonTagsHandler_Tags.get_Location_Never(data2))); } public static ItemID get_Item_ProcessItemProcessors(Game.Data data) { return ItemID.From(data, "Process Item Processor Items", (Game.Data data2) => new TagDefinition("Items indicating a Process Items processor is reachable", CommonTagsHandler_Tags.get_Item_Never(data2))); } public static Objective.Data Checked(Objective.Data data) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Invalid comparison between Unknown and I4 //IL_0026: Unknown result type (might be due to invalid IL or missing references) if ((int)data.Objective.Type != 10) { FeatureLogger.Warning("Fetched an ID for the wrong objective type. Desired: " + Enum.GetName((eWardenObjectiveType)10) + ", actual: " + Enum.GetName(data.Objective.Type)); } return data; } public static RegionID get_Region_ProcessItemProcessed(Objective.Data data) { return RegionID.From(Checked(data), data.ObjectiveName + " Item Processed", (Objective.Data data2) => new TagDefinition("Region entered by processing the process item objective's item.", data2.Region_Objective)); } public static LocationID get_Location_ProcessItemCage_Instance(Objective.Data data) { return LocationID.From(Checked(data), data.ObjectiveName + " Process Item Cage Locations", (Objective.Data data2) => new TagDefinition("A particular Process Item objective cage spawn location.", get_Location_ProcessItemCages(data2))); } public static LocationID get_Location_ProcessItemProcessor_Instance(Objective.Data data) { return LocationID.From(Checked(data), data.ObjectiveName + " Process Item Processor Locations", (Objective.Data data2) => new TagDefinition("A particular Process Item processor location", get_Location_ProcessItemProcessors(data2))); } public static ItemID get_Item_ProcessItemProcessor_Instance(Objective.Data data) { return ItemID.From(Checked(data), data.ObjectiveName + " Process Item Processor Items", (Objective.Data data2) => new TagDefinition("A particular Process Item processor", get_Item_ProcessItemProcessors(data2)), new ProcessItemHandler.ProcessItem_ProcessorItem(data.Region_Objective)); } } [EnableFeatureByDefault] [AutomatedFeature] public class ProcessItemHandler : ArchipelagoFeature { public class ProcessItem_ProcessorItem : Item { public RegionID ObjectiveRegion { get; private init; } public ProcessItem_ProcessorItem(RegionID objective) : base(new ItemData { IsProgression = true }) { ObjectiveRegion = objective; } } [ArchivePatch(/*Could not decode attribute arguments.*/)] public static class LG_Factory__FactoryDone__Patch { public static void Postfix() { //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Invalid comparison between Unknown and I4 //IL_0087: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Invalid comparison between Unknown and I4 Expedition.Data fromCurrentExpedition = Expedition.Data.GetFromCurrentExpedition(); Objective.Data data = Layer.get_MainLayer(fromCurrentExpedition).GetObjectiveDatas().First(); int num = 0; if (data.Objective.GenericItemFromStart != 0) { num++; } if ((int)data.Objective.Type == 7) { num += data.Objective.PowerCellsToDistribute; } foreach (Objective.Data item in Layer.get_RealLayers(fromCurrentExpedition).SelectMany((Layer.Data l) => l.GetObjectiveDatas())) { if ((int)item.Objective.Type == 10 && item.Objective.ActivateHSU_BringItemInElevator) { CarryItemPickup_Core componentInChildren = ((Component)ElevatorCage.Current.m_cargoCage.m_itemsToMoveToCargo[num]).GetComponentInChildren(); if (((GameDataBlockBase)(object)((Item)componentInChildren).ItemDataBlock).persistentID != item.Objective.ActivateHSU_ItemFromStart) { FeatureLogger.Warning("Associating wrong item with processor objective starting item!"); } PickupHelper.AssociateItem((ItemInLevel)(object)componentInChildren, ProcessItemHandler_Tags.get_Location_ProcessItemCage_Instance(item)); } } } } private static IArchiveLogger? m_featureLogger; public override string Name => "Process Item Handler"; public override string Description => "Handles the ActiveSmallHSU objective type.\nExample: R3A1"; public override FeatureGroup Group => ArchipelagoFeatureGroups.get_ObjectiveHandlers(); public new static IArchiveLogger FeatureLogger { get { return m_featureLogger ?? (m_featureLogger = Plugin.Get().Logger); } set { m_featureLogger = value; } } [Objective.Callback] public void HandleActivateSmallHSUObjective(Objective.Data data) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Invalid comparison between Unknown and I4 if ((int)data.Objective.Type == 10) { ItemID itemID = data.Item_BigPickup_Instance(data.Objective.ActivateHSU_ItemFromStart); if (data.Objective.ActivateHSU_BringItemInElevator) { RegionList owningRegions = Zone.get_FirstZone(data.GetLayer(LayerType.Main)).Region_Zone; data.Locations.CreateValue(ProcessItemHandler_Tags.get_Location_ProcessItemCage_Instance(data), owningRegions, default(LocationData), itemID); } ItemID itemID2 = ProcessItemHandler_Tags.get_Item_ProcessItemProcessor_Instance(data); data.Locations.CreateValue(ProcessItemHandler_Tags.get_Location_ProcessItemProcessor_Instance(data), (from info in data.ObjectiveData.ZonePlacementDatas.SelectMany, Game.Data.RegionInfo>(((Layer.Data)data).PlacementsToZoneRegions) select info.Region).ToList(), new LocationData { IsAutoDiscovered = true }, itemID2); RegionID regionID = ProcessItemHandler_Tags.get_Region_ProcessItemProcessed(data); data.AddPath(new ReTFO.Archipelago.ModdedInstanceData.Model.Path { StartingRegion = data.Region_Objective, EndingRegion = regionID, Reqs = new ReTFO.Archipelago.ModdedInstanceData.Model.Path.MultiPathReq(new ReTFO.Archipelago.ModdedInstanceData.Model.Path.PathReq(ReTFO.Archipelago.ModdedInstanceData.Model.Path.eType.Item, itemID, 1u), new ReTFO.Archipelago.ModdedInstanceData.Model.Path.PathReq(ReTFO.Archipelago.ModdedInstanceData.Model.Path.eType.Item, itemID2, 1u)) }); if (data.Objective.EventsOnActivate.Any()) { data.ProcessEvents(regionID, data.Objective.EventsOnActivate); } WardenObjectiveDataBlock objective = data.Objective; data.ProcessEvents(regionID, objective.ActivateHSU_Events ?? (objective.ActivateHSU_Events = new List(1))); if (data.Objective.ActivateHSU_ObjectiveCompleteAfterInsertion) { SharedObjectiveHandler.AddObjectiveCompleteItem(data, regionID); } } } } public static class SurvivalHandler_Tags { [SpecialName] public sealed class $2B8804A94F2EF68DF77A343A46EE5A78 { [SpecialName] public static class $55FD246F9BFF39DD56FCB5C25D4DF852 { } } [SpecialName] public sealed class $E93D81478905A37B27DF6F640623743D { [SpecialName] public static class $66441969E171E5CA8C86F896EE40E940 { } [ExtensionMarker("$66441969E171E5CA8C86F896EE40E940")] public RegionID Region_SurvivalStarted { [ExtensionMarker("$66441969E171E5CA8C86F896EE40E940")] get { throw new NotSupportedException(); } } [ExtensionMarker("$66441969E171E5CA8C86F896EE40E940")] public RegionID Region_SurvivalSurvived(float duration) { throw new NotSupportedException(); } } public static Objective.Data Checked(Objective.Data data) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Invalid comparison between Unknown and I4 //IL_0026: Unknown result type (might be due to invalid IL or missing references) if ((int)data.Objective.Type != 11) { FeatureLogger.Warning("Fetched an ID for the wrong objective type. Desired: " + Enum.GetName((eWardenObjectiveType)11) + ", actual: " + Enum.GetName(data.Objective.Type)); } return data; } public static RegionID get_Region_SurvivalStarted(Objective.Data data) { return RegionID.From(Checked(data), data.ObjectiveName + " Started", (Objective.Data data2) => new TagDefinition("Region entered by starting the survival portion of a survival objective", data2.Region_Objective)); } public static RegionID Region_SurvivalSurvived(this Objective.Data data, float duration) { return RegionID.From(Checked(data), $"{data.ObjectiveName} Survived {TimeSpan.FromSeconds(duration):c}", (Objective.Data data2) => new TagDefinition("Region entered by surviving a specific duration of a survival objective", data2.Region_Objective)); } } [EnableFeatureByDefault] [AutomatedFeature] public class SurvivalHandler : ArchipelagoFeature { private static IArchiveLogger? m_featureLogger; public override string Name => "Survival Handler"; public override string Description => "Handles the Survival objective type.\nThe survival objective is any objective that puts a timer at the top of the screen.\nExamples: R5B4, R8E1"; public override FeatureGroup Group => ArchipelagoFeatureGroups.get_ObjectiveHandlers(); public new static IArchiveLogger FeatureLogger { get { return m_featureLogger ?? (m_featureLogger = Plugin.Get().Logger); } set { m_featureLogger = value; } } [Objective.Callback] public void HandleSurvivalObjective(Objective.Data data) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Invalid comparison between Unknown and I4 //IL_00a9: Unknown result type (might be due to invalid IL or missing references) //IL_00b3: Invalid comparison between Unknown and I4 if ((int)data.Objective.Type != 11) { return; } RegionID regionID = SurvivalHandler_Tags.get_Region_SurvivalStarted(data); ReTFO.Archipelago.ModdedInstanceData.Model.Path path = new ReTFO.Archipelago.ModdedInstanceData.Model.Path(); path.StartingRegion = data.Region_Objective; path.EndingRegion = regionID; ReTFO.Archipelago.ModdedInstanceData.Model.Path path2 = path; if (data.ObjectiveIndex > 0) { path = new ReTFO.Archipelago.ModdedInstanceData.Model.Path(path2); path.Reqs = new ReTFO.Archipelago.ModdedInstanceData.Model.Path.MultiPathReq(ReTFO.Archipelago.ModdedInstanceData.Model.Path.eType.Category, SharedObjectiveHandler_Tags.get_Item_CompleteObjective_Instance(data), (uint)data.ObjectiveIndex); path2 = path; } data.AddPath(path2); SortedList> sortedList = new SortedList>(); WardenObjectiveDataBlock objective = data.Objective; Enumerator enumerator = (objective.EventsOnActivate ?? (objective.EventsOnActivate = new List())).GetEnumerator(); while (enumerator.MoveNext()) { WardenObjectiveEventData current = enumerator.Current; if ((int)current.Type == 999) { break; } if (!sortedList.TryGetValue(current.Delay, out var value)) { value = new List(2); sortedList.Add(current.Delay, value); } value.Add(current); } RegionID startingRegion = regionID; foreach (KeyValuePair> item in sortedList) { RegionID regionID2 = data.Region_SurvivalSurvived(item.Key); data.AddPath(new ReTFO.Archipelago.ModdedInstanceData.Model.Path { StartingRegion = startingRegion, EndingRegion = regionID2 }); startingRegion = regionID2; data.ProcessEvents(regionID2, item.Value); Enumerator enumerator3 = item.Value.GetEnumerator(); while (enumerator3.MoveNext()) { WardenObjectiveEventData current3 = enumerator3.Current; current3.Delay = item.Key; } } data.Objective.EventsOnActivate = new List(sortedList.Sum((KeyValuePair> pair) => pair.Value.Count)); foreach (WardenObjectiveEventData item2 in sortedList.SelectMany((KeyValuePair> pair) => pair.Value.Iter())) { data.Objective.EventsOnActivate.Add(item2); } RegionID regionID3 = data.Region_SurvivalSurvived(data.Objective.Survival_TimeToSurvive); if (!sortedList.ContainsKey(data.Objective.Survival_TimeToSurvive)) { startingRegion = regionID; foreach (KeyValuePair> item3 in sortedList.Reverse()) { if (item3.Key < data.Objective.Survival_TimeToSurvive) { startingRegion = data.Region_SurvivalSurvived(item3.Key); break; } } data.AddPath(new ReTFO.Archipelago.ModdedInstanceData.Model.Path { StartingRegion = startingRegion, EndingRegion = regionID3 }); } SharedObjectiveHandler.AddObjectiveCompleteItem(data, regionID3); } } public static class GatherTerminalHandler_Tags { [SpecialName] public sealed class $2B8804A94F2EF68DF77A343A46EE5A78 { [SpecialName] public static class $55FD246F9BFF39DD56FCB5C25D4DF852 { } [ExtensionMarker("$55FD246F9BFF39DD56FCB5C25D4DF852")] public LocationID Location_GatherTerminalsCommands { [ExtensionMarker("$55FD246F9BFF39DD56FCB5C25D4DF852")] get { throw new NotSupportedException(); } } [ExtensionMarker("$55FD246F9BFF39DD56FCB5C25D4DF852")] public ItemID Item_GatherTerminalsCommands { [ExtensionMarker("$55FD246F9BFF39DD56FCB5C25D4DF852")] get { throw new NotSupportedException(); } } } [SpecialName] public sealed class $E93D81478905A37B27DF6F640623743D { [SpecialName] public static class $66441969E171E5CA8C86F896EE40E940 { } [ExtensionMarker("$66441969E171E5CA8C86F896EE40E940")] public LocationID Location_GatherTerminalsCommands_ByObjective { [ExtensionMarker("$66441969E171E5CA8C86F896EE40E940")] get { throw new NotSupportedException(); } } [ExtensionMarker("$66441969E171E5CA8C86F896EE40E940")] public ItemID Item_GatherTerminalsCommands_ByObjective { [ExtensionMarker("$66441969E171E5CA8C86F896EE40E940")] get { throw new NotSupportedException(); } } [ExtensionMarker("$66441969E171E5CA8C86F896EE40E940")] public RegionID Region_GatherCommandExecuted(int count) { throw new NotSupportedException(); } [ExtensionMarker("$66441969E171E5CA8C86F896EE40E940")] public LocationID Location_GatherTerminalsCommand_Instance(int count) { throw new NotSupportedException(); } [ExtensionMarker("$66441969E171E5CA8C86F896EE40E940")] public ItemID Item_GatherTerminalsCommand_Instance(int count) { throw new NotSupportedException(); } } public static LocationID get_Location_GatherTerminalsCommands(Game.Data data) { return LocationID.From(data, "Gather Terminals Command Locations", (Game.Data data2) => new TagDefinition("Locations checked executing gather terminals commands", CommonTagsHandler_Tags.get_Location_All(data2))); } public static ItemID get_Item_GatherTerminalsCommands(Game.Data data) { return ItemID.From(data, "Gather Terminals Command Items", (Game.Data data2) => new TagDefinition("Items representing a gather terminals command having been executed", CommonTagsHandler_Tags.get_Item_All(data2))); } public static Objective.Data Checked(Objective.Data data) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Invalid comparison between Unknown and I4 //IL_0026: Unknown result type (might be due to invalid IL or missing references) if ((int)data.Objective.Type != 12) { FeatureLogger.Warning("Fetched an ID for the wrong objective type. Desired: " + Enum.GetName((eWardenObjectiveType)12) + ", actual: " + Enum.GetName(data.Objective.Type)); } return data; } public static RegionID Region_GatherCommandExecuted(this Objective.Data data, int count) { return RegionID.From(Checked(data), $"{data.ObjectiveName} {count} command{((count == 1) ? "" : "s")} executed", (Objective.Data data2) => new TagDefinition("Region entered by executing a particular number of Gather Termianl commands for a particualr objective", data2.Region_Objective)); } public static LocationID get_Location_GatherTerminalsCommands_ByObjective(Objective.Data data) { return LocationID.From(Checked(data), data.ObjectiveName + " Gather Terminals Command Locations", (Objective.Data data2) => new TagDefinition("Locations checked by executing gather terminals commands for a particular objective", get_Location_GatherTerminalsCommands(data2))); } public static ItemID get_Item_GatherTerminalsCommands_ByObjective(Objective.Data data) { return ItemID.From(Checked(data), data.ObjectiveName + " Gather Terminals Command Items", (Objective.Data data2) => new TagDefinition("Items representing a gather terminals command having been executed for a particular objective", get_Item_GatherTerminalsCommands(data2))); } public static LocationID Location_GatherTerminalsCommand_Instance(this Objective.Data data, int count) { return LocationID.From(Checked(data), $"{data.ObjectiveName} Gather Terminals Command Locations #{count}", (Objective.Data data2) => new TagDefinition("A particular checked by executing a gather terminals commands", get_Location_GatherTerminalsCommands_ByObjective(data2))); } public static ItemID Item_GatherTerminalsCommand_Instance(this Objective.Data data, int count) { return ItemID.From(Checked(data), $"{data.ObjectiveName} Gather Terminals Command #{count}", (Objective.Data data2) => new TagDefinition("An item representing a particular gather terminals command having been executed", get_Item_GatherTerminalsCommands_ByObjective(data2)), new GatherTerminalHandler.GatherTerminals_CommandItem(data.Region_Objective, count)); } } [EnableFeatureByDefault] [AutomatedFeature] public class GatherTerminalHandler : ArchipelagoFeature { public class GatherTerminals_CommandItem : TerminalItem { public RegionID ObjectiveRegion { get; private init; } public int Count { get; private init; } public override RegionID TargetRegion => ObjectiveRegion; public GatherTerminals_CommandItem(RegionID objective, int count) : base(new ItemData { IsProgression = true }) { ObjectiveRegion = objective; Count = count; } public override IEnumerable OnRetrieveFromTerminalSystem(StateTracker stateTracker, LG_ComputerTerminal terminal, ItemID itemId) { Objective.Data data = new Objective.Data(stateTracker.GameData, ObjectiveRegion); yield return delegate { LocalizedText gatherTerminal_DownloadingText = data.Objective.GatherTerminal_DownloadingText; if (gatherTerminal_DownloadingText.Id == 0) { string untranslatedText = gatherTerminal_DownloadingText.UntranslatedText; if (untranslatedText == null || untranslatedText.Length == 0) { terminal.m_command.AddOutput((TerminalLineType)4, 436196897u, 1f, (TerminalSoundType)0, (TerminalSoundType)0); return; } } terminal.m_command.AddOutput((TerminalLineType)4, LocalizedText.op_Implicit(data.Objective.GatherTerminal_DownloadingText), MathF.Min(1f, data.Objective.GatherTerminal_DownloadTime), (TerminalSoundType)0, (TerminalSoundType)0); }; yield return delegate { //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Unknown result type (might be due to invalid IL or missing references) List objectiveItemCollection = WardenObjectiveManager.GetObjectiveItemCollection((LG_LayerType)data.LayerType, data.ObjectiveIndex); objectiveItemCollection[Count - 1].ObjectiveItemSolved = true; WardenObjectiveManager.OnLocalPlayerSolvedObjectiveItem((LG_LayerType)data.LayerType, objectiveItemCollection[Count - 1], true); LocalizedText gatherTerminal_DownloadCompleteText = data.Objective.GatherTerminal_DownloadCompleteText; if (gatherTerminal_DownloadCompleteText.Id == 0) { string untranslatedText = gatherTerminal_DownloadCompleteText.UntranslatedText; if (untranslatedText == null || untranslatedText.Length == 0) { terminal.m_command.AddOutput(2410856699u, true); return; } } terminal.m_command.AddOutput(LocalizedText.op_Implicit(data.Objective.GatherTerminal_DownloadCompleteText), true); }; } } [ArchivePatch(/*Could not decode attribute arguments.*/)] public static class LG_ComputerTerminal__SetupAsWardenObjectiveGatherTerminal__Patch { public static void Postfix(LG_ComputerTerminal __instance, int objectiveChainIndex) { __instance.WardenObjectiveChainIndex = objectiveChainIndex; } } [ArchivePatch(/*Could not decode attribute arguments.*/)] public static class LG_ComputerTermina__OnWardenObjectiveGatherCommandDone__Patch { public static bool Prefix(LG_ComputerTerminal __instance) { Func func = delegate { //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Invalid comparison between Unknown and I4 //IL_006b: Unknown result type (might be due to invalid IL or missing references) Objective.Data data = Expedition.Data.GetFromCurrentExpedition().GetLayer(__instance.SpawnNode.LayerType).GetObjectiveDatas() .ElementAt(__instance.WardenObjectiveChainIndex); if ((int)data.Objective.Type != 12) { FeatureLogger.Error("Failed to find objective data while intercepting gather command!"); return true; } List objectiveItemCollection = WardenObjectiveManager.GetObjectiveItemCollection((LG_LayerType)data.LayerType, data.ObjectiveIndex); int i; for (i = 0; i < objectiveItemCollection.Count && !(((Il2CppObjectBase)objectiveItemCollection[i]).Pointer == ((Il2CppObjectBase)__instance).Pointer); i++) { } if (i == objectiveItemCollection.Count) { FeatureLogger.Error("Failed to find terminal index while intercepting gather command!"); return true; } LocationID id = data.Location_GatherTerminalsCommand_Instance(i + 1); Location loc = StateTracker.Get().NotifyFoundLocation(id, __instance.m_syncedInteractionSource); if (loc.RandData.IsTreatedAsRandom) { __instance.m_command.AddOutput("Discovered item(s):", false); __instance.m_command.AddOutput(" Item: " + itemName(), false); __instance.m_command.AddOutput(" World: " + itemGame(), false); __instance.m_command.AddOutput(" Owner: " + itemPlayer(), false); return false; } return true; string itemGame() { return loc.ScoutedGameName ?? "DEBUG"; } string itemName() { object obj = loc.ScoutedItemName; if (obj == null) { if (!loc.ItemID.IsNull) { return data.Items.LookUpName(loc.ItemID); } obj = "None"; } return (string)obj; } string itemPlayer() { return loc.ScoutedPlayerName ?? StateTracker.Config.Username; } }; return func(); } } private static IArchiveLogger? m_featureLogger; public override string Name => "Gather Terminals Handler"; public override string Description => "Handles the GatherTerminals objective type.\nThis objective type refers only to when you need to enter multiple special command.\nExample: R5A3 Main"; public override FeatureGroup Group => ArchipelagoFeatureGroups.get_ObjectiveHandlers(); public new static IArchiveLogger FeatureLogger { get { return m_featureLogger ?? (m_featureLogger = Plugin.Get().Logger); } set { m_featureLogger = value; } } [Game.Callback] public void AddGatherCommandOption(Game.Data data) { ItemID itemID = FreeCheckpointsHandler_Tags.get_Item_FreeCheckpoints(data); data.AddOption(new OptionItemTagOption("Gather Terminal Randomization", "Controls randomization of Gather Terminal commands. These are commands which are run many times on a variety of terminals, which you need to collect N of to complete the objective. For example, in R6D2.\nWhitelist: Enables for all unless blacklisted elsewhere.\nBlacklist: Disables for all.\nNone: Defer to other relevant setting(s). If no other relevant setting is set, defaults to blacklisted.", "Randomization Options", Option.MakeSortKey(data, itemID), 0L, default(OptionID), itemID)); } [Objective.Callback] public void HandleGatherTerminalObjective(Objective.Data data) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Invalid comparison between Unknown and I4 if ((int)data.Objective.Type != 12) { return; } if (data.Objective.GatherTerminal_RequiredCount > data.Objective.GatherTerminal_SpawnCount) { FeatureLogger.Error(data.ObjectiveName + ": Expected at least as many terminal spawns as required terminals"); return; } List> list = data.ObjectiveToTerminalRegionSets(data.Objective.GatherTerminal_SpawnCount).ToList(); Event.Wrapper wrapper = data.MakeOrWrapOnSolveEvents(); RegionID startingRegion = data.Region_Objective; ItemID target = GatherTerminalHandler_Tags.get_Item_GatherTerminalsCommands_ByObjective(data); for (int i = 1; i <= data.Objective.GatherTerminal_SpawnCount; i++) { ItemID item = data.Item_GatherTerminalsCommand_Instance(i); data.Locations.CreateValue(data.Location_GatherTerminalsCommand_Instance(i), list[i - 1], default(LocationData), item); RegionID regionID = data.Region_GatherCommandExecuted(i); data.AddPath(new ReTFO.Archipelago.ModdedInstanceData.Model.Path { StartingRegion = startingRegion, EndingRegion = regionID, Reqs = new ReTFO.Archipelago.ModdedInstanceData.Model.Path.MultiPathReq(ReTFO.Archipelago.ModdedInstanceData.Model.Path.eType.Category, target, (uint)i) }); startingRegion = regionID; if (i == data.Objective.GatherTerminal_RequiredCount) { SharedObjectiveHandler.AddObjectiveCompleteItem(data, regionID); } wrapper.Process(regionID, extendIfNecessary: true); } } } public static class CorruptedUplinkHandler_Tags { [SpecialName] public sealed class $2B8804A94F2EF68DF77A343A46EE5A78 { [SpecialName] public static class $55FD246F9BFF39DD56FCB5C25D4DF852 { } [ExtensionMarker("$55FD246F9BFF39DD56FCB5C25D4DF852")] public LocationID Location_CorruptedUplinkTerminals { [ExtensionMarker("$55FD246F9BFF39DD56FCB5C25D4DF852")] get { throw new NotSupportedException(); } } [ExtensionMarker("$55FD246F9BFF39DD56FCB5C25D4DF852")] public ItemID Item_CorruptedUplinkTerminals { [ExtensionMarker("$55FD246F9BFF39DD56FCB5C25D4DF852")] get { throw new NotSupportedException(); } } [ExtensionMarker("$55FD246F9BFF39DD56FCB5C25D4DF852")] public LocationID Location_CorruptedUplinkCompletions { [ExtensionMarker("$55FD246F9BFF39DD56FCB5C25D4DF852")] get { throw new NotSupportedException(); } } [ExtensionMarker("$55FD246F9BFF39DD56FCB5C25D4DF852")] public ItemID Item_CorruptedUplinkCompletions { [ExtensionMarker("$55FD246F9BFF39DD56FCB5C25D4DF852")] get { throw new NotSupportedException(); } } } [SpecialName] public sealed class $E93D81478905A37B27DF6F640623743D { [SpecialName] public static class $66441969E171E5CA8C86F896EE40E940 { } [ExtensionMarker("$66441969E171E5CA8C86F896EE40E940")] public LocationID Location_CorruptedUplinkTerminals_PerObjective { [ExtensionMarker("$66441969E171E5CA8C86F896EE40E940")] get { throw new NotSupportedException(); } } [ExtensionMarker("$66441969E171E5CA8C86F896EE40E940")] public ItemID Item_CorruptedUplinkTerminals_PerObjective { [ExtensionMarker("$66441969E171E5CA8C86F896EE40E940")] get { throw new NotSupportedException(); } } [ExtensionMarker("$66441969E171E5CA8C86F896EE40E940")] public LocationID Location_CorruptedUplinkCompletions_PerObjective { [ExtensionMarker("$66441969E171E5CA8C86F896EE40E940")] get { throw new NotSupportedException(); } } [ExtensionMarker("$66441969E171E5CA8C86F896EE40E940")] public ItemID Item_CorruptedUplinkCompletions_PerObjective { [ExtensionMarker("$66441969E171E5CA8C86F896EE40E940")] get { throw new NotSupportedException(); } } [ExtensionMarker("$66441969E171E5CA8C86F896EE40E940")] public RegionID Region_CorruptedUplinkPairFound(int count) { throw new NotSupportedException(); } [ExtensionMarker("$66441969E171E5CA8C86F896EE40E940")] public RegionID Region_CorruptedUplinkCompleted(int count) { throw new NotSupportedException(); } [ExtensionMarker("$66441969E171E5CA8C86F896EE40E940")] public LocationID Location_CorruptedUplinkTerminal_Instance(int count) { throw new NotSupportedException(); } [ExtensionMarker("$66441969E171E5CA8C86F896EE40E940")] public ItemID Item_CorruptedUplinkTerminal_Instance(int count) { throw new NotSupportedException(); } [ExtensionMarker("$66441969E171E5CA8C86F896EE40E940")] public LocationID Location_CorruptedUplinkCompletion_Instance(int count) { throw new NotSupportedException(); } [ExtensionMarker("$66441969E171E5CA8C86F896EE40E940")] public ItemID Item_CorruptedUplinkCompletion_Instance(int count) { throw new NotSupportedException(); } } public static LocationID get_Location_CorruptedUplinkTerminals(Game.Data data) { return LocationID.From(data, "Corrupted Uplink Terminal Locations", (Game.Data data2) => new TagDefinition("Locations checked by finding Corrupted Uplink terminals", CommonTagsHandler_Tags.get_Location_Never(data2))); } public static ItemID get_Item_CorruptedUplinkTerminals(Game.Data data) { return ItemID.From(data, "Corrupted Uplink Terminal Items", (Game.Data data2) => new TagDefinition("Terminal items used for Corrupted Uplinks", CommonTagsHandler_Tags.get_Item_Never(data2))); } public static LocationID get_Location_CorruptedUplinkCompletions(Game.Data data) { return LocationID.From(data, "Corrupted Uplink Completion Locations", (Game.Data data2) => new TagDefinition("Locations checked by completing Corrupted Uplinks", CommonTagsHandler_Tags.get_Location_Never(data2))); } public static ItemID get_Item_CorruptedUplinkCompletions(Game.Data data) { return ItemID.From(data, "Corrupted Uplink Completion Items", (Game.Data data2) => new TagDefinition("Represents a corrupted uplink having been completed", CommonTagsHandler_Tags.get_Item_Never(data2))); } public static Objective.Data Checked(Objective.Data data) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Invalid comparison between Unknown and I4 //IL_0026: Unknown result type (might be due to invalid IL or missing references) if ((int)data.Objective.Type != 13) { FeatureLogger.Warning("Fetched an ID for the wrong objective type. Desired: " + Enum.GetName((eWardenObjectiveType)13) + ", actual: " + Enum.GetName(data.Objective.Type)); } return data; } public static RegionID Region_CorruptedUplinkPairFound(this Objective.Data data, int count) { return RegionID.From(Checked(data), $"{data.ObjectiveName} Found {count} Terminal Pair{((count == 1) ? "" : "s")}", (Objective.Data data2) => new TagDefinition("Region entered by finding a number of corrupted uplink terminal pairs", data2.Region_Objective)); } public static RegionID Region_CorruptedUplinkCompleted(this Objective.Data data, int count) { return RegionID.From(Checked(data), $"{data.ObjectiveName} Uplink #{count} Completed", (Objective.Data data2) => new TagDefinition("Region entered by completing a numer of corrupted uplink", data2.Region_Objective)); } public static LocationID get_Location_CorruptedUplinkTerminals_PerObjective(Objective.Data data) { return LocationID.From(Checked(data), data.ObjectiveName + " Corrupted Uplink Terminal Locations", (Objective.Data data2) => new TagDefinition("Locations checked by finding Corrupted Uplink terminals for a particular objective", get_Location_CorruptedUplinkTerminals(data2))); } public static ItemID get_Item_CorruptedUplinkTerminals_PerObjective(Objective.Data data) { return ItemID.From(Checked(data), data.ObjectiveName + " Corrupted Uplink Terminal Items", (Objective.Data data2) => new TagDefinition("Terminal items used for Corrupted Uplinks for a particular objective", get_Item_CorruptedUplinkTerminals(data2))); } public static LocationID get_Location_CorruptedUplinkCompletions_PerObjective(Objective.Data data) { return LocationID.From(Checked(data), data.ObjectiveName + " Corrupted Uplink Completion Locations", (Objective.Data data2) => new TagDefinition("Locations checked by completing Corrupted Uplinks for a particular objective", get_Location_CorruptedUplinkCompletions(data2))); } public static ItemID get_Item_CorruptedUplinkCompletions_PerObjective(Objective.Data data) { return ItemID.From(Checked(data), data.ObjectiveName + " Corrupted Uplink Completion Items", (Objective.Data data2) => new TagDefinition("Represents a corrupted uplink having been completed for a particular objective", get_Item_CorruptedUplinkCompletions(data2))); } public static LocationID Location_CorruptedUplinkTerminal_Instance(this Objective.Data data, int count) { return LocationID.From(Checked(data), $"{data.ObjectiveName} Corrupted Uplink Terminal Location #{count}", (Objective.Data data2) => new TagDefinition("Location checked by finding a particular Corrupted Uplink terminal", get_Location_CorruptedUplinkTerminals_PerObjective(data2))); } public static ItemID Item_CorruptedUplinkTerminal_Instance(this Objective.Data data, int count) { return ItemID.From(Checked(data), $"{data.ObjectiveName} Corrupted Uplink Terminal #{count}", (Objective.Data data2) => new TagDefinition("Terminal item used for a particular corrupted Uplinks", get_Item_CorruptedUplinkTerminals_PerObjective(data2)), new CorruptedUplinkHandler.CorruptedUplink_TerminalItem(data.Region_Objective, count)); } public static LocationID Location_CorruptedUplinkCompletion_Instance(this Objective.Data data, int count) { return LocationID.From(Checked(data), $"{data.ObjectiveName} Corrupted Uplink Completion Location #{count}", (Objective.Data data2) => new TagDefinition("Location checked by completing a particular Corrupted Uplink", get_Location_CorruptedUplinkCompletions_PerObjective(data2))); } public static ItemID Item_CorruptedUplinkCompletion_Instance(this Objective.Data data, int count) { return ItemID.From(Checked(data), $"{data.ObjectiveName} Corrupted Uplink Completion #{count}", (Objective.Data data2) => new TagDefinition("Represents a particular corrupted uplink having been completed", get_Item_CorruptedUplinkCompletions_PerObjective(data2)), new CorruptedUplinkHandler.CorruptedUplink_CompletionItem(data.Region_Objective, count)); } } [EnableFeatureByDefault] [AutomatedFeature] public class CorruptedUplinkHandler : ArchipelagoFeature { public class CorruptedUplink_TerminalItem : Item { public RegionID ObjectiveRegion { get; private init; } public int Count { get; private init; } public CorruptedUplink_TerminalItem(RegionID objective, int count) : base(new ItemData { IsProgression = true }) { ObjectiveRegion = objective; Count = count; } } public class CorruptedUplink_CompletionItem : Item { public RegionID ObjectiveRegion { get; private init; } public int Count { get; private init; } public CorruptedUplink_CompletionItem(RegionID objective, int count) : base(new ItemData { IsProgression = true }) { ObjectiveRegion = objective; Count = count; } } private static IArchiveLogger? m_featureLogger; public override string Name => "Corrupted Uplink Handler"; public override string Description => "Handles the CorruptedTerminalUplink objective type.\nThis handles specifically only the corrupted or \"dual\" uplink typeExample: R5C3"; public override FeatureGroup Group => ArchipelagoFeatureGroups.get_ObjectiveHandlers(); public new static IArchiveLogger FeatureLogger { get { return m_featureLogger ?? (m_featureLogger = Plugin.Get().Logger); } set { m_featureLogger = value; } } [Objective.Callback] public void HandleCorruptedUplinkObjective(Objective.Data data) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Invalid comparison between Unknown and I4 if ((int)data.Objective.Type == 13) { List> list = data.UnstuffPlacements(data.PlacementsToTerminalRegions(data.ObjectiveData.ZonePlacementDatas), data.Objective.Uplink_NumberOfTerminals).ToList(); ItemID target = CorruptedUplinkHandler_Tags.get_Item_CorruptedUplinkTerminals_PerObjective(data); ItemID target2 = CorruptedUplinkHandler_Tags.get_Item_CorruptedUplinkCompletions_PerObjective(data); Event.Wrapper wrapper = data.MakeOrWrapOnSolveEvents(); RegionID regionID = data.Region_Objective; for (int i = 1; i <= data.Objective.Uplink_NumberOfTerminals; i++) { ItemID item = data.Item_CorruptedUplinkTerminal_Instance(2 * i - 1); data.Locations.CreateValue(data.Location_CorruptedUplinkTerminal_Instance(2 * i - 1), list[i - 1], new LocationData { IsAutoDiscovered = true }, item); ItemID item2 = data.Item_CorruptedUplinkTerminal_Instance(2 * i); data.Locations.CreateValue(data.Location_CorruptedUplinkTerminal_Instance(2 * i), list[i - 1], new LocationData { IsAutoDiscovered = true }, item2); RegionID regionID2 = data.Region_CorruptedUplinkPairFound(i); data.AddPath(new ReTFO.Archipelago.ModdedInstanceData.Model.Path { StartingRegion = regionID, EndingRegion = regionID2, Reqs = new ReTFO.Archipelago.ModdedInstanceData.Model.Path.MultiPathReq(ReTFO.Archipelago.ModdedInstanceData.Model.Path.eType.Category, target, (uint)(2 * i)) }); data.Locations.CreateValue(data.Location_CorruptedUplinkCompletion_Instance(i), regionID2, new LocationData { IsAutoDiscovered = true }, data.Item_CorruptedUplinkCompletion_Instance(i)); RegionID regionID3 = data.Region_CorruptedUplinkCompleted(i); data.AddPath(new ReTFO.Archipelago.ModdedInstanceData.Model.Path { StartingRegion = regionID2, EndingRegion = regionID3, Reqs = new ReTFO.Archipelago.ModdedInstanceData.Model.Path.MultiPathReq(ReTFO.Archipelago.ModdedInstanceData.Model.Path.eType.Category, target2, (uint)i) }); regionID = regionID3; wrapper.Process(regionID3); } SharedObjectiveHandler.AddObjectiveCompleteItem(data, regionID); } } } [EnableFeatureByDefault] [AutomatedFeature] public class EmptyHandler : ArchipelagoFeature { private static IArchiveLogger? m_featureLogger; public override string Name => "Empty Handler"; public override string Description => "Handles the Empty objective type.\nThis is a special objective type which cannot be beaten, and requires a ForceCompelteObjective event (or Win event).\nExample: R8E2 (Main) Objective #2\n -> This level has two chained objectives; the first is survival, and winning it triggers the nightmare surge. The second is empty, so you can't extract after \"surviving\" the objective."; public override FeatureGroup Group => ArchipelagoFeatureGroups.get_ObjectiveHandlers(); public new static IArchiveLogger FeatureLogger { get { return m_featureLogger ?? (m_featureLogger = Plugin.Get().Logger); } set { m_featureLogger = value; } } } public static class TimedSequenceHandler_Tags { [SpecialName] public sealed class $2B8804A94F2EF68DF77A343A46EE5A78 { [SpecialName] public static class $55FD246F9BFF39DD56FCB5C25D4DF852 { } [ExtensionMarker("$55FD246F9BFF39DD56FCB5C25D4DF852")] public LocationID Location_TimedSequenceMains { [ExtensionMarker("$55FD246F9BFF39DD56FCB5C25D4DF852")] get { throw new NotSupportedException(); } } [ExtensionMarker("$55FD246F9BFF39DD56FCB5C25D4DF852")] public ItemID Item_TimedSequenceMains { [ExtensionMarker("$55FD246F9BFF39DD56FCB5C25D4DF852")] get { throw new NotSupportedException(); } } [ExtensionMarker("$55FD246F9BFF39DD56FCB5C25D4DF852")] public LocationID Location_TimedSequenceVerifies { [ExtensionMarker("$55FD246F9BFF39DD56FCB5C25D4DF852")] get { throw new NotSupportedException(); } } [ExtensionMarker("$55FD246F9BFF39DD56FCB5C25D4DF852")] public ItemID Item_TimedSequenceVerifies { [ExtensionMarker("$55FD246F9BFF39DD56FCB5C25D4DF852")] get { throw new NotSupportedException(); } } } [SpecialName] public sealed class $E93D81478905A37B27DF6F640623743D { [SpecialName] public static class $66441969E171E5CA8C86F896EE40E940 { } [ExtensionMarker("$66441969E171E5CA8C86F896EE40E940")] public LocationID Location_TimedSequenceVerifies_PerObjective { [ExtensionMarker("$66441969E171E5CA8C86F896EE40E940")] get { throw new NotSupportedException(); } } [ExtensionMarker("$66441969E171E5CA8C86F896EE40E940")] public ItemID Item_TimedSequenceVerifies_PerObjective { [ExtensionMarker("$66441969E171E5CA8C86F896EE40E940")] get { throw new NotSupportedException(); } } [ExtensionMarker("$66441969E171E5CA8C86F896EE40E940")] public LocationID Location_TimedSequenceMain_Instance { [ExtensionMarker("$66441969E171E5CA8C86F896EE40E940")] get { throw new NotSupportedException(); } } [ExtensionMarker("$66441969E171E5CA8C86F896EE40E940")] public ItemID Item_TimedSequenceMain_Instance { [ExtensionMarker("$66441969E171E5CA8C86F896EE40E940")] get { throw new NotSupportedException(); } } [ExtensionMarker("$66441969E171E5CA8C86F896EE40E940")] public RegionID Region_TimedRoundStarted(int count) { throw new NotSupportedException(); } [ExtensionMarker("$66441969E171E5CA8C86F896EE40E940")] public RegionID Region_TimedRoundFailed(int count) { throw new NotSupportedException(); } [ExtensionMarker("$66441969E171E5CA8C86F896EE40E940")] public RegionID Region_TimedRoundCompleted(int count) { throw new NotSupportedException(); } [ExtensionMarker("$66441969E171E5CA8C86F896EE40E940")] public LocationID Location_TimedSequenceVerify_Instance(int count) { throw new NotSupportedException(); } [ExtensionMarker("$66441969E171E5CA8C86F896EE40E940")] public ItemID Item_TimedSequenceVerify_Instance(int count) { throw new NotSupportedException(); } } public static LocationID get_Location_TimedSequenceMains(Game.Data data) { return LocationID.From(data, "Timed Sequence Main Terminal Locations", (Game.Data data2) => new TagDefinition("Locations containing the main terminal for a timed sequence", CommonTagsHandler_Tags.get_Location_Never(data2))); } public static ItemID get_Item_TimedSequenceMains(Game.Data data) { return ItemID.From(data, "Timed Sequence Main Terminals", (Game.Data data2) => new TagDefinition("The main (central) terminals for timed sequences", CommonTagsHandler_Tags.get_Item_Never(data2))); } public static LocationID get_Location_TimedSequenceVerifies(Game.Data data) { return LocationID.From(data, "Timed Sequence Verify Terminal Locations", (Game.Data data2) => new TagDefinition("Locations containing a verify terminal for all timed sequences", CommonTagsHandler_Tags.get_Location_Never(data2))); } public static ItemID get_Item_TimedSequenceVerifies(Game.Data data) { return ItemID.From(data, "Timed Sequence Verify Terminals", (Game.Data data2) => new TagDefinition("The verification terminals for timed sequences", CommonTagsHandler_Tags.get_Item_Never(data2))); } public static Objective.Data Checked(Objective.Data data) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Invalid comparison between Unknown and I4 //IL_0026: Unknown result type (might be due to invalid IL or missing references) if ((int)data.Objective.Type != 15) { FeatureLogger.Warning("Fetched an ID for the wrong objective type. Desired: " + Enum.GetName((eWardenObjectiveType)15) + ", actual: " + Enum.GetName(data.Objective.Type)); } return data; } public static RegionID Region_TimedRoundStarted(this Objective.Data data, int count) { return RegionID.From(Checked(data), $"{data.ObjectiveName} Start Round {count}", (Objective.Data data2) => new TagDefinition("Region entered by starting a particular timed sequence verification round", data2.Region_Objective)); } public static RegionID Region_TimedRoundFailed(this Objective.Data data, int count) { return RegionID.From(Checked(data), $"{data.ObjectiveName} Fail Round {count}", (Objective.Data data2) => new TagDefinition("Region entered by failing a particular timed sequence verification round", data2.Region_Objective)); } public static RegionID Region_TimedRoundCompleted(this Objective.Data data, int count) { return RegionID.From(Checked(data), $"{data.ObjectiveName} Complete Round {count}", (Objective.Data data2) => new TagDefinition("Region entered by successfully completing a particular timed sequence verification round", data2.Region_Objective)); } public static LocationID get_Location_TimedSequenceVerifies_PerObjective(Objective.Data data) { return LocationID.From(Checked(data), data.ObjectiveName + " Timed Sequence Verify Terminal Locations", (Objective.Data data2) => new TagDefinition("Locations containing a verify terminal for a particular timed sequence", get_Location_TimedSequenceVerifies(data2))); } public static ItemID get_Item_TimedSequenceVerifies_PerObjective(Objective.Data data) { return ItemID.From(Checked(data), data.ObjectiveName + " Timed Sequence Verify Terminals", (Objective.Data data2) => new TagDefinition("Timed Sequence verify terminal items for a particular objective", get_Item_TimedSequenceVerifies(data2))); } public static LocationID get_Location_TimedSequenceMain_Instance(Objective.Data data) { return LocationID.From(Checked(data), data.ObjectiveName + " Timed Sequence Main Terminal Location", (Objective.Data data2) => new TagDefinition("Locations containing a verify terminal for a particular timed sequence", get_Location_TimedSequenceVerifies(data2))); } public static ItemID get_Item_TimedSequenceMain_Instance(Objective.Data data) { return ItemID.From(Checked(data), data.ObjectiveName + " Timed Sequence Main Terminal", (Objective.Data data2) => new TagDefinition("Timed Sequence verify terminal items for a particular objective", get_Item_TimedSequenceVerifies(data2)), new TimedSequenceHandler.TimedSequence_MainItem(data.Region_Objective)); } public static LocationID Location_TimedSequenceVerify_Instance(this Objective.Data data, int count) { return LocationID.From(Checked(data), $"{data.ObjectiveName} Timed Sequence Verify Terminal Location #{count}", (Objective.Data data2) => new TagDefinition("Locations containing a verify terminal for a particular timed sequence", get_Location_TimedSequenceVerifies(data2))); } public static ItemID Item_TimedSequenceVerify_Instance(this Objective.Data data, int count) { return ItemID.From(Checked(data), $"{data.ObjectiveName} Timed Sequence Verify Terminal #{count}", (Objective.Data data2) => new TagDefinition("Timed Sequence verify terminal items for a particular objective", get_Item_TimedSequenceVerifies(data2)), new TimedSequenceHandler.TimedSequence_VerifyItem(data.Region_Objective, count)); } } [EnableFeatureByDefault] [AutomatedFeature] public class TimedSequenceHandler : ArchipelagoFeature { public class TimedSequence_MainItem : Item { public RegionID ObjectiveRegion { get; private init; } public TimedSequence_MainItem(RegionID objective) : base(new ItemData { IsProgression = true }) { ObjectiveRegion = objective; } } public class TimedSequence_VerifyItem : Item { public RegionID ObjectiveRegion { get; private init; } public int Count { get; private init; } public TimedSequence_VerifyItem(RegionID objective, int count) : base(new ItemData { IsProgression = true }) { ObjectiveRegion = objective; Count = count; } } private static IArchiveLogger? m_featureLogger; public override string Name => "Timed Sequence Handler"; public override string Description => "Handles the TimedSequence objective type.\nThis handles specifically only the corrupted or \"dual\" uplink typeExample: R5C3"; public override FeatureGroup Group => ArchipelagoFeatureGroups.get_ObjectiveHandlers(); public new static IArchiveLogger FeatureLogger { get { return m_featureLogger ?? (m_featureLogger = Plugin.Get().Logger); } set { m_featureLogger = value; } } [Objective.Callback] public void HandleTimedSequenceObjective(Objective.Data data) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Invalid comparison between Unknown and I4 if ((int)data.Objective.Type != 15) { return; } if (data.Objective.TimedTerminalSequence_NumberOfRounds < 1) { FeatureLogger.Error(data.ObjectiveName + ": Cannot have fewer than 1 TimedSequence round!"); return; } IEnumerable> source = data.PlacementsToTerminalRegions(data.ObjectiveData.ZonePlacementDatas); ItemID itemID = TimedSequenceHandler_Tags.get_Item_TimedSequenceMain_Instance(data); data.Locations.CreateValue(TimedSequenceHandler_Tags.get_Location_TimedSequenceMain_Instance(data), (from info in source.First() select info.Region).ToList(), new LocationData { IsAutoDiscovered = true }, itemID); int num = 0; foreach (IEnumerable item in source.Skip(1)) { num++; data.Locations.CreateValue(data.Location_TimedSequenceVerify_Instance(num), item.Select((Game.Data.RegionInfo i) => i.Region).ToList(), new LocationData { IsAutoDiscovered = true }, data.Item_TimedSequenceVerify_Instance(num)); } int num2 = 1; RegionID regionID = data.Region_TimedRoundStarted(num2); data.AddPath(new ReTFO.Archipelago.ModdedInstanceData.Model.Path { StartingRegion = data.Region_Objective, EndingRegion = regionID, Reqs = new ReTFO.Archipelago.ModdedInstanceData.Model.Path.MultiPathReq(ReTFO.Archipelago.ModdedInstanceData.Model.Path.eType.Item, itemID, 1u) }); if (data.Objective.TimedTerminalSequence_EventsOnSequenceStart.Count >= num2) { data.ProcessEvents(regionID, data.Objective.TimedTerminalSequence_EventsOnSequenceStart[num2 - 1]); } RegionID regionID2 = data.Region_TimedRoundFailed(num2); data.AddPath(new ReTFO.Archipelago.ModdedInstanceData.Model.Path { StartingRegion = regionID, EndingRegion = regionID2 }); if (data.Objective.TimedTerminalSequence_EventsOnSequenceFail.Count >= num2) { data.ProcessEvents(regionID2, data.Objective.TimedTerminalSequence_EventsOnSequenceFail[num2 - 1]); } RegionID regionID3 = data.Region_TimedRoundCompleted(num2); data.AddPath(new ReTFO.Archipelago.ModdedInstanceData.Model.Path { StartingRegion = regionID, EndingRegion = regionID3, Reqs = new ReTFO.Archipelago.ModdedInstanceData.Model.Path.MultiPathReq(ReTFO.Archipelago.ModdedInstanceData.Model.Path.eType.Category, TimedSequenceHandler_Tags.get_Item_TimedSequenceVerifies(data), (uint)num) }); if (data.Objective.TimedTerminalSequence_EventsOnSequenceDone.Count >= num2) { data.ProcessEvents(regionID3, data.Objective.TimedTerminalSequence_EventsOnSequenceDone[num2 - 1]); } for (num2 = 2; num2 <= data.Objective.TimedTerminalSequence_NumberOfRounds; num2++) { regionID = data.Region_TimedRoundStarted(num2); data.AddPath(new ReTFO.Archipelago.ModdedInstanceData.Model.Path { StartingRegion = regionID3, EndingRegion = regionID }); if (data.Objective.TimedTerminalSequence_EventsOnSequenceStart.Count >= num2) { data.ProcessEvents(regionID, data.Objective.TimedTerminalSequence_EventsOnSequenceStart[num2 - 1]); } regionID2 = data.Region_TimedRoundFailed(num2); data.AddPath(new ReTFO.Archipelago.ModdedInstanceData.Model.Path { StartingRegion = regionID, EndingRegion = regionID2 }); if (data.Objective.TimedTerminalSequence_EventsOnSequenceFail.Count >= num2) { data.ProcessEvents(regionID2, data.Objective.TimedTerminalSequence_EventsOnSequenceFail[num2 - 1]); } regionID3 = data.Region_TimedRoundCompleted(num2); data.AddPath(new ReTFO.Archipelago.ModdedInstanceData.Model.Path { StartingRegion = regionID, EndingRegion = regionID3 }); if (data.Objective.TimedTerminalSequence_EventsOnSequenceDone.Count >= num2) { data.ProcessEvents(regionID3, data.Objective.TimedTerminalSequence_EventsOnSequenceDone[num2 - 1]); } } if (data.Objective.OnActivateOnSolveItem && data.Objective.EventsOnActivate.Any()) { data.ProcessEvents(regionID3, data.Objective.EventsOnActivate); } SharedObjectiveHandler.AddObjectiveCompleteItem(data, regionID3); } } public static class ExtractionHandler_Tags { [SpecialName] public sealed class $2B8804A94F2EF68DF77A343A46EE5A78 { [SpecialName] public static class $55FD246F9BFF39DD56FCB5C25D4DF852 { } [ExtensionMarker("$55FD246F9BFF39DD56FCB5C25D4DF852")] public LocationID Location_Extractions { [ExtensionMarker("$55FD246F9BFF39DD56FCB5C25D4DF852")] get { throw new NotSupportedException(); } } [ExtensionMarker("$55FD246F9BFF39DD56FCB5C25D4DF852")] public ItemID Item_Extractions { [ExtensionMarker("$55FD246F9BFF39DD56FCB5C25D4DF852")] get { throw new NotSupportedException(); } } } [SpecialName] public sealed class $2833969430CAB23CD70890D67B9ADDD5 { [SpecialName] public static class $5667123F7013DAD37BB214B248F3E5D2 { } [ExtensionMarker("$5667123F7013DAD37BB214B248F3E5D2")] public LocationID Location_Extraction_Instance { [ExtensionMarker("$5667123F7013DAD37BB214B248F3E5D2")] get { throw new NotSupportedException(); } } [ExtensionMarker("$5667123F7013DAD37BB214B248F3E5D2")] public ItemID Item_Extraction_Instance { [ExtensionMarker("$5667123F7013DAD37BB214B248F3E5D2")] get { throw new NotSupportedException(); } } } public static LocationID get_Location_Extractions(Game.Data data) { return LocationID.From(data, "Extraction Locations", (Game.Data data2) => new TagDefinition("Parent tag of all extraction locations", CommonTagsHandler_Tags.get_Location_Never(data2))); } public static ItemID get_Item_Extractions(Game.Data data) { return ItemID.From(data, "Extractions", (Game.Data data2) => new TagDefinition("Items indicating extraction is reachable on a particular level", CommonTagsHandler_Tags.get_Item_Never(data2))); } public static LocationID get_Location_Extraction_Instance(Expedition.Data data) { return LocationID.From(data, data.ExpeditionName + " Extraction Location", (Expedition.Data data2) => new TagDefinition("An extraction location for a particular expedition", get_Location_Extractions(data2))); } public static ItemID get_Item_Extraction_Instance(Expedition.Data data) { return ItemID.From(data, data.ExpeditionName + " Extraction", (Expedition.Data data2) => new TagDefinition("An item indicating extraction is reachable for a particular expedition", get_Item_Extractions(data2)), new ExtractionHandler.ExtractionReachableItem(data.Region_Expedition)); } } [EnableFeatureByDefault] [AutomatedFeature] public class ExtractionHandler : ArchipelagoFeature { public class ExtractionReachableItem : Item { public RegionID ExpeditionRegion { get; private init; } public ExtractionReachableItem(RegionID expedition) : base(new ItemData { IsProgression = true }) { ExpeditionRegion = expedition; } } private static IArchiveLogger? m_featureLogger; public override string Name => "Extraction Handler"; public override string Description => "Adds an \"Extraction Reachable\" item used to help identify when an expedition is clearable.\nThis item has no impact on play and is purely an internal item."; public override FeatureGroup Group => ArchipelagoFeatureGroups.get_ObjectiveHandlers(); public new static IArchiveLogger FeatureLogger { get { return m_featureLogger ?? Plugin.Get().Logger; } set { m_featureLogger = value; } } [Expedition.Callback] public void AddExtraction(Expedition.Data data) { //IL_00b7: Unknown result type (might be due to invalid IL or missing references) //IL_00bd: Invalid comparison between Unknown and I4 ComplexResourceSetDataBlock block = GameDataBlockBase.GetBlock(data.Expedition.Expedition.ComplexResourceData); Layer.Data layerData = Layer.get_MainLayer(data); Zone.Data data2 = null; foreach (Zone.Data z in Zone.get_AllZones(layerData).Reverse()) { if (z.CustomGeo != null && !(z.CustomGeo == "") && block.CustomGeomorphs_Exit_1x1.Any((ResourceData c) => c.Prefab == z.CustomGeo)) { data2 = z; break; } } if (data2 == null && (int)data.Expedition.MainLayerData.ObjectiveData.WinCondition != 1) { data2 = Zone.get_FirstZone(layerData); } else if (data2 == null) { FeatureLogger.Warning("Failed to place extraction for " + data.ExpeditionName); return; } data.Locations.CreateValue(ExtractionHandler_Tags.get_Location_Extraction_Instance(data), data2.Region_Zone, new LocationData { IsAutoDiscovered = true }, ExtractionHandler_Tags.get_Item_Extraction_Instance(data)); } } public static class SharedObjectiveHandler_Tags { [SpecialName] public sealed class $2B8804A94F2EF68DF77A343A46EE5A78 { [SpecialName] public static class $55FD246F9BFF39DD56FCB5C25D4DF852 { } [ExtensionMarker("$55FD246F9BFF39DD56FCB5C25D4DF852")] public LocationID Location_CompleteObjectives { [ExtensionMarker("$55FD246F9BFF39DD56FCB5C25D4DF852")] get { throw new NotSupportedException(); } } [ExtensionMarker("$55FD246F9BFF39DD56FCB5C25D4DF852")] public ItemID Item_CompleteObjectives { [ExtensionMarker("$55FD246F9BFF39DD56FCB5C25D4DF852")] get { throw new NotSupportedException(); } } [ExtensionMarker("$55FD246F9BFF39DD56FCB5C25D4DF852")] public LocationID Location_SectorClears { [ExtensionMarker("$55FD246F9BFF39DD56FCB5C25D4DF852")] get { throw new NotSupportedException(); } } [ExtensionMarker("$55FD246F9BFF39DD56FCB5C25D4DF852")] public ItemID Item_SectorClears { [ExtensionMarker("$55FD246F9BFF39DD56FCB5C25D4DF852")] get { throw new NotSupportedException(); } } [ExtensionMarker("$55FD246F9BFF39DD56FCB5C25D4DF852")] public LocationID Location_PEClears { [ExtensionMarker("$55FD246F9BFF39DD56FCB5C25D4DF852")] get { throw new NotSupportedException(); } } [ExtensionMarker("$55FD246F9BFF39DD56FCB5C25D4DF852")] public ItemID Item_PEClears { [ExtensionMarker("$55FD246F9BFF39DD56FCB5C25D4DF852")] get { throw new NotSupportedException(); } } [ExtensionMarker("$55FD246F9BFF39DD56FCB5C25D4DF852")] public LocationID Location_CompleteObjectives_LayerOnly(LayerType layer) { throw new NotSupportedException(); } [ExtensionMarker("$55FD246F9BFF39DD56FCB5C25D4DF852")] public ItemID Item_CompleteObjectives_LayerOnly(LayerType layer) { throw new NotSupportedException(); } [ExtensionMarker("$55FD246F9BFF39DD56FCB5C25D4DF852")] public LocationID Location_SectorClears_LayerOnly(LayerType layer) { throw new NotSupportedException(); } [ExtensionMarker("$55FD246F9BFF39DD56FCB5C25D4DF852")] public ItemID Item_SectorClears_LayerOnly(LayerType layer) { throw new NotSupportedException(); } } [SpecialName] public sealed class $2833969430CAB23CD70890D67B9ADDD5 { [SpecialName] public static class $5667123F7013DAD37BB214B248F3E5D2 { } [ExtensionMarker("$5667123F7013DAD37BB214B248F3E5D2")] public RegionID Region_PECleared { [ExtensionMarker("$5667123F7013DAD37BB214B248F3E5D2")] get { throw new NotSupportedException(); } } [ExtensionMarker("$5667123F7013DAD37BB214B248F3E5D2")] public LocationID Location_PEClear_Instance { [ExtensionMarker("$5667123F7013DAD37BB214B248F3E5D2")] get { throw new NotSupportedException(); } } [ExtensionMarker("$5667123F7013DAD37BB214B248F3E5D2")] public ItemID Item_PEClear_Instance { [ExtensionMarker("$5667123F7013DAD37BB214B248F3E5D2")] get { throw new NotSupportedException(); } } } [SpecialName] public sealed class $9DAFA10623A49E693D4D9BEA615A7202 { [SpecialName] public static class $70E40AF8BA672009D4689E0A70FAB84A { } [ExtensionMarker("$70E40AF8BA672009D4689E0A70FAB84A")] public RegionID Region_GoToWin { [ExtensionMarker("$70E40AF8BA672009D4689E0A70FAB84A")] get { throw new NotSupportedException(); } } [ExtensionMarker("$70E40AF8BA672009D4689E0A70FAB84A")] public RegionID Region_SectorCleared { [ExtensionMarker("$70E40AF8BA672009D4689E0A70FAB84A")] get { throw new NotSupportedException(); } } [ExtensionMarker("$70E40AF8BA672009D4689E0A70FAB84A")] public LocationID Location_CompleteObjectives_ByLayer { [ExtensionMarker("$70E40AF8BA672009D4689E0A70FAB84A")] get { throw new NotSupportedException(); } } [ExtensionMarker("$70E40AF8BA672009D4689E0A70FAB84A")] public ItemID Item_CompleteObjective_Instance { [ExtensionMarker("$70E40AF8BA672009D4689E0A70FAB84A")] get { throw new NotSupportedException(); } } [ExtensionMarker("$70E40AF8BA672009D4689E0A70FAB84A")] public LocationID Location_SectorClear_Instance { [ExtensionMarker("$70E40AF8BA672009D4689E0A70FAB84A")] get { throw new NotSupportedException(); } } [ExtensionMarker("$70E40AF8BA672009D4689E0A70FAB84A")] public ItemID Item_SectorClear_Instance { [ExtensionMarker("$70E40AF8BA672009D4689E0A70FAB84A")] get { throw new NotSupportedException(); } } } [SpecialName] public sealed class $E93D81478905A37B27DF6F640623743D { [SpecialName] public static class $66441969E171E5CA8C86F896EE40E940 { } [ExtensionMarker("$66441969E171E5CA8C86F896EE40E940")] public LocationID Location_CompleteObjective_Instance { [ExtensionMarker("$66441969E171E5CA8C86F896EE40E940")] get { throw new NotSupportedException(); } } } public static LocationID get_Location_CompleteObjectives(Game.Data data) { return LocationID.From(data, "Complete Objective Locations", (Game.Data data2) => new TagDefinition("Locations checked by completing objectives", CommonTagsHandler_Tags.get_Location_Never(data2))); } public static ItemID get_Item_CompleteObjectives(Game.Data data) { return ItemID.From(data, "Complete Objective Items", (Game.Data data2) => new TagDefinition("Items representing objective completions", CommonTagsHandler_Tags.get_Item_Never(data2))); } public static LocationID get_Location_SectorClears(Game.Data data) { return LocationID.From(data, "Sector Clear Locations", (Game.Data data2) => new TagDefinition("Locations checked by clearing a sector and successfully extracting (or equivalent)", CommonTagsHandler_Tags.get_Location_Never(data2))); } public static ItemID get_Item_SectorClears(Game.Data data) { return ItemID.From(data, "Sector Clear Items", (Game.Data data2) => new TagDefinition("Items awarded by successfully clearing sectors in a cateogry of a particular layer", CommonTagsHandler_Tags.get_Item_Never(data2))); } public static LocationID get_Location_PEClears(Game.Data data) { return LocationID.From(data, "PE Clear Locations", (Game.Data data2) => new TagDefinition("Locations checked by obtaining PE for expeditions", CommonTagsHandler_Tags.get_Location_Never(data2))); } public static ItemID get_Item_PEClears(Game.Data data) { return ItemID.From(data, "PE Clear Items", (Game.Data data2) => new TagDefinition("Items awarded by successfully clearing all sectors of a 3-sector expedition at once", CommonTagsHandler_Tags.get_Item_Never(data2))); } public static LocationID Location_CompleteObjectives_LayerOnly(this Game.Data data, LayerType layer) { return LocationID.From(data, layer.GetName() + " Complete Objective Locations", (Game.Data data2) => new TagDefinition("Locations checked by completing objectives which are part of a particular layer type", default(LocationID))); } public static ItemID Item_CompleteObjectives_LayerOnly(this Game.Data data, LayerType layer) { return ItemID.From(data, layer.GetName() + " Complete Objective Items", (Game.Data data2) => new TagDefinition("Items representing objective completions for a particular layer type", default(ItemID))); } public static LocationID Location_SectorClears_LayerOnly(this Game.Data data, LayerType layer) { return LocationID.From(data, layer.GetName() + " Sector Clear Locations", (Game.Data data2) => new TagDefinition("Locations checked by clearing a particular type of sector and successfully extracting (or equivalent)", default(LocationID))); } public static ItemID Item_SectorClears_LayerOnly(this Game.Data data, LayerType layer) { return ItemID.From(data, layer.GetName() + " Sector Clear Items", (Game.Data data2) => new TagDefinition("Items awarded by successfully clearing a particular type of sector and successfully extracting (or equivalent)", default(ItemID))); } public static RegionID get_Region_PECleared(Expedition.Data data) { return RegionID.From(data, data.ExpeditionName + " PE Cleared", (Expedition.Data data2) => new TagDefinition("Region entered when PE is achieved, only for expeditions with PE", data2.Region_Expedition)); } public static LocationID get_Location_PEClear_Instance(Expedition.Data data) { return LocationID.From(data, data.ExpeditionName + " PE Clear Location", (Expedition.Data data2) => new TagDefinition("Location checked by obtaining PE for a particular expedition", get_Location_PEClears(data2))); } public static ItemID get_Item_PEClear_Instance(Expedition.Data data) { return ItemID.From(data, data.ExpeditionName + " PE Clear Item", (Expedition.Data data2) => new TagDefinition("Item awarded for clearing PE for a particular expedition", get_Item_PEClears(data2)), new SharedObjectiveHandler.PEClearedItem(Expedition.get_Region_AllExpeditions(data))); } public static RegionID get_Region_GoToWin(Layer.Data data) { return RegionID.From(data, data.LayerName + " Go To Win", (Layer.Data data2) => new TagDefinition("Region entered when all layer objectives are completed", data2.Region_Layer)); } public static RegionID get_Region_SectorCleared(Layer.Data data) { return RegionID.From(data, data.LayerName + " Sector Cleared", (Layer.Data data2) => new TagDefinition("Region entered when a particular sector is cleared", data2.Region_Layer)); } public static LocationID get_Location_CompleteObjectives_ByLayer(Layer.Data data) { return LocationID.From(data, data.LayerName + " Complete Objective Locations", (Layer.Data data2) => new TagDefinition("Parent tag of complete objective locations for a particular layer", get_Location_CompleteObjectives(data2), data2.Location_CompleteObjectives_LayerOnly(data2.LayerType))); } public static ItemID get_Item_CompleteObjective_Instance(Layer.Data data) { return ItemID.From(data, data.LayerName + " Complete Objectives", (Layer.Data data2) => new TagDefinition("An objective clear item, indicating one of the objectives was cleared for a particular layer.", get_Item_CompleteObjectives(data2), data2.Item_CompleteObjectives_LayerOnly(data2.LayerType)), new SharedObjectiveHandler.CompleteObjectiveItem(data.Region_Layer)); } public static LocationID get_Location_SectorClear_Instance(Layer.Data data) { return LocationID.From(data, data.LayerName + " Sector Clear Location", (Layer.Data data2) => new TagDefinition("The location of a sector clear item in for a particular layer in a particular expedition", get_Location_SectorClears(data2), data2.Location_SectorClears_LayerOnly(data2.LayerType))); } public static ItemID get_Item_SectorClear_Instance(Layer.Data data) { return ItemID.From(data, data.LayerName + " Sector Clear Item", (Layer.Data data2) => new TagDefinition("The sector clear item for a particular layer in a particular expedition", get_Item_SectorClears(data2), data2.Item_SectorClears_LayerOnly(data2.LayerType)), new SharedObjectiveHandler.SectorClearedItem(data.Region_Layer)); } public static LocationID get_Location_CompleteObjective_Instance(Objective.Data data) { return LocationID.From(data, data.ObjectiveName + " Completed Location", (Objective.Data data2) => new TagDefinition("The location of a particular objective completion item", get_Location_CompleteObjectives_ByLayer(data2))); } } [EnableFeatureByDefault] [AutomatedFeature] public class SharedObjectiveHandler : ArchipelagoFeature { public class CompleteObjectiveItem : Item { public RegionID LayerRegion { get; private init; } public CompleteObjectiveItem(RegionID layer) : base(new ItemData { IsProgression = true }) { LayerRegion = layer; } } public class SectorClearedItem : Item { public RegionID LayerRegion { get; private init; } public SectorClearedItem(RegionID layer) : base(new ItemData { IsProgression = true, IsRandomLike = true }) { LayerRegion = layer; } } public class PEClearedItem : Item { public RegionID ExpeditionRegion { get; private init; } public PEClearedItem(RegionID expedition) : base(new ItemData { IsProgression = true, IsRandomLike = true }) { ExpeditionRegion = expedition; } } [ArchivePatch(/*Could not decode attribute arguments.*/)] public static class RundownManager__OnExpeditionEnded__Patch { public static void Postfix(ExpeditionEndState endState) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Invalid comparison between Unknown and I4 //IL_00a9: Unknown result type (might be due to invalid IL or missing references) //IL_00b0: Invalid comparison between Unknown and I4 if ((int)endState != 0) { FeatureLogger.Debug("Expedition did not end in success. No clears awarded"); return; } StateTracker stateTracker = StateTracker.Get(); Expedition.Data fromCurrentExpedition = Expedition.Data.GetFromCurrentExpedition(); Layer.Data data = Layer.get_MainLayer(fromCurrentExpedition); stateTracker.NotifyFoundRegion(SharedObjectiveHandler_Tags.get_Region_SectorCleared(data), null); stateTracker.NotifyFoundLocation(SharedObjectiveHandler_Tags.get_Location_SectorClear_Instance(data), null); bool flag = false; if (Layer.get_HasSecondary(fromCurrentExpedition)) { if ((int)WardenObjectiveManager.CurrentState.second_status == 40) { flag = true; Layer.Data layer = fromCurrentExpedition.GetLayer(LayerType.Secondary); stateTracker.NotifyFoundLocation(SharedObjectiveHandler_Tags.get_Location_SectorClear_Instance(layer), null); stateTracker.NotifyFoundRegion(SharedObjectiveHandler_Tags.get_Region_SectorCleared(layer), null); } else { FeatureLogger.Debug("Secondary clear not awarded due to it not being cleared"); } } if (!Layer.get_HasOverload(fromCurrentExpedition)) { return; } if ((int)WardenObjectiveManager.CurrentState.third_status == 40) { Layer.Data layer2 = fromCurrentExpedition.GetLayer(LayerType.Overload); stateTracker.NotifyFoundRegion(SharedObjectiveHandler_Tags.get_Region_SectorCleared(layer2), null); stateTracker.NotifyFoundLocation(SharedObjectiveHandler_Tags.get_Location_SectorClear_Instance(fromCurrentExpedition.GetLayer(LayerType.Overload)), null); if (flag) { stateTracker.NotifyFoundRegion(SharedObjectiveHandler_Tags.get_Region_PECleared(fromCurrentExpedition), null); stateTracker.NotifyFoundLocation(SharedObjectiveHandler_Tags.get_Location_PEClear_Instance(fromCurrentExpedition), null); } } else { FeatureLogger.Debug("Overload clear not awarded due to it not being cleared"); } } } private static IArchiveLogger? m_featureLogger; public const string GOAL_CATEGORY = "Goal"; public override string Name => "Shared Objective Handler"; public override string Description => "Handles several items shared by all objectives."; public override FeatureGroup Group => ArchipelagoFeatureGroups.get_ObjectiveHandlers(); public new static IArchiveLogger FeatureLogger { get { return m_featureLogger ?? (m_featureLogger = Plugin.Get().Logger); } set { m_featureLogger = value; } } [Game.Callback] public void AddGoalOptions(Game.Data data) { OptionID condition = data.AddOption(new OptionToggle("Require Mains", "If true, clearing the goal requires clearing all selected expeditions' main layers. Otherwise, it does not.", "Goal", Array.Empty(), 1L, default(OptionID))); data.AddOption(new OptionAddAll(condition, Option.eDictTarget.GoalItems, data.Item_SectorClears_LayerOnly(LayerType.Main))); OptionID condition2 = data.AddOption(new OptionToggle("Require Secondaries", "If true, clearing the goal requires clearing all selected expeditions' secondary layers. Otherwise, it does not.", "Goal", Array.Empty(), 1L, default(OptionID))); data.AddOption(new OptionAddAll(condition2, Option.eDictTarget.GoalItems, data.Item_SectorClears_LayerOnly(LayerType.Secondary))); OptionID condition3 = data.AddOption(new OptionToggle("Require Overloads", "If true, clearing the goal requires clearing all selected expeditions' overload layers. Otherwise, it does not.", "Goal", Array.Empty(), 1L, default(OptionID))); data.AddOption(new OptionAddAll(condition3, Option.eDictTarget.GoalItems, data.Item_SectorClears_LayerOnly(LayerType.Overload))); OptionID condition4 = data.AddOption(new OptionToggle("Require Prisoner Efficiencies", "If true, clearing the goal requires clearing all selected expeditions' Prisoner Efficiencies. Otherwise, it does not.", "Goal", Array.Empty(), 0L, default(OptionID))); data.AddOption(new OptionAddAll(condition4, Option.eDictTarget.GoalItems, SharedObjectiveHandler_Tags.get_Item_PEClears(data))); } [Expedition.Callback] public void AddPrisonerEfficiencyStuffs(Expedition.Data data) { List list = Layer.get_RealLayers(data).ToList(); if (list.Count >= 3) { if (list.Count > 3) { throw new NotSupportedException("Archipelago currently does not support more than 3 layers in reality!"); } RegionID regionID = SharedObjectiveHandler_Tags.get_Region_PECleared(data); data.AddPath(new ReTFO.Archipelago.ModdedInstanceData.Model.Path { StartingRegion = SharedObjectiveHandler_Tags.get_Region_SectorCleared(list[2]), EndingRegion = regionID, Reqs = new ReTFO.Archipelago.ModdedInstanceData.Model.Path.MultiPathReq(ReTFO.Archipelago.ModdedInstanceData.Model.Path.eType.Item, SharedObjectiveHandler_Tags.get_Item_SectorClear_Instance(list[1]), 1u) }); data.Locations.CreateValue(SharedObjectiveHandler_Tags.get_Location_PEClear_Instance(data), regionID, default(LocationData), SharedObjectiveHandler_Tags.get_Item_PEClear_Instance(data)); } } [Layer.Callback] public void AddCommonObjectiveElements(Layer.Data data) { //IL_011d: 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_015f: Invalid comparison between Unknown and I4 List source = data.GetObjectiveDatas().ToList(); if (!source.Any()) { return; } data.AddPath(new ReTFO.Archipelago.ModdedInstanceData.Model.Path { StartingRegion = data.Region_Expedition, EndingRegion = data.Region_Layer }); RegionID regionID = SharedObjectiveHandler_Tags.get_Region_GoToWin(data); data.AddPath(new ReTFO.Archipelago.ModdedInstanceData.Model.Path { StartingRegion = data.Region_Layer, EndingRegion = regionID, Reqs = new ReTFO.Archipelago.ModdedInstanceData.Model.Path.MultiPathReq(ReTFO.Archipelago.ModdedInstanceData.Model.Path.eType.Category, SharedObjectiveHandler_Tags.get_Item_CompleteObjective_Instance(data), (uint)data.GetObjectiveDatas().Count()) }); RegionID regionID2 = SharedObjectiveHandler_Tags.get_Region_SectorCleared(data); if (data.LayerType.IsMainLayer) { data.AddPath(new ReTFO.Archipelago.ModdedInstanceData.Model.Path { StartingRegion = regionID, EndingRegion = regionID2, Reqs = new ReTFO.Archipelago.ModdedInstanceData.Model.Path.MultiPathReq(ReTFO.Archipelago.ModdedInstanceData.Model.Path.eType.Item, ExtractionHandler_Tags.get_Item_Extraction_Instance(data), 1u) }); } else { data.AddPath(new ReTFO.Archipelago.ModdedInstanceData.Model.Path { StartingRegion = regionID, EndingRegion = regionID2, Reqs = new ReTFO.Archipelago.ModdedInstanceData.Model.Path.MultiPathReq(ReTFO.Archipelago.ModdedInstanceData.Model.Path.eType.Item, SharedObjectiveHandler_Tags.get_Item_SectorClear_Instance(Layer.get_MainLayer(data)), 1u) }); } Objective.Data data2 = source.Last(); if ((int)data2.Objective.EventsOnGotoWinTrigger == 0) { WardenObjectiveDataBlock objective = data2.Objective; data.ProcessEvents(regionID, objective.EventsOnGotoWin ?? (objective.EventsOnGotoWin = new List(1))); } else { if ((int)data2.Objective.EventsOnGotoWinTrigger != 1) { throw new ArgumentException("Objective.EventsOnGotoWinTrigger has an unexpected value for expedition: " + data.ExpeditionName); } WardenObjectiveDataBlock objective = data2.Objective; data.ProcessEvents(regionID2, objective.EventsOnGotoWin ?? (objective.EventsOnGotoWin = new List(1))); } data.Locations.CreateValue(SharedObjectiveHandler_Tags.get_Location_SectorClear_Instance(data), regionID2, default(LocationData), SharedObjectiveHandler_Tags.get_Item_SectorClear_Instance(data)); } [Objective.Callback] public void ConnectObjectiveRegions(Objective.Data data) { data.AddPath(new ReTFO.Archipelago.ModdedInstanceData.Model.Path { StartingRegion = data.Region_Layer, EndingRegion = data.Region_Objective }); } public static LocationID AddObjectiveCompleteItem(Objective.Data data, RegionList regions) { LocationID locationID = SharedObjectiveHandler_Tags.get_Location_CompleteObjective_Instance(data); data.Locations.CreateValue(locationID, regions, new LocationData { IsAutoDiscovered = true }, SharedObjectiveHandler_Tags.get_Item_CompleteObjective_Instance(data)); return locationID; } } } namespace ReTFO.Archipelago.Features.FloatingItems { [EnableFeatureByDefault] [InjectToIl2Cpp] public class ArtifactsAndBoostersHandler : ArchipelagoFeature { [ArchivePatch(/*Could not decode attribute arguments.*/)] public static class ArtifactPickup_Core__OnInteractionPickUp__Patch { public static void Postfix(ArtifactPickup_Core __instance, PlayerAgent player) { //IL_001e: 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) if (((Il2CppObjectBase)SNet.Master).Pointer != ((Il2CppObjectBase)player.Owner).Pointer) { return; } int num = BoosterUtils.BoosterCurrencyFromHeatAndArtifactCount((BoosterImplantCategory)__instance.m_artifactCategory, 1f, 1); float num2 = BoosterUtils.BoosterPartsFromCurrency(num); long num3 = (long)((float)GetArtifactValue(__instance.m_artifactCategory) * num2); EnergyLinkHandler.AddEnergy(num3).ContinueWith(delegate(Task t) { if (!t.IsCompletedSuccessfully) { FeatureLogger.Error("Failed to add energy when grabbing artifact!"); if (t.Exception != null) { FeatureLogger.Exception((Exception)t.Exception); } } }); } } [ArchivePatch(/*Could not decode attribute arguments.*/)] public static class PersistentInventoryManager__Setup__Patch { public static void Postfix(PersistentInventoryManager __instance) { ArtifactsAndBoostersHandler feature = ArchipelagoFeatureHelper.GetFeature(); if (feature.m_overwriteCallback == null) { feature.m_overwriteCallback = new Il2CppAction(feature.OverwriteInventory); __instance.OnBoosterImplantInventoryChanged += (Action)feature.m_overwriteCallback; } } } [ArchivePatch(/*Could not decode attribute arguments.*/)] public static class CM_ScrollWindow__SetContentItems__Patch { public static void Prefix(CM_ScrollWindow __instance, List contentItems) { //IL_003f: 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) //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_0058: 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_007c: Unknown result type (might be due to invalid IL or missing references) iScrollWindowContent? obj = contentItems.FirstOrDefault(); CM_BoosterImplantSlotItem val = ((obj != null) ? ((Il2CppObjectBase)obj).TryCast() : null); if (!((Object)(object)val != (Object)null)) { return; } CM_BoosterImplantSlotItem selectedBoosterImplantItem = ((CM_LobbyScrollItem)val).m_parentBar.selectedBoosterImplantItem; if (((selectedBoosterImplantItem != null) ? new BoosterImplantCategory?(selectedBoosterImplantItem.BoosterImplant.Category) : ((BoosterImplantCategory?)null)) != (BoosterImplantCategory?)val.BoosterImplant.Category) { ((CM_LobbyScrollItem)val).m_parentBar.selectedBoosterImplantItem = null; } List boosterImplantInventory = PersistentInventoryManager.GetBoosterImplantInventory(val.BoosterImplant.Category); while (contentItems.Count < boosterImplantInventory.Count) { GameObject val2 = Object.Instantiate(((Component)val).gameObject); CM_BoosterImplantSlotItem component = val2.GetComponent(); ((RectTransformComp)component).Setup(); ((CM_LobbyScrollItem)component).SetupFromLobby(((CM_LobbyScrollItem)val).m_guiAlign, ((CM_LobbyScrollItem)val).m_parentBar, false); component.LoadData(boosterImplantInventory[contentItems.Count]); ((CM_Item)component).ID = (int)component.BoosterInstanceID; ((CM_LobbyScrollItem)component).PlayIntro((float)contentItems.Count, -1); component.SetBackgroundEnabled(true); component.SetIconFromCategory(); ((RectTransformComp)component).SetVisible(true); if (component.IsPreparedSlot) { ((CM_LobbyScrollItem)component).m_parentBar.selectedBoosterImplantItem = component; } contentItems.Add(((Il2CppObjectBase)component).Cast()); } } } [ArchivePatch(/*Could not decode attribute arguments.*/)] public static class PersistentInventoryManager__ApplyPendingBoosterImplantTransactionsToModel__Patch { public static bool Prefix() { PersistentInventoryManager.Current.ClearPendingBoosterImplantTransactions(); return false; } } [ArchivePatch(/*Could not decode attribute arguments.*/)] public static class DropServerManager__NewGameSession__Patch { public static void Prefix(ref uint[] boosterIds) { boosterIds = null; } } [ArchivePatch(/*Could not decode attribute arguments.*/)] public static class DropServerGameSession__ConsumeBoosters__Patch { public static bool Prefix() { return false; } } [InjectToIl2Cpp(typeof(IEnumerator))] public class UpdateCreditRoutine : Object { public CreditCostManager? Manager; public Object Current => (Object)new WaitForSecondsRealtime(3f); public UpdateCreditRoutine(IntPtr ptr) : base(ptr) { } public UpdateCreditRoutine(CreditCostManager manager) : base(ClassInjector.DerivedConstructorPointer()) { ClassInjector.DerivedConstructorBody((Il2CppObjectBase)(object)this); Manager = manager; } public bool MoveNext() { if ((Object)(object)Manager == (Object)null) { return false; } Manager.GetEnergy(); return true; } public void Reset() { } } [InjectToIl2Cpp] public class CreditCostManager : MonoBehaviour { private CM_PlayerLobbyBar? m_lobbyBar; private CM_Item? m_costText; private CM_Item? m_creditText; private Task? m_getEnergyTask; private Coroutine? m_updateRoutine; public CreditCostManager(IntPtr ptr) : base(ptr) { } public static void DoUpdate(CM_PlayerLobbyBar lobbyBar) { CM_ScrollWindowInfoBox infoBox = lobbyBar.m_popupScrollWindow.InfoBox; CM_Item infoAcceptButton = infoBox.m_infoAcceptButton; if (Il2CppType.Of().IsAssignableFrom(((Object)infoBox).GetIl2CppType()) && !((Object)(object)infoAcceptButton == (Object)null)) { CreditCostManager creditCostManager = ((Component)infoAcceptButton).GetComponent(); if ((Object)(object)creditCostManager == (Object)null) { creditCostManager = ((Component)infoAcceptButton).gameObject.AddComponent(); creditCostManager.Setup(lobbyBar); } creditCostManager.GetEnergy(); } } public void Setup(CM_PlayerLobbyBar lobbyBar) { //IL_008d: Unknown result type (might be due to invalid IL or missing references) //IL_0098: Unknown result type (might be due to invalid IL or missing references) //IL_00a3: Unknown result type (might be due to invalid IL or missing references) //IL_00cc: Unknown result type (might be due to invalid IL or missing references) //IL_00d1: Unknown result type (might be due to invalid IL or missing references) //IL_00d8: 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_00ee: Unknown result type (might be due to invalid IL or missing references) //IL_00fa: Expected O, but got Unknown //IL_0188: Unknown result type (might be due to invalid IL or missing references) //IL_0193: Unknown result type (might be due to invalid IL or missing references) //IL_019e: Unknown result type (might be due to invalid IL or missing references) //IL_01c7: Unknown result type (might be due to invalid IL or missing references) //IL_01cc: Unknown result type (might be due to invalid IL or missing references) //IL_01d3: Unknown result type (might be due to invalid IL or missing references) //IL_01de: Unknown result type (might be due to invalid IL or missing references) //IL_01e9: Unknown result type (might be due to invalid IL or missing references) //IL_01f5: Expected O, but got Unknown m_lobbyBar = lobbyBar; CM_ScrollWindowBoosterInfoBox val = ((Il2CppObjectBase)lobbyBar.m_popupScrollWindow.InfoBox).TryCast(); if ((Object)(object)val == (Object)null) { throw new NotImplementedException("Somehow decided to show booster costs on non-booster popup!"); } CM_Item infoAcceptButton = ((CM_ScrollWindowInfoBox)val).m_infoAcceptButton; Transform val2 = ((Component)infoAcceptButton).transform.Find("BoosterCostText"); if ((Object)(object)val2 == (Object)null) { val2 = Object.Instantiate(lobbyBar.m_boosterTraitConditionPrefab).transform; ((Object)((Component)val2).gameObject).name = "BoosterCostText"; val2.SetParent(((Component)infoAcceptButton).transform); val2.localPosition = new Vector3(150f, 52f, 0f); val2.localRotation = Quaternion.identity; val2.localScale = Vector3.one; val2.SetParent(((Component)val).transform, true); m_costText = ((Component)val2).GetComponent(); m_costText.TooltipInfo = new TooltipInfo { UseTooptip = true, TooltipHeader = "Cost", TooltipText = "The amount of energy required to purchase this booster; its value when refunded.", PositionType = (TooltipPositionType)0 }; ((RectTransformComp)m_costText).Setup(); m_costText.SetupCMItem(); m_costText.SetText("Cost: -"); } else { m_costText = ((Component)val2).GetComponent(); } Transform val3 = ((Component)infoAcceptButton).transform.Find("BoosterCreditText"); if ((Object)(object)val3 == (Object)null) { val3 = Object.Instantiate(lobbyBar.m_boosterTraitConditionPrefab).transform; ((Object)((Component)val3).gameObject).name = "BoosterCreditText"; val3.SetParent(((Component)infoAcceptButton).transform); val3.localPosition = new Vector3(150f, 28f, 0f); val3.localRotation = Quaternion.identity; val3.localScale = Vector3.one; val3.SetParent(((Component)val).transform, true); m_creditText = ((Component)val3).GetComponent(); m_creditText.TooltipInfo = new TooltipInfo { UseTooptip = true, TooltipHeader = "Credit", TooltipText = "The total amount of energy available, shared by your team.", PositionType = (TooltipPositionType)0 }; ((RectTransformComp)m_creditText).Setup(); m_creditText.SetupCMItem(); m_creditText.SetText("Credit: -"); } else { m_creditText = ((Component)val3).GetComponent(); } if ((Object)(object)lobbyBar.selectedBoosterImplantItem == (Object)null) { ((Component)m_costText).gameObject.SetActive(false); ((Component)m_creditText).gameObject.SetActive(false); } } public void OnEnable() { //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Expected O, but got Unknown if (m_updateRoutine == null) { m_updateRoutine = ((MonoBehaviour)this).StartCoroutine(new IEnumerator(((Il2CppObjectBase)new UpdateCreditRoutine(this)).Pointer)); } CM_Item? costText = m_costText; if (costText != null) { ((Component)costText).gameObject.SetActive(true); } CM_Item? creditText = m_creditText; if (creditText != null) { ((Component)creditText).gameObject.SetActive(true); } } public void OnDisable() { if (m_updateRoutine != null) { ((MonoBehaviour)this).StopCoroutine(m_updateRoutine); } m_updateRoutine = null; CM_Item? costText = m_costText; if (costText != null) { ((Component)costText).gameObject.SetActive(false); } CM_Item? creditText = m_creditText; if (creditText != null) { ((Component)creditText).gameObject.SetActive(false); } } public void Update() { //IL_00de: Unknown result type (might be due to invalid IL or missing references) //IL_0160: 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_0157: Unknown result type (might be due to invalid IL or missing references) //IL_015c: Unknown result type (might be due to invalid IL or missing references) //IL_0178: Unknown result type (might be due to invalid IL or missing references) //IL_017f: Unknown result type (might be due to invalid IL or missing references) //IL_0186: Unknown result type (might be due to invalid IL or missing references) //IL_0192: Unknown result type (might be due to invalid IL or missing references) if (m_getEnergyTask == null || !m_getEnergyTask.IsCompleted) { return; } Task getEnergyTask = m_getEnergyTask; m_getEnergyTask = null; if (!getEnergyTask.IsCompletedSuccessfully) { FeatureLogger.Error("Failed to retrieve energy while updating energy credit"); if (getEnergyTask.Exception != null) { FeatureLogger.Exception((Exception)getEnergyTask.Exception); } return; } if ((Object)(object)m_lobbyBar == (Object)null || (Object)(object)m_costText == (Object)null || (Object)(object)m_creditText == (Object)null) { Object.Destroy((Object)(object)this); if ((Object)(object)m_costText != (Object)null) { Object.Destroy((Object)(object)((Component)m_costText).gameObject); } if ((Object)(object)m_creditText != (Object)null) { Object.Destroy((Object)(object)((Component)m_creditText).gameObject); } return; } CM_BoosterImplantSlotItem selectedBoosterImplantItem = m_lobbyBar.selectedBoosterImplantItem; BoosterImplant val = ((selectedBoosterImplantItem != null) ? selectedBoosterImplantItem.BoosterImplant : null); if (val != null) { long artifactValue = GetArtifactValue((ArtifactCategory)val.Category); BigInteger result = getEnergyTask.Result; m_costText.SetText($"Cost: {artifactValue}"); m_creditText.SetText($"Credit: {result}"); Color val2 = ((!(result >= artifactValue)) ? Color.red : Color.green); ((Graphic)((Il2CppArrayBase)(object)m_costText.GetTexts())[0]).color = new Color(val2.r, val2.g, val2.b, 0.5f); m_costText.UpdateTextColors(); } } public void GetEnergy() { if (m_getEnergyTask == null) { m_getEnergyTask = EnergyLinkHandler.GetCurrentEnergy(); } } } [ArchivePatch(/*Could not decode attribute arguments.*/)] public static class CM_PlayerLobbyBar__OnBoosterImplantSlotItemSelected__Patch { public static void Postfix(CM_PlayerLobbyBar __instance) { CM_ScrollWindowBoosterInfoBox val = ((Il2CppObjectBase)__instance.m_popupScrollWindow.InfoBox).TryCast(); if (!((Object)(object)val == (Object)null)) { CreditCostManager.DoUpdate(__instance); } } } [ArchivePatch(/*Could not decode attribute arguments.*/)] public static class CM_CM_ScrollWindowInfoBox__SetInfoBox__Patch { public static void Prefix(CM_ScrollWindowInfoBox __instance, ref string acceptText) { if (Il2CppType.Of().IsAssignableFrom(((Object)__instance).GetIl2CppType()) && acceptText != null) { if (acceptText.Contains("Unprepare", StringComparison.OrdinalIgnoreCase)) { acceptText = "Refund"; } else if (acceptText.Contains("Prepare", StringComparison.OrdinalIgnoreCase)) { acceptText = "Purchase"; } } } public static void Postfix(CM_ScrollWindowInfoBox __instance) { if (Il2CppType.Of().IsAssignableFrom(((Object)__instance).GetIl2CppType())) { CM_Item infoRejectButton = __instance.m_infoRejectButton; if (infoRejectButton != null) { ((Component)infoRejectButton).gameObject.SetActive(false); } CreditCostManager.DoUpdate(CM_PlayerLobbyBar.instances[SNet.LocalPlayer.PlayerSlotIndex()]); } } } [ArchivePatch(/*Could not decode attribute arguments.*/)] public static class CM_BoosterImplantSlotItem__PrepareBoosterImplant__Patch { public static bool Prefix(CM_BoosterImplantSlotItem __instance) { //IL_0006: 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_000c: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Expected I4, but got Unknown //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_0029: 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) BoosterImplantCategory category = __instance.BoosterImplant.Category; Task task = EnergyLinkHandler.RequestEnergy(GetArtifactValue((ArtifactCategory)((int)category switch { 0 => 0, 1 => 1, 2 => 2, _ => throw new ArgumentException("Expected booster type to be one of Muted, Bold, or Aggressive"), })), allowCancel: true); task.Wait(); return task.IsCompletedSuccessfully; } } [ArchivePatch(/*Could not decode attribute arguments.*/)] public static class CM_BoosterImplantSlotItem__UnprepareBoosterImplant__Patch { public static void Postfix(CM_BoosterImplantSlotItem __instance) { //IL_0006: 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_000c: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Expected I4, but got Unknown //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_0029: 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) BoosterImplantCategory category = __instance.BoosterImplant.Category; Task task = EnergyLinkHandler.AddEnergy(GetArtifactValue((ArtifactCategory)((int)category switch { 0 => 0, 1 => 1, 2 => 2, _ => throw new ArgumentException("Expected booster type to be one of Muted, Bold, or Aggressive"), }))); } } private static IArchiveLogger? m_featureLogger; private SortedList>? m_cachedImplants; private Il2CppAction? m_overwriteCallback; public override string Name => "Artifacts and Boosters Handler"; public override string Description => "Converts all collected artifacts to shared energy, and allows players to used energy to equip boosters."; public override FeatureGroup Group => ArchipelagoFeatureGroups.get_FloatingHandlers(); public new static IArchiveLogger FeatureLogger { get { return m_featureLogger ?? Plugin.Get().Logger; } set { m_featureLogger = value; } } public IReadOnlyDictionary> CachedImplants { get { RegenerateLists(); return m_cachedImplants; } } public uint NextID { get; protected set; } public override void OnEnable() { base.OnEnable(); if ((Object)(object)PersistentInventoryManager.Current != (Object)null && m_overwriteCallback == null) { m_overwriteCallback = new Il2CppAction(OverwriteInventory); OverwriteInventory(); PersistentInventoryManager.Current.OnBoosterImplantInventoryChanged.Invoke(); PersistentInventoryManager current = PersistentInventoryManager.Current; current.OnBoosterImplantInventoryChanged += (Action)m_overwriteCallback; } } public override void OnDisable() { //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Expected O, but got Unknown //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Expected O, but got Unknown //IL_01bb: Unknown result type (might be due to invalid IL or missing references) //IL_01c5: Expected O, but got Unknown //IL_0286: Unknown result type (might be due to invalid IL or missing references) //IL_0290: Expected O, but got Unknown //IL_0351: Unknown result type (might be due to invalid IL or missing references) //IL_035b: Expected O, but got Unknown base.OnDisable(); if (!((Object)(object)PersistentInventoryManager.Current != (Object)null)) { return; } if (m_overwriteCallback != null) { PersistentInventoryManager current = PersistentInventoryManager.Current; current.OnBoosterImplantInventoryChanged -= (Action)m_overwriteCallback; m_overwriteCallback = null; } PersistentInventoryManager.Current.m_boosterImplantInventory = new BoosterImplantInventoryModel(); CancellationTokenSource val = new CancellationTokenSource(); Task boosterImplantPlayerDataAsync = DropServerManager.Current.GetBoosterImplantPlayerDataAsync(val.Token); ((Task)boosterImplantPlayerDataAsync).Wait(); if (((Task)boosterImplantPlayerDataAsync).IsCanceled || ((Task)boosterImplantPlayerDataAsync).IsFaulted || !boosterImplantPlayerDataAsync.Result.BoosterData.HasValue) { FeatureLogger.Warning("Failed to retrieve actual booster data. Clearing out booster inventory!"); return; } BoosterImplantPlayerData valueOrDefault = boosterImplantPlayerDataAsync.Result.BoosterData.GetValueOrDefault(); BoosterImplantInventoryModel boosterImplantInventory = PersistentInventoryManager.Current.m_boosterImplantInventory; boosterImplantInventory.New = new List(((Il2CppArrayBase)(object)valueOrDefault.New).Count); foreach (uint item in (Il2CppArrayBase)(object)valueOrDefault.New) { boosterImplantInventory.New.Add(item); } ((Il2CppArrayBase)(object)boosterImplantInventory.Categories)[0].Currency = valueOrDefault.Basic.Currency; ((Il2CppArrayBase)(object)boosterImplantInventory.Categories)[0].Missed = valueOrDefault.Basic.Missed; ((Il2CppArrayBase)(object)boosterImplantInventory.Categories)[0].MissedAcknowledged = valueOrDefault.Basic.MissedAck; ((Il2CppArrayBase)(object)boosterImplantInventory.Categories)[0].Inventory = new List(((Il2CppArrayBase)(object)valueOrDefault.Basic.Inventory).Count); foreach (BoosterImplantInventoryItem item2 in (Il2CppArrayBase)(object)valueOrDefault.Basic.Inventory) { ((Il2CppArrayBase)(object)boosterImplantInventory.Categories)[0].Inventory.Add(new BoosterImplantInventoryItem(item2)); } ((Il2CppArrayBase)(object)boosterImplantInventory.Categories)[1].Currency = valueOrDefault.Advanced.Currency; ((Il2CppArrayBase)(object)boosterImplantInventory.Categories)[1].Missed = valueOrDefault.Advanced.Missed; ((Il2CppArrayBase)(object)boosterImplantInventory.Categories)[1].MissedAcknowledged = valueOrDefault.Advanced.MissedAck; ((Il2CppArrayBase)(object)boosterImplantInventory.Categories)[1].Inventory = new List(((Il2CppArrayBase)(object)valueOrDefault.Advanced.Inventory).Count); foreach (BoosterImplantInventoryItem item3 in (Il2CppArrayBase)(object)valueOrDefault.Advanced.Inventory) { ((Il2CppArrayBase)(object)boosterImplantInventory.Categories)[1].Inventory.Add(new BoosterImplantInventoryItem(item3)); } ((Il2CppArrayBase)(object)boosterImplantInventory.Categories)[2].Currency = valueOrDefault.Specialized.Currency; ((Il2CppArrayBase)(object)boosterImplantInventory.Categories)[2].Missed = valueOrDefault.Specialized.Missed; ((Il2CppArrayBase)(object)boosterImplantInventory.Categories)[2].MissedAcknowledged = valueOrDefault.Specialized.MissedAck; ((Il2CppArrayBase)(object)boosterImplantInventory.Categories)[2].Inventory = new List(((Il2CppArrayBase)(object)valueOrDefault.Specialized.Inventory).Count); foreach (BoosterImplantInventoryItem item4 in (Il2CppArrayBase)(object)valueOrDefault.Specialized.Inventory) { ((Il2CppArrayBase)(object)boosterImplantInventory.Categories)[2].Inventory.Add(new BoosterImplantInventoryItem(item4)); } } public void RegenerateLists(bool force = false) { //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_00dc: Unknown result type (might be due to invalid IL or missing references) if (m_cachedImplants != null && !force) { return; } m_cachedImplants?.Clear(); if (m_cachedImplants == null) { m_cachedImplants = new SortedList>(); } NextID = 1u; SortedList> sortedList = new SortedList>(4); foreach (BoosterImplantTemplateDataBlock allBlock in GameDataBlockBase.GetAllBlocks()) { if (!sortedList.TryGetValue(allBlock.ImplantCategory, out var value)) { value = new List(); sortedList[allBlock.ImplantCategory] = value; } foreach (BoosterImplantInventoryItem item in GenerateIdealBoosters(allBlock)) { value.Add(item); } } foreach (KeyValuePair> item2 in sortedList) { m_cachedImplants[item2.Key] = Il2CppReferenceArray.op_Implicit(item2.Value.ToArray()); } } public IEnumerable GenerateIdealBoosters(BoosterImplantTemplateDataBlock template) { BoosterImplantInventoryItem baseItem = new BoosterImplantInventoryItem { Flags = 1u, Effects = new Il2CppStructArray((long)(template.Effects.Count + template.RandomEffects.Count)), Conditions = new Il2CppStructArray((long)(template.Conditions.Count + ((template.RandomConditions.Count > 0) ? 1 : 0))), TemplateId = ((GameDataBlockBase)(object)template).persistentID, UsesRemaining = (int)template.DurationRange.y, Id = 1u }; for (int i = 0; i < template.Conditions.Count; i++) { ((Il2CppArrayBase)(object)((BoosterImplantBase)baseItem).Conditions)[i] = template.Conditions[i]; } for (int j = 0; j < template.Effects.Count; j++) { ((Il2CppArrayBase)(object)((BoosterImplantBase)baseItem).Effects)[j] = new BoosterImplantEffect { Id = template.Effects[j].BoosterImplantEffect, Param = template.Effects[j].MaxValue }; } if (template.RandomConditions.Count == 0) { foreach (BoosterImplantInventoryItem item in GenerateRecursive(0)) { yield return item; } yield break; } Enumerator enumerator2 = template.RandomConditions.GetEnumerator(); while (enumerator2.MoveNext()) { uint current = enumerator2.Current; if (current == 11 && template.RandomConditions.Count > 1) { continue; } ((Il2CppArrayBase)(object)((BoosterImplantBase)baseItem).Conditions)[template.Conditions.Count] = current; foreach (BoosterImplantInventoryItem item2 in GenerateRecursive(0)) { yield return item2; } } IEnumerable GenerateRecursive(int depth) { if (depth >= template.RandomEffects.Count) { BoosterImplantInventoryItem val = new BoosterImplantInventoryItem { Flags = baseItem.Flags, Conditions = Il2CppStructArray.op_Implicit(((IEnumerable)((BoosterImplantBase)baseItem).Conditions).ToArray()), Effects = Il2CppStructArray.op_Implicit(((IEnumerable)((BoosterImplantBase)baseItem).Effects).ToArray()), TemplateId = ((BoosterImplantBase)baseItem).TemplateId, UsesRemaining = ((BoosterImplantBase)baseItem).UsesRemaining }; uint nextID = NextID; NextID = nextID + 1; ((BoosterImplantBase)val).Id = nextID; yield return val; } else { for (int k = 0; k < template.RandomEffects[depth].Count; k++) { if (template.RandomEffects[depth][k].BoosterImplantEffect != 40 || template.RandomEffects[depth].Count <= 1) { ((Il2CppArrayBase)(object)((BoosterImplantBase)baseItem).Effects)[template.Effects.Count + depth] = new BoosterImplantEffect { Id = template.RandomEffects[depth][k].BoosterImplantEffect, Param = template.RandomEffects[depth][k].MaxValue }; foreach (BoosterImplantInventoryItem item3 in GenerateRecursive(depth + 1)) { yield return item3; } } } } } } public static long GetArtifactValue(ArtifactCategory cat) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Expected I4, but got Unknown //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Expected I4, but got Unknown return (int)cat switch { 0 => 40000000000L, 1 => 126000000000L, 2 => 400000000000L, _ => throw new ArgumentException($"Unexpected artifact category: {(int)cat}"), }; } public void OverwriteInventory() { //IL_00c5: Unknown result type (might be due to invalid IL or missing references) //IL_00cf: Expected O, but got Unknown //IL_0139: Unknown result type (might be due to invalid IL or missing references) //IL_0143: Expected O, but got Unknown //IL_01b0: Unknown result type (might be due to invalid IL or missing references) //IL_01ba: Expected O, but got Unknown PersistentInventoryManager current = PersistentInventoryManager.Current; if (((IEnumerable)current.m_boosterImplantInventory.Categories).Sum((Category c) => c.Inventory.Count) == CachedImplants.Sum>>((KeyValuePair> pair) => ((Il2CppArrayBase)(object)pair.Value).Count)) { return; } FeatureLogger.Debug("Overwriting booster inventory"); Il2CppReferenceArray val = CachedImplants[(BoosterImplantCategory)0]; Category val2 = ((Il2CppArrayBase)(object)current.m_boosterImplantInventory.Categories)[0]; val2.Inventory.Clear(); val2.Inventory.EnsureCapacity(((Il2CppArrayBase)(object)val).Length); foreach (BoosterImplantInventoryItem item in (Il2CppArrayBase)(object)val) { val2.Inventory.Add(new BoosterImplantInventoryItem(item)); } val = CachedImplants[(BoosterImplantCategory)1]; val2 = ((Il2CppArrayBase)(object)current.m_boosterImplantInventory.Categories)[1]; val2.Inventory.Clear(); val2.Inventory.EnsureCapacity(((Il2CppArrayBase)(object)val).Length); foreach (BoosterImplantInventoryItem item2 in (Il2CppArrayBase)(object)val) { val2.Inventory.Add(new BoosterImplantInventoryItem(item2)); } val = CachedImplants[(BoosterImplantCategory)2]; val2 = ((Il2CppArrayBase)(object)current.m_boosterImplantInventory.Categories)[2]; val2.Inventory.Clear(); val2.Inventory.EnsureCapacity(((Il2CppArrayBase)(object)val).Length); foreach (BoosterImplantInventoryItem item3 in (Il2CppArrayBase)(object)val) { val2.Inventory.Add(new BoosterImplantInventoryItem(item3)); } current.OnBoosterImplantInventoryChanged.Invoke(); } } public static class FreeCheckpointsHandler_Tags { [SpecialName] public sealed class $2B8804A94F2EF68DF77A343A46EE5A78 { [SpecialName] public static class $55FD246F9BFF39DD56FCB5C25D4DF852 { } [ExtensionMarker("$55FD246F9BFF39DD56FCB5C25D4DF852")] public ItemID Item_Checkpoints { [ExtensionMarker("$55FD246F9BFF39DD56FCB5C25D4DF852")] get { throw new NotSupportedException(); } } [ExtensionMarker("$55FD246F9BFF39DD56FCB5C25D4DF852")] public ItemID Item_FreeCheckpoints { [ExtensionMarker("$55FD246F9BFF39DD56FCB5C25D4DF852")] get { throw new NotSupportedException(); } } } [SpecialName] public sealed class $2833969430CAB23CD70890D67B9ADDD5 { [SpecialName] public static class $5667123F7013DAD37BB214B248F3E5D2 { } [ExtensionMarker("$5667123F7013DAD37BB214B248F3E5D2")] public ItemID Item_FreeCheckpoint_ByExpedition { [ExtensionMarker("$5667123F7013DAD37BB214B248F3E5D2")] get { throw new NotSupportedException(); } } } public static ItemID get_Item_Checkpoints(Game.Data data) { return ItemID.From(data, "Checkpoint Items", (Game.Data data2) => new TagDefinition("Items which trigger a checkpoint", CommonTagsHandler_Tags.get_Item_All(data2))); } public static ItemID get_Item_FreeCheckpoints(Game.Data data) { return ItemID.From(data, "Free Checkpoint Items", (Game.Data data2) => new TagDefinition("Items which trigger an immediate checkpoint when used", get_Item_Checkpoints(data2))); } public static ItemID get_Item_FreeCheckpoint_ByExpedition(Expedition.Data data) { return ItemID.From(data, data.ExpeditionName + " Free Checkpoint", (Expedition.Data data2) => new TagDefinition("Item for a particular expedition which triggers an immediate checkpoint when used", get_Item_FreeCheckpoints(data2)), new FreeCheckpointsHandler.FreeCheckpointItem(data.Region_Expedition)); } } [EnableFeatureByDefault] [AutomatedFeature] public class FreeCheckpointsHandler : ArchipelagoFeature { public class FreeCheckpointItem : TerminalItem { public RegionID ExpeditionRegion { get; private set; } public override RegionID TargetRegion => ExpeditionRegion; public FreeCheckpointItem(RegionID expedition) : base(MakeRandData()) { ExpeditionRegion = expedition; } public static ItemData MakeRandData() { return new ItemData { IsUseful = true }; } public override IEnumerable OnRetrieveFromTerminalSystem(StateTracker stateTracker, LG_ComputerTerminal terminal, ItemID itemId) { yield return delegate { terminal.AddLine((TerminalLineType)4, "Activating <#0F0>CHECKPOINT", 2.5f); }; yield return delegate { //IL_0011: Unknown result type (might be due to invalid IL or missing references) SNet.Capture.CaptureGameState((eBufferType)3); CheckpointManager.StoreCheckpoint(terminal.m_position); terminal.AddLine("<#0F0>CHECKPOINT reached!", true); }; } } private static IArchiveLogger? m_featureLogger; public override string Name => "Unlock Expedition Handler"; public override string Description => "Locks expeditions and adds floating expedition unlock items which unlock them"; public override FeatureGroup Group => ArchipelagoFeatureGroups.get_FloatingHandlers(); public new static IArchiveLogger FeatureLogger { get { return m_featureLogger ?? Plugin.Get().Logger; } set { m_featureLogger = value; } } [Game.Callback] public void AddCheckpointOption(Game.Data data) { ItemID itemID = FreeCheckpointsHandler_Tags.get_Item_FreeCheckpoints(data); data.AddOption(new OptionItemTagOption("Free Checkpoint Randomization", "Controls randomization of the \"free\" checkpoint item in all expeditions. Once found, this item can be used once per expedition attempt to trigger a checkpoint at any terminal. If disabled, it will not be obtainable.\nWhitelist: Enables for all unless blacklisted elsewhere.\nBlacklist: Disables for all.\nNone: Defer to other relevant setting(s). If no other relevant setting is set, defaults to blacklisted.", "Randomization Options", Option.MakeSortKey(data, itemID), 0L, default(OptionID), itemID)); } [Expedition.Callback] public void AddCheckpointItems(Expedition.Data data) { data.AddFloatingItem(data.Region_Expedition, FreeCheckpointsHandler_Tags.get_Item_FreeCheckpoint_ByExpedition(data)); } } public static class LockGearHandler_Tags { [SpecialName] public sealed class $2B8804A94F2EF68DF77A343A46EE5A78 { [SpecialName] public static class $55FD246F9BFF39DD56FCB5C25D4DF852 { } [ExtensionMarker("$55FD246F9BFF39DD56FCB5C25D4DF852")] public ItemID Item_Gear { [ExtensionMarker("$55FD246F9BFF39DD56FCB5C25D4DF852")] get { throw new NotSupportedException(); } } [ExtensionMarker("$55FD246F9BFF39DD56FCB5C25D4DF852")] public ItemID Item_HackingTool { [ExtensionMarker("$55FD246F9BFF39DD56FCB5C25D4DF852")] get { throw new NotSupportedException(); } } [ExtensionMarker("$55FD246F9BFF39DD56FCB5C25D4DF852")] public ItemID Item_Melees { [ExtensionMarker("$55FD246F9BFF39DD56FCB5C25D4DF852")] get { throw new NotSupportedException(); } } [ExtensionMarker("$55FD246F9BFF39DD56FCB5C25D4DF852")] public ItemID Item_MeleeSledgehammers { [ExtensionMarker("$55FD246F9BFF39DD56FCB5C25D4DF852")] get { throw new NotSupportedException(); } } [ExtensionMarker("$55FD246F9BFF39DD56FCB5C25D4DF852")] public ItemID Item_MeleeKnives { [ExtensionMarker("$55FD246F9BFF39DD56FCB5C25D4DF852")] get { throw new NotSupportedException(); } } [ExtensionMarker("$55FD246F9BFF39DD56FCB5C25D4DF852")] public ItemID Item_MeleeSpears { [ExtensionMarker("$55FD246F9BFF39DD56FCB5C25D4DF852")] get { throw new NotSupportedException(); } } [ExtensionMarker("$55FD246F9BFF39DD56FCB5C25D4DF852")] public ItemID Item_MeleeBats { [ExtensionMarker("$55FD246F9BFF39DD56FCB5C25D4DF852")] get { throw new NotSupportedException(); } } [ExtensionMarker("$55FD246F9BFF39DD56FCB5C25D4DF852")] public ItemID Item_Primaries { [ExtensionMarker("$55FD246F9BFF39DD56FCB5C25D4DF852")] get { throw new NotSupportedException(); } } [ExtensionMarker("$55FD246F9BFF39DD56FCB5C25D4DF852")] public ItemID Item_PrimaryGuns { [ExtensionMarker("$55FD246F9BFF39DD56FCB5C25D4DF852")] get { throw new NotSupportedException(); } } [ExtensionMarker("$55FD246F9BFF39DD56FCB5C25D4DF852")] public ItemID Item_PrimaryShotguns { [ExtensionMarker("$55FD246F9BFF39DD56FCB5C25D4DF852")] get { throw new NotSupportedException(); } } [ExtensionMarker("$55FD246F9BFF39DD56FCB5C25D4DF852")] public ItemID Item_Specials { [ExtensionMarker("$55FD246F9BFF39DD56FCB5C25D4DF852")] get { throw new NotSupportedException(); } } [ExtensionMarker("$55FD246F9BFF39DD56FCB5C25D4DF852")] public ItemID Item_SpecialGuns { [ExtensionMarker("$55FD246F9BFF39DD56FCB5C25D4DF852")] get { throw new NotSupportedException(); } } [ExtensionMarker("$55FD246F9BFF39DD56FCB5C25D4DF852")] public ItemID Item_SpecialShotguns { [ExtensionMarker("$55FD246F9BFF39DD56FCB5C25D4DF852")] get { throw new NotSupportedException(); } } [ExtensionMarker("$55FD246F9BFF39DD56FCB5C25D4DF852")] public ItemID Item_Tools { [ExtensionMarker("$55FD246F9BFF39DD56FCB5C25D4DF852")] get { throw new NotSupportedException(); } } [ExtensionMarker("$55FD246F9BFF39DD56FCB5C25D4DF852")] public ItemID Item_Biotrackers { [ExtensionMarker("$55FD246F9BFF39DD56FCB5C25D4DF852")] get { throw new NotSupportedException(); } } [ExtensionMarker("$55FD246F9BFF39DD56FCB5C25D4DF852")] public ItemID Item_MineDeployers { [ExtensionMarker("$55FD246F9BFF39DD56FCB5C25D4DF852")] get { throw new NotSupportedException(); } } [ExtensionMarker("$55FD246F9BFF39DD56FCB5C25D4DF852")] public ItemID Item_CFoamers { [ExtensionMarker("$55FD246F9BFF39DD56FCB5C25D4DF852")] get { throw new NotSupportedException(); } } [ExtensionMarker("$55FD246F9BFF39DD56FCB5C25D4DF852")] public ItemID Item_Sentries { [ExtensionMarker("$55FD246F9BFF39DD56FCB5C25D4DF852")] get { throw new NotSupportedException(); } } [ExtensionMarker("$55FD246F9BFF39DD56FCB5C25D4DF852")] public ItemID Item_Gear_Instance(GearIDRange idRange) { throw new NotSupportedException(); } [ExtensionMarker("$55FD246F9BFF39DD56FCB5C25D4DF852")] public ItemID Item_Gear_ByType(uint itemBaseID) { throw new NotSupportedException(); } [ExtensionMarker("$55FD246F9BFF39DD56FCB5C25D4DF852")] public ItemID Item_Gear_BySlot(InventorySlot slot) { throw new NotSupportedException(); } } public static ItemID get_Item_Gear(Game.Data data) { return ItemID.From(data, "Gear Items", (Game.Data data2) => new TagDefinition("All equippable gear items, including weapons, primaries, specials, tools, and the hacking tool.", CommonTagsHandler_Tags.get_Item_All(data2))); } public static ItemID Item_Gear_Instance(this Game.Data data, GearIDRange idRange) { return ItemID.From(data, LockGearHandler.FormatName(idRange), (Game.Data data2) => new TagDefinition("A specific gear item", data2.Item_Gear_ByType(idRange.GetCompID((eGearComponent)3))), new LockGearHandler.GearItemUnlock(idRange)); } public static ItemID Item_Gear_ByType(this Game.Data data, uint itemBaseID) { switch (itemBaseID) { case 53u: return get_Item_HackingTool(data); case 100u: return get_Item_MeleeSledgehammers(data); case 161u: return get_Item_MeleeKnives(data); case 162u: return get_Item_MeleeSpears(data); case 163u: return get_Item_MeleeBats(data); case 108u: return get_Item_PrimaryGuns(data); case 156u: return get_Item_PrimaryShotguns(data); case 109u: return get_Item_SpecialGuns(data); case 110u: return get_Item_SpecialShotguns(data); case 28u: return get_Item_Biotrackers(data); case 37u: return get_Item_MineDeployers(data); case 73u: return get_Item_CFoamers(data); case 97u: return get_Item_Sentries(data); default: { ItemDataBlock block = GameDataBlockBase.GetBlock(itemBaseID); throw new ArgumentException("Item " + (((block != null) ? block.publicName : null) ?? "NULL") + " is not a gear item type!"); } } } public static ItemID Item_Gear_BySlot(this Game.Data data, InventorySlot slot) { //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_0014: Expected I4, but got Unknown //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Invalid comparison between Unknown and I4 //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Invalid comparison between Unknown and I4 //IL_0057: Unknown result type (might be due to invalid IL or missing references) switch (slot - 1) { default: if ((int)slot != 10) { if ((int)slot == 11) { return get_Item_HackingTool(data); } throw new ArgumentException($"{slot} is not a recognized invetory slot!"); } return get_Item_Melees(data); case 0: return get_Item_Primaries(data); case 1: return get_Item_Specials(data); case 2: return get_Item_Tools(data); } } public static ItemID get_Item_HackingTool(Game.Data data) { return ItemID.From(data, "Hacking Tool", (Game.Data data2) => new TagDefinition("Special gear category for the hacking tool", CommonTagsHandler_Tags.get_Item_Never(data2))); } public static ItemID get_Item_Melees(Game.Data data) { return ItemID.From(data, "Melee Gear Items", (Game.Data data2) => new TagDefinition("All equippable gear items in the melee slot", get_Item_Gear(data2))); } public static ItemID get_Item_MeleeSledgehammers(Game.Data data) { return ItemID.From(data, "Melee Sledgehammer Items", (Game.Data data2) => new TagDefinition("All melee gear considered to be a sledgehammer", get_Item_Melees(data2))); } public static ItemID get_Item_MeleeKnives(Game.Data data) { return ItemID.From(data, "Melee Knife Items", (Game.Data data2) => new TagDefinition("All melee gear considered to be a knife", get_Item_Melees(data2))); } public static ItemID get_Item_MeleeSpears(Game.Data data) { return ItemID.From(data, "Melee Spear Items", (Game.Data data2) => new TagDefinition("All melee gear considered to be a spear", get_Item_Melees(data2))); } public static ItemID get_Item_MeleeBats(Game.Data data) { return ItemID.From(data, "Melee Bat Items", (Game.Data data2) => new TagDefinition("All melee gear considered to be a bat", get_Item_Melees(data2))); } public static ItemID get_Item_Primaries(Game.Data data) { return ItemID.From(data, "Primary Gear Items", (Game.Data data2) => new TagDefinition("All equippable gear items in the primary slot", get_Item_Gear(data2))); } public static ItemID get_Item_PrimaryGuns(Game.Data data) { return ItemID.From(data, "Primary Gun Items", (Game.Data data2) => new TagDefinition("Equippable items in the primary slot which are considered guns", get_Item_Primaries(data2))); } public static ItemID get_Item_PrimaryShotguns(Game.Data data) { return ItemID.From(data, "Primary Shotgun Items", (Game.Data data2) => new TagDefinition("Equippable items in the primary slot which are considered shotguns", get_Item_PrimaryGuns(data2))); } public static ItemID get_Item_Specials(Game.Data data) { return ItemID.From(data, "Special Gear Items", (Game.Data data2) => new TagDefinition("All equippable gear items in the special slot", get_Item_Gear(data2))); } public static ItemID get_Item_SpecialGuns(Game.Data data) { return ItemID.From(data, "Special Gun Items", (Game.Data data2) => new TagDefinition("Equippable items in the special slot which are considered guns", get_Item_Specials(data2))); } public static ItemID get_Item_SpecialShotguns(Game.Data data) { return ItemID.From(data, "Special Shotgun Items", (Game.Data data2) => new TagDefinition("Equippable items in the special slot which are considered shotguns", get_Item_Specials(data2))); } public static ItemID get_Item_Tools(Game.Data data) { return ItemID.From(data, "Tool Gear Items", (Game.Data data2) => new TagDefinition("All equippable gear items in the tool slot (also known as the class slot)", get_Item_Gear(data2))); } public static ItemID get_Item_Biotrackers(Game.Data data) { return ItemID.From(data, "Biotracker Items", (Game.Data data2) => new TagDefinition("All equippable gear items in the tool slot considered to be a biotracker", get_Item_Tools(data2))); } public static ItemID get_Item_MineDeployers(Game.Data data) { return ItemID.From(data, "Mine Deployer Items", (Game.Data data2) => new TagDefinition("All equippable gear items in the tool slot considered to be a mine deployer", get_Item_Tools(data2))); } public static ItemID get_Item_CFoamers(Game.Data data) { return ItemID.From(data, "C-foam Items Items", (Game.Data data2) => new TagDefinition("All equippable gear items in the tool slot considered to be a CFoam launcher", get_Item_Tools(data2))); } public static ItemID get_Item_Sentries(Game.Data data) { return ItemID.From(data, "Sentry Items", (Game.Data data2) => new TagDefinition("All equippable gear items in the tool slot considered to be a deployable sentry", get_Item_Tools(data2))); } } [EnableFeatureByDefault] [AutomatedFeature] public class LockGearHandler : ArchipelagoFeature { public class GearItemUnlock : Item { public GearIDRange IDRange { get; private init; } public GearItemUnlock(GearIDRange idRange) : base(MakeRandData()) { IDRange = idRange; } public static ItemData MakeRandData() { return new ItemData { IsUseful = true, IsCollectedByDefault = true }; } public override void OnItemObtained(StateTracker stateTracker, LocationID sourceLocationId, PlayerAgent? player, ItemID itemId) { AddGear(stateTracker, IDRange, itemId); stateTracker.AddItemToTerminal(itemId); } public override void OnItemLost(StateTracker stateTracker, ItemID itemId) { RemoveGear(IDRange); } public override IEnumerable OnRetrieveFromTerminalSystem(StateTracker stateTracker, LG_ComputerTerminal terminal, ItemID itemId) { SNet_Player player = terminal.m_syncedInteractionSource.Owner; yield return delegate { terminal.AddLine((TerminalLineType)2, "Retrieving your gear...", 2f); }; yield return delegate { PlayerBackpack val = default(PlayerBackpack); if (!PlayerBackpackManager.TryGetBackpack(player, ref val)) { FeatureLogger.Error("Failed to get player backpack while giving gear!"); terminal.AddLine("<#F00>Failed to retrieve your gear! It has been re-added to terminal system.", true); } SetPlayerGear(player, IDRange); terminal.AddLine("Gear item \"" + IDRange.PublicGearName + "\" has been given to " + player.NickName, true); }; } } [ArchivePatch(/*Could not decode attribute arguments.*/)] public static class PlayerBackpackManager__EquipBotGear__Patch { private static List> m_lastEquippedGear = new List>(); public static void Prefix(SNet_Player bot, ref GearIDRange gearSetup) { //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Expected I4, but got Unknown //IL_0079: Unknown result type (might be due to invalid IL or missing references) //IL_0083: Expected I4, but got Unknown //IL_00ae: Unknown result type (might be due to invalid IL or missing references) //IL_00b8: Expected I4, but got Unknown GearIDRange localGear = gearSetup; ItemDataBlock block = GameDataBlockBase.GetBlock(gearSetup.GetCompID((eGearComponent)3)); int index = bot.CharacterSlot.index; int num = (int)block.inventorySlot; while (m_lastEquippedGear.Count <= index) { m_lastEquippedGear.Add(new List()); } List list = m_lastEquippedGear[index]; while (list.Count <= num) { list.Add(null); } if (!((Il2CppArrayBase>)(object)GearManager.Current.m_gearPerSlot)[(int)block.inventorySlot].Any((GearIDRange g) => g.IsEqual(localGear))) { gearSetup = list[num] ?? ((Il2CppArrayBase>)(object)GearManager.Current.m_gearPerSlot)[(int)block.inventorySlot].First(); } list[num] = gearSetup; } } private static IArchiveLogger? m_featureLogger; public const string GEAR_OPTION_CATEGORY = "Gear"; public override string Name => "Lock Gear Handler"; public override string Description => "Disables player gear items and adds floating items which re-enables them"; public override FeatureGroup Group => ArchipelagoFeatureGroups.get_FloatingHandlers(); public new static IArchiveLogger FeatureLogger { get { return m_featureLogger ?? Plugin.Get().Logger; } set { m_featureLogger = value; } } [Game.Callback] public void AddGearItems(Game.Data data) { //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Invalid comparison between Unknown and I4 //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Expected O, but got Unknown //IL_007c: Unknown result type (might be due to invalid IL or missing references) //IL_0083: Expected O, but got Unknown //IL_0095: Unknown result type (might be due to invalid IL or missing references) //IL_00a6: 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) SortedList sortedList = new SortedList(); foreach (PlayerOfflineGearDataBlock allBlock in GameDataBlockBase.GetAllBlocks()) { if ((int)allBlock.Type == 0 || (int)allBlock.Type == 3 || !((GameDataBlockBase)(object)allBlock).internalEnabled) { continue; } ItemID itemID = data.Item_Gear_Instance(new GearIDRange(allBlock.GearJSON)); data.AddFloatingItem(data.Region_Menu, itemID); if (!data.Items.IsChild(itemID, CommonTagsHandler_Tags.get_Item_Never(data))) { GearIDRange val = new GearIDRange(allBlock.GearJSON); ItemDataBlock block = GameDataBlockBase.GetBlock(val.GetCompID((eGearComponent)3)); if (!sortedList.TryGetValue(block.inventorySlot, out var value)) { value = MakeOptionsForSlot(data, block.inventorySlot); sortedList.Add(block.inventorySlot, value); } value.ChoiceNames.Add(data.Items.LookUpName(itemID)); value.ChoiceValues.Add(itemID.ID); } } } private static OptionChoice MakeOptionsForSlot(Game.Data data, InventorySlot slot) { //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_0014: Expected I4, but got Unknown //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Invalid comparison between Unknown and I4 //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Unknown result type (might be due to invalid IL or missing references) string text = (slot - 1) switch { 0 => "Primary Gear", 1 => "Special Gear", 2 => "Tool Gear", _ => ((int)slot != 10) ? (Enum.GetName(slot) + " Gear") : "Melee Gear", }; ItemID itemID = data.Item_Gear_BySlot(slot); uint[] categorySort = Option.MakeSortKey(data, itemID); OptionID optionID = data.AddOption(new OptionRange("Number of Unlocked " + text, "Randomly selects the chosen number of " + text.ToLower() + " and adds it to your starting inventory. You may also set this to -1 to start with all gear in this slot unlocked. GTFO does not support zero gear items in a slot; ensure at least one item is selected here or below.", "Gear", categorySort, 1L, default(OptionID), -1f, 99f)); OptionID optionID2 = data.AddOption(new OptionDoesNotEqualOperation(optionID, -1L)); OptionParameter tag = itemID; data.AddOption(new OptionAddToSet(optionID2, Option.eSetTarget.ItemWhitelist, tag)); data.AddOption(new OptionAddToSet(tag: itemID, condition: data.AddOption(new OptionNotOperation(optionID2)), target: Option.eSetTarget.ItemBlacklist)); tag = itemID; OptionParameter count = optionID; data.AddOption(new OptionAddCount(optionID2, Option.eDictTarget.StartVouchers, tag, count)); OptionChoice result; OptionID optionID3 = data.AddOption(result = new OptionChoice("Starting " + text, "The chosen gear item is guaranteed to be unlocked at start (in addition to the randomly-selected gear items). You may also choose \"None\" to not add an item.", "Gear", categorySort, default(ItemID).ID, optionID2, new List { "None" }, new List { default(ItemID).ID })); count = optionID3; data.AddOption(new OptionAddToSet(optionID2, Option.eSetTarget.ItemBlacklist, count)); OptionID optionID4 = data.AddOption(new OptionRange("Early " + text, "Randomly selects the chosen amount of " + text.ToLower() + " and adds it to the early items list, ensuring it spawns somewhere it can be reached before any player picks up any item.\nNote: GTFO has a limited amount of space for early items. Adding too many early items many result in FILL errors!", "Gear", categorySort, 0L, optionID2, 0f, 99f)); count = itemID; tag = optionID4; data.AddOption(new OptionAddCount(optionID2, Option.eDictTarget.EarlyItems, count, tag)); return result; } public static string FormatName(GearIDRange idRange) { string text = idRange.PublicGearName.ToString(); GearCategoryDataBlock block = GameDataBlockBase.GetBlock(idRange.GetCompID((eGearComponent)2)); if (block != null) { text = ((Object)block.PublicName).ToString(); ArchetypeDataBlock block2 = GameDataBlockBase.GetBlock(idRange.GetCompID((eGearComponent)1) switch { 2u => block.AutoArchetype, 1u => block.BurstArchetype, 0u => block.SemiArchetype, 3u => block.SemiBurstArchetype, 11u => 57u, 12u => 55u, 10u => 54u, 13u => 58u, _ => 0u, }); if (block2 != null) { text = ((Object)block2.PublicName).ToString(); } } return text + " (" + idRange.PublicGearName + ")"; } private static void AddGear(StateTracker stateTracker, GearIDRange idRange, ItemID itemId = default(ItemID)) { //IL_0034: 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_0044: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Expected I4, but got Unknown Game.Data gameData = stateTracker.GameData; if (itemId.IsNull) { gameData.Items.TryLookUpID(FormatName(idRange), out itemId); } InventorySlot inventorySlot = GameDataBlockBase.GetBlock(idRange.GetCompID((eGearComponent)3)).inventorySlot; List val = ((Il2CppArrayBase>)(object)GearManager.Current.m_gearPerSlot)[(int)inventorySlot]; GearIDRange val2 = null; if (val.Count == 1 && gameData.Items.TryLookUpID(FormatName(val[0]), out var id)) { int valueOrDefault = stateTracker.CollectedItemCounts.GetValueOrDefault(id, 0); if (valueOrDefault == 0) { val2 = val[0]; } else if (id.Equals(itemId) && valueOrDefault == 1) { return; } } uint num = (itemId.IsNull ? uint.MaxValue : itemId.ID); bool flag = false; for (int i = 0; i < val.Count; i++) { ItemID id2; uint num2 = ((!gameData.Items.TryLookUpID(FormatName(val[i]), out id2)) ? uint.MaxValue : id2.ID); if (num < num2) { val.Insert(i, idRange); flag = true; break; } } if (!flag) { val.Add(idRange); } if (val2 != null) { RemoveGear(val2); } } private static void RemoveGear(GearIDRange idRange) { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Expected I4, but got Unknown //IL_0079: Unknown result type (might be due to invalid IL or missing references) //IL_014a: Unknown result type (might be due to invalid IL or missing references) //IL_0150: Expected I4, but got Unknown //IL_00a9: Unknown result type (might be due to invalid IL or missing references) //IL_00b2: Unknown result type (might be due to invalid IL or missing references) //IL_00b8: Invalid comparison between Unknown and I4 //IL_00c1: Unknown result type (might be due to invalid IL or missing references) //IL_00c7: Expected O, but got Unknown //IL_00d3: Unknown result type (might be due to invalid IL or missing references) //IL_00d8: 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_01bd: Expected I4, but got Unknown InventorySlot inventorySlot = GameDataBlockBase.GetBlock(idRange.GetCompID((eGearComponent)3)).inventorySlot; List val = ((Il2CppArrayBase>)(object)GearManager.Current.m_gearPerSlot)[(int)inventorySlot]; int i; for (i = 0; i < val.Count && !val[i].IsEqual(idRange); i++) { } if (i != val.Count) { val.RemoveAt(i); } else { FeatureLogger.Warning("Failed to remove gear item during OnItemLost"); } if (val.Count == 0) { FeatureLogger.Warning("Removed all player gear from slot " + Enum.GetName(inventorySlot) + "; restoring first entry to prevent bugs..."); GearIDRange val2 = null; foreach (PlayerOfflineGearDataBlock allBlock in GameDataBlockBase.GetAllBlocks()) { if ((int)allBlock.Type != 0 && (int)allBlock.Type != 3) { val2 = new GearIDRange(allBlock.GearJSON); if (GameDataBlockBase.GetBlock(val2.GetCompID((eGearComponent)3)).inventorySlot == inventorySlot) { break; } val2 = null; } } if (val2 == null) { FeatureLogger.Error("Somehow did not find a replacment gear item!"); val2 = idRange; } val.Add(val2); } else { for (i = 0; i < val.Count; i++) { if (val[i].IsEqual(idRange)) { return; } } } if (SNet.LobbyPlayers.Count == 0) { if (((Il2CppArrayBase)(object)PlayerBackpackManager.LocalBackpack.Slots)[(int)inventorySlot].GearIDRange.IsEqual(idRange)) { SetPlayerGear(SNet.LocalPlayer, val[0]); } return; } Enumerator enumerator2 = SNet.Slots.SlottedPlayers.GetEnumerator(); while (enumerator2.MoveNext()) { SNet_Player current2 = enumerator2.Current; if (current2.IsLocal || (SNet.IsMaster && current2.IsBot)) { PlayerBackpack backpack = PlayerBackpackManager.GetBackpack(current2); if (((Il2CppArrayBase)(object)backpack.Slots)[(int)inventorySlot].GearIDRange.IsEqual(idRange)) { SetPlayerGear(current2, val[0]); } } } } private static void SetPlayerGear(SNet_Player player, GearIDRange desiredGear) { //IL_008e: 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_00b4: Unknown result type (might be due to invalid IL or missing references) //IL_00ba: Expected I4, but got Unknown //IL_00ba: Unknown result type (might be due to invalid IL or missing references) //IL_00c0: Invalid comparison between Unknown and I4 //IL_00c3: Unknown result type (might be due to invalid IL or missing references) //IL_012e: Unknown result type (might be due to invalid IL or missing references) //IL_013c: Unknown result type (might be due to invalid IL or missing references) //IL_0142: Expected I4, but got Unknown //IL_016e: 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_0193: Unknown result type (might be due to invalid IL or missing references) //IL_01a6: Expected I4, but got Unknown //IL_0177: Unknown result type (might be due to invalid IL or missing references) //IL_017d: Invalid comparison between Unknown and I4 //IL_0181: Unknown result type (might be due to invalid IL or missing references) //IL_0187: Invalid comparison between Unknown and I4 //IL_01db: Unknown result type (might be due to invalid IL or missing references) //IL_01f1: Unknown result type (might be due to invalid IL or missing references) FeatureLogger.Debug($"Attempting to give \"{player.NickName}\" gear item \"{desiredGear.PublicGearName}\""); if (!player.IsLocal && (!player.IsBot || !SNet.IsMaster)) { FeatureLogger.Debug("Cancelled -> That player is not locally owned!"); return; } ItemDataBlock block = GameDataBlockBase.GetBlock(desiredGear.GetCompID((eGearComponent)3)); InventorySlot inventorySlot = block.inventorySlot; PlayerBackpack backpack = PlayerBackpackManager.GetBackpack(player); SNet_IPlayerAgent playerAgent = player.PlayerAgent; PlayerAgent val = ((playerAgent != null) ? ((Il2CppObjectBase)playerAgent).Cast() : null); Item val2 = default(Item); if ((int)((Il2CppArrayBase)(object)backpack.Slots)[(int)inventorySlot].Status == 1 && backpack.TryGetDeployedItem(inventorySlot, ref val2)) { FeatureLogger.Debug("Detected that gear being replaced is deployed. Attempting to pick up as a sentry gun..."); SentryGunInstance val3 = ((Il2CppObjectBase)val2).TryCast(); if ((Object)(object)val3 == (Object)null) { FeatureLogger.Debug("Failed to pick up sentry gun while changing gear!"); } else { ((ItemEquippable)val3).PickUp(val); } } if (player.IsBot) { PlayerBackpackManager.EquipBotGear(player, desiredGear); } else if (player.IsLocal) { PlayerBackpackManager.EquipLocalGear(desiredGear); } else { PlayerBackpackManager.Current.EquipSyncGear(inventorySlot, desiredGear, player); } Item instance = ((Il2CppArrayBase)(object)backpack.Slots)[(int)inventorySlot].Instance; ItemEquippable val4 = ((Il2CppObjectBase)instance).TryCast(); if ((Object)(object)val4 == (Object)null) { FeatureLogger.Warning("Failed to identify newly spawned gear as equippable. Skipping relevant calls."); } else if ((int)val4.AmmoType == 0 || (int)val4.AmmoType == 1 || (int)val4.AmmoType == 2) { AmmoType ammoType = val4.AmmoType; float num = 0.5f * (int)ammoType switch { 0 => 460f, 1 => 230f, 2 => 150f, _ => throw new ArgumentException(), }; if (backpack.AmmoStorage.GetAmmoInPack(val4.AmmoType) < num) { backpack.AmmoStorage.SetAmmo(val4.AmmoType, num); } BulletWeapon val5 = ((Il2CppObjectBase)val4).TryCast(); if ((Object)(object)val5 != (Object)null) { ((ItemEquippable)val5).SetCurrentClipRel(1f); } } } } public static class LockLobbySlotsHandler_Tags { [SpecialName] public sealed class $2B8804A94F2EF68DF77A343A46EE5A78 { [SpecialName] public static class $55FD246F9BFF39DD56FCB5C25D4DF852 { } [ExtensionMarker("$55FD246F9BFF39DD56FCB5C25D4DF852")] public ItemID Item_LobbySlotUnlocks { [ExtensionMarker("$55FD246F9BFF39DD56FCB5C25D4DF852")] get { throw new NotSupportedException(); } } [ExtensionMarker("$55FD246F9BFF39DD56FCB5C25D4DF852")] public ItemID Item_LobbySlotUnlock_Instance(int index) { throw new NotSupportedException(); } } public static ItemID get_Item_LobbySlotUnlocks(Game.Data data) { return ItemID.From(data, "Unlock Lobby Slot Items", (Game.Data data2) => new TagDefinition("Items which unlock more lobby slots", CommonTagsHandler_Tags.get_Item_All(data2))); } public static ItemID Item_LobbySlotUnlock_Instance(this Game.Data data, int index) { return ItemID.From(data, $"Lobby Slot #{index} Unlock", (Game.Data data2) => new TagDefinition("Item which unlocks a particular lobby slot", get_Item_LobbySlotUnlocks(data2)), new LockLobbySlotsHandler.LobbySlotUnlockItem(index)); } } [EnableFeatureByDefault] [AutomatedFeature] public class LockLobbySlotsHandler : ArchipelagoFeature { public class LobbySlotUnlockItem : Item { public int Index { get; private init; } public LobbySlotUnlockItem(int index) : base(MakeRandData()) { Index = index; } public static ItemData MakeRandData() { return new ItemData { IsUseful = true, IsCollectedByDefault = true }; } public void LockButtonNow() { //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_002c: 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_0066: 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_0072: 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) //IL_008e: 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_00c4: Unknown result type (might be due to invalid IL or missing references) //IL_00ca: Unknown result type (might be due to invalid IL or missing references) //IL_00dc: Unknown result type (might be due to invalid IL or missing references) //IL_00e6: Unknown result type (might be due to invalid IL or missing references) //IL_0116: Unknown result type (might be due to invalid IL or missing references) //IL_011c: 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_0134: Unknown result type (might be due to invalid IL or missing references) //IL_013e: 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) CM_PlayerLobbyBar val = ((Il2CppArrayBase)(object)MainMenuGuiLayer.Current.PageLoadout.m_playerLobbyBars)[Index]; TextMeshPro component = ((Component)val.m_permissionButton).GetComponent(); Color grey = Color.grey; grey.a = 0.4f; ((Graphic)component).color = grey; if ((((Il2CppArrayBase)(object)val.m_permissionButton.m_textColorOrg)?.Count ?? 0) > 0) { ((Il2CppArrayBase)(object)val.m_permissionButton.m_textColorOrg)[0] = new Color(grey.r, grey.g, grey.b, ((Il2CppArrayBase)(object)val.m_permissionButton.m_textColorOrg)[0].a); } if ((((Il2CppArrayBase)(object)val.m_permissionButton.m_textColorOut)?.Count ?? 0) > 0) { ((Il2CppArrayBase)(object)val.m_permissionButton.m_textColorOut)[0] = new Color(grey.r, grey.g, grey.b, ((Il2CppArrayBase)(object)val.m_permissionButton.m_textColorOut)[0].a); } if ((((Il2CppArrayBase)(object)val.m_permissionButton.m_textColorOver)?.Count ?? 0) > 0) { ((Il2CppArrayBase)(object)val.m_permissionButton.m_textColorOver)[0] = new Color(grey.r, grey.g, grey.b, ((Il2CppArrayBase)(object)val.m_permissionButton.m_textColorOver)[0].a); } foreach (SpriteRenderer componentsInChild in ((Component)val.m_permissionButton).GetComponentsInChildren()) { componentsInChild.color = grey; } val.OnPermissionButtonPressed = null; } public void UnlockButtonNow() { //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0020: 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_0066: 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_0072: 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) //IL_008e: 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_00c4: Unknown result type (might be due to invalid IL or missing references) //IL_00ca: Unknown result type (might be due to invalid IL or missing references) //IL_00dc: Unknown result type (might be due to invalid IL or missing references) //IL_00e6: Unknown result type (might be due to invalid IL or missing references) //IL_0116: Unknown result type (might be due to invalid IL or missing references) //IL_011c: 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_0134: Unknown result type (might be due to invalid IL or missing references) //IL_013e: Unknown result type (might be due to invalid IL or missing references) //IL_0167: Unknown result type (might be due to invalid IL or missing references) //IL_0184: Unknown result type (might be due to invalid IL or missing references) //IL_0189: Unknown result type (might be due to invalid IL or missing references) //IL_0199: Unknown result type (might be due to invalid IL or missing references) //IL_01a1: Expected O, but got Unknown CM_PlayerLobbyBar val = ((Il2CppArrayBase)(object)MainMenuGuiLayer.Current.PageLoadout.m_playerLobbyBars)[Index]; Color red = Color.red; red.a = 0.4f; TextMeshPro component = ((Component)val.m_permissionButton).GetComponent(); ((Graphic)component).color = red; if ((((Il2CppArrayBase)(object)val.m_permissionButton.m_textColorOrg)?.Count ?? 0) > 0) { ((Il2CppArrayBase)(object)val.m_permissionButton.m_textColorOrg)[0] = new Color(red.r, red.g, red.b, ((Il2CppArrayBase)(object)val.m_permissionButton.m_textColorOrg)[0].a); } if ((((Il2CppArrayBase)(object)val.m_permissionButton.m_textColorOut)?.Count ?? 0) > 0) { ((Il2CppArrayBase)(object)val.m_permissionButton.m_textColorOut)[0] = new Color(red.r, red.g, red.b, ((Il2CppArrayBase)(object)val.m_permissionButton.m_textColorOut)[0].a); } if ((((Il2CppArrayBase)(object)val.m_permissionButton.m_textColorOver)?.Count ?? 0) > 0) { ((Il2CppArrayBase)(object)val.m_permissionButton.m_textColorOver)[0] = new Color(red.r, red.g, red.b, ((Il2CppArrayBase)(object)val.m_permissionButton.m_textColorOver)[0].a); } foreach (SpriteRenderer componentsInChild in ((Component)val.m_permissionButton).GetComponentsInChildren()) { componentsInChild.color = red; } __c__DisplayClass29_0 val2 = new __c__DisplayClass29_0 { __4__this = MainMenuGuiLayer.Current.PageLoadout, bar = val }; IntPtr il2CppMethod = IL2CPP.GetIl2CppMethod(((Il2CppObjectBase)val2).ObjectClass, false, "b__7", typeof(void).FullName, new string[1] { typeof(int).FullName }); val.OnPermissionButtonPressed = new Action((Object)(object)val2, il2CppMethod); } public override void OnItemObtained(StateTracker stateTracker, LocationID sourceLocationId, PlayerAgent? player = null, ItemID itemId = default(ItemID)) { UnlockButtonNow(); } public override void OnItemLost(StateTracker stateTracker, ItemID itemId = default(ItemID)) { SNet.Slots.SetSlotPermission(Index, (SlotPermission)1); SNet_Player player = ((Il2CppArrayBase)(object)SNet.Slots.CharacterSlots)[Index].player; if ((Object)(object)player != (Object)null) { SNet.Slots.RemoveFromPlayersInGame(player); } LockButtonNow(); } } [ArchivePatch(/*Could not decode attribute arguments.*/)] public static class SNet_PlayerSlotManager__GetSlotPermission__Patch { public static bool Prefix(SNet_PlayerSlotManager __instance, int playerIndex) { if (playerIndex == 0) { return true; } StateTracker stateTracker = StateTracker.Get(); Game.Data processedGameData = stateTracker.MidManager.GetProcessedGameData(); ItemID itemID = processedGameData.Item_LobbySlotUnlock_Instance(playerIndex); if (stateTracker.CollectedItemCounts.GetValueOrDefault(itemID, 0) > 0) { return true; } if (!processedGameData.Items.LookUpValueChecked(itemID).RandData.CanBeRandomized) { return true; } ((Il2CppArrayBase)(object)__instance.m_playerSlotPermissions)[playerIndex] = (SlotPermission)1; return false; } } [ArchivePatch(/*Could not decode attribute arguments.*/)] public static class CM_PlayerLobbyBar__SetupSlot__Patch { public static void Postfix(CM_PlayerLobbyBar __instance, int pillarIndex) { if (pillarIndex != 0) { StateTracker stateTracker = StateTracker.Get(); Game.Data processedGameData = stateTracker.MidManager.GetProcessedGameData(); ItemID itemID = processedGameData.Item_LobbySlotUnlock_Instance(pillarIndex); Item item = processedGameData.Items.LookUpValueChecked(itemID); if (stateTracker.CollectedItemCounts.GetValueOrDefault(itemID, 0) <= 0 && item.RandData.CanBeRandomized) { item.OnItemLost(stateTracker, itemID); } } } } private static IArchiveLogger? m_featureLogger; public const string LOBBY_SLOT_OPTION_CATEGORY = "Lobby Slots"; public override string Name => "Lock Lobby Spots Handler"; public override string Description => "Locks lobby slots and forces players to find specific items to unlock them"; public override FeatureGroup Group => ArchipelagoFeatureGroups.get_FloatingHandlers(); public new static IArchiveLogger FeatureLogger { get { return m_featureLogger ?? Plugin.Get().Logger; } set { m_featureLogger = value; } } [Game.Callback] public void AddSlotUnlockItems(Game.Data data) { for (int i = 1; i < ((Il2CppArrayBase)(object)SNet.Slots.CharacterSlots).Count; i++) { data.AddFloatingItem(data.Region_Menu, data.Item_LobbySlotUnlock_Instance(i)); } ItemID itemID = LockLobbySlotsHandler_Tags.get_Item_LobbySlotUnlocks(data); uint[] categorySort = Option.MakeSortKey(data, itemID); OptionID optionID = data.AddOption(new OptionRange("Number of Unlocked Lobby Slots", "The number of lobby slots which will be unlocked when the game starts. This does not include the host slot, which will always be unlocked. This can be 0. To unlock all lobby slots, use -1.", "Lobby Slots", categorySort, 1L, default(OptionID), -1f, ((Il2CppArrayBase)(object)SNet.Slots.CharacterSlots).Count - 1)); OptionID optionID2 = data.AddOption(new OptionDoesNotEqualOperation(optionID, -1L)); OptionParameter tag = itemID; data.AddOption(new OptionAddToSet(optionID2, Option.eSetTarget.ItemWhitelist, tag)); data.AddOption(new OptionAddToSet(tag: itemID, condition: data.AddOption(new OptionNotOperation(optionID2)), target: Option.eSetTarget.ItemWhitelist)); tag = itemID; OptionParameter count = optionID; data.AddOption(new OptionAddCount(optionID2, Option.eDictTarget.StartVouchers, tag, count)); OptionID optionID3 = data.AddOption(new OptionRange("Early Lobby Slots", "The number of lobby slots which are guaranteed to randomize into locations which can be collected before any player collects any items. You may specify -1 to enable this for all randomized slots.\nNote: GTFO has a limited amount of space for early items. Adding too many early items many result in FILL errors!", "Lobby Slots", categorySort, 0L, optionID2, -1f, ((Il2CppArrayBase)(object)SNet.Slots.CharacterSlots).Count - 1)); count = itemID; tag = optionID3; data.AddOption(new OptionAddCount(optionID2, Option.eDictTarget.EarlyItems, count, tag)); } } public static class UnlockExpeditionHandler_Tags { [SpecialName] public sealed class $2B8804A94F2EF68DF77A343A46EE5A78 { [SpecialName] public static class $55FD246F9BFF39DD56FCB5C25D4DF852 { } [ExtensionMarker("$55FD246F9BFF39DD56FCB5C25D4DF852")] public RegionID Region_FloatingExpeditionPaths { [ExtensionMarker("$55FD246F9BFF39DD56FCB5C25D4DF852")] get { throw new NotSupportedException(); } } [ExtensionMarker("$55FD246F9BFF39DD56FCB5C25D4DF852")] public RegionID Region_ProgressiveExpeditionPaths { [ExtensionMarker("$55FD246F9BFF39DD56FCB5C25D4DF852")] get { throw new NotSupportedException(); } } [ExtensionMarker("$55FD246F9BFF39DD56FCB5C25D4DF852")] public LocationID Location_ProgressiveExpeditionUnlocks { [ExtensionMarker("$55FD246F9BFF39DD56FCB5C25D4DF852")] get { throw new NotSupportedException(); } } [ExtensionMarker("$55FD246F9BFF39DD56FCB5C25D4DF852")] public ItemID Item_FloatingExpeditionUnlocks { [ExtensionMarker("$55FD246F9BFF39DD56FCB5C25D4DF852")] get { throw new NotSupportedException(); } } [ExtensionMarker("$55FD246F9BFF39DD56FCB5C25D4DF852")] public ItemID Item_ProgressiveExpeditionUnlock { [ExtensionMarker("$55FD246F9BFF39DD56FCB5C25D4DF852")] get { throw new NotSupportedException(); } } [ExtensionMarker("$55FD246F9BFF39DD56FCB5C25D4DF852")] public ItemID Item_AllowMainOnlyProgression { [ExtensionMarker("$55FD246F9BFF39DD56FCB5C25D4DF852")] get { throw new NotSupportedException(); } } } [SpecialName] public sealed class $2833969430CAB23CD70890D67B9ADDD5 { [SpecialName] public static class $5667123F7013DAD37BB214B248F3E5D2 { } [ExtensionMarker("$5667123F7013DAD37BB214B248F3E5D2")] public RegionID Region_ProgressiveExpeditionUnlock_ByExpedition { [ExtensionMarker("$5667123F7013DAD37BB214B248F3E5D2")] get { throw new NotSupportedException(); } } [ExtensionMarker("$5667123F7013DAD37BB214B248F3E5D2")] public LocationID Location_ProgressiveExpeditionUnlock_Instance { [ExtensionMarker("$5667123F7013DAD37BB214B248F3E5D2")] get { throw new NotSupportedException(); } } [ExtensionMarker("$5667123F7013DAD37BB214B248F3E5D2")] public ItemID Item_FloatingExpedtionUnlock_Instance { [ExtensionMarker("$5667123F7013DAD37BB214B248F3E5D2")] get { throw new NotSupportedException(); } } } public static RegionID get_Region_FloatingExpeditionPaths(Game.Data data) { return RegionID.From(data, "Floating Expedition Paths", (Game.Data data2) => new TagDefinition("Region with paths connecting expeditions to the menu region via the ITEM requirements.", default(RegionID))); } public static RegionID get_Region_ProgressiveExpeditionPaths(Game.Data data) { return RegionID.From(data, "Progressive Expedition Paths", (Game.Data data2) => new TagDefinition("Region with paths connecting expeditions to the menu region via the PROGRESSIVE requirements.", default(RegionID))); } public static LocationID get_Location_ProgressiveExpeditionUnlocks(Game.Data data) { return LocationID.From(data, "Progressive Expedition Unlock Locations", (Game.Data data2) => new TagDefinition("Locations containing progressive expedition unlock items", CommonTagsHandler_Tags.get_Location_Never(data2))); } public static ItemID get_Item_FloatingExpeditionUnlocks(Game.Data data) { return ItemID.From(data, "Floating Expedition Unlock Items", (Game.Data data2) => new TagDefinition("Floating items which trigger specifc expeditions to be unlocked", CommonTagsHandler_Tags.get_Item_All(data2))); } public static ItemID get_Item_ProgressiveExpeditionUnlock(Game.Data data) { return ItemID.From(data, "Progressive Expedition Unlock", (Game.Data data2) => new TagDefinition("Item which, by gaining more, unlocks more and more expeditions", CommonTagsHandler_Tags.get_Item_All(data2)), new UnlockExpeditionHandler.ProgressiveExpeditionUnlockItem()); } public static ItemID get_Item_AllowMainOnlyProgression(Game.Data data) { return ItemID.From(data, "Allow Main Only Progression", (Game.Data data2) => new TagDefinition("Item which allows players to progress to next expedition with only a main clear", CommonTagsHandler_Tags.get_Item_Never(data2)), new Item(new ItemData { IsProgression = true })); } public static RegionID get_Region_ProgressiveExpeditionUnlock_ByExpedition(Expedition.Data data) { return RegionID.From(data, data.ExpeditionName + " Unlock Expedition Region", (Expedition.Data data2) => new TagDefinition("Region containg the progressive expedition unlock reward for a particular expedition", data2.Region_Expedition)); } public static LocationID get_Location_ProgressiveExpeditionUnlock_Instance(Expedition.Data data) { return LocationID.From(data, data.ExpeditionName + " Progressive Expedition Unlock Location", (Expedition.Data data2) => new TagDefinition("Location containing the progressive expedition unlock item for a particular expedition", get_Location_ProgressiveExpeditionUnlocks(data2))); } public static ItemID get_Item_FloatingExpedtionUnlock_Instance(Expedition.Data data) { return ItemID.From(data, data.ExpeditionName + " Expedition Unlock Item", (Expedition.Data data2) => new TagDefinition("Item which unlocks a particular expedition", get_Item_FloatingExpeditionUnlocks(data2)), new UnlockExpeditionHandler.FloatingExpeditionUnlockItem(data.Region_Expedition)); } } [EnableFeatureByDefault] [AutomatedFeature] public class UnlockExpeditionHandler : ArchipelagoFeature { public class Settings { [FSDisplayName("Unlock All Expeditions")] [FSDescription("Immediately unlocks all expeditions")] public FButton UnlockAllButton { get; set; } = new FButton("Unlock All", (string)null, (Action)UnlockAll, false); [FSDisplayName("Re-Lock All Expeditions")] [FSDescription("Undoes the Unlock All button, applying locks to any expeditions which were previously locked")] public FButton ResetAllButton { get; set; } = new FButton("Reset Locks", (string)null, (Action)ResetLocks, false); } private enum ProgressionStyles { BIT_EnableFloatingItems = 0, BIT_EnableFloatingPaths = 1, BIT_StartWithFloatingItems = 2, BIT_EnableProgressiveItems = 3, BIT_EnableProgressivePaths = 4, BIT_AllowMainOnlyProgression = 5, StartWithFloating = 4, FloatingItems = 1, FloatingPaths = 2, ProgressiveItems = 8, ProgressivePaths = 16, AllowMainOnly = 32, FREE = 6, ITEM = 3, PROGRESSIVE = 56, FULLPROG = 24, DUAL = 59, FULLDUAL = 27, SEMIPROG = 57, SEMIFULLPROG = 25 } public class FloatingExpeditionUnlockItem : Item { public RegionID ExpeditionRegion { get; private init; } public FloatingExpeditionUnlockItem(RegionID expedition) : base(new ItemData { IsProgression = true }) { ExpeditionRegion = expedition; } private IEnumerable FindExpeditions(Game.Data data) { List list = new List(); foreach (ExpeditionInTierData expedition in GetExpeditions()) { if (data.TryGetExpeditionData(expedition, out Expedition.Data result) && result.Region_Expedition.Equals(ExpeditionRegion)) { list.Add(expedition); } } if (list.Count == 0) { FeatureLogger.Error("Failed to find expedition during lock/unlock event: " + data.Regions.LookUpName(ExpeditionRegion)); } return list; } public override void OnItemObtained(StateTracker stateTracker, LocationID sourceLocationId, PlayerAgent? player = null, ItemID itemId = default(ItemID)) { if (!((Feature)ArchipelagoFeatureHelper.GetFeature()).Enabled) { return; } foreach (ExpeditionInTierData item in FindExpeditions(stateTracker.GameData)) { item.Accessibility = (eExpeditionAccessibility)2; } RundownHandler.UpdateAllCounts(); } public override void OnItemLost(StateTracker stateTracker, ItemID itemId = default(ItemID)) { if (!((Feature)ArchipelagoFeatureHelper.GetFeature()).Enabled || stateTracker.CollectedItemCounts.GetValueOrDefault(itemId, 0) > 0) { return; } foreach (ExpeditionInTierData item in FindExpeditions(stateTracker.GameData)) { item.Accessibility = (eExpeditionAccessibility)1; } RundownHandler.UpdateAllCounts(); } } public class ProgressiveExpeditionUnlockItem : Item { public ProgressiveExpeditionUnlockItem() : base(new ItemData { IsProgression = true, IsRandomLike = true }) { } public override void OnItemObtained(StateTracker stateTracker, LocationID sourceLocationId, PlayerAgent? player, ItemID itemId) { UnlockExpeditionHandler feature = ArchipelagoFeatureHelper.GetFeature(); if (!((Feature)feature).Enabled) { return; } IEnumerable expeditionsProgressiveOrdering = feature.GetExpeditionsProgressiveOrdering(stateTracker); int valueOrDefault = stateTracker.CollectedItemCounts.GetValueOrDefault(UnlockExpeditionHandler_Tags.get_Item_ProgressiveExpeditionUnlock(stateTracker.GameData)); HashSet hashSet = expeditionsProgressiveOrdering.Take(valueOrDefault).ToHashSet(); foreach (ExpeditionInTierData expedition in GetExpeditions()) { if (Expedition.Data.TryGetFromExpedition(expedition, out Expedition.Data result) && hashSet.Contains(result.Region_Expedition)) { expedition.Accessibility = (eExpeditionAccessibility)2; } } RundownHandler.UpdateAllCounts(); } } [ArchivePatch(/*Could not decode attribute arguments.*/)] public static class RundownManager__OnExpeditionEnded__Patch { public static void Postfix(ExpeditionEndState endState) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_00a1: Unknown result type (might be due to invalid IL or missing references) //IL_00a8: Invalid comparison between Unknown and I4 //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Invalid comparison between Unknown and I4 //IL_00d6: Unknown result type (might be due to invalid IL or missing references) //IL_00dd: Invalid comparison between Unknown and I4 //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Invalid comparison between Unknown and I4 if ((int)endState != 0) { return; } StateTracker stateTracker = StateTracker.Get(); Expedition.Data fromCurrentExpedition = Expedition.Data.GetFromCurrentExpedition(); if (stateTracker.CollectedItemCounts.GetValueOrDefault(UnlockExpeditionHandler_Tags.get_Item_AllowMainOnlyProgression(fromCurrentExpedition)) > 0) { stateTracker.NotifyFoundRegion(UnlockExpeditionHandler_Tags.get_Region_ProgressiveExpeditionUnlock_ByExpedition(fromCurrentExpedition), null); stateTracker.NotifyFoundLocation(UnlockExpeditionHandler_Tags.get_Location_ProgressiveExpeditionUnlock_Instance(fromCurrentExpedition), null); } else if (Layer.get_HasSecondary(fromCurrentExpedition) && Layer.get_HasOverload(fromCurrentExpedition)) { if ((int)WardenObjectiveManager.CurrentState.second_status == 40 && (int)WardenObjectiveManager.CurrentState.third_status == 40) { stateTracker.NotifyFoundRegion(UnlockExpeditionHandler_Tags.get_Region_ProgressiveExpeditionUnlock_ByExpedition(fromCurrentExpedition), null); stateTracker.NotifyFoundLocation(UnlockExpeditionHandler_Tags.get_Location_ProgressiveExpeditionUnlock_Instance(fromCurrentExpedition), null); } } else if (Layer.get_HasSecondary(fromCurrentExpedition)) { if ((int)WardenObjectiveManager.CurrentState.second_status == 40) { stateTracker.NotifyFoundRegion(UnlockExpeditionHandler_Tags.get_Region_ProgressiveExpeditionUnlock_ByExpedition(fromCurrentExpedition), null); stateTracker.NotifyFoundLocation(UnlockExpeditionHandler_Tags.get_Location_ProgressiveExpeditionUnlock_Instance(fromCurrentExpedition), null); } } else if (Layer.get_HasOverload(fromCurrentExpedition) && (int)WardenObjectiveManager.CurrentState.third_status == 40) { stateTracker.NotifyFoundRegion(UnlockExpeditionHandler_Tags.get_Region_ProgressiveExpeditionUnlock_ByExpedition(fromCurrentExpedition), null); stateTracker.NotifyFoundLocation(UnlockExpeditionHandler_Tags.get_Location_ProgressiveExpeditionUnlock_Instance(fromCurrentExpedition), null); } } } private static IArchiveLogger? m_featureLogger; public const string EXPEDITION_OPTION_CATEGORY = "Expeditions"; private (OptionMultiChoice?, OptionMultiChoice?) m_choices = (null, null); private RegionID[]? s_expeditionProgressivelyOrderered; public override string Name => "Unlock Expedition Handler"; public override string Description => "Locks expeditions and adds floating expedition unlock items which unlock them"; public override FeatureGroup Group => ArchipelagoFeatureGroups.get_FloatingHandlers(); public new static IArchiveLogger FeatureLogger { get { return m_featureLogger ?? Plugin.Get().Logger; } set { m_featureLogger = value; } } [FeatureConfig] public static int Config { get; set; } private (OptionMultiChoice, OptionMultiChoice) GetOrCreateOptions(Game.Data data) { if (m_choices.Item1 != null) { return m_choices; } OptionID optionID = data.AddOption(m_choices.Item1 = new OptionMultiChoice("Enabled Expeditions", "Select one or more expeditions to enable. These will be the expeditions you must clear. Optionally, choose \"All Expeditions\" to enable everything (including normally hidden expeditions, at your own risk)", "Expeditions", Array.Empty(), default(RegionID).ID, default(OptionID), new List { "All Expeditions" }, new List { Expedition.get_Region_AllExpeditions(data).ID })); OptionParameter tag = optionID; data.AddOption(new OptionAddToSet(default(OptionID), Option.eSetTarget.RegionWhitelist, tag)); OptionID optionID2 = data.AddOption(new OptionChoice("Progression Style", "Controls how expeditions are unlocked.\n FREE - All expeditions start unlocked.\n ITEM - You must obtain an item to unlock an expedition.\n PROGRESSIVE - Each main sector cleared unlocks a new expedition.\n FULLPROG - Each full clear unlocks a new expedition.\n This means PE, secondary and overload are required.\n *Note that the logic for this is currently broken.*\n DUAL - Enables both ITEM and PROGRESSIVE styles.\n FULLDUAL - Enables both ITEM and FULLPROG styles.\n SEMIPROG - Both ITEM and PROGRESSIVE. Archipelago will ignore\n ITEM paths during randomization.\n SEMIFULLPROG - Both ITEM and FULLPROG. Archipelago will ignore\n ITEM paths during randomization.", "Expeditions", Array.Empty(), 3L, default(OptionID), new List { "FREE", "ITEM", "PROGRESSIVE", "FULLPROG", "DUAL", "FULLDUAL", "SEMIPROG", "SEMIFULLPROG" }, new List { 6L, 3L, 56L, 24L, 59L, 27L, 57L, 25L })); OptionID condition = data.AddOption(new OptionGetBitOperation(optionID2, 2L)); OptionID optionID3 = data.AddOption(new OptionGetBitOperation(optionID2, 0L)); OptionID optionID4 = data.AddOption(new OptionGetBitOperation(optionID2, 1L)); OptionID optionID5 = data.AddOption(new OptionGetBitOperation(optionID2, 3L)); OptionID condition2 = data.AddOption(new OptionGetBitOperation(optionID2, 4L)); OptionID condition3 = data.AddOption(new OptionGetBitOperation(optionID2, 5L)); ItemID itemID = UnlockExpeditionHandler_Tags.get_Item_FloatingExpeditionUnlocks(data); uint[] categorySort = Option.MakeSortKey(data, itemID); data.AddOption(new OptionAddAll(condition, Option.eDictTarget.StartVouchers, itemID)); data.AddOption(new OptionAddToSet(optionID3, Option.eSetTarget.ItemWhitelist, itemID)); data.AddOption(new OptionAddToSet(data.AddOption(new OptionOrOperation(optionID4, data.AddOption(new OptionAndOperation(optionID3, CommonTagsHandler_Tags.get_Option_IsFakeGeneration(data))))), Option.eSetTarget.RegionWhitelist, UnlockExpeditionHandler_Tags.get_Region_FloatingExpeditionPaths(data))); data.AddOption(new OptionAddToSet(condition2, Option.eSetTarget.RegionWhitelist, UnlockExpeditionHandler_Tags.get_Region_ProgressiveExpeditionPaths(data))); data.AddOption(new OptionAddCount(condition3, Option.eDictTarget.StartInventory, UnlockExpeditionHandler_Tags.get_Item_AllowMainOnlyProgression(data), 1L)); OptionID optionID6 = data.AddOption(m_choices.Item2 = new OptionMultiChoice("Starting Expeditions (ITEM)", "Only applicable in ITEM mode. Choose one or more expeditions which start unlocked. You must choose expeditions which are enabled in the \"Enabled Expeditions\" option, otherwise this option has no effect.", "Expeditions", categorySort, default(ItemID).ID, optionID4, new List(), new List())); data.AddOption(new OptionAddAll(optionID4, Option.eDictTarget.StartVouchers, optionID6)); OptionID optionID7 = data.AddOption(new OptionRange("Random Starting Expeditions (ITEM)", "Only applicable in ITEM mode. The desired number of expeditions will be randomly selected and will start unlocked. Intended for when the expeditions themselves are randomly selected.", "Expeditions", categorySort, 0L, optionID4, 0f, 99f)); data.AddOption(new OptionAddCount(optionID4, Option.eDictTarget.StartVouchers, itemID, optionID7)); ItemID itemID2 = UnlockExpeditionHandler_Tags.get_Item_ProgressiveExpeditionUnlock(data); uint[] categorySort2 = Option.MakeSortKey(data, itemID2); OptionID optionID8 = data.AddOption(new OptionRange("Number of Unlocked Expeditions (PROGRESSIVE)", "Only applicable in any variant of PROGRESSIVE mode. The number of expeditions which will start unlocked. This generally guarantees you have access to at least N expeditions at any given time.", "Expeditions", categorySort2, 1L, condition2, 0f, 99f)); data.AddOption(new OptionAddCount(condition2, Option.eDictTarget.StartInventory, itemID2, optionID8)); return m_choices; } public static string GetProgressiveSortKey(Expedition.Data data) { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Expected I4, but got Unknown return $"{(int)data.ExpeditionTier}-{data.ExpeditionIndex}-{((GameDataBlockBase)(object)data.Rundown).name}"; } public IEnumerable GetExpeditionsProgressiveOrdering(StateTracker stateTracker) { if (s_expeditionProgressivelyOrderered != null) { return s_expeditionProgressivelyOrderered; } Game.Data gameData = stateTracker.GameData; List list = new List(); foreach (KeyValuePair.TagEntry> allEntry in gameData.Regions.GetAllEntries()) { if (allEntry.Value.Value.Randomized && Expedition.Data.TryFromRegion(gameData, allEntry.Key, out Expedition.Data expedition)) { list.Add(expedition); } } string[] array = new string[list.Count]; s_expeditionProgressivelyOrderered = new RegionID[list.Count]; int num = 0; foreach (Expedition.Data item in list) { array[num] = GetProgressiveSortKey(item); s_expeditionProgressivelyOrderered[num] = item.Region_Expedition; num++; } Array.Sort(s_expeditionProgressivelyOrderered, array); return s_expeditionProgressivelyOrderered; } private static IEnumerable UnpackRundown(RundownDataBlock rundown) { Enumerator enumerator = rundown.TierA.GetEnumerator(); while (enumerator.MoveNext()) { yield return enumerator.Current; } enumerator = rundown.TierB.GetEnumerator(); while (enumerator.MoveNext()) { yield return enumerator.Current; } enumerator = rundown.TierC.GetEnumerator(); while (enumerator.MoveNext()) { yield return enumerator.Current; } enumerator = rundown.TierD.GetEnumerator(); while (enumerator.MoveNext()) { yield return enumerator.Current; } enumerator = rundown.TierE.GetEnumerator(); while (enumerator.MoveNext()) { yield return enumerator.Current; } } private static IEnumerable GetExpeditions() { return ((IEnumerable)GameDataBlockBase.GetAllBlocks()).SelectMany(UnpackRundown) ?? Enumerable.Empty(); } [Game.Callback] public void ConnectUnlockPaths(Game.Data data) { data.AddPath(new ReTFO.Archipelago.ModdedInstanceData.Model.Path { StartingRegion = data.Region_Menu, EndingRegion = UnlockExpeditionHandler_Tags.get_Region_FloatingExpeditionPaths(data) }); data.AddPath(new ReTFO.Archipelago.ModdedInstanceData.Model.Path { StartingRegion = data.Region_Menu, EndingRegion = UnlockExpeditionHandler_Tags.get_Region_ProgressiveExpeditionPaths(data) }); } [Expedition.Callback] public void AddExpeditionUnlock(Expedition.Data data) { ItemID itemID = UnlockExpeditionHandler_Tags.get_Item_FloatingExpedtionUnlock_Instance(data); data.AddPath(new ReTFO.Archipelago.ModdedInstanceData.Model.Path { Name = data.ExpeditionName + " ITEM Expdition Unlock", StartingRegion = UnlockExpeditionHandler_Tags.get_Region_FloatingExpeditionPaths(data), EndingRegion = data.Region_Expedition, Reqs = new ReTFO.Archipelago.ModdedInstanceData.Model.Path.MultiPathReq(ReTFO.Archipelago.ModdedInstanceData.Model.Path.eType.Item, itemID, 1u) }); data.AddFloatingItem(data.Region_Expedition, itemID); ItemID itemID2 = UnlockExpeditionHandler_Tags.get_Item_ProgressiveExpeditionUnlock(data); data.AddPath(new ReTFO.Archipelago.ModdedInstanceData.Model.Path { Name = GetProgressiveSortKey(data) + " - " + data.ExpeditionName + " PROGRESSIVE Expedition Unlock", StartingRegion = UnlockExpeditionHandler_Tags.get_Region_ProgressiveExpeditionPaths(data), EndingRegion = data.Region_Expedition, Reqs = new ReTFO.Archipelago.ModdedInstanceData.Model.Path.MultiPathReq(ReTFO.Archipelago.ModdedInstanceData.Model.Path.eType.ItemGrowing, UnlockExpeditionHandler_Tags.get_Item_ProgressiveExpeditionUnlock(data), 1u) }); RegionID regionID = UnlockExpeditionHandler_Tags.get_Region_ProgressiveExpeditionUnlock_ByExpedition(data); List list = Layer.get_RealLayers(data).ToList(); RegionID startingRegion = ((list.Count >= 3) ? SharedObjectiveHandler_Tags.get_Region_PECleared(data) : SharedObjectiveHandler_Tags.get_Region_SectorCleared(list.Last())); data.AddPath(new ReTFO.Archipelago.ModdedInstanceData.Model.Path { StartingRegion = startingRegion, EndingRegion = regionID }); if (list.Count > 1) { data.AddPath(new ReTFO.Archipelago.ModdedInstanceData.Model.Path { StartingRegion = SharedObjectiveHandler_Tags.get_Region_SectorCleared(list[0]), EndingRegion = regionID, Reqs = new ReTFO.Archipelago.ModdedInstanceData.Model.Path.MultiPathReq(ReTFO.Archipelago.ModdedInstanceData.Model.Path.eType.Item, UnlockExpeditionHandler_Tags.get_Item_AllowMainOnlyProgression(data), 1u) }); } data.Locations.CreateValue(UnlockExpeditionHandler_Tags.get_Location_ProgressiveExpeditionUnlock_Instance(data), regionID, default(LocationData), UnlockExpeditionHandler_Tags.get_Item_ProgressiveExpeditionUnlock(data)); (OptionMultiChoice, OptionMultiChoice) orCreateOptions = GetOrCreateOptions(data); orCreateOptions.Item1.ChoiceNames.Add(data.ExpeditionName); orCreateOptions.Item1.ChoiceValues.Add(data.Region_Expedition.ID); orCreateOptions.Item2.ChoiceNames.Add(data.ExpeditionName); orCreateOptions.Item2.ChoiceValues.Add(itemID.ID); } public static void UnlockAll() { foreach (ExpeditionInTierData expedition in GetExpeditions()) { expedition.Accessibility = (eExpeditionAccessibility)2; } } public static void ResetLocks() { StateTracker stateTracker = StateTracker.Get(); Game.Data processedGameData = stateTracker.MidManager.GetProcessedGameData(); foreach (ExpeditionInTierData expedition in GetExpeditions()) { if (!processedGameData.TryGetExpeditionData(expedition, out Expedition.Data result)) { FeatureLogger.Warning("Failed to find data for expedition: " + expedition.Descriptive.Prefix + "; not applying lock!"); continue; } ItemID itemID = UnlockExpeditionHandler_Tags.get_Item_FloatingExpedtionUnlock_Instance(result); if (stateTracker.IsItemRandomized(result.Region_Expedition, itemID) && stateTracker.CollectedItemCounts.GetValueOrDefault(itemID, 0) <= 0) { expedition.Accessibility = (eExpeditionAccessibility)1; } } } } } namespace ReTFO.Archipelago.Features.EventHandlers { [EnableFeatureByDefault] [AutomatedFeature] public class CheckEventRegionsHandler : ArchipelagoFeature { private static IArchiveLogger? m_featureLogger; public override string Name => "Check Event Regions Handler"; public override string Description => "Adds check region events to event data to automatically identify when event regions are entered"; public override FeatureGroup Group => ArchipelagoFeatureGroups.get_EventHandlers(); public new static IArchiveLogger FeatureLogger { get { return m_featureLogger ?? Plugin.Get().Logger; } set { m_featureLogger = value; } } [Event.Callback] public void InsertCheckRegionEvent(Event.Data data) { WardenObjectiveEventData source = (WardenObjectiveEventData)((data.Count <= 0) ? ((object)((Il2CppObjectBase)Activator.CreateInstance(data.EventType)).Cast()) : ((object)data[0])); data.Insert(0, EventHelper.CreateCheckRegionEvent(source, data.Region_Event)); } } public static class CustomScanHandler_Tags { [SpecialName] public sealed class $2B8804A94F2EF68DF77A343A46EE5A78 { [SpecialName] public static class $F943E16B16B76A20C49A59C8DF7C8955 { } [ExtensionMarker("$F943E16B16B76A20C49A59C8DF7C8955")] public ItemID Item_EventScans { [ExtensionMarker("$F943E16B16B76A20C49A59C8DF7C8955")] get { throw new NotSupportedException(); } } } [SpecialName] public sealed class $2833969430CAB23CD70890D67B9ADDD5 { [SpecialName] public static class $5667123F7013DAD37BB214B248F3E5D2 { } [ExtensionMarker("$5667123F7013DAD37BB214B248F3E5D2")] public ItemID Item_EventScan_Instance(string worldEventObjectFilter) { throw new NotSupportedException(); } } public static ItemID get_Item_EventScans(Game.Data gameData) { return ItemID.From(gameData, "Event Scan Items", (Game.Data data) => new TagDefinition("Scans triggered by starting a custom event", CommonTagsHandler_Tags.get_Item_Scans(data))); } public static ItemID Item_EventScan_Instance(this Expedition.Data data, string worldEventObjectFilter) { return ItemID.From(data, data.ExpeditionName + " Event Scan \"" + worldEventObjectFilter + "\"", (Expedition.Data data2) => new TagDefinition("A particular event-triggered scan", CommonTagsHandler_Tags.get_Item_Scans(data2)), new CustomScanHandler.StartCustomScanItem(data.Region_Expedition, worldEventObjectFilter)); } } [EnableFeatureByDefault] [AutomatedFeature] public class CustomScanHandler : ArchipelagoFeature { public class StartCustomScanItem : TerminalItem { public RegionID Expedition { get; private init; } public string WorldEventObjectFilter { get; private init; } public override RegionID TargetRegion => Expedition; public StartCustomScanItem(RegionID region, string worldEventObjectFilter) : base(new ItemData { IsProgression = true }) { Expedition = region; WorldEventObjectFilter = worldEventObjectFilter; } public override IEnumerable OnRetrieveFromTerminalSystem(StateTracker stateTracker, LG_ComputerTerminal terminal, ItemID itemId) { yield return delegate { terminal.AddLine((TerminalLineType)2, "Initiating Scan " + WorldEventObjectFilter, 2f); terminal.AddLine("Scan will start in 10 seconds. Good luck :)", true); }; yield return delegate { //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_000d: 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_0033: Expected O, but got Unknown WorldEventManager.ExecuteEvent(new WardenObjectiveEventData { Type = (eWardenObjectiveEventType)22, WorldEventObjectFilter = WorldEventObjectFilter, Delay = 10f }, 0f); }; } } private static IArchiveLogger? m_featureLogger; public override string Name => "Custom Scans Handler"; public override string Description => "Handles certain custom scans which are triggered by events\nThese are typically zone scans, and are often started by a terminal command"; public override FeatureGroup Group => ArchipelagoFeatureGroups.get_EventHandlers(); public new static IArchiveLogger FeatureLogger { get { return m_featureLogger ?? Plugin.Get().Logger; } set { m_featureLogger = value; } } [Event.Callback] public void ProcessCustomScanStartEvents(Event.Data data) { //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Invalid comparison between Unknown and I4 int num = 0; foreach (WardenObjectiveEventData datum in data) { if ((int)datum.Type == 22) { num++; string worldEventObjectFilter = datum.WorldEventObjectFilter; if (worldEventObjectFilter != null && worldEventObjectFilter.Length != 0) { ItemID item = data.Item_EventScan_Instance(datum.WorldEventObjectFilter); EventHelper.CreateEventLocation(data, datum, num, item); } } } } [Zone.Callback] public void AddCustomScans(Zone.Data data) { if (data.Zone == null) { return; } foreach (SpecificChainPuzzleSpawnData item in data.Zone.WorldEventChainedPuzzleDatas.Iter()) { SpecificChainPuzzleSpawnData val = item; Event.Wrapper wrapper = data.WrapEvents(val.EventsOnScanDone ?? (val.EventsOnScanDone = new List(1))); ItemID target = data.Item_EventScan_Instance(item.WorldEventObjectFilter); uint num = 0u; while (!wrapper.IsDone) { num++; string name = $"{data.ZoneName} Custom Scan ({item.WorldEventObjectFilter}) (Completion #{num})"; RegionID regionID = data.Regions.Create(name, new TagDefinition("A custom scan's region", data.Region_Expedition)); data.AddPath(new ReTFO.Archipelago.ModdedInstanceData.Model.Path { StartingRegion = data.Region_Zone, EndingRegion = regionID, Reqs = new ReTFO.Archipelago.ModdedInstanceData.Model.Path.MultiPathReq(ReTFO.Archipelago.ModdedInstanceData.Model.Path.eType.Item, target, num) }); wrapper.Process(regionID); } } } } public static class EventHelper_Tags { [SpecialName] public sealed class $2B8804A94F2EF68DF77A343A46EE5A78 { [SpecialName] public static class $F943E16B16B76A20C49A59C8DF7C8955 { } [ExtensionMarker("$F943E16B16B76A20C49A59C8DF7C8955")] public LocationID Location_Event { [ExtensionMarker("$F943E16B16B76A20C49A59C8DF7C8955")] get { throw new NotSupportedException(); } } [ExtensionMarker("$F943E16B16B76A20C49A59C8DF7C8955")] public ItemID Item_Event { [ExtensionMarker("$F943E16B16B76A20C49A59C8DF7C8955")] get { throw new NotSupportedException(); } } [ExtensionMarker("$F943E16B16B76A20C49A59C8DF7C8955")] public LocationID Location_Event_ByType(eWardenObjectiveEventType type) { throw new NotSupportedException(); } } public static LocationID get_Location_Event(Game.Data gameData) { return LocationID.From(gameData, "Event Locations", (Game.Data data) => new TagDefinition("Locations found by triggering particular events", CommonTagsHandler_Tags.get_Location_All(data))); } public static LocationID Location_Event_ByType(this Game.Data gameData, eWardenObjectiveEventType type) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) return LocationID.From(gameData, "Event Locations for " + Enum.GetName(type) + " Event", (Game.Data data) => new TagDefinition("Locations found by triggering a particular event type", get_Location_Event(data))); } public static ItemID get_Item_Event(Game.Data gameData) { return ItemID.From(gameData, "Event Items", (Game.Data data) => new TagDefinition("Items corresponding to in-game events", CommonTagsHandler_Tags.get_Item_All(data))); } } [EnableFeatureByDefault] [AutomatedFeature] [InjectToIl2Cpp] public class EventHelper : ArchipelagoFeature { public class EventLocation : Location { public WardenObjectiveEventData SourceEvent { get; init; } public EventLocation(RegionList regions, LocationData randData, WardenObjectiveEventData sourceEvent, ItemID itemId = default(ItemID)) : base(regions, randData, itemId) { SourceEvent = sourceEvent; } } [ArchivePatch(/*Could not decode attribute arguments.*/)] public static class WorldEventManager__ExecuteEvent_Internal__Patch { public static bool Prefix(ref WardenObjectiveEventData eData, float currentDuration) { //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Invalid comparison between Unknown and I4 //IL_0085: Unknown result type (might be due to invalid IL or missing references) //IL_008f: Invalid comparison between Unknown and I4 WardenObjectiveEventData inputEvent = eData; bool flag = checkCondition(); RegionID id; if ((int)eData.Type == 1512758915) { if (checkCondition()) { return false; } id = new RegionID { ID = eData.EnemyID }; if (currentDuration >= inputEvent.Delay) { regionCallback(); } else { TriggerDelayedWorldEvent(regionCallback, inputEvent.Delay - currentDuration); } return false; } LocationID id2; if ((int)eData.Type == 1512758916) { id2 = new LocationID { ID = eData.EnemyID }; StateTracker stateTracker = StateTracker.Get(); Location location = stateTracker.MidManager.GetProcessedGameData().Locations.LookUpValue(id2); if (location != null && !location.RandData.IsTreatedAsRandom) { if (location is EventLocation eventLocation) { eData = eventLocation.SourceEvent; } return true; } if (checkCondition()) { return false; } if (currentDuration >= inputEvent.Delay) { locationCallback(); } else { TriggerDelayedWorldEvent(locationCallback, inputEvent.Delay - currentDuration); } return false; } return true; bool checkCondition() { if (inputEvent.Condition != null && inputEvent.Condition.ConditionIndex >= 0) { return WorldEventManager.GetCondition(inputEvent.Condition.ConditionIndex) != inputEvent.Condition.IsTrue; } return false; } void locationCallback() { StateTracker.Get().NotifyFoundLocation(id2, null); } void regionCallback() { StateTracker.Get().NotifyFoundRegion(id, null); } } } private static IArchiveLogger? m_featureLogger; public const eWardenObjectiveEventType CheckRegionEventType = (eWardenObjectiveEventType)1512758915; public const eWardenObjectiveEventType CheckLocationEventType = (eWardenObjectiveEventType)1512758916; public const string EVENT_OPTION_CATEGORY = "Events"; public override string Name => "Events Helper"; public override string Description => "Provides utilites used by other features to manage events"; public override FeatureGroup Group => ArchipelagoFeatureGroups.get_EventHandlers(); public new static IArchiveLogger FeatureLogger { get { return m_featureLogger ?? Plugin.Get().Logger; } set { m_featureLogger = value; } } public static void ClearEvent(WardenObjectiveEventData e) { //IL_001a: 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_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Expected O, but got Unknown //IL_0084: Unknown result type (might be due to invalid IL or missing references) //IL_0089: 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_009c: 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_00ae: 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_00bc: Unknown result type (might be due to invalid IL or missing references) //IL_00cc: Expected O, but got Unknown //IL_00ed: Unknown result type (might be due to invalid IL or missing references) e.AchievementKey = string.Empty; e.ChainPuzzle = 0u; e.ClearDimension = false; e.Condition = new WorldEventConditionPair { ConditionIndex = -1, IsTrue = false }; e.Count = 0; e.CustomSubObjective = LocalizedText.op_Implicit(0u); e.CustomSubObjectiveHeader = LocalizedText.op_Implicit(0u); e.Delay = 0f; e.DialogueID = 0u; e.DimensionIndex = (eDimensionIndex)0; e.Duration = 0f; e.Enabled = false; e.EnemyID = 0u; e.EnemyWaveData = new GenericEnemyWaveData { AreaDistance = 2, IntelMessage = LocalizedText.op_Implicit(0u), SpawnDelay = 0f, TriggerAlarm = false, WavePopulation = 0u, WaveSettings = 0u, WorldEventObjectFilterSpawnPoint = string.Empty }; e.FogSetting = 0u; e.FogTransitionDuration = 0f; e.Layer = (LG_LayerType)0; e.LocalIndex = (eLocalZoneIndex)0; e.Position = Vector3.zero; e.SoundID = 0u; e.SoundSubtitle = LocalizedText.op_Implicit(0u); e.SustainedEventDelay = 0f; e.SustainedEventSlotIndex = 0; e.SustainedEventStateCount = 0; e.SustainedEventStateDuration = 0f; e.TerminalCommand = (TERM_Command)0; e.TerminalCommandRule = (TERM_CommandRule)0; e.Trigger = (eWardenObjectiveEventTrigger)0; e.Type = (eWardenObjectiveEventType)0; e.UseStaticBioscanPoints = false; e.WardenIntel = LocalizedText.op_Implicit(0u); e.WorldEventObjectFilter = string.Empty; } public static WardenObjectiveEventData CreateCheckRegionEvent(WardenObjectiveEventData source, RegionID regionId) { WardenObjectiveEventData val = ((Il2CppObjectBase)((Object)source).MemberwiseClone()).Cast(); ClearEvent(val); ConvertToCheckRegionEvent(val, regionId); return val; } public static void ConvertToCheckRegionEvent(WardenObjectiveEventData source, RegionID regionId) { source.Type = (eWardenObjectiveEventType)1512758915; source.EnemyID = regionId.ID; } public static WardenObjectiveEventData CreateCheckLocationEvent(WardenObjectiveEventData source, LocationID locationId) { WardenObjectiveEventData val = ((Il2CppObjectBase)((Object)source).MemberwiseClone()).Cast(); ClearEvent(val); ConvertToCheckLocationEvent(val, locationId); return val; } public static void ConvertToCheckLocationEvent(WardenObjectiveEventData source, LocationID locationId) { source.Type = (eWardenObjectiveEventType)1512758915; source.EnemyID = locationId.ID; } public static LocationID CreateEventLocation(Event.Data data, WardenObjectiveEventData originalEvent, int count, ItemID item, LocationData randData = default(LocationData)) { //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Unknown result type (might be due to invalid IL or missing references) WardenObjectiveEventData sourceEvent = ((Il2CppObjectBase)((Object)originalEvent).MemberwiseClone()).Cast(); Location item2 = new EventLocation(data.Region_Event, randData, sourceEvent, item); LocationID result = data.Locations.Create($"{data.EventName} {Enum.GetName(originalEvent.Type)} #{count}", new TagDefinition("A specific event location", data.Location_Event_ByType(originalEvent.Type)), item2); originalEvent.Type = (eWardenObjectiveEventType)1512758916; originalEvent.EnemyID = result.ID; return result; } [Game.Callback] public void AddEventOptions(Game.Data data) { LocationID locationID = EventHelper_Tags.get_Location_Event(data); data.AddOption(new OptionLocationTagOption("Event Randomization", "Controls randomization of all supported events. This includes events which open/unlock doors, events which start scans, events which trigger warps, and instant win events.\nWhitelist: Enables for all unless blacklisted elsewhere.\nBlacklist: Disables for all.\nNone: Defer to other relevant setting(s). If no other relevant setting is set, defaults to blacklisted.", "Events", Option.MakeSortKey(data, locationID), 0L, default(OptionID), locationID)); locationID = data.Location_Event_ByType((eWardenObjectiveEventType)2); data.AddOption(new OptionLocationTagOption("Open/Unlock Door Event Randomization", "Controls randomization of open and unlock door events. For players' safety, these are all converted to unlock events.\nWhitelist: Enables for all unless blacklisted elsewhere.\nBlacklist: Disables for all.\nNone: Defer to other relevant setting(s). If no other relevant setting is set, defaults to blacklisted.", "Events", Option.MakeSortKey(data, locationID), 1L, default(OptionID), locationID)); locationID = data.Location_Event_ByType((eWardenObjectiveEventType)26); data.AddOption(new OptionLocationTagOption("Win Event Randomization", "Controls randomization of win events, which immediately clear main on the expedition. These events are how R8A2 Secondary, R8C2, and R8E2 end. Note that they only ever clear main and do not clear optional sectors.\nWhitelist: Enables for all unless blacklisted elsewhere.\nBlacklist: Disables for all.\nNone: Defer to other relevant setting(s). If no other relevant setting is set, defaults to blacklisted.", "Events", Option.MakeSortKey(data, locationID), 1L, default(OptionID), locationID)); } public static void TriggerDelayedWorldEvent(Action action, float delay) { Coroutine val = ((MonoBehaviour)WorldEventManager.Current).StartCoroutine((IEnumerator)new Il2CppEnumerator(ActionAfterDelayCoroutine(action, delay))); WorldEventManager.m_worldEventEventCoroutines.Add(val); static IEnumerator ActionAfterDelayCoroutine(Action action2, float num) { yield return (object)new WaitForSeconds(num); action2(); } } } [EnableFeatureByDefault] [AutomatedFeature] public class ForceCompleteObjectiveEventHandler : ArchipelagoFeature { private static IArchiveLogger? m_featureLogger; public override string Name => "Force Complete Objective Event Handler"; public override string Description => "Handles the ForceCompleteObjective event type, which immediately completes an objective."; public override FeatureGroup Group => ArchipelagoFeatureGroups.get_EventHandlers(); public new static IArchiveLogger FeatureLogger { get { return m_featureLogger ?? Plugin.Get().Logger; } set { m_featureLogger = value; } } [Event.Callback] public void ProcessForceCompleteEvents(Event.Data data) { //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Invalid comparison between Unknown and I4 //IL_0022: Unknown result type (might be due to invalid IL or missing references) int num = 0; foreach (WardenObjectiveEventData datum in data) { if ((int)datum.Type == 12) { num++; Layer.Data layer = data.GetLayer(datum.Layer); ItemID item = SharedObjectiveHandler_Tags.get_Item_CompleteObjective_Instance(layer); EventHelper.CreateEventLocation(data, datum, num, item); } } } } public static class UnlockEventHandler_Tags { [SpecialName] public sealed class $2B8804A94F2EF68DF77A343A46EE5A78 { [SpecialName] public static class $F943E16B16B76A20C49A59C8DF7C8955 { } [ExtensionMarker("$F943E16B16B76A20C49A59C8DF7C8955")] public ItemID Item_DoorUnlockEvent { [ExtensionMarker("$F943E16B16B76A20C49A59C8DF7C8955")] get { throw new NotSupportedException(); } } } [SpecialName] public sealed class $07060F1A014DE32BC9DAE9AB0EFE08B9 { [SpecialName] public static class $A55646E979CA6A3D946ACF0E8F38FB8D { } [ExtensionMarker("$A55646E979CA6A3D946ACF0E8F38FB8D")] public ItemID Item_DoorUnlockEvent_ByZone { [ExtensionMarker("$A55646E979CA6A3D946ACF0E8F38FB8D")] get { throw new NotSupportedException(); } } [ExtensionMarker("$A55646E979CA6A3D946ACF0E8F38FB8D")] public ItemID Item_DoorUnlockEvent_Instance(bool isUnlock) { throw new NotSupportedException(); } } public static ItemID get_Item_DoorUnlockEvent(Game.Data gameData) { return ItemID.From(gameData, "Zone Unlock Event Items", (Game.Data data) => new TagDefinition("Event items which trigger sec doors to unlock", EventHelper_Tags.get_Item_Event(data))); } public static ItemID get_Item_DoorUnlockEvent_ByZone(Zone.Data data) { return ItemID.From(data, data.ZoneName + " Unlock Event", (Zone.Data gameData) => new TagDefinition("Event item which unlocks a particular door", get_Item_DoorUnlockEvent(gameData))); } public static ItemID Item_DoorUnlockEvent_Instance(this Zone.Data data, bool isUnlock) { return ItemID.From(data, data.ZoneName + " Unlock Event (" + (isUnlock ? "Unlock" : "Open") + ")", (Zone.Data data2) => new TagDefinition("Event item which immediately opens a particular door", get_Item_DoorUnlockEvent_ByZone(data2)), new UnlockEventHandler.UnlockZoneItem(data.Region_Zone, isUnlock)); } } [EnableFeatureByDefault] [AutomatedFeature] public class UnlockEventHandler : ArchipelagoFeature { public class UnlockZoneItem : ExpeditionItem { public RegionID ZoneRegion { get; private init; } public bool IsUnlock { get; private init; } public override RegionID TargetRegion => ZoneRegion; public UnlockZoneItem(RegionID zone, bool isUnlock) : base(MakeRandData()) { ZoneRegion = zone; IsUnlock = isUnlock; } public static ItemData MakeRandData() { return new ItemData { IsProgression = true }; } public override void OnEnteredExpedition(StateTracker stateTracker, LocationID sourceLocationId, PlayerAgent? player, ItemID itemId) { //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_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0025: 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_0036: Unknown result type (might be due to invalid IL or missing references) //IL_0040: 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_005b: Expected O, but got Unknown Zone.Data data = new Zone.Data(stateTracker.GameData, ZoneRegion); WorldEventManager.ExecuteEvent(new WardenObjectiveEventData { Type = (eWardenObjectiveEventType)2, DimensionIndex = data.LayerType, Layer = data.LayerType, LocalIndex = data.Zone.LocalIndex }, 0f); } } private static IArchiveLogger? m_featureLogger; public override string Name => "Unlock Event Handler"; public override string Description => "Handles events which unlock or open doors"; public override FeatureGroup Group => ArchipelagoFeatureGroups.get_EventHandlers(); public new static IArchiveLogger FeatureLogger { get { return m_featureLogger ?? Plugin.Get().Logger; } set { m_featureLogger = value; } } [Event.Callback] public void ProcessUnlockEvents(Event.Data data) { //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Invalid comparison between Unknown and I4 //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Invalid comparison between Unknown and I4 //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Invalid comparison between Unknown and I4 int num = 0; foreach (WardenObjectiveEventData datum in data) { if ((int)datum.Type == 2 || (int)datum.Type == 1) { num++; Zone.Data data2 = data.FindZoneByEvent(datum); if (data2 != null) { EventHelper.CreateEventLocation(data, datum, num, data2.Item_DoorUnlockEvent_Instance((int)datum.Type == 2)); continue; } FeatureLogger.Debug($"Failed to find zone for unlock event: {data.EventName} #{num}"); } } } } public static class WarpEvent_Tags { [SpecialName] public sealed class $2B8804A94F2EF68DF77A343A46EE5A78 { [SpecialName] public static class $F943E16B16B76A20C49A59C8DF7C8955 { } [ExtensionMarker("$F943E16B16B76A20C49A59C8DF7C8955")] public ItemID Item_WarpEvents { [ExtensionMarker("$F943E16B16B76A20C49A59C8DF7C8955")] get { throw new NotSupportedException(); } } } [SpecialName] public sealed class $07060F1A014DE32BC9DAE9AB0EFE08B9 { [SpecialName] public static class $A55646E979CA6A3D946ACF0E8F38FB8D { } [ExtensionMarker("$A55646E979CA6A3D946ACF0E8F38FB8D")] public ItemID Item_WarpEvent_ByZone { [ExtensionMarker("$A55646E979CA6A3D946ACF0E8F38FB8D")] get { throw new NotSupportedException(); } } [ExtensionMarker("$A55646E979CA6A3D946ACF0E8F38FB8D")] public ItemID Item_WarpEvent_Instance(string? targetAlign, bool withDimensionClearing) { throw new NotSupportedException(); } } public static ItemID get_Item_WarpEvents(Game.Data gameData) { return ItemID.From(gameData, "Warp Event Items", (Game.Data data) => new TagDefinition("Event items which trigger the team to teleport, typically between dimensions", CommonTagsHandler_Tags.get_Item_Warps(data))); } public static ItemID get_Item_WarpEvent_ByZone(Zone.Data data) { return ItemID.From(data, "Team Warps to " + data.ZoneName, (Zone.Data gameData) => new TagDefinition("Event items which trigger the team to teleport to a particular zone", get_Item_WarpEvents(gameData))); } public static ItemID Item_WarpEvent_Instance(this Zone.Data data, string? targetAlign, bool withDimensionClearing) { return ItemID.From(data, "Team Warp to " + data.ZoneName + ((targetAlign != null) ? (", Align: \"" + targetAlign + "\"") : string.Empty) + (withDimensionClearing ? ", with ClearDimension" : string.Empty), (Zone.Data data2) => new TagDefinition("A particular variation of a team warp going to a particular zone", get_Item_WarpEvent_ByZone(data2)), new WarpEventsHandler.DimensionWarpItem(data.Region_Zone, targetAlign, withDimensionClearing)); } } [EnableFeatureByDefault] [AutomatedFeature] public class WarpEventsHandler : ArchipelagoFeature { public class DimensionWarpItem : TerminalItem { public RegionID TargetZone { get; private init; } public bool ClearDimension { get; private init; } public string? WarpAlign { get; private init; } public override RegionID TargetRegion => TargetZone; public DimensionWarpItem(RegionID targetZone, string? align, bool clearDimension) : base(MakeRandData()) { TargetZone = targetZone; ClearDimension = clearDimension; WarpAlign = align; } public static string MakeName(Zone.Data targetZone, string? align, bool clearDimension) { if (align != null) { return $"Warp to {targetZone.LayerName} (Align: {align}) {(clearDimension ? " (with DimensionClearing)" : "")}"; } return "Warp to " + targetZone.ZoneName + " " + (clearDimension ? " (with DimensionClearing)" : ""); } public static ItemData MakeRandData() { return new ItemData { IsProgression = true }; } public override IEnumerable OnRetrieveFromTerminalSystem(StateTracker stateTracker, LG_ComputerTerminal terminal, ItemID itemId) { Zone.Data zone = new Zone.Data(stateTracker.GameData, TargetZone); yield return delegate { //IL_0017: Unknown result type (might be due to invalid IL or missing references) terminal.AddLine((TerminalLineType)2, "Initiating Dimension Warp to " + Enum.GetName((eDimensionIndex)zone.LayerType), 2f); terminal.AddLine("Warp will occur in 3 seconds. Enjoy the scenery :)", true); }; yield return delegate { //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_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0018: 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_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_0060: 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_008c: Expected O, but got Unknown WardenObjectiveEventData val = new WardenObjectiveEventData { Type = (eWardenObjectiveEventType)8, DimensionIndex = zone.LayerType, Layer = zone.LayerType }; ExpeditionZoneData? zone2 = zone.Zone; val.LocalIndex = (eLocalZoneIndex)((zone2 != null) ? ((int)zone2.LocalIndex) : 0); val.Delay = 3f; val.ClearDimension = ClearDimension; val.WorldEventObjectFilter = WarpAlign; WorldEventManager.ExecuteEvent(val, 0f); }; } } private static IArchiveLogger? m_featureLogger; public override string Name => "Warp Events Helper"; public override string Description => "Handles dimension warp events as paths"; public override FeatureGroup Group => ArchipelagoFeatureGroups.get_EventHandlers(); public new static IArchiveLogger FeatureLogger { get { return m_featureLogger ?? Plugin.Get().Logger; } set { m_featureLogger = value; } } [Event.Callback] public void AddEventWarps(Event.Data data) { //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Invalid comparison between Unknown and I4 int num = 0; foreach (WardenObjectiveEventData datum in data) { if ((int)datum.Type == 8) { num++; Zone.Data data2 = data.FindZoneByEvent(datum); if (data2 == null) { FeatureLogger.Warning("Failed to identify warp target for event: " + data.EventName); continue; } EventHelper.CreateEventLocation(data, datum, num, data2.Item_WarpEvent_Instance(datum.WorldEventObjectFilter, datum.ClearDimension)); data.AddPath(new ReTFO.Archipelago.ModdedInstanceData.Model.Path { StartingRegion = data.Region_Event, EndingRegion = data2.Region_Zone, Reqs = new ReTFO.Archipelago.ModdedInstanceData.Model.Path.MultiPathReq(ReTFO.Archipelago.ModdedInstanceData.Model.Path.eType.Category, WarpEvent_Tags.get_Item_WarpEvent_ByZone(data2), 1u) }); } } } } public static class WinEventHandler_Tags { [SpecialName] public sealed class $2B8804A94F2EF68DF77A343A46EE5A78 { [SpecialName] public static class $F943E16B16B76A20C49A59C8DF7C8955 { } [ExtensionMarker("$F943E16B16B76A20C49A59C8DF7C8955")] public ItemID Item_WinEvent { [ExtensionMarker("$F943E16B16B76A20C49A59C8DF7C8955")] get { throw new NotSupportedException(); } } } [SpecialName] public sealed class $2833969430CAB23CD70890D67B9ADDD5 { [SpecialName] public static class $5667123F7013DAD37BB214B248F3E5D2 { } [ExtensionMarker("$5667123F7013DAD37BB214B248F3E5D2")] public ItemID Item_WinEvent_ByExpedition { [ExtensionMarker("$5667123F7013DAD37BB214B248F3E5D2")] get { throw new NotSupportedException(); } } [ExtensionMarker("$5667123F7013DAD37BB214B248F3E5D2")] public ItemID Item_WinEvent_Instance(bool onDeath) { throw new NotSupportedException(); } } public static ItemID get_Item_WinEvent(Game.Data gameData) { return ItemID.From(gameData, "Win Event Items", (Game.Data data) => new TagDefinition("Event items which cause the player to immediately clear the main sector and extract (sometimes triggered on death)", EventHelper_Tags.get_Item_Event(data))); } public static ItemID get_Item_WinEvent_ByExpedition(Expedition.Data data) { return ItemID.From(data, data.ExpeditionName + " Win Event Items", (Expedition.Data gameData) => new TagDefinition("Parent tag for win event items for a particular expedition", get_Item_WinEvent(gameData))); } public static ItemID Item_WinEvent_Instance(this Expedition.Data data, bool onDeath) { return ItemID.From(data, onDeath ? (data.ExpeditionName + " Win-On-Death Event") : (data.ExpeditionName + " Instance Win Event"), (Expedition.Data data2) => new TagDefinition("A particular type of win event item for an expedition", get_Item_WinEvent_ByExpedition(data2)), new WinEventHandler.InstantWinItem(data.Region_Expedition, onDeath)); } } [EnableFeatureByDefault] [AutomatedFeature] public class WinEventHandler : ArchipelagoFeature { public class InstantWinItem : TerminalItem { public RegionID ExpeditionRegion { get; private init; } public bool OnDeath { get; private init; } public override RegionID TargetRegion => ExpeditionRegion; public InstantWinItem(RegionID expedition, bool onDeath) : base(MakeRandData()) { ExpeditionRegion = expedition; OnDeath = onDeath; } public static ItemData MakeRandData() { return new ItemData { IsProgression = true }; } public override IEnumerable OnRetrieveFromTerminalSystem(StateTracker stateTracker, LG_ComputerTerminal terminal, ItemID itemId) { yield return delegate { terminal.AddLine((TerminalLineType)2, "Retrieving your win event", 2f); }; yield return delegate { //IL_0048: 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_0055: 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: Expected O, but got Unknown //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_001a: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Expected O, but got Unknown if (OnDeath) { WorldEventManager.ExecuteEvent(new WardenObjectiveEventData { Type = (eWardenObjectiveEventType)26, Layer = (LG_LayerType)0, Delay = 0f }, 0f); terminal.AddLine("<#F00>ERROR: Prisoner death required. Proceed to self-terminate immediately.", true); } else { WorldEventManager.ExecuteEvent(new WardenObjectiveEventData { Type = (eWardenObjectiveEventType)27, Layer = (LG_LayerType)0, Delay = 0f }, 0f); terminal.AddLine("Congrats, you win!", true); } }; } } private static IArchiveLogger? m_featureLogger; public override string Name => "Win Event Handler"; public override string Description => "Handles the Win event type.\nWin events immediately complete the main sector and end the expedition, skipping extract.\nThe WinOnDeath event is treated as a win event, with the assumption you will die very soon."; public override FeatureGroup Group => ArchipelagoFeatureGroups.get_EventHandlers(); public new static IArchiveLogger FeatureLogger { get { return m_featureLogger ?? Plugin.Get().Logger; } set { m_featureLogger = value; } } [Expedition.Callback] public void AddInstanceWinPaths(Expedition.Data data) { Layer.Data data2 = Layer.get_MainLayer(data); data.AddPath(new ReTFO.Archipelago.ModdedInstanceData.Model.Path { StartingRegion = data2.Region_Layer, EndingRegion = SharedObjectiveHandler_Tags.get_Region_SectorCleared(data2), Reqs = new ReTFO.Archipelago.ModdedInstanceData.Model.Path.MultiPathReq(ReTFO.Archipelago.ModdedInstanceData.Model.Path.eType.Category, WinEventHandler_Tags.get_Item_WinEvent_ByExpedition(data), 1u) }); } [Event.Callback] public void ProcessWinEvents(Event.Data data) { //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Invalid comparison between Unknown and I4 //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Invalid comparison between Unknown and I4 //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Invalid comparison between Unknown and I4 int num = 0; foreach (WardenObjectiveEventData datum in data) { if ((int)datum.Type == 27 || (int)datum.Type == 26) { num++; EventHelper.CreateEventLocation(data, datum, num, data.Item_WinEvent_Instance((int)datum.Type == 26)); } } } } } namespace ReTFO.Archipelago.FeaturesAPI { public class ArchipelagoFeature : Feature { private static IArchiveLogger? m_featureLogger; public override string Name => "Archipelago Feature"; public override string Description => "Abstract base class used by Archipelago features and handlers"; public override FeatureGroup Group => ArchipelagoFeatureGroups.get_Archipelago(); public static IArchiveLogger FeatureLogger { get { return m_featureLogger ?? (m_featureLogger = Plugin.Get().Logger); } set { m_featureLogger = value; } } public override bool ShouldInit() { if (!Plugin.TryGet(out Plugin _)) { FeatureLogger.Error("Failed to find plugin during init for feature: " + ((object)this).GetType().FullName); return false; } if (((object)this).GetType() == typeof(ArchipelagoFeature)) { return false; } return ((Feature)this).ShouldInit(); } public override void OnEnable() { ((Feature)this).OnEnable(); ArchipelagoFeatureHelper.RegisterInstancedCallbacks(this); } public override void OnDisable() { ((Feature)this).OnDisable(); ArchipelagoFeatureHelper.UnregisterInstancedCallbacks(this); } public override bool Equals(object? obj) { if (obj is ArchipelagoFeatureHelper.FakeFeature fakeFeature) { return ((object)this).GetType().Equals(fakeFeature.WrappedType); } return ((object)this).GetType().Equals(obj?.GetType()); } public override int GetHashCode() { return ((object)this).GetType().GetHashCode(); } } public static class ArchipelagoFeatureHelper { [ForceDisable("Internal archipelago feature used only for finding features")] [HideInModSettings] internal class FakeFeature : ArchipelagoFeature { public override string Name => "Archipelago Fake Feature"; public override string Description => "Feature used by Archipelago for hash lookups"; public override FeatureGroup Group => ArchipelagoFeatureGroups.get_Archipelago(); public Type? WrappedType { get; set; } public FakeFeature() { WrappedType = null; } public FakeFeature(Type intendedType) { WrappedType = intendedType; } public override bool Equals(object? obj) { return WrappedType?.Equals(obj?.GetType()) ?? (obj == null); } public override int GetHashCode() { return WrappedType?.GetHashCode() ?? 0; } } public static TFeature GetFeature() where TFeature : ArchipelagoFeature { Exception ex = null; if (!InitSingletonBase.Instance.RegisteredFeatures.TryGetValue((Feature)(object)new FakeFeature(typeof(TFeature)), out var actualValue)) { ex = new KeyNotFoundException("Could not find a registered feature of type " + typeof(TFeature).FullName); FeatureLogger.Exception(ex); throw ex; } if (!(actualValue is TFeature result)) { ex = new NotSupportedException("When searching for registered feature of type " + typeof(TFeature).FullName + ", instead got a feature of type " + ((object)actualValue).GetType().FullName); FeatureLogger.Exception(ex); throw ex; } return result; } public static IEnumerable GetProcessorCallbacks(Type type) { return from m in type.GetMethods(BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic) where m.CustomAttributes.Any((CustomAttributeData a) => a.AttributeType.IsAssignableTo(typeof(MidManager.Processor.CallbackBase))) select m; } public static IEnumerable GetInstancedProcessorCallbacks(Type type) { return from m in GetProcessorCallbacks(type) where !m.IsStatic select m; } public static void RegisterInstancedCallbacks(object instance) { IEnumerable instancedProcessorCallbacks = GetInstancedProcessorCallbacks(instance.GetType()); MidManager midManager = Plugin.Get().MidManager; foreach (MethodInfo item in instancedProcessorCallbacks) { MidManager.Processor.CallbackBase customAttribute = item.GetCustomAttribute(); if (customAttribute == null) { throw new NotSupportedException("After checking for the Callback attribute, it was still somehow null!"); } MidManager.Processor processor = midManager.GetProcessor(customAttribute.DataType); Delegate obj = Delegate.CreateDelegate(customAttribute.DelegateType, instance, item, throwOnBindFailure: false); if ((object)obj == null) { FeatureLogger.Error($"Failed to bind delegate! Method: {item.DeclaringType.FullName}.{item.Name} Delegate Type: {customAttribute.DelegateType.DeclaringType}.{customAttribute.DelegateType.Name}"); } else { processor.UntypedRegisterCallback(obj); } } } public static void UnregisterInstancedCallbacks(object instance) { IEnumerable instancedProcessorCallbacks = GetInstancedProcessorCallbacks(instance.GetType()); MidManager midManager = Plugin.Get().MidManager; foreach (MethodInfo item in instancedProcessorCallbacks) { MidManager.Processor.CallbackBase customAttribute = item.GetCustomAttribute(); if (customAttribute == null) { throw new NotSupportedException("After checking for the Callback attribute, it was still somehow null!"); } MidManager.Processor processor = midManager.GetProcessor(customAttribute.DataType); Delegate callback = Delegate.CreateDelegate(customAttribute.DelegateType, instance, item); processor.UntypedUnregisterCallback(callback); } } } public static class FeatureLogger { private static IArchiveLogger? m_current; public static IArchiveLogger Current { get { return m_current ?? (m_current = Plugin.Get().Logger); } set { m_current = value; } } public static void Success(string msg) { Current.Success(msg); } public static void Notice(string msg) { Current.Notice(msg); } public static void Msg(ConsoleColor col, string msg) { Current.Msg(col, msg); } public static void Info(string msg) { Current.Info(msg); } public static void Fail(string msg) { Current.Fail(msg); } public static void Debug(string msg) { Current.Debug(msg); } public static void Warning(string msg) { Current.Warning(msg); } public static void Error(string msg) { Current.Error(msg); } public static void Exception(Exception ex) { Current.Exception(ex); } } }