using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text.RegularExpressions;
using BepInEx;
using BepInEx.Logging;
using Configgy;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using UnityEngine;
using UnityEngine.SceneManagement;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("FriendlyGabriel")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyFileVersion("2.0.12.0")]
[assembly: AssemblyInformationalVersion("2.0.12")]
[assembly: AssemblyProduct("FriendlyGabriel")]
[assembly: AssemblyTitle("FriendlyGabriel")]
[assembly: AssemblyVersion("2.0.12.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
[CompilerGenerated]
[Embedded]
internal sealed class EmbeddedAttribute : Attribute
{
}
}
namespace System.Runtime.CompilerServices
{
[CompilerGenerated]
[Embedded]
[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
internal sealed class RefSafetyRulesAttribute : Attribute
{
public readonly int Version;
public RefSafetyRulesAttribute(int P_0)
{
Version = P_0;
}
}
}
namespace FriendlyGabriel
{
internal static class Cfg
{
[Configgable("General", "Enable Friendly Gabriel", 0, null)]
public static bool Enabled = true;
[Configgable("General", "Debug logging", 0, null)]
public static bool DebugLogging = false;
[Configgable("Companions", "Gabriel, Judge of Hell is friendly", 0, null)]
public static bool FirstGabriel = true;
[Configgable("Companions", "Gabriel, Apostate of Hope is friendly", 0, null)]
public static bool SecondGabriel = true;
[Configgable("Durability", "Immortal", 0, null)]
public static bool Immortal = true;
[Configgable("Durability", "Health pool", 0, null)]
public static float MaxHealth = 999f;
[Configgable("Durability", "Revive if killed anyway", 0, null)]
public static bool ReviveIfKilled = true;
[Configgable("Following", "Follow player", 0, null)]
public static bool FollowPlayer = true;
[Configgable("Following", "Stay within distance", 0, null)]
public static float FollowDistance = 5f;
[Configgable("Following", "Follow speed", 0, null)]
public static float FollowSpeed = 12f;
[Configgable("Following", "Face the player while following", 0, null)]
public static bool FacePlayer = true;
[Configgable("Following", "Teleport distance", 0, null)]
public static float TeleportDistance = 80f;
[Configgable("Spawning", "Spawn companion Gabriel", 0, null)]
public static bool SpawnCompanion = true;
[Configgable("Spawning", "Spawn after level", 0, null)]
public static string SpawnAfterLevel = "3-2";
[Configgable("Spawning", "Spawn Gabriel Second instead", 0, null)]
public static bool SpawnGabrielSecond = false;
[Configgable("Spawning", "Spawn distance", 0, null)]
public static float SpawnDistance = 4f;
[Configgable("Spawning", "Prefab keys", 0, null)]
public static string PrefabKeys = "Assets/Prefabs/Enemies/Gabriel.prefab,Assets/Prefabs/Enemies/Gabriel Second.prefab";
[Configgable("Protection", "Block damage to me near friendly Gabriel", 0, null)]
public static bool ProtectPlayer = true;
[Configgable("Protection", "Protection radius", 0, null)]
public static float ProtectRadius = 30f;
[Configgable("Combat", "Attack enemies", 0, null)]
public static bool AttackEnemies = true;
[Configgable("Combat", "Max target range", 0, null)]
public static float TargetRange = 0f;
[Configgable("Combat", "Enemy scan interval", 0, null)]
public static float ScanInterval = 0.5f;
[Configgable("Advanced", "Ignored enemy types", 0, null)]
public static string IgnoredEnemyTypes = "None";
[Configgable("Advanced", "Decoy target when no enemies left", 0, null)]
public static bool UseDecoyTarget = true;
[Configgable("Level Progression", "Open exit without killing Gabriel", 0, null)]
public static bool OpenExitWithoutKill = true;
[Configgable("Level Progression", "Exit delay", 0, null)]
public static float OpenExitDelay = 3f;
[Configgable("Level Progression", "Exit levels", 0, null)]
public static string ExitLevels = "3-2,6-2";
private static string _lastIgnoredRaw;
private static readonly HashSet<int> _ignored = new HashSet<int>();
public static bool IsIgnored(EnemyType type)
{
//IL_00be: Unknown result type (might be due to invalid IL or missing references)
//IL_00c4: Expected I4, but got Unknown
//IL_008c: Unknown result type (might be due to invalid IL or missing references)
//IL_0093: Expected I4, but got Unknown
string text = IgnoredEnemyTypes ?? string.Empty;
if (!string.Equals(text, _lastIgnoredRaw, StringComparison.Ordinal))
{
_lastIgnoredRaw = text;
_ignored.Clear();
string[] array = text.Split(',');
foreach (string text2 in array)
{
string text3 = text2.Trim();
if (text3.Length != 0 && !text3.Equals("None", StringComparison.OrdinalIgnoreCase))
{
if (Enum.TryParse<EnemyType>(text3, ignoreCase: true, out EnemyType result))
{
_ignored.Add((int)result);
}
else
{
FriendlyGabrielPlugin.Log.LogWarning((object)("Unknown enemy type in ignore list: " + text3));
}
}
}
}
return _ignored.Contains((int)type);
}
}
internal static class CompanionManager
{
private class TargetCache
{
public Transform Victim;
public EnemyTarget VictimTarget;
public GameObject Decoy;
public bool FallbackSet;
public EnemyTarget DecoyTarget;
}
private class Seen
{
public Transform T;
public float Time;
}
private static readonly Dictionary<int, int> _kindCache = new Dictionary<int, int>();
private static readonly HashSet<int> _loggedTypes = new HashSet<int>();
private static readonly Dictionary<int, TargetCache> _cache = new Dictionary<int, TargetCache>();
private static EnemyIdentifier[] _enemies = (EnemyIdentifier[])(object)new EnemyIdentifier[0];
private static float _nextScan;
private static Transform _player;
private const BindingFlags AnyInstance = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;
private static bool _nativeLooked;
private static FieldInfo _fIgnorePlayer;
private static FieldInfo _fAttackEnemies;
private static MethodInfo _mSetFallbackTarget;
private static PropertyInfo _pIsCurrentTargetFallback;
private static bool _fallbackBroken;
private static readonly Dictionary<int, Seen> _seen = new Dictionary<int, Seen>();
private static readonly Dictionary<int, int> _instanceKind = new Dictionary<int, int>();
private static readonly Dictionary<int, EnemyIdentifier> _companions = new Dictionary<int, EnemyIdentifier>();
private static readonly Dictionary<int, int> _lastTickFrame = new Dictionary<int, int>();
private static Gabriel[] _gabriels = (Gabriel[])(object)new Gabriel[0];
private static GabrielSecond[] _gabrielSeconds = (GabrielSecond[])(object)new GabrielSecond[0];
public static bool LoopDrivesTick = true;
private static readonly Dictionary<int, EnemyIdentifier> _hookEid = new Dictionary<int, EnemyIdentifier>();
private static bool _hookLogged;
private static bool _loopLogged;
private static bool _scanLoggedThisScene;
private static bool Native
{
get
{
if (!_nativeLooked)
{
_nativeLooked = true;
Type typeFromHandle = typeof(EnemyIdentifier);
_fIgnorePlayer = typeFromHandle.GetField("ignorePlayer", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
_fAttackEnemies = typeFromHandle.GetField("attackEnemies", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
_mSetFallbackTarget = typeFromHandle.GetMethod("SetFallbackTarget", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
_pIsCurrentTargetFallback = typeFromHandle.GetProperty("IsCurrentTargetFallback", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
FriendlyGabrielPlugin.Log.LogInfo((object)("Game friendly-AI fields: ignorePlayer=" + (_fIgnorePlayer != null) + ", attackEnemies=" + (_fAttackEnemies != null) + ", SetFallbackTarget=" + (_mSetFallbackTarget != null) + ", IsCurrentTargetFallback=" + (_pIsCurrentTargetFallback != null)));
}
return _fIgnorePlayer != null && _fAttackEnemies != null;
}
}
public static bool FirstIsImmortal => Cfg.Enabled && Cfg.FirstGabriel && Cfg.Immortal;
public static bool SecondIsImmortal => Cfg.Enabled && Cfg.SecondGabriel && Cfg.Immortal;
private unsafe static int Kind(EnemyType t)
{
//IL_0001: Unknown result type (might be due to invalid IL or missing references)
//IL_0003: Expected I4, but got Unknown
int num = (int)t;
if (!_kindCache.TryGetValue(num, out var value))
{
string text = ((object)(*(EnemyType*)(&t))/*cast due to .constrained prefix*/).ToString();
value = num switch
{
28 => 2,
16 => 1,
_ => (text == "Gabriel") ? 1 : ((text == "GabrielSecond") ? 2 : 0),
};
_kindCache[num] = value;
}
return value;
}
private static void ApplyNative(EnemyIdentifier eid)
{
_fIgnorePlayer.SetValue(eid, true);
_fAttackEnemies.SetValue(eid, Cfg.AttackEnemies);
}
private static bool CurrentTargetIsFallback(EnemyIdentifier eid)
{
if (_pIsCurrentTargetFallback == null)
{
return true;
}
try
{
return (bool)_pIsCurrentTargetFallback.GetValue(eid, null);
}
catch
{
return true;
}
}
private static void SetFallback(EnemyIdentifier eid, TargetCache cache, Transform self, Transform player)
{
//IL_003c: Unknown result type (might be due to invalid IL or missing references)
//IL_0046: Expected O, but got Unknown
//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_0063: 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_0068: 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_0076: Unknown result type (might be due to invalid IL or missing references)
//IL_0081: 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_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_00c4: Unknown result type (might be due to invalid IL or missing references)
//IL_00c9: Unknown result type (might be due to invalid IL or missing references)
//IL_00a7: 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)
if (!Cfg.UseDecoyTarget || _mSetFallbackTarget == null || _fallbackBroken)
{
return;
}
if ((Object)(object)cache.Decoy == (Object)null)
{
cache.Decoy = new GameObject("FriendlyGabriel_Decoy");
}
Vector3 val = (((Object)(object)player != (Object)null) ? (self.position - player.position) : self.forward);
((Vector3)(ref val))..ctor(val.x, 0f, val.z);
if (Vector3.Distance(val, new Vector3(0f, 0f, 0f)) < 0.01f)
{
val = self.forward;
}
cache.Decoy.transform.position = self.position + val * 40f;
if (cache.FallbackSet)
{
return;
}
try
{
_mSetFallbackTarget.Invoke(eid, new object[1] { cache.Decoy.transform });
cache.FallbackSet = true;
FriendlyGabrielPlugin.Log.LogInfo((object)("Fallback target set for " + ((object)Unsafe.As<EnemyType, EnemyType>(ref eid.enemyType)/*cast due to .constrained prefix*/).ToString()));
}
catch (Exception ex)
{
_fallbackBroken = true;
FriendlyGabrielPlugin.Log.LogWarning((object)("SetFallbackTarget failed, decoy disabled: " + ex.Message));
}
}
private static void MarkSeen(EnemyIdentifier eid)
{
int instanceID = ((Object)eid).GetInstanceID();
if (!_seen.TryGetValue(instanceID, out var value))
{
value = new Seen();
_seen[instanceID] = value;
}
value.T = ((Component)eid).transform;
value.Time = Time.time;
}
public static bool PlayerShouldBeProtected()
{
//IL_009b: 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)
if (!Cfg.Enabled || !Cfg.ProtectPlayer)
{
return false;
}
Transform player = GetPlayer();
if ((Object)(object)player == (Object)null)
{
return false;
}
float num = Mathf.Max(1f, Cfg.ProtectRadius);
foreach (Seen value in _seen.Values)
{
if ((Object)(object)value.T == (Object)null || Time.time - value.Time > 1f || !(Vector3.Distance(value.T.position, player.position) <= num))
{
continue;
}
return true;
}
return false;
}
private static int KindOf(EnemyIdentifier eid)
{
//IL_0021: Unknown result type (might be due to invalid IL or missing references)
//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
//IL_00b2: Expected I4, but got Unknown
int instanceID = ((Object)eid).GetInstanceID();
if (_instanceKind.TryGetValue(instanceID, out var value))
{
return value;
}
value = Kind(eid.enemyType);
if (value == 0)
{
if ((Object)(object)((Component)eid).GetComponent<Gabriel>() != (Object)null)
{
value = 1;
}
else if ((Object)(object)((Component)eid).GetComponent<GabrielSecond>() != (Object)null)
{
value = 2;
}
}
_instanceKind[instanceID] = value;
if (value != 0)
{
FriendlyGabrielPlugin.Log.LogInfo((object)("Gabriel recognised: enemy type " + ((object)Unsafe.As<EnemyType, EnemyType>(ref eid.enemyType)/*cast due to .constrained prefix*/).ToString() + " (" + (int)eid.enemyType + "), kind " + value));
}
return value;
}
public static bool IsCompanion(EnemyIdentifier eid)
{
if (!Cfg.Enabled || (Object)(object)eid == (Object)null)
{
return false;
}
int num = KindOf(eid);
return (num == 1 && Cfg.FirstGabriel) || (num == 2 && Cfg.SecondGabriel);
}
public static void OnSceneLoaded()
{
LevelProgression.OnSceneLoaded();
SpawnManager.OnSceneLoaded();
_scanLoggedThisScene = false;
_lastTickFrame.Clear();
_companions.Clear();
_hookEid.Clear();
_instanceKind.Clear();
_gabriels = (Gabriel[])(object)new Gabriel[0];
_gabrielSeconds = (GabrielSecond[])(object)new GabrielSecond[0];
_seen.Clear();
_player = null;
_enemies = (EnemyIdentifier[])(object)new EnemyIdentifier[0];
_nextScan = 0f;
foreach (TargetCache value in _cache.Values)
{
if ((Object)(object)value.Decoy != (Object)null)
{
Object.Destroy((Object)(object)value.Decoy);
}
}
_cache.Clear();
}
public static Transform PlayerTransform()
{
return GetPlayer();
}
public static bool HasAnyGabriel()
{
RefreshEnemies();
for (int i = 0; i < _gabriels.Length; i++)
{
if ((Object)(object)_gabriels[i] != (Object)null)
{
return true;
}
}
for (int j = 0; j < _gabrielSeconds.Length; j++)
{
if ((Object)(object)_gabrielSeconds[j] != (Object)null)
{
return true;
}
}
return false;
}
public static void MoveAll()
{
//IL_008b: 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_00ae: 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_00c8: Unknown result type (might be due to invalid IL or missing references)
//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
if (!Cfg.Enabled || !Native)
{
return;
}
Transform player = GetPlayer();
if ((Object)(object)player == (Object)null)
{
return;
}
foreach (EnemyIdentifier value in _companions.Values)
{
if (!((Object)(object)value == (Object)null) && IsCompanion(value))
{
Transform transform = ((Component)value).transform;
if (Cfg.TeleportDistance > 0f && Vector3.Distance(transform.position, player.position) > Cfg.TeleportDistance)
{
transform.position = player.position - player.forward * Mathf.Max(2f, Cfg.FollowDistance);
}
if (Cfg.FollowPlayer && (Object)(object)FindNearestEnemy(value) == (Object)null)
{
FollowStep(transform, player);
}
}
}
}
public static void Tick(EnemyIdentifier eid)
{
//IL_0119: Unknown result type (might be due to invalid IL or missing references)
//IL_011f: Unknown result type (might be due to invalid IL or missing references)
//IL_0133: Unknown result type (might be due to invalid IL or missing references)
//IL_0138: Unknown result type (might be due to invalid IL or missing references)
//IL_00f6: Unknown result type (might be due to invalid IL or missing references)
//IL_00fc: Unknown result type (might be due to invalid IL or missing references)
//IL_01c4: Unknown result type (might be due to invalid IL or missing references)
//IL_01ce: Expected O, but got Unknown
//IL_0283: Unknown result type (might be due to invalid IL or missing references)
//IL_0289: Unknown result type (might be due to invalid IL or missing references)
//IL_0293: Unknown result type (might be due to invalid IL or missing references)
//IL_0298: Unknown result type (might be due to invalid IL or missing references)
//IL_0253: Unknown result type (might be due to invalid IL or missing references)
//IL_025d: Expected O, but got Unknown
//IL_026b: Unknown result type (might be due to invalid IL or missing references)
//IL_0275: Expected O, but got Unknown
if (!IsCompanion(eid))
{
return;
}
int instanceID = ((Object)eid).GetInstanceID();
if (_lastTickFrame.TryGetValue(instanceID, out var value) && value == Time.frameCount)
{
return;
}
_lastTickFrame[instanceID] = Time.frameCount;
MarkSeen(eid);
_companions[((Object)eid).GetInstanceID()] = eid;
LevelProgression.Tick(eid);
DebugDump.Once(eid);
if (Cfg.Immortal)
{
if (Cfg.ReviveIfKilled && eid.dead)
{
eid.dead = false;
}
float num = Mathf.Max(1f, Cfg.MaxHealth);
if (eid.health < num)
{
eid.health = num;
}
}
Transform player = GetPlayer();
Transform transform = ((Component)eid).transform;
if (!Native && (Object)(object)player != (Object)null && Cfg.TeleportDistance > 0f && Vector3.Distance(transform.position, player.position) > Cfg.TeleportDistance)
{
transform.position = player.position - player.forward * Mathf.Max(2f, Cfg.FollowDistance);
}
TargetCache cache = GetCache(eid);
if (Native)
{
ApplyNative(eid);
SetFallback(eid, cache, transform, player);
return;
}
EnemyIdentifier val = (Cfg.AttackEnemies ? FindNearestEnemy(eid) : null);
if ((Object)(object)val != (Object)null)
{
if ((Object)(object)cache.Victim != (Object)(object)((Component)val).transform)
{
cache.Victim = ((Component)val).transform;
cache.VictimTarget = new EnemyTarget(((Component)val).transform);
if (Cfg.DebugLogging)
{
FriendlyGabrielPlugin.Log.LogInfo((object)(((object)Unsafe.As<EnemyType, EnemyType>(ref eid.enemyType)/*cast due to .constrained prefix*/).ToString() + " now targeting " + ((object)Unsafe.As<EnemyType, EnemyType>(ref val.enemyType)/*cast due to .constrained prefix*/).ToString()));
}
}
eid.target = cache.VictimTarget;
return;
}
cache.Victim = null;
if (Cfg.UseDecoyTarget)
{
if ((Object)(object)cache.Decoy == (Object)null)
{
cache.Decoy = new GameObject("FriendlyGabriel_Decoy");
cache.DecoyTarget = new EnemyTarget(cache.Decoy.transform);
}
cache.Decoy.transform.position = transform.position + transform.forward * 30f;
eid.target = cache.DecoyTarget;
}
else
{
eid.target = null;
}
if (Cfg.FollowPlayer && (Object)(object)player != (Object)null)
{
FollowStep(transform, player);
}
}
private static void FollowStep(Transform self, Transform player)
{
//IL_0002: Unknown result type (might be due to invalid IL or missing references)
//IL_0007: Unknown result type (might be due to invalid IL or missing references)
//IL_0009: 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_0032: Unknown result type (might be due to invalid IL or missing references)
//IL_0037: Unknown result type (might be due to invalid IL or missing references)
//IL_004d: Unknown result type (might be due to invalid IL or missing references)
//IL_0062: 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_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)
Vector3 position = player.position;
float num = Vector3.Distance(self.position, position);
if (!(num <= Mathf.Max(0.5f, Cfg.FollowDistance)))
{
self.position = Vector3.MoveTowards(self.position, position, Mathf.Max(0f, Cfg.FollowSpeed) * Time.deltaTime);
if (Cfg.FacePlayer)
{
self.LookAt(new Vector3(position.x, self.position.y, position.z));
}
}
}
private static Transform GetPlayer()
{
if ((Object)(object)_player == (Object)null)
{
GameObject val = GameObject.FindWithTag("Player");
_player = (((Object)(object)val != (Object)null) ? val.transform : null);
}
return _player;
}
private static TargetCache GetCache(EnemyIdentifier eid)
{
int instanceID = ((Object)eid).GetInstanceID();
if (!_cache.TryGetValue(instanceID, out var value))
{
value = new TargetCache();
_cache[instanceID] = value;
}
return value;
}
public static void TickFromHook(Component gabriel)
{
if ((Object)(object)gabriel == (Object)null || !Cfg.Enabled)
{
return;
}
int instanceID = ((Object)gabriel).GetInstanceID();
if (!_hookEid.TryGetValue(instanceID, out var value))
{
value = gabriel.GetComponent<EnemyIdentifier>();
_hookEid[instanceID] = value;
}
if (!((Object)(object)value == (Object)null))
{
if (!_hookLogged)
{
_hookLogged = true;
FriendlyGabrielPlugin.Log.LogInfo((object)("Gabriel hook running on " + ((object)gabriel).GetType().Name + " (enemy type " + ((object)Unsafe.As<EnemyType, EnemyType>(ref value.enemyType)/*cast due to .constrained prefix*/).ToString() + ", companion=" + IsCompanion(value) + ")"));
}
if (IsCompanion(value))
{
Tick(value);
}
}
}
private static void RefreshEnemies()
{
if (Time.unscaledTime >= _nextScan)
{
_enemies = Object.FindObjectsOfType<EnemyIdentifier>();
_gabriels = Object.FindObjectsOfType<Gabriel>();
_gabrielSeconds = Object.FindObjectsOfType<GabrielSecond>();
_nextScan = Time.unscaledTime + Mathf.Max(0.1f, Cfg.ScanInterval);
if (!_scanLoggedThisScene && (_enemies.Length != 0 || _gabriels.Length != 0 || _gabrielSeconds.Length != 0))
{
_scanLoggedThisScene = true;
FriendlyGabrielPlugin.Log.LogInfo((object)("Scan found " + _enemies.Length + " enemies, " + _gabriels.Length + " Gabriel and " + _gabrielSeconds.Length + " GabrielSecond components"));
}
}
}
public static void TickAll()
{
//IL_0082: Unknown result type (might be due to invalid IL or missing references)
//IL_008c: Expected I4, but got Unknown
//IL_00c4: Unknown result type (might be due to invalid IL or missing references)
//IL_00cb: Expected I4, but got Unknown
//IL_00de: Unknown result type (might be due to invalid IL or missing references)
if (!_loopLogged)
{
_loopLogged = true;
FriendlyGabrielPlugin.Log.LogInfo((object)("Companion loop running (Enabled=" + Cfg.Enabled + ")"));
}
if (!Cfg.Enabled || !LoopDrivesTick)
{
return;
}
RefreshEnemies();
for (int i = 0; i < _enemies.Length; i++)
{
EnemyIdentifier val = _enemies[i];
if (!((Object)(object)val == (Object)null))
{
if (_loggedTypes.Add((int)val.enemyType))
{
FriendlyGabrielPlugin.Log.LogInfo((object)("Enemy type seen: " + ((object)Unsafe.As<EnemyType, EnemyType>(ref val.enemyType)/*cast due to .constrained prefix*/).ToString() + " (" + (int)val.enemyType + ")" + ((Kind(val.enemyType) != 0) ? " <- treated as Gabriel" : "")));
}
if (IsCompanion(val))
{
Tick(val);
}
}
}
for (int j = 0; j < _gabriels.Length; j++)
{
TickFromComponent((Component)(object)_gabriels[j], 1);
}
for (int k = 0; k < _gabrielSeconds.Length; k++)
{
TickFromComponent((Component)(object)_gabrielSeconds[k], 2);
}
}
private static void TickFromComponent(Component c, int kind)
{
//IL_008d: Unknown result type (might be due to invalid IL or missing references)
//IL_0094: Expected I4, but got Unknown
if ((Object)(object)c == (Object)null)
{
return;
}
EnemyIdentifier component = c.GetComponent<EnemyIdentifier>();
if (!((Object)(object)component == (Object)null))
{
int instanceID = ((Object)component).GetInstanceID();
if (!_instanceKind.TryGetValue(instanceID, out var value) || value == 0)
{
_instanceKind[instanceID] = kind;
FriendlyGabrielPlugin.Log.LogInfo((object)("Gabriel recognised from component: enemy type " + ((object)Unsafe.As<EnemyType, EnemyType>(ref component.enemyType)/*cast due to .constrained prefix*/).ToString() + " (" + (int)component.enemyType + "), kind " + kind));
}
if (IsCompanion(component))
{
Tick(component);
}
}
}
private static EnemyIdentifier FindNearestEnemy(EnemyIdentifier self)
{
//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_006d: 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_008a: Unknown result type (might be due to invalid IL or missing references)
RefreshEnemies();
Vector3 position = ((Component)self).transform.position;
float num = ((Cfg.TargetRange > 0f) ? Cfg.TargetRange : float.PositiveInfinity);
EnemyIdentifier result = null;
for (int i = 0; i < _enemies.Length; i++)
{
EnemyIdentifier val = _enemies[i];
if (!((Object)(object)val == (Object)null) && !((Object)(object)val == (Object)(object)self) && !val.dead && !IsCompanion(val) && !Cfg.IsIgnored(val.enemyType))
{
float num2 = Vector3.Distance(position, ((Component)val).transform.position);
if (num2 < num)
{
num = num2;
result = val;
}
}
}
return result;
}
}
internal static class DebugDump
{
private static readonly HashSet<string> _done = new HashSet<string>();
public static void Once(EnemyIdentifier eid)
{
Dump(eid);
Dump(((Component)eid).GetComponent<Gabriel>());
Dump(((Component)eid).GetComponent<GabrielSecond>());
}
private static void Dump(object comp)
{
if (comp == null)
{
return;
}
Type type = comp.GetType();
if (!_done.Add(type.Name))
{
return;
}
FriendlyGabrielPlugin.Log.LogInfo((object)("--- " + type.Name + " members of interest (base: " + ((type.BaseType != null) ? type.BaseType.Name : "none") + ") ---"));
FieldInfo[] fields = type.GetFields(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
foreach (FieldInfo fieldInfo in fields)
{
if (Interesting(fieldInfo.Name) || Interesting(fieldInfo.FieldType.Name))
{
FriendlyGabrielPlugin.Log.LogInfo((object)("field " + fieldInfo.FieldType.Name + " " + fieldInfo.Name));
}
}
MethodInfo[] methods = type.GetMethods(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
foreach (MethodInfo methodInfo in methods)
{
if (Interesting(methodInfo.Name))
{
FriendlyGabrielPlugin.Log.LogInfo((object)("method " + methodInfo.Name + " (" + methodInfo.GetParameters().Length + " params)"));
}
}
}
private static bool Interesting(string n)
{
string text = n.ToLowerInvariant();
return text.Contains("target") || text.Contains("player") || text.Contains("damage") || text.Contains("hurt") || text.Contains("ignore") || text.Contains("friend") || text.Contains("attack") || text.Contains("death");
}
}
internal static class LevelId
{
private const BindingFlags Static = BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic;
private static readonly Regex LevelPattern = new Regex("(\\d+)-(\\d+)");
private static Assembly Game => typeof(EnemyIdentifier).Assembly;
public static string Best(out string candidates)
{
//IL_000f: Unknown result type (might be due to invalid IL or missing references)
//IL_0014: Unknown result type (might be due to invalid IL or missing references)
string text = FromSceneHelper();
int levelNumber;
string text2 = FromStats(out levelNumber);
Scene activeScene = SceneManager.GetActiveScene();
string name = ((Scene)(ref activeScene)).name;
candidates = "SceneHelper.CurrentScene='" + text + "', StatsManager mission='" + text2 + "' (levelNumber=" + levelNumber + "), scene='" + name + "'";
string[] array = new string[3] { text, text2, name };
foreach (string text3 in array)
{
if (!string.IsNullOrEmpty(text3) && LevelPattern.IsMatch(text3))
{
return text3;
}
}
return text ?? text2 ?? name ?? "";
}
public static string Best()
{
string candidates;
return Best(out candidates);
}
public static bool TryParse(string id, out int layer, out int number)
{
layer = (number = 0);
Match match = LevelPattern.Match(id ?? "");
if (!match.Success)
{
return false;
}
layer = int.Parse(match.Groups[1].Value);
number = int.Parse(match.Groups[2].Value);
return true;
}
private static string FromSceneHelper()
{
try
{
Type type = Game.GetType("SceneHelper");
if (type == null)
{
return null;
}
PropertyInfo property = type.GetProperty("CurrentScene", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
if (property != null)
{
return property.GetValue(null, null) as string;
}
FieldInfo field = type.GetField("CurrentScene", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
return (field != null) ? (field.GetValue(null) as string) : null;
}
catch
{
return null;
}
}
private static string FromStats(out int levelNumber)
{
levelNumber = -1;
try
{
Type type = Game.GetType("StatsManager");
if (type == null)
{
return null;
}
Object val = Object.FindObjectOfType(type);
if (val == (Object)null)
{
return null;
}
FieldInfo field = type.GetField("levelNumber", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
if (field == null)
{
return null;
}
levelNumber = (int)field.GetValue(val);
Type type2 = Game.GetType("GetMissionName");
MethodInfo methodInfo = ((type2 != null) ? type2.GetMethod("GetMission", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[1] { typeof(int) }, null) : null);
return (methodInfo != null) ? (methodInfo.Invoke(null, new object[1] { levelNumber }) as string) : null;
}
catch
{
return null;
}
}
}
internal static class LevelProgression
{
private static readonly HashSet<int> _fired = new HashSet<int>();
private static readonly Dictionary<int, float> _firstSeen = new Dictionary<int, float>();
private static int _sceneHandle = -1;
private static bool _sceneMatches;
public static void OnSceneLoaded()
{
_fired.Clear();
_firstSeen.Clear();
_sceneHandle = -1;
}
public static void Tick(EnemyIdentifier eid)
{
if (!Cfg.OpenExitWithoutKill || !SceneMatches())
{
return;
}
int instanceID = ((Object)eid).GetInstanceID();
if (!_fired.Contains(instanceID))
{
if (!_firstSeen.TryGetValue(instanceID, out var value))
{
_firstSeen[instanceID] = Time.time;
}
else if (!(Time.time - value < Mathf.Max(0f, Cfg.OpenExitDelay)))
{
_fired.Add(instanceID);
FireDeathEvents(eid);
}
}
}
private static bool SceneMatches()
{
//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)
Scene activeScene = SceneManager.GetActiveScene();
if (((Scene)(ref activeScene)).handle != _sceneHandle)
{
_sceneHandle = ((Scene)(ref activeScene)).handle;
_sceneMatches = false;
string text = LevelId.Best() + " " + (((Scene)(ref activeScene)).name ?? string.Empty);
string[] array = (Cfg.ExitLevels ?? string.Empty).Split(',');
foreach (string text2 in array)
{
string text3 = text2.Trim();
if (text3.Length > 0 && text.IndexOf(text3, StringComparison.OrdinalIgnoreCase) >= 0)
{
_sceneMatches = true;
break;
}
}
if (Cfg.DebugLogging)
{
FriendlyGabrielPlugin.Log.LogInfo((object)("Scene '" + text + "' exit-unlock active: " + _sceneMatches));
}
}
return _sceneMatches;
}
private static void FireDeathEvents(EnemyIdentifier eid)
{
int num = 0;
num += FireOn(((Component)eid).GetComponent<Gabriel>());
num += FireOn(((Component)eid).GetComponent<GabrielSecond>());
num += FireOn(eid);
if (num == 0)
{
FriendlyGabrielPlugin.Log.LogWarning((object)("No death event found on " + ((object)Unsafe.As<EnemyType, EnemyType>(ref eid.enemyType)/*cast due to .constrained prefix*/).ToString() + "; the exit may not open. Enable Debug logging to list the event fields."));
}
else
{
FriendlyGabrielPlugin.Log.LogInfo((object)("Fired " + num + " death event(s) for " + ((object)Unsafe.As<EnemyType, EnemyType>(ref eid.enemyType)/*cast due to .constrained prefix*/).ToString()));
}
}
private static int FireOn(object component)
{
if (component == null)
{
return 0;
}
int num = 0;
Type type = component.GetType();
while (type != null && type != typeof(MonoBehaviour) && type != typeof(object))
{
FieldInfo[] fields = type.GetFields(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
foreach (FieldInfo fieldInfo in fields)
{
bool flag = fieldInfo.Name.IndexOf("death", StringComparison.OrdinalIgnoreCase) >= 0;
string name = fieldInfo.FieldType.Name;
if (Cfg.DebugLogging && (name == "UltrakillEvent" || name == "UnityEvent" || fieldInfo.FieldType == typeof(GameObject[])))
{
FriendlyGabrielPlugin.Log.LogInfo((object)("Found " + name + " " + type.Name + "." + fieldInfo.Name));
}
if (!flag)
{
continue;
}
try
{
if (name == "UltrakillEvent" || name == "UnityEvent")
{
object value = fieldInfo.GetValue(component);
MethodInfo method = fieldInfo.FieldType.GetMethod("Invoke", Type.EmptyTypes);
if (value != null && method != null)
{
method.Invoke(value, null);
num++;
FriendlyGabrielPlugin.Log.LogInfo((object)("Fired " + type.Name + "." + fieldInfo.Name));
}
}
else
{
if (!(fieldInfo.FieldType == typeof(GameObject[])) || !(fieldInfo.GetValue(component) is GameObject[] array))
{
continue;
}
GameObject[] array2 = array;
foreach (GameObject val in array2)
{
if ((Object)(object)val != (Object)null)
{
val.SetActive(true);
}
}
num++;
FriendlyGabrielPlugin.Log.LogInfo((object)("Activated " + array.Length + " object(s) from " + type.Name + "." + fieldInfo.Name));
continue;
}
}
catch (Exception ex)
{
FriendlyGabrielPlugin.Log.LogError((object)("Failed on " + fieldInfo.Name + ": " + ex.Message));
}
}
type = type.BaseType;
}
return num;
}
}
internal static class Patches
{
public static void EnemyIdentifier_LateUpdate_Postfix(EnemyIdentifier __instance)
{
CompanionManager.Tick(__instance);
}
public static void GabrielBase_FixedUpdate_Prefix(Component __instance)
{
CompanionManager.TickFromHook(__instance);
}
public static bool Gabriel_TakeDamage_Prefix()
{
return !CompanionManager.FirstIsImmortal;
}
public static bool GabrielSecond_TakeDamage_Prefix()
{
return !CompanionManager.SecondIsImmortal;
}
public static bool NewMovement_GetHurt_Prefix()
{
return !CompanionManager.PlayerShouldBeProtected();
}
public static bool EnemyIdentifier_DeliverDamage_Prefix(EnemyIdentifier __instance, GameObject target)
{
if (!CompanionManager.IsCompanion(__instance))
{
return true;
}
if (Cfg.Immortal)
{
return false;
}
return !((Object)(object)target != (Object)null) || !target.CompareTag("Player");
}
}
[BepInPlugin("com.friendlygabriel.ultrakill", "Friendly Gabriel", "2.0.12")]
[BepInDependency(/*Could not decode attribute arguments.*/)]
[BepInProcess("ULTRAKILL.exe")]
public class FriendlyGabrielPlugin : BaseUnityPlugin
{
public const string Guid = "com.friendlygabriel.ultrakill";
public const string PluginName = "Friendly Gabriel";
public const string PluginVersion = "2.0.12";
internal static ManualLogSource Log;
private Harmony _harmony;
private bool _errorLogged;
private void Awake()
{
//IL_0017: Unknown result type (might be due to invalid IL or missing references)
//IL_0052: Unknown result type (might be due to invalid IL or missing references)
//IL_005c: Expected O, but got Unknown
Log = ((BaseUnityPlugin)this).Logger;
try
{
new ConfigBuilder("com.friendlygabriel.ultrakill", "Friendly Gabriel").BuildAll();
}
catch (Exception ex)
{
Log.LogError((object)("Configgy registration failed: " + ex));
}
_harmony = new Harmony("com.friendlygabriel.ultrakill");
int num = 0;
int num2 = 6;
if (TryPatch("GabrielBase", "FixedUpdate", "GabrielBase_FixedUpdate_Prefix", null))
{
num++;
CompanionManager.LoopDrivesTick = false;
}
if (TryPatch("EnemyIdentifier", "LateUpdate", null, "EnemyIdentifier_LateUpdate_Postfix"))
{
num++;
}
if (TryPatch("Gabriel", "TakeDamage", "Gabriel_TakeDamage_Prefix", null))
{
num++;
}
if (TryPatch("GabrielSecond", "TakeDamage", "GabrielSecond_TakeDamage_Prefix", null))
{
num++;
}
if (TryPatch("EnemyIdentifier", "DeliverDamage", "EnemyIdentifier_DeliverDamage_Prefix", null))
{
num++;
}
if (TryPatch("NewMovement", "GetHurt", "NewMovement_GetHurt_Prefix", null))
{
num++;
}
SceneManager.sceneLoaded += delegate
{
CompanionManager.OnSceneLoaded();
};
Log.LogInfo((object)("=== Friendly Gabriel 2.0.12 loaded (" + num + "/" + num2 + " optional patches applied) ==="));
}
private void LateUpdate()
{
try
{
CompanionManager.TickAll();
CompanionManager.MoveAll();
SpawnManager.Tick();
}
catch (Exception ex)
{
if (!_errorLogged)
{
_errorLogged = true;
Log.LogError((object)("Companion loop error (logged once): " + ex));
}
}
}
private bool TryPatch(string typeName, string methodName, string prefix, string postfix)
{
//IL_0097: 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)
try
{
Type type = typeof(EnemyIdentifier).Assembly.GetType(typeName);
if (type == null)
{
Log.LogWarning((object)("Type not found, skipped: " + typeName));
return false;
}
Type type2 = type;
while (type2 != null && type2 != typeof(object))
{
bool flag = false;
MethodInfo[] methods = type2.GetMethods(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
foreach (MethodInfo methodInfo in methods)
{
if (!(methodInfo.Name != methodName))
{
_harmony.Patch((MethodBase)methodInfo, (prefix == null) ? ((HarmonyMethod)null) : new HarmonyMethod(typeof(Patches).GetMethod(prefix)), (postfix == null) ? ((HarmonyMethod)null) : new HarmonyMethod(typeof(Patches).GetMethod(postfix)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
flag = true;
}
}
if (flag)
{
if (type2 != type)
{
Log.LogInfo((object)(typeName + "." + methodName + " is declared on parent class " + type2.Name + ", patched there"));
}
return true;
}
type2 = type2.BaseType;
}
Log.LogWarning((object)("Method not found (also checked parent classes), skipped: " + typeName + "." + methodName));
return false;
}
catch (Exception ex)
{
Log.LogError((object)("Patch failed for " + typeName + "." + methodName + ": " + ex.Message));
return false;
}
}
private void OnDestroy()
{
if (_harmony != null)
{
_harmony.UnpatchSelf();
}
}
}
internal static class SpawnManager
{
private static float _nextAttempt;
private static int _attempts;
private static GameObject _spawned;
private static bool _checkLogged;
private static string _lastCandidates;
public static void OnSceneLoaded()
{
_nextAttempt = Time.time + 4f;
_attempts = 0;
_spawned = null;
_checkLogged = false;
}
public static void Tick()
{
//IL_0194: Unknown result type (might be due to invalid IL or missing references)
//IL_019a: Unknown result type (might be due to invalid IL or missing references)
//IL_01ae: Unknown result type (might be due to invalid IL or missing references)
//IL_01b3: 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)
if (!Cfg.Enabled || !Cfg.SpawnCompanion || Time.time < _nextAttempt)
{
return;
}
_nextAttempt = Time.time + 3f;
string candidates;
bool flag = LevelQualifies(out candidates);
bool flag2 = CompanionManager.HasAnyGabriel();
if (!_checkLogged || candidates != _lastCandidates)
{
_checkLogged = true;
_lastCandidates = candidates;
FriendlyGabrielPlugin.Log.LogInfo((object)("Spawn check: " + candidates + " -> after '" + Cfg.SpawnAfterLevel + "' = " + flag + ", Gabriel already in level = " + flag2));
}
if (!flag || flag2 || (Object)(object)_spawned != (Object)null || _attempts >= 3)
{
return;
}
Transform val = CompanionManager.PlayerTransform();
if (!((Object)(object)val == (Object)null))
{
_attempts++;
int wantId = (Cfg.SpawnGabrielSecond ? 28 : 16);
GameObject val2 = FindPrefab(wantId);
if ((Object)(object)val2 == (Object)null)
{
FriendlyGabrielPlugin.Log.LogWarning((object)("Spawn attempt " + _attempts + "/3: could not find a Gabriel prefab (see 'Prefab keys' in the Spawning section)."));
return;
}
GameObject val3 = Object.Instantiate<GameObject>(val2);
val3.transform.position = val.position + val.right * Mathf.Max(1f, Cfg.SpawnDistance) + new Vector3(0f, 1f, 0f);
val3.SetActive(true);
_spawned = val3;
FriendlyGabrielPlugin.Log.LogInfo((object)("Spawned companion Gabriel from prefab '" + ((Object)val2).name + "'"));
}
}
private static bool LevelQualifies(out string candidates)
{
string id = LevelId.Best(out candidates);
if (!LevelId.TryParse(id, out var layer, out var number))
{
return false;
}
if (!LevelId.TryParse(Cfg.SpawnAfterLevel, out var layer2, out var number2))
{
return false;
}
return layer > layer2 || (layer == layer2 && number > number2);
}
private static GameObject FindPrefab(int wantId)
{
//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_0045: Unknown result type (might be due to invalid IL or missing references)
//IL_004b: Invalid comparison between Unknown and I4
//IL_00f7: Unknown result type (might be due to invalid IL or missing references)
//IL_00fd: Invalid comparison between Unknown and I4
//IL_0182: Unknown result type (might be due to invalid IL or missing references)
//IL_0188: Invalid comparison between Unknown and I4
GameObject[] array = Resources.FindObjectsOfTypeAll<GameObject>();
foreach (GameObject val in array)
{
if ((Object)(object)val == (Object)null)
{
continue;
}
Scene scene = val.scene;
if (!((Scene)(ref scene)).IsValid())
{
EnemyIdentifier component = val.GetComponent<EnemyIdentifier>();
if ((Object)(object)component != (Object)null && (int)component.enemyType == wantId)
{
FriendlyGabrielPlugin.Log.LogInfo((object)("Found loaded Gabriel prefab: " + ((Object)val).name));
return val;
}
}
}
string[] array2 = (Cfg.PrefabKeys ?? "").Split(',');
foreach (string text in array2)
{
string text2 = text.Trim();
if (text2.Length == 0)
{
continue;
}
GameObject val2 = LoadAddressable(text2);
if (!((Object)(object)val2 == (Object)null))
{
EnemyIdentifier component2 = val2.GetComponent<EnemyIdentifier>();
if ((Object)(object)component2 != (Object)null && (int)component2.enemyType == wantId)
{
FriendlyGabrielPlugin.Log.LogInfo((object)("Loaded Gabriel prefab via Addressables key: " + text2));
return val2;
}
}
}
foreach (string item in DiscoverGabrielKeys())
{
GameObject val3 = LoadAddressable(item);
if (!((Object)(object)val3 == (Object)null))
{
EnemyIdentifier component3 = val3.GetComponent<EnemyIdentifier>();
if ((Object)(object)component3 != (Object)null && (int)component3.enemyType == wantId)
{
FriendlyGabrielPlugin.Log.LogInfo((object)("Loaded Gabriel prefab via discovered key: " + item));
return val3;
}
}
}
return null;
}
private static List<string> DiscoverGabrielKeys()
{
List<string> list = new List<string>();
try
{
Type type = Type.GetType("UnityEngine.AddressableAssets.Addressables, Unity.Addressables");
Type type2 = Type.GetType("UnityEngine.AddressableAssets.ResourceLocators.IResourceLocator, Unity.Addressables");
if (type == null || type2 == null)
{
FriendlyGabrielPlugin.Log.LogInfo((object)"Addressables types not found, cannot discover keys");
return list;
}
PropertyInfo property = type.GetProperty("ResourceLocators", BindingFlags.Static | BindingFlags.Public);
PropertyInfo property2 = type2.GetProperty("Keys");
IEnumerable enumerable = ((property != null) ? (property.GetValue(null, null) as IEnumerable) : null);
if (enumerable == null || property2 == null)
{
return list;
}
foreach (object item in enumerable)
{
if (!(property2.GetValue(item, null) is IEnumerable enumerable2))
{
continue;
}
foreach (object item2 in enumerable2)
{
if (item2 is string text && text.IndexOf("gabriel", StringComparison.OrdinalIgnoreCase) >= 0 && text.EndsWith(".prefab", StringComparison.OrdinalIgnoreCase) && !list.Contains(text))
{
list.Add(text);
}
}
}
FriendlyGabrielPlugin.Log.LogInfo((object)("Addressables keys that look like Gabriel prefabs (" + list.Count + "):"));
for (int i = 0; i < list.Count && i < 25; i++)
{
FriendlyGabrielPlugin.Log.LogInfo((object)(" " + list[i]));
}
}
catch (Exception ex)
{
FriendlyGabrielPlugin.Log.LogInfo((object)("Key discovery failed: " + (ex.InnerException ?? ex).Message));
}
return list;
}
private static GameObject LoadAddressable(string key)
{
try
{
Type type = Type.GetType("UnityEngine.AddressableAssets.Addressables, Unity.Addressables");
if (type == null)
{
return null;
}
MethodInfo methodInfo = null;
MethodInfo[] methods = type.GetMethods(BindingFlags.Static | BindingFlags.Public);
foreach (MethodInfo methodInfo2 in methods)
{
ParameterInfo[] parameters = methodInfo2.GetParameters();
if (methodInfo2.Name == "LoadAssetAsync" && methodInfo2.IsGenericMethodDefinition && parameters.Length == 1 && parameters[0].ParameterType == typeof(object))
{
methodInfo = methodInfo2;
break;
}
}
if (methodInfo == null)
{
return null;
}
object obj = methodInfo.MakeGenericMethod(typeof(GameObject)).Invoke(null, new object[1] { key });
MethodInfo method = obj.GetType().GetMethod("WaitForCompletion");
return (GameObject)((method != null) ? /*isinst with value type is only supported in some contexts*/: null);
}
catch (Exception ex)
{
Exception ex2 = ex.InnerException ?? ex;
FriendlyGabrielPlugin.Log.LogInfo((object)("Addressables key '" + key + "' did not load: " + ex2.Message));
return null;
}
}
}
}