Decompiled source of easy checkpoints v0.0.1

silgsong_checkpoint-mod.dll

Decompiled 2 weeks ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using GlobalEnums;
using HarmonyLib;
using TeamCherry.SharedUtils;
using UnityEngine;
using UnityEngine.InputSystem;
using UnityEngine.InputSystem.Controls;
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("silgsong_checkpoint-mod")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+76311ddc742297d098e756f857f84c74f8d7a050")]
[assembly: AssemblyProduct("silgsong_checkpoint-mod")]
[assembly: AssemblyTitle("silgsong_checkpoint-mod")]
[assembly: AssemblyVersion("1.0.0.0")]
namespace silgsong_checkpoint_mod;

internal sealed class CheckpointHotkeys : MonoBehaviour
{
	private const float MessageSeconds = 2.5f;

	private const float FadeSeconds = 0.5f;

	private static ConfigEntry<KeyCode> hotKey;

	private string message;

	private float messageUntil;

	private GUIStyle messageStyle;

	private Texture2D background;

	public static void Bind(ConfigFile config)
	{
		hotKey = config.Bind<KeyCode>("Controls", "HotKey", (KeyCode)112, "Клавиша: нажать — поставить точку возрождения здесь, с Shift — удалить её.");
	}

	private void Update()
	{
		//IL_0000: Unknown result type (might be due to invalid IL or missing references)
		//IL_0031: Unknown result type (might be due to invalid IL or missing references)
		if (WasKeyPressed(EasyModeManager.HotKey))
		{
			bool flag = EasyModeManager.Toggle(HeroController.instance);
			ShowMessage(flag ? "Легкий режим: ВКЛ" : "Легкий режим: ВЫКЛ");
		}
		if (WasKeyPressed(hotKey.Value))
		{
			if (IsShiftHeld())
			{
				ClearCheckpoint();
			}
			else
			{
				SetCheckpointHere();
			}
		}
	}

	private void OnDestroy()
	{
		if ((Object)(object)background != (Object)null)
		{
			Object.Destroy((Object)(object)background);
		}
	}

	private void SetCheckpointHere()
	{
		//IL_001f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0025: Invalid comparison between Unknown and I4
		//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)
		GameManager instance = GameManager.instance;
		HeroController instance2 = HeroController.instance;
		if (!((Object)(object)instance != (Object)null) || !((Object)(object)instance2 != (Object)null) || (int)instance.GameState != 4 || instance2.cState.dead || string.IsNullOrEmpty(instance.GetSceneNameString()))
		{
			ShowMessage("Точку можно поставить только в обычной игре");
			return;
		}
		CustomCheckpoint.Set(instance.GetSceneNameString(), Vector2.op_Implicit(((Component)instance2).transform.position), instance2.cState.facingRight);
		ShowMessage("Точка возрождения поставлена здесь");
	}

	private void ClearCheckpoint()
	{
		if (!CustomCheckpoint.IsSet)
		{
			ShowMessage("Точка возрождения не задана");
			return;
		}
		CustomCheckpoint.Clear();
		ShowMessage("Точка возрождения удалена — возрождение как в ванилле");
	}

	private void ShowMessage(string text)
	{
		message = text;
		messageUntil = Time.unscaledTime + 2.5f;
	}

	private void OnGUI()
	{
		//IL_002f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0035: Expected O, but got Unknown
		//IL_003c: Unknown result type (might be due to invalid IL or missing references)
		//IL_008e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0093: Unknown result type (might be due to invalid IL or missing references)
		//IL_0098: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b5: 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)
		float num = messageUntil - Time.unscaledTime;
		if (!string.IsNullOrEmpty(message) && !(num <= 0f))
		{
			EnsureStyles();
			GUIContent val = new GUIContent(message);
			float num2 = Mathf.Min(messageStyle.CalcSize(val).x + 40f, (float)Screen.width - 40f);
			float num3 = messageStyle.CalcHeight(val, num2) + 20f;
			Rect val2 = new Rect(((float)Screen.width - num2) * 0.5f, (float)Screen.height * 0.1f, num2, num3);
			Color color = GUI.color;
			GUI.color = new Color(1f, 1f, 1f, Mathf.Clamp01(num / 0.5f));
			GUI.Label(val2, val, messageStyle);
			GUI.color = color;
		}
	}

