Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

There are so many changes that I don't know what to put in the title. #217

Open
wants to merge 6 commits into
base: 13.1
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 5 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
18 changes: 18 additions & 0 deletions NwPluginAPI/Core/Doors/FacilityBreakableDoor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,24 @@ public void Destroy()
DoorEvents.TriggerAction(OriginalObject, DoorAction.Destroyed, null);
}

/// <summary>
/// Try-get a <see cref="FacilityBreakableDoor"/> from a <see cref="DoorVariant"/>
/// </summary>
/// <param name="baseDoor">The <see cref="DoorVariant"/></param>
/// <param name="facilityDoor">The <see cref="FacilityBreakableDoor"/> if its found otherwise will be <see langword="null"/></param>
/// <returns>A boolean indicating if the <see cref="FacilityBreakableDoor"/> was found.</returns>
public static bool TryGet(DoorVariant baseDoor, out FacilityBreakableDoor facilityDoor)
{
if (List == null)
{
facilityDoor = null;
return false;
}

facilityDoor = List.FirstOrDefault(door => door.GameObject == baseDoor.gameObject);
return facilityDoor != null;
}

/// <summary>
/// Initializes a new instance of the <see cref="FacilityBreakableDoor"/> class.
/// </summary>
Expand Down
19 changes: 19 additions & 0 deletions NwPluginAPI/Core/Doors/FacilityDoor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,25 @@ public static IEnumerable<FacilityDoor> Get(Zones.FacilityZone facilityZone) =>
/// <param name="enabled">Whether or not the door lock reason is new.</param>
public void Lock(DoorLockReason reason, bool enabled) => OriginalObject.ServerChangeLock(reason, enabled);


/// <summary>
/// Try-get a <see cref="FacilityDoor"/> from a <see cref="DoorVariant"/>
/// </summary>
/// <param name="baseDoor">The <see cref="DoorVariant"/></param>
/// <param name="facilityDoor">The <see cref="FacilityDoor"/> if its found otherwise will be <see langword="null"/></param>
/// <returns>A boolean indicating if the <see cref="FacilityDoor"/> was found.</returns>
public static bool TryGet(DoorVariant baseDoor, out FacilityDoor facilityDoor)
{
if (Facility.Doors == null)
{
facilityDoor = null;
return false;
}

facilityDoor = Facility.Doors.FirstOrDefault(door => door.GameObject == baseDoor.gameObject);
return facilityDoor != null;
}

/// <summary>
/// Initializes a new instance of the <see cref="FacilityDoor"/> class.
/// </summary>
Expand Down
19 changes: 19 additions & 0 deletions NwPluginAPI/Core/Doors/FacilityGate.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ namespace PluginAPI.Core.Doors
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using Interactables.Interobjects.DoorUtils;

/// <summary>
/// Represents a gate.
Expand All @@ -32,6 +33,24 @@ public class FacilityGate : FacilityDoor
/// </summary>
public Transform[] PryPositions => OriginalObject.PryPositions;

/// <summary>
/// Try-get a <see cref="FacilityGate"/> from a <see cref="DoorVariant"/>
/// </summary>
/// <param name="baseDoor">The <see cref="DoorVariant"/></param>
/// <param name="facilityDoor">The <see cref="FacilityGate"/> if its found otherwise will be <see langword="null"/></param>
/// <returns>A boolean indicating if the <see cref="FacilityGate"/> was found.</returns>
public static bool TryGet(DoorVariant baseDoor, out FacilityGate facilityDoor)
{
if (List == null)
{
facilityDoor = null;
return false;
}

facilityDoor = List.FirstOrDefault(door => door.GameObject == baseDoor.gameObject);
return facilityDoor != null;
}

