Skip to content

Commit

Permalink
Merge branch 'dev' into rec079
Browse files Browse the repository at this point in the history
  • Loading branch information
louis1706 authored Aug 6, 2024
2 parents 28f1567 + eb046ac commit 2f58ca2
Show file tree
Hide file tree
Showing 39 changed files with 406 additions and 153 deletions.
9 changes: 4 additions & 5 deletions EXILED/Exiled.API/Extensions/MirrorExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -435,12 +435,11 @@ public static void SendFakeTargetRpc(Player target, NetworkIdentity behaviorOwne
/// <example>
/// EffectOnlySCP207.
/// <code>
/// MirrorExtensions.SendCustomSync(player, player.ReferenceHub.networkIdentity, typeof(PlayerEffectsController), (writer) => {
/// writer.WriteUInt64(1ul); // DirtyObjectsBit
/// writer.WriteUInt32(1); // DirtyIndexCount
/// MirrorExtensions.SendFakeSyncObject(player, player.NetworkIdentity, typeof(PlayerEffectsController), (writer) => {
/// writer.WriteULong(1ul); // DirtyObjectsBit
/// writer.WriteUInt(1); // DirtyIndexCount
/// writer.WriteByte((byte)SyncList&lt;byte&gt;.Operation.OP_SET); // Operations
/// writer.WriteUInt32(17); // EditIndex
/// writer.WriteByte(1); // Value
/// writer.WriteUInt(17); // EditIndex
/// });
/// </code>
/// </example>
Expand Down
2 changes: 1 addition & 1 deletion EXILED/Exiled.API/Features/Camera.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ public class Camera : IWrapper<Scp079Camera>, IWorldSpace
/// <summary>
/// A <see cref="Dictionary{TKey,TValue}"/> containing all known <see cref="Scp079Camera"/>s and their corresponding <see cref="Camera"/>.
/// </summary>
internal static readonly Dictionary<Scp079Camera, Camera> Camera079ToCamera = new(250);
internal static readonly Dictionary<Scp079Camera, Camera> Camera079ToCamera = new(250, new ComponentsEqualityComparer());

private static readonly Dictionary<string, CameraType> NameToCameraType = new()
{
Expand Down
2 changes: 1 addition & 1 deletion EXILED/Exiled.API/Features/Doors/AirlockController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ public class AirlockController
/// <summary>
/// A <see cref="Dictionary{TKey,TValue}"/> containing all known <see cref="BaseController"/>'s and their corresponding <see cref="AirlockController"/>.
/// </summary>
internal static readonly Dictionary<BaseController, AirlockController> BaseToExiledControllers = new();
internal static readonly Dictionary<BaseController, AirlockController> BaseToExiledControllers = new(new ComponentsEqualityComparer());

/// <summary>
/// Initializes a new instance of the <see cref="AirlockController"/> class.
Expand Down
2 changes: 1 addition & 1 deletion EXILED/Exiled.API/Features/Doors/Door.cs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ public class Door : TypeCastObject<Door>, IWrapper<DoorVariant>, IWorldSpace
/// <summary>
/// A <see cref="Dictionary{TKey,TValue}"/> containing all known <see cref="DoorVariant"/>'s and their corresponding <see cref="Door"/>.
/// </summary>
internal static readonly Dictionary<DoorVariant, Door> DoorVariantToDoor = new();
internal static readonly Dictionary<DoorVariant, Door> DoorVariantToDoor = new(new ComponentsEqualityComparer());

/// <summary>
/// Initializes a new instance of the <see cref="Door"/> class.
Expand Down
2 changes: 1 addition & 1 deletion EXILED/Exiled.API/Features/Generator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ public class Generator : IWrapper<Scp079Generator>, IWorldSpace
/// <summary>
/// A <see cref="List{T}"/> of <see cref="Generator"/> on the map.
/// </summary>
internal static readonly Dictionary<Scp079Generator, Generator> Scp079GeneratorToGenerator = new();
internal static readonly Dictionary<Scp079Generator, Generator> Scp079GeneratorToGenerator = new(new ComponentsEqualityComparer());
private Room room;

/// <summary>
Expand Down
2 changes: 1 addition & 1 deletion EXILED/Exiled.API/Features/Hazards/Hazard.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ public class Hazard : TypeCastObject<Hazard>, IWrapper<EnvironmentalHazard>
/// <summary>
/// <see cref="Dictionary{TKey,TValue}"/> with <see cref="EnvironmentalHazard"/> to it's <see cref="Hazard"/>.
/// </summary>
internal static readonly Dictionary<EnvironmentalHazard, Hazard> EnvironmentalHazardToHazard = new();
internal static readonly Dictionary<EnvironmentalHazard, Hazard> EnvironmentalHazardToHazard = new(new ComponentsEqualityComparer());

/// <summary>
/// Initializes a new instance of the <see cref="Hazard"/> class.
Expand Down
2 changes: 1 addition & 1 deletion EXILED/Exiled.API/Features/Items/Ammo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ public class Ammo : Item, IWrapper<AmmoItem>
/// <summary>
/// Gets the absolute maximum amount of ammo that may be held at one time, if ammo is forcefully given to the player (regardless of worn armor or server configuration).
/// <para>
/// For accessing the maximum amount of ammo that may be held based on worn armor and server settings, see <see cref="Player.GetAmmoLimit(AmmoType)"/>.
/// For accessing the maximum amount of ammo that may be held based on worn armor and server settings, see <see cref="Player.GetAmmoLimit(AmmoType, bool)"/>.
/// </para>
/// </summary>
public const ushort AmmoLimit = ushort.MaxValue;
Expand Down
2 changes: 1 addition & 1 deletion EXILED/Exiled.API/Features/Items/Item.cs
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ public class Item : TypeCastObject<Item>, IWrapper<ItemBase>
/// <summary>
/// A dictionary of all <see cref="ItemBase"/>'s that have been converted into <see cref="Item"/>.
/// </summary>
internal static readonly Dictionary<ItemBase, Item> BaseToItem = new();
internal static readonly Dictionary<ItemBase, Item> BaseToItem = new(new ComponentsEqualityComparer());

/// <summary>
/// Initializes a new instance of the <see cref="Item"/> class.
Expand Down
2 changes: 1 addition & 1 deletion EXILED/Exiled.API/Features/Lift.cs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ public class Lift : IWrapper<ElevatorChamber>, IWorldSpace
/// <summary>
/// A <see cref="Dictionary{TKey,TValue}"/> containing all known <see cref="ElevatorChamber"/>s and their corresponding <see cref="Lift"/>.
/// </summary>
internal static readonly Dictionary<ElevatorChamber, Lift> ElevatorChamberToLift = new(8);
internal static readonly Dictionary<ElevatorChamber, Lift> ElevatorChamberToLift = new(8, new ComponentsEqualityComparer());

/// <summary>
/// Internal list that contains all ElevatorDoor for current group.
Expand Down
173 changes: 166 additions & 7 deletions EXILED/Exiled.API/Features/Player.cs
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,16 @@ public class Player : TypeCastObject<Player>, IEntity, IWorldSpace
/// A list of the player's items.
/// </summary>
internal readonly List<Item> ItemsValue = new(8);

/// <summary>
/// A dictionary of custom item category limits.
/// </summary>
internal Dictionary<ItemCategory, sbyte> CustomCategoryLimits = new();

/// <summary>
/// A dictionary of custom ammo limits.
/// </summary>
internal Dictionary<AmmoType, ushort> CustomAmmoLimits = new();
#pragma warning restore SA1401

private readonly HashSet<EActor> componentsInChildren = new();
Expand Down Expand Up @@ -2382,21 +2392,170 @@ public bool DropAmmo(AmmoType ammoType, ushort amount, bool checkMinimals = fals

/// <summary>
/// Gets the maximum amount of ammo the player can hold, given the ammo <see cref="AmmoType"/>.
/// This method factors in the armor the player is wearing, as well as server configuration.
/// For the maximum amount of ammo that can be given regardless of worn armor and server configuration, see <see cref="ServerConfigSynchronizer.AmmoLimit"/>.
/// </summary>
/// <param name="type">The <see cref="AmmoType"/> of the ammo to check.</param>
/// <returns>The maximum amount of ammo this player can carry. Guaranteed to be between <c>0</c> and <see cref="ServerConfigSynchronizer.AmmoLimit"/>.</returns>
public int GetAmmoLimit(AmmoType type) =>
InventorySystem.Configs.InventoryLimits.GetAmmoLimit(type.GetItemType(), referenceHub);
/// <param name="ignoreArmor">If the method should ignore the armor the player is wearing.</param>
/// <returns>The maximum amount of ammo this player can carry.</returns>
public ushort GetAmmoLimit(AmmoType type, bool ignoreArmor = false)
{
if (ignoreArmor)
{
if (CustomAmmoLimits.TryGetValue(type, out ushort limit))
return limit;

ItemType itemType = type.GetItemType();
return ServerConfigSynchronizer.Singleton.AmmoLimitsSync.FirstOrDefault(x => x.AmmoType == itemType).Limit;
}

return InventorySystem.Configs.InventoryLimits.GetAmmoLimit(type.GetItemType(), referenceHub);
}

/// <summary>
/// Gets the maximum amount of ammo the player can hold, given the ammo <see cref="AmmoType"/>.
/// This limit will scale with the armor the player is wearing.
/// For armor ammo limits, see <see cref="Armor.AmmoLimits"/>.
/// </summary>
/// <param name="ammoType">The <see cref="AmmoType"/> of the ammo to check.</param>
/// <param name="limit">The <see cref="ushort"/> number that will define the new limit.</param>
public void SetAmmoLimit(AmmoType ammoType, ushort limit)
{
CustomAmmoLimits[ammoType] = limit;

ItemType itemType = ammoType.GetItemType();
int index = ServerConfigSynchronizer.Singleton.AmmoLimitsSync.FindIndex(x => x.AmmoType == itemType);
MirrorExtensions.SendFakeSyncObject(this, ServerConfigSynchronizer.Singleton.netIdentity, typeof(ServerConfigSynchronizer), writer =>
{
writer.WriteULong(2ul);
writer.WriteUInt(1);
writer.WriteByte((byte)SyncList<ServerConfigSynchronizer.AmmoLimit>.Operation.OP_SET);
writer.WriteInt(index);
writer.WriteAmmoLimit(new() { Limit = limit, AmmoType = itemType, });
});
}

/// <summary>
/// Reset a custom <see cref="AmmoType"/> limit.
/// </summary>
/// <param name="ammoType">The <see cref="AmmoType"/> of the ammo to reset.</param>
public void ResetAmmoLimit(AmmoType ammoType)
{
if (!HasCustomAmmoLimit(ammoType))
{
Log.Error($"{nameof(Player)}.{nameof(ResetAmmoLimit)}(AmmoType): AmmoType.{ammoType} does not have a custom limit.");
return;
}

CustomAmmoLimits.Remove(ammoType);

ItemType itemType = ammoType.GetItemType();
int index = ServerConfigSynchronizer.Singleton.AmmoLimitsSync.FindIndex(x => x.AmmoType == itemType);
MirrorExtensions.SendFakeSyncObject(this, ServerConfigSynchronizer.Singleton.netIdentity, typeof(ServerConfigSynchronizer), writer =>
{
writer.WriteULong(2ul);
writer.WriteUInt(1);
writer.WriteByte((byte)SyncList<ServerConfigSynchronizer.AmmoLimit>.Operation.OP_SET);
writer.WriteInt(index);
writer.WriteAmmoLimit(ServerConfigSynchronizer.Singleton.AmmoLimitsSync[index]);
});
}

/// <summary>
/// Check if the player has a custom limit for a specific <see cref="AmmoType"/>.
/// </summary>
/// <param name="ammoType">The <see cref="AmmoType"/> to check.</param>
/// <returns>If the player has a custom limit for the specific <see cref="AmmoType"/>.</returns>
public bool HasCustomAmmoLimit(AmmoType ammoType) => CustomAmmoLimits.ContainsKey(ammoType);

/// <summary>
/// Gets the maximum amount of an <see cref="ItemCategory"/> the player can hold, based on the armor the player is wearing, as well as server configuration.
/// </summary>
/// <param name="category">The <see cref="ItemCategory"/> to check.</param>
/// <param name="ignoreArmor">If the method should ignore the armor the player is wearing.</param>
/// <returns>The maximum amount of items in the category that the player can hold.</returns>
public int GetCategoryLimit(ItemCategory category) =>
InventorySystem.Configs.InventoryLimits.GetCategoryLimit(category, referenceHub);
public sbyte GetCategoryLimit(ItemCategory category, bool ignoreArmor = false)
{
int index = InventorySystem.Configs.InventoryLimits.StandardCategoryLimits.Where(x => x.Value >= 0).OrderBy(x => x.Key).ToList().FindIndex(x => x.Key == category);

if (ignoreArmor && index != -1)
{
if (CustomCategoryLimits.TryGetValue(category, out sbyte customLimit))
return customLimit;

return ServerConfigSynchronizer.Singleton.CategoryLimits[index];
}

sbyte limit = InventorySystem.Configs.InventoryLimits.GetCategoryLimit(category, referenceHub);

return limit == -1 ? (sbyte)1 : limit;
}

/// <summary>
/// Set the maximum amount of an <see cref="ItemCategory"/> the player can hold. Only works with <see cref="ItemCategory.Keycard"/>, <see cref="ItemCategory.Medical"/>, <see cref="ItemCategory.Firearm"/>, <see cref="ItemCategory.Grenade"/> and <see cref="ItemCategory.SCPItem"/>.
/// This limit will scale with the armor the player is wearing.
/// For armor category limits, see <see cref="Armor.CategoryLimits"/>.
/// </summary>
/// <param name="category">The <see cref="ItemCategory"/> to check.</param>
/// <param name="limit">The <see cref="int"/> number that will define the new limit.</param>
public void SetCategoryLimit(ItemCategory category, sbyte limit)
{
int index = InventorySystem.Configs.InventoryLimits.StandardCategoryLimits.Where(x => x.Value >= 0).OrderBy(x => x.Key).ToList().FindIndex(x => x.Key == category);

if (index == -1)
{
Log.Error($"{nameof(Player)}.{nameof(SetCategoryLimit)}(ItemCategory, sbyte): Cannot set category limit for ItemCategory.{category}.");
return;
}

CustomCategoryLimits[category] = limit;

MirrorExtensions.SendFakeSyncObject(this, ServerConfigSynchronizer.Singleton.netIdentity, typeof(ServerConfigSynchronizer), writer =>
{
writer.WriteULong(1ul);
writer.WriteUInt(1);
writer.WriteByte((byte)SyncList<sbyte>.Operation.OP_SET);
writer.WriteInt(index);
writer.WriteSByte(limit);
});
}

/// <summary>
/// Reset a custom <see cref="ItemCategory"/> limit. Only works with <see cref="ItemCategory.Keycard"/>, <see cref="ItemCategory.Medical"/>, <see cref="ItemCategory.Firearm"/>, <see cref="ItemCategory.Grenade"/> and <see cref="ItemCategory.SCPItem"/>.
/// </summary>
/// <param name="category">The <see cref="ItemCategory"/> of the category to reset.</param>
public void ResetCategoryLimit(ItemCategory category)
{
int index = InventorySystem.Configs.InventoryLimits.StandardCategoryLimits.Where(x => x.Value >= 0).OrderBy(x => x.Key).ToList().FindIndex(x => x.Key == category);

if (index == -1)
{
Log.Error($"{nameof(Player)}.{nameof(ResetCategoryLimit)}(ItemCategory, sbyte): Cannot reset category limit for ItemCategory.{category}.");
return;
}

if (!HasCustomCategoryLimit(category))
{
Log.Error($"{nameof(Player)}.{nameof(ResetCategoryLimit)}(ItemCategory): ItemCategory.{category} does not have a custom limit.");
return;
}

CustomCategoryLimits.Remove(category);

MirrorExtensions.SendFakeSyncObject(this, ServerConfigSynchronizer.Singleton.netIdentity, typeof(ServerConfigSynchronizer), writer =>
{
writer.WriteULong(1ul);
writer.WriteUInt(1);
writer.WriteByte((byte)SyncList<sbyte>.Operation.OP_SET);
writer.WriteInt(index);
writer.WriteSByte(ServerConfigSynchronizer.Singleton.CategoryLimits[index]);
});
}

/// <summary>
/// Check if the player has a custom limit for a specific <see cref="ItemCategory"/>.
/// </summary>
/// <param name="category">The <see cref="ItemCategory"/> to check.</param>
/// <returns>If the player has a custom limit for the specific <see cref="ItemCategory"/>.</returns>
public bool HasCustomCategoryLimit(ItemCategory category) => CustomCategoryLimits.ContainsKey(category);

/// <summary>
/// Adds an item of the specified type with default durability(ammo/charge) and no mods to the player's inventory.
Expand Down
2 changes: 1 addition & 1 deletion EXILED/Exiled.API/Features/Ragdoll.cs
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ public class Ragdoll : IWrapper<BasicRagdoll>, IWorldSpace
/// <summary>
/// A <see cref="Dictionary{TKey,TValue}"/> containing all known <see cref="BasicRagdoll"/>s and their corresponding <see cref="Ragdoll"/>.
/// </summary>
internal static readonly Dictionary<BasicRagdoll, Ragdoll> BasicRagdollToRagdoll = new(250);
internal static readonly Dictionary<BasicRagdoll, Ragdoll> BasicRagdollToRagdoll = new(250, new ComponentsEqualityComparer());

/// <summary>
/// Initializes a new instance of the <see cref="Ragdoll"/> class.
Expand Down
5 changes: 5 additions & 0 deletions EXILED/Exiled.API/Features/Recontainer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,11 @@ public static class Recontainer
/// </summary>
public static bool IsCassieBusy => Base.CassieBusy;

/// <summary>
/// Gets a value about how many generator have been activated.
/// </summary>
public static int EngagedGeneratorCount => Base._prevEngaged;

/// <summary>
/// Gets or sets a value indicating whether the containment zone is open.
/// </summary>
Expand Down
16 changes: 16 additions & 0 deletions EXILED/Exiled.API/Features/Roles/FpcRole.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,11 @@
namespace Exiled.API.Features.Roles
{
using System.Collections.Generic;
using System.Reflection;

using Exiled.API.Features.Pools;

using HarmonyLib;
using PlayerRoles;
using PlayerRoles.FirstPersonControl;

Expand All @@ -24,6 +26,7 @@ namespace Exiled.API.Features.Roles
/// </summary>
public abstract class FpcRole : Role
{
private static FieldInfo enableFallDamageField;
private bool isUsingStamina = true;

/// <summary>
Expand Down Expand Up @@ -55,6 +58,19 @@ public RelativePosition RelativePosition
set => FirstPersonController.FpcModule.Motor.ReceivedPosition = value;
}

/// <summary>
/// Gets or sets a value indicating whether if the player should get <see cref="Enums.DamageType.Falldown"/> damage.
/// </summary>
public bool IsFallDamageEnable
{
get => FirstPersonController.FpcModule.Motor._enableFallDamage;
set
{
enableFallDamageField ??= AccessTools.Field(typeof(FpcMotor), nameof(FpcMotor._enableFallDamage));
enableFallDamageField.SetValue(FirstPersonController.FpcModule.Motor, value);
}
}

/// <summary>
/// Gets or sets a value indicating whether if a rotation is detected on the player.
/// </summary>
Expand Down
2 changes: 1 addition & 1 deletion EXILED/Exiled.API/Features/Roles/Scp049Role.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ namespace Exiled.API.Features.Roles
/// <summary>
/// Defines a role that represents SCP-049.
/// </summary>
public class Scp049Role : FpcRole, ISubroutinedScpRole, IHumeShieldRole
public class Scp049Role : FpcRole, ISubroutinedScpRole, IHumeShieldRole, ISpawnableScp
{
/// <summary>
/// Initializes a new instance of the <see cref="Scp049Role"/> class.
Expand Down
3 changes: 2 additions & 1 deletion EXILED/Exiled.API/Features/Roles/Scp079Role.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ namespace Exiled.API.Features.Roles
using MapGeneration;
using Mirror;
using PlayerRoles;
using PlayerRoles.PlayableScps;
using PlayerRoles.PlayableScps.Scp079;
using PlayerRoles.PlayableScps.Scp079.Cameras;
using PlayerRoles.PlayableScps.Scp079.Pinging;
Expand All @@ -31,7 +32,7 @@ namespace Exiled.API.Features.Roles
/// <summary>
/// Defines a role that represents SCP-079.
/// </summary>
public class Scp079Role : Role, ISubroutinedScpRole
public class Scp079Role : Role, ISubroutinedScpRole, ISpawnableScp
{
/// <summary>
/// Initializes a new instance of the <see cref="Scp079Role"/> class.
Expand Down
Loading

0 comments on commit 2f58ca2

Please sign in to comment.