	private void EnsureStyles()
	{
		//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)
		//IL_001e: Expected O, but got Unknown
		//IL_003a: Unknown result type (might be due to invalid IL or missing references)
		//IL_005a: 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_0085: Unknown result type (might be due to invalid IL or missing references)
		//IL_008c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0093: Unknown result type (might be due to invalid IL or missing references)
		//IL_009c: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a6: Expected O, but got Unknown
		//IL_00ab: Expected O, but got Unknown
		//IL_00cc: Unknown result type (might be due to invalid IL or missing references)
		if (messageStyle == null)
		{
			background = new Texture2D(1, 1)
			{
				hideFlags = (HideFlags)61
			};
			background.SetPixel(0, 0, new Color(0f, 0f, 0f, 0.75f));
			background.Apply();
			messageStyle = new GUIStyle(GUI.skin.label)
			{
				fontSize = Mathf.Clamp(Mathf.RoundToInt(18f * (float)Screen.height / 1080f), 16, 32),
				alignment = (TextAnchor)4,
				wordWrap = true,
				padding = new RectOffset(20, 20, 10, 10)
			};
			messageStyle.normal.background = background;
			messageStyle.normal.textColor = Color.white;
		}
	}

	private static bool IsShiftHeld()
	{
		try
		{
			Keyboard current = Keyboard.current;
			if (current != null)
			{
				return ((ButtonControl)current.leftShiftKey).isPressed || ((ButtonControl)current.rightShiftKey).isPressed;
			}
		}
		catch (Exception)
		{
		}
		try
		{
			return Input.GetKey((KeyCode)304) || Input.GetKey((KeyCode)303);
		}
		catch (Exception)
		{
			return false;
		}
	}

	private unsafe static bool WasKeyPressed(KeyCode key)
	{
		//IL_0020: Unknown result type (might be due to invalid IL or missing references)
		//IL_003d: 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)
		try
		{
			Keyboard current = Keyboard.current;
			if (current != null && Enum.TryParse<Key>(((object)(*(KeyCode*)(&key))/*cast due to .constrained prefix*/).ToString(), ignoreCase: true, out Key result) && (int)result != 0)
			{
				KeyControl val = current[result];
				if (val != null)
				{
					return ((ButtonControl)val).wasPressedThisFrame;
				}
			}
		}
		catch (Exception)
		{
		}
		try
		{
			return Input.GetKeyDown(key);
		}
		catch (Exception)
		{
			return false;
		}
	}
}
internal static class CustomCheckpoint
{
	public const string MarkerName = "S2E Custom Respawn Marker";

	private static ConfigEntry<string> scene;

	private static ConfigEntry<float> posX;

	private static ConfigEntry<float> posY;

	private static ConfigEntry<bool> facingRight;

	public static bool IsSet => !string.IsNullOrEmpty(scene.Value);

	public static string Scene => scene.Value;

	public static Vector2 Position => new Vector2(posX.Value, posY.Value);

	public static bool FacingRight => facingRight.Value;

	public static void Bind(ConfigFile config)
	{
		scene = config.Bind<string>("Checkpoint", "Scene", "", "Сцена пользовательской точки возрождения. Пусто — точка не задана, возрождение полностью ванильное.");
		posX = config.Bind<float>("Checkpoint", "X", 0f, "Координата X точки возрождения.");
		posY = config.Bind<float>("Checkpoint", "Y", 0f, "Координата Y точки возрождения.");
		facingRight = config.Bind<bool>("Checkpoint", "FacingRight", true, "В какую сторону смотрит герой после возрождения.");
	}

	public static void Set(string sceneName, Vector2 position, bool isFacingRight)
	{
		//IL_0010: 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_0041: 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)
		scene.Value = sceneName;
		posX.Value = position.x;
		posY.Value = position.y;
		facingRight.Value = isFacingRight;
		ModEntry.Log.LogInfo((object)$"Точка возрождения поставлена: {sceneName} ({position.x:0.##}, {position.y:0.##}).");
	}

