using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Logging;
using BepInEx.Unity.IL2CPP;
using GTFO.API;
using GameData;
using Gear;
using HarmonyLib;
using Il2CppInterop.Runtime.InteropTypes;
using Il2CppInterop.Runtime.InteropTypes.Arrays;
using Microsoft.CodeAnalysis;
using ModifierAPI.Structs;
using Player;
using UnityEngine;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")]
[assembly: AssemblyCompany("ModifierAPI")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+dde1f5b3ee041a72953a1756d694ecd097773235")]
[assembly: AssemblyProduct("ModifierAPI")]
[assembly: AssemblyTitle("ModifierAPI")]
[assembly: AssemblyVersion("1.0.0.0")]
namespace Microsoft.CodeAnalysis
{
[CompilerGenerated]
[Microsoft.CodeAnalysis.Embedded]
internal sealed class EmbeddedAttribute : Attribute
{
}
}
namespace System.Runtime.CompilerServices
{
[CompilerGenerated]
[Microsoft.CodeAnalysis.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]
[Microsoft.CodeAnalysis.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;
}
}
}
namespace ModifierAPI
{
internal static class DinoLogger
{
private static ManualLogSource logger = Logger.CreateLogSource("ModifierAPI");
public static void Log(string format, params object[] args)
{
Log(string.Format(format, args));
}
public static void Log(string str)
{
if (logger != null)
{
logger.Log((LogLevel)8, (object)str);
}
}
public static void Warning(string format, params object[] args)
{
Warning(string.Format(format, args));
}
public static void Warning(string str)
{
if (logger != null)
{
logger.Log((LogLevel)4, (object)str);
}
}
public static void Error(string format, params object[] args)
{
Error(string.Format(format, args));
}
public static void Error(string str)
{
if (logger != null)
{
logger.Log((LogLevel)2, (object)str);
}
}
public static void Debug(string format, params object[] args)
{
Debug(string.Format(format, args));
}
public static void Debug(string str)
{
if (logger != null)
{
logger.Log((LogLevel)32, (object)str);
}
}
}
[BepInPlugin("Dinorush.ModifierAPI", "ModifierAPI", "1.2.0")]
internal sealed class EntryPoint : BasePlugin
{
public const string MODNAME = "ModifierAPI";
public override void Load()
{
//IL_0005: Unknown result type (might be due to invalid IL or missing references)
new Harmony("ModifierAPI").PatchAll();
LevelAPI.OnLevelCleanup += MoveSpeedAPI.Reset;
((BasePlugin)this).Log.LogMessage((object)"Loaded ModifierAPI");
}
}
public interface IStatModifier
{
float Mod { get; set; }
StackLayer Layer { get; }
bool Active { get; }
void Enable();
void Enable(float mod);
void Disable();
}
public static class MeleeAttackSpeedAPI
{
public const string DefaultGroup = "Default";
private static readonly Dictionary<string, ModifierGroup> _groups = new Dictionary<string, ModifierGroup>();
private static readonly Dictionary<string, ModifierGroup> _lightGroups = new Dictionary<string, ModifierGroup>();
private static readonly Dictionary<string, ModifierGroup> _chargedGroups = new Dictionary<string, ModifierGroup>();
private static readonly Dictionary<string, ModifierGroup> _pushGroups = new Dictionary<string, ModifierGroup>();
private static float _mod = 1f;
private static float _lightMod = 1f;
private static float _chargedMod = 1f;
private static float _pushMod = 1f;
public static IStatModifier AddModifier(float mod, StackLayer layer = StackLayer.Multiply, string group = "Default")
{
return AddModifier(mod, layer, group, _groups);
}
public static IStatModifier AddLightModifier(float mod, StackLayer layer = StackLayer.Multiply, string group = "Default")
{
return AddModifier(mod, layer, group, _lightGroups);
}
public static IStatModifier AddChargedModifier(float mod, StackLayer layer = StackLayer.Multiply, string group = "Default")
{
return AddModifier(mod, layer, group, _chargedGroups);
}
public static IStatModifier AddPushModifier(float mod, StackLayer layer = StackLayer.Multiply, string group = "Default")
{
return AddModifier(mod, layer, group, _pushGroups);
}
private static IStatModifier AddModifier(float mod, StackLayer layer, string group, Dictionary<string, ModifierGroup> groupSet)
{
if (layer < StackLayer.Multiply || (int)layer >= StackLayerConst.NumLayers)
{
throw new ArgumentException($"Invalid layer {layer} provided.");
}
if (!groupSet.TryGetValue(group, out ModifierGroup value))
{
groupSet.Add(group, value = new ModifierGroup(delegate
{
Refresh();
}));
}
return value.Add(mod, layer);
}
internal static float GetMod(eMeleeWeaponState state)
{
//IL_0000: Unknown result type (might be due to invalid IL or missing references)
//IL_0002: Unknown result type (might be due to invalid IL or missing references)
//IL_0034: Expected I4, but got Unknown
float num;
switch (state - 3)
{
case 0:
case 1:
case 2:
case 3:
num = _lightMod;
break;
case 4:
case 5:
case 6:
case 7:
case 8:
case 9:
num = _chargedMod;
break;
case 10:
num = _pushMod;
break;
default:
num = 1f;
break;
}
return num * _mod;
}
internal static void ApplyToWeapon(MeleeWeaponFirstPerson melee)
{
Refresh(force: true);
SetLightAttackTimings(melee);
SetChargedAttackTimings(melee);
SetPushAttackTimings(melee);
}
internal static void Reset()
{
_mod = 1f;
_lightMod = 1f;
_chargedMod = 1f;
_pushMod = 1f;
foreach (ModifierGroup value in _groups.Values)
{
value.Reset();
}
foreach (ModifierGroup value2 in _lightGroups.Values)
{
value2.Reset();
}
foreach (ModifierGroup value3 in _chargedGroups.Values)
{
value3.Reset();
}
foreach (ModifierGroup value4 in _pushGroups.Values)
{
value4.Reset();
}
Refresh(force: true);
}
private static void Refresh(bool force = false)
{
bool flag = TryRefresh(ref _mod, _groups) || force;
bool flag2 = TryRefresh(ref _lightMod, _lightGroups) || flag;
bool flag3 = TryRefresh(ref _chargedMod, _chargedGroups) || flag;
bool flag4 = TryRefresh(ref _pushMod, _pushGroups) || flag;
BackpackItem val = default(BackpackItem);
if (!PlayerManager.HasLocalPlayerAgent() || !PlayerBackpackManager.LocalBackpack.TryGetBackpackItem((InventorySlot)10, ref val))
{
return;
}
MeleeWeaponFirstPerson val2 = ((Il2CppObjectBase)val.Instance).TryCast<MeleeWeaponFirstPerson>();
if (!((Object)(object)val2 == (Object)null))
{
if (flag2)
{
SetLightAttackTimings(val2);
}
if (flag3)
{
SetChargedAttackTimings(val2);
}
if (flag4)
{
SetPushAttackTimings(val2);
}
}
}
private static bool TryRefresh(ref float mod, Dictionary<string, ModifierGroup> groups)
{
float num = 1f;
foreach (ModifierGroup value in groups.Values)
{
num *= value.Mod.Value;
}
if (mod != num)
{
mod = num;
return true;
}
return false;
}
private static void SetLightAttackTimings(MeleeWeaponFirstPerson melee)
{
float mod = 1f / (_mod * _lightMod);
Il2CppReferenceArray<MWS_Base> states = melee.m_states;
MeleeAnimationSetDataBlock meleeAnimationData = ((ItemEquippable)melee).MeleeAnimationData;
CopyMeleeData(((Il2CppArrayBase<MWS_Base>)(object)states)[3].AttackData, meleeAnimationData.FPAttackMissLeft, mod);
CopyMeleeData(((Il2CppArrayBase<MWS_Base>)(object)states)[4].AttackData, meleeAnimationData.FPAttackMissRight, mod);
CopyMeleeData(((Il2CppArrayBase<MWS_Base>)(object)states)[5].AttackData, meleeAnimationData.FPAttackHitLeft, mod);
CopyMeleeData(((Il2CppArrayBase<MWS_Base>)(object)states)[6].AttackData, meleeAnimationData.FPAttackHitRight, mod);
}
private static void SetChargedAttackTimings(MeleeWeaponFirstPerson melee)
{
float mod = 1f / (_mod * _chargedMod);
Il2CppReferenceArray<MWS_Base> states = melee.m_states;
MeleeAnimationSetDataBlock meleeAnimationData = ((ItemEquippable)melee).MeleeAnimationData;
CopyMeleeData(((Il2CppArrayBase<MWS_Base>)(object)states)[8].AttackData, meleeAnimationData.FPAttackChargeUpReleaseLeft, mod);
CopyMeleeData(((Il2CppArrayBase<MWS_Base>)(object)states)[10].AttackData, meleeAnimationData.FPAttackChargeUpReleaseRight, mod);
CopyMeleeData(((Il2CppArrayBase<MWS_Base>)(object)states)[11].AttackData, meleeAnimationData.FPAttackChargeUpHitLeft, mod);
CopyMeleeData(((Il2CppArrayBase<MWS_Base>)(object)states)[12].AttackData, meleeAnimationData.FPAttackChargeUpHitRight, mod);
}
private static void SetPushAttackTimings(MeleeWeaponFirstPerson melee)
{
float mod = 1f / (_mod * _pushMod);
Il2CppReferenceArray<MWS_Base> states = melee.m_states;
CopyMeleeData(animData: ((ItemEquippable)melee).MeleeAnimationData.FPAttackPush, data: ((Il2CppArrayBase<MWS_Base>)(object)states)[13].AttackData, mod: mod);
}
private static void CopyMeleeData(MeleeAttackData data, MeleeAttackData animData, float mod = 1f)
{
data.m_attackLength = animData.AttackLengthTime * mod;
data.m_attackHitTime = animData.AttackHitTime * mod;
data.m_damageStartTime = animData.DamageStartTime * mod;
data.m_damageEndTime = animData.DamageEndTime * mod;
data.m_attackCamFwdHitTime = animData.AttackCamFwdHitTime * mod;
data.m_comboEarlyTime = animData.ComboEarlyTime * mod;
}
}
internal class ModifierGroup
{
public class StatModifier : IStatModifier
{
private float _mod;
private readonly ModifierGroup _parent;
public float Mod
{
get
{
return _mod;
}
set
{
float mod = _mod;
_mod = value;
if (Active && mod != _mod)
{
_parent.Refresh(Layer);
}
}
}
public StackLayer Layer { get; }
public bool Active { get; internal set; }
public StatModifier(float mod, StackLayer layer, ModifierGroup parent)
{
Active = false;
_mod = mod;
Layer = layer;
_parent = parent;
}
public void Enable()
{
if (!Active)
{
Active = true;
_parent.GetLayer(Layer).Add(this);
_parent.Refresh(Layer);
}
}
public void Enable(float mod)
{
Enable();
Mod = mod;
}
public void Disable()
{
if (Active)
{
Active = false;
_parent.GetLayer(Layer).Remove(this);
_parent.Refresh(Layer);
}
}
}
private readonly HashSet<StatModifier>[] _layers = new HashSet<StatModifier>[StackLayerConst.NumLayers];
private readonly Action _onRefresh;
private StackValue _mod = new StackValue();
public StackValue Mod => _mod;
public ModifierGroup(Action onRefresh)
{
_onRefresh = onRefresh;
}
public IStatModifier Add(float mod, StackLayer layer = StackLayer.Multiply)
{
StatModifier statModifier = new StatModifier(mod, layer, this);
statModifier.Enable();
return statModifier;
}
public void Reset()
{
HashSet<StatModifier>[] layers = _layers;
foreach (HashSet<StatModifier> hashSet in layers)
{
if (hashSet == null)
{
continue;
}
foreach (StatModifier item in hashSet)
{
item.Active = false;
}
hashSet.Clear();
}
_mod.Reset();
}
private HashSet<StatModifier> GetLayer(StackLayer layer)
{
return _layers[(int)layer] ?? (_layers[(int)layer] = new HashSet<StatModifier>());
}
private void Refresh(StackLayer layer)
{
if (_layers[(int)layer] == null)
{
return;
}
_mod.Reset(layer);
foreach (StatModifier item in GetLayer(layer))
{
_mod.Add(item.Mod, layer);
}
_onRefresh();
}
}
public static class MoveSpeedAPI
{
public const string DefaultGroup = "Default";
private static readonly Dictionary<string, ModifierGroup> _groups = new Dictionary<string, ModifierGroup>();
private static PlayerDataBlock _playerData = null;
private static float _baseWalkSpeed;
private static float _baseRunSpeed;
private static float _baseCrouchSpeed;
private static float _baseAirSpeed;
private static float _lastScale;
public static IStatModifier AddModifier(float mod, StackLayer layer = StackLayer.Multiply, string group = "Default")
{
if (layer < StackLayer.Multiply || (int)layer >= StackLayerConst.NumLayers)
{
throw new ArgumentException($"Invalid layer {layer} provided.");
}
if (!_groups.TryGetValue(group, out ModifierGroup value))
{
_groups.Add(group, value = new ModifierGroup(Refresh));
}
return value.Add(mod, layer);
}
internal static void Reset()
{
_lastScale = 1f;
foreach (ModifierGroup value in _groups.Values)
{
value.Reset();
}
if (_playerData != null)
{
_playerData.walkMoveSpeed = _baseWalkSpeed;
_playerData.runMoveSpeed = _baseRunSpeed;
_playerData.crouchMoveSpeed = _baseCrouchSpeed;
_playerData.airMoveSpeed = _baseAirSpeed;
}
}
internal static void Refresh()
{
float num = 1f;
foreach (ModifierGroup value in _groups.Values)
{
num *= value.Mod.Value;
}
if (_lastScale != num && _playerData != null)
{
_lastScale = num;
_playerData.walkMoveSpeed = _baseWalkSpeed * num;
_playerData.runMoveSpeed = _baseRunSpeed * num;
_playerData.crouchMoveSpeed = _baseCrouchSpeed * num;
_playerData.airMoveSpeed = _baseAirSpeed * num;
}
}
internal static void CachePlayerData(PlayerDataBlock data)
{
if (_playerData == null || !(((Il2CppObjectBase)_playerData).Pointer == ((Il2CppObjectBase)data).Pointer))
{
_playerData = data;
_baseWalkSpeed = _playerData.walkMoveSpeed;
_baseRunSpeed = _playerData.runMoveSpeed;
_baseCrouchSpeed = _playerData.crouchMoveSpeed;
_baseAirSpeed = _playerData.airMoveSpeed;
}
}
}
public enum StackLayer
{
Multiply,
Add,
Max,
Min,
Override
}
public static class StackLayerConst
{
public static readonly int NumLayers = (int)(Enum.GetValues<StackLayer>()[^1] + 1);
}
}
namespace ModifierAPI.Structs
{
internal struct StackValue
{
private float _value;
private bool _isDirty;
public bool UseOverride;
public float OverrideMod;
public float AddMod;
public float MultMod;
public float MaxMod;
private bool _hasMax;
public float MinMod;
private bool _hasMin;
public float Value
{
get
{
if (!_isDirty)
{
return _value;
}
_value = (UseOverride ? OverrideMod : (AddMod * MultMod * MaxMod * MinMod));
_isDirty = false;
return _value;
}
}
public StackValue()
{
UseOverride = false;
OverrideMod = 1f;
AddMod = 1f;
MultMod = 1f;
MaxMod = 1f;
_hasMax = false;
MinMod = 1f;
_hasMin = false;
_value = 1f;
_isDirty = false;
}
public StackValue(StackValue other)
{
UseOverride = other.UseOverride;
OverrideMod = other.OverrideMod;
AddMod = other.AddMod;
MultMod = other.MultMod;
MaxMod = other.MaxMod;
_hasMax = other._hasMax;
MinMod = other.MinMod;
_hasMin = other._hasMin;
_value = other._value;
_isDirty = other._isDirty;
}
public void Add(float mod, StackLayer type)
{
switch (type)
{
case StackLayer.Override:
OverrideMod = mod;
UseOverride = true;
break;
case StackLayer.Add:
AddMod += mod - 1f;
break;
case StackLayer.Multiply:
MultMod *= mod;
break;
case StackLayer.Max:
MaxMod = Math.Max(GetMax(), mod);
_hasMax = true;
break;
case StackLayer.Min:
MinMod = Math.Min(GetMin(), mod);
_hasMin = true;
break;
}
_isDirty = true;
}
public void Reset(StackLayer type)
{
switch (type)
{
case StackLayer.Override:
UseOverride = false;
OverrideMod = 1f;
break;
case StackLayer.Add:
AddMod = 1f;
break;
case StackLayer.Multiply:
MultMod = 1f;
break;
case StackLayer.Max:
MaxMod = 1f;
_hasMax = false;
break;
case StackLayer.Min:
MinMod = 1f;
_hasMin = false;
break;
}
_isDirty = true;
}
public void Reset()
{
UseOverride = false;
OverrideMod = 1f;
AddMod = 1f;
MultMod = 1f;
MaxMod = 1f;
_hasMax = false;
MinMod = 1f;
_hasMin = false;
_value = 1f;
_isDirty = false;
}
public void Combine(StackValue other)
{
AddMod += other.AddMod - 1f;
MultMod *= other.MultMod;
MaxMod = ((_hasMax || other._hasMax) ? Math.Max(GetMax(), other.GetMax()) : 1f);
_hasMax |= other._hasMax;
MinMod = ((_hasMin || other._hasMin) ? Math.Min(GetMin(), other.GetMin()) : 1f);
_hasMin |= other._hasMin;
OverrideMod = (UseOverride ? OverrideMod : other.OverrideMod);
UseOverride |= other.UseOverride;
_isDirty = true;
}
private readonly float GetMin()
{
if (!_hasMin)
{
return float.MaxValue;
}
return MinMod;
}
private readonly float GetMax()
{
if (!_hasMax)
{
return float.MinValue;
}
return MaxMod;
}
}
}
namespace ModifierAPI.Patches
{
[HarmonyPatch(typeof(MeleeWeaponFirstPerson))]
internal static class MeleePatches
{
private static MWS_AttackLight? _lightLeft;
private static MWS_AttackLight? _lightRight;
private static IntPtr _cachedPtr = IntPtr.Zero;
private static float _cacheChargeDiff = -1f;
[HarmonyPatch("SetupMeleeAnimations")]
[HarmonyWrapSafe]
[HarmonyPostfix]
private static void Post_MeleeSetup(MeleeWeaponFirstPerson __instance)
{
MeleeAttackSpeedAPI.ApplyToWeapon(__instance);
}
[HarmonyPatch("ChangeState")]
[HarmonyWrapSafe]
[HarmonyPostfix]
private static void Post_MeleeChangeState(MeleeWeaponFirstPerson __instance, eMeleeWeaponState newState)
{
//IL_0049: 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_0052: Unknown result type (might be due to invalid IL or missing references)
//IL_0084: Expected I4, but got Unknown
if (_cachedPtr != ((Il2CppObjectBase)__instance).Pointer)
{
_cachedPtr = ((Il2CppObjectBase)__instance).Pointer;
_lightLeft = ((Il2CppObjectBase)((Il2CppArrayBase<MWS_Base>)(object)__instance.m_states)[3]).TryCast<MWS_AttackLight>();
_lightRight = ((Il2CppObjectBase)((Il2CppArrayBase<MWS_Base>)(object)__instance.m_states)[4]).TryCast<MWS_AttackLight>();
}
float mod = MeleeAttackSpeedAPI.GetMod(newState);
switch (newState - 3)
{
case 0:
_lightLeft.m_wantedNormalSpeed = mod;
_lightLeft.m_wantedChargeSpeed = mod * 0.3f;
break;
case 1:
_lightRight.m_wantedNormalSpeed = mod;
_lightRight.m_wantedChargeSpeed = mod * 0.3f;
break;
case 2:
case 3:
__instance.WeaponAnimator.speed = mod;
break;
case 5:
case 7:
__instance.WeaponAnimator.speed = mod;
break;
case 10:
{
Animator weaponAnimator = __instance.WeaponAnimator;
weaponAnimator.speed *= mod;
break;
}
case 4:
case 6:
case 8:
case 9:
break;
}
}
[HarmonyPatch(typeof(MWS_ChargeUp), "Enter")]
[HarmonyWrapSafe]
[HarmonyPostfix]
private static void ChargeCallback(MWS_ChargeUp __instance)
{
float mod = MeleeAttackSpeedAPI.GetMod((eMeleeWeaponState)8);
if (mod != 1f)
{
_cacheChargeDiff = __instance.m_maxDamageTime;
__instance.m_maxDamageTime /= mod;
_cacheChargeDiff -= __instance.m_maxDamageTime;
MeleeAnimationSetDataBlock meleeAnimationData = ((ItemEquippable)((MWS_Base)__instance).m_weapon).MeleeAnimationData;
meleeAnimationData.AutoAttackTime -= _cacheChargeDiff;
meleeAnimationData.AutoAttackWarningTime -= _cacheChargeDiff;
}
}
[HarmonyPatch(typeof(MWS_ChargeUp), "Exit")]
[HarmonyWrapSafe]
[HarmonyPostfix]
private static void RestoreAutoAttackTimings(MWS_ChargeUp __instance)
{
if (_cacheChargeDiff != -1f)
{
MeleeAnimationSetDataBlock meleeAnimationData = ((ItemEquippable)((MWS_Base)__instance).m_weapon).MeleeAnimationData;
meleeAnimationData.AutoAttackTime += _cacheChargeDiff;
meleeAnimationData.AutoAttackWarningTime += _cacheChargeDiff;
_cacheChargeDiff = -1f;
}
}
}
[HarmonyPatch(typeof(LocalPlayerAgent))]
internal static class PlayerSetupPatch
{
[HarmonyPatch("Setup")]
[HarmonyPrefix]
private static void OnAgentSetup(LocalPlayerAgent __instance)
{
if (!((PlayerAgent)__instance).m_isSetup)
{
MoveSpeedAPI.CachePlayerData(GameDataBlockBase<PlayerDataBlock>.GetBlock(1u));
}
}
}
}