using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Security;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Logging;
using GameNetcodeStuff;
using Microsoft.CodeAnalysis;
using On;
using Unity.Netcode;
using UnityEngine;
using XuMiscTools.Patches;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyCompany("XuXiaolan")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyDescription("The coolest mod ever made")]
[assembly: AssemblyFileVersion("1.1.0.0")]
[assembly: AssemblyInformationalVersion("1.1.0+55a20245c05e8204d992c070d08a367a16740562")]
[assembly: AssemblyProduct("XuMiscTools")]
[assembly: AssemblyTitle("com.github.xuxiaolan.xumisctools")]
[assembly: AssemblyMetadata("RepositoryUrl", "https://github.com/XuuXiao/xumisctools")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.1.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
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;
}
}
[CompilerGenerated]
[Microsoft.CodeAnalysis.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;
}
}
}
[BepInPlugin("com.github.xuxiaolan.xumisctools", "XuMiscTools", "1.1.0")]
public class Plugin : BaseUnityPlugin
{
public static ManualLogSource Log;
private void Awake()
{
Log = ((BaseUnityPlugin)this).Logger;
ShovelPatch.Init();
Log.LogInfo((object)"Plugin XuMiscTools is loaded!");
}
}
internal static class LCMPluginInfo
{
public const string PLUGIN_GUID = "com.github.xuxiaolan.xumisctools";
public const string PLUGIN_NAME = "XuMiscTools";
public const string PLUGIN_VERSION = "1.1.0";
}
namespace XuMiscTools
{
public class BetterCooldownTrigger : MonoBehaviour
{
public enum DeathAnimation
{
Default,
HeadBurst,
Spring,
Electrocuted,
ComedyMask,
TragedyMask,
Burnt,
Snipped,
SliceHead
}
public enum ForceDirection
{
Forward,
Backward,
Up,
Down,
Left,
Right,
Center
}
[Tooltip("Different ragdoll body types that spawn after death.")]
public DeathAnimation deathAnimation;
[Tooltip("The force direction of the damage.")]
public ForceDirection forceDirection;
[Tooltip("Cause of death displayed in ScanNode after death.")]
public CauseOfDeath causeOfDeath;
[Tooltip("The force magnitude of the damage.")]
public float forceMagnitudeAfterDamage;
[Tooltip("The force magnitude after death of player.")]
public float forceMagnitudeAfterDeath;
[Tooltip("Whether to trigger for enemies.")]
public bool triggerForEnemies;
[Tooltip("Whether to use shared cooldown between different GameObjects that use this script.")]
public bool sharedCooldown;
[Tooltip("Whether to play default player damage SFX when damage is dealt.")]
public bool playDefaultPlayerDamageSFX;
[Tooltip("If true, the force direction will be calculated from the object's transform. If false, the force direction will be calculated from the player's transform.")]
public bool forceDirectionFromThisObject = true;
[Tooltip("Whether to play sound when damage is dealt to player that enemies can hear.")]
public bool soundAttractsDogs;
[Tooltip("Timer in which the gameobject will disable itself, 0 will not disable itself after any point of time.")]
public float damageDuration;
[Tooltip("Damage to deal every interval for players.")]
public int damageToDealForPlayers;
[Tooltip("Damage to deal every interval for enemies.")]
public int damageToDealForEnemies;
[Tooltip("Cooldown to deal damage for players.")]
public float damageIntervalForPlayers = 0.25f;
[Tooltip("Cooldown to deal damage for enemies.")]
public float damageIntervalForEnemies = 0.25f;
[Tooltip("Damage clip to play when damage is dealt to player/enemy.")]
public List<AudioClip>? damageClip;
[Tooltip("Damage audio sources to play when damage is dealt to player (picks the closest AudioSource to the player).")]
public List<AudioSource>? damageAudioSources;
private static float lastDamageTime = float.NegativeInfinity;
private Dictionary<PlayerControllerB, bool> playerCoroutineStatus = new Dictionary<PlayerControllerB, bool>();
private Dictionary<EnemyAI, bool> enemyCoroutineStatus = new Dictionary<EnemyAI, bool>();
private Dictionary<PlayerControllerB, AudioSource> playerClosestAudioSources = new Dictionary<PlayerControllerB, AudioSource>();
private Dictionary<EnemyAI, AudioSource> enemyClosestAudioSources = new Dictionary<EnemyAI, AudioSource>();
private void OnEnable()
{
((MonoBehaviour)this).StartCoroutine(ManageDamageTimer());
}
private IEnumerator ManageDamageTimer()
{
if (!(damageDuration <= 0f))
{
yield return (object)new WaitForSeconds(damageDuration);
((Component)this).gameObject.SetActive(false);
}
}
private void OnTriggerEnter(Collider other)
{
PlayerControllerB val = default(PlayerControllerB);
if (((Component)other).CompareTag("Player") && Object.op_Implicit((Object)(object)GameNetworkManager.Instance.localPlayerController) == ((Component)other).TryGetComponent<PlayerControllerB>(ref val))
{
if (!playerCoroutineStatus.ContainsKey(val))
{
playerCoroutineStatus[val] = true;
if (damageAudioSources != null && damageAudioSources.Count > 0)
{
playerClosestAudioSources[val] = GetClosestAudioSource(((Component)val).transform);
}
((MonoBehaviour)this).StartCoroutine(DamagePlayerCoroutine(val));
}
}
else
{
if (!triggerForEnemies)
{
return;
}
Transform val2 = TryFindRoot(((Component)other).transform);
EnemyAI val3 = default(EnemyAI);
if ((Object)(object)val2 != (Object)null && ((Component)val2).TryGetComponent<EnemyAI>(ref val3) && !val3.isEnemyDead && !enemyCoroutineStatus.ContainsKey(val3))
{
enemyCoroutineStatus[val3] = true;
if (damageAudioSources != null && damageAudioSources.Count > 0)
{
enemyClosestAudioSources[val3] = GetClosestAudioSource(((Component)val3).transform);
}
((MonoBehaviour)this).StartCoroutine(DamageEnemyCoroutine(val3));
}
}
}
private void OnTriggerExit(Collider other)
{
PlayerControllerB key = default(PlayerControllerB);
if (((Component)other).CompareTag("Player") && Object.op_Implicit((Object)(object)GameNetworkManager.Instance.localPlayerController) == ((Component)other).TryGetComponent<PlayerControllerB>(ref key))
{
playerCoroutineStatus[key] = false;
playerClosestAudioSources.Remove(key);
}
else if (triggerForEnemies)
{
Transform val = TryFindRoot(((Component)other).transform);
EnemyAI key2 = default(EnemyAI);
if ((Object)(object)val != (Object)null && ((Component)val).TryGetComponent<EnemyAI>(ref key2))
{
enemyCoroutineStatus[key2] = false;
enemyClosestAudioSources.Remove(key2);
}
}
}
private IEnumerator DamagePlayerCoroutine(PlayerControllerB player)
{
while (playerCoroutineStatus[player])
{
if (sharedCooldown && Time.time < lastDamageTime + damageIntervalForPlayers)
{
yield return null;
continue;
}
lastDamageTime = Time.time;
ApplyDamageToPlayer(player);
yield return (object)new WaitForSeconds(damageIntervalForPlayers);
}
}
private IEnumerator DamageEnemyCoroutine(EnemyAI enemy)
{
while (enemyCoroutineStatus[enemy])
{
if (sharedCooldown && Time.time < lastDamageTime + damageIntervalForEnemies)
{
yield return null;
continue;
}
lastDamageTime = Time.time;
ApplyDamageToEnemy(enemy);
yield return (object)new WaitForSeconds(damageIntervalForEnemies);
}
}
private void ApplyDamageToPlayer(PlayerControllerB player)
{
//IL_0008: 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_0016: 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_002b: 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_0070: Unknown result type (might be due to invalid IL or missing references)
//IL_0075: 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_007b: Unknown result type (might be due to invalid IL or missing references)
Vector3 val = CalculateForceDirection(player, forceMagnitudeAfterDamage);
Vector3 val2 = CalculateForceDirection(player, forceMagnitudeAfterDeath);
player.DamagePlayer(damageToDealForPlayers, playDefaultPlayerDamageSFX, true, causeOfDeath, (int)deathAnimation, false, val2);
PlayDamageSound(((Component)player).transform, playerClosestAudioSources.ContainsKey(player) ? playerClosestAudioSources[player] : null);
if (!player.isPlayerDead)
{
player.externalForces += val;
}
}
private void ApplyDamageToEnemy(EnemyAI enemy)
{
enemy.HitEnemy(damageToDealForEnemies, (PlayerControllerB)null, false, -1);
PlayDamageSound(((Component)enemy).transform, enemyClosestAudioSources.ContainsKey(enemy) ? enemyClosestAudioSources[enemy] : null);
}
private Vector3 CalculateForceDirection(PlayerControllerB player, float baseForce)
{
//IL_0000: Unknown result type (might be due to invalid IL or missing references)
//IL_0005: 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_0095: Unknown result type (might be due to invalid IL or missing references)
//IL_009a: 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_0042: Unknown result type (might be due to invalid IL or missing references)
//IL_007a: Unknown result type (might be due to invalid IL or missing references)
//IL_007f: 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_0143: Unknown result type (might be due to invalid IL or missing references)
//IL_0149: Unknown result type (might be due to invalid IL or missing references)
//IL_00c0: Unknown result type (might be due to invalid IL or missing references)
//IL_00c5: Unknown result type (might be due to invalid IL or missing references)
//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
//IL_00e8: Unknown result type (might be due to invalid IL or missing references)
//IL_00db: Unknown result type (might be due to invalid IL or missing references)
//IL_0123: Unknown result type (might be due to invalid IL or missing references)
//IL_012e: Unknown result type (might be due to invalid IL or missing references)
//IL_0133: 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_013b: Unknown result type (might be due to invalid IL or missing references)
//IL_00fe: Unknown result type (might be due to invalid IL or missing references)
//IL_0109: Unknown result type (might be due to invalid IL or missing references)
//IL_010e: Unknown result type (might be due to invalid IL or missing references)
//IL_0113: Unknown result type (might be due to invalid IL or missing references)
//IL_0116: 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_0084: Unknown result type (might be due to invalid IL or missing references)
//IL_00ca: Unknown result type (might be due to invalid IL or missing references)
//IL_00ed: Unknown result type (might be due to invalid IL or missing references)
//IL_0140: Unknown result type (might be due to invalid IL or missing references)
Vector3 val = Vector3.zero;
switch (forceDirection)
{
case ForceDirection.Forward:
val = (forceDirectionFromThisObject ? ((Component)this).transform.forward : ((Component)player).transform.forward);
break;
case ForceDirection.Backward:
val = (forceDirectionFromThisObject ? (-((Component)this).transform.forward) : (-((Component)player).transform.forward));
break;
case ForceDirection.Up:
val = Vector3.up;
break;
case ForceDirection.Down:
val = Vector3.down;
break;
case ForceDirection.Left:
val = (forceDirectionFromThisObject ? (-((Component)this).transform.right) : (-((Component)player).transform.right));
break;
case ForceDirection.Right:
val = (forceDirectionFromThisObject ? ((Component)this).transform.right : ((Component)player).transform.right);
break;
case ForceDirection.Center:
{
Vector3 val2;
Vector3 normalized;
if (!forceDirectionFromThisObject)
{
val2 = ((Component)this).transform.position - ((Component)player).transform.position;
normalized = ((Vector3)(ref val2)).normalized;
}
else
{
val2 = ((Component)player).transform.position - ((Component)this).transform.position;
normalized = ((Vector3)(ref val2)).normalized;
}
val = normalized;
break;
}
}
return ((Vector3)(ref val)).normalized * baseForce;
}
private void PlayDamageSound(Transform targetTransform, AudioSource? audioSource)
{
//IL_0027: Unknown result type (might be due to invalid IL or missing references)
if (damageClip != null && (Object)(object)audioSource != (Object)null)
{
if (soundAttractsDogs)
{
RoundManager.Instance.PlayAudibleNoise(((Component)audioSource).transform.position, audioSource.maxDistance, audioSource.volume, 0, false, 0);
}
WalkieTalkie.TransmitOneShotAudio(audioSource, damageClip[Random.Range(0, damageClip.Count)], audioSource.volume);
RoundManager.PlayRandomClip(audioSource, damageClip.ToArray(), true, audioSource.volume, 0, damageClip.Count);
}
}
private AudioSource GetClosestAudioSource(Transform targetTransform)
{
//IL_0013: Unknown result type (might be due to invalid IL or missing references)
//IL_0019: 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_0046: Unknown result type (might be due to invalid IL or missing references)
AudioSource val = damageAudioSources[0];
float num = Vector3.Distance(((Component)val).transform.position, targetTransform.position);
foreach (AudioSource damageAudioSource in damageAudioSources)
{
float num2 = Vector3.Distance(((Component)damageAudioSource).transform.position, targetTransform.position);
if (num2 < num)
{
val = damageAudioSource;
num = num2;
}
}
return val;
}
public void OnDisable()
{
((MonoBehaviour)this).StopAllCoroutines();
playerCoroutineStatus.Clear();
enemyCoroutineStatus.Clear();
playerClosestAudioSources.Clear();
enemyClosestAudioSources.Clear();
}
public static Transform? TryFindRoot(Transform child)
{
Transform val = child;
while ((Object)(object)val != (Object)null)
{
if ((Object)(object)((Component)val).GetComponent<NetworkObject>() != (Object)null)
{
return val;
}
val = ((Component)val).transform.parent;
}
return null;
}
}
public class BetterShovel : Shovel
{
private bool _animatorSpeedCurrentlyModified;
private float _originalPlayerAnimatorSpeed;
private PlayerControllerB previouslyHeldBy;
[NonSerialized]
public int defaultForce;
[Tooltip("Setup the shovel type automatically, you STILL need to make a proper itemProperties and set it up how you see fit, this just makes sure the values are correct.")]
public bool SetupShovelTypeAutomatically;
[Tooltip("The speed of the shovel hitting.")]
public float ShovelSpeedMultiplier = 1f;
[Tooltip("If true, the player will be able to crit with this weapon, dealing 2x damage.")]
public bool CritPossible;
[Tooltip("The chance that the player will crit with this weapon.")]
public float CritChance;
[Tooltip("If true, the player will be able to break trees using this weapon, uses vehicle mechanics.")]
public bool CanBreakTrees;
[Tooltip("The position of the tip of the shovel.")]
public Transform WeaponTip;
public override void Start()
{
((GrabbableObject)this).Start();
if (SetupShovelTypeAutomatically)
{
((GrabbableObject)this).itemProperties.twoHandedAnimation = true;
((GrabbableObject)this).itemProperties.weight = Mathf.Clamp(((GrabbableObject)this).itemProperties.weight, 1f, 9f);
((GrabbableObject)this).itemProperties.grabAnim = "HoldLung";
((GrabbableObject)this).itemProperties.isDefensiveWeapon = true;
((GrabbableObject)this).itemProperties.holdButtonUse = true;
}
}
public override void EquipItem()
{
((GrabbableObject)this).EquipItem();
AnimationClip val = ((IEnumerable<AnimationClip>)((GrabbableObject)this).playerHeldBy.playerBodyAnimator.runtimeAnimatorController.animationClips).FirstOrDefault((Func<AnimationClip, bool>)((AnimationClip clip) => ((Object)clip).name == "ShovelReelUp"));
AnimationClip val2 = ((IEnumerable<AnimationClip>)((GrabbableObject)this).playerHeldBy.playerBodyAnimator.runtimeAnimatorController.animationClips).FirstOrDefault((Func<AnimationClip, bool>)((AnimationClip clip) => ((Object)clip).name == "HitShovel"));
if ((Object)(object)val != (Object)null && (Object)(object)val2 != (Object)null && !_animatorSpeedCurrentlyModified)
{
_originalPlayerAnimatorSpeed = ((GrabbableObject)this).playerHeldBy.playerBodyAnimator.speed;
float length = val.length;
float speed = length * ShovelSpeedMultiplier;
_animatorSpeedCurrentlyModified = true;
((GrabbableObject)this).playerHeldBy.playerBodyAnimator.speed = speed;
}
previouslyHeldBy = ((GrabbableObject)this).playerHeldBy;
}
public override void DiscardItem()
{
((Shovel)this).DiscardItem();
AnimationClip val = ((IEnumerable<AnimationClip>)previouslyHeldBy.playerBodyAnimator.runtimeAnimatorController.animationClips).FirstOrDefault((Func<AnimationClip, bool>)((AnimationClip clip) => ((Object)clip).name == "ShovelReelUp"));
AnimationClip val2 = ((IEnumerable<AnimationClip>)previouslyHeldBy.playerBodyAnimator.runtimeAnimatorController.animationClips).FirstOrDefault((Func<AnimationClip, bool>)((AnimationClip clip) => ((Object)clip).name == "HitShovel"));
if ((Object)(object)val != (Object)null && (Object)(object)val2 != (Object)null && _animatorSpeedCurrentlyModified)
{
previouslyHeldBy.playerBodyAnimator.speed = _originalPlayerAnimatorSpeed;
_animatorSpeedCurrentlyModified = false;
}
}
public override void PocketItem()
{
((GrabbableObject)this).PocketItem();
AnimationClip val = ((IEnumerable<AnimationClip>)previouslyHeldBy.playerBodyAnimator.runtimeAnimatorController.animationClips).FirstOrDefault((Func<AnimationClip, bool>)((AnimationClip clip) => ((Object)clip).name == "ShovelReelUp"));
AnimationClip val2 = ((IEnumerable<AnimationClip>)previouslyHeldBy.playerBodyAnimator.runtimeAnimatorController.animationClips).FirstOrDefault((Func<AnimationClip, bool>)((AnimationClip clip) => ((Object)clip).name == "HitShovel"));
if ((Object)(object)val != (Object)null && (Object)(object)val2 != (Object)null && _animatorSpeedCurrentlyModified)
{
previouslyHeldBy.playerBodyAnimator.speed = _originalPlayerAnimatorSpeed;
_animatorSpeedCurrentlyModified = false;
}
}
}
public static class ShovelExtensions
{
public static int CriticalHit(int force, Random random, float critChance)
{
if ((float)random.NextDouble() * 100f < Math.Clamp(critChance, 0f, 100f))
{
return force * 2;
}
return force;
}
}
}
namespace XuMiscTools.Patches
{
internal static class ShovelPatch
{
[CompilerGenerated]
private static class <>O
{
public static hook_HitShovel <0>__Shovel_HitShovel;
}
public static Random? random;
public static void Init()
{
//IL_0010: 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: Expected O, but got Unknown
object obj = <>O.<0>__Shovel_HitShovel;
if (obj == null)
{
hook_HitShovel val = Shovel_HitShovel;
<>O.<0>__Shovel_HitShovel = val;
obj = (object)val;
}
Shovel.HitShovel += (hook_HitShovel)obj;
}
private static void Shovel_HitShovel(orig_HitShovel orig, Shovel self, bool cancel)
{
//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
if (random == null)
{
if ((Object)(object)StartOfRound.Instance != (Object)null)
{
random = new Random(StartOfRound.Instance.randomMapSeed + 85);
}
else
{
random = new Random(69);
}
}
if (self is BetterShovel betterShovel)
{
betterShovel.defaultForce = ((Shovel)betterShovel).shovelHitForce;
if (betterShovel.CritPossible)
{
((Shovel)betterShovel).shovelHitForce = ShovelExtensions.CriticalHit(((Shovel)betterShovel).shovelHitForce, random, betterShovel.CritChance);
}
}
orig.Invoke(self, cancel);
if (self is BetterShovel betterShovel2)
{
((Shovel)betterShovel2).shovelHitForce = betterShovel2.defaultForce;
if (betterShovel2.CanBreakTrees)
{
RoundManager.Instance.DestroyTreeOnLocalClient(betterShovel2.WeaponTip.position);
}
}
}
}
}
namespace System.Runtime.CompilerServices
{
[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
internal sealed class IgnoresAccessChecksToAttribute : Attribute
{
public IgnoresAccessChecksToAttribute(string assemblyName)
{
}
}
}