diff --git a/patches/minecraft/net/minecraft/entity/item/EntityMinecartMobSpawner.java.patch b/patches/minecraft/net/minecraft/entity/item/EntityMinecartMobSpawner.java.patch new file mode 100644 index 000000000..b3f36c892 --- /dev/null +++ b/patches/minecraft/net/minecraft/entity/item/EntityMinecartMobSpawner.java.patch @@ -0,0 +1,12 @@ +--- ../src-base/minecraft/net/minecraft/entity/item/EntityMinecartMobSpawner.java ++++ ../src-work/minecraft/net/minecraft/entity/item/EntityMinecartMobSpawner.java +@@ -33,6 +33,9 @@ + { + return new BlockPos(EntityMinecartMobSpawner.this); + } ++ public net.minecraft.entity.Entity getSpawnerEntity() { ++ return EntityMinecartMobSpawner.this; ++ } + }; + + public EntityMinecartMobSpawner(World p_i46752_1_) diff --git a/patches/minecraft/net/minecraft/tileentity/MobSpawnerBaseLogic.java.patch b/patches/minecraft/net/minecraft/tileentity/MobSpawnerBaseLogic.java.patch index 2fa117c95..15fb0accd 100644 --- a/patches/minecraft/net/minecraft/tileentity/MobSpawnerBaseLogic.java.patch +++ b/patches/minecraft/net/minecraft/tileentity/MobSpawnerBaseLogic.java.patch @@ -5,11 +5,19 @@ entity.func_70012_b(entity.field_70165_t, entity.field_70163_u, entity.field_70161_v, world.field_73012_v.nextFloat() * 360.0F, 0.0F); - if (entityliving == null || entityliving.func_70601_bi() && entityliving.func_70058_J()) -+ if (entityliving == null || net.minecraftforge.event.ForgeEventFactory.canEntitySpawnSpawner(entityliving, func_98271_a(), (float)entity.field_70165_t, (float)entity.field_70163_u, (float)entity.field_70161_v)) ++ if (entityliving == null || net.minecraftforge.event.ForgeEventFactory.canEntitySpawnSpawner(entityliving, func_98271_a(), (float)entity.field_70165_t, (float)entity.field_70163_u, (float)entity.field_70161_v, this)) { if (this.field_98282_f.func_185277_b().func_186856_d() == 1 && this.field_98282_f.func_185277_b().func_150297_b("id", 8) && entity instanceof EntityLiving) { -+ if (!net.minecraftforge.event.ForgeEventFactory.doSpecialSpawn(entityliving, this.func_98271_a(), (float)entity.field_70165_t, (float)entity.field_70163_u, (float)entity.field_70161_v)) ++ if (!net.minecraftforge.event.ForgeEventFactory.doSpecialSpawn(entityliving, this.func_98271_a(), (float)entity.field_70165_t, (float)entity.field_70163_u, (float)entity.field_70161_v, this)) ((EntityLiving)entity).func_180482_a(world.func_175649_E(new BlockPos(entity)), (IEntityLivingData)null); } +@@ -307,4 +308,7 @@ + { + return this.field_98284_d; + } ++ ++ /* ======================================== FORGE START =====================================*/ ++ @Nullable public Entity getSpawnerEntity() { return null; } + } diff --git a/src/main/java/net/minecraftforge/event/ForgeEventFactory.java b/src/main/java/net/minecraftforge/event/ForgeEventFactory.java index a319a7af9..2f9d1e3fa 100644 --- a/src/main/java/net/minecraftforge/event/ForgeEventFactory.java +++ b/src/main/java/net/minecraftforge/event/ForgeEventFactory.java @@ -42,6 +42,7 @@ import net.minecraft.entity.projectile.EntityThrowable; import net.minecraft.init.Blocks; import net.minecraft.item.Item; import net.minecraft.item.ItemStack; +import net.minecraft.tileentity.MobSpawnerBaseLogic; import net.minecraft.tileentity.TileEntity; import net.minecraft.util.ActionResult; import net.minecraft.util.DamageSource; @@ -176,23 +177,52 @@ public class ForgeEventFactory } /** - * @deprecated use {@link #canEntitySpawn(EntityLiving, World, float, float, float, boolean)} instead + * @deprecated use {@link #canEntitySpawn(EntityLiving, World, float, float, float, MobSpawnerBaseLogic)} instead */ - @Deprecated + @Deprecated // TODO remove in 1.13 public static Result canEntitySpawn(EntityLiving entity, World world, float x, float y, float z) { return canEntitySpawn(entity, world, x, y, z, true); } - + /** + * @deprecated use {@link #canEntitySpawn(EntityLiving, World, float, float, float, MobSpawnerBaseLogic)} instead + */ + @Deprecated // Still used in base game for non-spawner spawns, which is safe public static Result canEntitySpawn(EntityLiving entity, World world, float x, float y, float z, boolean isSpawner) { if (entity == null) return Result.DEFAULT; - LivingSpawnEvent.CheckSpawn event = new LivingSpawnEvent.CheckSpawn(entity, world, x, y, z, isSpawner); + LivingSpawnEvent.CheckSpawn event = new LivingSpawnEvent.CheckSpawn(entity, world, x, y, z, isSpawner); // TODO: replace isSpawner with null in 1.13 MinecraftForge.EVENT_BUS.post(event); return event.getResult(); } + public static Result canEntitySpawn(EntityLiving entity, World world, float x, float y, float z, MobSpawnerBaseLogic spawner) + { + if (entity == null) + return Result.DEFAULT; + LivingSpawnEvent.CheckSpawn event = new LivingSpawnEvent.CheckSpawn(entity, world, x, y, z, spawner); + MinecraftForge.EVENT_BUS.post(event); + return event.getResult(); + } + + public static boolean canEntitySpawnSpawner(EntityLiving entity, World world, float x, float y, float z, MobSpawnerBaseLogic spawner) + { + Result result = canEntitySpawn(entity, world, x, y, z, spawner); + if (result == Result.DEFAULT) + { + return entity.getCanSpawnHere() && entity.isNotColliding(); // vanilla logic + } + else + { + return result == Result.ALLOW; + } + } + + /** + * @deprecated Use {@link #canEntitySpawnSpawner(EntityLiving, World, float, float, float, MobSpawnerBaseLogic)} + */ + @Deprecated // TODO remove in 1.13 public static boolean canEntitySpawnSpawner(EntityLiving entity, World world, float x, float y, float z) { Result result = canEntitySpawn(entity, world, x, y, z, true); @@ -206,9 +236,18 @@ public class ForgeEventFactory } } + /** + * @deprecated Use {@link #canEntitySpawnSpawner(EntityLiving, World, float, float, float, MobSpawnerBaseLogic)} + */ + @Deprecated // Still used in base game for non-spawner spawns, which is safe public static boolean doSpecialSpawn(EntityLiving entity, World world, float x, float y, float z) { - return MinecraftForge.EVENT_BUS.post(new LivingSpawnEvent.SpecialSpawn(entity, world, x, y, z)); + return MinecraftForge.EVENT_BUS.post(new LivingSpawnEvent.SpecialSpawn(entity, world, x, y, z, null)); + } + + public static boolean doSpecialSpawn(EntityLiving entity, World world, float x, float y, float z, MobSpawnerBaseLogic spawner) + { + return MinecraftForge.EVENT_BUS.post(new LivingSpawnEvent.SpecialSpawn(entity, world, x, y, z, spawner)); } public static Result canEntityDespawn(EntityLiving entity) diff --git a/src/main/java/net/minecraftforge/event/entity/living/LivingSpawnEvent.java b/src/main/java/net/minecraftforge/event/entity/living/LivingSpawnEvent.java index 29484f2bd..71788aafa 100644 --- a/src/main/java/net/minecraftforge/event/entity/living/LivingSpawnEvent.java +++ b/src/main/java/net/minecraftforge/event/entity/living/LivingSpawnEvent.java @@ -19,6 +19,9 @@ package net.minecraftforge.event.entity.living; +import javax.annotation.Nullable; +import net.minecraft.tileentity.MobSpawnerBaseLogic; +import net.minecraft.util.math.BlockPos; import net.minecraftforge.common.MinecraftForge; import net.minecraftforge.event.ForgeEventFactory; import net.minecraftforge.fml.common.eventhandler.Cancelable; @@ -70,9 +73,31 @@ public class LivingSpawnEvent extends LivingEvent @HasResult public static class CheckSpawn extends LivingSpawnEvent { - private final boolean isSpawner; + private final boolean isSpawner; // TODO: remove in 1.13 + @Nullable + private final MobSpawnerBaseLogic spawner; + /** + * CheckSpawn is fired when an Entity is about to be spawned. + * @param entity the spawning entity + * @param world the world to spawn in + * @param x x coordinate + * @param y y coordinate + * @param z z coordinate + * @param spawner position of the MobSpawner + * null if it this spawn is coming from a WorldSpawner + */ + public CheckSpawn(EntityLiving entity, World world, float x, float y, float z, @Nullable MobSpawnerBaseLogic spawner) + { + super(entity, world, x, y, z); + this.isSpawner = spawner != null; + this.spawner = spawner; + } + + /** + * @deprecated Use {@link CheckSpawn##CheckSpawn(EntityLiving, World, float, float, float, MobSpawnerBaseLogic)} + * with a spawner instance, or null if not a spawner * CheckSpawn is fired when an Entity is about to be spawned. * @param entity the spawning entity * @param world the world to spawn in @@ -82,22 +107,33 @@ public class LivingSpawnEvent extends LivingEvent * @param isSpawner true if this spawn is done by a MobSpawner, * false if it this spawn is coming from a WorldSpawner */ + @Deprecated // TODO: Remove in 1.13 public CheckSpawn(EntityLiving entity, World world, float x, float y, float z, boolean isSpawner) { super(entity, world, x, y, z); this.isSpawner = isSpawner; + spawner = null; } /** - * @deprecated Use {@link CheckSpawn#CheckSpawn(EntityLiving, World, float, float, float, boolean)} instead + * @deprecated Use {@link CheckSpawn#CheckSpawn(EntityLiving, World, float, float, float, MobSpawnerBaseLogic)} instead */ - @Deprecated + @Deprecated // TODO: Remove in 1.13 public CheckSpawn(EntityLiving entity, World world, float x, float y, float z) { this(entity, world, x, y, z, true); } - public boolean isSpawner() { return isSpawner; } + public boolean isSpawner() + { + return isSpawner; // TODO: replace with spawner null check in 1.13 + } + + @Nullable + public MobSpawnerBaseLogic getSpawner() + { + return spawner; + } } /** @@ -116,9 +152,33 @@ public class LivingSpawnEvent extends LivingEvent @Cancelable public static class SpecialSpawn extends LivingSpawnEvent { + @Nullable + private final MobSpawnerBaseLogic spawner; + + /** + * @deprecated Use {@link SpecialSpawn#SpecialSpawn(EntityLiving, World, float, float, float, MobSpawnerBaseLogic)} + * with originating spawner instance or null + */ + @Deprecated // TODO: remove in 1.13 public SpecialSpawn(EntityLiving entity, World world, float x, float y, float z) { super(entity, world, x, y, z); + spawner = null; + } + + /** + * @param spawner the position of a tileentity or approximate position of an entity that initiated the spawn if any + */ + public SpecialSpawn(EntityLiving entity, World world, float x, float y, float z, @Nullable MobSpawnerBaseLogic spawner) + { + super(entity, world, x, y, z); + this.spawner = spawner; + } + + @Nullable + public MobSpawnerBaseLogic getSpawner() + { + return spawner; } } diff --git a/src/test/java/net/minecraftforge/fml/test/SpecialSpawnEventTest.java b/src/test/java/net/minecraftforge/fml/test/SpecialSpawnEventTest.java new file mode 100644 index 000000000..4823705a0 --- /dev/null +++ b/src/test/java/net/minecraftforge/fml/test/SpecialSpawnEventTest.java @@ -0,0 +1,46 @@ +package net.minecraftforge.fml.test; + +import net.minecraft.entity.Entity; +import net.minecraft.entity.passive.EntityChicken; +import net.minecraft.init.Blocks; +import net.minecraft.tileentity.MobSpawnerBaseLogic; +import net.minecraftforge.common.MinecraftForge; +import net.minecraftforge.event.entity.living.LivingSpawnEvent; +import net.minecraftforge.fml.common.Mod; +import net.minecraftforge.fml.common.Mod.EventHandler; +import net.minecraftforge.fml.common.event.FMLPreInitializationEvent; +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; + +@Mod(modid = SpecialSpawnEventTest.MOD_ID, version = "1.0", acceptableRemoteVersions="*") +public class SpecialSpawnEventTest { + private static final boolean ENABLED = false; + public static final String MOD_ID = "spawnerduratest"; + + @EventHandler + public void onPreInit(FMLPreInitializationEvent e) + { + if (ENABLED) + { + MinecraftForge.EVENT_BUS.register(this); + } + + } + + @SubscribeEvent + public void specialSpawnEvent(LivingSpawnEvent.SpecialSpawn e) + { + MobSpawnerBaseLogic spawner = e.getSpawner(); + if (spawner == null) return; + if (spawner.getSpawnerEntity() != null) + { + Entity spawn = new EntityChicken(e.getWorld()); + spawn.copyLocationAndAnglesFrom(spawner.getSpawnerEntity()); + e.getWorld().spawnEntity(spawn); + spawner.getSpawnerEntity().setDead(); + } + else + { + e.getWorld().setBlockState(spawner.getSpawnerPosition(), Blocks.FIRE.getDefaultState()); + } + } +}