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

feat: Features.CustomStats #130

Open
wants to merge 21 commits into
base: dev
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
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
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
// </copyright>
// -----------------------------------------------------------------------

namespace Exiled.API.Features
namespace Exiled.API.Features.CustomStats
{
using PlayerStatsSystem;

Expand Down
79 changes: 79 additions & 0 deletions EXILED/Exiled.API/Features/CustomStats/CustomHumeShieldStat.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
// -----------------------------------------------------------------------
// <copyright file="CustomHumeShieldStat.cs" company="ExMod Team">
// Copyright (c) ExMod Team. All rights reserved.
// Licensed under the CC BY-SA 3.0 license.
// </copyright>
// -----------------------------------------------------------------------

namespace Exiled.API.Features.CustomStats
{
using Mirror;
using PlayerRoles.PlayableScps.HumeShield;
using PlayerStatsSystem;
using UnityEngine;
using Utils.Networking;

/// <summary>
/// A custom version of <see cref="HumeShieldStat"/> which allows the player's max amount of HumeShield to be changed.
/// </summary>
public class CustomHumeShieldStat : HumeShieldStat
{
/// <inheritdoc />
public override float MaxValue => CustomMaxValue == -1 ? base.MaxValue : CustomMaxValue;

/// <summary>
/// Gets or sets the multiplier for gaining HumeShield.
/// </summary>
public float ShieldRegenerationMultiplier { get; set; } = 1;

/// <summary>
/// Gets or sets the maximum amount of HumeShield the player can have.
/// </summary>
public float CustomMaxValue { get; set; } = -1;

private float ShieldRegeneration => TryGetHsModule(out HumeShieldModuleBase controller) ? controller.HsRegeneration * ShieldRegenerationMultiplier : 0;

/// <inheritdoc/>
public override void Update()
{
if (MaxValue == -1 && ShieldRegenerationMultiplier is 1)
{
base.Update();
return;
}

if (!NetworkServer.active)
return;

if (_valueDirty)
{
new SyncedStatMessages.StatMessage()
{
Stat = this,
SyncedValue = CurValue,
}.SendToHubsConditionally(CanReceive);
_lastSent = CurValue;
_valueDirty = false;
}

if (ShieldRegeneration == 0)
louis1706 marked this conversation as resolved.
Show resolved Hide resolved
return;

float delta = ShieldRegeneration * Time.deltaTime;

if (delta > 0)
{
if (CurValue >= MaxValue)
return;

CurValue = Mathf.MoveTowards(CurValue, MaxValue, delta);
return;
}

if (CurValue <= 0)
return;

CurValue += delta;
}
}
}
56 changes: 56 additions & 0 deletions EXILED/Exiled.API/Features/CustomStats/CustomStaminaStat.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
// -----------------------------------------------------------------------
// <copyright file="CustomStaminaStat.cs" company="ExMod Team">
// Copyright (c) ExMod Team. All rights reserved.
// Licensed under the CC BY-SA 3.0 license.
// </copyright>
// -----------------------------------------------------------------------

namespace Exiled.API.Features.CustomStats
{
using Mirror;
using PlayerStatsSystem;
using UnityEngine;

/// <summary>
/// A custom version of <see cref="StaminaStat"/> which allows the player's maximum amount of Stamina to be changed.
/// </summary>
public class CustomStaminaStat : StaminaStat
{
/// <inheritdoc/>
public override float MaxValue => CustomMaxValue == -1 ? base.MaxValue : CustomMaxValue;

/// <summary>
/// Gets or sets the maximum amount of stamina the player will have.
/// </summary>
public float CustomMaxValue { get; set; } = -1;

/// <summary>
/// Clamps a float to fit the current stamina bar.
/// </summary>
/// <param name="value">The value to clamp.</param>
/// <returns>The clamped num.</returns>
public float Clamp(float value) => CustomMaxValue == -1 ? Mathf.Clamp01(value) : Mathf.Clamp(value, 0, MaxValue);

/// <summary>
/// Overiding NW Method to sync Player percentage of Stamina.
/// </summary>
/// <param name="writer">The writer.</param>
public override void WriteValue(NetworkWriter writer)
{
if (CustomMaxValue == -1)
{
base.WriteValue(writer);
return;
}

writer.WriteByte(ToByte(CurValue / CustomMaxValue));
}

/// <summary>
/// Overriding NW Method to sync Player percentage of Stamina.
/// </summary>
/// <param name="reader">The reader.</param>
/// <returns>the float value sync to server.</returns>
public override float ReadValue(NetworkReader reader) => CustomMaxValue == -1 ? base.ReadValue(reader) : CurValue * CustomMaxValue;
}
}
36 changes: 34 additions & 2 deletions EXILED/Exiled.API/Features/Player.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ namespace Exiled.API.Features
using DamageHandlers;
using Enums;
using Exiled.API.Features.Core.Interfaces;
using Exiled.API.Features.CustomStats;
using Exiled.API.Features.Doors;
using Exiled.API.Features.Hazards;
using Exiled.API.Features.Items;
Expand Down Expand Up @@ -95,7 +96,9 @@ public class Player : TypeCastObject<Player>, IEntity, IWorldSpace
private readonly HashSet<EActor> componentsInChildren = new();

private ReferenceHub referenceHub;
private CustomHumeShieldStat humeShieldStat;
private CustomHealthStat healthStat;
private CustomStaminaStat staminaStat;
private Role role;

/// <summary>
Expand Down Expand Up @@ -177,6 +180,8 @@ private set
CameraTransform = value.PlayerCameraReference;

value.playerStats._dictionarizedTypes[typeof(HealthStat)] = value.playerStats.StatModules[Array.IndexOf(PlayerStats.DefinedModules, typeof(HealthStat))] = healthStat = new CustomHealthStat { Hub = value };
value.playerStats._dictionarizedTypes[typeof(HumeShieldStat)] = value.playerStats.StatModules[Array.IndexOf(PlayerStats.DefinedModules, typeof(HumeShieldStat))] = humeShieldStat = new CustomHumeShieldStat { Hub = value };
value.playerStats._dictionarizedTypes[typeof(StaminaStat)] = value.playerStats.StatModules[Array.IndexOf(PlayerStats.DefinedModules, typeof(StaminaStat))] = staminaStat = new CustomStaminaStat { Hub = value };
}
}

