diff --git a/OTAPI.Patcher/Targets/PCServerTarget.cs b/OTAPI.Patcher/Targets/PCServerTarget.cs
index bc86d7505..b8c75568c 100644
--- a/OTAPI.Patcher/Targets/PCServerTarget.cs
+++ b/OTAPI.Patcher/Targets/PCServerTarget.cs
@@ -210,6 +210,7 @@ public void Patch()
mm.Module.GetType("Terraria.NPC").CreateHooks(mm);
mm.Module.GetType("Terraria.WorldGen").CreateHooks(mm);
mm.Module.GetType("Terraria.Chat.ChatHelper").CreateHooks(mm);
+ mm.Module.GetType("Terraria.GameContent.ItemDropRules.CommonCode").CreateHooks(mm);
mm.Module.GetType("Terraria.IO.WorldFile").CreateHooks(mm);
mm.Module.GetType("Terraria.Net.NetManager").CreateHooks(mm);
mm.Module.GetType("Terraria.Projectile").CreateHooks(mm);
diff --git a/OTAPI.Scripts/Mods/HookNpcBossBag.Server.cs b/OTAPI.Scripts/Mods/HookNpcBossBag.Server.cs
deleted file mode 100644
index 30d02b273..000000000
--- a/OTAPI.Scripts/Mods/HookNpcBossBag.Server.cs
+++ /dev/null
@@ -1,145 +0,0 @@
-/*
-Copyright (C) 2020 DeathCradle
-
-This file is part of Open Terraria API v3 (OTAPI)
-
-This program is free software: you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program. If not, see .
-*/
-#pragma warning disable CS8321 // Local function is declared but never used
-#pragma warning disable CS0436 // Type conflicts with imported type
-
-using System;
-using System.Linq;
-using ModFramework;
-using Mono.Cecil;
-using Mono.Cecil.Cil;
-
-///
-/// @doc Creates Hooks.NPC.BossBag. Allows plugins to cancel boss bag items.
-///
-[Modification(ModType.PreMerge, "Hooking npc boss bags")]
-[MonoMod.MonoModIgnore]
-void HookNpcBossBag(ModFramework.ModFwModder modder)
-{
- // replace NewItem calls, and handle the -1 result to cancel the method from actioning.
-
- var csr = modder.GetILCursor(() => (new Terraria.NPC()).DropItemInstanced(default, default, 0, 0, false));
- var callback = csr.Module.ImportReference(
-#if TerrariaServer_EntitySourcesActive || Terraria_EntitySourcesActive || tModLoader_EntitySourcesActive
- modder.GetMethodDefinition(() => OTAPI.Hooks.NPC.InvokeBossBag(null, 0, 0, 0, 0, 0, 0, false, 0, false, false, null))
-#else
- modder.GetMethodDefinition(() => OTAPI.Hooks.NPC.InvokeBossBag(0, 0, 0, 0, 0, 0, false, 0, false, false, null))
-#endif
- );
-
- var instructions = csr.Body.Instructions.Where(x => x.OpCode == OpCodes.Call
- && x.Operand is MethodReference mref && mref.Name == "NewItem"
- && x.Next.OpCode == OpCodes.Stloc_0);
-
- if (instructions.Count() != 1) throw new NotSupportedException("Only one server NewItem call expected in DropBossBags.");
-
- var ins = instructions.First();
-
- ins.Operand = callback;
-
- csr.Goto(ins);
- csr.EmitAll(
- new { OpCodes.Ldarg_0 }
- );
-
- csr.Goto(ins.Next.Next);
- csr.EmitAll(
- new { OpCodes.Ldloc_0 },
- new { OpCodes.Ldc_I4_M1 },
- new { OpCodes.Ceq },
- new { OpCodes.Brfalse_S, Operand = ins.Next.Next },
- new { OpCodes.Ret }
- );
-}
-
-namespace OTAPI
-{
- public static partial class Hooks
- {
- public static partial class NPC
- {
- public class BossBagEventArgs : EventArgs
- {
- public HookResult? Result { get; set; }
-
-#if TerrariaServer_EntitySourcesActive || Terraria_EntitySourcesActive || tModLoader_EntitySourcesActive
- public Terraria.DataStructures.IEntitySource Source { get; set; }
-#endif
-
- public Terraria.NPC Npc { get; set; }
- public int X { get; set; }
- public int Y { get; set; }
- public int Width { get; set; }
- public int Height { get; set; }
- public int Type { get; set; }
- public int Stack { get; set; }
- public bool NoBroadcast { get; set; }
- public int Pfix { get; set; }
- public bool NoGrabDelay { get; set; }
- public bool ReverseLookup { get; set; }
- }
- public static event EventHandler BossBag;
-
- public static int InvokeBossBag(
-#if TerrariaServer_EntitySourcesActive || Terraria_EntitySourcesActive || tModLoader_EntitySourcesActive
- Terraria.DataStructures.IEntitySource Source,
-#endif
- int X,
- int Y,
- int Width,
- int Height,
- int Type,
- int Stack,
- bool noBroadcast,
- int pfix,
- bool noGrabDelay,
- bool reverseLookup,
- Terraria.NPC npc
- )
- {
- var args = new BossBagEventArgs()
- {
-#if TerrariaServer_EntitySourcesActive || Terraria_EntitySourcesActive || tModLoader_EntitySourcesActive
- Source = Source,
-#endif
- X = X,
- Y = Y,
- Width = Width,
- Height = Height,
- Type = Type,
- Stack = Stack,
- NoBroadcast = noBroadcast,
- Pfix = pfix,
- NoGrabDelay = noGrabDelay,
- ReverseLookup = reverseLookup,
- Npc = npc,
- };
- BossBag?.Invoke(null, args);
- if (args.Result == HookResult.Cancel)
- return -1;
-
-#if TerrariaServer_EntitySourcesActive || Terraria_EntitySourcesActive || tModLoader_EntitySourcesActive
- return Terraria.Item.NewItem(Source, args.X, args.Y, args.Width, args.Height, args.Type, args.Stack, args.NoBroadcast, args.Pfix, args.NoGrabDelay, args.ReverseLookup);
-#else
- return Terraria.Item.NewItem(args.X, args.Y, args.Width, args.Height, args.Type, args.Stack, args.NoBroadcast, args.Pfix, args.NoGrabDelay, args.ReverseLookup);
-#endif
- }
- }
- }
-}
\ No newline at end of file
diff --git a/OTAPI.Scripts/Patches/PatchNpcBossBag.Server.cs b/OTAPI.Scripts/Patches/PatchNpcBossBag.Server.cs
new file mode 100644
index 000000000..e4128e22f
--- /dev/null
+++ b/OTAPI.Scripts/Patches/PatchNpcBossBag.Server.cs
@@ -0,0 +1,112 @@
+/*
+Copyright (C) 2020 DeathCradle
+
+This file is part of Open Terraria API v3 (OTAPI)
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see .
+*/
+#pragma warning disable CS8321 // Local function is declared but never used
+#pragma warning disable CS0436 // Type conflicts with imported type
+
+using System;
+using ModFramework;
+using MonoMod.Cil;
+using Mono.Cecil;
+using Mono.Cecil.Cil;
+using System.Linq;
+using MonoMod;
+
+///
+/// @doc Creates Hooks.NPC.BossBag. Allows plugins to customize bosses loot as well as distributing it.
+///
+
+[MonoModIgnore]
+partial class NpcBossBag
+{
+ [Modification(ModType.PreMerge, "Hooking NPC Boss Bag")]
+ static void HookNpcBossBag(ModFwModder modder)
+ {
+ foreach (var csr in new[] {
+ modder.GetILCursor(() => (new Terraria.NPC()).DropItemInstanced(default, default, 0, 0, false)),
+ modder.GetILCursor(() => Terraria.GameContent.ItemDropRules.CommonCode.DropItemLocalPerClientAndSetNPCMoneyTo0(default, default, default, default))
+ })
+ {
+ csr.GotoNext(MoveType.After,
+ i => i.OpCode == OpCodes.Ldsfld &&
+ i.Operand is FieldReference fieldReference &&
+ fieldReference.Name == "netMode" &&
+ fieldReference.DeclaringType.FullName == "Terraria.Main",
+ i => i.OpCode == OpCodes.Ldc_I4_2,
+ i => i.OpCode == OpCodes.Bne_Un
+ );
+
+ csr.Emit(OpCodes.Ldarg_0);
+ if (csr.Method.Name == "DropItemLocalPerClientAndSetNPCMoneyTo0")
+ {
+ csr.Emit(OpCodes.Ldarg_1);
+ csr.Emit(OpCodes.Ldarg_2);
+ csr.Emit(OpCodes.Ldarg_3);
+ }
+ else
+ {
+ csr.Emit(OpCodes.Ldarg_3);
+ csr.Emit(OpCodes.Ldarg, 4);
+ csr.Emit(OpCodes.Ldarg, 5);
+ }
+ csr.EmitDelegate(OTAPI.Hooks.NPC.InvokeBossBag);
+ csr.Emit(OpCodes.Nop);
+ csr.Emit(OpCodes.Nop);
+
+ csr.Previous.Previous.OpCode = OpCodes.Brtrue;
+ csr.Previous.Previous.Operand = csr.Next;
+
+ var targetBranch = csr.Method.Body.Instructions.Reverse().Where(x => x.OpCode == OpCodes.Ldarg_0).FirstOrDefault();
+
+ csr.Previous.OpCode = OpCodes.Br;
+ csr.Previous.Operand = targetBranch;
+ }
+ }
+}
+
+namespace OTAPI
+{
+ public static partial class Hooks
+ {
+ public static partial class NPC
+ {
+ public class BossBagEventArgs : EventArgs
+ {
+ public HookResult? Result { get; set; }
+ public Terraria.NPC NPC { get; set; }
+ public int ItemID { get; set; }
+ public int Stack { get; set; }
+ public bool InteractionRequired { get; set; }
+ }
+ public static event EventHandler BossBag;
+
+ public static bool InvokeBossBag(Terraria.NPC npc, int itemid, int stack, bool interactionRequired)
+ {
+ var args = new BossBagEventArgs()
+ {
+ NPC = npc,
+ ItemID = itemid,
+ Stack = stack,
+ InteractionRequired = interactionRequired
+ };
+ BossBag?.Invoke(null, args);
+ return args.Result != HookResult.Cancel;
+ }
+ }
+ }
+}
diff --git a/OTAPI.Scripts/Patches/PatchNpcStrikeArgs.Server.cs b/OTAPI.Scripts/Patches/PatchNpcStrikeArgs.Server.cs
index 4280e9ad9..f4ede2d7e 100644
--- a/OTAPI.Scripts/Patches/PatchNpcStrikeArgs.Server.cs
+++ b/OTAPI.Scripts/Patches/PatchNpcStrikeArgs.Server.cs
@@ -15,27 +15,27 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
You should have received a copy of the GNU General Public License
along with this program. If not, see .
-*/
+*/
#if !tModLoaderServer_V1_3
using ModFramework;
-using Mono.Cecil;
-using Mono.Cecil.Cil;
-using MonoMod;
+using Mono.Cecil;
+using Mono.Cecil.Cil;
+using MonoMod;
using System;
-using System.Linq;
-
-///
-/// @doc Adds a Terraria.Entity entity parameter to Terraria.NPC.StrikeNPC.
-///
-[MonoModIgnore]
-partial class NpcStrikeArgs
-{
- //static ParameterDefinition Entity { get; set; }
- //static MethodDefinition StrikeNPC { get; set; }
-
- [Modification(ModType.PreMerge, "Patching in entity source for NPC strike")]
- static void PatchNpcStrikeArgs(ModFwModder modder)
- {
+using System.Linq;
+
+///
+/// @doc Adds a Terraria.Entity entity parameter to Terraria.NPC.StrikeNPC.
+///
+[MonoModIgnore]
+partial class NpcStrikeArgs
+{
+ //static ParameterDefinition Entity { get; set; }
+ //static MethodDefinition StrikeNPC { get; set; }
+
+ [Modification(ModType.PreMerge, "Patching in entity source for NPC strike")]
+ static void PatchNpcStrikeArgs(ModFwModder modder)
+ {
var csr = modder.GetILCursor(() => (new Terraria.NPC()).StrikeNPC(0, 0, 0, false, false, false));
var redirects = csr.Method.DeclaringType.Methods
.Where(x => (HookEmitter.HookMethodNamePrefix + x.Name) == csr.Method.Name || ("orig_" + x.Name) == csr.Method.Name)
@@ -45,16 +45,16 @@ static void PatchNpcStrikeArgs(ModFwModder modder)
foreach (var method in redirects.Append(csr))
{
ParameterDefinition Entity;
- method.Method.Parameters.Add(Entity = new ("entity",
- ParameterAttributes.HasDefault | ParameterAttributes.Optional,
-
- modder.Module.ImportReference(modder.GetDefinition())
+ method.Method.Parameters.Add(Entity = new ("entity",
+ ParameterAttributes.HasDefault | ParameterAttributes.Optional,
+
+ modder.Module.ImportReference(modder.GetDefinition())
)
{
Constant = null
});
- modder.OnRewritingMethodBody += (MonoModder modder, MethodBody body, Instruction instr, int instri) =>
+ modder.OnRewritingMethodBody += (MonoModder modder, MethodBody body, Instruction instr, int instri) =>
{
if (instr.Operand is MethodReference methodReference)
{
@@ -102,7 +102,7 @@ static void PatchNpcStrikeArgs(ModFwModder modder)
}
}
};
- }
- }
+ }
+ }
}
#endif
\ No newline at end of file