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

fix: ChangingAttachments transpiler #347

Merged
merged 2 commits into from
Dec 27, 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
31 changes: 10 additions & 21 deletions EXILED/Exiled.Events/EventArgs/Item/ChangingAttachmentsEventArgs.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,31 +28,20 @@ public class ChangingAttachmentsEventArgs : IPlayerEvent, IDeniableEvent, IFirea
/// <summary>
/// Initializes a new instance of the <see cref="ChangingAttachmentsEventArgs" /> class.
/// </summary>
/// <param name="player">
/// <inheritdoc cref="Player" />
/// <param name="request">
/// The request received from client.
/// </param>
/// <param name="firearm">
/// <inheritdoc cref="Firearm" />
/// </param>
/// <param name="code">The attachments code.</param>
/// <param name="isAllowed">
/// <inheritdoc cref="IsAllowed" />
/// </param>
public ChangingAttachmentsEventArgs(Player player, InventorySystem.Items.Firearms.Firearm firearm, uint code, bool isAllowed = true)
public ChangingAttachmentsEventArgs(AttachmentsChangeRequest request)
{
Player = player;
Firearm = Item.Get<Firearm>(firearm);
CurrentAttachmentIdentifiers = Firearm.AttachmentIdentifiers;
NewAttachmentIdentifiers = Firearm.FirearmType.GetAttachmentIdentifiers(code).ToList();
CurrentCode = firearm.GetCurrentAttachmentsCode();
NewCode = code;
IsAllowed = isAllowed;
Firearm = Item.Get<Firearm>(request.WeaponSerial);
Player = Firearm.Owner;
NewAttachmentIdentifiers = Firearm.FirearmType.GetAttachmentIdentifiers(request.AttachmentsCode).ToList();
}

/// <summary>
/// Gets the old <see cref="AttachmentIdentifier" />.
/// </summary>
public IEnumerable<AttachmentIdentifier> CurrentAttachmentIdentifiers { get; }
public IEnumerable<AttachmentIdentifier> CurrentAttachmentIdentifiers => Firearm.AttachmentIdentifiers;

