using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using GangBeastsSandevistan;
using HarmonyLib;
using Il2CppFemur;
using Il2CppGB.Game;
using Il2CppInterop.Runtime;
using Il2CppInterop.Runtime.InteropTypes;
using Il2CppInterop.Runtime.InteropTypes.Arrays;
using MelonLoader;
using MelonLoader.NativeUtils;
using MelonLoader.Preferences;
using Microsoft.CodeAnalysis;
using UnityEngine;
using UnityEngine.InputSystem;
using UnityEngine.InputSystem.Controls;
using UnityEngine.InputSystem.Users;
using UnityEngine.InputSystem.Utilities;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: MelonInfo(typeof(Mod), "Gang Beasts Sandevistan", "0.9.0-beta.1", "Delan", null)]
[assembly: MelonGame("Boneloaf", "Gang Beasts")]
[assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")]
[assembly: AssemblyCompany("GangBeastsSandevistan")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("0.9.0.0")]
[assembly: AssemblyInformationalVersion("0.9.0-beta.1+c28132d28914e626b16ebebf1c3a0678c245bac4")]
[assembly: AssemblyProduct("GangBeastsSandevistan")]
[assembly: AssemblyTitle("GangBeastsSandevistan")]
[assembly: AssemblyVersion("0.9.0.0")]
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;
}
}
}
namespace GangBeastsSandevistan
{
public sealed class AbilityState
{
public bool Active { get; private set; }
public double EndsAt { get; private set; }
public double ReadyAt { get; private set; }
public bool TryStart(double now, bool allowed)
{
if (Active || !allowed || now < ReadyAt)
{
return false;
}
Active = true;
EndsAt = now + 3.0;
return true;
}
public void Stop(double now)
{
if (Active)
{
Active = false;
ReadyAt = now + 6.0;
}
}
public bool Expired(double now)
{
if (Active)
{
return now >= EndsAt;
}
return false;
}
public void Reset()
{
Active = false;
double endsAt = (ReadyAt = 0.0);
EndsAt = endsAt;
}
}
public sealed class ButtonEdges
{
private readonly Dictionary<int, (bool left, bool right)> previous = new Dictionary<int, (bool, bool)>();
public (bool cycle, bool toggle) Poll(int device, bool left, bool right)
{
(bool, bool) value;
bool num = previous.TryGetValue(device, out value);
previous[device] = (left, right);
if (!num)
{
return (cycle: false, toggle: false);
}
return (cycle: left && !value.Item1, toggle: right && !value.Item2);
}
public void KeepOnly(HashSet<int> connected)
{
int[] array = previous.Keys.Where((int id) => !connected.Contains(id)).ToArray();
foreach (int key in array)
{
previous.Remove(key);
}
}
public void Reset()
{
previous.Clear();
}
}
public static class LocalTimeHooks
{
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
private delegate float Scalar();
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
private delegate void Force(IntPtr body, ref Vector3 value, ForceMode mode);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
private delegate void VectorAccess(IntPtr body, ref Vector3 value);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
private delegate void BodyScalarSet(IntPtr body, float value);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
private delegate float BodyScalarGet(IntPtr body);
private static NativeHook<Scalar>? delta;
private static NativeHook<Scalar>? fixedDelta;
private static NativeHook<Force>? force;
private static NativeHook<Force>? torque;
private static NativeHook<Force>? relativeForce;
private static NativeHook<Force>? relativeTorque;
private static NativeHook<BodyScalarSet>? setMaxAngular;
private static NativeHook<BodyScalarSet>? setDrag;
private static NativeHook<BodyScalarSet>? setAngularDrag;
private static NativeHook<BodyScalarGet>? getMaxAngular;
private static NativeHook<BodyScalarGet>? getDrag;
private static NativeHook<BodyScalarGet>? getAngularDrag;
private static NativeHook<VectorAccess>? getVelocity;
private static NativeHook<VectorAccess>? setVelocity;
private static NativeHook<VectorAccess>? getAngular;
private static NativeHook<VectorAccess>? setAngular;
private static readonly List<Delegate> callbacks = new List<Delegate>();
private static readonly List<Action> detach = new List<Action>();
public static readonly HashSet<IntPtr> Bodies = new HashSet<IntPtr>();
[ThreadStatic]
public static int ScopeDepth;
public static float Factor = 1f;
public static long ForceCalls;
public static long TimeCalls;
public static long LimitCalls;
public static long RelativeCalls;
private static bool Scoped
{
get
{
if (ScopeDepth > 0)
{
return Factor > 1f;
}
return false;
}
}
private static bool Applies(IntPtr body)
{
if (Scoped)
{
return Bodies.Contains(body);
}
return false;
}
private static void Attach<T>(ref NativeHook<T>? field, string name, T callback) where T : Delegate
{
IntPtr intPtr = IL2CPP.il2cpp_resolve_icall(name);
if (intPtr == IntPtr.Zero)
{
throw new InvalidOperationException("Missing native call " + name);
}
callbacks.Add(callback);
NativeHook<T> val = (field = new NativeHook<T>(intPtr, Marshal.GetFunctionPointerForDelegate(callback)));
val.Attach();
detach.Add((Action)val.Detach);
}
public static void Install()
{
try
{
Attach(ref delta, "UnityEngine.Time::get_deltaTime()", Delta);
Attach(ref fixedDelta, "UnityEngine.Time::get_fixedDeltaTime()", FixedDelta);
Attach(ref force, "UnityEngine.Rigidbody::AddForce_Injected(UnityEngine.Vector3&,UnityEngine.ForceMode)", AddForce);
Attach(ref torque, "UnityEngine.Rigidbody::AddTorque_Injected(UnityEngine.Vector3&,UnityEngine.ForceMode)", AddTorque);
Attach(ref relativeForce, "UnityEngine.Rigidbody::AddRelativeForce_Injected(UnityEngine.Vector3&,UnityEngine.ForceMode)", AddRelativeForce);
Attach(ref relativeTorque, "UnityEngine.Rigidbody::AddRelativeTorque_Injected(UnityEngine.Vector3&,UnityEngine.ForceMode)", AddRelativeTorque);
Attach(ref setMaxAngular, "UnityEngine.Rigidbody::set_maxAngularVelocity(System.Single)", SetMaxAngular);
Attach(ref getMaxAngular, "UnityEngine.Rigidbody::get_maxAngularVelocity()", GetMaxAngular);
Attach(ref setDrag, "UnityEngine.Rigidbody::set_drag(System.Single)", SetDrag);
Attach(ref getDrag, "UnityEngine.Rigidbody::get_drag()", GetDrag);
Attach(ref setAngularDrag, "UnityEngine.Rigidbody::set_angularDrag(System.Single)", SetAngularDrag);
Attach(ref getAngularDrag, "UnityEngine.Rigidbody::get_angularDrag()", GetAngularDrag);
Attach(ref getVelocity, "UnityEngine.Rigidbody::get_velocity_Injected(UnityEngine.Vector3&)", GetVelocity);
Attach(ref setVelocity, "UnityEngine.Rigidbody::set_velocity_Injected(UnityEngine.Vector3&)", SetVelocity);
Attach(ref getAngular, "UnityEngine.Rigidbody::get_angularVelocity_Injected(UnityEngine.Vector3&)", GetAngular);
Attach(ref setAngular, "UnityEngine.Rigidbody::set_angularVelocity_Injected(UnityEngine.Vector3&)", SetAngular);
}
catch
{
Uninstall();
throw;
}
}
public static void Uninstall()
{
ScopeDepth = 0;
Factor = 1f;
Bodies.Clear();
for (int num = detach.Count - 1; num >= 0; num--)
{
detach[num]();
}
detach.Clear();
}
private static float Delta()
{
float num = delta.Trampoline();
if (Scoped)
{
TimeCalls++;
return num * Factor;
}
return num;
}
private static float FixedDelta()
{
float num = fixedDelta.Trampoline();
if (!Scoped)
{
return num;
}
return num * Factor;
}
public static float ForceFactor(ForceMode mode)
{
//IL_0000: Unknown result type (might be due to invalid IL or missing references)
//IL_0002: Invalid comparison between Unknown and I4
//IL_0004: Unknown result type (might be due to invalid IL or missing references)
//IL_0006: Invalid comparison between Unknown and I4
if ((int)mode != 1 && (int)mode != 2)
{
return Factor * Factor;
}
return Factor;
}
private static void AddForce(IntPtr body, ref Vector3 value, ForceMode mode)
{
//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_0036: Unknown result type (might be due to invalid IL or missing references)
//IL_000f: 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_0016: 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)
Vector3 value2 = value;
if (Applies(body))
{
value2 *= ForceFactor(mode);
ForceCalls++;
}
force.Trampoline(body, ref value2, mode);
}
private static void AddTorque(IntPtr body, ref Vector3 value, ForceMode mode)
{
//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_0036: Unknown result type (might be due to invalid IL or missing references)
//IL_000f: 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_0016: 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)
Vector3 value2 = value;
if (Applies(body))
{
value2 *= ForceFactor(mode);
ForceCalls++;
}
torque.Trampoline(body, ref value2, mode);
}
private static void AddRelativeForce(IntPtr body, ref Vector3 value, ForceMode mode)
{
//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_0036: Unknown result type (might be due to invalid IL or missing references)
//IL_000f: 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_0016: 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)
Vector3 value2 = value;
if (Applies(body))
{
value2 *= ForceFactor(mode);
RelativeCalls++;
}
relativeForce.Trampoline(body, ref value2, mode);
}
private static void AddRelativeTorque(IntPtr body, ref Vector3 value, ForceMode mode)
{
//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_0036: Unknown result type (might be due to invalid IL or missing references)
//IL_000f: 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_0016: 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)
Vector3 value2 = value;
if (Applies(body))
{
value2 *= ForceFactor(mode);
RelativeCalls++;
}
relativeTorque.Trampoline(body, ref value2, mode);
}
private static void SetMaxAngular(IntPtr body, float value)
{
if (Applies(body))
{
value *= Factor;
LimitCalls++;
}
setMaxAngular.Trampoline(body, value);
}
private static float GetMaxAngular(IntPtr body)
{
float num = getMaxAngular.Trampoline(body);
if (!Applies(body))
{
return num;
}
return num / Factor;
}
private static void SetDrag(IntPtr body, float value)
{
setDrag.Trampoline(body, Applies(body) ? (value * Factor) : value);
}
private static float GetDrag(IntPtr body)
{
float num = getDrag.Trampoline(body);
if (!Applies(body))
{
return num;
}
return num / Factor;
}
private static void SetAngularDrag(IntPtr body, float value)
{
setAngularDrag.Trampoline(body, Applies(body) ? (value * Factor) : value);
}
private static float GetAngularDrag(IntPtr body)
{
float num = getAngularDrag.Trampoline(body);
if (!Applies(body))
{
return num;
}
return num / Factor;
}
private static void GetVelocity(IntPtr body, ref Vector3 value)
{
//IL_001b: 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_002a: Unknown result type (might be due to invalid IL or missing references)
getVelocity.Trampoline(body, ref value);
if (Applies(body))
{
value /= Factor;
}
}
private static void SetVelocity(IntPtr body, ref Vector3 value)
{
//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_0009: 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)
Vector3 value2 = (Applies(body) ? (value * Factor) : value);
setVelocity.Trampoline(body, ref value2);
}
private static void GetAngular(IntPtr body, ref Vector3 value)
{
//IL_001b: 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_002a: Unknown result type (might be due to invalid IL or missing references)
getAngular.Trampoline(body, ref value);
if (Applies(body))
{
value /= Factor;
}
}
private static void SetAngular(IntPtr body, ref Vector3 value)
{
//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_0009: 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)
Vector3 value2 = (Applies(body) ? (value * Factor) : value);
setAngular.Trampoline(body, ref value2);
}
}
public sealed class Mod : MelonMod
{
private sealed class Session
{
public Actor Actor;
public PlayerClock? Clock;
public MotionEcho? Echo;
public int? TriggerDevice;
public float Started;
}
private const float SlowFactor = 0.2f;
private readonly PlayerAbilities abilities = new PlayerAbilities();
private readonly Dictionary<int, Session> sessions = new Dictionary<int, Session>();
private readonly Dictionary<int, int> deviceOwners = new Dictionary<int, int>();
private readonly ButtonEdges buttons = new ButtonEdges();
private WorldDilation? dilation;
private float startedGameTime;
private float startedRealTime;
private Actor? selected;
private string message = "Each controller: R3 activates or cancels its paired Beast.";
private MelonPreferences_Entry<bool> showHud;
private bool inputErrorReported;
public override void OnInitializeMelon()
{
showHud = MelonPreferences.CreateCategory("Sandevistan").CreateEntry<bool>("ShowHUD", true, (string)null, (string)null, false, false, (ValueValidator)null, (string)null);
((MelonBase)this).LoggerInstance.Msg("Independent local players: R3 toggles the paired Beast. F7 cycles the keyboard target, F8 toggles it. Three seconds active, six seconds cooldown per Beast.");
}
private static bool Usable(Actor? a)
{
//IL_002d: Unknown result type (might be due to invalid IL or missing references)
//IL_0033: Invalid comparison between Unknown and I4
if ((Object)(object)a != (Object)null && ((Component)a).gameObject.activeInHierarchy && a.initialized && (Object)(object)a.bodyHandeler != (Object)null)
{
return (int)a.actorState != 1;
}
return false;
}
private static bool HasRemoteHuman(IEnumerable<Actor> actors)
{
return actors.Any((Actor a) => !a.IsAI && !a.IsLocal);
}
private static List<Actor> LocalActors(IEnumerable<Actor> actors)
{
return (from a in actors
where Usable(a) && a.IsLocal && !a.IsAI
orderby a.playerID, ((Object)a).GetInstanceID()
select a).ToList();
}
private Session SessionFor(Actor actor)
{
int instanceID = ((Object)actor).GetInstanceID();
if (!sessions.TryGetValue(instanceID, out Session value))
{
Dictionary<int, Session> dictionary = sessions;
Session obj = new Session
{
Actor = actor
};
value = obj;
dictionary[instanceID] = obj;
}
return value;
}
private Actor? Owner(Gamepad pad, List<Actor> locals)
{
//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)
List<Actor> list = new List<Actor>();
foreach (Actor local in locals)
{
InputUser inputPlayer = local.InputPlayer;
if (!((InputUser)(ref inputPlayer)).valid)
{
continue;
}
ReadOnlyArray<InputDevice> pairedDevices = ((InputUser)(ref inputPlayer)).pairedDevices;
for (int i = 0; i < pairedDevices.Count; i++)
{
if (pairedDevices[i].deviceId == ((InputDevice)pad).deviceId)
{
list.Add(local);
break;
}
}
}
if (list.Count != 1)
{
deviceOwners.Remove(((InputDevice)pad).deviceId);
return null;
}
Actor val = list[0];
int instanceID = ((Object)val).GetInstanceID();
if (!deviceOwners.TryGetValue(((InputDevice)pad).deviceId, out var value) || value != instanceID)
{
deviceOwners[((InputDevice)pad).deviceId] = instanceID;
((MelonBase)this).LoggerInstance.Msg($"CONTROLLER OWNER device={((InputDevice)pad).deviceId} player={val.playerID} actor={instanceID}");
}
return val;
}
public override void OnUpdate()
{
double now = Time.realtimeSinceStartup;
try
{
Actor[] actors = ((IEnumerable<Actor>)Object.FindObjectsOfType<Actor>()).ToArray();
bool flag = HasRemoteHuman(actors);
if (!Application.isFocused || flag)
{
StopAll(now);
buttons.Reset();
if (flag)
{
message = "Local play only: remote human detected.";
}
return;
}
List<Actor> list = LocalActors(actors);
foreach (Actor item in list)
{
SessionFor(item);
}
KeyValuePair<int, Session>[] array = sessions.ToArray();
for (int i = 0; i < array.Length; i++)
{
KeyValuePair<int, Session> keyValuePair = array[i];
Session value = keyValuePair.Value;
if (abilities.IsActive(keyValuePair.Key) && (abilities.For(keyValuePair.Key).Expired(now) || !Usable(value.Actor) || !value.Actor.IsLocal || value.Actor.IsAI))
{
StopSession(keyValuePair.Key, now);
}
}
if (Time.timeScale <= 0f)
{
StopAll(now);
buttons.Reset();
return;
}
HashSet<int> connected = new HashSet<int>();
ReadOnlyArray<Gamepad> all = Gamepad.all;
for (int j = 0; j < all.Count; j++)
{
Gamepad val = all[j];
connected.Add(((InputDevice)val).deviceId);
Actor val2 = Owner(val, list);
if (buttons.Poll(((InputDevice)val).deviceId, left: false, val.rightStickButton.isPressed).toggle)
{
if ((Object)(object)val2 == (Object)null)
{
message = "This controller has no uniquely paired local Beast. Join the match first.";
continue;
}
((MelonBase)this).LoggerInstance.Msg($"Gamepad device {((InputDevice)val).deviceId}: player={val2.playerID} R3=true");
Toggle(val2, now, ((InputDevice)val).deviceId);
}
}
Keyboard current2 = Keyboard.current;
if (current2 != null)
{
connected.Add(((InputDevice)current2).deviceId);
(bool, bool) tuple = buttons.Poll(((InputDevice)current2).deviceId, ((ButtonControl)current2.f7Key).isPressed, ((ButtonControl)current2.f8Key).isPressed);
if (tuple.Item1)
{
Cycle(list);
}
else if (tuple.Item2)
{
if (!Usable(selected))
{
selected = list.FirstOrDefault();
}
if ((Object)(object)selected != (Object)null)
{
Toggle(selected, now, ((InputDevice)current2).deviceId);
}
}
}
array = sessions.ToArray();
for (int i = 0; i < array.Length; i++)
{
KeyValuePair<int, Session> keyValuePair2 = array[i];
if (!abilities.IsActive(keyValuePair2.Key))
{
continue;
}
int? triggerDevice = keyValuePair2.Value.TriggerDevice;
if (triggerDevice.HasValue)
{
int valueOrDefault = triggerDevice.GetValueOrDefault();
if (!connected.Contains(valueOrDefault))
{
StopSession(keyValuePair2.Key, now);
}
}
}
buttons.KeepOnly(connected);
int[] array2 = deviceOwners.Keys.Where((int d) => !connected.Contains(d)).ToArray();
foreach (int key in array2)
{
deviceOwners.Remove(key);
}
}
catch (Exception ex)
{
StopAll(now);
message = "Sandevistan stopped: see MelonLoader log.";
if (!inputErrorReported)
{
((MelonBase)this).LoggerInstance.Error(ex.ToString());
inputErrorReported = true;
}
}
}
private void Cycle(List<Actor> locals)
{
if (locals.Count == 0)
{
selected = null;
message = "Start a local match first.";
return;
}
int num = (((Object)(object)selected == (Object)null) ? (-1) : locals.FindIndex((Actor a) => ((Object)a).GetInstanceID() == ((Object)selected).GetInstanceID()));
selected = locals[(num + 1) % locals.Count];
message = $"Keyboard target: Beast {selected.playerID + 1}. F8 activates/cancels this Beast.";
}
private void Toggle(Actor actor, double now, int? device)
{
int instanceID = ((Object)actor).GetInstanceID();
if (abilities.IsActive(instanceID))
{
StopSession(instanceID, now);
}
else
{
StartActor(actor, now, device);
}
}
private void Start(double now)
{
if (!Usable(selected))
{
selected = LocalActors((IEnumerable<Actor>)Object.FindObjectsOfType<Actor>()).FirstOrDefault();
}
if ((Object)(object)selected != (Object)null)
{
StartActor(selected, now, null);
}
}
private void Stop(double now)
{
StopAll(now);
}
private void StartActor(Actor actor, double now, int? device)
{
if (!Usable(actor) || !actor.IsLocal || actor.IsAI || HasRemoteHuman((IEnumerable<Actor>)Object.FindObjectsOfType<Actor>()) || Time.timeScale <= 0f)
{
return;
}
int instanceID = ((Object)actor).GetInstanceID();
Session session = SessionFor(actor);
if (!abilities.For(instanceID).TryStart(now, allowed: true))
{
message = $"Beast {actor.playerID + 1} is cooling down.";
return;
}
session.TriggerDevice = device;
session.Started = Time.realtimeSinceStartup;
try
{
if (dilation == null)
{
dilation = new WorldDilation(actor, 0.2f);
dilation.Apply();
startedGameTime = Time.time;
startedRealTime = Time.realtimeSinceStartup;
}
session.Clock = new PlayerClock(actor, 0.2f);
session.Clock.Apply();
NativeLocomotion.Start(actor);
try
{
Rigidbody[] source = ((IEnumerable<Rigidbody>)actor.bodyHandeler.GetAllRigidbodies()).Where((Rigidbody b) => (Object)(object)b != (Object)null).ToArray();
Rigidbody val = ((IEnumerable<Rigidbody>)source).FirstOrDefault((Func<Rigidbody, bool>)((Rigidbody b) => ((Object)b).name.Contains("chest", StringComparison.OrdinalIgnoreCase))) ?? source.FirstOrDefault();
List<Transform> list = new List<Transform> { ((Object)(object)val == (Object)null) ? ((Component)actor).transform : ((Component)val).transform };
list.AddRange(from b in source.Where((Rigidbody b) => ((Object)b).name.Contains("hand", StringComparison.OrdinalIgnoreCase)).Take(2)
select ((Component)b).transform);
session.Echo = new MotionEcho(list);
}
catch (Exception ex)
{
((MelonBase)this).LoggerInstance.Warning("Echo unavailable: " + ex.Message);
}
message = $"Beast {actor.playerID + 1} active. {abilities.ActiveCount} active player(s).";
((MelonBase)this).LoggerInstance.Msg($"SANDE START player={actor.playerID} actor={instanceID} device={device} active={abilities.ActiveCount} world={Time.timeScale:F3}");
}
catch
{
StopSession(instanceID, now);
throw;
}
}
private void StopSession(int id, double now)
{
if (!sessions.TryGetValue(id, out Session value))
{
return;
}
bool flag = abilities.IsActive(id);
abilities.For(id).Stop(now);
foreach (string item in NativeLocomotion.Stop(id))
{
((MelonBase)this).LoggerInstance.Msg(item);
}
try
{
value.Clock?.Dispose();
}
catch (Exception ex)
{
((MelonBase)this).LoggerInstance.Error("Body cleanup: " + ex);
}
finally
{
value.Clock = null;
value.Echo = null;
value.TriggerDevice = null;
}
if (flag)
{
((MelonBase)this).LoggerInstance.Msg($"SANDE END actor={id} real={Time.realtimeSinceStartup - value.Started:F3}s remaining={abilities.ActiveCount} cooldown=6s");
}
if (abilities.ActiveCount == 0 && dilation != null)
{
float num = Time.realtimeSinceStartup - startedRealTime;
((MelonBase)this).LoggerInstance.Msg($"World clock evidence: real={num:F3}s, game={Time.time - startedGameTime:F3}s, ratio={((num > 0f) ? ((Time.time - startedGameTime) / num) : 0f):F3}, scale={Time.timeScale:F3}");
try
{
dilation.Dispose();
}
finally
{
dilation = null;
}
((MelonBase)this).LoggerInstance.Msg($"World restored: scale={Time.timeScale:F3}");
}
}
private void StopAll(double now)
{
KeyValuePair<int, Session>[] array = sessions.ToArray();
for (int i = 0; i < array.Length; i++)
{
KeyValuePair<int, Session> keyValuePair = array[i];
if (abilities.IsActive(keyValuePair.Key) || keyValuePair.Value.Clock != null)
{
StopSession(keyValuePair.Key, now);
}
}
if (abilities.ActiveCount == 0 && dilation != null)
{
try
{
dilation.Dispose();
}
finally
{
dilation = null;
}
}
}
public override void OnFixedUpdate()
{
KeyValuePair<int, Session>[] array = sessions.ToArray();
for (int i = 0; i < array.Length; i++)
{
KeyValuePair<int, Session> keyValuePair = array[i];
if (abilities.IsActive(keyValuePair.Key))
{
try
{
keyValuePair.Value.Clock?.FixedUpdate();
}
catch (Exception ex)
{
StopSession(keyValuePair.Key, Time.realtimeSinceStartup);
((MelonBase)this).LoggerInstance.Error(ex.ToString());
}
}
}
}
public override void OnLateUpdate()
{
KeyValuePair<int, Session>[] array = sessions.ToArray();
for (int i = 0; i < array.Length; i++)
{
KeyValuePair<int, Session> keyValuePair = array[i];
if (!abilities.IsActive(keyValuePair.Key))
{
continue;
}
Session value = keyValuePair.Value;
try
{
PlayerClock? clock = value.Clock;
if (clock != null && clock.ExcessiveSpeed())
{
((MelonBase)this).LoggerInstance.Error($"Player clock safety stop: actor={keyValuePair.Key} excessive real body speed.");
StopSession(keyValuePair.Key, Time.realtimeSinceStartup);
}
else
{
value.Echo?.Update(Time.realtimeSinceStartup);
}
}
catch (Exception ex)
{
StopSession(keyValuePair.Key, Time.realtimeSinceStartup);
((MelonBase)this).LoggerInstance.Error(ex.ToString());
}
}
}
private void ResetScene()
{
StopAll(Time.realtimeSinceStartup);
sessions.Clear();
abilities.Reset();
deviceOwners.Clear();
buttons.Reset();
selected = null;
inputErrorReported = false;
message = "Each controller: R3 activates or cancels its paired Beast.";
}
public override void OnSceneWasUnloaded(int index, string name)
{
ResetScene();
}
public override void OnSceneWasInitialized(int index, string name)
{
ResetScene();
try
{
PlayerClock.Prepare();
}
catch (Exception ex)
{
((MelonBase)this).LoggerInstance.Error("Player clock preparation failed: " + ex);
}
}
public override void OnDeinitializeMelon()
{
ResetScene();
PlayerClock.Unload();
}
public override void OnGUI()
{
//IL_0375: Unknown result type (might be due to invalid IL or missing references)
//IL_02b2: Unknown result type (might be due to invalid IL or missing references)
//IL_02b7: Unknown result type (might be due to invalid IL or missing references)
//IL_02c1: Unknown result type (might be due to invalid IL or missing references)
//IL_02c6: Unknown result type (might be due to invalid IL or missing references)
//IL_02cb: Unknown result type (might be due to invalid IL or missing references)
//IL_02d0: Unknown result type (might be due to invalid IL or missing references)
//IL_02d2: Unknown result type (might be due to invalid IL or missing references)
//IL_02e0: 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)
//IL_0305: Unknown result type (might be due to invalid IL or missing references)
float realtimeSinceStartup = Time.realtimeSinceStartup;
Camera main = Camera.main;
foreach (KeyValuePair<int, Session> session in sessions)
{
if (abilities.IsActive(session.Key) && session.Value.Echo != null && (Object)(object)main != (Object)null)
{
try
{
session.Value.Echo.Draw(main, realtimeSinceStartup);
}
catch (Exception ex)
{
session.Value.Echo = null;
((MelonBase)this).LoggerInstance.Warning("Echo draw: " + ex.Message);
}
}
}
if (showHud == null || !showHud.Value)
{
return;
}
KeyValuePair<int, Session>[] array = (from p in sessions
where Usable(p.Value.Actor)
orderby p.Value.Actor.playerID
select p).ToArray();
List<string> list = new List<string> { "SANDEVISTAN | Independent local players", "R3: your ability F7/F8: keyboard target" };
KeyValuePair<int, Session>[] array2 = array;
for (int num = 0; num < array2.Length; num++)
{
KeyValuePair<int, Session> keyValuePair = array2[num];
AbilityState abilityState = abilities.For(keyValuePair.Key);
Actor actor = keyValuePair.Value.Actor;
string value = (abilityState.Active ? $"ACTIVE {Math.Max(0.0, abilityState.EndsAt - (double)realtimeSinceStartup):0.0}s" : (((double)realtimeSinceStartup < abilityState.ReadyAt) ? $"Cooldown {abilityState.ReadyAt - (double)realtimeSinceStartup:0.0}s" : "Ready"));
string value2 = (((Object)(object)selected != (Object)null && ((Object)selected).GetInstanceID() == keyValuePair.Key) ? " [keyboard]" : "");
list.Add($"Beast {actor.playerID + 1}: {value}{value2}");
if (abilityState.Active && (Object)(object)main != (Object)null)
{
Vector3 val = main.WorldToScreenPoint(((Component)actor).transform.position + Vector3.up * 1.4f);
if (val.z > 0f)
{
GUI.Label(new Rect(val.x - 60f, (float)Screen.height - val.y, 180f, 30f), $"▼ SANDEVISTAN P{actor.playerID + 1}");
}
}
}
list.Add(message);
GUI.Box(new Rect(16f, 16f, 580f, (float)(26 + list.Count * 18)), string.Join("\n", list));
}
}
public sealed class MotionEcho
{
private readonly Transform[] anchors;
private readonly Queue<(float time, Vector3[] points)> history = new Queue<(float, Vector3[])>();
private float nextSample;
private static GUIStyle? strokeStyle;
public int Samples => history.Count;
public MotionEcho(IEnumerable<Transform> anchors)
{
this.anchors = anchors.Where((Transform t) => (Object)(object)t != (Object)null).Take(3).ToArray();
}
public void Update(float now)
{
while (history.Count > 0 && now - history.Peek().time > 0.45f)
{
history.Dequeue();
}
if (now < nextSample)
{
return;
}
nextSample = now + 0.025f;
if (anchors.Any((Transform t) => (Object)(object)t == (Object)null))
{
history.Clear();
return;
}
history.Enqueue((now, anchors.Select((Transform t) => t.position).ToArray()));
while (history.Count > 20)
{
history.Dequeue();
}
}
public void Draw(Camera camera, float now)
{
//IL_0287: Unknown result type (might be due to invalid IL or missing references)
//IL_028d: 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_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)
//IL_0197: Unknown result type (might be due to invalid IL or missing references)
//IL_019c: Unknown result type (might be due to invalid IL or missing references)
//IL_01a1: Unknown result type (might be due to invalid IL or missing references)
//IL_01a2: Unknown result type (might be due to invalid IL or missing references)
//IL_01b4: Unknown result type (might be due to invalid IL or missing references)
//IL_01c0: Unknown result type (might be due to invalid IL or missing references)
//IL_01fa: 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_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_0086: 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_0092: 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_022d: 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_0244: Unknown result type (might be due to invalid IL or missing references)
//IL_0249: Unknown result type (might be due to invalid IL or missing references)
//IL_024e: Unknown result type (might be due to invalid IL or missing references)
//IL_025e: Unknown result type (might be due to invalid IL or missing references)
//IL_0265: Unknown result type (might be due to invalid IL or missing references)
//IL_026a: Unknown result type (might be due to invalid IL or missing references)
//IL_00b6: Unknown result type (might be due to invalid IL or missing references)
//IL_00c3: 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_00df: 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_00ee: 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_011e: Unknown result type (might be due to invalid IL or missing references)
//IL_0146: Unknown result type (might be due to invalid IL or missing references)
//IL_0148: Unknown result type (might be due to invalid IL or missing references)
(float, Vector3[])[] array = history.ToArray();
if (array.Length == 0 || anchors.Length == 0)
{
return;
}
Color color = GUI.color;
Matrix4x4 matrix = GUI.matrix;
try
{
Vector2 val3 = default(Vector2);
Vector2 val4 = default(Vector2);
for (int i = 1; i < array.Length; i++)
{
float num = Mathf.Clamp01(1f - (now - array[i].Item1) / 0.45f);
for (int j = 0; j < array[i].Item2.Length; j++)
{
Vector3 val = camera.WorldToScreenPoint(array[i - 1].Item2[j]);
Vector3 val2 = camera.WorldToScreenPoint(array[i].Item2[j]);
if (!(val.z <= 0f) && !(val2.z <= 0f))
{
((Vector2)(ref val3))..ctor(val.x, (float)Screen.height - val.y);
((Vector2)(ref val4))..ctor(val2.x, (float)Screen.height - val2.y);
if (!(Vector2.Distance(val3, val4) > (float)Screen.width * 0.3f))
{
GUI.color = ((j == 0) ? new Color(0f, 1f, 1f, num * 0.8f) : new Color(1f, 0.1f, 0.35f, num * 0.8f));
Stroke(val3, val4, (j == 0) ? 9 : 5);
}
}
}
}
Vector3 val5 = camera.WorldToScreenPoint(array[^1].Item2[0]);
if (val5.z > 0f)
{
Vector2 val6 = default(Vector2);
((Vector2)(ref val6))..ctor(val5.x, (float)Screen.height - val5.y);
float num2 = 25f + Mathf.Sin(now * 14f) * 4f;
GUI.color = new Color(0f, 1f, 1f, 0.9f);
for (int k = 0; k < 20; k++)
{
float num3 = (float)k * (float)Math.PI / 10f;
float num4 = (float)(k + 1) * (float)Math.PI / 10f;
Stroke(val6 + new Vector2(Mathf.Cos(num3), Mathf.Sin(num3)) * num2, val6 + new Vector2(Mathf.Cos(num4), Mathf.Sin(num4)) * num2, 3f);
}
}
}
finally
{
GUI.color = color;
GUI.matrix = matrix;
}
}
private static void Stroke(Vector2 a, Vector2 b, float width)
{
//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_00b0: 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_0016: 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_001d: 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_003c: 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_008a: Unknown result type (might be due to invalid IL or missing references)
//IL_009a: 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_005d: Expected O, but got Unknown
//IL_007a: Unknown result type (might be due to invalid IL or missing references)
//IL_0084: Expected O, but got Unknown
float num = Vector2.Distance(a, b);
if (num < 0.1f)
{
return;
}
Matrix4x4 matrix = GUI.matrix;
try
{
GUIUtility.RotateAroundPivot(Mathf.Atan2(b.y - a.y, b.x - a.x) * 57.29578f, a);
if (strokeStyle == null)
{
strokeStyle = new GUIStyle(GUI.skin.box);
strokeStyle.normal.background = Texture2D.whiteTexture;
strokeStyle.border = new RectOffset(0, 0, 0, 0);
}
GUI.Box(new Rect(a.x, a.y - width / 2f, num, width), GUIContent.none, strokeStyle);
}
finally
{
GUI.matrix = matrix;
}
}
}
internal sealed class MutationJournal
{
private readonly Stack<Action> undo = new Stack<Action>();
public void Set(Action change, Action restore)
{
undo.Push(restore);
change();
}
public void Commit()
{
undo.Clear();
}
public void Rollback()
{
List<Exception> list = new List<Exception>();
Action result;
while (undo.TryPop(out result))
{
try
{
result();
}
catch (Exception item)
{
list.Add(item);
}
}
if (list.Count != 0)
{
throw new AggregateException("Body restoration failed", list);
}
}
}
public static class NativeLocomotion
{
[HarmonyPatch(typeof(MovementHandeler_HumanoidMediumEctomorph), "RunCycleRotateBall")]
private static class SpeedPatch
{
[HarmonyPriority(800)]
private static void Prefix(MovementHandeler_HumanoidMediumEctomorph __instance, out float? __state)
{
__state = null;
if (Active && !((Object)(object)((MovementHandeler)__instance).actor == (Object)null))
{
Actor actor = ((MovementHandeler)__instance).actor;
float cycleModifer = __instance._cycleModifer;
if (float.IsFinite(cycleModifer) && !(cycleModifer < 0f))
{
int instanceID = ((Object)actor).GetInstanceID();
float num = (activeActors.Contains(instanceID) ? (cycleModifer * Math.Clamp(SelectedWalkMultiplier, 1f, 4f)) : cycleModifer);
__state = cycleModifer;
__instance._cycleModifer = num;
evidence.TryGetValue(instanceID, out (bool, int, float, float) value);
evidence[instanceID] = (actor.IsAI, value.Item2 + 1, cycleModifer, num);
}
}
}
private static void Postfix(MovementHandeler_HumanoidMediumEctomorph __instance, float? __state)
{
if (__state.HasValue)
{
__instance._cycleModifer = __state.Value;
}
}
private static Exception? Finalizer(MovementHandeler_HumanoidMediumEctomorph __instance, float? __state, Exception? __exception)
{
if (__state.HasValue)
{
__instance._cycleModifer = __state.Value;
}
return __exception;
}
}
private static readonly HashSet<int> activeActors = new HashSet<int>();
private static readonly Dictionary<int, (bool ai, int calls, float before, float during)> evidence = new Dictionary<int, (bool, int, float, float)>();
public static bool Active => activeActors.Count > 0;
public static float SelectedWalkMultiplier { get; set; } = 1.5f;
public static void Start(Actor selected)
{
activeActors.Add(((Object)selected).GetInstanceID());
}
public static IEnumerable<string> Stop(int actorId)
{
activeActors.Remove(actorId);
string[] result = (from x in evidence
where x.Key == actorId
select $"Native locomotion: actor={x.Key}, ai={x.Value.ai}, calls={x.Value.calls}, baseline={x.Value.before:F3}, effective={x.Value.during:F3}").ToArray();
evidence.Remove(actorId);
if (activeActors.Count == 0)
{
evidence.Clear();
}
return result;
}
}
public sealed class PlayerAbilities
{
private readonly Dictionary<int, AbilityState> players = new Dictionary<int, AbilityState>();
public int ActiveCount => players.Values.Count((AbilityState s) => s.Active);
public AbilityState For(int actorId)
{
if (!players.TryGetValue(actorId, out AbilityState value))
{
value = (players[actorId] = new AbilityState());
}
return value;
}
public bool IsActive(int actorId)
{
if (players.TryGetValue(actorId, out AbilityState value))
{
return value.Active;
}
return false;
}
public void Reset()
{
players.Clear();
}
}
public sealed class PlayerClock : IDisposable
{
[HarmonyPatch(typeof(Actor), "FixedUpdate")]
private static class FixedScope
{
private static void Prefix(Actor __instance, out int __state)
{
__state = LocalTimeHooks.ScopeDepth;
LocalTimeHooks.ScopeDepth = (IsActive(((Object)__instance).GetInstanceID()) ? 1 : 0);
}
private static Exception? Finalizer(int __state, Exception? __exception)
{
LocalTimeHooks.ScopeDepth = __state;
return __exception;
}
}
[HarmonyPatch(typeof(Actor), "Update")]
private static class UpdateScope
{
private static void Prefix(Actor __instance, out int __state)
{
__state = LocalTimeHooks.ScopeDepth;
LocalTimeHooks.ScopeDepth = (IsActive(((Object)__instance).GetInstanceID()) ? 1 : 0);
}
private static Exception? Finalizer(int __state, Exception? __exception)
{
LocalTimeHooks.ScopeDepth = __state;
return __exception;
}
}
private readonly List<(Rigidbody body, float drag, float angularDrag, float maxAngular, bool gravity)> bodies = new List<(Rigidbody, float, float, float, bool)>();
private readonly float factor;
private readonly int actorId;
private bool applied;
private bool disposed;
private static bool hooksReady;
private static readonly HashSet<int> activeActors = new HashSet<int>();
public static bool IsActive(int id)
{
return activeActors.Contains(id);
}
public static void Prepare()
{
if (!hooksReady)
{
LocalTimeHooks.Install();
hooksReady = true;
}
}
public PlayerClock(Actor actor, float worldScale)
{
Prepare();
factor = 1f / worldScale;
actorId = ((Object)actor).GetInstanceID();
foreach (Rigidbody item in (Il2CppArrayBase<Rigidbody>)(object)actor.bodyHandeler.GetAllRigidbodies())
{
if ((Object)(object)item != (Object)null && !item.isKinematic)
{
bodies.Add((item, item.drag, item.angularDrag, item.maxAngularVelocity, item.useGravity));
}
}
}
public void Apply()
{
//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_0076: Unknown result type (might be due to invalid IL or missing references)
//IL_007b: Unknown result type (might be due to invalid IL or missing references)
if (disposed)
{
throw new ObjectDisposedException("PlayerClock");
}
if (applied)
{
return;
}
MutationJournal mutationJournal = new MutationJournal();
try
{
foreach (var item in bodies)
{
Rigidbody body = item.body;
Vector3 velocity = body.velocity;
Vector3 angular = body.angularVelocity;
mutationJournal.Set(delegate
{
//IL_0007: 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)
body.velocity = velocity * factor;
}, delegate
{
//IL_0015: Unknown result type (might be due to invalid IL or missing references)
if ((Object)(object)body != (Object)null)
{
body.velocity = velocity;
}
});
mutationJournal.Set(delegate
{
//IL_0007: 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)
body.angularVelocity = angular * factor;
}, delegate
{
//IL_0015: Unknown result type (might be due to invalid IL or missing references)
if ((Object)(object)body != (Object)null)
{
body.angularVelocity = angular;
}
});
mutationJournal.Set(delegate
{
body.drag = item.drag * factor;
}, delegate
{
if ((Object)(object)body != (Object)null)
{
body.drag = item.drag;
}
});
mutationJournal.Set(delegate
{
body.angularDrag = item.angularDrag * factor;
}, delegate
{
if ((Object)(object)body != (Object)null)
{
body.angularDrag = item.angularDrag;
}
});
mutationJournal.Set(delegate
{
body.maxAngularVelocity = item.maxAngular * factor;
}, delegate
{
if ((Object)(object)body != (Object)null)
{
body.maxAngularVelocity = item.maxAngular;
}
});
}
foreach (var body2 in bodies)
{
LocalTimeHooks.Bodies.Add(((Il2CppObjectBase)body2.body).Pointer);
}
LocalTimeHooks.Factor = factor;
activeActors.Add(actorId);
applied = true;
mutationJournal.Commit();
}
catch (Exception ex)
{
foreach (var body3 in bodies)
{
LocalTimeHooks.Bodies.Remove(((Il2CppObjectBase)body3.body).Pointer);
}
activeActors.Remove(actorId);
if (activeActors.Count == 0)
{
LocalTimeHooks.Factor = 1f;
}
try
{
mutationJournal.Rollback();
}
catch (Exception ex2)
{
throw new AggregateException(ex, ex2);
}
throw;
}
}
public void FixedUpdate()
{
//IL_0055: 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)
if (!applied || disposed)
{
return;
}
foreach (var body in bodies)
{
if ((Object)(object)body.body != (Object)null && body.body.useGravity && !body.body.isKinematic)
{
body.body.AddForce(Physics.gravity * (factor * factor - 1f), (ForceMode)5);
}
}
}
public bool ExcessiveSpeed()
{
return bodies.Any<(Rigidbody, float, float, float, bool)>(delegate((Rigidbody body, float drag, float angularDrag, float maxAngular, bool gravity) x)
{
//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)
if ((Object)(object)x.body != (Object)null)
{
Vector3 velocity = x.body.velocity;
return ((Vector3)(ref velocity)).magnitude * Time.timeScale > 25f;
}
return false;
});
}
public void Dispose()
{
if (disposed)
{
return;
}
disposed = true;
activeActors.Remove(actorId);
foreach (var body in bodies)
{
LocalTimeHooks.Bodies.Remove(((Il2CppObjectBase)body.body).Pointer);
}
if (activeActors.Count == 0)
{
LocalTimeHooks.Factor = 1f;
LocalTimeHooks.ScopeDepth = 0;
}
if (!applied)
{
return;
}
MutationJournal mutationJournal = new MutationJournal();
foreach (var item in bodies)
{
if ((Object)(object)item.body == (Object)null)
{
continue;
}
mutationJournal.Set(delegate
{
}, delegate
{
//IL_001f: 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)
if ((Object)(object)item.body != (Object)null)
{
Rigidbody item2 = item.body;
item2.velocity /= factor;
}
});
mutationJournal.Set(delegate
{
}, delegate
{
//IL_001f: 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)
if ((Object)(object)item.body != (Object)null)
{
Rigidbody item2 = item.body;
item2.angularVelocity /= factor;
}
});
mutationJournal.Set(delegate
{
}, delegate
{
if ((Object)(object)item.body != (Object)null)
{
item.body.drag = item.drag;
}
});
mutationJournal.Set(delegate
{
}, delegate
{
if ((Object)(object)item.body != (Object)null)
{
item.body.angularDrag = item.angularDrag;
}
});
mutationJournal.Set(delegate
{
}, delegate
{
if ((Object)(object)item.body != (Object)null)
{
item.body.maxAngularVelocity = item.maxAngular;
}
});
}
mutationJournal.Rollback();
}
public static void Unload()
{
if (hooksReady)
{
LocalTimeHooks.Uninstall();
}
hooksReady = false;
activeActors.Clear();
}
}
public sealed class WorldDilation : IDisposable
{
private readonly float scale;
private readonly float savedScale;
private readonly float savedStep;
private readonly float savedGameplay;
private readonly TimeManager? timeManager;
private bool applied;
private bool disposed;
public WorldDilation(Actor actor, float scale)
{
if (scale <= 0f || scale > 1f)
{
throw new ArgumentOutOfRangeException("scale");
}
this.scale = scale;
savedScale = Time.timeScale;
savedStep = Time.fixedDeltaTime;
timeManager = Object.FindObjectOfType<TimeManager>();
savedGameplay = (((Object)(object)timeManager == (Object)null) ? savedScale : timeManager.GamePlayTime);
}
public void Apply()
{
applied = true;
if ((Object)(object)timeManager != (Object)null)
{
timeManager.GamePlayTime = savedGameplay * scale;
}
Time.fixedDeltaTime = savedStep * scale;
Time.timeScale = savedScale * scale;
}
public void Dispose()
{
if (disposed)
{
return;
}
disposed = true;
if (applied)
{
if ((Object)(object)timeManager != (Object)null && Mathf.Approximately(timeManager.GamePlayTime, savedGameplay * scale))
{
timeManager.GamePlayTime = savedGameplay;
}
if (Mathf.Approximately(Time.timeScale, savedScale * scale))
{
Time.timeScale = savedScale;
}
if (Mathf.Approximately(Time.fixedDeltaTime, savedStep * scale))
{
Time.fixedDeltaTime = savedStep;
}
}
}
}
}