/// <summary>
/// Initializes a new instance of the <see cref="FacilityGate"/> class.
/// </summary>
Expand Down
220 changes: 220 additions & 0 deletions NwPluginAPI/Core/Extensions/ItemExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,220 @@
using InventorySystem;
using InventorySystem.Items;
using InventorySystem.Items.Firearms;
using InventorySystem.Items.Firearms.Attachments;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace PluginAPI.Core.Extensions
{
public static class ItemExtensions
{
/// <summary>
/// Gets if the <see cref="ItemType"/> is ammo for a firearm.
/// </summary>
/// <param name="type">The <see cref="ItemType"/> to check</param>
/// <returns>Returns whether or not the <see cref="ItemType"/> is ammo.</returns>
public static bool IsAmmo(this ItemType type)
{
switch (type)
{
case ItemType.Ammo12gauge:
case ItemType.Ammo44cal:
case ItemType.Ammo556x45:
case ItemType.Ammo762x39:
case ItemType.Ammo9x19:
return true;
}
return false;
}

/// <summary>
/// Gets if the <see cref="ItemType"/> is a fire Firearm.
/// </summary>
/// <param name="type">The <see cref="ItemType"/> to check</param>
/// <param name="countSpecialWeapons">if is <see langword="true"/>, jailbird and microhid count as firearms</param>
/// <returns>Returns whether or not the <see cref="ItemType"/> is a firearm.</returns>
public static bool IsFirearm(this ItemType type, bool countSpecialWeapons = false)
{
switch (type)
{
case ItemType.GunAK:
case ItemType.GunCOM15:
case ItemType.GunCOM18:
case ItemType.GunCom45:
case ItemType.GunCrossvec:
case ItemType.GunLogicer:
case ItemType.GunRevolver:
case ItemType.GunShotgun:
case ItemType.GunE11SR:
case ItemType.GunFSP9:
return true;
case ItemType.Jailbird:
case ItemType.MicroHID:
{
if (countSpecialWeapons)
return true;
return false;
}
}
return false;
}

/// <summary>
/// Gets if the <see cref="ItemType"/> is a medical item.
/// </summary>
/// <param name="type"></param>
/// <returns>Returns whether or not the <see cref="ItemType"/> is a medical item.</returns>
public static bool IsMedical(this ItemType type) => type is ItemType.Medkit or ItemType.Adrenaline or ItemType.Painkillers or ItemType.SCP500;

/// <summary>
/// Gets if the <see cref="ItemType"/> is a utility item.
/// </summary>
/// <param name="type"></param>
/// <returns>Returns whether or not the <see cref="ItemType"/> is a utility item.</returns>
public static bool IsUtility(this ItemType type) => type is ItemType.Radio or ItemType.Flashlight;

/// <summary>
/// Gets if the <see cref="ItemType"/> is a armor item.
/// </summary>
/// <param name="type"></param>
/// <returns>Returns whether or not the <see cref="ItemType"/> is a armor item.</returns>
public static bool IsArmor(this ItemType type) => type is ItemType.ArmorCombat or ItemType.ArmorHeavy or ItemType.ArmorLight;

/// <summary>
/// Checks if the specified <see cref="ItemType"/> is a throwable item.
/// </summary>
/// <param name="type">The <see cref="ItemType"/> to be checked.</param>
/// <returns>
/// Returns whether or not the <see cref="ItemType"/> is a throwable item.
/// </returns>
public static bool IsThrowable(this ItemType type) => type is ItemType.SCP018 or ItemType.GrenadeFlash or ItemType.GrenadeHE or ItemType.SCP2176;

/// <summary>
/// Gets if the <see cref="ItemType"/> is a keycard item.
/// </summary>
/// <param name="type"></param>
/// <returns>Returns whether or not the <see cref="ItemType"/> is a keycard item.</returns>
public static bool IsKeycard(this ItemType type)
{
switch (type)
{
case ItemType.KeycardChaosInsurgency:
case ItemType.KeycardContainmentEngineer:
case ItemType.KeycardFacilityManager:
case ItemType.KeycardGuard:
case ItemType.KeycardJanitor:
case ItemType.KeycardNTFCommander:
case ItemType.KeycardNTFLieutenant:
case ItemType.KeycardNTFOfficer:
case ItemType.KeycardO5:
case ItemType.KeycardResearchCoordinator:
case ItemType.KeycardScientist:
case ItemType.KeycardZoneManager:
return true;
}
return false;
}

/// <summary>
/// Gets a <see cref="ItemBase"/> of a <see cref="ItemType"/>.
/// </summary>
/// <param name="type"></param>
/// <returns>The <see cref="ItemBase"/> or <see langword="null"/> if not found.</returns>
public static ItemBase GetItemBase(this ItemType type)
{
if(InventoryItemLoader.TryGetItem(type, out ItemBase itembase))
return itembase;

return null;
}

/// <summary>
/// Gets a random attachments code for the specified <see cref="ItemType"/> representing a set of random attachments for a firearm.
/// </summary>
/// <param name="firearm">The <see cref="ItemType"/> of the firearm to be searched for random attachments.</param>
/// <returns>The attachments code, a <see cref="uint"/> value representing a random set of attachments for the firearm.</returns>
public static uint GetRandomAttachments(this ItemType firearm)
{
if (!firearm.IsFirearm())
throw new ArgumentException("The provided argument is not a valid firearm.", nameof(firearm));

return AttachmentsUtils.GetRandomAttachmentsCode(firearm);
}

/// <summary>
/// Applies the specified attachments to the given <see cref="Firearm"/>.
/// </summary>
/// <param name="firearm">The <see cref="Firearm"/> to which the attachments will be applied.</param>
/// <param name="attachmentCode">The attachments code representing the set of attachments to apply.</param>
public static void ApllyAttachments(this Firearm firearm, uint attachmentCode)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this should say ApplyAttachments

{
if (firearm == null)
throw new ArgumentNullException(nameof(Firearm), "Firearm is null");

firearm.ApplyAttachmentsCode(attachmentCode, true);

FirearmStatusFlags firearmStatusFlags = FirearmStatusFlags.MagazineInserted;
if (firearm.HasAdvantageFlag(AttachmentDescriptiveAdvantages.Flashlight))
{
firearmStatusFlags |= FirearmStatusFlags.FlashlightEnabled;
}
firearm.Status = new(firearm.AmmoManagerModule.MaxAmmo, firearmStatusFlags, firearm.GetCurrentAttachmentsCode());
}

/// <summary>
/// Applies a set of random attachments to the specified <see cref="Firearm"/>.
/// </summary>
/// <param name="firearm">The <see cref="Firearm"/> to which random attachments will be applied.</param>
/// <exception cref="ArgumentNullException">Thrown if the <paramref name="firearm"/> is null.</exception>
public static void ApllyRandomAttachments(this Firearm firearm)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Apply, couldn't you also call ApplyAttachment using the value from the GetRandomAttachmentsCode instead of copy-pasting the function.

{
if (firearm == null)
throw new ArgumentNullException(nameof(Firearm), "Firearm is null");

firearm.ApplyAttachmentsCode(AttachmentsUtils.GetRandomAttachmentsCode(firearm.ItemTypeId), true);

FirearmStatusFlags firearmStatusFlags = FirearmStatusFlags.MagazineInserted;
if (firearm.HasAdvantageFlag(AttachmentDescriptiveAdvantages.Flashlight))
{
firearmStatusFlags |= FirearmStatusFlags.FlashlightEnabled;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Potentially check what the old state of the flashlight is, as this will always enable it if there is a flashlight, or we could pass an argument that decides to enable it, disable it, or leave it as is when a flashlight is present.

Perhaps an enum flag could be introduced to decide these modifications, to avoid having a lot of method parameters, please let me know what you think of that idea.

}
firearm.Status = new(firearm.AmmoManagerModule.MaxAmmo, firearmStatusFlags, firearm.GetCurrentAttachmentsCode());
}

/// <summary>
/// Applies the preferences of a <see cref="Player"/>'s attachments to a given <see cref="Firearm"/>.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

could "Tries to apply the pref...." be better in this case?

/// </summary>
/// <param name="firearm">The <see cref="Firearm"/> to modify.</param>
/// <param name="player">The <see cref="Player"/> whose attachments preferences are to be applied.</param>
/// <param name="reloadWeapon">If this value is true, the weapon will be fully reloaded with ammunition when the attachment is applied.</param>
/// <returns>Returns true if the weapon was modified with the attachments; otherwise, false.</returns>
public static bool TryApplyAttachmentsPreferences(this Firearm firearm, Player player, bool reloadWeapon = false)
Copy link
Member

@ced777ric ced777ric Sep 26, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps ApplyAttachment could be used here to prevent copy-pasting the same code.

{
if(firearm == null)
throw new ArgumentNullException(nameof(Firearm), "Firearm is null");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps returning false here could be better, as it is a "Try" style method

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

makes sense I will do it


if(AttachmentsServerHandler.PlayerPreferences.TryGetValue(player.ReferenceHub, out var prefs) && prefs.TryGetValue(firearm.ItemTypeId, out uint attachmentsCode))
{
firearm.ApplyAttachmentsCode(attachmentsCode, true);

FirearmStatusFlags firearmStatusFlags = FirearmStatusFlags.MagazineInserted;
if (firearm.HasAdvantageFlag(AttachmentDescriptiveAdvantages.Flashlight))
{
firearmStatusFlags |= FirearmStatusFlags.FlashlightEnabled;
}

if(reloadWeapon)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wouldnt this either force ammo to 0, or to the max, and not retain current ammunition?

firearm.Status = new(firearm.AmmoManagerModule.MaxAmmo, firearmStatusFlags, firearm.GetCurrentAttachmentsCode());
else
firearm.Status = new(0, firearmStatusFlags, firearm.GetCurrentAttachmentsCode());
return true;
}
return false;
}

}
}
59 changes: 56 additions & 3 deletions NwPluginAPI/Core/Player.cs
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,54 @@ public static bool TryGet<T>(IGameComponent component, out T player) where T : P
return true;
}

