Decompiled source of FusionSyringe v1.0.0

FusionSyringe.dll

Decompiled a day ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BoneLib;
using BoneLib.BoneMenu;
using FusionSyringe;
using HarmonyLib;
using Il2CppInterop.Runtime.InteropTypes.Arrays;
using Il2CppSLZ.Marrow;
using Il2CppSLZ.Marrow.Combat;
using Il2CppSLZ.Marrow.Warehouse;
using LabFusion.Entities;
using LabFusion.Network;
using LabFusion.Network.Serialization;
using LabFusion.Player;
using LabFusion.Preferences.Server;
using LabFusion.SDK.Modules;
using LabFusion.Senders;
using MelonLoader;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: MelonInfo(typeof(Core), "Fusion Syringe", "1.0.1", "RusMenu", null)]
[assembly: MelonGame("Stress Level Zero", "BONELAB")]
[assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")]
[assembly: AssemblyVersion("0.0.0.0")]
namespace FusionSyringe;

public sealed class Core : MelonMod
{
	public const float SedationSeconds = 20f;

	public const string SyringeBarcode = "Bugrax.BLSyringe.Spawnable.SyringeTest";

	private static float _sedatedUntil;

	private static readonly Dictionary<byte, float> HitCooldowns = new Dictionary<byte, float>();

	private bool _crateRenamed;

	private bool _menuReady;

	internal static bool NativeMode;

	private static bool _rulesSaved;

	private static bool _oldKnockout;

	private static bool _oldMortality;

	private static bool _oldFriendly;

	private static int _oldLength;

	internal static Core Instance { get; private set; }

	internal static bool IsSedated => Time.unscaledTime < _sedatedUntil;

	private static void RestoreRules()
	{
		if (_rulesSaved)
		{
			SavedServerSettings.Knockout.Value = _oldKnockout;
			SavedServerSettings.Mortality.Value = _oldMortality;
			SavedServerSettings.FriendlyFire.Value = _oldFriendly;
			SavedServerSettings.KnockoutLength.Value = _oldLength;
			_rulesSaved = false;
		}
	}

	private static void SelectMode(bool native)
	{
		if (native && !NetworkInfo.IsHost)
		{
			Core instance = Instance;
			if (instance != null)
			{
				((MelonBase)instance).LoggerInstance.Warning("Native mode requires hosting an active Fusion lobby.");
			}
			return;
		}
		NativeMode = native;
		if (!native)
		{
			RestoreRules();
		}
		HitCooldowns.Clear();
		Core instance2 = Instance;
		if (instance2 != null)
		{
			((MelonBase)instance2).LoggerInstance.Msg(native ? "Mode: native Fusion (host only)" : "Mode: DLL on participants");
		}
	}

	public override void OnInitializeMelon()
	{
		Instance = this;
		ModuleMessageManager.RegisterHandler<SedateMessage>();
		((MelonBase)this).LoggerInstance.Msg("Fusion Syringe initialized. Effect duration: 20 seconds.");
	}

	public override void OnUpdate()
	{
		//IL_0022: 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_0063: Unknown result type (might be due to invalid IL or missing references)
		//IL_0198: Unknown result type (might be due to invalid IL or missing references)
		//IL_019d: Unknown result type (might be due to invalid IL or missing references)
		//IL_01a8: 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)
		TryRenameCrate();
		if (!_menuReady && Page.Root != null)
		{
			Page obj = Page.Root.CreatePage("Fusion Syringe", Color.cyan, 0, true);
			obj.CreateFunction("DLL у игроков (по умолчанию)", Color.green, (Action)delegate
			{
				SelectMode(native: false);
			});
			obj.CreateFunction("Без DLL у остальных [Хост]", Color.yellow, (Action)delegate
			{
				SelectMode(native: true);
			});
			_menuReady = true;
		}
		if (NativeMode && !NetworkInfo.IsHost)
		{
			SelectMode(native: false);
		}
		if (NativeMode && NetworkInfo.IsHost && SavedServerSettings.Knockout != null)
		{
			if (!_rulesSaved)
			{
				_oldKnockout = SavedServerSettings.Knockout.Value;
				_oldMortality = SavedServerSettings.Mortality.Value;
				_oldFriendly = SavedServerSettings.FriendlyFire.Value;
				_oldLength = SavedServerSettings.KnockoutLength.Value;
				_rulesSaved = true;
			}
			if (!SavedServerSettings.Knockout.Value)
			{
				SavedServerSettings.Knockout.Value = true;
			}
			if (!SavedServerSettings.Mortality.Value)
			{
				SavedServerSettings.Mortality.Value = true;
			}
			if (!SavedServerSettings.FriendlyFire.Value)
			{
				SavedServerSettings.FriendlyFire.Value = true;
			}
			if (SavedServerSettings.KnockoutLength.Value != 20)
			{
				SavedServerSettings.KnockoutLength.Value = 20;
			}
		}
		if (IsSedated && !((Object)(object)Player.RigManager == (Object)null))
		{
			RemapRig remapHeptaRig = Player.RigManager.remapHeptaRig;
			if ((Object)(object)remapHeptaRig != (Object)null)
			{
				remapHeptaRig._currentVelocity = Vector2.op_Implicit(Vector3.zero);
				remapHeptaRig._currentAcceleration = Vector2.op_Implicit(Vector3.zero);
			}
		}
	}

	public override void OnDeinitializeMelon()
	{
		RestoreRules();
		_sedatedUntil = 0f;
		HitCooldowns.Clear();
		Instance = null;
	}

	internal static void SedateLocal(float seconds = 20f)
	{
		if (float.IsFinite(seconds) && !(seconds <= 0f) && !IsSedated && !LocalRagdoll.KnockedOut)
		{
			float num = Mathf.Clamp(seconds, 0f, 20f);
			LocalRagdoll.Knockout(num, false);
			_sedatedUntil = Mathf.Max(_sedatedUntil, Time.unscaledTime + num);
			Core instance = Instance;
			if (instance != null)
			{
				((MelonBase)instance).LoggerInstance.Msg($"Local player sedated for {num:0} seconds.");
			}
		}
	}

	internal static void OnSyringeStab(StabPoint stabPoint, Transform syringeTransform)
	{
		if ((NativeMode && NetworkInfo.HasServer && !NetworkInfo.IsHost) || stabPoint == null || (Object)(object)syringeTransform == (Object)null || !IsFusionSyringe(syringeTransform) || stabPoint.stabJoints == null)
		{
			return;
		}
		foreach (StabJoint item in (Il2CppArrayBase<StabJoint>)(object)stabPoint.stabJoints)
		{
			if (item != null && !((Object)(object)item.collider == (Object)null))
			{
				RigManager componentInParent = ((Component)item.collider).GetComponentInParent<RigManager>();
				if (!((Object)(object)componentInParent == (Object)null) && TryGetPlayerId(componentInParent, out var playerId) && (!HitCooldowns.TryGetValue(playerId, out var value) || !(Time.unscaledTime < value)))
				{
					HitCooldowns[playerId] = Time.unscaledTime + 20f + 1f;
					SendSedation(playerId);
					break;
				}
			}
		}
	}

	private static bool IsFusionSyringe(Transform transform)
	{
		Transform val = transform;
		while ((Object)(object)val != (Object)null)
		{
			string name = ((Object)val).name;
			if (!string.IsNullOrEmpty(name) && (name.IndexOf("SyringeTest", StringComparison.OrdinalIgnoreCase) >= 0 || name.IndexOf("Tracker[SyringeTest]", StringComparison.OrdinalIgnoreCase) >= 0))
			{
				return true;
			}
			val = val.parent;
		}
		return false;
	}

	private static bool TryGetPlayerId(RigManager rig, out byte playerId)
	{
		playerId = 0;
		if ((Object)(object)Player.RigManager != (Object)null && (Object)(object)rig == (Object)(object)Player.RigManager)
		{
			if (!NetworkInfo.HasServer)
			{
				return true;
			}
			playerId = PlayerIDManager.LocalSmallID;
			return true;
		}
		NetworkPlayer val = default(NetworkPlayer);
		if (!NetworkInfo.HasServer || !NetworkPlayerManager.TryGetPlayer(rig, ref val) || ((val != null) ? val.PlayerID : null) == null)
		{
			return false;
		}
		playerId = val.PlayerID.SmallID;
		return true;
	}

	private static void SendSedation(byte targetId)
	{
		//IL_0038: Unknown result type (might be due to invalid IL or missing references)
		//IL_0053: Unknown result type (might be due to invalid IL or missing references)
		//IL_0058: Unknown result type (might be due to invalid IL or missing references)
		//IL_0068: Expected O, but got Unknown
		if (!NetworkInfo.HasServer)
		{
			SedateLocal();
		}
		else if (targetId == PlayerIDManager.LocalSmallID)
		{
			SedateLocal();
		}
		else if (!NativeMode)
		{
			MessageRelay.RelayModule<SedateMessage, SedateData>(new SedateData
			{
				Target = targetId
			}, CommonMessageRoutes.ReliableToOtherClients);
		}
		else if (NetworkInfo.IsHost && _rulesSaved)
		{
			PlayerSender.SendPlayerDamage(targetId, new Attack
			{
				damage = 10000f
			});
			Core instance = Instance;
			if (instance != null)
			{
				((MelonBase)instance).LoggerInstance.Msg("Sent native Fusion knockout damage to player " + targetId);
			}
		}
	}

	private void TryRenameCrate()
	{
		//IL_0022: Unknown result type (might be due to invalid IL or missing references)
		//IL_002e: Expected O, but got Unknown
		if (_crateRenamed || AssetWarehouse.Instance == null || !AssetWarehouse.ready)
		{
			return;
		}
		try
		{
			Crate val = default(Crate);
			if (AssetWarehouse.Instance.TryGetCrate(new Barcode("Bugrax.BLSyringe.Spawnable.SyringeTest"), ref val) && !((Object)(object)val == (Object)null))
			{
				((Scannable)val).Title = "Syringe (Fusion)";
				((Scannable)val).Description = "Stops a Fusion player for 20 seconds";
				_crateRenamed = true;
				((MelonBase)this).LoggerInstance.Msg("Spawn-menu item renamed to Syringe (Fusion).");
			}
		}
		catch (Exception ex)
		{
			((MelonBase)this).LoggerInstance.Warning("Could not rename the syringe crate yet: " + ex.Message);
		}
	}
}
[HarmonyPatch(typeof(StabPoint), "SpawnStab")]
internal static class SyringeStabPatch
{
	private static void Postfix(StabPoint __instance, Transform tran)
	{
		Core.OnSyringeStab(__instance, tran);
	}
}
[HarmonyPatch(typeof(RemapRig), "ApplyMovement")]
internal static class SedatedMovementPatch
{
	private readonly struct MovementState
	{
		public readonly float MaxVelocity;

		public readonly float MaxAcceleration;

		public readonly float JumpVelocity;

		public readonly bool JumpEnabled;

		public MovementState(RemapRig rig)
		{
			MaxVelocity = rig.maxVelocity;
			MaxAcceleration = rig.maxAcceleration;
			JumpVelocity = rig.jumpVelocity;
			JumpEnabled = rig.jumpEnabled;
		}
	}

	private static void Prefix(RemapRig __instance, out MovementState? __state)
	{
		__state = null;
		if (Core.IsSedated && !((Object)(object)Player.RigManager == (Object)null) && !((Object)(object)Player.RigManager.remapHeptaRig != (Object)(object)__instance))
		{
			__state = new MovementState(__instance);
			__instance.maxVelocity = 0f;
			__instance.maxAcceleration = 0f;
			__instance.jumpVelocity = 0f;
			__instance.jumpEnabled = false;
		}
	}

	private static void Finalizer(RemapRig __instance, MovementState? __state)
	{
		if (__state.HasValue)
		{
			MovementState value = __state.Value;
			__instance.maxVelocity = value.MaxVelocity;
			__instance.maxAcceleration = value.MaxAcceleration;
			__instance.jumpVelocity = value.JumpVelocity;
			__instance.jumpEnabled = value.JumpEnabled;
		}
	}
}
public sealed class SedateData : INetSerializable
{
	public byte Target;

	public int? GetSize()
	{
		return 1;
	}

	public void Serialize(INetSerializer serializer)
	{
		serializer.SerializeValue(ref Target);
	}
}
public sealed class SedateMessage : ModuleMessageHandler
{
	protected override void OnHandleMessage(ReceivedMessage message)
	{
		if (((ReceivedMessage)(ref message)).Sender.HasValue && PlayerIDManager.HasPlayerID(((ReceivedMessage)(ref message)).Sender.Value) && ((ReceivedMessage)(ref message)).ReadData<SedateData>().Target == PlayerIDManager.LocalSmallID)
		{
			Core.SedateLocal();
		}
	}
}