using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text.Json;
using BoneLib;
using BoneLib.BoneMenu;
using BoneLib.Notifications;
using HarmonyLib;
using Il2CppSLZ.Marrow;
using MelonLoader;
using MelonLoader.Preferences;
using MelonLoader.Utils;
using Microsoft.CodeAnalysis;
using SpawnMaster;
using UnityEngine;
using UnityEngine.SceneManagement;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: MelonInfo(typeof(MainMod), "SpawnMaster", "1.0.0", "dimastv", null)]
[assembly: MelonGame("Stress Level Zero", "BONELAB")]
[assembly: MelonOptionalDependencies(new string[] { "BoneLib" })]
[assembly: MelonColor(255, 50, 180, 230)]
[assembly: MelonAuthorColor(255, 100, 220, 255)]
[assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")]
[assembly: AssemblyCompany("SpawnMaster")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("SpawnMaster")]
[assembly: AssemblyTitle("SpawnMaster")]
[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.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
internal sealed class NullableAttribute : Attribute
{
public readonly byte[] NullableFlags;
public NullableAttribute(byte P_0)
{
NullableFlags = new byte[1] { P_0 };
}
public NullableAttribute(byte[] P_0)
{
NullableFlags = P_0;
}
}
[CompilerGenerated]
[Embedded]
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
internal sealed class NullableContextAttribute : Attribute
{
public readonly byte Flag;
public NullableContextAttribute(byte P_0)
{
Flag = P_0;
}
}
[CompilerGenerated]
[Embedded]
[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
internal sealed class RefSafetyRulesAttribute : Attribute
{
public readonly int Version;
public RefSafetyRulesAttribute(int P_0)
{
Version = P_0;
}
}
}
namespace SpawnMaster
{
internal static class BoneMenuIntegration
{
private static Page? _mainPage;
private static Page? _infoPage;
[MethodImpl(MethodImplOptions.NoInlining)]
internal static void SetupMenu()
{
//IL_0019: 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_0072: 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_00e4: Unknown result type (might be due to invalid IL or missing references)
//IL_0118: Unknown result type (might be due to invalid IL or missing references)
//IL_015b: Unknown result type (might be due to invalid IL or missing references)
//IL_018f: Unknown result type (might be due to invalid IL or missing references)
_mainPage = Page.Root.CreatePage("Spawn Master", new Color(0.2f, 0.8f, 1f), 0, true);
_mainPage.CreateBool("Mod Enabled", Color.white, ModConfig.Enabled.Value, (Action<bool>)delegate(bool val)
{
ModConfig.Enabled.Value = val;
ModConfig.PrefCategory.SaveToFile(true);
});
_mainPage.CreateBool("Spawn at Death Location", Color.yellow, ModConfig.SpawnAtDeathLocation.Value, (Action<bool>)delegate(bool val)
{
ModConfig.SpawnAtDeathLocation.Value = val;
ModConfig.PrefCategory.SaveToFile(true);
if (val)
{
NotificationHelper.ShowSuccess("Spawn Master", "Spawn at death location: ENABLED");
}
else
{
NotificationHelper.Show("Spawn Master", "Spawn at death location: DISABLED", (NotificationType)0);
}
RefreshInfoPage();
});
_mainPage.CreateFunction("Set Spawn Point Here", Color.green, (Action)delegate
{
SpawnManager.SetSpawnAtCurrentPlayerLocation();
RefreshInfoPage();
});
_mainPage.CreateFunction("Teleport to Spawn Point", Color.cyan, (Action)delegate
{
SpawnManager.TeleportToCurrentSpawnPoint();
});
_mainPage.CreateFunction("Clear Custom Spawn", Color.red, (Action)delegate
{
SpawnManager.ClearCustomSpawnForCurrentLevel();
RefreshInfoPage();
});
_mainPage.CreateFunction("Teleport to Last Death", new Color(1f, 0.4f, 0.8f), (Action)delegate
{
SpawnManager.TeleportToLastDeathLocation();
});
_infoPage = _mainPage.CreatePage("Settings & Info", Color.white, 0, true);
BuildInfoPage();
}
[MethodImpl(MethodImplOptions.NoInlining)]
public static void RefreshInfoPage()
{
if (_infoPage != null)
{
_infoPage.RemoveAll();
BuildInfoPage();
}
}
[MethodImpl(MethodImplOptions.NoInlining)]
private static void BuildInfoPage()
{
//IL_0012: Unknown result type (might be due to invalid IL or missing references)
//IL_0046: Unknown result type (might be due to invalid IL or missing references)
//IL_0084: Unknown result type (might be due to invalid IL or missing references)
//IL_00c2: Unknown result type (might be due to invalid IL or missing references)
//IL_0100: Unknown result type (might be due to invalid IL or missing references)
//IL_013e: Unknown result type (might be due to invalid IL or missing references)
//IL_0191: Unknown result type (might be due to invalid IL or missing references)
//IL_0289: Unknown result type (might be due to invalid IL or missing references)
//IL_0253: Unknown result type (might be due to invalid IL or missing references)
//IL_039d: 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_02e4: Unknown result type (might be due to invalid IL or missing references)
//IL_0303: Unknown result type (might be due to invalid IL or missing references)
//IL_0322: Unknown result type (might be due to invalid IL or missing references)
//IL_0368: Unknown result type (might be due to invalid IL or missing references)
if (_infoPage != null)
{
_infoPage.CreateFunction("Refresh Info", Color.green, (Action)delegate
{
RefreshInfoPage();
});
_infoPage.CreateBool("Spawn On Level Load", Color.white, ModConfig.SpawnAtCustomPointOnLoad.Value, (Action<bool>)delegate(bool val)
{
ModConfig.SpawnAtCustomPointOnLoad.Value = val;
ModConfig.PrefCategory.SaveToFile(true);
});
_infoPage.CreateBool("No Level Reload on Death", Color.white, ModConfig.PreventLevelReloadOnDeath.Value, (Action<bool>)delegate(bool val)
{
ModConfig.PreventLevelReloadOnDeath.Value = val;
ModConfig.PrefCategory.SaveToFile(true);
});
_infoPage.CreateBool("Prevent Void Loop", Color.white, ModConfig.PreventVoidDeathLoop.Value, (Action<bool>)delegate(bool val)
{
ModConfig.PreventVoidDeathLoop.Value = val;
ModConfig.PrefCategory.SaveToFile(true);
});
_infoPage.CreateBool("Show Notifications", Color.white, ModConfig.ShowNotifications.Value, (Action<bool>)delegate(bool val)
{
ModConfig.ShowNotifications.Value = val;
ModConfig.PrefCategory.SaveToFile(true);
});
_infoPage.CreateFunction("Clear Last Death Position", Color.red, (Action)delegate
{
SpawnManager.ClearLastDeathPosition();
RefreshInfoPage();
});
string text = ((!string.IsNullOrEmpty(SpawnManager.CurrentLevelTitle)) ? SpawnManager.CurrentLevelTitle : "(None)");
_infoPage.CreateFunction("Map: " + text, Color.gray, (Action)delegate
{
});
SpawnPointData customSpawn = ModConfig.GetCustomSpawn(SpawnManager.CurrentLevelKey);
if (customSpawn != null)
{
string text2 = $"({customSpawn.X:F1}, {customSpawn.Y:F1}, {customSpawn.Z:F1})";
_infoPage.CreateFunction("Custom Spawn: " + text2, Color.cyan, (Action)delegate
{
});
}
else
{
_infoPage.CreateFunction("Custom Spawn: (Default Map Spawn)", Color.gray, (Action)delegate
{
});
}
if (SpawnManager.HasDeathPosition)
{
Vector3 value = SpawnManager.LastDeathPosition.Value;
string text3 = $"({value.x:F1}, {value.y:F1}, {value.z:F1})";
_infoPage.CreateFunction("Last Death: " + text3, new Color(1f, 0.4f, 0.8f), (Action)delegate
{
});
}
else
{
_infoPage.CreateFunction("Last Death: (None)", Color.gray, (Action)delegate
{
});
}
}
}
}
public class MainMod : MelonMod
{
public override void OnInitializeMelon()
{
ModConfig.Initialize();
MelonLogger.Msg("SpawnMaster initialized successfully!");
}
public override void OnLateInitializeMelon()
{
TryInitBoneLib();
}
public override void OnSceneWasLoaded(int buildIndex, string sceneName)
{
SpawnManager.OnSceneLoadedDirect(sceneName);
BoneMenuIntegration.RefreshInfoPage();
}
private void TryInitBoneLib()
{
try
{
if (AppDomain.CurrentDomain.GetAssemblies().Any((Assembly a) => a.GetName().Name == "BoneLib"))
{
HookBoneLibEvents();
BoneMenuIntegration.SetupMenu();
MelonLogger.Msg("BoneLib integration & BoneMenu initialized successfully!");
}
else
{
MelonLogger.Warning("BoneLib not detected. Running without BoneMenu.");
}
}
catch (Exception ex)
{
MelonLogger.Warning("BoneLib integration failed to load: " + ex.Message);
}
}
private void HookBoneLibEvents()
{
Hooking.OnLevelLoaded += delegate(LevelInfo levelInfo)
{
//IL_0000: Unknown result type (might be due to invalid IL or missing references)
try
{
SpawnManager.OnLevelLoaded(levelInfo);
BoneMenuIntegration.RefreshInfoPage();
}
catch (Exception ex)
{
MelonLogger.Warning("Error on LevelLoaded hook: " + ex.Message);
}
};
Hooking.OnPlayerDeath += delegate(RigManager rm)
{
try
{
if (ModConfig.Enabled.Value)
{
SpawnManager.RecordDeath(rm);
BoneMenuIntegration.RefreshInfoPage();
}
}
catch (Exception ex)
{
MelonLogger.Warning("Error on Hooking.OnPlayerDeath: " + ex.Message);
}
};
Hooking.OnPlayerResurrected += delegate
{
try
{
BoneMenuIntegration.RefreshInfoPage();
}
catch (Exception ex)
{
MelonLogger.Warning("Error on Hooking.OnPlayerResurrected: " + ex.Message);
}
};
}
}
public static class ModConfig
{
private static readonly string FolderPath = Path.Combine(MelonEnvironment.UserDataDirectory, "SpawnMaster");
private static readonly string SpawnsFilePath = Path.Combine(FolderPath, "saved_spawns.json");
private static readonly Dictionary<string, SpawnPointData> _savedSpawns = new Dictionary<string, SpawnPointData>(StringComparer.OrdinalIgnoreCase);
private static readonly object _lock = new object();
public static MelonPreferences_Category PrefCategory { get; private set; } = null;
public static MelonPreferences_Entry<bool> Enabled { get; private set; } = null;
public static MelonPreferences_Entry<bool> SpawnAtDeathLocation { get; private set; } = null;
public static MelonPreferences_Entry<bool> SpawnAtCustomPointOnLoad { get; private set; } = null;
public static MelonPreferences_Entry<bool> PreventLevelReloadOnDeath { get; private set; } = null;
public static MelonPreferences_Entry<bool> PreventVoidDeathLoop { get; private set; } = null;
public static MelonPreferences_Entry<float> SafetyElevationOffset { get; private set; } = null;
public static MelonPreferences_Entry<bool> ShowNotifications { get; private set; } = null;
public static void Initialize()
{
PrefCategory = MelonPreferences.CreateCategory("SpawnMaster", "Spawn Master");
Enabled = PrefCategory.CreateEntry<bool>("Enabled", true, "Mod Enabled", "Master toggle for SpawnMaster mod", false, false, (ValueValidator)null, (string)null);
SpawnAtDeathLocation = PrefCategory.CreateEntry<bool>("SpawnAtDeathLocation", true, "Spawn At Death Location", "When enabled, player respawns directly at the place where they died", false, false, (ValueValidator)null, (string)null);
SpawnAtCustomPointOnLoad = PrefCategory.CreateEntry<bool>("SpawnAtCustomPointOnLoad", true, "Spawn On Level Load", "Automatically spawn at custom spawn point when loading into the level", false, false, (ValueValidator)null, (string)null);
PreventLevelReloadOnDeath = PrefCategory.CreateEntry<bool>("PreventLevelReloadOnDeath", true, "Prevent Level Reload On Death", "Prevent reloading the entire level on death, respawning seamlessly in place", false, false, (ValueValidator)null, (string)null);
PreventVoidDeathLoop = PrefCategory.CreateEntry<bool>("PreventVoidDeathLoop", true, "Prevent Void Death Loop", "If dying repeatedly below void thresholds, safely fall back to spawn point", false, false, (ValueValidator)null, (string)null);
SafetyElevationOffset = PrefCategory.CreateEntry<float>("SafetyElevationOffset", 0.15f, "Safety Elevation Offset", "Height offset above ground to prevent feet clipping into floor collisions", false, false, (ValueValidator)null, (string)null);
ShowNotifications = PrefCategory.CreateEntry<bool>("ShowNotifications", true, "Show Notifications", "Display VR notifications when setting spawn points or respawning", false, false, (ValueValidator)null, (string)null);
LoadSavedSpawns();
}
public static void LoadSavedSpawns()
{
lock (_lock)
{
_savedSpawns.Clear();
try
{
if (!Directory.Exists(FolderPath))
{
Directory.CreateDirectory(FolderPath);
}
if (!File.Exists(SpawnsFilePath))
{
return;
}
List<SpawnPointData> list = JsonSerializer.Deserialize<List<SpawnPointData>>(File.ReadAllText(SpawnsFilePath));
if (list != null)
{
foreach (SpawnPointData item in list)
{
if (!string.IsNullOrEmpty(item.LevelKey))
{
_savedSpawns[item.LevelKey] = item;
}
}
}
MelonLogger.Msg($"Loaded {_savedSpawns.Count} custom spawn point(s) from disk.");
}
catch (Exception ex)
{
MelonLogger.Warning("Failed to load saved spawns: " + ex.Message);
}
}
}
public static void SaveToFile()
{
lock (_lock)
{
try
{
if (!Directory.Exists(FolderPath))
{
Directory.CreateDirectory(FolderPath);
}
List<SpawnPointData> value = new List<SpawnPointData>(_savedSpawns.Values);
JsonSerializerOptions options = new JsonSerializerOptions
{
WriteIndented = true
};
string contents = JsonSerializer.Serialize(value, options);
File.WriteAllText(SpawnsFilePath, contents);
}
catch (Exception ex)
{
MelonLogger.Warning("Failed to save spawn points to file: " + ex.Message);
}
}
}
public static bool HasCustomSpawn(string levelKey)
{
if (string.IsNullOrEmpty(levelKey))
{
return false;
}
lock (_lock)
{
return _savedSpawns.ContainsKey(levelKey);
}
}
public static SpawnPointData? GetCustomSpawn(string levelKey)
{
if (string.IsNullOrEmpty(levelKey))
{
return null;
}
lock (_lock)
{
SpawnPointData value;
return _savedSpawns.TryGetValue(levelKey, out value) ? value : null;
}
}
public static void SetCustomSpawn(string levelKey, Vector3 position, Vector3 forward, string title)
{
//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)
if (string.IsNullOrEmpty(levelKey))
{
return;
}
lock (_lock)
{
_savedSpawns[levelKey] = new SpawnPointData(position, forward, levelKey, title);
SaveToFile();
}
}
public static bool RemoveCustomSpawn(string levelKey)
{
if (string.IsNullOrEmpty(levelKey))
{
return false;
}
lock (_lock)
{
bool num = _savedSpawns.Remove(levelKey);
if (num)
{
SaveToFile();
}
return num;
}
}
}
public static class NotificationHelper
{
public static void Show(string title, string message, NotificationType type = (NotificationType)0, float duration = 2.5f)
{
//IL_000e: Unknown result type (might be due to invalid IL or missing references)
//IL_0013: Unknown result type (might be due to invalid IL or missing references)
//IL_0015: Unknown result type (might be due to invalid IL or missing references)
//IL_001b: Unknown result type (might be due to invalid IL or missing references)
//IL_0020: Unknown result type (might be due to invalid IL or missing references)
//IL_0025: Unknown result type (might be due to invalid IL or missing references)
//IL_0027: Unknown result type (might be due to invalid IL or missing references)
//IL_002d: Unknown result type (might be due to invalid IL or missing references)
//IL_0032: Unknown result type (might be due to invalid IL or missing references)
//IL_0037: Unknown result type (might be due to invalid IL or missing references)
//IL_0038: 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_003e: Unknown result type (might be due to invalid IL or missing references)
//IL_0045: Unknown result type (might be due to invalid IL or missing references)
//IL_0051: Expected O, but got Unknown
if (!ModConfig.ShowNotifications.Value)
{
return;
}
try
{
Notifier.Send(new Notification
{
Title = new NotificationText(title, Color.cyan, false),
Message = new NotificationText(message, Color.white, false),
Type = type,
PopupLength = duration,
ShowTitleOnPopup = true
});
}
catch (Exception ex)
{
MelonLogger.Warning("Could not send BoneLib notification: " + ex.Message);
}
}
public static void ShowSuccess(string title, string message, float duration = 2.5f)
{
Show(title, message, (NotificationType)3, duration);
}
public static void ShowWarning(string title, string message, float duration = 3f)
{
Show(title, message, (NotificationType)1, duration);
}
}
[Serializable]
public class SpawnPointData
{
public float X { get; set; }
public float Y { get; set; }
public float Z { get; set; }
public float FwdX { get; set; }
public float FwdY { get; set; }
public float FwdZ { get; set; }
public string LevelKey { get; set; } = string.Empty;
public string LevelTitle { get; set; } = string.Empty;
public string SavedAt { get; set; } = string.Empty;
public SpawnPointData()
{
}
public SpawnPointData(Vector3 position, Vector3 forward, string levelKey, string levelTitle)
{
//IL_0028: 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_0040: 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_0058: 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)
X = position.x;
Y = position.y;
Z = position.z;
FwdX = forward.x;
FwdY = forward.y;
FwdZ = forward.z;
LevelKey = levelKey;
LevelTitle = levelTitle;
SavedAt = DateTime.UtcNow.ToString("o");
}
public Vector3 GetPosition()
{
//IL_0012: Unknown result type (might be due to invalid IL or missing references)
return new Vector3(X, Y, Z);
}
public Vector3 GetForward()
{
//IL_002f: Unknown result type (might be due to invalid IL or missing references)
//IL_0027: Unknown result type (might be due to invalid IL or missing references)
Vector3 val = default(Vector3);
((Vector3)(ref val))..ctor(FwdX, FwdY, FwdZ);
if (!(((Vector3)(ref val)).sqrMagnitude > 0.001f))
{
return Vector3.forward;
}
return ((Vector3)(ref val)).normalized;
}
}
public static class SpawnManager
{
private static float _lastDeathTime = -999f;
private static int _quickDeathCount = 0;
private const float VoidKillHeightThreshold = -120f;
private const float QuickDeathThresholdSeconds = 2f;
public static string CurrentLevelKey { get; private set; } = string.Empty;
public static string CurrentLevelTitle { get; private set; } = string.Empty;
public static Vector3? LastDeathPosition { get; private set; }
public static Vector3? LastDeathForward { get; private set; }
public static bool HasDeathPosition => LastDeathPosition.HasValue;
public static void OnLevelLoaded(LevelInfo levelInfo)
{
//IL_0000: Unknown result type (might be due to invalid IL or missing references)
//IL_001c: Unknown result type (might be due to invalid IL or missing references)
//IL_000d: Unknown result type (might be due to invalid IL or missing references)
//IL_0012: Unknown result type (might be due to invalid IL or missing references)
//IL_0027: Unknown result type (might be due to invalid IL or missing references)
//IL_0043: 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)
Scene activeScene;
string currentLevelKey;
if (string.IsNullOrEmpty(levelInfo.barcode))
{
activeScene = SceneManager.GetActiveScene();
currentLevelKey = ((Scene)(ref activeScene)).name;
}
else
{
currentLevelKey = levelInfo.barcode;
}
CurrentLevelKey = currentLevelKey;
string currentLevelTitle;
if (string.IsNullOrEmpty(levelInfo.title))
{
activeScene = SceneManager.GetActiveScene();
currentLevelTitle = ((Scene)(ref activeScene)).name;
}
else
{
currentLevelTitle = levelInfo.title;
}
CurrentLevelTitle = currentLevelTitle;
_quickDeathCount = 0;
_lastDeathTime = -999f;
MelonLogger.Msg($"[SpawnMaster] Level loaded: '{CurrentLevelTitle}' ({CurrentLevelKey})");
if (ModConfig.Enabled.Value && ModConfig.SpawnAtCustomPointOnLoad.Value && ModConfig.HasCustomSpawn(CurrentLevelKey))
{
MelonCoroutines.Start(CoDelayedLevelLoadSpawn());
}
}
public static void OnSceneLoadedDirect(string sceneName)
{
if (string.IsNullOrEmpty(CurrentLevelKey) || CurrentLevelKey == sceneName)
{
CurrentLevelKey = sceneName;
CurrentLevelTitle = sceneName;
}
}
public static void RecordDeath(RigManager? rm = null)
{
//IL_00cd: 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_0077: 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_00d3: Unknown result type (might be due to invalid IL or missing references)
//IL_00d8: Unknown result type (might be due to invalid IL or missing references)
//IL_00ab: 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_00ba: Unknown result type (might be due to invalid IL or missing references)
//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
//IL_00c4: Unknown result type (might be due to invalid IL or missing references)
//IL_017f: Unknown result type (might be due to invalid IL or missing references)
//IL_018a: Unknown result type (might be due to invalid IL or missing references)
//IL_01ad: 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)
//IL_01e9: 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_010a: Unknown result type (might be due to invalid IL or missing references)
//IL_010f: Unknown result type (might be due to invalid IL or missing references)
//IL_0114: Unknown result type (might be due to invalid IL or missing references)
//IL_0159: Unknown result type (might be due to invalid IL or missing references)
//IL_015e: Unknown result type (might be due to invalid IL or missing references)
//IL_0163: Unknown result type (might be due to invalid IL or missing references)
//IL_0168: Unknown result type (might be due to invalid IL or missing references)
//IL_0125: Unknown result type (might be due to invalid IL or missing references)
//IL_012a: Unknown result type (might be due to invalid IL or missing references)
//IL_0179: Unknown result type (might be due to invalid IL or missing references)
//IL_017e: Unknown result type (might be due to invalid IL or missing references)
if ((Object)(object)rm == (Object)null)
{
rm = Player.RigManager;
}
if ((Object)(object)rm == (Object)null)
{
return;
}
float realtimeSinceStartup = Time.realtimeSinceStartup;
if (realtimeSinceStartup - _lastDeathTime < 2f)
{
_quickDeathCount++;
}
else
{
_quickDeathCount = 1;
}
_lastDeathTime = realtimeSinceStartup;
Vector3 val = (((Object)(object)rm.physicsRig != (Object)null && (Object)(object)rm.physicsRig.feet != (Object)null) ? rm.physicsRig.feet.transform.position : ((!((Object)(object)rm.physicsRig != (Object)null) || !((Object)(object)((Rig)rm.physicsRig).m_pelvis != (Object)null)) ? ((Component)rm).transform.position : (((Rig)rm.physicsRig).m_pelvis.position - Vector3.up * 0.9f)));
Vector3 value = Vector3.forward;
if ((Object)(object)rm.physicsRig != (Object)null && (Object)(object)((Rig)rm.physicsRig).m_head != (Object)null)
{
Vector3 val2 = Vector3.ProjectOnPlane(((Rig)rm.physicsRig).m_head.forward, Vector3.up);
if (((Vector3)(ref val2)).sqrMagnitude > 0.01f)
{
value = ((Vector3)(ref val2)).normalized;
}
}
else if ((Object)(object)rm.physicsRig != (Object)null && (Object)(object)((Rig)rm.physicsRig).m_pelvis != (Object)null)
{
Vector3 val3 = Vector3.ProjectOnPlane(((Rig)rm.physicsRig).m_pelvis.forward, Vector3.up);
if (((Vector3)(ref val3)).sqrMagnitude > 0.01f)
{
value = ((Vector3)(ref val3)).normalized;
}
}
LastDeathPosition = val;
LastDeathForward = value;
MelonLogger.Msg($"[SpawnMaster] Death recorded at ({val.x:F2}, {val.y:F2}, {val.z:F2}). QuickDeathCount: {_quickDeathCount}");
}
public static bool HandleRespawn(Player_Health health)
{
//IL_0057: Unknown result type (might be due to invalid IL or missing references)
//IL_005c: Unknown result type (might be due to invalid IL or missing references)
//IL_005d: Unknown result type (might be due to invalid IL or missing references)
//IL_01f0: Unknown result type (might be due to invalid IL or missing references)
//IL_01f5: Unknown result type (might be due to invalid IL or missing references)
//IL_0204: Unknown result type (might be due to invalid IL or missing references)
//IL_0209: Unknown result type (might be due to invalid IL or missing references)
//IL_020e: Unknown result type (might be due to invalid IL or missing references)
//IL_0212: Unknown result type (might be due to invalid IL or missing references)
//IL_0217: Unknown result type (might be due to invalid IL or missing references)
//IL_021a: Unknown result type (might be due to invalid IL or missing references)
//IL_021c: Unknown result type (might be due to invalid IL or missing references)
//IL_0240: Unknown result type (might be due to invalid IL or missing references)
//IL_025f: Unknown result type (might be due to invalid IL or missing references)
//IL_027e: 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_00fc: Unknown result type (might be due to invalid IL or missing references)
//IL_010b: Unknown result type (might be due to invalid IL or missing references)
//IL_0110: Unknown result type (might be due to invalid IL or missing references)
//IL_0115: Unknown result type (might be due to invalid IL or missing references)
//IL_0130: Unknown result type (might be due to invalid IL or missing references)
//IL_0127: Unknown result type (might be due to invalid IL or missing references)
//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
//IL_0135: Unknown result type (might be due to invalid IL or missing references)
//IL_0138: Unknown result type (might be due to invalid IL or missing references)
//IL_013a: Unknown result type (might be due to invalid IL or missing references)
//IL_015e: Unknown result type (might be due to invalid IL or missing references)
//IL_017d: 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)
if (!ModConfig.Enabled.Value)
{
return false;
}
RigManager val = (((Object)(object)((Health)health)._rigManager != (Object)null) ? ((Health)health)._rigManager : Player.RigManager);
if ((Object)(object)val == (Object)null)
{
return false;
}
if (ModConfig.SpawnAtDeathLocation.Value && HasDeathPosition)
{
Vector3 value = LastDeathPosition.Value;
bool flag = value.y < -120f;
bool flag2 = _quickDeathCount >= 3;
if (ModConfig.PreventVoidDeathLoop.Value && (flag || flag2))
{
MelonLogger.Warning($"[SpawnMaster] Void death loop prevented (Y: {value.y:F1}, QuickDeaths: {_quickDeathCount}). Falling back to safe spawn.");
NotificationHelper.ShowWarning("Void Loop Prevented", "Teleporting to safe spawn point instead of the void.");
return TeleportToCustomOrDefaultSpawn(val);
}
Vector3 val2 = value + Vector3.up * ModConfig.SafetyElevationOffset.Value;
Vector3 forward = (Vector3)(((??)LastDeathForward) ?? Vector3.forward);
ExecuteTeleport(val, val2, forward);
NotificationHelper.ShowSuccess("Respawned", $"Respawned at death location ({val2.x:F1}, {val2.y:F1}, {val2.z:F1})");
return true;
}
if (ModConfig.HasCustomSpawn(CurrentLevelKey))
{
SpawnPointData customSpawn = ModConfig.GetCustomSpawn(CurrentLevelKey);
if (customSpawn != null)
{
Vector3 val3 = customSpawn.GetPosition() + Vector3.up * ModConfig.SafetyElevationOffset.Value;
Vector3 forward2 = customSpawn.GetForward();
ExecuteTeleport(val, val3, forward2);
NotificationHelper.ShowSuccess("Respawned", $"Respawned at custom spawn ({val3.x:F1}, {val3.y:F1}, {val3.z:F1})");
return true;
}
}
return false;
}
public static bool SetSpawnAtCurrentPlayerLocation()
{
//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
//IL_00b1: Unknown result type (might be due to invalid IL or missing references)
//IL_0056: 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_00b2: Unknown result type (might be due to invalid IL or missing references)
//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
//IL_008a: Unknown result type (might be due to invalid IL or missing references)
//IL_008f: Unknown result type (might be due to invalid IL or missing references)
//IL_0099: Unknown result type (might be due to invalid IL or missing references)
//IL_009e: 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_0117: Unknown result type (might be due to invalid IL or missing references)
//IL_011c: Unknown result type (might be due to invalid IL or missing references)
//IL_00e4: Unknown result type (might be due to invalid IL or missing references)
//IL_00e9: 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_00f3: 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_010a: Unknown result type (might be due to invalid IL or missing references)
//IL_0144: Unknown result type (might be due to invalid IL or missing references)
//IL_0145: Unknown result type (might be due to invalid IL or missing references)
//IL_014e: Unknown result type (might be due to invalid IL or missing references)
//IL_0155: Unknown result type (might be due to invalid IL or missing references)
//IL_0188: Unknown result type (might be due to invalid IL or missing references)
//IL_01a6: Unknown result type (might be due to invalid IL or missing references)
//IL_01c4: Unknown result type (might be due to invalid IL or missing references)
//IL_0209: Unknown result type (might be due to invalid IL or missing references)
//IL_0227: Unknown result type (might be due to invalid IL or missing references)
//IL_0245: Unknown result type (might be due to invalid IL or missing references)
RigManager rigManager = Player.RigManager;
if ((Object)(object)rigManager == (Object)null)
{
NotificationHelper.ShowWarning("Spawn Master", "Player rig not found!");
return false;
}
Vector3 val = (((Object)(object)rigManager.physicsRig != (Object)null && (Object)(object)rigManager.physicsRig.feet != (Object)null) ? rigManager.physicsRig.feet.transform.position : ((!((Object)(object)rigManager.physicsRig != (Object)null) || !((Object)(object)((Rig)rigManager.physicsRig).m_pelvis != (Object)null)) ? ((Component)rigManager).transform.position : (((Rig)rigManager.physicsRig).m_pelvis.position - Vector3.up * 0.9f)));
Vector3 val2 = Vector3.forward;
if ((Object)(object)rigManager.physicsRig != (Object)null && (Object)(object)((Rig)rigManager.physicsRig).m_head != (Object)null)
{
Vector3 val3 = Vector3.ProjectOnPlane(((Rig)rigManager.physicsRig).m_head.forward, Vector3.up);
if (((Vector3)(ref val3)).sqrMagnitude > 0.01f)
{
val2 = ((Vector3)(ref val3)).normalized;
}
}
string text;
if (string.IsNullOrEmpty(CurrentLevelKey))
{
Scene activeScene = SceneManager.GetActiveScene();
text = ((Scene)(ref activeScene)).name;
}
else
{
text = CurrentLevelKey;
}
string text2 = text;
string text3 = ((!string.IsNullOrEmpty(CurrentLevelTitle)) ? CurrentLevelTitle : text2);
ModConfig.SetCustomSpawn(text2, val, val2, text3);
rigManager.checkpointPosition = val;
rigManager.checkpointFwd = val2;
MelonLogger.Msg($"[SpawnMaster] Custom spawn point saved for '{text3}': ({val.x:F2}, {val.y:F2}, {val.z:F2})");
NotificationHelper.ShowSuccess("Spawn Point Set!", $"New spawn set at ({val.x:F1}, {val.y:F1}, {val.z:F1})");
return true;
}
public static bool ClearCustomSpawnForCurrentLevel()
{
//IL_000c: Unknown result type (might be due to invalid IL or missing references)
//IL_0011: Unknown result type (might be due to invalid IL or missing references)
string text;
if (string.IsNullOrEmpty(CurrentLevelKey))
{
Scene activeScene = SceneManager.GetActiveScene();
text = ((Scene)(ref activeScene)).name;
}
else
{
text = CurrentLevelKey;
}
string text2 = text;
bool num = ModConfig.RemoveCustomSpawn(text2);
if (num)
{
NotificationHelper.ShowWarning("Spawn Master", "Custom spawn point cleared. Reverted to default.");
MelonLogger.Msg("[SpawnMaster] Custom spawn cleared for '" + text2 + "'");
return num;
}
NotificationHelper.Show("Spawn Master", "No custom spawn point was set for this map.", (NotificationType)0);
return num;
}
public static bool TeleportToCurrentSpawnPoint()
{
//IL_0031: 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_0097: Unknown result type (might be due to invalid IL or missing references)
//IL_009d: Unknown result type (might be due to invalid IL or missing references)
//IL_004f: Unknown result type (might be due to invalid IL or missing references)
//IL_0054: Unknown result type (might be due to invalid IL or missing references)
//IL_0063: Unknown result type (might be due to invalid IL or missing references)
//IL_0068: Unknown result type (might be due to invalid IL or missing references)
//IL_006d: Unknown result type (might be due to invalid IL or missing references)
//IL_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_0077: 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)
RigManager rigManager = Player.RigManager;
if ((Object)(object)rigManager == (Object)null)
{
NotificationHelper.ShowWarning("Spawn Master", "Player rig not found!");
return false;
}
string levelKey;
if (string.IsNullOrEmpty(CurrentLevelKey))
{
Scene activeScene = SceneManager.GetActiveScene();
levelKey = ((Scene)(ref activeScene)).name;
}
else
{
levelKey = CurrentLevelKey;
}
SpawnPointData customSpawn = ModConfig.GetCustomSpawn(levelKey);
if (customSpawn != null)
{
Vector3 position = customSpawn.GetPosition() + Vector3.up * ModConfig.SafetyElevationOffset.Value;
Vector3 forward = customSpawn.GetForward();
ExecuteTeleport(rigManager, position, forward);
NotificationHelper.ShowSuccess("Teleported", "Teleported to custom spawn point!");
return true;
}
ExecuteTeleport(rigManager, rigManager.checkpointPosition, rigManager.checkpointFwd);
NotificationHelper.Show("Teleported", "Teleported to map checkpoint.", (NotificationType)0);
return true;
}
public static bool TeleportToLastDeathLocation()
{
//IL_004b: Unknown result type (might be due to invalid IL or missing references)
//IL_0050: Unknown result type (might be due to invalid IL or missing references)
//IL_005f: 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_0069: 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_0079: 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_0089: 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_00ad: Unknown result type (might be due to invalid IL or missing references)
//IL_00cb: Unknown result type (might be due to invalid IL or missing references)
//IL_00e9: Unknown result type (might be due to invalid IL or missing references)
RigManager rigManager = Player.RigManager;
if ((Object)(object)rigManager == (Object)null)
{
NotificationHelper.ShowWarning("Spawn Master", "Player rig not found!");
return false;
}
if (!HasDeathPosition)
{
NotificationHelper.Show("Spawn Master", "No death location recorded yet.", (NotificationType)0);
return false;
}
Vector3 val = LastDeathPosition.Value + Vector3.up * ModConfig.SafetyElevationOffset.Value;
Vector3 forward = (Vector3)(((??)LastDeathForward) ?? Vector3.forward);
ExecuteTeleport(rigManager, val, forward);
NotificationHelper.ShowSuccess("Teleported", $"Teleported to death location ({val.x:F1}, {val.y:F1}, {val.z:F1})");
return true;
}
public static void ClearLastDeathPosition()
{
LastDeathPosition = null;
LastDeathForward = null;
_quickDeathCount = 0;
NotificationHelper.Show("Spawn Master", "Cleared last death position.", (NotificationType)0);
}
private static bool TeleportToCustomOrDefaultSpawn(RigManager rm)
{
//IL_0049: Unknown result type (might be due to invalid IL or missing references)
//IL_004f: Unknown result type (might be due to invalid IL or missing references)
//IL_001c: Unknown result type (might be due to invalid IL or missing references)
//IL_0021: Unknown result type (might be due to invalid IL or missing references)
//IL_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_003b: Unknown result type (might be due to invalid IL or missing references)
if (ModConfig.HasCustomSpawn(CurrentLevelKey))
{
SpawnPointData customSpawn = ModConfig.GetCustomSpawn(CurrentLevelKey);
if (customSpawn != null)
{
ExecuteTeleport(rm, customSpawn.GetPosition() + Vector3.up * ModConfig.SafetyElevationOffset.Value, customSpawn.GetForward());
return true;
}
}
ExecuteTeleport(rm, rm.checkpointPosition, rm.checkpointFwd);
return true;
}
private static void ExecuteTeleport(RigManager rm, Vector3 position, Vector3 forward)
{
//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_0020: Unknown result type (might be due to invalid IL or missing references)
//IL_0027: Unknown result type (might be due to invalid IL or missing references)
//IL_000e: Unknown result type (might be due to invalid IL or missing references)
//IL_0013: Unknown result type (might be due to invalid IL or missing references)
//IL_0059: Unknown result type (might be due to invalid IL or missing references)
//IL_006e: Unknown result type (might be due to invalid IL or missing references)
//IL_0096: 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)
try
{
if (((Vector3)(ref forward)).sqrMagnitude < 0.01f)
{
forward = Vector3.forward;
}
rm.Teleport(position, forward, true);
rm.checkpointPosition = position;
rm.checkpointFwd = forward;
if ((Object)(object)rm.physicsRig != (Object)null)
{
if ((Object)(object)rm.physicsRig.rbFeet != (Object)null)
{
rm.physicsRig.rbFeet.velocity = Vector3.zero;
rm.physicsRig.rbFeet.angularVelocity = Vector3.zero;
}
if ((Object)(object)rm.physicsRig.rbKnee != (Object)null)
{
rm.physicsRig.rbKnee.velocity = Vector3.zero;
rm.physicsRig.rbKnee.angularVelocity = Vector3.zero;
}
}
}
catch (Exception value)
{
MelonLogger.Error($"[SpawnMaster] Error during teleport: {value}");
}
}
private static IEnumerator CoDelayedLevelLoadSpawn()
{
yield return (object)new WaitForSeconds(0.8f);
int attempts = 0;
while ((Object)(object)Player.RigManager == (Object)null && attempts < 20)
{
yield return (object)new WaitForSeconds(0.2f);
attempts++;
}
RigManager rigManager = Player.RigManager;
if ((Object)(object)rigManager != (Object)null && ModConfig.HasCustomSpawn(CurrentLevelKey))
{
SpawnPointData customSpawn = ModConfig.GetCustomSpawn(CurrentLevelKey);
if (customSpawn != null)
{
Vector3 val = customSpawn.GetPosition() + Vector3.up * ModConfig.SafetyElevationOffset.Value;
Vector3 forward = customSpawn.GetForward();
ExecuteTeleport(rigManager, val, forward);
NotificationHelper.Show("Spawn Master", "Spawned at custom level spawn point!", (NotificationType)0);
MelonLogger.Msg($"[SpawnMaster] Applied custom spawn on level load: {val}");
}
}
}
}
[HarmonyPatch(typeof(Player_Health), "Death")]
internal static class Patch_PlayerHealth_Death
{
[HarmonyPrefix]
public static void Prefix(Player_Health __instance)
{
try
{
if (ModConfig.Enabled.Value)
{
if (ModConfig.PreventLevelReloadOnDeath.Value)
{
__instance.reloadLevelOnDeath = false;
}
SpawnManager.RecordDeath(((Health)__instance)._rigManager);
}
}
catch (Exception value)
{
MelonLogger.Error($"[SpawnMaster] Error in Player_Health.Death prefix: {value}");
}
}
}
[HarmonyPatch(typeof(Player_Health), "TeleportToCheckpoint")]
internal static class Patch_PlayerHealth_TeleportToCheckpoint
{
[HarmonyPrefix]
public static bool Prefix(Player_Health __instance)
{
try
{
if (!ModConfig.Enabled.Value)
{
return true;
}
if (SpawnManager.HandleRespawn(__instance))
{
return false;
}
}
catch (Exception value)
{
MelonLogger.Error($"[SpawnMaster] Error in TeleportToCheckpoint prefix: {value}");
}
return true;
}
}
}