	public static void Clear()
	{
		scene.Value = "";
		posX.Value = 0f;
		posY.Value = 0f;
		DestroyMarker();
		ModEntry.Log.LogInfo((object)"Точка возрождения удалена, возрождение снова ванильное.");
	}

	public static Transform GetOrCreateMarker(Vector2 position, bool isFacingRight)
	{
		//IL_0014: 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_004c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0057: Unknown result type (might be due to invalid IL or missing references)
		//IL_0028: Unknown result type (might be due to invalid IL or missing references)
		//IL_0032: Expected O, but got Unknown
		RespawnMarker val = FindMarker();
		if ((Object)(object)val == (Object)null)
		{
			val = new GameObject("S2E Custom Respawn Marker").AddComponent<RespawnMarker>();
		}
		if (val.customFadeDuration == null)
		{
			val.customFadeDuration = new OverrideFloat();
		}
		val.customWakeUp = false;
		val.respawnFacingRight = isFacingRight;
		((Component)val).transform.position = new Vector3(position.x, position.y, 0f);
		return ((Component)val).transform;
	}

	private static RespawnMarker FindMarker()
	{
		List<RespawnMarker> markers = RespawnMarker.Markers;
		if (markers == null)
		{
			return null;
		}
		foreach (RespawnMarker item in markers)
		{
			if ((Object)(object)item != (Object)null && ((Object)item).name == "S2E Custom Respawn Marker")
			{
				return item;
			}
		}
		return null;
	}

	private static void DestroyMarker()
	{
		RespawnMarker val = FindMarker();
		if ((Object)(object)val != (Object)null)
		{
			Object.Destroy((Object)(object)((Component)val).gameObject);
		}
	}
}
internal static class EasyModeManager
{
	private static ConfigEntry<KeyCode> hotKey;

	private static ConfigEntry<bool> isEnabledConfig;

	private static readonly Dictionary<HeroController, float> fractionalDamageMap = new Dictionary<HeroController, float>();

	private static bool isEnabled;

	public static KeyCode HotKey
	{
		get
		{
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			if (hotKey == null)
			{
				return (KeyCode)108;
			}
			return hotKey.Value;
		}
	}

	public static void Bind(ConfigFile config)
	{
		hotKey = config.Bind<KeyCode>("Controls", "EasyModeHotKey", (KeyCode)108, "Клавиша для переключения Легкого режима (Easy Mode).");
		isEnabledConfig = config.Bind<bool>("EasyMode", "Enabled", false, "Включен ли легкий режим по умолчанию.");
		isEnabled = isEnabledConfig.Value;
	}

	public static bool IsEnabled(HeroController hero = null)
	{
		return isEnabled;
	}

	public static bool Toggle(HeroController hero = null)
	{
		isEnabled = !isEnabled;
		if (isEnabledConfig != null)
		{
			isEnabledConfig.Value = isEnabled;
		}
		ResetFractionalDamage(hero);
		ModEntry.Log.LogInfo((object)("Легкий режим (Easy Mode) " + (isEnabled ? "ВКЛЮЧЕН" : "ВЫКЛЮЧЕН") + "."));
		return isEnabled;
	}

	public static int CalculateIncomingDamage(HeroController hero, int rawDamage)
	{
		if (rawDamage <= 0)
		{
			return 0;
		}
		float fractionalDamage = GetFractionalDamage(hero);
		float num = (float)rawDamage * 0.5f;
		float num2 = fractionalDamage + num;
		int num3 = Mathf.FloorToInt(num2);
		float num4 = num2 - (float)num3;
		SetFractionalDamage(hero, num4);
		ModEntry.Log.LogDebug((object)$"[EasyMode] Входящий урон: {rawDamage} -> Получено: {num3} (Дробный остаток: {num4:0.0})");
		return num3;
	}

	public static void ResetFractionalDamage(HeroController hero = null)
	{
		if ((Object)(object)hero != (Object)null)
		{
			fractionalDamageMap.Remove(hero);
		}
		else
		{
			fractionalDamageMap.Clear();
		}
	}

