Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
93 changes: 69 additions & 24 deletions EXILED/Exiled.API/Features/Items/Firearm.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,21 +21,15 @@ namespace Exiled.API.Features.Items
using Exiled.API.Interfaces;
using Exiled.API.Structs;
using Extensions;
using InventorySystem;
using InventorySystem.Items;
using InventorySystem.Items.Autosync;
using InventorySystem.Items.Firearms;
using InventorySystem.Items.Firearms.Attachments;
using InventorySystem.Items.Firearms.Attachments.Components;
using InventorySystem.Items.Firearms.BasicMessages;
using InventorySystem.Items.Firearms.Modules;
using InventorySystem.Items.Pickups;
using MEC;
using UnityEngine;

using static InventorySystem.Items.Firearms.Modules.AnimatorReloaderModuleBase;

using BaseFirearm = InventorySystem.Items.Firearms.Firearm;
using FirearmPickup = Pickups.FirearmPickup;
using Object = UnityEngine.Object;

/// <summary>
/// A wrapper class for <see cref="InventorySystem.Items.Firearms.Firearm"/>.
Expand Down Expand Up @@ -63,20 +57,26 @@ public Firearm(BaseFirearm itemBase)

foreach (ModuleBase module in Base.Modules)
{
if (module is IPrimaryAmmoContainerModule primaryAmmoModule)
switch (module)
{
PrimaryMagazine ??= (PrimaryMagazine)Magazine.Get(primaryAmmoModule);
continue;
}
case IPrimaryAmmoContainerModule primaryAmmoModule:
PrimaryMagazine ??= (PrimaryMagazine)Magazine.Get(primaryAmmoModule);
break;

if (module is IAmmoContainerModule ammoModule)
{
BarrelMagazine ??= (BarrelMagazine)Magazine.Get(ammoModule);
}
case IAmmoContainerModule ammoModule:
BarrelMagazine ??= (BarrelMagazine)Magazine.Get(ammoModule);
break;

if (module is HitscanHitregModuleBase hitregModule)
{
HitscanHitregModule = hitregModule;
case HitscanHitregModuleBase hitregModule:
HitscanHitregModule = hitregModule;
break;

case AnimatorReloaderModuleBase animatorReloaderModule:
AnimatorReloaderModule = animatorReloaderModule;
break;

default:
break;
}
}
}
Expand Down Expand Up @@ -146,6 +146,11 @@ public static IReadOnlyDictionary<Player, Dictionary<FirearmType, AttachmentIden
/// </summary>
public HitscanHitregModuleBase HitscanHitregModule { get; }

/// <summary>
/// Gets an animator reloader module for the current firearm.
/// </summary>
public AnimatorReloaderModuleBase AnimatorReloaderModule { get; }

/// <summary>
/// Gets or sets the amount of ammo in the firearm magazine.
/// </summary>
Expand Down Expand Up @@ -713,12 +718,52 @@ public void ClearPreferences()
/// <remarks>
/// For specific reloading logic you also can use <see cref="NormalMagazine"/> for avaible weapons.
/// </remarks>
public void Reload()
public void ForceReload()
{
if (Base.TryGetModule(out AnimatorReloaderModuleBase module))
{
module.StartReloading();
}
if (AnimatorReloaderModule == null)
return;

AnimatorReloaderModule.IsReloading = true;
AnimatorReloaderModule.SendRpcHeaderWithRandomByte(ReloaderMessageHeader.Reload);
}

/// <summary>
/// Attempts to reload the firearm with server-side validation.
/// </summary>
/// <returns><see langword="true"/> if the firearm was successfully reloaded. Otherwise, <see langword="false"/>.</returns>
public bool Reload()
{
if (AnimatorReloaderModule == null)
return false;

return AnimatorReloaderModule.ServerTryReload();
}

/// <summary>
/// Attempts to unload the firearm with server-side validation.
/// </summary>
/// <returns><see langword="true"/> if the firearm was successfully unload. Otherwise, <see langword="false"/>.</returns>
public bool Unload()
{
if (AnimatorReloaderModule == null)
return false;

return AnimatorReloaderModule.ServerTryUnload();
}

