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

[Master] SpawningRagdoll Fix & ChangingItem Fix #2748

Merged
merged 4 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/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
Loading