	public static bool IsHeroAttack(HitInstance hitInstance)
	{
		//IL_0009: 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_0024: 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_0054: 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_008d: Unknown result type (might be due to invalid IL or missing references)
		if (!isEnabled)
		{
			return false;
		}
		if (hitInstance.IsHeroDamage)
		{
			return true;
		}
		if ((Object)(object)hitInstance.Source != (Object)null)
		{
			if (hitInstance.Source.CompareTag("Player") || ((Component)hitInstance.Source.transform.root).CompareTag("Player"))
			{
				return true;
			}
			if ((Object)(object)hitInstance.Source.GetComponentInParent<HeroController>() != (Object)null)
			{
				return true;
			}
			if ((Object)(object)HeroController.instance != (Object)null && ((Object)(object)hitInstance.Source == (Object)(object)((Component)HeroController.instance).gameObject || hitInstance.Source.transform.IsChildOf(((Component)HeroController.instance).transform)))
			{
				return true;
			}
		}
		return false;
	}

	private static float GetFractionalDamage(HeroController hero)
	{
		if ((Object)(object)hero != (Object)null && fractionalDamageMap.TryGetValue(hero, out var value))
		{
			return value;
		}
		return 0f;
	}

	private static void SetFractionalDamage(HeroController hero, float val)
	{
		if ((Object)(object)hero != (Object)null)
		{
			if (val > 0.001f)
			{
				fractionalDamageMap[hero] = val;
			}
			else
			{
				fractionalDamageMap.Remove(hero);
			}
		}
	}
}
[HarmonyPatch]
internal static class EasyModePatches
{
	private static bool isHandlingTakeHealth;

	[HarmonyPatch(typeof(PlayerData), "TakeHealth")]
	[HarmonyPrefix]
	private static void PlayerDataTakeHealthPrefix(PlayerData __instance, ref int amount)
	{
		if (isHandlingTakeHealth || amount <= 0 || !EasyModeManager.IsEnabled())
		{
			return;
		}
		try
		{
			isHandlingTakeHealth = true;
			amount = EasyModeManager.CalculateIncomingDamage(HeroController.instance, amount);
		}
		finally
		{
			isHandlingTakeHealth = false;
		}
	}

	[HarmonyPatch(typeof(HeroController), "StartRecoil")]
	[HarmonyPrefix]
	private static void HeroStartRecoilPrefix(HeroController __instance, ref CollisionSide impactSide)
	{
		if (EasyModeManager.IsEnabled(__instance))
		{
			impactSide = (CollisionSide)4;
		}
	}

	[HarmonyPatch(typeof(HealthManager), "Hit")]
	[HarmonyPrefix]
	private static void HealthManagerHitPrefix(ref HitInstance hitInstance)
	{
		//IL_0001: Unknown result type (might be due to invalid IL or missing references)
		if (EasyModeManager.IsHeroAttack(hitInstance))
		{
			hitInstance.DamageDealt *= 2;
		}
	}

	[HarmonyPatch(typeof(HealthManager), "ApplyExtraDamage", new Type[] { typeof(HitInstance) })]
	[HarmonyPrefix]
	private static void HealthManagerApplyExtraDamagePrefix(ref HitInstance hitInstance)
	{
		//IL_0001: Unknown result type (might be due to invalid IL or missing references)
		if (EasyModeManager.IsHeroAttack(hitInstance))
		{
			hitInstance.DamageDealt *= 2;
		}
	}

	[HarmonyPatch(typeof(HeroController), "HeroRespawned")]
	[HarmonyPostfix]
	private static void HeroRespawnedPostfix(HeroController __instance)
	{
		EasyModeManager.ResetFractionalDamage(__instance);
	}

	[HarmonyPatch(typeof(HeroController), "Die")]
	[HarmonyPostfix]
	private static void HeroDiePostfix(HeroController __instance)
	{
		EasyModeManager.ResetFractionalDamage(__instance);
	}
}
[BepInPlugin("silksong.checkpoint.mod", "Silksong Checkpoint Mod", "1.0.0")]
public sealed class ModEntry : BaseUnityPlugin
{
	public const string Guid = "silksong.checkpoint.mod";

