diff --git a/patches/minecraft/net/minecraft/entity/NpcMerchant.java.patch b/patches/minecraft/net/minecraft/entity/NpcMerchant.java.patch new file mode 100644 index 000000000..2b48c073d --- /dev/null +++ b/patches/minecraft/net/minecraft/entity/NpcMerchant.java.patch @@ -0,0 +1,11 @@ +--- a/net/minecraft/entity/NpcMerchant.java ++++ b/net/minecraft/entity/NpcMerchant.java +@@ -36,7 +36,7 @@ + + @Nullable + public MerchantRecipeList func_70934_b(EntityPlayer p_70934_1_) { +- return this.field_70936_c; ++ return net.minecraftforge.event.ForgeEventFactory.listTradeOffers(this, p_70934_1_, this.field_70936_c); + } + + public void func_70930_a(@Nullable MerchantRecipeList p_70930_1_) { diff --git a/patches/minecraft/net/minecraft/entity/passive/EntityVillager.java.patch b/patches/minecraft/net/minecraft/entity/passive/EntityVillager.java.patch index fc87d7c1c..e19504b5e 100644 --- a/patches/minecraft/net/minecraft/entity/passive/EntityVillager.java.patch +++ b/patches/minecraft/net/minecraft/entity/passive/EntityVillager.java.patch @@ -121,7 +121,12 @@ } else { this.field_82189_bL = null; } -@@ -473,11 +512,10 @@ +@@ -469,15 +508,14 @@ + this.func_175554_cu(); + } + +- return this.field_70963_i; ++ return net.minecraftforge.event.ForgeEventFactory.listTradeOffers(this, p_70934_1_, field_70963_i); } private void func_175554_cu() { diff --git a/patches/minecraft/net/minecraft/village/VillageSiege.java.patch b/patches/minecraft/net/minecraft/village/VillageSiege.java.patch new file mode 100644 index 000000000..98a6c8ff9 --- /dev/null +++ b/patches/minecraft/net/minecraft/village/VillageSiege.java.patch @@ -0,0 +1,10 @@ +--- a/net/minecraft/village/VillageSiege.java ++++ b/net/minecraft/village/VillageSiege.java +@@ -115,6 +115,7 @@ + + Vec3d vec3d = this.func_179867_a(new BlockPos(this.field_75532_g, this.field_75538_h, this.field_75539_i)); + if (vec3d != null) { ++ if (net.minecraftforge.common.MinecraftForge.EVENT_BUS.post(new net.minecraftforge.event.village.VillageSiegeEvent(this, field_75537_a, entityplayer, field_75531_f, vec3d))) return false; + break; + } + } diff --git a/src/main/java/net/minecraftforge/event/ForgeEventFactory.java b/src/main/java/net/minecraftforge/event/ForgeEventFactory.java index 2e8cc266d..a6af63ec4 100644 --- a/src/main/java/net/minecraftforge/event/ForgeEventFactory.java +++ b/src/main/java/net/minecraftforge/event/ForgeEventFactory.java @@ -35,6 +35,7 @@ import net.minecraft.entity.Entity; import net.minecraft.entity.EntityLiving; import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.EnumCreatureType; +import net.minecraft.entity.IMerchant; import net.minecraft.entity.effect.EntityLightningBolt; import net.minecraft.entity.item.EntityItem; import net.minecraft.entity.monster.EntityZombie; @@ -62,6 +63,8 @@ import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.RayTraceResult; import net.minecraft.util.text.ChatType; import net.minecraft.util.text.ITextComponent; +import net.minecraft.village.MerchantRecipeList; +import net.minecraft.village.Village; import net.minecraft.world.Explosion; import net.minecraft.world.IWorld; import net.minecraft.world.World; @@ -118,6 +121,7 @@ import net.minecraftforge.event.entity.player.SleepingTimeCheckEvent; import net.minecraftforge.event.entity.player.UseHoeEvent; import net.minecraftforge.event.furnace.FurnaceFuelBurnTimeEvent; import net.minecraftforge.event.terraingen.ChunkGeneratorEvent; +import net.minecraftforge.event.village.MerchantTradeOffersEvent; import net.minecraftforge.event.world.BlockEvent; import net.minecraftforge.event.world.BlockEvent.CreateFluidSourceEvent; import net.minecraftforge.event.world.BlockEvent.EntityMultiPlaceEvent; @@ -695,4 +699,17 @@ public class ForgeEventFactory MinecraftForge.EVENT_BUS.post(event); return event.getResult() != Result.DENY; } + + public static MerchantRecipeList listTradeOffers(IMerchant merchant, EntityPlayer player, @Nullable MerchantRecipeList list) + { + MerchantRecipeList dupeList = null; + if (list != null) + { + dupeList = new MerchantRecipeList(); + dupeList.addAll(list); + } + MerchantTradeOffersEvent event = new MerchantTradeOffersEvent(merchant, player, dupeList); + MinecraftForge.EVENT_BUS.post(event); + return event.getList(); + } } diff --git a/src/main/java/net/minecraftforge/event/village/MerchantTradeOffersEvent.java b/src/main/java/net/minecraftforge/event/village/MerchantTradeOffersEvent.java new file mode 100644 index 000000000..474c38cde --- /dev/null +++ b/src/main/java/net/minecraftforge/event/village/MerchantTradeOffersEvent.java @@ -0,0 +1,80 @@ +/* + * Minecraft Forge + * Copyright (c) 2016-2018. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +package net.minecraftforge.event.village; + +import javax.annotation.Nullable; + +import net.minecraft.entity.IMerchant; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.village.MerchantRecipeList; +import net.minecraftforge.common.MinecraftForge; +import net.minecraftforge.eventbus.api.Cancelable; +import net.minecraftforge.eventbus.api.Event; + +/** + * MerchantTradeOffersEvent is fired when a list of villager trade offers is presented in + * {@link IMerchant#getRecipes(EntityPlayer)}, allowing mods to modify trade offers depending + * on the player. Be warned that this event is fired on both server and client; thus, modders + * should ensure that they sync the needed data for this event themselves.
+ *
+ * This event is not {@link Cancelable}.
+ *
+ * This event does not have a result. {@link HasResult}
+ *
+ * This event is fired on the {@link MinecraftForge#EVENT_BUS}. + */ +public class MerchantTradeOffersEvent extends Event +{ + private final IMerchant merchant; + private final EntityPlayer player; + private @Nullable MerchantRecipeList list; + + public MerchantTradeOffersEvent(IMerchant merchant, EntityPlayer player, @Nullable MerchantRecipeList list) + { + this.merchant = merchant; + this.player = player; + this.list = list; + } + + /** + * The recipe list (if not {@code null}) returned from this function may be modified. + * @return the recipe list + */ + public @Nullable MerchantRecipeList getList() + { + return list; + } + + public void setList(@Nullable MerchantRecipeList list) + { + this.list = list; + } + + public IMerchant getMerchant() + { + return merchant; + } + + public EntityPlayer getPlayer() + { + return player; + } + +} diff --git a/src/main/java/net/minecraftforge/event/village/VillageSiegeEvent.java b/src/main/java/net/minecraftforge/event/village/VillageSiegeEvent.java new file mode 100644 index 000000000..aa4ea6972 --- /dev/null +++ b/src/main/java/net/minecraftforge/event/village/VillageSiegeEvent.java @@ -0,0 +1,83 @@ +/* + * Minecraft Forge + * Copyright (c) 2016-2018. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +package net.minecraftforge.event.village; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.util.math.Vec3d; +import net.minecraft.village.Village; +import net.minecraft.village.VillageSiege; +import net.minecraft.world.World; +import net.minecraftforge.common.MinecraftForge; +import net.minecraftforge.eventbus.api.Cancelable; +import net.minecraftforge.eventbus.api.Event; + +/** + * VillageSiegeEvent is fired just before a zombie siege finds a successful location in + * {@link VillageSiege#trySetupSiege}, to give mods the chance to stop the siege.
+ *
+ * This event is {@link Cancelable}; canceling stops the siege.
+ *
+ * This event does not have a result. {@link HasResult}
+ *
+ * This event is fired on the {@link MinecraftForge#EVENT_BUS}. + */ +@Cancelable +public class VillageSiegeEvent extends Event +{ + private final VillageSiege siege; + private final World world; + private final EntityPlayer player; + private final Village village; + private final Vec3d attemptedSpawnPos; + + public VillageSiegeEvent(VillageSiege siege, World world, EntityPlayer player, Village village, Vec3d attemptedSpawnPos) + { + this.siege = siege; + this.world = world; + this.player = player; + this.village = village; + this.attemptedSpawnPos = attemptedSpawnPos; + } + + public VillageSiege getSiege() + { + return siege; + } + + public World getWorld() + { + return world; + } + + public EntityPlayer getPlayer() + { + return player; + } + + public Village getVillage() + { + return village; + } + + public Vec3d getAttemptedSpawnPos() + { + return attemptedSpawnPos; + } +} diff --git a/src/test/java/net/minecraftforge/debug/village/MerchantTradeOffersEventTest.java b/src/test/java/net/minecraftforge/debug/village/MerchantTradeOffersEventTest.java new file mode 100644 index 000000000..330a3dc47 --- /dev/null +++ b/src/test/java/net/minecraftforge/debug/village/MerchantTradeOffersEventTest.java @@ -0,0 +1,66 @@ +/* + * Minecraft Forge + * Copyright (c) 2016-2018. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +package net.minecraftforge.debug.village; + +import java.util.ListIterator; + +import net.minecraft.village.MerchantRecipe; +import net.minecraft.village.MerchantRecipeList; +import net.minecraftforge.common.MinecraftForge; +import net.minecraftforge.event.village.MerchantTradeOffersEvent; +import net.minecraftforge.fml.common.Mod; +import net.minecraftforge.fml.common.event.FMLPreInitializationEvent; +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; + +/** + * Tests {@link MerchantTradeOffersEvent}. When enabled, the item that the villager sells to + * the player will be maxed out in stack size. + */ +@Mod(modid = MerchantTradeOffersEventTest.MODID, name = MerchantTradeOffersEventTest.NAME, version = "0.0.0", acceptableRemoteVersions = "*") +public class MerchantTradeOffersEventTest +{ + public static final String MODID = "merchanttradeofferseventtest"; + public static final String NAME = "Merchant Trade Offers Event Test"; + public static final boolean ENABLED = false; + + @Mod.EventHandler + public void preInit(FMLPreInitializationEvent event) + { + if (ENABLED) + { + MinecraftForge.EVENT_BUS.register(MerchantTradeOffersEventTest.class); + } + } + + @SubscribeEvent + public static void onGetRecipes(MerchantTradeOffersEvent event) + { + MerchantRecipeList list = event.getList(); + if (list != null) + { + ListIterator it = list.listIterator(); + while (it.hasNext()) + { + MerchantRecipe recipe = it.next(); + recipe.getItemToSell().setCount(recipe.getItemToSell().getMaxStackSize()); + } + } + } +} diff --git a/src/test/java/net/minecraftforge/debug/village/VillageSiegeEventTest.java b/src/test/java/net/minecraftforge/debug/village/VillageSiegeEventTest.java new file mode 100644 index 000000000..bbf23c037 --- /dev/null +++ b/src/test/java/net/minecraftforge/debug/village/VillageSiegeEventTest.java @@ -0,0 +1,65 @@ +/* + * Minecraft Forge + * Copyright (c) 2016-2018. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +package net.minecraftforge.debug.village; + +import java.util.Locale; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import net.minecraft.init.Items; +import net.minecraftforge.common.MinecraftForge; +import net.minecraftforge.event.village.VillageSiegeEvent; +import net.minecraftforge.fml.common.Mod; +import net.minecraftforge.fml.common.event.FMLPreInitializationEvent; +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; + +/** + * Tests {@link VillageSiegeEvent}. When enabled, players holding a diamond sword in the mainhand + * slot are not counted in determining where the zombie siege occurs. + */ +@Mod(modid = VillageSiegeEventTest.MODID, name = VillageSiegeEventTest.NAME, version = "0.0.0", acceptableRemoteVersions = "*") +public class VillageSiegeEventTest +{ + public static final String MODID = "villagesiegeeventtest"; + public static final String NAME = "Village Siege Event Test"; + public static final boolean ENABLED = false; + + public static final Logger LOG = LogManager.getLogger(MODID.toUpperCase(Locale.US)); + + @Mod.EventHandler + public void preInit(FMLPreInitializationEvent event) + { + if (ENABLED) + { + MinecraftForge.EVENT_BUS.register(VillageSiegeEventTest.class); + } + } + + @SubscribeEvent + public static void onVillageSiege(VillageSiegeEvent event) + { + if (!event.getWorld().isRemote && event.getPlayer().getHeldItemMainhand().getItem() == Items.DIAMOND_SWORD) + { + LOG.info("Village siege event for player "+event.getPlayer().getName()+" canceled"); + event.setCanceled(true); + } + } +}