/// <summary>
/// Gets a <see cref="Player"/> <see cref="IEnumerable{T}"/> filtred by <see cref="Team"/>.
/// <para><b>Can be empty.</b></para>
/// </summary>
/// <param name="team">The player's team</param>
/// <returns>The filtered <see cref="IEnumerable{T}"/>.</returns>
public static IEnumerable<Player> GetPlayers(Team team) => GetPlayers().Where(p => p.Team == team);

/// <summary>
/// Gets a <see cref="Player"/> <see cref="IEnumerable{T}"/> filtred by <see cref="RoleTypeId"/>.
/// <para><b>Can be empty.</b></para>
/// </summary>
/// <param name="team">The player's team</param>
/// <returns>The filtered <see cref="IEnumerable{T}"/>.</returns>
public static IEnumerable<Player> GetPlayers(RoleTypeId roleType) => GetPlayers().Where(p => p.Role == roleType);

#region Get player from collider

/// <summary>
/// Gets the <see cref="Player"/> associated with the <see cref="Footprint"/>, if any.
/// </summary>
public static Player Get(Collider collider) => Get(collider.gameObject);

/// <summary>
/// Try-get a <see cref="Player"/> associated with the <see cref="Collider"/>.
/// </summary>
/// <param name="collider">The <see cref="Collider"/></param>
/// <param name="player">The <see cref="Player"/> found by the <see cref="Collider"/>, if there is none it will return <see langword="null"/>.</param>
/// <returns>A boolean indicating whether or not a player was found.</returns>
public static bool TryGet(Collider collider, out Player player) => TryGet(collider.gameObject, out player);
#endregion