/// <summary>
/// Forces the firearm's client-side unload animation, bypassing server-side checks.
/// </summary>
/// <remarks>
/// This only plays the animation and is not guaranteed to result in a successful unload. For server-validated unloading, use <see cref="Unload"/>.
/// </remarks>
public void ForceUnload()
{
if (AnimatorReloaderModule == null)
return;

AnimatorReloaderModule.IsUnloading = true;
AnimatorReloaderModule.SendRpcHeaderWithRandomByte(ReloaderMessageHeader.Unload);
}

/// <summary>
Expand Down
66 changes: 57 additions & 9 deletions EXILED/Exiled.API/Features/Player.cs
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ namespace Exiled.API.Features
using VoiceChat.Playbacks;

using static DamageHandlers.DamageHandlerBase;
using static InventorySystem.Items.Firearms.Modules.AnimatorReloaderModuleBase;

using DamageHandlerBase = PlayerStatsSystem.DamageHandlerBase;
using Firearm = Items.Firearm;
Expand Down Expand Up @@ -1803,23 +1804,70 @@ public void TrySetCustomRoleFriendlyFire(string roleTypeId, Dictionary<RoleTypeI
/// <returns> Whether the item was able to be added. </returns>
public bool TryRemoveCustomeRoleFriendlyFire(string role) => CustomRoleFriendlyFireMultiplier.Remove(role);

/// <summary>
/// Forces the player's client to play the weapon reload animation, bypassing server-side checks.
/// </summary>
/// <returns><see langword="true"/> if the command to start reloading was sent. Otherwise, <see langword="false"/>.</returns>
/// <remarks>
/// This method does not check if the weapon can actually be reloaded. It only forces the animation and is not guaranteed to result in a successful reload.
/// </remarks>
public bool ForceReloadWeapon()
{
if (CurrentItem is not Firearm firearm || firearm.AnimatorReloaderModule == null)
{
return false;
}

firearm.AnimatorReloaderModule.IsReloading = true;
firearm.AnimatorReloaderModule.SendRpcHeaderWithRandomByte(ReloaderMessageHeader.Reload);
return true;
}

/// <summary>
/// Forces the player to reload their current weapon.
/// </summary>
/// <returns><see langword="true"/> if firearm was successfully reloaded. Otherwise, <see langword="false"/>.</returns>
/// <returns><see langword="true"/> if the firearm was successfully reloaded. Otherwise, <see langword="false"/>.</returns>
public bool ReloadWeapon()
{
if (CurrentItem is Firearm firearm)
if (CurrentItem is not Firearm firearm || firearm.AnimatorReloaderModule == null)
{
// TODO not finish
/*
bool result = firearm.Base.Ammo.ServerTryReload();
Connection.Send(new RequestMessage(firearm.Serial, RequestType.Reload));
return result;
*/
return false;
}

return false;
return firearm.AnimatorReloaderModule.ServerTryReload();
}

/// <summary>
/// Forces the player's client to play the weapon unload animation, bypassing server-side checks.
/// </summary>
/// <returns><see langword="true"/> if the command to start unloading was sent. Otherwise, <see langword="false"/>.</returns>
/// <remarks>
/// This method does not check if the weapon can actually be unloaded. It only forces the animation and is not guaranteed to result in a successful unload.
/// </remarks>
public bool ForceUnloadWeapon()
{
if (CurrentItem is not Firearm firearm || firearm.AnimatorReloaderModule == null)
{
return false;
}

firearm.AnimatorReloaderModule.IsUnloading = true;
firearm.AnimatorReloaderModule.SendRpcHeaderWithRandomByte(ReloaderMessageHeader.Unload);
return true;
}

/// <summary>
/// Forces the player to unload their current weapon.
/// </summary>
/// <returns><see langword="true"/> if the firearm was successfully unloaded. Otherwise, <see langword="false"/>.</returns>
public bool UnloadWeapon()
{
if (CurrentItem is not Firearm firearm || firearm.AnimatorReloaderModule == null)
{
return false;
}

return firearm.AnimatorReloaderModule.ServerTryUnload();
}

/// <summary>
Expand Down
Loading