Skip to content
This repository has been archived by the owner on Jan 19, 2025. It is now read-only.

[Resonance] Alpha 18 Fixes #2747

Merged
merged 5 commits into from
Jul 21, 2024
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
2 changes: 1 addition & 1 deletion Exiled.Events/EventArgs/Player/SpawningRagdollEventArgs.cs
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ public string Nickname
/// </summary>
public DamageHandler DamageHandlerBase
{
get => damageHandler ??= new(Player, Info.Handler);
get => damageHandler ??= new DamageHandler(Player, Info.Handler);
set
{
Info = new RagdollData(Player.ReferenceHub, value, Role, Position, Rotation, Nickname, CreationTime);
Expand Down
60 changes: 16 additions & 44 deletions Exiled.Events/EventArgs/Scp3114/StranglingEventArgs.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,68 +8,40 @@
namespace Exiled.Events.EventArgs.Scp3114
{
using Exiled.API.Features;
using Exiled.API.Features.Roles;
using Exiled.Events.EventArgs.Interfaces;

using PlayerRoles.PlayableScps.Scp3114;

using HumanRole = PlayerRoles.HumanRole;
using Scp3114Role = API.Features.Roles.Scp3114Role;

/// <summary>
/// Contains all information before strangling a player.
/// </summary>
public class StranglingEventArgs : IScp3114Event, IDeniableEvent
{
private readonly Scp3114Strangle strangle;
private Player target = null;

/// <summary>
/// Initializes a new instance of the <see cref="StranglingEventArgs"/> class.
/// Initializes a new instance of the <see cref="StranglingEventArgs" /> class.
/// </summary>
/// <param name="strangle">The <see cref="Scp3114Strangle"/> instance.</param>
/// <param name="player">The <see cref="API.Features.Player"/> triggering the event.</param>
/// <param name="target">The <see cref="API.Features.Player"/> being targeted.</param>
public StranglingEventArgs(Scp3114Strangle strangle, Player player, Scp3114Strangle.StrangleTarget target)
/// <param name="player"><see cref="Player"/>.</param>
/// <param name="target"><see cref="Target"/>.</param>
/// <param name="isAllowed"><see cref="IsAllowed"/>.</param>
public StranglingEventArgs(Player player, Player target, bool isAllowed = true)
{
this.strangle = strangle;
Scp3114 = player.Role.As<Scp3114Role>();
Player = player;
Target = Player.Get(target.Target);
StrangleTarget = target;
Scp3114 = Player.Role.As<Scp3114Role>();
Target = target;
IsAllowed = isAllowed;
}

/// <inheritdoc />
public Scp3114Role Scp3114 { get; }

/// <inheritdoc />
public Player Player
{
get => target;
set
{
target = value;

if (!target)
{
StrangleTarget = default(Scp3114Strangle.StrangleTarget);
return;
}
/// <inheritdoc/>
public Player Player { get; }

StrangleTarget = new(target.ReferenceHub, strangle.GetStranglePosition(target.ReferenceHub.roleManager.CurrentRole as HumanRole), Player.Position);
}
}
/// <inheritdoc/>
public Scp3114Role Scp3114 { get; }

/// <summary>
/// Gets the target player.
/// Gets the <see cref="Player"/> being strangled.
/// </summary>
public Player Target { get; }

/// <summary>
/// Gets the <see cref="Scp3114Strangle.StrangleTarget"/>. This value is updated when <see cref="Target"/> is changed.
/// </summary>
public Scp3114Strangle.StrangleTarget? StrangleTarget { get; private set; }

/// <inheritdoc />
public bool IsAllowed { get; set; } = true;
/// <inheritdoc/>
public bool IsAllowed { get; set; }
}
}
32 changes: 22 additions & 10 deletions Exiled.Events/Patches/Events/Player/Healing.cs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstructi
List<CodeInstruction> newInstructions = ListPool<CodeInstruction>.Pool.Get(instructions);

Label continueLabel = generator.DefineLabel();
Label skip1 = generator.DefineLabel();
Label skip2 = generator.DefineLabel();

LocalBuilder ev = generator.DeclareLocal(typeof(HealingEventArgs));
LocalBuilder player = generator.DeclareLocal(typeof(Player));
Expand All @@ -48,49 +50,59 @@ private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstructi
new(OpCodes.Stloc_S, lastHealth.LocalIndex),

// player = Player.Get(this.Hub);
// if (player is null) skip
new(OpCodes.Ldarg_0),
new(OpCodes.Callvirt, AccessTools.PropertyGetter(typeof(HealthStat), nameof(HealthStat.Hub))),
new(OpCodes.Call, AccessTools.Method(typeof(Player), nameof(Player.Get), new Type[] { typeof(ReferenceHub) })),
new(OpCodes.Call, AccessTools.Method(typeof(Player), nameof(Player.Get), new[] { typeof(ReferenceHub) })),
new(OpCodes.Dup),
new(OpCodes.Stloc_S, player.LocalIndex),
new(OpCodes.Brfalse_S, skip1),

// HealingEventArgs ev = new(Player, amount)
// HealingEventArgs args = new(player, amount)
new(OpCodes.Ldloc_S, player.LocalIndex),
new(OpCodes.Ldarg_1),
new(OpCodes.Newobj, AccessTools.GetDeclaredConstructors(typeof(HealingEventArgs))[0]),
new(OpCodes.Dup),
new(OpCodes.Dup),
new(OpCodes.Stloc_S, ev.LocalIndex),

// OnHealing(ev)
// Player::OnHealing(args)
new(OpCodes.Call, AccessTools.Method(typeof(Handlers.Player), nameof(Handlers.Player.OnHealing))),

// if (!ev.IsAllowed)
// return
// if (!args.IsAllowed) return
new(OpCodes.Callvirt, AccessTools.PropertyGetter(typeof(HealingEventArgs), nameof(HealingEventArgs.IsAllowed))),
new(OpCodes.Brtrue_S, continueLabel),
new(OpCodes.Pop),
new(OpCodes.Pop),
new(OpCodes.Ret),

// healAmount = ev.Amount
// healAmount = args.Amount
new CodeInstruction(OpCodes.Ldloc_S, ev.LocalIndex).WithLabels(continueLabel),
new(OpCodes.Callvirt, AccessTools.PropertyGetter(typeof(HealingEventArgs), nameof(HealingEventArgs.Amount))),
new(OpCodes.Starg_S, 1),

new CodeInstruction(OpCodes.Nop).WithLabels(skip1),
});

