using System; using System.Collections.Generic; using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using BepInEx; using FishNet; using FishNet.Broadcast; using FishNet.Connection; using FishNet.Managing; using FishNet.Object; using FishNet.Serializing; using FishNet.Transporting; using HarmonyLib; using UnityEngine; 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("sharko")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyDescription("Turns the shotgun into an impact dynamite launcher.")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0+3a4d4b112dfa7424cb1e60491d109288c41f0174")] [assembly: AssemblyProduct("GrenadesShotgun")] [assembly: AssemblyTitle("GrenadesShotgun")] [assembly: AssemblyVersion("1.0.0.0")] namespace GrenadesShotgun; [BepInPlugin("sharko.grenadesshotgun", "GrenadesShotgun", "1.4.0")] public sealed class Plugin : BaseUnityPlugin { public const string Guid = "sharko.grenadesshotgun"; public const string Name = "GrenadesShotgun"; public const string Version = "1.4.0"; private const int Protocol = 140; private const float LaunchSpeed = 22f; private const int BaseDamage = 35; private const int MaxDamage = 800; private const int MaxPlayableUpgradeLevel = 6; private const float Radius = 2.5f; private static readonly FieldInfo ExplosionInfoField = AccessTools.Field(typeof(Explosive), "_explosionInfo"); private static readonly FieldInfo DamageField = AccessTools.Field(typeof(ExplosionInfo), "_damage"); private static readonly FieldInfo BulletUpgradesField = AccessTools.Field(typeof(Attachments), "_bulletUpgrades"); private static readonly FieldInfo DamageRadiusField = AccessTools.Field(typeof(ExplosionInfo), "damageRadius"); private static readonly FieldInfo ForceRadiusField = AccessTools.Field(typeof(ExplosionInfo), "_forceRadius"); private static readonly FieldInfo ItemForceField = AccessTools.Field(typeof(ExplosionInfo), "_itemForce"); private static readonly FieldInfo BoatForceField = AccessTools.Field(typeof(ExplosionInfo), "_boatForce"); private static readonly FieldInfo PlayerForceField = AccessTools.Field(typeof(ExplosionInfo), "_playerForce"); private static Plugin _instance; private Harmony _harmony; private Item _dynamitePrefab; private NetworkManager _network; private readonly HashSet _confirmedClients = new HashSet(); private bool _networkReady; private bool _serverState; private bool _helloSent; private float _nextCheck; private void Awake() { //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Expected O, but got Unknown _instance = this; RegisterSerializers(); _harmony = new Harmony("sharko.grenadesshotgun"); Patch("AddProjectile", "ReplaceSingle"); Patch("AddProjectiles", "ReplacePellets"); ((BaseUnityPlugin)this).Logger.LogInfo((object)"GrenadesShotgun loaded - sharko"); } private void Update() { TryHookNetwork(); if (!_networkReady) { return; } if (_network.ClientManager.Started && _network.ClientManager.Connection.IsAuthenticated) { if (!_helloSent) { _helloSent = true; _network.ClientManager.Broadcast(new ModHello { Protocol = 140 }, (Channel)0); } } else { _helloSent = false; _serverState = false; } if (_network.ServerManager.Started && Time.unscaledTime >= _nextCheck) { _nextCheck = Time.unscaledTime + 0.25f; RefreshServerState(); } } private void OnDestroy() { UnhookNetwork(); if (_harmony != null) { _harmony.UnpatchSelf(); } if ((Object)(object)_instance == (Object)(object)this) { _instance = null; } } private static void RegisterSerializers() { GenericWriter.SetWrite((Action)WriteHello); GenericReader.SetRead((Func)ReadHello); GenericWriter.SetWrite((Action)WriteState); GenericReader.SetRead((Func)ReadState); GenericWriter.SetWrite((Action)WriteLaunchRequest); GenericReader.SetRead((Func)ReadLaunchRequest); } private static void WriteHello(Writer writer, ModHello value) { writer.WriteInt32(value.Protocol); } private static ModHello ReadHello(Reader reader) { return new ModHello { Protocol = reader.ReadInt32() }; } private static void WriteState(Writer writer, ModState value) { writer.WriteInt32(value.Protocol); writer.WriteBoolean(value.Enabled); } private static ModState ReadState(Reader reader) { return new ModState { Protocol = reader.ReadInt32(), Enabled = reader.ReadBoolean() }; } private static void WriteLaunchRequest(Writer writer, LaunchRequest value) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Unknown result type (might be due to invalid IL or missing references) writer.WriteVector3(value.Position); writer.WriteVector3(value.Direction); } private static LaunchRequest ReadLaunchRequest(Reader reader) { //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) return new LaunchRequest { Position = reader.ReadVector3(), Direction = reader.ReadVector3() }; } private void TryHookNetwork() { NetworkManager networkManager = InstanceFinder.NetworkManager; if (_networkReady) { if (Object.op_Implicit((Object)(object)_network) && (Object)(object)_network == (Object)(object)networkManager) { return; } UnhookNetwork(); } if (Object.op_Implicit((Object)(object)networkManager)) { _network = networkManager; _network.ServerManager.RegisterBroadcast((Action)OnHello, true); _network.ServerManager.RegisterBroadcast((Action)OnLaunchRequest, true); _network.ClientManager.RegisterBroadcast((Action)OnState); _network.ServerManager.OnRemoteConnectionState += OnRemoteConnectionState; _networkReady = true; } } private void UnhookNetwork() { if (_networkReady && Object.op_Implicit((Object)(object)_network)) { _network.ServerManager.UnregisterBroadcast((Action)OnHello); _network.ServerManager.UnregisterBroadcast((Action)OnLaunchRequest); _network.ClientManager.UnregisterBroadcast((Action)OnState); _network.ServerManager.OnRemoteConnectionState -= OnRemoteConnectionState; _networkReady = false; _serverState = false; _confirmedClients.Clear(); } } private void OnHello(NetworkConnection connection, ModHello message, Channel channel) { if (message.Protocol == 140) { _confirmedClients.Add(connection.ClientId); } else { _confirmedClients.Remove(connection.ClientId); } RefreshServerState(); } private void OnState(ModState state, Channel channel) { _serverState = state.Protocol == 140 && state.Enabled; ((BaseUnityPlugin)this).Logger.LogInfo((object)(_serverState ? "Enabled: every player has the mod." : "Disabled: waiting for every player to have the mod.")); } private void OnLaunchRequest(NetworkConnection connection, LaunchRequest request, Channel channel) { //IL_006c: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_00cf: Unknown result type (might be due to invalid IL or missing references) //IL_00d4: Unknown result type (might be due to invalid IL or missing references) //IL_0096: 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_00a1: Unknown result type (might be due to invalid IL or missing references) //IL_00a6: Unknown result type (might be due to invalid IL or missing references) //IL_00b8: Unknown result type (might be due to invalid IL or missing references) //IL_00bd: Unknown result type (might be due to invalid IL or missing references) if (!_serverState || !_confirmedClients.Contains(connection.ClientId)) { return; } Player val = FindPlayer(connection); if (!Object.op_Implicit((Object)(object)val) || !Object.op_Implicit((Object)(object)val.Holding) || !Object.op_Implicit((Object)(object)val.Holding.HeldItem)) { return; } Item heldItem = val.Holding.HeldItem; Weapon val2 = (Weapon)(object)((heldItem is Weapon) ? heldItem : null); if (!IsShotgun(val2)) { return; } Vector3 normalized = ((Vector3)(ref request.Direction)).normalized; if (((Vector3)(ref normalized)).sqrMagnitude < 0.9f) { return; } Transform firePoint = val2.Attachments.FirePoint; if (Object.op_Implicit((Object)(object)firePoint)) { Vector3 val3 = request.Position - firePoint.position; if (((Vector3)(ref val3)).sqrMagnitude > 9f || Vector3.Dot(firePoint.forward, normalized) < 0.35f) { return; } } Launch(val, val2, request.Position, normalized); } private void OnRemoteConnectionState(NetworkConnection connection, RemoteConnectionStateArgs args) { _confirmedClients.Remove(connection.ClientId); SetServerState(enabled: false); _nextCheck = 0f; } private void RefreshServerState() { if (!_networkReady || !_network.ServerManager.Started) { SetServerState(enabled: false); return; } bool flag = false; bool flag2 = true; foreach (NetworkConnection value in _network.ServerManager.Clients.Values) { if (value.IsAuthenticated) { flag = true; if (!_confirmedClients.Contains(value.ClientId)) { flag2 = false; break; } } } SetServerState(flag && flag2); } private void SetServerState(bool enabled) { if (_serverState != enabled) { _serverState = enabled; if (_networkReady && _network.ServerManager.Started) { _network.ServerManager.Broadcast(new ModState { Protocol = 140, Enabled = enabled }, true, (Channel)0); } } } private void Patch(string originalName, string patchName) { //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Expected O, but got Unknown MethodInfo methodInfo = AccessTools.Method(typeof(ProjectileManager), originalName, (Type[])null, (Type[])null); MethodInfo methodInfo2 = AccessTools.Method(typeof(Plugin), patchName, (Type[])null, (Type[])null); if (methodInfo != null && methodInfo2 != null) { _harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(methodInfo2), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); } } private static bool ReplaceSingle(Player owner, WeaponInfo weaponInfo, bool isLocal, Vector3 pos, Vector3 velocity) { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Unknown result type (might be due to invalid IL or missing references) if (!IsModdedShot(owner, weaponInfo)) { return true; } if (!isLocal) { return SuppressEcho(weaponInfo, pos, velocity); } return !_instance.HandleLaunch(owner, weaponInfo.Weapon, pos, ((Vector3)(ref velocity)).normalized); } private static bool ReplacePellets(Player owner, WeaponInfo weaponInfo, bool isLocal, Vector3 pos, Vector3[] velocities) { //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) if (!IsModdedShot(owner, weaponInfo) || velocities == null || velocities.Length == 0) { return true; } if (!isLocal) { return SuppressEcho(weaponInfo, pos, velocities[0]); } return !_instance.HandleLaunch(owner, weaponInfo.Weapon, pos, ((Vector3)(ref velocities[0])).normalized); } private static bool SuppressEcho(WeaponInfo weaponInfo, Vector3 pos, Vector3 direction) { //IL_0012: 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_001a: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Unknown result type (might be due to invalid IL or missing references) weaponInfo.Weapon.ShootEffects(false); string shootVFX = weaponInfo.ShootVFX; Quaternion val = Quaternion.LookRotation(((Vector3)(ref direction)).normalized); VFXManager.Play(shootVFX, pos, ((Quaternion)(ref val)).eulerAngles); return false; } private static bool IsModdedShot(Player owner, WeaponInfo info) { if (!Object.op_Implicit((Object)(object)_instance) || !_instance._serverState || !Object.op_Implicit((Object)(object)owner) || info == null || !Object.op_Implicit((Object)(object)info.Weapon)) { return false; } return IsShotgun(info.Weapon); } private static bool IsShotgun(Weapon weapon) { if (!Object.op_Implicit((Object)(object)weapon)) { return false; } string text = ((Object)weapon).name.ToLowerInvariant(); if (!text.Contains("shotgun")) { return text.Contains("pump"); } return true; } private bool HandleLaunch(Player owner, Weapon weapon, Vector3 position, Vector3 direction) { //IL_0027: 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_0070: Unknown result type (might be due to invalid IL or missing references) //IL_0071: 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) if (!_networkReady || !_serverState) { return false; } if (_network.ServerManager.Started) { return Launch(owner, weapon, position, direction); } if (!_network.ClientManager.Started || !_network.ClientManager.Connection.IsAuthenticated) { return false; } _network.ClientManager.Broadcast(new LaunchRequest { Position = position, Direction = ((Vector3)(ref direction)).normalized }, (Channel)0); return true; } private static Player FindPlayer(NetworkConnection connection) { for (int i = 0; i < PlayerManager.Players.Count; i++) { Player val = PlayerManager.Players[i]; if (Object.op_Implicit((Object)(object)val) && ((NetworkBehaviour)val).Owner == connection) { return val; } } return null; } private bool Launch(Player owner, Weapon weapon, Vector3 fallbackPosition, Vector3 fallbackDirection) { //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_003c: 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_0047: 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_0038: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_0059: 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_005b: 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_00b8: Unknown result type (might be due to invalid IL or missing references) //IL_00d1: Unknown result type (might be due to invalid IL or missing references) //IL_00d7: Unknown result type (might be due to invalid IL or missing references) Item dynamite = GetDynamite(); if (!Object.op_Implicit((Object)(object)dynamite)) { return false; } Transform firePoint = weapon.Attachments.FirePoint; Vector3 val = (Object.op_Implicit((Object)(object)firePoint) ? firePoint.forward : fallbackDirection); Vector3 val2 = (Object.op_Implicit((Object)(object)firePoint) ? (firePoint.position + val * 0.4f) : fallbackPosition); Item val3 = null; bool flag = false; try { val3 = Object.Instantiate(dynamite, val2, Quaternion.LookRotation(val)); Explosive component = ((Component)val3).GetComponent(); if (!Object.op_Implicit((Object)(object)component)) { Object.Destroy((Object)(object)((Component)val3).gameObject); return false; } TuneExplosion(component, GetGrenadeDamage(weapon)); ImpactDynamite impactDynamite = ((Component)val3).gameObject.AddComponent(); impactDynamite.Setup(val3, component, owner, ((Vector3)(ref val)).normalized * 22f); ((NetworkBehaviour)Server.Instance).Spawn(((Component)val3).gameObject, (NetworkConnection)null, default(Scene)); flag = true; impactDynamite.PushNow(); return true; } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("Could not launch dynamite: " + ex.Message)); if (Object.op_Implicit((Object)(object)val3)) { try { if (flag) { ((NetworkBehaviour)Server.Instance).Despawn(((Component)val3).gameObject, (DespawnType?)null); } else { Object.Destroy((Object)(object)((Component)val3).gameObject); } } catch (Exception ex2) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("Could not clean up failed dynamite: " + ex2.Message)); } } return false; } } private Item GetDynamite() { if (Object.op_Implicit((Object)(object)_dynamitePrefab)) { return _dynamitePrefab; } Item val = null; Item[] array = Resources.LoadAll("Items"); foreach (Item val2 in array) { if (Object.op_Implicit((Object)(object)val2) && Object.op_Implicit((Object)(object)((Component)val2).GetComponent())) { if (!Object.op_Implicit((Object)(object)val)) { val = val2; } if (((Object)val2).name.IndexOf("dynamite", StringComparison.OrdinalIgnoreCase) >= 0) { _dynamitePrefab = val2; break; } } } if (!Object.op_Implicit((Object)(object)_dynamitePrefab)) { _dynamitePrefab = val; } return _dynamitePrefab; } private static int GetGrenadeDamage(Weapon weapon) { if (!Object.op_Implicit((Object)(object)weapon) || !Object.op_Implicit((Object)(object)weapon.Attachments)) { return 35; } if (!(BulletUpgradesField?.GetValue(weapon.Attachments) is BulletUpgrade[] array) || array.Length <= 1) { return 35; } float num = Mathf.Clamp01((float)Mathf.Clamp((int)weapon.Attachments.AmmoType, 0, array.Length - 1) / 6f); float num2 = num * num; return Mathf.RoundToInt(Mathf.Lerp(35f, 800f, num2)); } private static void TuneExplosion(Explosive explosive, int damage) { object? value = ExplosionInfoField.GetValue(explosive); ExplosionInfo val = (ExplosionInfo)((value is ExplosionInfo) ? value : null); if (val != null) { DamageField.SetValue(val, Mathf.Clamp(damage, 35, 800)); DamageRadiusField.SetValue(val, 2.5f); ForceRadiusField.SetValue(val, 3f); ItemForceField.SetValue(val, 250f); BoatForceField.SetValue(val, 150f); PlayerForceField.SetValue(val, 12f); } } } public struct ModHello : IBroadcast { public int Protocol; } public struct ModState : IBroadcast { public int Protocol; public bool Enabled; } public struct LaunchRequest : IBroadcast { public Vector3 Position; public Vector3 Direction; } public sealed class ImpactDynamite : MonoBehaviour { private const float MinSpinSpeed = 8f; private const float MaxSpinSpeed = 20f; private Item _item; private Explosive _explosive; private Player _owner; private Vector3 _velocity; private Vector3 _spin; private float _pushUntil; private float _armedAt; private bool _exploded; public void Setup(Item item, Explosive explosive, Player owner, Vector3 velocity) { //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_001e: 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) //IL_0037: Unknown result type (might be due to invalid IL or missing references) _item = item; _explosive = explosive; _owner = owner; _velocity = velocity; _spin = Random.onUnitSphere * Random.Range(8f, 20f); _armedAt = Time.time + 0.06f; _pushUntil = Time.time + 0.14f; if (Object.op_Implicit((Object)(object)_item) && Object.op_Implicit((Object)(object)_item.Rig)) { _item.Rig.angularDamping = 0f; } } public void PushNow() { ApplyVelocity(); ApplySpin(); } private void FixedUpdate() { if (!_exploded) { if (Time.time <= _pushUntil) { ApplyVelocity(); } ApplySpin(); } } private void ApplyVelocity() { //IL_004e: Unknown result type (might be due to invalid IL or missing references) if (Object.op_Implicit((Object)(object)_item) && Object.op_Implicit((Object)(object)_item.Rig)) { _item.Rig.isKinematic = false; _item.Rig.collisionDetectionMode = (CollisionDetectionMode)2; _item.Rig.linearVelocity = _velocity; } } private void ApplySpin() { //IL_002c: Unknown result type (might be due to invalid IL or missing references) if (Object.op_Implicit((Object)(object)_item) && Object.op_Implicit((Object)(object)_item.Rig)) { _item.Rig.angularVelocity = _spin; } } private void OnCollisionEnter(Collision collision) { if (!_exploded && !(Time.time < _armedAt) && Object.op_Implicit((Object)(object)_explosive) && Object.op_Implicit((Object)(object)Server.Instance) && ((NetworkBehaviour)Server.Instance).IsServerInitialized) { _exploded = true; _explosive.ForceExplode(_owner, true); } } }