	public const string Name = "Silksong Checkpoint Mod";

	public const string Version = "1.0.0";

	private Harmony harmony;

	internal static ManualLogSource Log { get; private set; }

	private void Awake()
	{
		//IL_0032: Unknown result type (might be due to invalid IL or missing references)
		//IL_003c: Expected O, but got Unknown
		Log = ((BaseUnityPlugin)this).Logger;
		CustomCheckpoint.Bind(((BaseUnityPlugin)this).Config);
		CheckpointHotkeys.Bind(((BaseUnityPlugin)this).Config);
		EasyModeManager.Bind(((BaseUnityPlugin)this).Config);
		harmony = new Harmony("silksong.checkpoint.mod");
		harmony.PatchAll(typeof(RespawnPatches));
		harmony.PatchAll(typeof(EasyModePatches));
		((Component)this).gameObject.AddComponent<CheckpointHotkeys>();
		Log.LogInfo((object)("Silksong Checkpoint Mod 1.0.0 загружен. Точка возрождения: " + (CustomCheckpoint.IsSet ? CustomCheckpoint.Scene : "не задана") + ". Легкий режим: " + (EasyModeManager.IsEnabled() ? "ВКЛ" : "ВЫКЛ") + "."));
	}

	private void OnDestroy()
	{
		Harmony obj = harmony;
		if (obj != null)
		{
			obj.UnpatchSelf();
		}
	}
}
[HarmonyPatch]
internal static class RespawnPatches
{
	private static bool loadingSavedGame;

	private static bool overrideArmed;

	private static string armedScene;

	private static Vector2 armedPosition;

	private static bool armedFacingRight;

	[HarmonyPatch(typeof(GameManager), "ReadyForRespawn")]
	[HarmonyPrefix]
	private static void ReadyForRespawnPrefix(bool isFirstLevelForPlayer)
	{
		loadingSavedGame = isFirstLevelForPlayer;
	}

	[HarmonyPatch(typeof(GameManager), "ReadyForRespawn")]
	[HarmonyFinalizer]
	private static void ReadyForRespawnFinalizer()
	{
		loadingSavedGame = false;
	}

	[HarmonyPatch(typeof(GameManager), "GetRespawnInfo")]
	[HarmonyPostfix]
	private static void GetRespawnInfoPostfix(ref string scene, ref string marker)
	{
		//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)
		if (!loadingSavedGame && CustomCheckpoint.IsSet)
		{
			scene = CustomCheckpoint.Scene;
			marker = "S2E Custom Respawn Marker";
			overrideArmed = true;
			armedScene = CustomCheckpoint.Scene;
			armedPosition = CustomCheckpoint.Position;
			armedFacingRight = CustomCheckpoint.FacingRight;
		}
	}

	[HarmonyPatch(typeof(HeroController), "LocateSpawnPoint")]
	[HarmonyPostfix]
	private static void LocateSpawnPointPostfix(ref Transform __result)
	{
		//IL_001a: Unknown result type (might be due to invalid IL or missing references)
		if (overrideArmed && (IsArmedScene() || !((Object)(object)__result != (Object)null)))
		{
			Transform orCreateMarker = CustomCheckpoint.GetOrCreateMarker(armedPosition, armedFacingRight);
			if (!((Object)(object)orCreateMarker == (Object)null))
			{
				__result = orCreateMarker;
				overrideArmed = false;
			}
		}
	}

	private static bool IsArmedScene()
	{
		//IL_0023: Unknown result type (might be due to invalid IL or missing references)
		//IL_0028: Unknown result type (might be due to invalid IL or missing references)
		GameManager instance = GameManager.instance;
		if ((Object)(object)instance != (Object)null && instance.GetSceneNameString() == armedScene)
		{
			return true;
		}
		Scene activeScene = SceneManager.GetActiveScene();
		return ((Scene)(ref activeScene)).name == armedScene;
	}
}