newInstructions[newInstructions.Count - 1].labels.Add(skip2);

newInstructions.InsertRange(newInstructions.Count - 1, new[]
{
// HealedEventArgs ev = new(Player, lastAmount)
// if (player is null) skip
new(OpCodes.Ldloc_S, player.LocalIndex),
new(OpCodes.Brfalse_S, skip2),

// HealedEventArgs args = new(player, lastAmount)
new(OpCodes.Ldloc_S, player.LocalIndex),
new(OpCodes.Ldloc_S, lastHealth.LocalIndex),
new(OpCodes.Newobj, AccessTools.GetDeclaredConstructors(typeof(HealedEventArgs))[0]),

// OnHealed(ev)
// Player::OnHealed(args)
new CodeInstruction(OpCodes.Call, AccessTools.Method(typeof(Handlers.Player), nameof(Handlers.Player.OnHealed))),
});

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

ListPool<CodeInstruction>.Pool.Return(newInstructions);
}
Expand Down
121 changes: 32 additions & 89 deletions Exiled.Events/Patches/Events/Player/SpawningRagdoll.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,9 @@ namespace Exiled.Events.Patches.Events.Player
using Exiled.API.Features;
using Exiled.Events.Attributes;
using Exiled.Events.EventArgs.Player;

using HarmonyLib;
using PlayerRoles.Ragdolls;

using PlayerStatsSystem;

using UnityEngine;

