Skip to content

Commit

Permalink
[Master] SpawningRagdoll Fix & ChangingItem Fix (#2748)
Browse files Browse the repository at this point in the history
* remove log line from Verified Patch

* fix changing item & spawning ragdoll

* spawning ragdoll event changes

* fix summary & revert breaking change
  • Loading branch information
xNexusACS authored Jul 21, 2024
1 parent 5031f5c commit 1bd2916
Show file tree
Hide file tree
Showing 3 changed files with 34 additions and 91 deletions.
2 changes: 1 addition & 1 deletion Exiled.Events/EventArgs/Player/ChangingItemEventArgs.cs
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ public Item Item
get => newItem;
set
{
if (!Player.Inventory.UserInventory.Items.TryGetValue(value.Serial, out _))
if (value is not null && !Player.Inventory.UserInventory.Items.TryGetValue(value.Serial, out _))
throw new InvalidOperationException("ev.NewItem cannot be set to an item they do not have.");

newItem = value;
Expand Down
5 changes: 1 addition & 4 deletions Exiled.Events/EventArgs/Player/SpawningRagdollEventArgs.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,10 @@
namespace Exiled.Events.EventArgs.Player
{
using API.Features;

using Interfaces;

using PlayerRoles;
using PlayerRoles.Ragdolls;
using PlayerStatsSystem;

using UnityEngine;

/// <summary>
Expand Down Expand Up @@ -91,7 +88,7 @@ public string Nickname
public RagdollData Info { get; set; }

/// <summary>
/// Gets or sets the ragdoll's <see cref="PlayerStatsSystem.DamageHandlerBase" />.
/// Gets or sets the ragdoll's <see cref="PlayerStatsSystem.DamageHandlerBase"/>.
/// </summary>
public DamageHandlerBase DamageHandlerBase
{
Expand Down
118 changes: 32 additions & 86 deletions Exiled.Events/Patches/Events/Player/SpawningRagdoll.cs
Original file line number Diff line number Diff line change
Expand Up @@ -39,118 +39,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;
int index = newInstructions.FindIndex(instruction => instruction.Calls(PropertySetter(typeof(BasicRagdoll), nameof(BasicRagdoll.NetworkInfo))));

// remove
// "basicRagdoll.NetworkInfo = new RagdollData(owner, handler, transform.localPosition, transform.localRotation);"
newInstructions.RemoveRange(index, 9);

// 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),
new(OpCodes.Brtrue_S, continueLabel),

// 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.Pop),
new(OpCodes.Call, Method(typeof(Object), nameof(Object.Destroy), new[] { typeof(Object) })),
new(OpCodes.Ldnull),
new(OpCodes.Ret),

// new Vector3()
new(OpCodes.Ldloca_S, targetScale.LocalIndex),
new(OpCodes.Initobj, typeof(Vector3)),

// 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 +119,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

0 comments on commit 1bd2916

Please sign in to comment.