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<int> _confirmedClients = new HashSet<int>();
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<ModHello>(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<ModHello>.SetWrite((Action<Writer, ModHello>)WriteHello);
GenericReader<ModHello>.SetRead((Func<Reader, ModHello>)ReadHello);
GenericWriter<ModState>.SetWrite((Action<Writer, ModState>)WriteState);
GenericReader<ModState>.SetRead((Func<Reader, ModState>)ReadState);
GenericWriter<LaunchRequest>.SetWrite((Action<Writer, LaunchRequest>)WriteLaunchRequest);
GenericReader<LaunchRequest>.SetRead((Func<Reader, LaunchRequest>)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<ModHello>((Action<NetworkConnection, ModHello, Channel>)OnHello, true);
_network.ServerManager.RegisterBroadcast<LaunchRequest>((Action<NetworkConnection, LaunchRequest, Channel>)OnLaunchRequest, true);
_network.ClientManager.RegisterBroadcast<ModState>((Action<ModState, Channel>)OnState);
_network.ServerManager.OnRemoteConnectionState += OnRemoteConnectionState;
_networkReady = true;
}
}
private void UnhookNetwork()
{
if (_networkReady && Object.op_Implicit((Object)(object)_network))
{
_network.ServerManager.UnregisterBroadcast<ModHello>((Action<NetworkConnection, ModHello, Channel>)OnHello);
_network.ServerManager.UnregisterBroadcast<LaunchRequest>((Action<NetworkConnection, LaunchRequest, Channel>)OnLaunchRequest);
_network.ClientManager.UnregisterBroadcast<ModState>((Action<ModState, Channel>)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<ModState>(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<LaunchRequest>(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<Item>(dynamite, val2, Quaternion.LookRotation(val));
Explosive component = ((Component)val3).GetComponent<Explosive>();
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>();
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<Item>("Items");
foreach (Item val2 in array)
{
if (Object.op_Implicit((Object)(object)val2) && Object.op_Implicit((Object)(object)((Component)val2).GetComponent<Explosive>()))
{
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);
}
}
}