using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Photon.Pun;
using Photon.Realtime;
using UnityEngine;
using UnityEngine.SceneManagement;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("AdultSupervision")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("AdultSupervision")]
[assembly: AssemblyTitle("AdultSupervision")]
[assembly: AssemblyVersion("1.0.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
[CompilerGenerated]
[Embedded]
internal sealed class EmbeddedAttribute : Attribute
{
}
}
namespace System.Runtime.CompilerServices
{
[CompilerGenerated]
[Embedded]
[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
internal sealed class RefSafetyRulesAttribute : Attribute
{
public readonly int Version;
public RefSafetyRulesAttribute(int P_0)
{
Version = P_0;
}
}
}
namespace AdultSupervision
{
[BepInPlugin("emiko.adult-supervision", "Adult Supervision", "1.0.21")]
public sealed class Plugin : BaseUnityPlugin
{
public const string PluginGuid = "emiko.adult-supervision";
public const string PluginName = "Adult Supervision";
public const string PluginVersion = "1.0.21";
internal const string NearestFollowMode = "Nearest";
internal const string SpecificPlayerFollowMode = "SpecificUserId";
private const float SpawnCheckInterval = 2f;
private const float SceneTransitionGracePeriod = 5f;
private const float RescueDistance = 100f;
private Harmony _harmony;
private float _nextSpawnCheck;
private float _sceneTransitionGraceEnds;
private string _lastLoggedPlayerScene;
private int _rescuedScoutmasterInstanceId;
private ConfigEntry<string> _followMode;
private ConfigEntry<string> _specificPlayerUserId;
private ConfigEntry<float> _scoutmasterSfxVolume;
private ConfigEntry<KeyboardShortcut> _respawnScoutmasterKey;
private void Awake()
{
//IL_003b: Unknown result type (might be due to invalid IL or missing references)
//IL_0045: Expected O, but got Unknown
//IL_007b: Unknown result type (might be due to invalid IL or missing references)
//IL_0085: Expected O, but got Unknown
//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
//IL_00c3: Expected O, but got Unknown
//IL_00e3: Unknown result type (might be due to invalid IL or missing references)
//IL_0140: Unknown result type (might be due to invalid IL or missing references)
//IL_014a: Expected O, but got Unknown
_followMode = ((BaseUnityPlugin)this).Config.Bind<string>("Follow Target", "Mode", "Nearest", new ConfigDescription("Choose Nearest or SpecificUserId. In specific mode, the Scoutmaster waits if that user is not in the room.", (AcceptableValueBase)(object)new AcceptableValueList<string>(new string[2] { "Nearest", "SpecificUserId" }), Array.Empty<object>()));
_specificPlayerUserId = ((BaseUnityPlugin)this).Config.Bind<string>("Follow Target", "SpecificPlayerUserId", string.Empty, new ConfigDescription("Choose a player from the current lobby when Mode is SpecificUserId.", (AcceptableValueBase)(object)new LobbyPlayerAcceptableValues(() => _specificPlayerUserId?.Value), Array.Empty<object>()));
_scoutmasterSfxVolume = ((BaseUnityPlugin)this).Config.Bind<float>("Follow Target", "ScoutmasterSfxVolume", 1f, new ConfigDescription("Volume multiplier for the room Scoutmaster's sound effects. 0 mutes them; 1 keeps the original volume.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>()));
_respawnScoutmasterKey = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("Follow Target", "RespawnScoutmasterKey", new KeyboardShortcut((KeyCode)289, Array.Empty<KeyCode>()), "Respawn the room Scoutmaster. Only the room master can use this key.");
ScoutmasterUpdatePatch.Bind(((BaseUnityPlugin)this).Logger, _followMode, _specificPlayerUserId);
ScoutmasterSfxVolume.Bind(_scoutmasterSfxVolume);
ScoutmasterVoidWarpPatch.Bind(((BaseUnityPlugin)this).Logger);
ScoutmasterSpawnPosePatch.Bind(((BaseUnityPlugin)this).Logger);
ScoutmasterAggression.Bind(((BaseUnityPlugin)this).Logger);
_harmony = new Harmony("emiko.adult-supervision");
_harmony.PatchAll();
SceneManager.sceneLoaded += OnSceneLoaded;
((BaseUnityPlugin)this).Logger.LogInfo((object)"Adult Supervision loaded.");
}
private void Update()
{
//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_0081: 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_0087: Unknown result type (might be due to invalid IL or missing references)
//IL_01d1: Unknown result type (might be due to invalid IL or missing references)
//IL_01d7: 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_0389: Unknown result type (might be due to invalid IL or missing references)
//IL_03b4: Unknown result type (might be due to invalid IL or missing references)
//IL_03bb: Unknown result type (might be due to invalid IL or missing references)
//IL_03a5: Unknown result type (might be due to invalid IL or missing references)
//IL_03aa: Unknown result type (might be due to invalid IL or missing references)
//IL_0330: 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_0193: Unknown result type (might be due to invalid IL or missing references)
//IL_03e0: Unknown result type (might be due to invalid IL or missing references)
//IL_03e2: Unknown result type (might be due to invalid IL or missing references)
//IL_0233: 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)
//IL_0254: Unknown result type (might be due to invalid IL or missing references)
//IL_0259: Unknown result type (might be due to invalid IL or missing references)
//IL_0285: Unknown result type (might be due to invalid IL or missing references)
//IL_028c: Unknown result type (might be due to invalid IL or missing references)
//IL_02aa: Unknown result type (might be due to invalid IL or missing references)
//IL_02f3: Unknown result type (might be due to invalid IL or missing references)
KeyboardShortcut value = _respawnScoutmasterKey.Value;
bool flag = ((KeyboardShortcut)(ref value)).IsDown();
if (!PhotonNetwork.InRoom)
{
_nextSpawnCheck = 0f;
}
else
{
if (!PhotonNetwork.IsMasterClient)
{
return;
}
if (flag)
{
_nextSpawnCheck = 0f;
}
if (Time.time < _nextSpawnCheck)
{
return;
}
_nextSpawnCheck = Time.time + 2f;
Character localCharacter = Character.localCharacter;
if ((Object)(object)localCharacter == (Object)null || (Object)(object)localCharacter.data == (Object)null)
{
return;
}
Scene scene = ((Component)localCharacter).gameObject.scene;
Scoutmaster val = ScoutmasterSceneLookup.FindRoomScoutmasterInScene(scene, requireMine: false);
if (flag)
{
if ((Object)(object)val != (Object)null)
{
PhotonView component = ((Component)val).GetComponent<PhotonView>();
if ((Object)(object)component == (Object)null || !component.IsRoomView || !component.IsMine)
{
((BaseUnityPlugin)this).Logger.LogWarning((object)"Cannot respawn the active Scoutmaster because this room master does not own its room object.");
return;
}
try
{
PhotonNetwork.Destroy(((Component)val).gameObject);
_nextSpawnCheck = Time.time + 0.5f;
((BaseUnityPlugin)this).Logger.LogInfo((object)"Respawn requested: removed the active Scoutmaster; a replacement will spawn shortly.");
return;
}
catch (Exception arg)
{
((BaseUnityPlugin)this).Logger.LogError((object)$"Failed to remove the active Scoutmaster for respawn: {arg}");
return;
}
}
((BaseUnityPlugin)this).Logger.LogInfo((object)"Respawn requested: no active room Scoutmaster was found; attempting to spawn one.");
}
if (_lastLoggedPlayerScene != ((Scene)(ref scene)).name)
{
_lastLoggedPlayerScene = ((Scene)(ref scene)).name;
PhotonView val2 = (((Object)(object)val != (Object)null) ? ((Component)val).GetComponent<PhotonView>() : null);
((BaseUnityPlugin)this).Logger.LogInfo((object)(((Object)(object)val == (Object)null) ? ("Scene " + ((Scene)(ref scene)).name + ": no active room-owned Scoutmaster found.") : $"Scene {((Scene)(ref scene)).name}: found room Scoutmaster (mine={val2.IsMine}) at {((Component)val).transform.position}."));
}
if ((Object)(object)val != (Object)null)
{
float num = Vector3.Distance(((Component)val).transform.position, localCharacter.Center);
int instanceID = ((Object)val).GetInstanceID();
if (!(num > 100f) || _rescuedScoutmasterInstanceId == instanceID)
{
return;
}
_rescuedScoutmasterInstanceId = instanceID;
PhotonView component2 = ((Component)val).GetComponent<PhotonView>();
if (!((Object)(object)component2 != (Object)null) || !component2.IsMine)
{
return;
}
Vector3 val3 = localCharacter.data.lookDirection;
val3.y = 0f;
if (((Vector3)(ref val3)).sqrMagnitude < 0.01f)
{
val3 = Vector3.forward;
}
((Vector3)(ref val3)).Normalize();
Character component3 = ((Component)val).GetComponent<Character>();
if ((Object)(object)component3 != (Object)null && (Object)(object)component2 != (Object)null && ScoutmasterSpawnPosition.TryGetGroundedCenter(localCharacter, val3 * 2f, out var target))
{
component2.RPC("WarpPlayerRPC", (RpcTarget)0, new object[2] { target, false });
if ((Object)(object)component3.data != (Object)null)
{
component3.data.spawnPoint = ((Component)val).transform;
}
((BaseUnityPlugin)this).Logger.LogInfo((object)$"One-time rescue repositioned run Scoutmaster from {num:F1}m away to {target}.");
}
else
{
((BaseUnityPlugin)this).Logger.LogWarning((object)"Could not find safe ground near the player to rescue the run Scoutmaster; leaving its current position unchanged.");
}
return;
}
Scoutmaster val4 = default(Scoutmaster);
if (Scoutmaster.GetPrimaryScoutmaster(ref val4) && (Object)(object)val4 != (Object)null)
{
if ((((Component)val4).gameObject.scene == scene && ((Behaviour)val4).isActiveAndEnabled && ((Component)val4).gameObject.activeInHierarchy) || Time.time < _sceneTransitionGraceEnds || TryRemoveStaleRoomScoutmaster(val4))
{
return;
}
((BaseUnityPlugin)this).Logger.LogWarning((object)"A stale Scoutmaster remains outside the active player scene; attempting a replacement for the active scene.");
}
Vector3 val5 = localCharacter.data.lookDirection;
val5.y = 0f;
if (((Vector3)(ref val5)).sqrMagnitude < 0.01f)
{
val5 = Vector3.forward;
}
((Vector3)(ref val5)).Normalize();
if (ScoutmasterSpawnPosition.TryGetGroundedCenter(localCharacter, val5 * 5f, out var target2))
{
try
{
GameObject val6 = PhotonNetwork.InstantiateRoomObject("Character_Scoutmaster", target2, Quaternion.identity, (byte)0, (object[])null);
if ((Object)(object)val6 == (Object)null)
{
((BaseUnityPlugin)this).Logger.LogError((object)"Photon failed to spawn Character_Scoutmaster; will retry.");
}
else
{
Character component4 = val6.GetComponent<Character>();
if ((Object)(object)component4 != (Object)null && (Object)(object)component4.data != (Object)null)
{
component4.data.spawnPoint = val6.transform;
}
((BaseUnityPlugin)this).Logger.LogInfo((object)"Spawned a Scoutmaster for this level.");
}
return;
}
catch (Exception arg2)
{
((BaseUnityPlugin)this).Logger.LogError((object)$"Failed to spawn Character_Scoutmaster: {arg2}");
return;
}
}
((BaseUnityPlugin)this).Logger.LogWarning((object)"Could not find safe ground near the player to spawn a Scoutmaster; will retry.");
}
}
private void OnSceneLoaded(Scene scene, LoadSceneMode mode)
{
ScoutmasterSceneLookup.Invalidate();
_sceneTransitionGraceEnds = Time.time + 5f;
_nextSpawnCheck = _sceneTransitionGraceEnds;
_lastLoggedPlayerScene = null;
}
private bool TryRemoveStaleRoomScoutmaster(Scoutmaster scoutmaster)
{
PhotonView component = ((Component)scoutmaster).GetComponent<PhotonView>();
if ((Object)(object)component == (Object)null || !component.IsRoomView || !component.IsMine)
{
((BaseUnityPlugin)this).Logger.LogWarning((object)"Found a stale Scoutmaster outside the player's scene, but it is not a room-owned object this client can remove. Waiting for the game to clean it up.");
return false;
}
try
{
PhotonNetwork.Destroy(((Component)scoutmaster).gameObject);
((BaseUnityPlugin)this).Logger.LogInfo((object)"Removed a stale Scoutmaster from the previous scene.");
return true;
}
catch (Exception arg)
{
((BaseUnityPlugin)this).Logger.LogError((object)$"Failed to remove stale Scoutmaster: {arg}");
return false;
}
}
private void OnDestroy()
{
SceneManager.sceneLoaded -= OnSceneLoaded;
Harmony harmony = _harmony;
if (harmony != null)
{
harmony.UnpatchSelf();
}
}
}
internal sealed class LobbyPlayerAcceptableValues : AcceptableValueList<string>
{
private const string JoinLobbyChoice = "Join a lobby to choose a player";
private const string PlayerIdPrefix = " (ID ";
private readonly Func<string> _selectedChoice;
public override string[] AcceptableValues
{
get
{
Player[] array = (PhotonNetwork.InRoom ? PhotonNetwork.PlayerList : Array.Empty<Player>());
List<Player> list = new List<Player>(array.Length);
foreach (Player val in array)
{
if (val != null && !string.IsNullOrEmpty(val.UserId))
{
list.Add(val);
}
}
list.Sort((Player left, Player right) => string.Compare(left.NickName, right.NickName, StringComparison.OrdinalIgnoreCase));
List<string> list2 = new List<string>(list.Count + 2) { "Join a lobby to choose a player" };
string text = _selectedChoice();
bool flag = false;
for (int num = 0; num < list.Count; num++)
{
Player val2 = list[num];
string item = val2.NickName + " (ID " + val2.UserId + ")";
list2.Add(item);
if (TryGetUserId(text, out var userId) && string.Equals(val2.UserId, userId, StringComparison.OrdinalIgnoreCase))
{
flag = true;
}
}
if (!string.IsNullOrEmpty(text) && !flag && !list2.Contains(text) && TryGetUserId(text, out var _))
{
list2.Add("(Not in lobby) " + text);
}
return list2.ToArray();
}
}
internal LobbyPlayerAcceptableValues(Func<string> selectedChoice)
: base(new string[1] { "Join a lobby to choose a player" })
{
_selectedChoice = selectedChoice;
}
public override bool IsValid(object value)
{
return value is string;
}
internal static bool TryGetUserId(string choice, out string userId)
{
int num = choice.LastIndexOf(" (ID ", StringComparison.Ordinal);
if (num >= 0 && choice.EndsWith(")", StringComparison.Ordinal))
{
userId = choice.Substring(num + " (ID ".Length, choice.Length - num - " (ID ".Length - 1);
return userId.Length > 0;
}
userId = choice;
return !string.IsNullOrWhiteSpace(userId);
}
}
internal static class ScoutmasterSceneLookup
{
private const float LookupRefreshInterval = 1f;
private static Scoutmaster _cachedAnyScoutmaster;
private static int _cachedAnySceneHandle = int.MinValue;
private static float _nextAnyRefresh;
private static Scoutmaster _cachedOwnedScoutmaster;
private static int _cachedOwnedSceneHandle = int.MinValue;
private static float _nextOwnedRefresh;
internal static Scoutmaster FindRoomScoutmasterInScene(Scene scene, bool requireMine)
{
//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_0071: 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_0054: 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)
Scoutmaster val = (requireMine ? _cachedOwnedScoutmaster : _cachedAnyScoutmaster);
int num = (requireMine ? _cachedOwnedSceneHandle : _cachedAnySceneHandle);
float num2 = (requireMine ? _nextOwnedRefresh : _nextAnyRefresh);
if (SceneHandle.op_Implicit(num) == ((Scene)(ref scene)).handle && Time.time < num2 && ((Object)(object)val == (Object)null || IsUsable(val, scene, requireMine)))
{
return val;
}
Scoutmaster[] array = Object.FindObjectsByType<Scoutmaster>((FindObjectsSortMode)0);
foreach (Scoutmaster val2 in array)
{
if (IsUsable(val2, scene, requireMine))
{
Cache(val2, scene, requireMine);
return val2;
}
}
Cache(null, scene, requireMine);
return null;
}
internal static void Invalidate()
{
_cachedAnyScoutmaster = null;
_cachedAnySceneHandle = int.MinValue;
_nextAnyRefresh = 0f;
_cachedOwnedScoutmaster = null;
_cachedOwnedSceneHandle = int.MinValue;
_nextOwnedRefresh = 0f;
}
private static bool IsUsable(Scoutmaster scoutmaster, Scene scene, bool requireMine)
{
//IL_0024: 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)
if ((Object)(object)scoutmaster == (Object)null || !((Behaviour)scoutmaster).isActiveAndEnabled || !((Component)scoutmaster).gameObject.activeInHierarchy || ((Component)scoutmaster).gameObject.scene != scene)
{
return false;
}
PhotonView component = ((Component)scoutmaster).GetComponent<PhotonView>();
if ((Object)(object)component != (Object)null && component.IsRoomView)
{
if (requireMine)
{
return component.IsMine;
}
return true;
}
return false;
}
private static void Cache(Scoutmaster scoutmaster, Scene scene, bool requireMine)
{
//IL_0035: 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)
float num = Time.time + 1f;
if (requireMine)
{
_cachedOwnedScoutmaster = scoutmaster;
_cachedOwnedSceneHandle = SceneHandle.op_Implicit(((Scene)(ref scene)).handle);
_nextOwnedRefresh = num;
}
else
{
_cachedAnyScoutmaster = scoutmaster;
_cachedAnySceneHandle = SceneHandle.op_Implicit(((Scene)(ref scene)).handle);
_nextAnyRefresh = num;
}
}
internal static bool IsPrimaryInPlayerScene(Scoutmaster scoutmaster)
{
//IL_001e: Unknown result type (might be due to invalid IL or missing references)
Character localCharacter = Character.localCharacter;
if ((Object)(object)localCharacter != (Object)null && (Object)(object)scoutmaster != (Object)null)
{
return (Object)(object)FindRoomScoutmasterInScene(((Component)localCharacter).gameObject.scene, requireMine: true) == (Object)(object)scoutmaster;
}
return false;
}
internal static bool IsInPlayerScene(Scoutmaster scoutmaster)
{
//IL_001e: Unknown result type (might be due to invalid IL or missing references)
Character localCharacter = Character.localCharacter;
if ((Object)(object)localCharacter != (Object)null && (Object)(object)scoutmaster != (Object)null)
{
return (Object)(object)FindRoomScoutmasterInScene(((Component)localCharacter).gameObject.scene, requireMine: false) == (Object)(object)scoutmaster;
}
return false;
}
}
internal static class ScoutmasterSpawnPosition
{
private const float GroundSearchUp = 3f;
private const float GroundSearchDown = 14f;
private const float MaxGroundHeightDifference = 3.5f;
internal static bool TryGetGroundedCenter(Character reference, Vector3 horizontalOffset, out Vector3 target)
{
//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_0023: 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)
//IL_003a: Unknown result type (might be due to invalid IL or missing references)
//IL_004a: Unknown result type (might be due to invalid IL or missing references)
//IL_0056: 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_007c: Unknown result type (might be due to invalid IL or missing references)
//IL_008b: Unknown result type (might be due to invalid IL or missing references)
//IL_0090: Unknown result type (might be due to invalid IL or missing references)
//IL_009c: 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_00a6: Unknown result type (might be due to invalid IL or missing references)
target = Vector3.zero;
if ((Object)(object)reference == (Object)null)
{
return false;
}
horizontalOffset.y = 0f;
if (!TryFindGround(reference.Center, out var closestHit))
{
return false;
}
if (!TryFindGround(reference.Center + horizontalOffset, out var closestHit2) || Mathf.Abs(((RaycastHit)(ref closestHit2)).point.y - ((RaycastHit)(ref closestHit)).point.y) > 3.5f)
{
return false;
}
float num = reference.Center.y - ((RaycastHit)(ref closestHit)).point.y;
target = ((RaycastHit)(ref closestHit2)).point + Vector3.up * (num + 0.2f);
return true;
}
private static bool TryFindGround(Vector3 position, out RaycastHit closestHit)
{
//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_000b: Unknown result type (might be due to invalid IL or missing references)
//IL_0010: Unknown result type (might be due to invalid IL or missing references)
//IL_0015: 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_0064: 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)
//IL_008c: Unknown result type (might be due to invalid IL or missing references)
RaycastHit[] array = Physics.RaycastAll(position + Vector3.up * 3f, Vector3.down, 17f, -5, (QueryTriggerInteraction)1);
closestHit = default(RaycastHit);
float num = float.MaxValue;
for (int i = 0; i < array.Length; i++)
{
Collider collider = ((RaycastHit)(ref array[i])).collider;
if (!((Object)(object)collider == (Object)null) && !((Object)(object)((Component)collider).GetComponentInParent<Character>() != (Object)null) && !(((RaycastHit)(ref array[i])).normal.y < 0.5f) && !(((RaycastHit)(ref array[i])).distance >= num))
{
closestHit = array[i];
num = ((RaycastHit)(ref array[i])).distance;
}
}
return num < float.MaxValue;
}
}
[HarmonyPatch(typeof(Scoutmaster), "Update")]
internal static class ScoutmasterUpdatePatch
{
private const float FollowDistance = 8f;
private const float SprintDistance = 10f;
private static Action<Scoutmaster, Vector3, float> _walkTowards;
private static Action<Scoutmaster, Vector3, float> _climbTowards;
private static Action<Scoutmaster, Vector3> _lookAt;
private static Action<Scoutmaster> _resetInput;
private static ManualLogSource _logger;
private static ConfigEntry<string> _followMode;
private static ConfigEntry<string> _specificPlayerUserId;
private static float _nextStatusLog;
private static float _nextMissingTargetLog;
internal static void Bind(ManualLogSource logger, ConfigEntry<string> followMode, ConfigEntry<string> specificPlayerUserId)
{
_logger = logger;
_followMode = followMode;
_specificPlayerUserId = specificPlayerUserId;
Type? typeFromHandle = typeof(Scoutmaster);
_walkTowards = AccessTools.MethodDelegate<Action<Scoutmaster, Vector3, float>>(AccessTools.Method(typeFromHandle, "WalkTowards", (Type[])null, (Type[])null), (object)null, true);
_climbTowards = AccessTools.MethodDelegate<Action<Scoutmaster, Vector3, float>>(AccessTools.Method(typeFromHandle, "ClimbTowards", (Type[])null, (Type[])null), (object)null, true);
_lookAt = AccessTools.MethodDelegate<Action<Scoutmaster, Vector3>>(AccessTools.Method(typeFromHandle, "LookAt", (Type[])null, (Type[])null), (object)null, true);
_resetInput = AccessTools.MethodDelegate<Action<Scoutmaster>>(AccessTools.Method(typeFromHandle, "ResetInput", (Type[])null, (Type[])null), (object)null, true);
}
[HarmonyPostfix]
private static void Postfix(Scoutmaster __instance)
{
//IL_00b1: 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_00c9: Unknown result type (might be due to invalid IL or missing references)
//IL_013d: Unknown result type (might be due to invalid IL or missing references)
//IL_0142: Unknown result type (might be due to invalid IL or missing references)
//IL_01e2: Unknown result type (might be due to invalid IL or missing references)
//IL_01cb: Unknown result type (might be due to invalid IL or missing references)
if ((Object)(object)Player.localPlayer == (Object)null)
{
return;
}
PhotonView component = ((Component)__instance).GetComponent<PhotonView>();
if ((Object)(object)component == (Object)null || !component.IsRoomView || !component.IsMine || !ScoutmasterSceneLookup.IsPrimaryInPlayerScene(__instance))
{
return;
}
Character component2 = ((Component)__instance).GetComponent<Character>();
if ((Object)(object)component2 == (Object)null || (Object)(object)component2.data == (Object)null)
{
return;
}
ScoutmasterRagdollDamping.ApplyOnce(component2, _logger);
_resetInput(__instance);
component2.input.useSecondaryIsPressed = false;
Character obj = ScoutmasterAggression.GetTarget(__instance);
if ((Object)(object)obj == (Object)null)
{
ClearAggroTarget(__instance, component);
}
if (obj == null)
{
obj = FindTarget(component2);
}
Character val = obj;
if ((Object)(object)val == (Object)null)
{
component2.input.sprintIsPressed = false;
return;
}
float num = Vector3.Distance(component2.Center, val.Center);
_lookAt(__instance, val.Head);
component2.input.sprintIsPressed = num > 10f;
if (component2.input.sprintIsPressed)
{
component2.data.currentStamina = 1f;
}
if (Time.time >= _nextStatusLog)
{
_nextStatusLog = Time.time + 5f;
ManualLogSource logger = _logger;
string[] obj2 = new string[5] { "Controlling run Scoutmaster in ", null, null, null, null };
Scene scene = ((Component)__instance).gameObject.scene;
obj2[1] = ((Scene)(ref scene)).name;
obj2[2] = ": ";
obj2[3] = $"distance={num:F1}m, sprintInput={component2.input.sprintIsPressed}, ";
obj2[4] = $"sprinting={component2.data.isSprinting}, climbing={component2.data.isClimbing}.";
logger.LogInfo((object)string.Concat(obj2));
}
if (!(num <= 8f))
{
if (component2.data.isClimbing)
{
_climbTowards(__instance, val.Head, 1f);
}
else
{
_walkTowards(__instance, val.Head, 1f);
}
}
}
private static Character FindTarget(Character body)
{
List<Character> allPlayerCharacters = PlayerHandler.GetAllPlayerCharacters();
if (_followMode.Value == "SpecificUserId")
{
Character val = FindSpecificPlayer(allPlayerCharacters);
if ((Object)(object)val != (Object)null)
{
return val;
}
return FindNearestLivingPlayer(body, allPlayerCharacters);
}
return FindNearestLivingPlayer(body, allPlayerCharacters);
}
private static Character FindNearestLivingPlayer(Character body, List<Character> players)
{
//IL_0046: 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)
Character result = null;
float num = float.MaxValue;
for (int i = 0; i < players.Count; i++)
{
Character val = players[i];
if (!((Object)(object)val == (Object)null) && !((Object)(object)val.data == (Object)null) && !val.data.dead && !val.data.fullyPassedOut)
{
float num2 = Vector3.Distance(body.Center, val.Center);
if (num2 < num)
{
result = val;
num = num2;
}
}
}
return result;
}
private static Character FindSpecificPlayer(List<Character> players)
{
string text = _specificPlayerUserId.Value.Trim();
if (!LobbyPlayerAcceptableValues.TryGetUserId(text, out var userId) || text == "Join a lobby to choose a player" || text.StartsWith("(Not in lobby) ", StringComparison.Ordinal))
{
LogMissingTarget("The configured specific player is not available in this lobby; falling back to the nearest living player.");
return null;
}
for (int i = 0; i < players.Count; i++)
{
Character val = players[i];
if (!((Object)(object)val == (Object)null) && !((Object)(object)val.data == (Object)null) && !val.data.dead && !((Object)(object)((MonoBehaviourPun)val).photonView == (Object)null) && ((MonoBehaviourPun)val).photonView.Owner != null && string.Equals(((MonoBehaviourPun)val).photonView.Owner.UserId, userId, StringComparison.OrdinalIgnoreCase))
{
return val;
}
}
LogMissingTarget("Configured follow target '" + userId + "' is absent or dead; falling back to the nearest living player.");
return null;
}
private static void LogMissingTarget(string message)
{
if (!(Time.time < _nextMissingTargetLog))
{
_nextMissingTargetLog = Time.time + 10f;
_logger.LogWarning((object)message);
}
}
private static void ClearAggroTarget(Scoutmaster scoutmaster, PhotonView view)
{
if ((Object)(object)scoutmaster.currentTarget != (Object)null)
{
view.RPC("RPCA_SetCurrentTarget", (RpcTarget)0, new object[2] { -1, 0f });
}
}
}
internal static class ScoutmasterSfxVolume
{
private const float UnattachedSoundRadius = 4f;
private static ConfigEntry<float> _volume;
internal static void Bind(ConfigEntry<float> volume)
{
_volume = volume;
}
internal static void Apply(Vector3 position, Transform followTransform, ref float volumeMultiplier)
{
//IL_002f: Unknown result type (might be due to invalid IL or missing references)
Scoutmaster val = (((Object)(object)followTransform != (Object)null) ? ((Component)followTransform).GetComponentInParent<Scoutmaster>() : null);
if ((Object)(object)val != (Object)null && !IsRoomScoutmasterInLocalScene(val))
{
val = null;
}
if ((Object)(object)val == (Object)null)
{
val = FindRoomScoutmasterNear(position);
}
if ((Object)(object)val != (Object)null)
{
volumeMultiplier *= Mathf.Clamp01(_volume.Value);
}
}
private static bool IsRoomScoutmasterInLocalScene(Scoutmaster scoutmaster)
{
//IL_0015: 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)
Character localCharacter = Character.localCharacter;
if ((Object)(object)localCharacter == (Object)null || ((Component)scoutmaster).gameObject.scene != ((Component)localCharacter).gameObject.scene)
{
return false;
}
PhotonView component = ((Component)scoutmaster).GetComponent<PhotonView>();
if ((Object)(object)component != (Object)null)
{
return component.IsRoomView;
}
return false;
}
private static Scoutmaster FindRoomScoutmasterNear(Vector3 position)
{
//IL_0017: 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_0044: 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_0052: 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)
Character localCharacter = Character.localCharacter;
if ((Object)(object)localCharacter == (Object)null)
{
return null;
}
Scoutmaster val = ScoutmasterSceneLookup.FindRoomScoutmasterInScene(((Component)localCharacter).gameObject.scene, requireMine: false);
if ((Object)(object)val == (Object)null)
{
return null;
}
Character component = ((Component)val).GetComponent<Character>();
Vector3 val2 = (((Object)(object)component != (Object)null) ? component.Center : ((Component)val).transform.position);
if (!(Vector3.Distance(position, val2) < 4f))
{
return null;
}
return val;
}
}
[HarmonyPatch(typeof(SFX_Player), "PlaySFX")]
internal static class ScoutmasterSfxVolumePatch
{
[HarmonyPrefix]
private static void ApplyScoutmasterVolume(Vector3 __1, Transform __2, ref float __4)
{
//IL_0000: Unknown result type (might be due to invalid IL or missing references)
ScoutmasterSfxVolume.Apply(__1, __2, ref __4);
}
}
[HarmonyPatch(typeof(Scoutmaster), "Start")]
internal static class ScoutmasterSpawnPosePatch
{
private static readonly HashSet<int> ScheduledScoutmasters = new HashSet<int>();
private static ManualLogSource _logger;
internal static void Bind(ManualLogSource logger)
{
_logger = logger;
}
[HarmonyPostfix]
private static void AfterScoutmasterStart(Scoutmaster __instance)
{
PhotonView component = ((Component)__instance).GetComponent<PhotonView>();
if (!((Object)(object)component == (Object)null) && component.IsRoomView && component.IsMine && ScheduledScoutmasters.Add(((Object)__instance).GetInstanceID()))
{
((MonoBehaviour)__instance).StartCoroutine(SnapAfterRagdollInitialization(__instance));
}
}
private static IEnumerator SnapAfterRagdollInitialization(Scoutmaster scoutmaster)
{
yield return (object)new WaitForFixedUpdate();
yield return (object)new WaitForFixedUpdate();
if (!((Object)(object)scoutmaster == (Object)null))
{
CharacterRagdoll componentInChildren = ((Component)scoutmaster).GetComponentInChildren<CharacterRagdoll>();
if ((Object)(object)componentInChildren == (Object)null || componentInChildren.partList == null || componentInChildren.partList.Count == 0)
{
_logger.LogWarning((object)"Could not snap newly spawned Scoutmaster to animation: its ragdoll is not initialized.");
yield break;
}
componentInChildren.SnapToAnimation();
_logger.LogInfo((object)"Snapped newly spawned Scoutmaster to its initialized animation pose.");
}
}
}
internal static class ScoutmasterAggression
{
private static Scoutmaster _scoutmaster;
private static Character _target;
private static float _forcedUntil;
private static ManualLogSource _logger;
internal static void Bind(ManualLogSource logger)
{
_logger = logger;
}
internal static bool TryRedirectForcedTarget(Scoutmaster source, Character target, float forceForTime)
{
//IL_002a: Unknown result type (might be due to invalid IL or missing references)
if ((Object)(object)target == (Object)null || forceForTime <= 0f)
{
return false;
}
Character localCharacter = Character.localCharacter;
if ((Object)(object)localCharacter == (Object)null)
{
return false;
}
Scoutmaster val = ScoutmasterSceneLookup.FindRoomScoutmasterInScene(((Component)localCharacter).gameObject.scene, requireMine: false);
if ((Object)(object)val == (Object)null || (Object)(object)val == (Object)(object)source)
{
return false;
}
PhotonView component = ((Component)val).GetComponent<PhotonView>();
PhotonView photonView = ((MonoBehaviourPun)target).photonView;
if ((Object)(object)component == (Object)null || !component.IsRoomView || (Object)(object)photonView == (Object)null)
{
return false;
}
component.RPC("RPCA_SetCurrentTarget", (RpcTarget)0, new object[2] { photonView.ViewID, forceForTime });
_logger.LogInfo((object)$"Redirected forced Scoutmaster aggression to {target.characterName} for {forceForTime:F0}s.");
return true;
}
internal static bool RegisterForcedTarget(Scoutmaster scoutmaster, int targetViewId, float forceForTime)
{
if (forceForTime <= 0f || targetViewId < 0 || !IsManagedRoomScoutmaster(scoutmaster))
{
return false;
}
PhotonView val = PhotonView.Find(targetViewId);
Character val2 = (((Object)(object)val != (Object)null) ? ((Component)val).GetComponent<Character>() : null);
if ((Object)(object)val2 == (Object)null)
{
return false;
}
_scoutmaster = scoutmaster;
_target = val2;
_forcedUntil = Time.time + forceForTime;
return true;
}
internal static Character GetTarget(Scoutmaster scoutmaster)
{
if ((Object)(object)_scoutmaster != (Object)(object)scoutmaster || (Object)(object)_target == (Object)null || (Object)(object)_target.data == (Object)null || _target.data.dead || Time.time >= _forcedUntil)
{
if ((Object)(object)_scoutmaster == (Object)(object)scoutmaster)
{
Clear(scoutmaster);
}
return null;
}
return _target;
}
internal static bool IsActive(Scoutmaster scoutmaster)
{
return (Object)(object)GetTarget(scoutmaster) != (Object)null;
}
private static bool IsManagedRoomScoutmaster(Scoutmaster scoutmaster)
{
if ((Object)(object)scoutmaster == (Object)null)
{
return false;
}
PhotonView component = ((Component)scoutmaster).GetComponent<PhotonView>();
if ((Object)(object)component != (Object)null && component.IsRoomView)
{
return ScoutmasterSceneLookup.IsInPlayerScene(scoutmaster);
}
return false;
}
private static void Clear(Scoutmaster scoutmaster)
{
if (!((Object)(object)_scoutmaster != (Object)(object)scoutmaster))
{
_scoutmaster = null;
_target = null;
_forcedUntil = 0f;
}
}
}
[HarmonyPatch(typeof(Scoutmaster), "SetCurrentTarget")]
internal static class ScoutmasterForcedTargetRedirectPatch
{
[HarmonyPrefix]
private static bool RedirectForcedTarget(Scoutmaster __instance, Character __0, float __1)
{
return !ScoutmasterAggression.TryRedirectForcedTarget(__instance, __0, __1);
}
}
internal static class ScoutmasterRagdollDamping
{
private const float AddedLinearDamping = 0.1f;
private const float AddedAngularDamping = 0.1f;
private static readonly HashSet<int> DampenedCharacters = new HashSet<int>();
internal static void ApplyOnce(Character character, ManualLogSource logger)
{
int instanceID = ((Object)character).GetInstanceID();
if (DampenedCharacters.Contains(instanceID))
{
return;
}
CharacterRagdoll componentInChildren = ((Component)character).GetComponentInChildren<CharacterRagdoll>();
if ((Object)(object)componentInChildren == (Object)null || componentInChildren.partList == null || componentInChildren.partList.Count == 0)
{
return;
}
int num = 0;
for (int i = 0; i < componentInChildren.partList.Count; i++)
{
Bodypart val = componentInChildren.partList[i];
if (!((Object)(object)val == (Object)null) && !((Object)(object)val.Rig == (Object)null))
{
Rigidbody rig = val.Rig;
rig.linearDamping += 0.1f;
Rigidbody rig2 = val.Rig;
rig2.angularDamping += 0.1f;
num++;
}
}
if (num != 0)
{
DampenedCharacters.Add(instanceID);
logger.LogInfo((object)$"Added light ragdoll damping to {num} Scoutmaster body parts.");
}
}
}
[HarmonyPatch(typeof(Character), "CheckSprint")]
internal static class ScoutmasterSprintPatch
{
[HarmonyPrefix]
private static bool AllowScoutmasterSprint(Character __instance, ref bool __result)
{
Scoutmaster component = ((Component)__instance).GetComponent<Scoutmaster>();
CharacterData data = __instance.data;
CharacterInput input = __instance.input;
if ((Object)(object)component == (Object)null || (Object)(object)data == (Object)null || (Object)(object)input == (Object)null || !input.sprintIsPressed || input.movementInput.y <= 0.01f || data.isClimbing || data.isRopeClimbing || data.isVineClimbing || !ScoutmasterSceneLookup.IsPrimaryInPlayerScene(component))
{
return true;
}
PhotonView component2 = ((Component)component).GetComponent<PhotonView>();
if ((Object)(object)component2 == (Object)null || !component2.IsMine)
{
return true;
}
__result = true;
return false;
}
}
[HarmonyPatch(typeof(Scoutmaster), "TeleportFarAway")]
internal static class ScoutmasterTeleportFarAwayPatch
{
[HarmonyPrefix]
private static bool PreventTeleportToVoid(Scoutmaster __instance)
{
PhotonView component = ((Component)__instance).GetComponent<PhotonView>();
if (!((Object)(object)component == (Object)null) && component.IsRoomView)
{
return !component.IsMine;
}
return true;
}
}
[HarmonyPatch(typeof(Character), "WarpPlayerRPC")]
internal static class ScoutmasterVoidWarpPatch
{
private static readonly HashSet<int> LoggedScoutmasters = new HashSet<int>();
private static ManualLogSource _logger;
internal static void Bind(ManualLogSource logger)
{
_logger = logger;
}
[HarmonyPrefix]
private static bool PreventVoidWarp(Character __instance, Vector3 __0)
{
//IL_0000: Unknown result type (might be due to invalid IL or missing references)
//IL_0061: Unknown result type (might be due to invalid IL or missing references)
if (__0.y < 1000f)
{
return true;
}
Scoutmaster component = ((Component)__instance).GetComponent<Scoutmaster>();
PhotonView val = (((Object)(object)component != (Object)null) ? ((Component)component).GetComponent<PhotonView>() : null);
if ((Object)(object)component == (Object)null || (Object)(object)val == (Object)null || !val.IsRoomView)
{
return true;
}
if (LoggedScoutmasters.Add(((Object)component).GetInstanceID()))
{
_logger.LogInfo((object)$"Prevented out-of-world warp for room Scoutmaster (target={__0}).");
}
return false;
}
}
[HarmonyPatch(typeof(Scoutmaster), "HoldPlayer")]
internal static class ScoutmasterHoldPatch
{
[HarmonyPrefix]
private static bool AllowForcedAttack(Scoutmaster __instance)
{
return ScoutmasterAggression.IsActive(__instance);
}
}
[HarmonyPatch(typeof(Scoutmaster), "RPCA_SetCurrentTarget")]
internal static class ScoutmasterTargetPatch
{
[HarmonyPrefix]
private static bool PreserveForcedTarget(Scoutmaster __instance, ref int __0, float __1)
{
if (__0 >= 0 && __1 > 0f && ScoutmasterAggression.RegisterForcedTarget(__instance, __0, __1))
{
return true;
}
if (__0 == -1 && ScoutmasterAggression.IsActive(__instance))
{
return false;
}
__0 = -1;
return true;
}
}
}