forked from ExMod-Team/EXILED
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathChangingWearables.cs
More file actions
120 lines (92 loc) · 4.79 KB
/
Copy pathChangingWearables.cs
File metadata and controls
120 lines (92 loc) · 4.79 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
// -----------------------------------------------------------------------
// <copyright file="ChangingWearables.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.Events.Player
{
using System.Collections.Generic;
using System.Reflection.Emit;
using Exiled.API.Enums;
using Exiled.API.Extensions;
using Exiled.API.Features;
using Exiled.API.Features.Pools;
using Exiled.Events.Attributes;
using Exiled.Events.EventArgs.Player;
using HarmonyLib;
using Mirror;
using PlayerRoles.FirstPersonControl.Thirdperson.Subcontrollers.Wearables;
using static HarmonyLib.AccessTools;
/// <summary>
/// Patches <see cref="WearableSync.OverrideWearables"/>
/// to add <see cref="Handlers.Player.ChangingWearables"/> event.
/// </summary>
[EventPatch(typeof(Handlers.Player), nameof(Handlers.Player.ChangingWearables))]
[HarmonyPatch(typeof(WearableSync), nameof(WearableSync.OverrideWearables))]
internal static class ChangingWearables
{
private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions, ILGenerator generator)
{
List<CodeInstruction> newInstructions = ListPool<CodeInstruction>.Pool.Get(instructions);
int index = newInstructions.FindIndex(x => x.opcode == OpCodes.Ldarg_1);
LocalBuilder ev = generator.DeclareLocal(typeof(ChangingWearablesEventArgs));
Label returnLabel = generator.DefineLabel();
newInstructions[^1].labels.Add(returnLabel);
newInstructions.RemoveAt(index);
newInstructions.InsertRange(index, new CodeInstruction[]
{
// Player.Get(hub)
new(OpCodes.Ldarg_0),
new(OpCodes.Call, Method(typeof(Player), nameof(Player.Get), new[] { typeof(ReferenceHub) })),
// newWearables
new(OpCodes.Ldarg_1),
// true
new(OpCodes.Ldc_I4_1),
// ChangingWearablesEventArgs ev = new(Player.Get(hub), newWearables, true);
new(OpCodes.Newobj, GetDeclaredConstructors(typeof(ChangingWearablesEventArgs))[0]),
new(OpCodes.Dup),
new(OpCodes.Dup),
new(OpCodes.Stloc_S, ev.LocalIndex),
// Handlers.Player.OnChangingWearables(ev);
new(OpCodes.Call, Method(typeof(Handlers.Player), nameof(Handlers.Player.OnChangingWearables))),
// if (!ev.IsAllowed)
// return;
new(OpCodes.Callvirt, PropertyGetter(typeof(ChangingWearablesEventArgs), nameof(ChangingWearablesEventArgs.IsAllowed))),
new(OpCodes.Brfalse_S, returnLabel),
// push ev.NewWearables to stack for check
new(OpCodes.Ldloc_S, ev.LocalIndex),
new(OpCodes.Callvirt, PropertyGetter(typeof(ChangingWearablesEventArgs), nameof(ChangingWearablesEventArgs.NewWearables))),
});
int offset = -4;
index = newInstructions.FindLastIndex(x => x.opcode == OpCodes.Ldarg_0) + offset;
newInstructions.RemoveRange(index, 4);
newInstructions.InsertRange(index, new CodeInstruction[]
{
// newWearables = ChangingWearables.WriteArmor(ev);
new(OpCodes.Ldloc_S, ev.LocalIndex),
new(OpCodes.Call, Method(typeof(ChangingWearables), nameof(WriteArmor))),
new(OpCodes.Starg_S, 1),
});
for (int z = 0; z < newInstructions.Count; z++)
yield return newInstructions[z];
ListPool<CodeInstruction>.Pool.Return(newInstructions);
}
private static WearableElements WriteArmor(ChangingWearablesEventArgs ev)
{
WearableElementType value = ev.NewWearables;
if (value is WearableElementType.None)
return WearableElements.None;
if (value.HasFlagFast(WearableElementType.ArmorDefault))
{
ItemType displayedArmor = value.HasFlagFast(WearableElementType.ArmorLight) ? ItemType.ArmorLight :
value.HasFlagFast(WearableElementType.ArmorCombat) ? ItemType.ArmorCombat :
value.HasFlagFast(WearableElementType.ArmorHeavy) ? ItemType.ArmorHeavy :
ev.Player.CurrentArmor?.Type ?? ItemType.None;
WearableSync.PayloadWriter.WriteSByte((sbyte)displayedArmor);
value &= ~WearableElementType.ArmorLight | WearableElementType.ArmorCombat | WearableElementType.ArmorHeavy;
}
return (WearableElements)value;
}
}
}