Expand Down Expand Up @@ -930,6 +935,24 @@ public float HumeShield
set => HumeShieldStat.CurValue = value;
}

/// <summary>
/// Gets or sets the players maximum Hume Shield.
/// </summary>
public float MaxHumeShield
{
get => humeShieldStat.MaxValue;
set => humeShieldStat.CustomMaxValue = value;
}

/// <summary>
/// Gets or sets the players multiplier for gaining HumeShield.
/// </summary>
public float HumeShieldRegenerationMultiplier
{
get => humeShieldStat.ShieldRegenerationMultiplier;
set => humeShieldStat.ShieldRegenerationMultiplier = value;
}

/// <summary>
/// Gets a <see cref="IEnumerable{T}"/> of all active Artificial Health processes on the player.
/// </summary>
Expand All @@ -938,7 +961,7 @@ public float HumeShield
/// <summary>
/// Gets the player's <see cref="PlayerStatsSystem.HumeShieldStat"/>.
/// </summary>
public HumeShieldStat HumeShieldStat => ReferenceHub.playerStats.GetModule<HumeShieldStat>();
public HumeShieldStat HumeShieldStat => humeShieldStat;

/// <summary>
/// Gets or sets the item in the player's hand. Value will be <see langword="null"/> if the player is not holding anything.
Expand Down Expand Up @@ -970,7 +993,7 @@ public Item CurrentItem
/// <summary>
/// Gets the <see cref="StaminaStat"/> class.
/// </summary>
public StaminaStat StaminaStat => ReferenceHub.playerStats.GetModule<StaminaStat>();
public StaminaStat StaminaStat => staminaStat;

/// <summary>
/// Gets or sets the amount of stamina the player has.
Expand All @@ -982,6 +1005,15 @@ public float Stamina
set => StaminaStat.CurValue = value;
}

/// <summary>
/// Gets or sets the players maximum stamina.
/// </summary>
public float MaxStamina
{
get => staminaStat.MaxValue;
set => staminaStat.CustomMaxValue = value;
}

/// <summary>
/// Gets a value indicating whether the staff bypass is enabled.
/// </summary>
Expand Down
47 changes: 47 additions & 0 deletions EXILED/Exiled.Events/Patches/Generic/FixStaminaStat.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
// -----------------------------------------------------------------------
// <copyright file="FixStaminaStat.cs" company="ExMod Team">
// Copyright (c) ExMod Team. All rights reserved.
// Licensed under the CC BY-SA 3.0 license.
// </copyright>
// -----------------------------------------------------------------------

namespace Exiled.Events.Patches.Generic
{
using System.Collections.Generic;
using System.Reflection.Emit;

using Exiled.API.Features.CustomStats;
using Exiled.API.Features.Pools;
using HarmonyLib;
using PlayerRoles.FirstPersonControl;
using PlayerStatsSystem;

using static HarmonyLib.AccessTools;

/// <summary>
/// Fix for <see cref="CustomStaminaStat"/>.
/// </summary>
[HarmonyPatch(typeof(FpcStateProcessor), nameof(FpcStateProcessor.UpdateMovementState))]
internal static class FixStaminaStat
{
private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions, ILGenerator generator)
{
List<CodeInstruction> newInstructions = ListPool<CodeInstruction>.Pool.Get(instructions);

int index = newInstructions.FindLastIndex(i => i.opcode == OpCodes.Ldc_R4);
newInstructions.RemoveAt(index);

newInstructions.InsertRange(index, new CodeInstruction[]
{
new(OpCodes.Ldarg_0),
new(OpCodes.Ldfld, Field(typeof(FpcStateProcessor), nameof(FpcStateProcessor._stat))),
new(OpCodes.Callvirt, PropertyGetter(typeof(StaminaStat), nameof(StaminaStat.MaxValue))),
});

for (int z = 0; z < newInstructions.Count; z++)
yield return newInstructions[z];

ListPool<CodeInstruction>.Pool.Return(newInstructions);
}
}
}
Loading