using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.Linq;
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 UnityEngine;
using UnityEngine.AddressableAssets;
using UnityEngine.Events;
using UnityEngine.ResourceManagement.AsyncOperations;
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("SunChase")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+0c5c7ba8d3508d758a3dd573876bc63099f0c052")]
[assembly: AssemblyProduct("SunChase")]
[assembly: AssemblyTitle("SunChase")]
[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 SunChase
{
[BepInPlugin("lakisa.sunchase", "Sun Chase", "1.0.0")]
public class SunChasePlugin : BaseUnityPlugin
{
internal static ManualLogSource Log;
internal static ConfigEntry<bool> Enabled;
internal static ConfigEntry<string> SpeedMode;
private static readonly string[] Modes = new string[3] { "vanilla", "mass_logic", "player" };
private static readonly string[] PlayerModes = new string[3] { "walk", "run", "crouch" };
private const string Usage = "sun_spd <vanilla|mass_logic|player [run|walk|crouch]|m/s>";
private CommandConsole console;
private static SunChasePlugin instance;
private static readonly HashSet<DEN_DeathFloor> replaced = new HashSet<DEN_DeathFloor>();
private void Awake()
{
//IL_0030: Unknown result type (might be due to invalid IL or missing references)
//IL_0035: Unknown result type (might be due to invalid IL or missing references)
//IL_005d: Unknown result type (might be due to invalid IL or missing references)
//IL_006a: Expected O, but got Unknown
//IL_0091: Unknown result type (might be due to invalid IL or missing references)
//IL_009f: Expected O, but got Unknown
Log = ((BaseUnityPlugin)this).Logger;
Enabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enabled", true, "Replace the mass with the Shuttered Rift's bomb.");
Harmony val = new Harmony("lakisa.sunchase");
val.Patch((MethodBase)AccessTools.Method(typeof(DEN_DeathFloor), "Start", (Type[])null, (Type[])null), (HarmonyMethod)null, new HarmonyMethod(typeof(SunChasePlugin), "MassStartPostfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
val.Patch((MethodBase)AccessTools.Method(typeof(DEN_DeathFloor), "Update", (Type[])null, (Type[])null), new HarmonyMethod(typeof(SunChasePlugin), "MassUpdatePrefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
SpeedMode = ((BaseUnityPlugin)this).Config.Bind<string>("General", "SunSpeed", "mass_logic", "How fast the sun's edge grows: vanilla (the Rift's), mass_logic (speeds up and slows down exactly like the mass would), player run / player walk / player crouch (your own speed for that), or a number in m/s. Also the sun_spd console command.");
instance = this;
SceneManager.sceneLoaded += delegate(Scene s, LoadSceneMode _)
{
if (((Scene)(ref s)).name == "Main-Menu")
{
StartFind();
}
};
}
private void Update()
{
if ((Object)(object)CommandConsole.instance == (Object)null || (Object)(object)CommandConsole.instance == (Object)(object)console)
{
return;
}
console = CommandConsole.instance;
CommandConsole.BuildCommand("sun_spd", (Action<string[]>)SunSpeedCommand).NotCheat().Description("sun_spd <vanilla|mass_logic|player [run|walk|crouch]|m/s>: how fast the sun grows. vanilla = the Rift's, mass_logic = speeds up and slows down like the mass, player = your own run / walk / crouch speed")
.AutocompleteCustom((Action<CommandAutocomplete>)delegate(CommandAutocomplete ac)
{
if (ac.activeArg == 0)
{
ac.FromArray((IReadOnlyList<string>)Modes);
}
else if (ac.activeArg == 1)
{
ac.FromArray((IReadOnlyList<string>)PlayerModes);
}
});
}
internal static string Normalize(string[] args)
{
if (args == null || args.Length == 0)
{
return null;
}
string text = args[0].ToLowerInvariant();
switch (text)
{
case "catch_up":
case "catchup":
case "mass":
return "mass_logic";
case "relative":
return "player walk";
case "player":
{
string text2 = ((args.Length > 1) ? args[1].ToLowerInvariant() : "walk");
if (text2 == "sprint")
{
text2 = "run";
}
if (!PlayerModes.Contains(text2))
{
return null;
}
return "player " + text2;
}
default:
{
if (Modes.Contains(text))
{
return text;
}
if (!float.TryParse(text, NumberStyles.Float, CultureInfo.InvariantCulture, out var result) || !(result >= 0f))
{
return null;
}
return text;
}
}
}
private static void SunSpeedCommand(string[] args)
{
if (args.Length == 0)
{
CommandConsole.Log(string.Format("sun_spd is {0} ({1:0.0} m/s now). {2}", SpeedMode.Value, BombRunner.CurrentSpeed, "sun_spd <vanilla|mass_logic|player [run|walk|crouch]|m/s>"));
return;
}
string text = Normalize(args);
if (text == null)
{
CommandConsole.Log("Unknown sun_spd '" + string.Join(" ", args) + "'. sun_spd <vanilla|mass_logic|player [run|walk|crouch]|m/s>");
return;
}
SpeedMode.Value = text;
CommandConsole.Log("sun_spd set to " + text);
Log.LogInfo((object)("> sun_spd " + text));
}
internal static void StartFind()
{
if (Bomb.State == Bomb.Status.NotTried && (Object)(object)instance != (Object)null)
{
((MonoBehaviour)instance).StartCoroutine(Bomb.Find());
}
}
private static void MassStartPostfix(DEN_DeathFloor __instance)
{
//IL_0050: Unknown result type (might be due to invalid IL or missing references)
//IL_0055: Unknown result type (might be due to invalid IL or missing references)
//IL_005b: 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)
if (Enabled.Value && ModeOk())
{
replaced.RemoveWhere((DEN_DeathFloor m) => (Object)(object)m == (Object)null);
replaced.Add(__instance);
Vector3 position = ((Component)__instance).transform.position;
StartFind();
BombRunner.Make(position, __instance);
if ((Object)(object)__instance.visualRoot != (Object)null)
{
__instance.visualRoot.SetActive(false);
}
AudioSource[] componentsInChildren = ((Component)__instance).GetComponentsInChildren<AudioSource>(true);
foreach (AudioSource obj in componentsInChildren)
{
obj.Stop();
((Behaviour)obj).enabled = false;
}
Log.LogInfo((object)($"Mass replaced by the bomb at {position}" + ((Bomb.State == Bomb.Status.Found) ? "" : " (waiting for the Rift's bomb to load)")));
}
}
private static bool MassUpdatePrefix(DEN_DeathFloor __instance)
{
return !replaced.Contains(__instance);
}
internal static void GiveBack(DEN_DeathFloor mass)
{
if (!((Object)(object)mass == (Object)null))
{
replaced.Remove(mass);
if ((Object)(object)mass.visualRoot != (Object)null)
{
mass.visualRoot.SetActive(true);
}
AudioSource[] componentsInChildren = ((Component)mass).GetComponentsInChildren<AudioSource>(true);
for (int i = 0; i < componentsInChildren.Length; i++)
{
((Behaviour)componentsInChildren[i]).enabled = true;
}
Log.LogWarning((object)"No Shuttered Rift bomb: the mass stays.");
}
}
private static bool ModeOk()
{
M_Gamemode baseGamemode = CL_GameManager.GetBaseGamemode();
string text = (baseGamemode?.gamemodeName + ((baseGamemode != null) ? ((Object)baseGamemode).name : null)).ToLowerInvariant();
if (!text.Contains("arena"))
{
return !text.Contains("gauntlet");
}
return false;
}
}
internal static class Bomb
{
public enum Status
{
NotTried,
Loading,
Found,
Missing
}
public struct Call
{
public Object target;
public string method;
}
public class FieldPath
{
public FieldInfo field;
public int index = -1;
public FieldInfo inner;
public UnityEventBase Get(object o)
{
object obj = field.GetValue(o);
if (index >= 0)
{
obj = ((obj is IList list && index < list.Count && list[index] != null) ? inner.GetValue(list[index]) : null);
}
return (UnityEventBase)((obj is UnityEventBase) ? obj : null);
}
public override string ToString()
{
if (index >= 0)
{
return $"{field.Name}[{index}].{inner.Name}";
}
return field.Name;
}
}
public static Status State;
public static GameObject Template;
public static int[] SunPath;
public static int[] ButtonPath;
public static Type ButtonType;
public static FieldPath ButtonEvent;
public static int[] SequencePath;
private const string BombLevel = "CH_Shutter_Pier_End_Big";
private const int MaxModuleSize = 400;
private static GameObject holder;
public static bool Done
{
get
{
if (State != Status.Found)
{
return State == Status.Missing;
}
return true;
}
}
public static IEnumerator Find()
{
State = Status.Loading;
List<LevelAssetHolder> levels = ((AccessTools.Field(typeof(CL_AssetManager), "databases").GetValue(null) is IEnumerable<WKDatabaseHolder> source) ? (from val3 in source.Where((WKDatabaseHolder d) => d?.database?.levelAssets != null).SelectMany((WKDatabaseHolder d) => d.database.levelAssets)
where val3?.levelAssetReference != null && val3.id.IndexOf("shutter", StringComparison.OrdinalIgnoreCase) >= 0
orderby (val3.id.IndexOf("CH_Shutter_Pier_End_Big", StringComparison.OrdinalIgnoreCase) < 0) ? 1 : 0
select val3).ToList() : null) ?? new List<LevelAssetHolder>();
foreach (LevelAssetHolder l in levels)
{
AsyncOperationHandle<GameObject> op;
try
{
op = Addressables.LoadAssetAsync<GameObject>(((AssetReference)l.levelAssetReference).RuntimeKey);
}
catch (Exception ex)
{
SunChasePlugin.Log.LogWarning((object)("Load " + l.id + ": " + ex.Message));
continue;
}
while (!op.IsDone)
{
yield return null;
}
GameObject val = (((int)op.Status == 1) ? op.Result : null);
ENV_KillBubble val2 = (((Object)(object)val != (Object)null) ? val.GetComponentsInChildren<ENV_KillBubble>(true).FirstOrDefault() : null);
if ((Object)(object)val2 == (Object)null)
{
Addressables.Release<GameObject>(op);
continue;
}
bool flag = false;
try
{
flag = Cut(val, val2);
}
catch (Exception arg)
{
SunChasePlugin.Log.LogError((object)$"Cutting the bomb out of {l.id}: {arg}");
}
if (!flag)
{
Addressables.Release<GameObject>(op);
continue;
}
SunChasePlugin.Log.LogInfo((object)("Bomb module cut from " + l.id));
State = Status.Found;
yield break;
}
SunChasePlugin.Log.LogWarning((object)$"No bomb found in {levels.Count} Shuttered Rift levels.");
State = Status.Missing;
}
private static bool Cut(GameObject level, ENV_KillBubble kb)
{
//IL_0473: Unknown result type (might be due to invalid IL or missing references)
//IL_047d: Expected O, but got Unknown
//IL_04b9: Unknown result type (might be due to invalid IL or missing references)
//IL_04c4: Unknown result type (might be due to invalid IL or missing references)
Transform root = level.transform;
List<MonoBehaviour> list = (from m in level.GetComponentsInChildren<MonoBehaviour>(true)
where (Object)(object)m != (Object)null
select m).ToList();
UT_Timer seq = list.OfType<UT_Timer>().FirstOrDefault((Func<UT_Timer, bool>)((UT_Timer mb) => Events((MonoBehaviour)(object)mb).Any((UnityEventBase e) => Calls(e).Any((Call c) => c.target == (Object)(object)kb && c.method == "GrowTo"))));
MonoBehaviour val = null;
FieldPath fieldPath = null;
if ((Object)(object)seq != (Object)null)
{
foreach (MonoBehaviour item in list)
{
if ((Object)(object)item == (Object)(object)seq)
{
continue;
}
foreach (var (ev, fieldPath2) in EventsWithPaths(item))
{
if (Calls(ev).Any((Call c) => c.target == (Object)(object)seq || c.target == (Object)(object)((Component)seq).gameObject))
{
val = item;
fieldPath = fieldPath2;
break;
}
}
if ((Object)(object)val != (Object)null)
{
break;
}
}
}
SunChasePlugin.Log.LogInfo((object)("Bomb: sun " + Path(root, ((Component)kb).transform) + ", sequence " + (((Object)(object)seq != (Object)null) ? Path(root, ((Component)seq).transform) : "none") + ", button " + (((Object)(object)val != (Object)null) ? (Path(root, ((Component)val).transform) + " (" + ((object)val).GetType().Name + "." + fieldPath?.ToString() + ")") : "none")));
HashSet<Transform> keep = new HashSet<Transform>();
if ((Object)(object)val != (Object)null)
{
Transform t = (((Object)(object)((Component)val).transform.parent != (Object)null && (Object)(object)((Component)val).transform.parent != (Object)(object)root) ? ((Component)val).transform.parent : ((Component)val).transform);
Add(t, "bomb machine");
Add(((Component)val).transform, "button");
}
Add(((Component)kb).transform, "sun");
if ((Object)(object)seq != (Object)null)
{
Add(((Component)seq).transform, "sequence");
}
List<Transform> list2 = keep.ToList();
for (int num = 0; num < 3; num++)
{
if (list2.Count <= 0)
{
break;
}
List<Transform> list3 = new List<Transform>();
foreach (Transform item2 in list2)
{
MonoBehaviour[] componentsInChildren = ((Component)item2).GetComponentsInChildren<MonoBehaviour>(true);
foreach (MonoBehaviour val2 in componentsInChildren)
{
foreach (UnityEventBase item3 in Events(val2))
{
foreach (Call item4 in Calls(item3))
{
Object target = item4.target;
Component val3 = (Component)(object)((target is Component) ? target : null);
object obj2;
if (val3 == null)
{
Object target2 = item4.target;
Object obj = ((target2 is GameObject) ? target2 : null);
obj2 = ((obj != null) ? ((GameObject)obj).transform : null);
}
else
{
obj2 = val3.transform;
}
Transform tt = (Transform)obj2;
if (!((Object)(object)tt == (Object)null) && !keep.Any((Transform k) => tt.IsChildOf(k)))
{
Add(tt, ((Object)val2).name + "." + item4.method);
if (keep.Contains(tt))
{
list3.Add(tt);
}
}
}
}
}
}
list2 = list3;
}
holder = new GameObject("SunChase_Templates");
holder.SetActive(false);
Object.DontDestroyOnLoad((Object)(object)holder);
GameObject copy = Object.Instantiate<GameObject>(level, holder.transform);
copy.transform.SetPositionAndRotation(root.position, root.rotation);
SunPath = IndexPath(root, ((Component)kb).transform);
if ((Object)(object)seq != (Object)null)
{
SequencePath = IndexPath(root, ((Component)seq).transform);
}
if ((Object)(object)val != (Object)null)
{
ButtonPath = IndexPath(root, ((Component)val).transform);
ButtonType = ((object)val).GetType();
ButtonEvent = fieldPath;
}
HashSet<Transform> keep2 = new HashSet<Transform>(keep.Select((Transform t3) => Follow(copy.transform, IndexPath(root, t3))));
Transform t2 = Follow(copy.transform, SunPath);
Transform val4 = ((SequencePath != null) ? Follow(copy.transform, SequencePath) : null);
Transform val5 = ((ButtonPath != null) ? Follow(copy.transform, ButtonPath) : null);
Prune(copy.transform, keep2);
foreach (Component item5 in (from c in copy.GetComponents<Component>()
where !(c is Transform)
select c).ToList())
{
Object.DestroyImmediate((Object)(object)item5);
}
SunPath = IndexPath(copy.transform, t2);
if ((Object)(object)val4 != (Object)null)
{
SequencePath = IndexPath(copy.transform, val4);
}
if ((Object)(object)val5 != (Object)null)
{
ButtonPath = IndexPath(copy.transform, val5);
}
Template = copy;
SunChasePlugin.Log.LogInfo((object)($"Bomb module: {copy.GetComponentsInChildren<Transform>(true).Length} objects, components " + string.Join(", ", (from c in copy.GetComponentsInChildren<Component>(true)
select ((object)c).GetType().Name).Distinct())));
return true;
void Add(Transform val6, string why)
{
if (!((Object)(object)val6 == (Object)null) && !((Object)(object)val6 == (Object)(object)root) && val6.IsChildOf(root) && !keep.Any((Transform k) => val6.IsChildOf(k)))
{
int num3 = ((Component)val6).GetComponentsInChildren<Transform>(true).Length;
if (num3 > 400)
{
SunChasePlugin.Log.LogInfo((object)$"Bomb: skipped {Path(root, val6)} ({num3} objects, {why})");
}
else
{
keep.RemoveWhere((Transform k) => k.IsChildOf(val6));
keep.Add(val6);
SunChasePlugin.Log.LogInfo((object)$"Bomb: keep {Path(root, val6)} ({num3} objects, {why})");
}
}
}
}
private static void Prune(Transform t, HashSet<Transform> keep)
{
for (int num = t.childCount - 1; num >= 0; num--)
{
Transform c = t.GetChild(num);
if (!keep.Contains(c))
{
if (keep.Any((Transform k) => k.IsChildOf(c)))
{
foreach (Component item in (from x in ((Component)c).GetComponents<Component>()
where !(x is Transform)
orderby (!(x is MonoBehaviour)) ? 1 : 0
select x).ToList())
{
try
{
Object.DestroyImmediate((Object)(object)item);
}
catch
{
}
}
Prune(c, keep);
}
else
{
Object.DestroyImmediate((Object)(object)((Component)c).gameObject);
}
}
}
}
public static IEnumerable<Call> Calls(UnityEventBase ev)
{
if (!(Traverse.Create((object)ev).Field("m_PersistentCalls").Field("m_Calls")
.GetValue() is IList list))
{
yield break;
}
foreach (object item in list)
{
Traverse val = Traverse.Create(item);
yield return new Call
{
target = val.Field("m_Target").GetValue<Object>(),
method = val.Field("m_MethodName").GetValue<string>()
};
}
}
public static IEnumerable<UnityEventBase> Events(MonoBehaviour mb)
{
return from x in EventsWithPaths(mb)
select x.Item1;
}
public static IEnumerable<(UnityEventBase, FieldPath)> EventsWithPaths(MonoBehaviour mb)
{
List<(UnityEventBase, FieldPath)> list = new List<(UnityEventBase, FieldPath)>();
Type type = ((object)mb).GetType();
while (type != null && type != typeof(MonoBehaviour))
{
FieldInfo[] fields = type.GetFields(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
foreach (FieldInfo fieldInfo in fields)
{
try
{
if (typeof(UnityEventBase).IsAssignableFrom(fieldInfo.FieldType))
{
object? value = fieldInfo.GetValue(mb);
UnityEventBase val = (UnityEventBase)((value is UnityEventBase) ? value : null);
if (val != null)
{
list.Add((val, new FieldPath
{
field = fieldInfo
}));
}
}
else
{
if (!typeof(IList).IsAssignableFrom(fieldInfo.FieldType) || !fieldInfo.FieldType.IsGenericType || !fieldInfo.FieldType.GetGenericArguments()[0].IsClass || typeof(Object).IsAssignableFrom(fieldInfo.FieldType.GetGenericArguments()[0]) || !(fieldInfo.GetValue(mb) is IList list2))
{
continue;
}
List<FieldInfo> list3 = (from x in fieldInfo.FieldType.GetGenericArguments()[0].GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)
where typeof(UnityEventBase).IsAssignableFrom(x.FieldType)
select x).ToList();
if (list3.Count == 0)
{
continue;
}
for (int num = 0; num < list2.Count; num++)
{
foreach (FieldInfo item in list3)
{
if (list2[num] != null)
{
object? value2 = item.GetValue(list2[num]);
UnityEventBase val2 = (UnityEventBase)((value2 is UnityEventBase) ? value2 : null);
if (val2 != null)
{
list.Add((val2, new FieldPath
{
field = fieldInfo,
index = num,
inner = item
}));
}
}
}
}
continue;
}
}
catch
{
}
}
type = type.BaseType;
}
return list;
}
public static int[] IndexPath(Transform root, Transform t)
{
List<int> list = new List<int>();
Transform val = t;
while ((Object)(object)val != (Object)(object)root)
{
list.Insert(0, val.GetSiblingIndex());
val = val.parent;
}
return list.ToArray();
}
public static Transform Follow(Transform root, int[] path)
{
Transform val = root;
foreach (int num in path)
{
val = val.GetChild(num);
}
return val;
}
private static string Path(Transform root, Transform t)
{
List<string> list = new List<string>();
Transform val = t;
while ((Object)(object)val != (Object)null && (Object)(object)val != (Object)(object)root)
{
list.Insert(0, ((Object)val).name);
val = val.parent;
}
return string.Join("/", list);
}
}
internal class BombRunner : MonoBehaviour
{
private DEN_DeathFloor mass;
private Transform sun;
private bool placed;
private float placedAt;
private float fxLogAt = 20f;
public static float CurrentSpeed;
private ENV_KillBubble kb;
private float vanillaSpeed = 2f;
private float loggedRun = -1f;
private static readonly FieldRef<ENV_KillBubble, float> Scale = AccessTools.FieldRefAccess<ENV_KillBubble, float>("scale");
private static readonly FieldRef<DEN_DeathFloor, float> MassSpeedMult = AccessTools.FieldRefAccess<DEN_DeathFloor, float>("speedMult");
private static readonly FieldRef<DEN_DeathFloor, float> MassFrameMult = AccessTools.FieldRefAccess<DEN_DeathFloor, float>("speedMultFrameStorage");
private static readonly FieldRef<DEN_DeathFloor, float> MassRampMult = AccessTools.FieldRefAccess<DEN_DeathFloor, float>("speedIncreaseRateMultiplier");
private static readonly FieldRef<DEN_DeathFloor, bool> MassRubberband = AccessTools.FieldRefAccess<DEN_DeathFloor, bool>("rubberbandActive");
private static readonly FieldRef<DEN_DeathFloor, bool> MassActive = AccessTools.FieldRefAccess<DEN_DeathFloor, bool>("active");
private bool massStarted;
private bool caughtUp;
private float virtualRise;
private const float BurstRate = 1.5f;
private static readonly FieldRef<ENT_Player, float> PlayerSpeedMult = AccessTools.FieldRefAccess<ENT_Player, float>("speedMult");
private static readonly FieldRef<ENT_Player, float> TempFriction = AccessTools.FieldRefAccess<ENT_Player, float>("tempFrictionMult");
public static void Make(Vector3 massPos, DEN_DeathFloor mass)
{
//IL_0005: Unknown result type (might be due to invalid IL or missing references)
//IL_000b: Expected O, but got Unknown
//IL_0011: Unknown result type (might be due to invalid IL or missing references)
GameObject val = new GameObject("SunChase_Bomb");
val.transform.position = massPos;
if ((Object)(object)WorldLoader.instance != (Object)null)
{
val.transform.SetParent(WorldLoader.GetWorldLoaderNullParent(), true);
}
val.AddComponent<BombRunner>().mass = mass;
}
private void Update()
{
//IL_019a: Unknown result type (might be due to invalid IL or missing references)
//IL_01a5: Unknown result type (might be due to invalid IL or missing references)
if (!placed)
{
if (Bomb.Done)
{
if (Bomb.State != Bomb.Status.Found || (Object)(object)Bomb.Template == (Object)null)
{
SunChasePlugin.GiveBack(mass);
Object.Destroy((Object)(object)((Component)this).gameObject);
}
else
{
placed = true;
placedAt = Time.time;
Place();
}
}
return;
}
if ((Object)(object)sun != (Object)null && (Object)(object)((Component)this).transform.parent != (Object)null && (Object)(object)sun.parent != (Object)(object)((Component)this).transform.parent)
{
sun.SetParent(((Component)this).transform.parent, true);
}
PlaceMass();
SetSpeed();
if (!(fxLogAt > 0f) || !(Time.time - placedAt > fxLogAt) || !((Object)(object)sun != (Object)null))
{
return;
}
fxLogAt = -1f;
ENT_Player playerObject = ENT_Player.playerObject;
foreach (FX_Zone item in ((Component)this).GetComponentsInChildren<FX_Zone>(true).Concat(((Component)sun).GetComponentsInChildren<FX_Zone>(true)).Distinct())
{
SunChasePlugin.Log.LogInfo((object)($"Bomb FX: {((Object)item).name} blend {item.blend:0.00}, range {item.minRange}-{item.maxRange}, active {((Behaviour)item).isActiveAndEnabled}, " + (((Object)(object)playerObject != (Object)null) ? (Vector3.Distance(((Component)playerObject).transform.position, ((Component)item).transform.position).ToString("0") + " m from you") : "")));
}
}
private void SetSpeed()
{
ENT_Player playerObject = ENT_Player.playerObject;
if (!((Object)(object)kb == (Object)null) && !((Object)(object)playerObject == (Object)null))
{
string text = SunChasePlugin.Normalize(SunChasePlugin.SpeedMode.Value.Split(' ')) ?? "mass_logic";
float result;
float num = (text.StartsWith("player ") ? PlayerSpeed(playerObject, text.Substring(7)) : ((text == "mass_logic") ? MassLogic(playerObject) : ((!float.TryParse(text, NumberStyles.Float, CultureInfo.InvariantCulture, out result)) ? vanillaSpeed : result)));
kb.growSpeed = num;
CurrentSpeed = num;
}
}
private float RealGap(ENT_Player p)
{
//IL_0006: 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)
return Mathf.Max(Vector3.Distance(((Component)p).transform.position, ((Component)kb).transform.position) - Scale.Invoke(kb), 0f);
}
private float VirtualGap(ENT_Player p)
{
//IL_0006: 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)
return Mathf.Max(((Component)p).transform.position.y - (((Component)kb).transform.position.y + virtualRise), 0f);
}
private float Gap(ENT_Player p)
{
if (!caughtUp)
{
return VirtualGap(p);
}
return RealGap(p);
}
private void PlaceMass()
{
//IL_0094: Unknown result type (might be due to invalid IL or missing references)
//IL_0099: Unknown result type (might be due to invalid IL or missing references)
//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
//IL_0073: Unknown result type (might be due to invalid IL or missing references)
//IL_0078: Unknown result type (might be due to invalid IL or missing references)
//IL_0082: Unknown result type (might be due to invalid IL or missing references)
//IL_0087: Unknown result type (might be due to invalid IL or missing references)
if (!((Object)(object)mass == (Object)null) && !((Object)(object)sun == (Object)null))
{
ENT_Player playerObject = ENT_Player.playerObject;
bool flag = (Object)(object)kb != (Object)null && (Object)(object)playerObject != (Object)null && SunChasePlugin.Normalize(SunChasePlugin.SpeedMode.Value.Split(' ')) == "mass_logic";
((Component)mass).transform.position = (flag ? (((Component)playerObject).transform.position - Vector3.up * Gap(playerObject)) : (sun.position - Vector3.up * 100000f));
}
}
private float MassLogic(ENT_Player p)
{
float num = Gap(p);
float num2 = RealGap(p);
if ((Object)(object)mass == (Object)null)
{
return vanillaSpeed * Mathf.Max(1f, num * 0.07f);
}
if (!MassActive.Invoke(mass))
{
return 0f;
}
if ((Object)(object)CL_GameManager.gMan != (Object)null && CL_GameManager.gMan.isPaused)
{
return 0f;
}
if (!massStarted && (!mass.usePlayerStartHeight || CL_GameManager.GetPlayerTravelDistance() > mass.playerStartHeight))
{
massStarted = true;
}
if (!massStarted)
{
return 0f;
}
float num3 = 1f;
float num4 = 1f;
if ((Object)(object)CL_GameManager.gamemode != (Object)null)
{
num3 = CL_GameManager.gamemode.gooSpeedIncreaseMult;
num4 = CL_GameManager.gamemode.gooSpeedMult;
}
if (CL_GameManager.IsHardmode())
{
num4 *= 2f;
}
float num5 = MassSpeedMult.Invoke(mass) * num4 * MassFrameMult.Invoke(mass);
EntityBuff curBuffs = ((GameEntity)p).curBuffs;
if (curBuffs != null)
{
num5 = num5 / (1f + curBuffs.GetBuff("massResist")) * (1f + curBuffs.GetBuff("massSpeedMult")) / (1f + curBuffs.GetBuff("massSlow"));
}
if (WorldLoader.initialized && WorldLoader.isLoaded && WorldLoader.instance.GetCurrentLevel() != null)
{
M_Level level = WorldLoader.instance.GetCurrentLevel().GetLevel();
num5 *= level.massSpeedMult;
if ((Object)(object)level.subRegion != (Object)null)
{
num5 *= level.subRegion.massSpeedMult;
}
}
float num6 = (MassRubberband.Invoke(mass) ? (num * 0.07f * mass.rubberbandMult) : 1f);
float num7 = Mathf.Max(mass.speed * num6, mass.speed) * num5;
if (num > 300f)
{
num7 *= 4f;
}
if (CL_GameManager.GetPlayerTravelDistance() > mass.playerEaseHeight)
{
float num8 = mass.maxSpeed;
float num9 = 1f;
if ((Object)(object)CL_GameManager.GetBaseGamemode() != (Object)null && CL_GameManager.GetBaseGamemode().HasTag("endless"))
{
float playerBestTravelDistance = CL_GameManager.gMan.GetPlayerBestTravelDistance();
if (playerBestTravelDistance > 10000f)
{
num8 = mass.maxSpeed * 100f;
num9 = 5f;
}
else if (playerBestTravelDistance > 5000f)
{
num8 = mass.maxSpeed * 1.5f;
num9 = 1.3f;
}
}
if (mass.speed < num8)
{
DEN_DeathFloor obj = mass;
obj.speed += Time.deltaTime * mass.speedIncreaseRate * MassRampMult.Invoke(mass) * num3 * ((num5 < 0.5f) ? num5 : 1f) * num9;
}
}
if (!float.IsFinite(num7))
{
num7 = 0f;
}
if (!caughtUp)
{
virtualRise += num7 * Time.deltaTime;
if (!(Scale.Invoke(kb) > 0.01f) || !(num2 <= num + 0.5f))
{
return Mathf.Max(num7, 0f) + Mathf.Max(num2 - num, 0f) * 1.5f;
}
caughtUp = true;
SunChasePlugin.Log.LogInfo((object)$"mass_logic: sun caught up with where the mass would be ({num:0.0} m below you)");
}
return Mathf.Max(num7, 0f);
}
private float PlayerSpeed(ENT_Player p, string how)
{
float num = PlayerSpeedMult.Invoke(p);
EntityBuff curBuffs = ((GameEntity)p).curBuffs;
float num2 = ((curBuffs == null) ? 1f : ((curBuffs.GetBuff("addSpeed") + 1f + curBuffs.GetBuff("addGroundedSpeed")) / (1f + curBuffs.GetBuff("addSlow")) / (1f + curBuffs.GetBuff("divideSpeed"))));
float num3 = ((how == "run") ? (p.sprintSpeed * num) : ((how == "crouch") ? (p.crouchSpeed * num) : p.speed)) * num * Mathf.Max(num2, 0f) * 0.15f;
float num4 = p.dragCoefficient * TempFriction.Invoke(p) * 15f * (1f + ((curBuffs != null) ? curBuffs.GetBuff("addDrag") : 0f));
float num5 = ((num4 > 0f) ? (Mathf.Sqrt(num3 / num4) * 175f) : vanillaSpeed);
if (!float.IsFinite(num5) || num5 < 0.3f || num5 > 40f)
{
if (loggedRun != -2f)
{
loggedRun = -2f;
SunChasePlugin.Log.LogWarning((object)$"Sun player speed: {how} worked out as {num5:0.00} m/s, not believable; using the Rift's {vanillaSpeed} m/s");
}
return vanillaSpeed;
}
if (Mathf.Abs(num5 - loggedRun) > 0.05f)
{
loggedRun = num5;
SunChasePlugin.Log.LogInfo((object)$"Sun player speed: your {how} = {num5:0.00} m/s");
}
return num5;
}
private void Place()
{
//IL_00e5: Unknown result type (might be due to invalid IL or missing references)
//IL_00f0: Unknown result type (might be due to invalid IL or missing references)
//IL_00fb: Unknown result type (might be due to invalid IL or missing references)
//IL_0100: Unknown result type (might be due to invalid IL or missing references)
//IL_0105: Unknown result type (might be due to invalid IL or missing references)
//IL_024b: Unknown result type (might be due to invalid IL or missing references)
GameObject val = Object.Instantiate<GameObject>(Bomb.Template, ((Component)this).transform);
sun = Bomb.Follow(val.transform, Bomb.SunPath);
kb = ((Component)sun).GetComponent<ENV_KillBubble>();
if ((Object)(object)kb != (Object)null)
{
vanillaSpeed = kb.growSpeed;
}
if ((Object)(object)mass != (Object)null)
{
SunChasePlugin.Log.LogInfo((object)$"Mass numbers for mass_logic: speed {mass.speed}, max {mass.maxSpeed}, ramp {mass.speedIncreaseRate}/s after {mass.playerEaseHeight} m, catch-up x{mass.rubberbandMult}");
}
Transform transform = val.transform;
transform.position += ((Component)this).transform.position - sun.position;
bool flag = false;
if (Bomb.ButtonPath != null)
{
Component component = ((Component)Bomb.Follow(val.transform, Bomb.ButtonPath)).GetComponent(Bomb.ButtonType);
UnityEventBase val2 = (((Object)(object)component != (Object)null) ? Bomb.ButtonEvent.Get(component) : null);
MethodInfo methodInfo = ((object)val2)?.GetType().GetMethods().FirstOrDefault((MethodInfo m) => m.Name == "Invoke");
if (methodInfo != null)
{
object[] parameters = (from p in methodInfo.GetParameters()
select (!p.ParameterType.IsValueType) ? null : Activator.CreateInstance(p.ParameterType)).ToArray();
try
{
methodInfo.Invoke(val2, parameters);
flag = true;
}
catch (Exception ex)
{
SunChasePlugin.Log.LogWarning((object)("Bomb press: " + (ex.InnerException?.Message ?? ex.Message)));
}
}
}
if (!flag && Bomb.SequencePath != null)
{
UT_Timer component2 = ((Component)Bomb.Follow(val.transform, Bomb.SequencePath)).GetComponent<UT_Timer>();
if ((Object)(object)component2 != (Object)null)
{
component2.Play(false);
flag = true;
}
}
SunChasePlugin.Log.LogInfo((object)($"Bomb placed at {((Component)this).transform.position}, " + (flag ? "pressed" : "NOT pressed (no button or sequence found)")));
}
}
}