#region Get player from footprint

/// <summary>
/// Gets the <see cref="Player"/> associated with the <see cref="Footprint"/>, if any.
/// </summary>
public static Player Get(Footprint footprint) => Get(footprint.Hub);

/// <summary>
/// Try-get a <see cref="Player"/> associated with the <see cref="Footprint"/>.
/// </summary>
/// <param name="footprint">The <see cref="Footprint"/></param>
/// <param name="player">The <see cref="Player"/> found by the <see cref="Footprint"/>, if there is none it will return <see langword="null"/>.</param>
/// <returns>A boolean indicating whether or not a player was found.</returns>
public static bool TryGet(Footprint footprint, out Player player) => TryGet(footprint.Hub, out player);
#endregion

#region Get player from gameobject.

/// <summary>
Expand Down Expand Up @@ -581,6 +629,11 @@ public RoleTypeId Role
set => ReferenceHub.roleManager.ServerSetRole(value, RoleChangeReason.RemoteAdmin);
}

/// <summary>
/// Gets the player's <see cref="Footprinting.Footprint"/>.
/// </summary>
public Footprint Footprint => new(ReferenceHub);

/// <summary>
/// Gets player <see cref="PlayerRoleBase"/>.
/// <remarks>
Expand Down Expand Up @@ -1200,7 +1253,7 @@ public void RemoveItems(ItemType itemType, int number = 1)
/// <param name="amount">The amount of ammo which will be dropped.</param>
/// <param name="checkMinimals">Will prevent dropping small amounts of ammo.</param>
/// <returns>Whether or not the player dropped the ammo successfully.</returns>
public List<AmmoPickup> DropAmmo(ItemType item, ushort amount, bool checkMinimals = false) => null;// ReferenceHub.inventory.ServerDropAmmo(item, amount, checkMinimals);
public List<AmmoPickup> DropAmmo(ItemType item, ushort amount, bool checkMinimals = false) => ReferenceHub.inventory.ServerDropAmmo(item, amount, checkMinimals);

/// <summary>
/// Drops all items including ammo.
Expand Down Expand Up @@ -1248,7 +1301,8 @@ public void SetGroup(UserGroup group)
/// </summary>
/// <param name="newRole">The <see cref="RoleTypeId"/> which will be set.</param>
/// <param name="reason">The <see cref="RoleChangeReason"/> of role change.</param>
public void SetRole(RoleTypeId newRole, RoleChangeReason reason = RoleChangeReason.RemoteAdmin) => ReferenceHub.roleManager.ServerSetRole(newRole, reason);
/// <param name="spawnFlags">The <see cref="RoleSpawnFlags"/> of role change.</param>
public void SetRole(RoleTypeId newRole, RoleChangeReason reason = RoleChangeReason.RemoteAdmin, RoleSpawnFlags spawnFlags = RoleSpawnFlags.All) => ReferenceHub.roleManager.ServerSetRole(newRole, reason, spawnFlags);

/// <summary>
/// Disconnects the player from the server.
Expand Down Expand Up @@ -1387,6 +1441,5 @@ public bool TryGetComponent<T>(out T component, bool globalSearch = false) where
#endregion

#endregion

}
}