using static HarmonyLib.AccessTools;
Expand All @@ -39,118 +36,66 @@ private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstructi
{
List<CodeInstruction> newInstructions = ListPool<CodeInstruction>.Pool.Get(instructions);

Label ret = generator.DefineLabel();
Label continueLabel = generator.DefineLabel();

LocalBuilder ev = generator.DeclareLocal(typeof(SpawningRagdollEventArgs));
LocalBuilder newRagdoll = generator.DeclareLocal(typeof(Ragdoll));
LocalBuilder localScale = generator.DeclareLocal(typeof(Vector3));
LocalBuilder evScale = generator.DeclareLocal(typeof(Vector3));
LocalBuilder targetScale = generator.DeclareLocal(typeof(Vector3));

int offset = 0;
int index = newInstructions.FindIndex(instruction => instruction.opcode == OpCodes.Ldloc_1) + offset;

// remove
// "basicRagdoll.NetworkInfo = new RagdollData(owner, handler, transform.localPosition, transform.localRotation);"
newInstructions.RemoveRange(index, 9);
int index = newInstructions.FindIndex(instruction => instruction.Calls(PropertySetter(typeof(BasicRagdoll), nameof(BasicRagdoll.NetworkInfo))));

// replace with
newInstructions.InsertRange(index, new[]
{
// hub
new CodeInstruction(OpCodes.Ldarg_0),

// handler
new(OpCodes.Ldarg_1),

// ragdollRole.transform.localPosition
new(OpCodes.Ldloc_2),
new(OpCodes.Callvirt, PropertyGetter(typeof(Transform), nameof(Transform.localPosition))),

// ragdollRole.transform.localRotation
new(OpCodes.Ldloc_2),
new(OpCodes.Callvirt, PropertyGetter(typeof(Transform), nameof(Transform.localRotation))),

// new RagdollInfo(ReferenceHub, DamageHandlerBase, Vector3, Quaternion)
new(OpCodes.Newobj, GetDeclaredConstructors(typeof(RagdollData))[0]),

// true
new(OpCodes.Ldc_I4_1),

// SpawningRagdollEventArgs ev = new(RagdollInfo, DamageHandlerBase, bool)
// SpawningRagdollEventArgs args = new(RagdollInfo, bool)
new(OpCodes.Newobj, GetDeclaredConstructors(typeof(SpawningRagdollEventArgs))[0]),
new(OpCodes.Dup),
new(OpCodes.Dup),
new(OpCodes.Stloc_S, ev.LocalIndex),

// Player.OnSpawningRagdoll(ev)
// Player::OnSpawningRagdoll(args)
new(OpCodes.Call, Method(typeof(Player), nameof(Player.OnSpawningRagdoll))),

// if (!ev.IsAllowed)
// return;
// if (!args.IsAllowed)
// {
// Object.Destroy(gameObject);
// return null;
// }
new(OpCodes.Callvirt, PropertyGetter(typeof(SpawningRagdollEventArgs), nameof(SpawningRagdollEventArgs.IsAllowed))),
new(OpCodes.Brfalse_S, ret),

// basicRagdoll.NetworkInfo = ev.Info
new(OpCodes.Ldloc_1),
new(OpCodes.Ldloc_S, ev.LocalIndex),
new(OpCodes.Callvirt, PropertyGetter(typeof(SpawningRagdollEventArgs), nameof(SpawningRagdollEventArgs.Info))),
new(OpCodes.Call, PropertySetter(typeof(BasicRagdoll), nameof(BasicRagdoll.NetworkInfo))),
new(OpCodes.Brtrue_S, continueLabel),

// new Vector3()
new(OpCodes.Ldloca_S, targetScale.LocalIndex),
new(OpCodes.Initobj, typeof(Vector3)),
new(OpCodes.Pop),
new(OpCodes.Call, Method(typeof(Object), nameof(Object.Destroy), new[] { typeof(Object) })),
new(OpCodes.Ldnull),
new(OpCodes.Ret),

// localScale = ragdoll.gameObject.transform.localScale
new(OpCodes.Ldloc_1),
// ragdoll transform
new CodeInstruction(OpCodes.Ldloc_1).WithLabels(continueLabel),
new(OpCodes.Callvirt, PropertyGetter(typeof(BasicRagdoll), nameof(BasicRagdoll.gameObject))),
new(OpCodes.Callvirt, PropertyGetter(typeof(GameObject), nameof(GameObject.transform))),

// ragdoll localScale
new(OpCodes.Dup),
new(OpCodes.Callvirt, PropertyGetter(typeof(Transform), nameof(Transform.localScale))),
new(OpCodes.Stloc_S, localScale.LocalIndex),

// evScale = ev.Scale
// SpawningRagdollEventArgs::Scale
new(OpCodes.Ldloc_S, ev.LocalIndex),
new(OpCodes.Callvirt, PropertyGetter(typeof(SpawningRagdollEventArgs), nameof(SpawningRagdollEventArgs.Scale))),
new(OpCodes.Stloc_S, evScale.LocalIndex),

// targetScale.x = evScale.x * localScale.x
new(OpCodes.Ldloca_S, targetScale.LocalIndex),
new(OpCodes.Ldloc_S, evScale.LocalIndex),
new(OpCodes.Ldfld, Field(typeof(Vector3), nameof(Vector3.x))),
new(OpCodes.Ldloc_S, localScale.LocalIndex),
new(OpCodes.Ldfld, Field(typeof(Vector3), nameof(Vector3.x))),
new(OpCodes.Mul),
new(OpCodes.Stfld, Field(typeof(Vector3), nameof(Vector3.x))),

// targetScale.y = evScale.y * localScale.y
new(OpCodes.Ldloca_S, targetScale.LocalIndex),
new(OpCodes.Ldloc_S, evScale.LocalIndex),
new(OpCodes.Ldfld, Field(typeof(Vector3), nameof(Vector3.y))),
new(OpCodes.Ldloc_S, localScale.LocalIndex),
new(OpCodes.Ldfld, Field(typeof(Vector3), nameof(Vector3.y))),
new(OpCodes.Mul),
new(OpCodes.Stfld, Field(typeof(Vector3), nameof(Vector3.y))),

// targetScale.z = evScale.z * localScale.z
new(OpCodes.Ldloca_S, targetScale.LocalIndex),
new(OpCodes.Ldloc_S, evScale.LocalIndex),
new(OpCodes.Ldfld, Field(typeof(Vector3), nameof(Vector3.z))),
new(OpCodes.Ldloc_S, localScale.LocalIndex),
new(OpCodes.Ldfld, Field(typeof(Vector3), nameof(Vector3.z))),
new(OpCodes.Mul),
new(OpCodes.Stfld, Field(typeof(Vector3), nameof(Vector3.z))),

// ragdoll.gameObject.transform.localScale = targetScale
new(OpCodes.Ldloc_1),
new(OpCodes.Callvirt, PropertyGetter(typeof(BasicRagdoll), nameof(BasicRagdoll.gameObject))),
new(OpCodes.Callvirt, PropertyGetter(typeof(GameObject), nameof(GameObject.transform))),
new(OpCodes.Ldloc_S, targetScale.LocalIndex),

// newScale = Vector3::Scale(ragdollScale, SpawningRagdollEventArgs::Scale);
new(OpCodes.Call, Method(typeof(Vector3), nameof(Vector3.Scale), new[] { typeof(Vector3), typeof(Vector3) })),

// BasicRagdoll::gameObject::transform::localScale = targetScale
new(OpCodes.Callvirt, PropertySetter(typeof(Transform), nameof(Transform.localScale))),

// load ragdollInfo
new(OpCodes.Ldloc_S, ev.LocalIndex),
new(OpCodes.Callvirt, PropertyGetter(typeof(SpawningRagdollEventArgs), nameof(SpawningRagdollEventArgs.Info))),
});

newInstructions.InsertRange(newInstructions.Count - 2, new CodeInstruction[]
{
// ev.Player
// SpawningRagdollEventArgs::Player
new(OpCodes.Ldloc_S, ev.LocalIndex),
new(OpCodes.Callvirt, PropertyGetter(typeof(SpawningRagdollEventArgs), nameof(SpawningRagdollEventArgs.Player))),

Expand All @@ -171,10 +116,8 @@ private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstructi
new(OpCodes.Call, Method(typeof(Player), nameof(Player.OnSpawnedRagdoll))),
});

newInstructions[newInstructions.Count - 1].labels.Add(ret);

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

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