diff --git a/EXILED/Exiled.Events/Patches/Fixes/RemoteAdminNpcCommandAddToDictionaryFix.cs b/EXILED/Exiled.Events/Patches/Fixes/RemoteAdminNpcCommandAddToDictionaryFix.cs new file mode 100644 index 000000000..cb7b867f7 --- /dev/null +++ b/EXILED/Exiled.Events/Patches/Fixes/RemoteAdminNpcCommandAddToDictionaryFix.cs @@ -0,0 +1,70 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) ExMod Team. All rights reserved. +// Licensed under the CC BY-SA 3.0 license. +// +// ----------------------------------------------------------------------- + +namespace Exiled.Events.Patches.Fixes +{ + using System.Collections.Generic; + using System.Reflection; + using System.Reflection.Emit; + + using CommandSystem.Commands.RemoteAdmin.Dummies; + using Exiled.API.Features; + using Exiled.API.Features.Pools; + using GameCore; + using HarmonyLib; + using UnityEngine; + + using static HarmonyLib.AccessTools; + + /// + /// Fix to add created via RA to the . + /// + [HarmonyPatch(typeof(SpawnDummyCommand), nameof(SpawnDummyCommand.Execute))] + internal static class RemoteAdminNpcCommandAddToDictionaryFix + { + private static IEnumerable Transpiler(IEnumerable instructions, ILGenerator generator) + { + List newInstructions = ListPool.Pool.Get(instructions); + + MethodBase method = Method(typeof(DummyUtils), nameof(DummyUtils.SpawnDummy)); + + // call ReferenceHub GameCore.DummyUtils::SpawnDummy(string) + int index = newInstructions.FindIndex(instruction => + instruction.operand == (object)method) + 1; + + LocalBuilder npc = generator.DeclareLocal(typeof(Npc)); + + // pop + newInstructions.RemoveAt(index); + + newInstructions.InsertRange( + index, + new CodeInstruction[] + { + // Npc::.ctor(ReferenceHub) + new(OpCodes.Newobj, Constructor(typeof(Npc), new[] { typeof(ReferenceHub) })), + new(OpCodes.Stloc_S, npc.LocalIndex), + + // Player.Dictionary.get_Dictionary + new(OpCodes.Call, PropertyGetter(typeof(Player), nameof(Player.Dictionary))), + new(OpCodes.Ldloc_S, npc.LocalIndex), + + // Player::GameObject.get_GameObject + new(OpCodes.Callvirt, PropertyGetter(typeof(Player), nameof(Player.GameObject))), + new(OpCodes.Ldloc_S, npc.LocalIndex), + + // Player.Dictionary.Add(GameObject, ReferenceHub) + new(OpCodes.Callvirt, Method(typeof(Dictionary), nameof(Dictionary.Add))), + }); + + for (int i = 0; i < newInstructions.Count; i++) + yield return newInstructions[i]; + + ListPool.Pool.Return(newInstructions); + } + } +}