/// <summary>
/// Gets or sets the new <see cref="AttachmentIdentifier" />.
Expand All @@ -62,17 +51,17 @@ public ChangingAttachmentsEventArgs(Player player, InventorySystem.Items.Firearm
/// <summary>
/// Gets the <see cref="CurrentAttachmentIdentifiers" /> code.
/// </summary>
public uint CurrentCode { get; }
public uint CurrentCode => Firearm.Base.GetCurrentAttachmentsCode();

/// <summary>
/// Gets the <see cref="NewAttachmentIdentifiers" /> code.
/// </summary>
public uint NewCode { get; }
public uint NewCode => NewAttachmentIdentifiers.GetAttachmentsCode();

/// <summary>
/// Gets or sets a value indicating whether the attachments can be changed.
/// </summary>
public bool IsAllowed { get; set; }
public bool IsAllowed { get; set; } = true;

/// <summary>
/// Gets the <see cref="API.Features.Items.Firearm" /> which is being modified.
Expand Down
74 changes: 26 additions & 48 deletions EXILED/Exiled.Events/Patches/Events/Item/ChangingAttachments.cs
Original file line number Diff line number Diff line change
Expand Up @@ -38,72 +38,50 @@ private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstructi
{
List<CodeInstruction> newInstructions = ListPool<CodeInstruction>.Pool.Get(instructions);

const int offset = -3;
int index = newInstructions.FindLastIndex(instruction => instruction.opcode == OpCodes.Ldc_I4_1) + offset;

LocalBuilder ev = generator.DeclareLocal(typeof(ChangingAttachmentsEventArgs));
LocalBuilder curCode = generator.DeclareLocal(typeof(uint));

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

/*
[] <= Here, right after msg validation.
IL_0039: ldloc.1 // curInstance
IL_003a: ldarg.1 // msg
IL_003b: ldfld unsigned int32 InventorySystem.Items.Firearms.Attachments.AttachmentsChangeRequest::AttachmentsCode
IL_0040: ldc.i4.1
IL_0041: call void InventorySystem.Items.Firearms.Attachments.AttachmentsUtils::ApplyAttachmentsCode(class InventorySystem.Items.Firearms.Firearm, unsigned int32, bool)
*/
int index = newInstructions.FindIndex(i => i.IsLdarg(1)) - 1;
List<Label> jumpLabels = newInstructions[index].ExtractLabels();

newInstructions.InsertRange(
index,
new CodeInstruction[]
{
// curCode = Firearm::GetCurrentAttachmentsCode
new(OpCodes.Ldloc_1),
new(OpCodes.Call, Method(typeof(AttachmentsUtils), nameof(AttachmentsUtils.GetCurrentAttachmentsCode))),
new(OpCodes.Stloc_S, curCode.LocalIndex),

// If the Firearm::GetCurrentAttachmentsCode isn't changed, prevents the method from being executed
new(OpCodes.Ldarg_1),
new(OpCodes.Ldfld, Field(typeof(AttachmentsChangeRequest), nameof(AttachmentsChangeRequest.AttachmentsCode))),
new(OpCodes.Ldloc_S, curCode.LocalIndex),
new(OpCodes.Ceq),
new(OpCodes.Brtrue_S, ret),

// API::Features::Player::Get(NetworkConnection::identity::netId)
new(OpCodes.Ldarg_0),
new(OpCodes.Callvirt, PropertyGetter(typeof(NetworkConnection), nameof(NetworkConnection.identity))),
new(OpCodes.Callvirt, PropertyGetter(typeof(NetworkIdentity), nameof(NetworkIdentity.netId))),
new(OpCodes.Call, Method(typeof(Player), nameof(Player.Get), new[] { typeof(uint) })),

// firearm
new(OpCodes.Ldloc_1),

// AttachmentsChangeRequest::AttachmentsCode
// ev = new ChangingAttachmentsEventArgs(msg);
new(OpCodes.Ldarg_1),
new(OpCodes.Ldfld, Field(typeof(AttachmentsChangeRequest), nameof(AttachmentsChangeRequest.AttachmentsCode))),

// true
new(OpCodes.Ldc_I4_1),

// ChangingAttachmentsEventArgs ev = new ChangingAttachmentsEventArgs(Player, Firearm, uint, bool)
new(OpCodes.Newobj, GetDeclaredConstructors(typeof(ChangingAttachmentsEventArgs))[0]),
new(OpCodes.Dup),
new(OpCodes.Dup),
new(OpCodes.Stloc_S, ev.LocalIndex),
new(OpCodes.Stloc, ev),

// Handlers::Item::OnChangingAttachments(ev)
// Handlers.Item.OnChangingAttachments(ev);
new(OpCodes.Ldloc, ev),
new(OpCodes.Call, Method(typeof(Handlers.Item), nameof(Handlers.Item.OnChangingAttachments))),

// ev.IsAllowed
// if (!ev.IsAllowed) return;
new(OpCodes.Ldloc, ev),
new(OpCodes.Callvirt, PropertyGetter(typeof(ChangingAttachmentsEventArgs), nameof(ChangingAttachmentsEventArgs.IsAllowed))),
new(OpCodes.Brfalse_S, ret),
new(OpCodes.Brfalse_S, returnLabel),

// **AttachmentsChangeRequest = ev::NewCode + curCode - ev::CurrentCode
new(OpCodes.Ldarga_S, 1),
new(OpCodes.Ldloc_S, ev.LocalIndex),
// msg.AttachmentsCode = ev.NewCode;
new(OpCodes.Ldarga, 1),
new(OpCodes.Ldloc, ev),
new(OpCodes.Callvirt, PropertyGetter(typeof(ChangingAttachmentsEventArgs), nameof(ChangingAttachmentsEventArgs.NewCode))),
new(OpCodes.Ldloc_S, curCode.LocalIndex),
new(OpCodes.Add),
new(OpCodes.Ldloc_S, ev.LocalIndex),
new(OpCodes.Callvirt, PropertyGetter(typeof(ChangingAttachmentsEventArgs), nameof(ChangingAttachmentsEventArgs.CurrentCode))),
new(OpCodes.Sub),
new(OpCodes.Stfld, Field(typeof(AttachmentsChangeRequest), nameof(AttachmentsChangeRequest.AttachmentsCode))),
});

newInstructions[newInstructions.Count - 1].labels.Add(ret);
// Prevent if expression from branching over inserted instructions
newInstructions[index].WithLabels(jumpLabels);

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

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