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();
}
}
}