diff --git a/NMS/NMS-API/src/com/songoda/core/nms/ReflectionUtils.java b/NMS/NMS-API/src/com/songoda/core/nms/ReflectionUtils.java new file mode 100644 index 00000000..311c60bd --- /dev/null +++ b/NMS/NMS-API/src/com/songoda/core/nms/ReflectionUtils.java @@ -0,0 +1,52 @@ +package com.songoda.core.nms; + +import java.lang.reflect.Field; + +public class ReflectionUtils { + private ReflectionUtils() { + throw new IllegalStateException("Utility class"); + } + + public static Object getFieldValue(Object instance, String fieldName) throws NoSuchFieldException, IllegalAccessException { + Field f = getField(instance, fieldName); + boolean accessible = f.isAccessible(); + + f.setAccessible(true); + + Object result = f.get(instance); + + f.setAccessible(accessible); + + return result; + } + + public static void setFieldValue(Object instance, String fieldName, Object value) throws NoSuchFieldException, IllegalAccessException { + Field f = getField(instance, fieldName); + boolean accessible = f.isAccessible(); + + f.setAccessible(true); + + f.set(instance, value); + + f.setAccessible(accessible); + } + + private static Field getField(Object instance, String fieldName) throws NoSuchFieldException { + Field f = null; + + Class currClass = instance.getClass(); + do { + try { + f = currClass.getDeclaredField(fieldName); + } catch (NoSuchFieldException ex) { + currClass = currClass.getSuperclass(); + + if (currClass == null) { + throw ex; + } + } + } while (f == null); + + return f; + } +} diff --git a/NMS/NMS-API/src/com/songoda/core/nms/world/BBaseSpawner.java b/NMS/NMS-API/src/com/songoda/core/nms/world/BBaseSpawner.java new file mode 100644 index 00000000..d510705d --- /dev/null +++ b/NMS/NMS-API/src/com/songoda/core/nms/world/BBaseSpawner.java @@ -0,0 +1,12 @@ +package com.songoda.core.nms.world; + +import java.lang.reflect.InvocationTargetException; + +public interface BBaseSpawner { + boolean isNearPlayer() throws InvocationTargetException, IllegalAccessException; + + /** + * Ignores {@link #isNearPlayer()} - Make sure the server isn't already ticking the spawner! + */ + void tick() throws NoSuchFieldException, IllegalAccessException, InvocationTargetException; +} diff --git a/NMS/NMS-API/src/com/songoda/core/nms/world/WorldCore.java b/NMS/NMS-API/src/com/songoda/core/nms/world/WorldCore.java index d1143b5f..75da36f8 100644 --- a/NMS/NMS-API/src/com/songoda/core/nms/world/WorldCore.java +++ b/NMS/NMS-API/src/com/songoda/core/nms/world/WorldCore.java @@ -1,12 +1,15 @@ package com.songoda.core.nms.world; +import org.bukkit.Chunk; import org.bukkit.Location; import org.bukkit.World; +import org.bukkit.block.BlockState; import org.bukkit.block.CreatureSpawner; import org.bukkit.inventory.ItemStack; -public interface WorldCore { +import java.lang.reflect.InvocationTargetException; +public interface WorldCore { SSpawner getSpawner(CreatureSpawner spawner); SSpawner getSpawner(Location location); @@ -14,4 +17,39 @@ public interface WorldCore { SItemStack getItemStack(ItemStack item); SWorld getWorld(World world); + + BBaseSpawner getBaseSpawner(CreatureSpawner spawner) throws NoSuchFieldException, IllegalAccessException; + + /** + * Performs random ticks on a specific chunks. + *

+ * More information: https://minecraft.fandom.com/wiki/Tick#Random_tick + * + * @param bukkitChunk The chunk to tick + * @param tickAmount The number of blocks to tick per ChunkSection, normally referred to as randomTickSpeed + */ + void randomTickChunk(Chunk bukkitChunk, int tickAmount) throws NoSuchFieldException, IllegalAccessException; + + /** + * Ticks all inactive spawners in a specific chunk ignoring the minimum required players within a specific range.
+ * A spawner is deemed inactive if no player is within its activation range. + * + * @param chunk The chunk to tick the spawners in + * @param amount The amount of ticks to execute for each spawner + */ + default void tickInactiveSpawners(Chunk chunk, int amount) throws NoSuchFieldException, IllegalAccessException, InvocationTargetException { + if (amount <= 0) return; + + for (BlockState tileEntity : chunk.getTileEntities()) { + if (tileEntity instanceof CreatureSpawner) { + BBaseSpawner spawner = getBaseSpawner((CreatureSpawner) tileEntity); + + if (!spawner.isNearPlayer()) { + for (int i = 0; i < amount; ++i) { + spawner.tick(); + } + } + } + } + } } diff --git a/NMS/NMS-v1_10_R1/src/com/songoda/core/nms/v1_10_R1/world/WorldCoreImpl.java b/NMS/NMS-v1_10_R1/src/com/songoda/core/nms/v1_10_R1/world/WorldCoreImpl.java index 9fa44825..2630a68a 100644 --- a/NMS/NMS-v1_10_R1/src/com/songoda/core/nms/v1_10_R1/world/WorldCoreImpl.java +++ b/NMS/NMS-v1_10_R1/src/com/songoda/core/nms/v1_10_R1/world/WorldCoreImpl.java @@ -1,16 +1,26 @@ package com.songoda.core.nms.v1_10_R1.world; import com.songoda.core.nms.world.SItemStack; +import com.songoda.core.nms.ReflectionUtils; +import com.songoda.core.nms.v1_10_R1.world.spawner.BBaseSpawnerImpl; +import com.songoda.core.nms.world.BBaseSpawner; import com.songoda.core.nms.world.SSpawner; import com.songoda.core.nms.world.SWorld; import com.songoda.core.nms.world.WorldCore; +import net.minecraft.server.v1_10_R1.Block; +import net.minecraft.server.v1_10_R1.BlockPosition; +import net.minecraft.server.v1_10_R1.Chunk; +import net.minecraft.server.v1_10_R1.ChunkSection; +import net.minecraft.server.v1_10_R1.IBlockData; +import net.minecraft.server.v1_10_R1.MobSpawnerAbstract; +import net.minecraft.server.v1_10_R1.WorldServer; import org.bukkit.Location; import org.bukkit.World; import org.bukkit.block.CreatureSpawner; import org.bukkit.inventory.ItemStack; +import org.bukkit.craftbukkit.v1_10_R1.CraftChunk; public class WorldCoreImpl implements WorldCore { - @Override public SSpawner getSpawner(CreatureSpawner spawner) { return new SSpawnerImpl(spawner.getLocation()); @@ -30,4 +40,47 @@ public class WorldCoreImpl implements WorldCore { public SWorld getWorld(World world) { return new SWorldImpl(); } + + @Override + public BBaseSpawner getBaseSpawner(CreatureSpawner spawner) throws NoSuchFieldException, IllegalAccessException { + Object cTileEntity = ReflectionUtils.getFieldValue(spawner, "spawner"); + + return new BBaseSpawnerImpl((MobSpawnerAbstract) ReflectionUtils.getFieldValue(cTileEntity, "a")); + } + + /** + * Method is based on {@link WorldServer#j()}. + */ + @SuppressWarnings("JavadocReference") + @Override + public void randomTickChunk(org.bukkit.Chunk bukkitChunk, int tickAmount) throws NoSuchFieldException, IllegalAccessException { + Chunk chunk = ((CraftChunk) bukkitChunk).getHandle(); + + if (tickAmount > 0) { + int j = chunk.locX * 16; + int k = chunk.locZ * 16; + + for (ChunkSection chunksection : chunk.getSections()) { + if (chunksection != net.minecraft.server.v1_10_R1.Chunk.a && chunksection.shouldTick()) { + for (int i = 0; i < tickAmount; ++i) { + int worldL = (int) ReflectionUtils.getFieldValue(chunk.world, "l"); + worldL = worldL * 3 + 1013904223; + ReflectionUtils.setFieldValue(chunk.world, "l", worldL); + + int l1 = worldL >> 2; + int i2 = l1 & 15; + int j2 = l1 >> 8 & 15; + int k2 = l1 >> 16 & 15; + + IBlockData iblockdata = chunksection.getType(i2, k2, j2); + Block block = iblockdata.getBlock(); + + if (block.isTicking()) { + block.a(chunk.world, new BlockPosition(i2 + j, k2 + chunksection.getYPosition(), j2 + k), iblockdata, chunk.world.random); + } + } + } + } + } + } } diff --git a/NMS/NMS-v1_10_R1/src/com/songoda/core/nms/v1_10_R1/world/spawner/BBaseSpawnerImpl.java b/NMS/NMS-v1_10_R1/src/com/songoda/core/nms/v1_10_R1/world/spawner/BBaseSpawnerImpl.java new file mode 100644 index 00000000..18e7a641 --- /dev/null +++ b/NMS/NMS-v1_10_R1/src/com/songoda/core/nms/v1_10_R1/world/spawner/BBaseSpawnerImpl.java @@ -0,0 +1,165 @@ +package com.songoda.core.nms.v1_10_R1.world.spawner; + +import com.songoda.core.nms.ReflectionUtils; +import com.songoda.core.nms.world.BBaseSpawner; +import net.minecraft.server.v1_10_R1.AxisAlignedBB; +import net.minecraft.server.v1_10_R1.BlockPosition; +import net.minecraft.server.v1_10_R1.ChunkRegionLoader; +import net.minecraft.server.v1_10_R1.Entity; +import net.minecraft.server.v1_10_R1.EntityInsentient; +import net.minecraft.server.v1_10_R1.EnumParticle; +import net.minecraft.server.v1_10_R1.MobSpawnerAbstract; +import net.minecraft.server.v1_10_R1.MobSpawnerData; +import net.minecraft.server.v1_10_R1.NBTTagCompound; +import net.minecraft.server.v1_10_R1.NBTTagList; +import org.bukkit.craftbukkit.v1_10_R1.event.CraftEventFactory; +import org.bukkit.event.entity.CreatureSpawnEvent; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; + +public class BBaseSpawnerImpl implements BBaseSpawner { + private static Method iMethod, hMethod; + + private final MobSpawnerAbstract spawner; + + static { + try { + iMethod = MobSpawnerAbstract.class.getDeclaredMethod("i"); + iMethod.setAccessible(true); + + hMethod = MobSpawnerAbstract.class.getDeclaredMethod("h"); + hMethod.setAccessible(true); + } catch (NoSuchMethodException ex) { + ex.printStackTrace(); + } + } + + public BBaseSpawnerImpl(MobSpawnerAbstract spawner) { + this.spawner = spawner; + } + + /** + * This method calls {@link MobSpawnerAbstract#h()} using Reflections. + */ + @SuppressWarnings("JavadocReference") + @Override + public boolean isNearPlayer() throws InvocationTargetException, IllegalAccessException { + return (boolean) hMethod.invoke(spawner); + } + + /** + * This method is based on {@link MobSpawnerAbstract#c()}. + */ + @Override + public void tick() throws NoSuchFieldException, IllegalAccessException, InvocationTargetException { + BlockPosition blockposition = spawner.b(); + + if (spawner.a().isClientSide) { + double d0 = (float) blockposition.getX() + spawner.a().random.nextFloat(); + double d1 = (float) blockposition.getY() + spawner.a().random.nextFloat(); + double d2 = (float) blockposition.getZ() + spawner.a().random.nextFloat(); + + spawner.a().addParticle(EnumParticle.SMOKE_NORMAL, d0, d1, d2, 0D, 0D, 0D); + spawner.a().addParticle(EnumParticle.FLAME, d0, d1, d2, 0D, 0D, 0D); + + if (spawner.spawnDelay > 0) { + --spawner.spawnDelay; + } + + double spawnerD = (double) ReflectionUtils.getFieldValue(spawner, "d"); + + ReflectionUtils.setFieldValue(spawner, "e", spawnerD); + ReflectionUtils.setFieldValue(spawner, "d", (spawnerD + (double) (1000F / ((float) spawner.spawnDelay + 200F))) % 360D); + } else { + if (spawner.spawnDelay == -1) { + delay(spawner); + } + + if (spawner.spawnDelay > 0) { + --spawner.spawnDelay; + return; + } + + boolean flag = false; + int i = 0; + + int spawnCount = (int) ReflectionUtils.getFieldValue(spawner, "spawnCount"); + int spawnRange = (int) ReflectionUtils.getFieldValue(spawner, "spawnRange"); + int maxNearbyEntities = (int) ReflectionUtils.getFieldValue(spawner, "maxNearbyEntities"); + MobSpawnerData spawnData = (MobSpawnerData) ReflectionUtils.getFieldValue(spawner, "spawnData"); + + while (true) { + if (i >= spawnCount) { + if (flag) { + delay(spawner); + } + + break; + } + + NBTTagCompound nbttagcompound = spawnData.b(); + NBTTagList nbttaglist = nbttagcompound.getList("Pos", 6); + + net.minecraft.server.v1_10_R1.World world = spawner.a(); + + int j = nbttaglist.size(); + double d3 = j >= 1 ? nbttaglist.e(0) : (double) blockposition.getX() + (world.random.nextDouble() - world.random.nextDouble()) * (double) spawnRange + .5D; + double d4 = j >= 2 ? nbttaglist.e(1) : (double) (blockposition.getY() + world.random.nextInt(3) - 1); + double d5 = j >= 3 ? nbttaglist.e(2) : (double) blockposition.getZ() + (world.random.nextDouble() - world.random.nextDouble()) * (double) spawnRange + .5D; + + Entity entity = ChunkRegionLoader.a(nbttagcompound, world, d3, d4, d5, false); + + if (entity == null) { + return; + } + + int k = world.a(entity.getClass(), (new AxisAlignedBB(blockposition.getX(), + blockposition.getY(), + blockposition.getZ(), + blockposition.getX() + 1, + blockposition.getY() + 1, + blockposition.getZ() + 1)) + .g(spawnRange)).size(); + + if (k >= maxNearbyEntities) { + delay(spawner); + return; + } + + EntityInsentient entityinsentient = entity instanceof EntityInsentient ? (EntityInsentient) entity : null; + entity.setPositionRotation(entity.locX, entity.locY, entity.locZ, world.random.nextFloat() * 360.0F, 0.0F); + + if (entityinsentient == null || entityinsentient.cK() && entityinsentient.canSpawn()) { + if (spawnData.b().d() == 1 && spawnData.b().hasKeyOfType("id", 8) && entity instanceof EntityInsentient) { + ((EntityInsentient) entity).prepare(world.D(new BlockPosition(entity)), null); + } + + if (entity.world.spigotConfig.nerfSpawnerMobs) { + entity.fromMobSpawner = true; + } + + if (!CraftEventFactory.callSpawnerSpawnEvent(entity, blockposition).isCancelled()) { + ChunkRegionLoader.a(entity, world, CreatureSpawnEvent.SpawnReason.SPAWNER); + world.triggerEffect(2004, blockposition, 0); + if (entityinsentient != null) { + entityinsentient.doSpawnEffect(); + } + + flag = true; + } + } + + ++i; + } + } + } + + /** + * This method calls {@link MobSpawnerAbstract#i()} using Reflections. + */ + @SuppressWarnings("JavadocReference") + private void delay(MobSpawnerAbstract spawner) throws InvocationTargetException, IllegalAccessException { + iMethod.invoke(spawner); + } +} \ No newline at end of file diff --git a/NMS/NMS-v1_11_R1/src/com/songoda/core/nms/v1_11_R1/world/WorldCoreImpl.java b/NMS/NMS-v1_11_R1/src/com/songoda/core/nms/v1_11_R1/world/WorldCoreImpl.java index 191ba2fa..7d45f652 100644 --- a/NMS/NMS-v1_11_R1/src/com/songoda/core/nms/v1_11_R1/world/WorldCoreImpl.java +++ b/NMS/NMS-v1_11_R1/src/com/songoda/core/nms/v1_11_R1/world/WorldCoreImpl.java @@ -1,16 +1,26 @@ package com.songoda.core.nms.v1_11_R1.world; import com.songoda.core.nms.world.SItemStack; +import com.songoda.core.nms.ReflectionUtils; +import com.songoda.core.nms.v1_11_R1.world.spawner.BBaseSpawnerImpl; +import com.songoda.core.nms.world.BBaseSpawner; import com.songoda.core.nms.world.SSpawner; import com.songoda.core.nms.world.SWorld; import com.songoda.core.nms.world.WorldCore; +import net.minecraft.server.v1_11_R1.Block; +import net.minecraft.server.v1_11_R1.BlockPosition; +import net.minecraft.server.v1_11_R1.Chunk; +import net.minecraft.server.v1_11_R1.ChunkSection; +import net.minecraft.server.v1_11_R1.IBlockData; +import net.minecraft.server.v1_11_R1.MobSpawnerAbstract; +import net.minecraft.server.v1_11_R1.WorldServer; import org.bukkit.Location; import org.bukkit.World; import org.bukkit.block.CreatureSpawner; import org.bukkit.inventory.ItemStack; +import org.bukkit.craftbukkit.v1_11_R1.CraftChunk; public class WorldCoreImpl implements WorldCore { - @Override public SSpawner getSpawner(CreatureSpawner spawner) { return new SSpawnerImpl(spawner.getLocation()); @@ -30,4 +40,47 @@ public class WorldCoreImpl implements WorldCore { public SWorld getWorld(World world) { return new SWorldImpl(); } + + @Override + public BBaseSpawner getBaseSpawner(CreatureSpawner spawner) throws NoSuchFieldException, IllegalAccessException { + Object cTileEntity = ReflectionUtils.getFieldValue(spawner, "spawner"); + + return new BBaseSpawnerImpl((MobSpawnerAbstract) ReflectionUtils.getFieldValue(cTileEntity, "a")); + } + + /** + * Method is based on {@link WorldServer#j()}. + */ + @SuppressWarnings("JavadocReference") + @Override + public void randomTickChunk(org.bukkit.Chunk bukkitChunk, int tickAmount) throws NoSuchFieldException, IllegalAccessException { + Chunk chunk = ((CraftChunk) bukkitChunk).getHandle(); + + if (tickAmount > 0) { + int j = chunk.locX * 16; + int k = chunk.locZ * 16; + + for (ChunkSection chunksection : chunk.getSections()) { + if (chunksection != net.minecraft.server.v1_11_R1.Chunk.a && chunksection.shouldTick()) { + for (int i = 0; i < tickAmount; ++i) { + int worldL = (int) ReflectionUtils.getFieldValue(chunk.world, "l"); + worldL = worldL * 3 + 1013904223; + ReflectionUtils.setFieldValue(chunk.world, "l", worldL); + + int l1 = worldL >> 2; + int i2 = l1 & 15; + int j2 = l1 >> 8 & 15; + int k2 = l1 >> 16 & 15; + + IBlockData iblockdata = chunksection.getType(i2, k2, j2); + Block block = iblockdata.getBlock(); + + if (block.isTicking()) { + block.a(chunk.world, new BlockPosition(i2 + j, k2 + chunksection.getYPosition(), j2 + k), iblockdata, chunk.world.random); + } + } + } + } + } + } } diff --git a/NMS/NMS-v1_11_R1/src/com/songoda/core/nms/v1_11_R1/world/spawner/BBaseSpawnerImpl.java b/NMS/NMS-v1_11_R1/src/com/songoda/core/nms/v1_11_R1/world/spawner/BBaseSpawnerImpl.java new file mode 100644 index 00000000..bbb52105 --- /dev/null +++ b/NMS/NMS-v1_11_R1/src/com/songoda/core/nms/v1_11_R1/world/spawner/BBaseSpawnerImpl.java @@ -0,0 +1,160 @@ +package com.songoda.core.nms.v1_11_R1.world.spawner; + +import com.songoda.core.nms.ReflectionUtils; +import com.songoda.core.nms.world.BBaseSpawner; +import net.minecraft.server.v1_11_R1.AxisAlignedBB; +import net.minecraft.server.v1_11_R1.BlockPosition; +import net.minecraft.server.v1_11_R1.ChunkRegionLoader; +import net.minecraft.server.v1_11_R1.Entity; +import net.minecraft.server.v1_11_R1.EntityInsentient; +import net.minecraft.server.v1_11_R1.EnumParticle; +import net.minecraft.server.v1_11_R1.MobSpawnerAbstract; +import net.minecraft.server.v1_11_R1.MobSpawnerData; +import net.minecraft.server.v1_11_R1.NBTTagCompound; +import net.minecraft.server.v1_11_R1.NBTTagList; +import org.bukkit.craftbukkit.v1_11_R1.event.CraftEventFactory; +import org.bukkit.event.entity.CreatureSpawnEvent; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; + +public class BBaseSpawnerImpl implements BBaseSpawner { + private static Method iMethod, hMethod; + + private final MobSpawnerAbstract spawner; + + static { + try { + hMethod = MobSpawnerAbstract.class.getDeclaredMethod("h"); + hMethod.setAccessible(true); + + iMethod = MobSpawnerAbstract.class.getDeclaredMethod("i"); + iMethod.setAccessible(true); + } catch (NoSuchMethodException ex) { + ex.printStackTrace(); + } + } + + public BBaseSpawnerImpl(MobSpawnerAbstract spawner) { + this.spawner = spawner; + } + + /** + * This method calls {@link MobSpawnerAbstract#h()} using Reflections. + */ + @SuppressWarnings("JavadocReference") + @Override + public boolean isNearPlayer() throws InvocationTargetException, IllegalAccessException { + return (boolean) hMethod.invoke(spawner); + } + + /** + * This method is based on {@link MobSpawnerAbstract#c()}. + */ + @Override + public void tick() throws NoSuchFieldException, IllegalAccessException, InvocationTargetException { + BlockPosition blockposition = spawner.b(); + + if (spawner.a().isClientSide) { + double d0 = (float) blockposition.getX() + spawner.a().random.nextFloat(); + double d1 = (float) blockposition.getY() + spawner.a().random.nextFloat(); + double d2 = (float) blockposition.getZ() + spawner.a().random.nextFloat(); + + spawner.a().addParticle(EnumParticle.SMOKE_NORMAL, d0, d1, d2, 0D, 0D, 0D); + spawner.a().addParticle(EnumParticle.FLAME, d0, d1, d2, 0D, 0D, 0D); + + if (spawner.spawnDelay > 0) { + --spawner.spawnDelay; + } + + double spawnerD = (double) ReflectionUtils.getFieldValue(spawner, "d"); + + ReflectionUtils.setFieldValue(spawner, "e", spawnerD); + ReflectionUtils.setFieldValue(spawner, "d", (spawnerD + (double) (1000F / ((float) spawner.spawnDelay + 200F))) % 360D); + } else { + if (spawner.spawnDelay == -1) { + delay(spawner); + } + + if (spawner.spawnDelay > 0) { + --spawner.spawnDelay; + return; + } + + boolean flag = false; + int i = 0; + + int spawnCount = (int) ReflectionUtils.getFieldValue(spawner, "spawnCount"); + int spawnRange = (int) ReflectionUtils.getFieldValue(spawner, "spawnRange"); + int maxNearbyEntities = (int) ReflectionUtils.getFieldValue(spawner, "maxNearbyEntities"); + MobSpawnerData spawnData = (MobSpawnerData) ReflectionUtils.getFieldValue(spawner, "spawnData"); + + while (true) { + if (i >= spawnCount) { + if (flag) { + delay(spawner); + } + break; + } + + NBTTagCompound nbttagcompound = spawnData.b(); + NBTTagList nbttaglist = nbttagcompound.getList("Pos", 6); + net.minecraft.server.v1_11_R1.World world = spawner.a(); + int j = nbttaglist.size(); + double d3 = j >= 1 ? nbttaglist.e(0) : (double) blockposition.getX() + (world.random.nextDouble() - world.random.nextDouble()) * (double) spawnRange + .5D; + double d4 = j >= 2 ? nbttaglist.e(1) : (double) (blockposition.getY() + world.random.nextInt(3) - 1); + double d5 = j >= 3 ? nbttaglist.e(2) : (double) blockposition.getZ() + (world.random.nextDouble() - world.random.nextDouble()) * (double) spawnRange + .5D; + Entity entity = ChunkRegionLoader.a(nbttagcompound, world, d3, d4, d5, false); + if (entity == null) { + return; + } + + int k = world.a(entity.getClass(), (new AxisAlignedBB( + blockposition.getX(), + blockposition.getY(), + blockposition.getZ(), + blockposition.getX() + 1, + blockposition.getY() + 1, + blockposition.getZ() + 1)) + .g(spawnRange)).size(); + if (k >= maxNearbyEntities) { + delay(spawner); + return; + } + + EntityInsentient entityinsentient = entity instanceof EntityInsentient ? (EntityInsentient) entity : null; + entity.setPositionRotation(entity.locX, entity.locY, entity.locZ, world.random.nextFloat() * 360.0F, 0.0F); + if (entityinsentient == null || entityinsentient.cM() && entityinsentient.canSpawn()) { + if (spawnData.b().d() == 1 && spawnData.b().hasKeyOfType("id", 8) && entity instanceof EntityInsentient) { + ((EntityInsentient) entity).prepare(world.D(new BlockPosition(entity)), null); + } + + if (entity.world.spigotConfig.nerfSpawnerMobs) { + entity.fromMobSpawner = true; + } + + if (!CraftEventFactory.callSpawnerSpawnEvent(entity, blockposition).isCancelled()) { + ChunkRegionLoader.a(entity, world, CreatureSpawnEvent.SpawnReason.SPAWNER); + world.triggerEffect(2004, blockposition, 0); + + if (entityinsentient != null) { + entityinsentient.doSpawnEffect(); + } + + flag = true; + } + } + + ++i; + } + } + } + + /** + * This method calls {@link MobSpawnerAbstract#i()} using Reflections. + */ + @SuppressWarnings("JavadocReference") + private void delay(MobSpawnerAbstract spawner) throws InvocationTargetException, IllegalAccessException { + iMethod.invoke(spawner); + } +} \ No newline at end of file diff --git a/NMS/NMS-v1_12_R1/src/com/songoda/core/nms/v1_12_R1/world/WorldCoreImpl.java b/NMS/NMS-v1_12_R1/src/com/songoda/core/nms/v1_12_R1/world/WorldCoreImpl.java index aeb21a05..df653a91 100644 --- a/NMS/NMS-v1_12_R1/src/com/songoda/core/nms/v1_12_R1/world/WorldCoreImpl.java +++ b/NMS/NMS-v1_12_R1/src/com/songoda/core/nms/v1_12_R1/world/WorldCoreImpl.java @@ -1,16 +1,26 @@ package com.songoda.core.nms.v1_12_R1.world; import com.songoda.core.nms.world.SItemStack; +import com.songoda.core.nms.ReflectionUtils; +import com.songoda.core.nms.v1_12_R1.world.spawner.BBaseSpawnerImpl; +import com.songoda.core.nms.world.BBaseSpawner; import com.songoda.core.nms.world.SSpawner; import com.songoda.core.nms.world.SWorld; import com.songoda.core.nms.world.WorldCore; +import net.minecraft.server.v1_12_R1.Block; +import net.minecraft.server.v1_12_R1.BlockPosition; +import net.minecraft.server.v1_12_R1.Chunk; +import net.minecraft.server.v1_12_R1.ChunkSection; +import net.minecraft.server.v1_12_R1.IBlockData; +import net.minecraft.server.v1_12_R1.MobSpawnerAbstract; +import net.minecraft.server.v1_12_R1.WorldServer; import org.bukkit.Location; import org.bukkit.World; import org.bukkit.block.CreatureSpawner; import org.bukkit.inventory.ItemStack; +import org.bukkit.craftbukkit.v1_12_R1.CraftChunk; public class WorldCoreImpl implements WorldCore { - @Override public SSpawner getSpawner(CreatureSpawner spawner) { return new SSpawnerImpl(spawner.getLocation()); @@ -30,4 +40,47 @@ public class WorldCoreImpl implements WorldCore { public SWorld getWorld(World world) { return new SWorldImpl(); } + + @Override + public BBaseSpawner getBaseSpawner(CreatureSpawner spawner) throws NoSuchFieldException, IllegalAccessException { + Object cTileEntity = ReflectionUtils.getFieldValue(spawner, "tileEntity"); + + return new BBaseSpawnerImpl((MobSpawnerAbstract) ReflectionUtils.getFieldValue(cTileEntity, "a")); + } + + /** + * Method is based on {@link WorldServer#j()}. + */ + @SuppressWarnings("JavadocReference") + @Override + public void randomTickChunk(org.bukkit.Chunk bukkitChunk, int tickAmount) throws NoSuchFieldException, IllegalAccessException { + Chunk chunk = ((CraftChunk) bukkitChunk).getHandle(); + + if (tickAmount > 0) { + int j = chunk.locX * 16; + int k = chunk.locZ * 16; + + for (ChunkSection chunksection : chunk.getSections()) { + if (chunksection != net.minecraft.server.v1_12_R1.Chunk.a && chunksection.shouldTick()) { + for (int k1 = 0; k1 < tickAmount; ++k1) { + int worldL = (int) ReflectionUtils.getFieldValue(chunk.world, "l"); + worldL = worldL * 3 + 1013904223; + ReflectionUtils.setFieldValue(chunk.world, "l", worldL); + + int l1 = worldL >> 2; + int i2 = l1 & 15; + int j2 = l1 >> 8 & 15; + int k2 = l1 >> 16 & 15; + + IBlockData iblockdata = chunksection.getType(i2, k2, j2); + Block block = iblockdata.getBlock(); + + if (block.isTicking()) { + block.a(chunk.world, new BlockPosition(i2 + j, k2 + chunksection.getYPosition(), j2 + k), iblockdata, chunk.world.random); + } + } + } + } + } + } } diff --git a/NMS/NMS-v1_12_R1/src/com/songoda/core/nms/v1_12_R1/world/spawner/BBaseSpawnerImpl.java b/NMS/NMS-v1_12_R1/src/com/songoda/core/nms/v1_12_R1/world/spawner/BBaseSpawnerImpl.java new file mode 100644 index 00000000..47501034 --- /dev/null +++ b/NMS/NMS-v1_12_R1/src/com/songoda/core/nms/v1_12_R1/world/spawner/BBaseSpawnerImpl.java @@ -0,0 +1,164 @@ +package com.songoda.core.nms.v1_12_R1.world.spawner; + +import com.songoda.core.nms.ReflectionUtils; +import com.songoda.core.nms.world.BBaseSpawner; +import net.minecraft.server.v1_12_R1.AxisAlignedBB; +import net.minecraft.server.v1_12_R1.BlockPosition; +import net.minecraft.server.v1_12_R1.ChunkRegionLoader; +import net.minecraft.server.v1_12_R1.Entity; +import net.minecraft.server.v1_12_R1.EntityInsentient; +import net.minecraft.server.v1_12_R1.EnumParticle; +import net.minecraft.server.v1_12_R1.MobSpawnerAbstract; +import net.minecraft.server.v1_12_R1.MobSpawnerData; +import net.minecraft.server.v1_12_R1.NBTTagCompound; +import net.minecraft.server.v1_12_R1.NBTTagList; +import org.bukkit.craftbukkit.v1_12_R1.event.CraftEventFactory; +import org.bukkit.event.entity.CreatureSpawnEvent; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; + +public class BBaseSpawnerImpl implements BBaseSpawner { + private static Method iMethod; + + private final MobSpawnerAbstract spawner; + + static { + try { + iMethod = MobSpawnerAbstract.class.getDeclaredMethod("i"); + iMethod.setAccessible(true); + } catch (NoSuchMethodException ex) { + ex.printStackTrace(); + } + } + + public BBaseSpawnerImpl(MobSpawnerAbstract spawner) { + this.spawner = spawner; + } + + /** + * This method is based on {@link MobSpawnerAbstract#h()}. + */ + @SuppressWarnings("JavadocReference") + @Override + public boolean isNearPlayer() { + BlockPosition blockposition = spawner.b(); + + return spawner.a().isPlayerNearby( + (double) blockposition.getX() + 0.5D, + (double) blockposition.getY() + 0.5D, + (double) blockposition.getZ() + 0.5D, + spawner.requiredPlayerRange); + } + + /** + * This method is based on {@link MobSpawnerAbstract#c()}. + */ + @Override + public void tick() throws NoSuchFieldException, IllegalAccessException, InvocationTargetException { + BlockPosition blockposition = spawner.b(); + + if (spawner.a().isClientSide) { + double d0 = (float) blockposition.getX() + spawner.a().random.nextFloat(); + double d1 = (float) blockposition.getY() + spawner.a().random.nextFloat(); + double d2 = (float) blockposition.getZ() + spawner.a().random.nextFloat(); + spawner.a().addParticle(EnumParticle.SMOKE_NORMAL, d0, d1, d2, 0.0D, 0.0D, 0.0D); + spawner.a().addParticle(EnumParticle.FLAME, d0, d1, d2, 0.0D, 0.0D, 0.0D); + if (spawner.spawnDelay > 0) { + --spawner.spawnDelay; + } + + double spawnerD = (double) ReflectionUtils.getFieldValue(spawner, "d"); + + ReflectionUtils.setFieldValue(spawner, "e", spawnerD); + ReflectionUtils.setFieldValue(spawner, "d", (spawnerD + (double) (1000F / ((float) spawner.spawnDelay + 200F))) % 360D); + } else { + if (spawner.spawnDelay == -1) { + delay(spawner); + } + + if (spawner.spawnDelay > 0) { + --spawner.spawnDelay; + return; + } + + boolean flag = false; + int i = 0; + + MobSpawnerData spawnData = (MobSpawnerData) ReflectionUtils.getFieldValue(spawner, "spawnData"); + + while (true) { + if (i >= spawner.spawnCount) { + if (flag) { + delay(spawner); + } + break; + } + + NBTTagCompound nbttagcompound = spawnData.b(); + NBTTagList nbttaglist = nbttagcompound.getList("Pos", 6); + + net.minecraft.server.v1_12_R1.World world = spawner.a(); + + int j = nbttaglist.size(); + double d3 = j >= 1 ? nbttaglist.f(0) : (double) blockposition.getX() + (world.random.nextDouble() - world.random.nextDouble()) * (double) spawner.spawnRange + .5D; + double d4 = j >= 2 ? nbttaglist.f(1) : (double) (blockposition.getY() + world.random.nextInt(3) - 1); + double d5 = j >= 3 ? nbttaglist.f(2) : (double) blockposition.getZ() + (world.random.nextDouble() - world.random.nextDouble()) * (double) spawner.spawnRange + .5D; + + Entity entity = ChunkRegionLoader.a(nbttagcompound, world, d3, d4, d5, false); + + if (entity == null) { + return; + } + + int k = world.a(entity.getClass(), (new AxisAlignedBB( + blockposition.getX(), + blockposition.getY(), + blockposition.getZ(), + blockposition.getX() + 1, + blockposition.getY() + 1, + blockposition.getZ() + 1)) + .g(spawner.spawnRange)).size(); + + if (k >= spawner.maxNearbyEntities) { + delay(spawner); + return; + } + + EntityInsentient entityinsentient = entity instanceof EntityInsentient ? (EntityInsentient) entity : null; + entity.setPositionRotation(entity.locX, entity.locY, entity.locZ, world.random.nextFloat() * 360.0F, 0.0F); + + if (entityinsentient == null || entityinsentient.P() && entityinsentient.canSpawn()) { + if (spawnData.b().d() == 1 && spawnData.b().hasKeyOfType("id", 8) && entity instanceof EntityInsentient) { + ((EntityInsentient) entity).prepare(world.D(new BlockPosition(entity)), null); + } + + if (entity.world.spigotConfig.nerfSpawnerMobs) { + entity.fromMobSpawner = true; + } + + if (!CraftEventFactory.callSpawnerSpawnEvent(entity, blockposition).isCancelled()) { + ChunkRegionLoader.a(entity, world, CreatureSpawnEvent.SpawnReason.SPAWNER); + world.triggerEffect(2004, blockposition, 0); + + if (entityinsentient != null) { + entityinsentient.doSpawnEffect(); + } + + flag = true; + } + } + + ++i; + } + } + } + + /** + * This method calls {@link MobSpawnerAbstract#i()} using Reflections. + */ + @SuppressWarnings("JavadocReference") + private void delay(MobSpawnerAbstract spawner) throws InvocationTargetException, IllegalAccessException { + iMethod.invoke(spawner); + } +} \ No newline at end of file diff --git a/NMS/NMS-v1_13_R1/src/com/songoda/core/nms/v1_13_R1/world/WorldCoreImpl.java b/NMS/NMS-v1_13_R1/src/com/songoda/core/nms/v1_13_R1/world/WorldCoreImpl.java index 7e152faa..027c9521 100644 --- a/NMS/NMS-v1_13_R1/src/com/songoda/core/nms/v1_13_R1/world/WorldCoreImpl.java +++ b/NMS/NMS-v1_13_R1/src/com/songoda/core/nms/v1_13_R1/world/WorldCoreImpl.java @@ -1,16 +1,26 @@ package com.songoda.core.nms.v1_13_R1.world; import com.songoda.core.nms.world.SItemStack; +import com.songoda.core.nms.ReflectionUtils; +import com.songoda.core.nms.v1_13_R1.world.spawner.BBaseSpawnerImpl; +import com.songoda.core.nms.world.BBaseSpawner; import com.songoda.core.nms.world.SSpawner; import com.songoda.core.nms.world.SWorld; import com.songoda.core.nms.world.WorldCore; +import net.minecraft.server.v1_13_R1.BlockPosition; +import net.minecraft.server.v1_13_R1.Chunk; +import net.minecraft.server.v1_13_R1.ChunkSection; +import net.minecraft.server.v1_13_R1.Fluid; +import net.minecraft.server.v1_13_R1.IBlockData; +import net.minecraft.server.v1_13_R1.MobSpawnerAbstract; +import net.minecraft.server.v1_13_R1.WorldServer; import org.bukkit.Location; import org.bukkit.World; import org.bukkit.block.CreatureSpawner; import org.bukkit.inventory.ItemStack; +import org.bukkit.craftbukkit.v1_13_R1.CraftChunk; public class WorldCoreImpl implements WorldCore { - @Override public SSpawner getSpawner(CreatureSpawner spawner) { return new SSpawnerImpl(spawner.getLocation()); @@ -30,4 +40,51 @@ public class WorldCoreImpl implements WorldCore { public SWorld getWorld(World world) { return new SWorldImpl(); } + + @Override + public BBaseSpawner getBaseSpawner(CreatureSpawner spawner) throws NoSuchFieldException, IllegalAccessException { + Object cTileEntity = ReflectionUtils.getFieldValue(spawner, "tileEntity"); + + return new BBaseSpawnerImpl((MobSpawnerAbstract) ReflectionUtils.getFieldValue(cTileEntity, "a")); + } + + /** + * Method is based on {@link WorldServer#l()}. + */ + @SuppressWarnings("JavadocReference") + @Override + public void randomTickChunk(org.bukkit.Chunk bukkitChunk, int tickAmount) throws NoSuchFieldException, IllegalAccessException { + Chunk chunk = ((CraftChunk) bukkitChunk).getHandle(); + + if (tickAmount > 0) { + int j = chunk.locX * 16; + int k = chunk.locZ * 16; + + for (ChunkSection chunksection : chunk.getSections()) { + if (chunksection != net.minecraft.server.v1_13_R1.Chunk.a && chunksection.b()) { + for (int i = 0; i < tickAmount; ++i) { + int worldM = (int) ReflectionUtils.getFieldValue(chunk.world, "m"); + worldM = worldM * 3 + 1013904223; + ReflectionUtils.setFieldValue(chunk.world, "m", worldM); + + int l1 = worldM >> 2; + int i2 = l1 & 15; + int j2 = l1 >> 8 & 15; + int k2 = l1 >> 16 & 15; + + IBlockData iblockdata = chunksection.getType(i2, k2, j2); + Fluid fluid = chunksection.b(i2, k2, j2); + + if (iblockdata.t()) { + iblockdata.b(chunk.world, new BlockPosition(i2 + j, k2 + chunksection.getYPosition(), j2 + k), chunk.world.random); + } + + if (fluid.h()) { + fluid.b(chunk.world, new BlockPosition(i2 + j, k2 + chunksection.getYPosition(), j2 + k), chunk.world.random); + } + } + } + } + } + } } diff --git a/NMS/NMS-v1_13_R1/src/com/songoda/core/nms/v1_13_R1/world/spawner/BBaseSpawnerImpl.java b/NMS/NMS-v1_13_R1/src/com/songoda/core/nms/v1_13_R1/world/spawner/BBaseSpawnerImpl.java new file mode 100644 index 00000000..f19c4c64 --- /dev/null +++ b/NMS/NMS-v1_13_R1/src/com/songoda/core/nms/v1_13_R1/world/spawner/BBaseSpawnerImpl.java @@ -0,0 +1,167 @@ +package com.songoda.core.nms.v1_13_R1.world.spawner; + +import com.songoda.core.nms.ReflectionUtils; +import com.songoda.core.nms.world.BBaseSpawner; +import net.minecraft.server.v1_13_R1.AxisAlignedBB; +import net.minecraft.server.v1_13_R1.BlockPosition; +import net.minecraft.server.v1_13_R1.ChunkRegionLoader; +import net.minecraft.server.v1_13_R1.Entity; +import net.minecraft.server.v1_13_R1.EntityInsentient; +import net.minecraft.server.v1_13_R1.MobSpawnerAbstract; +import net.minecraft.server.v1_13_R1.MobSpawnerData; +import net.minecraft.server.v1_13_R1.NBTTagCompound; +import net.minecraft.server.v1_13_R1.NBTTagList; +import net.minecraft.server.v1_13_R1.Particles; +import org.bukkit.craftbukkit.v1_13_R1.event.CraftEventFactory; +import org.bukkit.event.entity.CreatureSpawnEvent; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; + +public class BBaseSpawnerImpl implements BBaseSpawner { + private static Method iMethod; + + private final MobSpawnerAbstract spawner; + + static { + try { + iMethod = MobSpawnerAbstract.class.getDeclaredMethod("i"); + iMethod.setAccessible(true); + } catch (NoSuchMethodException ex) { + ex.printStackTrace(); + } + } + + public BBaseSpawnerImpl(MobSpawnerAbstract spawner) { + this.spawner = spawner; + } + + /** + * This method is based on {@link MobSpawnerAbstract#h()}. + */ + @SuppressWarnings("JavadocReference") + @Override + public boolean isNearPlayer() { + BlockPosition blockposition = spawner.b(); + + return spawner.a().isPlayerNearby( + (double) blockposition.getX() + .5D, + (double) blockposition.getY() + .5D, + (double) blockposition.getZ() + .5D, + spawner.requiredPlayerRange); + } + + /** + * This method is based on {@link MobSpawnerAbstract#c()}. + */ + @Override + public void tick() throws NoSuchFieldException, IllegalAccessException, InvocationTargetException { + BlockPosition blockposition = spawner.b(); + + if (spawner.a().isClientSide) { + double d0 = (float) blockposition.getX() + spawner.a().random.nextFloat(); + double d1 = (float) blockposition.getY() + spawner.a().random.nextFloat(); + double d2 = (float) blockposition.getZ() + spawner.a().random.nextFloat(); + + spawner.a().addParticle(Particles.M, d0, d1, d2, 0D, 0D, 0D); + spawner.a().addParticle(Particles.y, d0, d1, d2, 0D, 0D, 0D); + + if (spawner.spawnDelay > 0) { + --spawner.spawnDelay; + } + + double spawnerE = (double) ReflectionUtils.getFieldValue(spawner, "e"); + + ReflectionUtils.setFieldValue(spawner, "f", spawnerE); + ReflectionUtils.setFieldValue(spawner, "e", (spawnerE + (double) (1000F / ((float) spawner.spawnDelay + 200F))) % 360D); + } else { + if (spawner.spawnDelay == -1) { + delay(spawner); + } + + if (spawner.spawnDelay > 0) { + --spawner.spawnDelay; + return; + } + + boolean flag = false; + int i = 0; + + MobSpawnerData spawnData = (MobSpawnerData) ReflectionUtils.getFieldValue(spawner, "spawnData"); + + while (true) { + if (i >= spawner.spawnCount) { + if (flag) { + delay(spawner); + } + + break; + } + + NBTTagCompound nbttagcompound = spawnData.b(); + NBTTagList nbttaglist = nbttagcompound.getList("Pos", 6); + + net.minecraft.server.v1_13_R1.World world = spawner.a(); + + int j = nbttaglist.size(); + double d3 = j >= 1 ? nbttaglist.k(0) : (double) blockposition.getX() + (world.random.nextDouble() - world.random.nextDouble()) * (double) spawner.spawnRange + .5D; + double d4 = j >= 2 ? nbttaglist.k(1) : (double) (blockposition.getY() + world.random.nextInt(3) - 1); + double d5 = j >= 3 ? nbttaglist.k(2) : (double) blockposition.getZ() + (world.random.nextDouble() - world.random.nextDouble()) * (double) spawner.spawnRange + .5D; + + Entity entity = ChunkRegionLoader.a(nbttagcompound, world, d3, d4, d5, false); + + if (entity == null) { + delay(spawner); + return; + } + + int k = world.a(entity.getClass(), (new AxisAlignedBB(blockposition.getX(), + blockposition.getY(), + blockposition.getZ(), + blockposition.getX() + 1, + blockposition.getY() + 1, + blockposition.getZ() + 1)) + .g(spawner.spawnRange)).size(); + + if (k >= spawner.maxNearbyEntities) { + delay(spawner); + return; + } + + EntityInsentient entityinsentient = entity instanceof EntityInsentient ? (EntityInsentient) entity : null; + entity.setPositionRotation(entity.locX, entity.locY, entity.locZ, world.random.nextFloat() * 360F, 0F); + + if (entityinsentient == null || entityinsentient.M() && entityinsentient.canSpawn()) { + if (spawnData.b().d() == 1 && spawnData.b().hasKeyOfType("id", 8) && entity instanceof EntityInsentient) { + ((EntityInsentient) entity).prepare(world.getDamageScaler(new BlockPosition(entity)), null, null); + } + + if (entity.world.spigotConfig.nerfSpawnerMobs) { + entity.fromMobSpawner = true; + } + + if (!CraftEventFactory.callSpawnerSpawnEvent(entity, blockposition).isCancelled()) { + ChunkRegionLoader.a(entity, world, CreatureSpawnEvent.SpawnReason.SPAWNER); + world.triggerEffect(2004, blockposition, 0); + + if (entityinsentient != null) { + entityinsentient.doSpawnEffect(); + } + + flag = true; + } + } + + ++i; + } + } + } + + /** + * This method calls {@link MobSpawnerAbstract#i()} using Reflections. + */ + @SuppressWarnings("JavadocReference") + private void delay(MobSpawnerAbstract spawner) throws InvocationTargetException, IllegalAccessException { + iMethod.invoke(spawner); + } +} diff --git a/NMS/NMS-v1_13_R2/src/com/songoda/core/nms/v1_13_R2/world/WorldCoreImpl.java b/NMS/NMS-v1_13_R2/src/com/songoda/core/nms/v1_13_R2/world/WorldCoreImpl.java index de90a615..6f4e89e9 100644 --- a/NMS/NMS-v1_13_R2/src/com/songoda/core/nms/v1_13_R2/world/WorldCoreImpl.java +++ b/NMS/NMS-v1_13_R2/src/com/songoda/core/nms/v1_13_R2/world/WorldCoreImpl.java @@ -1,16 +1,26 @@ package com.songoda.core.nms.v1_13_R2.world; import com.songoda.core.nms.world.SItemStack; +import com.songoda.core.nms.ReflectionUtils; +import com.songoda.core.nms.v1_13_R2.world.spawner.BBaseSpawnerImpl; +import com.songoda.core.nms.world.BBaseSpawner; import com.songoda.core.nms.world.SSpawner; import com.songoda.core.nms.world.SWorld; import com.songoda.core.nms.world.WorldCore; +import net.minecraft.server.v1_13_R2.BlockPosition; +import net.minecraft.server.v1_13_R2.Chunk; +import net.minecraft.server.v1_13_R2.ChunkSection; +import net.minecraft.server.v1_13_R2.Fluid; +import net.minecraft.server.v1_13_R2.IBlockData; +import net.minecraft.server.v1_13_R2.MobSpawnerAbstract; +import net.minecraft.server.v1_13_R2.WorldServer; import org.bukkit.Location; import org.bukkit.World; import org.bukkit.block.CreatureSpawner; import org.bukkit.inventory.ItemStack; +import org.bukkit.craftbukkit.v1_13_R2.CraftChunk; public class WorldCoreImpl implements WorldCore { - @Override public SSpawner getSpawner(CreatureSpawner spawner) { return new SSpawnerImpl(spawner.getLocation()); @@ -30,4 +40,58 @@ public class WorldCoreImpl implements WorldCore { public SWorld getWorld(World world) { return new SWorldImpl(); } + + @Override + public BBaseSpawner getBaseSpawner(CreatureSpawner spawner) throws NoSuchFieldException, IllegalAccessException { + Object cTileEntity = ReflectionUtils.getFieldValue(spawner, "tileEntity"); + + return new BBaseSpawnerImpl((MobSpawnerAbstract) ReflectionUtils.getFieldValue(cTileEntity, "a")); + } + + /** + * Method is based on {@link WorldServer#n_()}. + */ + @SuppressWarnings("JavadocReference") + @Override + public void randomTickChunk(org.bukkit.Chunk bukkitChunk, int tickAmount) throws NoSuchFieldException, IllegalAccessException { + Chunk chunk = ((CraftChunk) bukkitChunk).getHandle(); + + if (tickAmount > 0) { + int j = chunk.locX * 16; + int k = chunk.locZ * 16; + + chunk.world.methodProfiler.enter("tickBlocks"); + for (ChunkSection chunksection : chunk.getSections()) { + if (chunksection != net.minecraft.server.v1_13_R2.Chunk.a && chunksection.b()) { + for (int k1 = 0; k1 < tickAmount; ++k1) { + int worldM = (int) ReflectionUtils.getFieldValue(chunk.world, "m"); + worldM = worldM * 3 + 1013904223; + ReflectionUtils.setFieldValue(chunk.world, "m", worldM); + + int l1 = worldM >> 2; + int i2 = l1 & 15; + int j2 = l1 >> 8 & 15; + int k2 = l1 >> 16 & 15; + + IBlockData iblockdata = chunksection.getType(i2, k2, j2); + Fluid fluid = chunksection.b(i2, k2, j2); + + chunk.world.methodProfiler.enter("randomTick"); + + if (iblockdata.t()) { + iblockdata.b(chunk.world, new BlockPosition(i2 + j, k2 + chunksection.getYPosition(), j2 + k), chunk.world.random); + } + + if (fluid.h()) { + fluid.b(chunk.world, new BlockPosition(i2 + j, k2 + chunksection.getYPosition(), j2 + k), chunk.world.random); + } + + chunk.world.methodProfiler.exit(); + } + } + } + + chunk.world.methodProfiler.exit(); + } + } } diff --git a/NMS/NMS-v1_13_R2/src/com/songoda/core/nms/v1_13_R2/world/spawner/BBaseSpawnerImpl.java b/NMS/NMS-v1_13_R2/src/com/songoda/core/nms/v1_13_R2/world/spawner/BBaseSpawnerImpl.java new file mode 100644 index 00000000..af7a68cd --- /dev/null +++ b/NMS/NMS-v1_13_R2/src/com/songoda/core/nms/v1_13_R2/world/spawner/BBaseSpawnerImpl.java @@ -0,0 +1,172 @@ +package com.songoda.core.nms.v1_13_R2.world.spawner; + +import com.songoda.core.nms.ReflectionUtils; +import com.songoda.core.nms.world.BBaseSpawner; +import net.minecraft.server.v1_13_R2.AxisAlignedBB; +import net.minecraft.server.v1_13_R2.BlockPosition; +import net.minecraft.server.v1_13_R2.ChunkRegionLoader; +import net.minecraft.server.v1_13_R2.Entity; +import net.minecraft.server.v1_13_R2.EntityInsentient; +import net.minecraft.server.v1_13_R2.MobSpawnerAbstract; +import net.minecraft.server.v1_13_R2.MobSpawnerData; +import net.minecraft.server.v1_13_R2.NBTTagCompound; +import net.minecraft.server.v1_13_R2.NBTTagList; +import net.minecraft.server.v1_13_R2.Particles; +import org.bukkit.craftbukkit.v1_13_R2.event.CraftEventFactory; +import org.bukkit.event.entity.CreatureSpawnEvent; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.Iterator; + +public class BBaseSpawnerImpl implements BBaseSpawner { + private static Method iMethod; + + private final MobSpawnerAbstract spawner; + + static { + try { + iMethod = MobSpawnerAbstract.class.getDeclaredMethod("i"); + iMethod.setAccessible(true); + } catch (NoSuchMethodException ex) { + ex.printStackTrace(); + } + } + + public BBaseSpawnerImpl(MobSpawnerAbstract spawner) { + this.spawner = spawner; + } + + /** + * This method is based on {@link MobSpawnerAbstract#h()}. + */ + @SuppressWarnings("JavadocReference") + @Override + public boolean isNearPlayer() { + BlockPosition blockposition = spawner.b(); + + return spawner.a().b( + (double) blockposition.getX() + .5D, + (double) blockposition.getY() + .5D, + (double) blockposition.getZ() + .5D, + spawner.requiredPlayerRange); + } + + /** + * This method is based on {@link MobSpawnerAbstract#c()}. + */ + @Override + public void tick() throws NoSuchFieldException, IllegalAccessException, InvocationTargetException { + BlockPosition blockposition = spawner.b(); + + if (spawner.a().isClientSide) { + double d0 = (float) blockposition.getX() + spawner.a().random.nextFloat(); + double d1 = (float) blockposition.getY() + spawner.a().random.nextFloat(); + double d2 = (float) blockposition.getZ() + spawner.a().random.nextFloat(); + spawner.a().addParticle(Particles.M, d0, d1, d2, 0.0D, 0.0D, 0.0D); + spawner.a().addParticle(Particles.y, d0, d1, d2, 0.0D, 0.0D, 0.0D); + if (spawner.spawnDelay > 0) { + --spawner.spawnDelay; + } + + double spawnerE = (double) ReflectionUtils.getFieldValue(spawner, "e"); + + ReflectionUtils.setFieldValue(spawner, "f", spawnerE); + ReflectionUtils.setFieldValue(spawner, "e", (spawnerE + (double) (1000F / ((float) spawner.spawnDelay + 200F))) % 360D); + } else { + if (spawner.spawnDelay == -1) { + delay(spawner); + } + + if (spawner.spawnDelay > 0) { + --spawner.spawnDelay; + return; + } + + boolean flag = false; + int i = 0; + + MobSpawnerData spawnData = (MobSpawnerData) ReflectionUtils.getFieldValue(spawner, "spawnData"); + + while (true) { + if (i >= spawner.spawnCount) { + if (flag) { + delay(spawner); + } + + break; + } + + NBTTagCompound nbttagcompound = spawnData.b(); + NBTTagList nbttaglist = nbttagcompound.getList("Pos", 6); + net.minecraft.server.v1_13_R2.World world = spawner.a(); + int j = nbttaglist.size(); + double d3 = j >= 1 ? nbttaglist.k(0) : (double) blockposition.getX() + (world.random.nextDouble() - world.random.nextDouble()) * (double) spawner.spawnRange + .5D; + double d4 = j >= 2 ? nbttaglist.k(1) : (double) (blockposition.getY() + world.random.nextInt(3) - 1); + double d5 = j >= 3 ? nbttaglist.k(2) : (double) blockposition.getZ() + (world.random.nextDouble() - world.random.nextDouble()) * (double) spawner.spawnRange + .5D; + Entity entity = ChunkRegionLoader.a(nbttagcompound, world, d3, d4, d5, false); + if (entity == null) { + delay(spawner); + return; + } + + int k = world.a(entity.getClass(), (new AxisAlignedBB( + blockposition.getX(), + blockposition.getY(), + blockposition.getZ(), + blockposition.getX() + 1, + blockposition.getY() + 1, + blockposition.getZ() + 1)) + .g(spawner.spawnRange)).size(); + + if (k >= spawner.maxNearbyEntities) { + delay(spawner); + return; + } + + EntityInsentient entityinsentient = entity instanceof EntityInsentient ? (EntityInsentient) entity : null; + entity.setPositionRotation(entity.locX, entity.locY, entity.locZ, world.random.nextFloat() * 360.0F, 0.0F); + if (entityinsentient == null || entityinsentient.a(world, true) && entityinsentient.canSpawn()) { + if (spawnData.b().d() == 1 && spawnData.b().hasKeyOfType("id", 8) && entity instanceof EntityInsentient) { + ((EntityInsentient) entity).prepare(world.getDamageScaler(new BlockPosition(entity)), null, null); + } + + if (entity.world.spigotConfig.nerfSpawnerMobs) { + entity.fromMobSpawner = true; + } + + if (CraftEventFactory.callSpawnerSpawnEvent(entity, blockposition).isCancelled()) { + Entity vehicle = entity.getVehicle(); + if (vehicle != null) { + vehicle.dead = true; + } + + Entity passenger; + for (Iterator var19 = entity.getAllPassengers().iterator(); var19.hasNext(); passenger.dead = true) { + passenger = var19.next(); + } + } else { + ChunkRegionLoader.a(entity, world, CreatureSpawnEvent.SpawnReason.SPAWNER); + world.triggerEffect(2004, blockposition, 0); + + if (entityinsentient != null) { + entityinsentient.doSpawnEffect(); + } + + flag = true; + } + } + + ++i; + } + } + } + + /** + * This method calls {@link MobSpawnerAbstract#i()} using Reflections. + */ + @SuppressWarnings("JavadocReference") + private void delay(MobSpawnerAbstract spawner) throws InvocationTargetException, IllegalAccessException { + iMethod.invoke(spawner); + } +} diff --git a/NMS/NMS-v1_14_R1/src/com/songoda/core/nms/v1_14_R1/world/WorldCoreImpl.java b/NMS/NMS-v1_14_R1/src/com/songoda/core/nms/v1_14_R1/world/WorldCoreImpl.java index 5650cce8..b2ffa2a8 100644 --- a/NMS/NMS-v1_14_R1/src/com/songoda/core/nms/v1_14_R1/world/WorldCoreImpl.java +++ b/NMS/NMS-v1_14_R1/src/com/songoda/core/nms/v1_14_R1/world/WorldCoreImpl.java @@ -1,16 +1,28 @@ package com.songoda.core.nms.v1_14_R1.world; import com.songoda.core.nms.world.SItemStack; +import com.songoda.core.nms.ReflectionUtils; +import com.songoda.core.nms.v1_14_R1.world.spawner.BBaseSpawnerImpl; +import com.songoda.core.nms.world.BBaseSpawner; import com.songoda.core.nms.world.SSpawner; import com.songoda.core.nms.world.SWorld; import com.songoda.core.nms.world.WorldCore; +import net.minecraft.server.v1_14_R1.BlockPosition; +import net.minecraft.server.v1_14_R1.Chunk; +import net.minecraft.server.v1_14_R1.ChunkCoordIntPair; +import net.minecraft.server.v1_14_R1.ChunkSection; +import net.minecraft.server.v1_14_R1.Fluid; +import net.minecraft.server.v1_14_R1.GameProfilerFiller; +import net.minecraft.server.v1_14_R1.IBlockData; +import net.minecraft.server.v1_14_R1.MobSpawnerAbstract; +import net.minecraft.server.v1_14_R1.WorldServer; import org.bukkit.Location; import org.bukkit.World; import org.bukkit.block.CreatureSpawner; import org.bukkit.inventory.ItemStack; +import org.bukkit.craftbukkit.v1_14_R1.CraftChunk; public class WorldCoreImpl implements WorldCore { - @Override public SSpawner getSpawner(CreatureSpawner spawner) { return new SSpawnerImpl(spawner.getLocation()); @@ -30,4 +42,53 @@ public class WorldCoreImpl implements WorldCore { public SWorld getWorld(World world) { return new SWorldImpl(); } + + @Override + public BBaseSpawner getBaseSpawner(CreatureSpawner spawner) throws NoSuchFieldException, IllegalAccessException { + Object cTileEntity = ReflectionUtils.getFieldValue(spawner, "tileEntity"); + + return new BBaseSpawnerImpl((MobSpawnerAbstract) ReflectionUtils.getFieldValue(cTileEntity, "a")); + } + + /** + * Method is based on {@link WorldServer#a(Chunk, int)}. + */ + @Override + public void randomTickChunk(org.bukkit.Chunk bukkitChunk, int tickAmount) { + Chunk chunk = ((CraftChunk) bukkitChunk).getHandle(); + + if (tickAmount > 0) { + ChunkCoordIntPair chunkcoordintpair = chunk.getPos(); + int j = chunkcoordintpair.d(); + int k = chunkcoordintpair.e(); + + GameProfilerFiller profiler = chunk.world.getMethodProfiler(); + + profiler.enter("tickBlocks"); + for (ChunkSection chunksection : chunk.getSections()) { + if (chunksection != net.minecraft.server.v1_14_R1.Chunk.a && chunksection.d()) { + int j1 = chunksection.getYPosition(); + + for (int i = 0; i < tickAmount; ++i) { + BlockPosition blockposition2 = chunk.world.a(j, j1, k, 15); + profiler.enter("randomTick"); + IBlockData iblockdata = chunksection.getType(blockposition2.getX() - j, blockposition2.getY() - j1, blockposition2.getZ() - k); + + if (iblockdata.q()) { + iblockdata.b(chunk.world, blockposition2, chunk.world.random); + } + + Fluid fluid = iblockdata.p(); + if (fluid.h()) { + fluid.b(chunk.world, blockposition2, chunk.world.random); + } + + profiler.exit(); + } + } + } + + profiler.exit(); + } + } } diff --git a/NMS/NMS-v1_14_R1/src/com/songoda/core/nms/v1_14_R1/world/spawner/BBaseSpawnerImpl.java b/NMS/NMS-v1_14_R1/src/com/songoda/core/nms/v1_14_R1/world/spawner/BBaseSpawnerImpl.java new file mode 100644 index 00000000..a09bf563 --- /dev/null +++ b/NMS/NMS-v1_14_R1/src/com/songoda/core/nms/v1_14_R1/world/spawner/BBaseSpawnerImpl.java @@ -0,0 +1,202 @@ +package com.songoda.core.nms.v1_14_R1.world.spawner; + +import com.songoda.core.nms.ReflectionUtils; +import com.songoda.core.nms.world.BBaseSpawner; +import net.minecraft.server.v1_14_R1.AxisAlignedBB; +import net.minecraft.server.v1_14_R1.BlockPosition; +import net.minecraft.server.v1_14_R1.Entity; +import net.minecraft.server.v1_14_R1.EntityInsentient; +import net.minecraft.server.v1_14_R1.EntityPositionTypes; +import net.minecraft.server.v1_14_R1.EntityTypes; +import net.minecraft.server.v1_14_R1.EnumMobSpawn; +import net.minecraft.server.v1_14_R1.MobSpawnerAbstract; +import net.minecraft.server.v1_14_R1.NBTTagCompound; +import net.minecraft.server.v1_14_R1.NBTTagList; +import net.minecraft.server.v1_14_R1.Particles; +import net.minecraft.server.v1_14_R1.WeightedRandom; +import org.bukkit.craftbukkit.v1_14_R1.event.CraftEventFactory; +import org.bukkit.event.entity.CreatureSpawnEvent; + +import java.util.Iterator; +import java.util.Optional; + +public class BBaseSpawnerImpl implements BBaseSpawner { + private final MobSpawnerAbstract spawner; + + public BBaseSpawnerImpl(MobSpawnerAbstract spawner) { + this.spawner = spawner; + } + + /** + * This method is based on {@link MobSpawnerAbstract#h()}. + */ + @SuppressWarnings("JavadocReference") + @Override + public boolean isNearPlayer() { + BlockPosition blockposition = spawner.b(); + + return spawner.a().isPlayerNearby( + (double) blockposition.getX() + .5D, + (double) blockposition.getY() + .5D, + (double) blockposition.getZ() + .5D, + spawner.requiredPlayerRange); + } + + /** + * This method is based on {@link MobSpawnerAbstract#c()}. + */ + @Override + public void tick() throws NoSuchFieldException, IllegalAccessException { + net.minecraft.server.v1_14_R1.World world = spawner.a(); + BlockPosition blockposition = spawner.b(); + + if (world.isClientSide) { + double d0 = (float) blockposition.getX() + world.random.nextFloat(); + double d1 = (float) blockposition.getY() + world.random.nextFloat(); + double d2 = (float) blockposition.getZ() + world.random.nextFloat(); + + world.addParticle(Particles.SMOKE, d0, d1, d2, 0D, 0D, 0D); + world.addParticle(Particles.FLAME, d0, d1, d2, 0D, 0D, 0D); + + if (spawner.spawnDelay > 0) { + --spawner.spawnDelay; + } + + double spawnerE = (double) ReflectionUtils.getFieldValue(spawner, "e"); + ReflectionUtils.setFieldValue(spawner, "f", spawnerE); + ReflectionUtils.setFieldValue(spawner, "e", (spawnerE + (double) (1000F / ((float) spawner.spawnDelay + 200F))) % 360D); + } else { + if (spawner.spawnDelay == -1) { + delay(spawner); + } + + if (spawner.spawnDelay > 0) { + --spawner.spawnDelay; + return; + } + + boolean flag = false; + int i = 0; + + while (true) { + if (i >= spawner.spawnCount) { + if (flag) { + delay(spawner); + } + + break; + } + + NBTTagCompound nbttagcompound = spawner.spawnData.getEntity(); + Optional> optional = EntityTypes.a(nbttagcompound); + if (!optional.isPresent()) { + delay(spawner); + return; + } + + NBTTagList nbttaglist = nbttagcompound.getList("Pos", 6); + int j = nbttaglist.size(); + double d3 = j >= 1 ? nbttaglist.h(0) : (double) blockposition.getX() + (world.random.nextDouble() - world.random.nextDouble()) * (double) spawner.spawnRange + .5D; + double d4 = j >= 2 ? nbttaglist.h(1) : (double) (blockposition.getY() + world.random.nextInt(3) - 1); + double d5 = j >= 3 ? nbttaglist.h(2) : (double) blockposition.getZ() + (world.random.nextDouble() - world.random.nextDouble()) * (double) spawner.spawnRange + .5D; + if (world.c(optional.get().a(d3, d4, d5)) && EntityPositionTypes.a(optional.get(), world.getMinecraftWorld(), EnumMobSpawn.SPAWNER, new BlockPosition(d3, d4, d5), world.getRandom())) { + label112: + { + Entity entity = EntityTypes.a(nbttagcompound, world, (entity1) -> { + entity1.setPositionRotation(d3, d4, d5, entity1.yaw, entity1.pitch); + return entity1; + }); + if (entity == null) { + delay(spawner); + return; + } + + int k = world.a(entity.getClass(), (new AxisAlignedBB( + blockposition.getX(), + blockposition.getY(), + blockposition.getZ(), + blockposition.getX() + 1, + blockposition.getY() + 1, + blockposition.getZ() + 1)) + .g(spawner.spawnRange)).size(); + + if (k >= spawner.maxNearbyEntities) { + delay(spawner); + return; + } + + entity.setPositionRotation(entity.locX, entity.locY, entity.locZ, world.random.nextFloat() * 360F, 0F); + if (entity instanceof EntityInsentient) { + EntityInsentient entityinsentient = (EntityInsentient) entity; + if (!entityinsentient.a(world, EnumMobSpawn.SPAWNER) || !entityinsentient.a(world)) { + break label112; + } + + if (spawner.spawnData.getEntity().d() == 1 && spawner.spawnData.getEntity().hasKeyOfType("id", 8)) { + ((EntityInsentient) entity).prepare(world, world.getDamageScaler(new BlockPosition(entity)), EnumMobSpawn.SPAWNER, null, null); + } + } + + if (entity.world.spigotConfig.nerfSpawnerMobs) { + entity.fromMobSpawner = true; + } + + if (CraftEventFactory.callSpawnerSpawnEvent(entity, blockposition).isCancelled()) { + Entity vehicle = entity.getVehicle(); + if (vehicle != null) { + vehicle.dead = true; + } + + Entity passenger; + for (Iterator var19 = entity.getAllPassengers().iterator(); var19.hasNext(); passenger.dead = true) { + passenger = var19.next(); + } + } else { + addWithPassengers(spawner, entity); + world.triggerEffect(2004, blockposition, 0); + + if (entity instanceof EntityInsentient) { + ((EntityInsentient) entity).doSpawnEffect(); + } + + flag = true; + } + } + } + + ++i; + } + } + } + + /** + * This method is based on {@link MobSpawnerAbstract#i()}. + */ + @SuppressWarnings("JavadocReference") + private void delay(MobSpawnerAbstract spawner) { + if (spawner.maxSpawnDelay <= spawner.minSpawnDelay) { + spawner.spawnDelay = spawner.minSpawnDelay; + } else { + int i = spawner.maxSpawnDelay - spawner.minSpawnDelay; + spawner.spawnDelay = spawner.minSpawnDelay + spawner.a().random.nextInt(i); + } + + if (!spawner.mobs.isEmpty()) { + spawner.setSpawnData(WeightedRandom.a(spawner.a().random, spawner.mobs)); + } + + spawner.a(1); + } + + /** + * This method is based on {@link MobSpawnerAbstract#a(Entity)}. + */ + @SuppressWarnings("JavadocReference") + static void addWithPassengers(MobSpawnerAbstract spawner, Entity entity) { + if (spawner.a().addEntity(entity, CreatureSpawnEvent.SpawnReason.SPAWNER)) { + for (Entity value : entity.getPassengers()) { + addWithPassengers(spawner, value); + } + } + } +} \ No newline at end of file diff --git a/NMS/NMS-v1_15_R1/src/com/songoda/core/nms/v1_15_R1/world/WorldCoreImpl.java b/NMS/NMS-v1_15_R1/src/com/songoda/core/nms/v1_15_R1/world/WorldCoreImpl.java index 22fd035b..fa37a0ae 100644 --- a/NMS/NMS-v1_15_R1/src/com/songoda/core/nms/v1_15_R1/world/WorldCoreImpl.java +++ b/NMS/NMS-v1_15_R1/src/com/songoda/core/nms/v1_15_R1/world/WorldCoreImpl.java @@ -1,16 +1,28 @@ package com.songoda.core.nms.v1_15_R1.world; import com.songoda.core.nms.world.SItemStack; +import com.songoda.core.nms.ReflectionUtils; +import com.songoda.core.nms.v1_15_R1.world.spawner.BBaseSpawnerImpl; +import com.songoda.core.nms.world.BBaseSpawner; import com.songoda.core.nms.world.SSpawner; import com.songoda.core.nms.world.SWorld; import com.songoda.core.nms.world.WorldCore; +import net.minecraft.server.v1_15_R1.BlockPosition; +import net.minecraft.server.v1_15_R1.Chunk; +import net.minecraft.server.v1_15_R1.ChunkCoordIntPair; +import net.minecraft.server.v1_15_R1.ChunkSection; +import net.minecraft.server.v1_15_R1.Fluid; +import net.minecraft.server.v1_15_R1.GameProfilerFiller; +import net.minecraft.server.v1_15_R1.IBlockData; +import net.minecraft.server.v1_15_R1.MobSpawnerAbstract; +import net.minecraft.server.v1_15_R1.WorldServer; import org.bukkit.Location; import org.bukkit.World; import org.bukkit.block.CreatureSpawner; import org.bukkit.inventory.ItemStack; +import org.bukkit.craftbukkit.v1_15_R1.CraftChunk; public class WorldCoreImpl implements WorldCore { - @Override public SSpawner getSpawner(CreatureSpawner spawner) { return new SSpawnerImpl(spawner.getLocation()); @@ -30,4 +42,56 @@ public class WorldCoreImpl implements WorldCore { public SWorld getWorld(World world) { return new SWorldImpl(); } + + @Override + public BBaseSpawner getBaseSpawner(CreatureSpawner spawner) throws NoSuchFieldException, IllegalAccessException { + Object cTileEntity = ReflectionUtils.getFieldValue(spawner, "tileEntity"); + + return new BBaseSpawnerImpl((MobSpawnerAbstract) ReflectionUtils.getFieldValue(cTileEntity, "a")); + } + + /** + * Method is based on {@link WorldServer#a(net.minecraft.server.v1_15_R1.Chunk, int)}. + */ + @Override + public void randomTickChunk(org.bukkit.Chunk bukkitChunk, int tickAmount) { + Chunk chunk = ((CraftChunk) bukkitChunk).getHandle(); + + if (tickAmount > 0) { + ChunkCoordIntPair chunkcoordintpair = chunk.getPos(); + int j = chunkcoordintpair.d(); + int k = chunkcoordintpair.e(); + GameProfilerFiller profiler = chunk.world.getMethodProfiler(); + + profiler.enter("tickBlocks"); + + for (ChunkSection chunksection : chunk.getSections()) { + if (chunksection != Chunk.a && chunksection.d()) { + int j1 = chunksection.getYPosition(); + + for (int k1 = 0; k1 < tickAmount; ++k1) { + BlockPosition blockposition2 = chunk.world.a(j, j1, k, 15); + profiler.enter("randomTick"); + IBlockData iblockdata = chunksection.getType( + blockposition2.getX() - j, + blockposition2.getY() - j1, + blockposition2.getZ() - k); + + if (iblockdata.q()) { + iblockdata.b((WorldServer) chunk.world, blockposition2, chunk.world.random); + } + + Fluid fluid = iblockdata.getFluid(); + if (fluid.h()) { + fluid.b(chunk.world, blockposition2, chunk.world.random); + } + + profiler.exit(); + } + } + } + + profiler.exit(); + } + } } diff --git a/NMS/NMS-v1_15_R1/src/com/songoda/core/nms/v1_15_R1/world/spawner/BBaseSpawnerImpl.java b/NMS/NMS-v1_15_R1/src/com/songoda/core/nms/v1_15_R1/world/spawner/BBaseSpawnerImpl.java new file mode 100644 index 00000000..a353d577 --- /dev/null +++ b/NMS/NMS-v1_15_R1/src/com/songoda/core/nms/v1_15_R1/world/spawner/BBaseSpawnerImpl.java @@ -0,0 +1,203 @@ +package com.songoda.core.nms.v1_15_R1.world.spawner; + +import com.songoda.core.nms.ReflectionUtils; +import com.songoda.core.nms.world.BBaseSpawner; +import net.minecraft.server.v1_15_R1.AxisAlignedBB; +import net.minecraft.server.v1_15_R1.BlockPosition; +import net.minecraft.server.v1_15_R1.Entity; +import net.minecraft.server.v1_15_R1.EntityInsentient; +import net.minecraft.server.v1_15_R1.EntityPositionTypes; +import net.minecraft.server.v1_15_R1.EntityTypes; +import net.minecraft.server.v1_15_R1.EnumMobSpawn; +import net.minecraft.server.v1_15_R1.MobSpawnerAbstract; +import net.minecraft.server.v1_15_R1.NBTTagCompound; +import net.minecraft.server.v1_15_R1.NBTTagList; +import net.minecraft.server.v1_15_R1.Particles; +import net.minecraft.server.v1_15_R1.WeightedRandom; +import org.bukkit.craftbukkit.v1_15_R1.event.CraftEventFactory; +import org.bukkit.event.entity.CreatureSpawnEvent; + +import java.util.Iterator; +import java.util.Optional; + +public class BBaseSpawnerImpl implements BBaseSpawner { + private final MobSpawnerAbstract spawner; + + public BBaseSpawnerImpl(MobSpawnerAbstract spawner) { + this.spawner = spawner; + } + + /** + * This method is based on {@link MobSpawnerAbstract#h()}. + */ + @SuppressWarnings("JavadocReference") + @Override + public boolean isNearPlayer() { + BlockPosition blockposition = spawner.b(); + + return spawner.a().isPlayerNearby( + (double) blockposition.getX() + .5D, + (double) blockposition.getY() + .5D, + (double) blockposition.getZ() + .5D, + spawner.requiredPlayerRange); + } + + /** + * This method is based on {@link MobSpawnerAbstract#c()}. + */ + @Override + public void tick() throws NoSuchFieldException, IllegalAccessException { + net.minecraft.server.v1_15_R1.World world = spawner.a(); + BlockPosition blockposition = spawner.b(); + + if (world.isClientSide) { + double d0 = (double) blockposition.getX() + (double) world.random.nextFloat(); + double d1 = (double) blockposition.getY() + (double) world.random.nextFloat(); + double d2 = (double) blockposition.getZ() + (double) world.random.nextFloat(); + world.addParticle(Particles.SMOKE, d0, d1, d2, 0.0D, 0.0D, 0.0D); + world.addParticle(Particles.FLAME, d0, d1, d2, 0.0D, 0.0D, 0.0D); + if (spawner.spawnDelay > 0) { + --spawner.spawnDelay; + } + + double spawnerE = (double) ReflectionUtils.getFieldValue(spawner, "e"); + ReflectionUtils.setFieldValue(spawner, "f", spawnerE); + ReflectionUtils.setFieldValue(spawner, "e", (spawnerE + (double) (1000F / ((float) spawner.spawnDelay + 200F))) % 360D); + } else { + if (spawner.spawnDelay == -1) { + delay(spawner); + } + + if (spawner.spawnDelay > 0) { + --spawner.spawnDelay; + return; + } + + boolean flag = false; + int i = 0; + + while (true) { + if (i >= spawner.spawnCount) { + if (flag) { + delay(spawner); + } + + break; + } + + NBTTagCompound nbttagcompound = spawner.spawnData.getEntity(); + Optional> optional = EntityTypes.a(nbttagcompound); + if (!optional.isPresent()) { + delay(spawner); + return; + } + + NBTTagList nbttaglist = nbttagcompound.getList("Pos", 6); + int j = nbttaglist.size(); + double d3 = j >= 1 ? nbttaglist.h(0) : (double) blockposition.getX() + (world.random.nextDouble() - world.random.nextDouble()) * (double) spawner.spawnRange + .5D; + double d4 = j >= 2 ? nbttaglist.h(1) : (double) (blockposition.getY() + world.random.nextInt(3) - 1); + double d5 = j >= 3 ? nbttaglist.h(2) : (double) blockposition.getZ() + (world.random.nextDouble() - world.random.nextDouble()) * (double) spawner.spawnRange + .5D; + if (world.a(optional.get().a(d3, d4, d5)) && EntityPositionTypes.a(optional.get(), world.getMinecraftWorld(), EnumMobSpawn.SPAWNER, new BlockPosition(d3, d4, d5), world.getRandom())) { + label112: + { + Entity entity = EntityTypes.a(nbttagcompound, world, (entity1) -> { + entity1.setPositionRotation(d3, d4, d5, entity1.yaw, entity1.pitch); + return entity1; + }); + if (entity == null) { + delay(spawner); + return; + } + + int k = world.a(entity.getClass(), (new AxisAlignedBB( + blockposition.getX(), + blockposition.getY(), + blockposition.getZ(), + blockposition.getX() + 1, + blockposition.getY() + 1, + blockposition.getZ() + 1)) + .g(spawner.spawnRange)).size(); + + if (k >= spawner.maxNearbyEntities) { + delay(spawner); + return; + } + + entity.setPositionRotation(entity.locX(), entity.locY(), entity.locZ(), world.random.nextFloat() * 360F, 0F); + if (entity instanceof EntityInsentient) { + EntityInsentient entityinsentient = (EntityInsentient) entity; + if (!entityinsentient.a(world, EnumMobSpawn.SPAWNER) || !entityinsentient.a(world)) { + break label112; + } + + if (spawner.spawnData.getEntity().e() == 1 && spawner.spawnData.getEntity().hasKeyOfType("id", 8)) { + ((EntityInsentient) entity).prepare(world, world.getDamageScaler(new BlockPosition(entity)), EnumMobSpawn.SPAWNER, null, null); + } + + if (entityinsentient.world.spigotConfig.nerfSpawnerMobs) { + try { + entityinsentient.getClass().getField("aware").setBoolean(entityinsentient, false); + } catch (NoSuchFieldException ignore) { // Spigot 1.15.0 uses another flag for it + entityinsentient.fromMobSpawner = true; + } + } + } + + if (CraftEventFactory.callSpawnerSpawnEvent(entity, blockposition).isCancelled()) { + Entity vehicle = entity.getVehicle(); + if (vehicle != null) { + vehicle.dead = true; + } + + Entity passenger; + for (Iterator var19 = entity.getAllPassengers().iterator(); var19.hasNext(); passenger.dead = true) { + passenger = var19.next(); + } + } else { + addWithPassengers(spawner, entity); + world.triggerEffect(2004, blockposition, 0); + if (entity instanceof EntityInsentient) { + ((EntityInsentient) entity).doSpawnEffect(); + } + + flag = true; + } + } + } + + ++i; + } + } + } + + /** + * This method is based on {@link MobSpawnerAbstract#i()}. + */ + @SuppressWarnings("JavadocReference") + private void delay(MobSpawnerAbstract spawner) { + if (spawner.maxSpawnDelay <= spawner.minSpawnDelay) { + spawner.spawnDelay = spawner.minSpawnDelay; + } else { + int i = spawner.maxSpawnDelay - spawner.minSpawnDelay; + spawner.spawnDelay = spawner.minSpawnDelay + spawner.a().random.nextInt(i); + } + + if (!spawner.mobs.isEmpty()) { + spawner.setSpawnData(WeightedRandom.a(spawner.a().random, spawner.mobs)); + } + + spawner.a(1); + } + + /** + * This method is based on {@link MobSpawnerAbstract#a(Entity)}. + */ + @SuppressWarnings("JavadocReference") + static void addWithPassengers(MobSpawnerAbstract spawner, Entity entity) { + if (spawner.a().addEntity(entity, CreatureSpawnEvent.SpawnReason.SPAWNER)) { + for (Entity entity1 : entity.getPassengers()) { + addWithPassengers(spawner, entity1); + } + } + } +} \ No newline at end of file diff --git a/NMS/NMS-v1_16_R1/src/com/songoda/core/nms/v1_16_R1/world/WorldCoreImpl.java b/NMS/NMS-v1_16_R1/src/com/songoda/core/nms/v1_16_R1/world/WorldCoreImpl.java index 7167300d..573f20b1 100644 --- a/NMS/NMS-v1_16_R1/src/com/songoda/core/nms/v1_16_R1/world/WorldCoreImpl.java +++ b/NMS/NMS-v1_16_R1/src/com/songoda/core/nms/v1_16_R1/world/WorldCoreImpl.java @@ -1,16 +1,28 @@ package com.songoda.core.nms.v1_16_R1.world; import com.songoda.core.nms.world.SItemStack; +import com.songoda.core.nms.ReflectionUtils; +import com.songoda.core.nms.v1_16_R1.world.spawner.BBaseSpawnerImpl; +import com.songoda.core.nms.world.BBaseSpawner; import com.songoda.core.nms.world.SSpawner; import com.songoda.core.nms.world.SWorld; import com.songoda.core.nms.world.WorldCore; +import net.minecraft.server.v1_16_R1.BlockPosition; +import net.minecraft.server.v1_16_R1.Chunk; +import net.minecraft.server.v1_16_R1.ChunkCoordIntPair; +import net.minecraft.server.v1_16_R1.ChunkSection; +import net.minecraft.server.v1_16_R1.Fluid; +import net.minecraft.server.v1_16_R1.GameProfilerFiller; +import net.minecraft.server.v1_16_R1.IBlockData; +import net.minecraft.server.v1_16_R1.MobSpawnerAbstract; +import net.minecraft.server.v1_16_R1.WorldServer; import org.bukkit.Location; import org.bukkit.World; import org.bukkit.block.CreatureSpawner; import org.bukkit.inventory.ItemStack; +import org.bukkit.craftbukkit.v1_16_R1.CraftChunk; public class WorldCoreImpl implements WorldCore { - @Override public SSpawner getSpawner(CreatureSpawner spawner) { return new SSpawnerImpl(spawner.getLocation()); @@ -30,4 +42,57 @@ public class WorldCoreImpl implements WorldCore { public SWorld getWorld(World world) { return new SWorldImpl(); } + + @Override + public BBaseSpawner getBaseSpawner(CreatureSpawner spawner) throws NoSuchFieldException, IllegalAccessException { + Object cTileEntity = ReflectionUtils.getFieldValue(spawner, "tileEntity"); + + return new BBaseSpawnerImpl((MobSpawnerAbstract) ReflectionUtils.getFieldValue(cTileEntity, "a")); + } + + /** + * Method is based on {@link WorldServer#a(Chunk, int)}. + */ + @Override + public void randomTickChunk(org.bukkit.Chunk bukkitChunk, int tickAmount) { + Chunk chunk = ((CraftChunk) bukkitChunk).getHandle(); + + if (tickAmount > 0) { + ChunkCoordIntPair chunkcoordintpair = chunk.getPos(); + int j = chunkcoordintpair.d(); + int k = chunkcoordintpair.e(); + + GameProfilerFiller profiler = chunk.world.getMethodProfiler(); + + profiler.enter("tickBlocks"); + for (ChunkSection chunksection : chunk.getSections()) { + if (chunksection != Chunk.a && chunksection.d()) { + int j1 = chunksection.getYPosition(); + + for (int k1 = 0; k1 < tickAmount; ++k1) { + BlockPosition blockposition2 = chunk.world.a(j, j1, k, 15); + profiler.enter("randomTick"); + + IBlockData iblockdata = chunksection.getType( + blockposition2.getX() - j, + blockposition2.getY() - j1, + blockposition2.getZ() - k); + + if (iblockdata.isTicking()) { + iblockdata.b(chunk.world, blockposition2, chunk.world.random); + } + + Fluid fluid = iblockdata.getFluid(); + if (fluid.f()) { + fluid.b(chunk.world, blockposition2, chunk.world.random); + } + + profiler.exit(); + } + } + } + + profiler.exit(); + } + } } diff --git a/NMS/NMS-v1_16_R1/src/com/songoda/core/nms/v1_16_R1/world/spawner/BBaseSpawnerImpl.java b/NMS/NMS-v1_16_R1/src/com/songoda/core/nms/v1_16_R1/world/spawner/BBaseSpawnerImpl.java new file mode 100644 index 00000000..1ba12b09 --- /dev/null +++ b/NMS/NMS-v1_16_R1/src/com/songoda/core/nms/v1_16_R1/world/spawner/BBaseSpawnerImpl.java @@ -0,0 +1,197 @@ +package com.songoda.core.nms.v1_16_R1.world.spawner; + +import com.songoda.core.nms.ReflectionUtils; +import com.songoda.core.nms.world.BBaseSpawner; +import net.minecraft.server.v1_16_R1.AxisAlignedBB; +import net.minecraft.server.v1_16_R1.BlockPosition; +import net.minecraft.server.v1_16_R1.Entity; +import net.minecraft.server.v1_16_R1.EntityInsentient; +import net.minecraft.server.v1_16_R1.EntityPositionTypes; +import net.minecraft.server.v1_16_R1.EntityTypes; +import net.minecraft.server.v1_16_R1.EnumMobSpawn; +import net.minecraft.server.v1_16_R1.MobSpawnerAbstract; +import net.minecraft.server.v1_16_R1.NBTTagCompound; +import net.minecraft.server.v1_16_R1.NBTTagList; +import net.minecraft.server.v1_16_R1.Particles; +import net.minecraft.server.v1_16_R1.WeightedRandom; +import org.bukkit.craftbukkit.v1_16_R1.event.CraftEventFactory; +import org.bukkit.event.entity.CreatureSpawnEvent; + +import java.util.Iterator; +import java.util.Optional; + +public class BBaseSpawnerImpl implements BBaseSpawner { + private final MobSpawnerAbstract spawner; + + public BBaseSpawnerImpl(MobSpawnerAbstract spawner) { + this.spawner = spawner; + } + + /** + * This method is based on {@link MobSpawnerAbstract#h()}. + */ + @SuppressWarnings("JavadocReference") + @Override + public boolean isNearPlayer() { + BlockPosition blockposition = spawner.b(); + + return spawner.a().isPlayerNearby((double) blockposition.getX() + .5D, + (double) blockposition.getY() + .5D, + (double) blockposition.getZ() + .5D, + spawner.requiredPlayerRange); + } + + /** + * This method is based on {@link MobSpawnerAbstract#c()}. + */ + @Override + public void tick() throws NoSuchFieldException, IllegalAccessException { + net.minecraft.server.v1_16_R1.World world = spawner.a(); + BlockPosition blockposition = spawner.b(); + + if (world.isClientSide) { + double d0 = (double) blockposition.getX() + world.random.nextDouble(); + double d1 = (double) blockposition.getY() + world.random.nextDouble(); + double d2 = (double) blockposition.getZ() + world.random.nextDouble(); + world.addParticle(Particles.SMOKE, d0, d1, d2, 0.0D, 0.0D, 0.0D); + world.addParticle(Particles.FLAME, d0, d1, d2, 0.0D, 0.0D, 0.0D); + if (spawner.spawnDelay > 0) { + --spawner.spawnDelay; + } + + double spawnerE = (double) ReflectionUtils.getFieldValue(spawner, "e"); + ReflectionUtils.setFieldValue(spawner, "f", spawnerE); + ReflectionUtils.setFieldValue(spawner, "e", (spawnerE + (double) (1000F / ((float) spawner.spawnDelay + 200F))) % 360D); + } else { + if (spawner.spawnDelay == -1) { + delay(spawner); + } + + if (spawner.spawnDelay > 0) { + --spawner.spawnDelay; + return; + } + + boolean flag = false; + int i = 0; + + while (true) { + if (i >= spawner.spawnCount) { + if (flag) { + delay(spawner); + } + break; + } + + NBTTagCompound nbttagcompound = spawner.spawnData.getEntity(); + Optional> optional = EntityTypes.a(nbttagcompound); + if (!optional.isPresent()) { + delay(spawner); + return; + } + + NBTTagList nbttaglist = nbttagcompound.getList("Pos", 6); + int j = nbttaglist.size(); + double d3 = j >= 1 ? nbttaglist.h(0) : (double) blockposition.getX() + (world.random.nextDouble() - world.random.nextDouble()) * (double) spawner.spawnRange + .5D; + double d4 = j >= 2 ? nbttaglist.h(1) : (double) (blockposition.getY() + world.random.nextInt(3) - 1); + double d5 = j >= 3 ? nbttaglist.h(2) : (double) blockposition.getZ() + (world.random.nextDouble() - world.random.nextDouble()) * (double) spawner.spawnRange + .5D; + if (world.b(optional.get().a(d3, d4, d5)) && EntityPositionTypes.a(optional.get(), world.getMinecraftWorld(), EnumMobSpawn.SPAWNER, new BlockPosition(d3, d4, d5), world.getRandom())) { + label112: + { + Entity entity = EntityTypes.a(nbttagcompound, world, (entity1) -> { + entity1.setPositionRotation(d3, d4, d5, entity1.yaw, entity1.pitch); + return entity1; + }); + if (entity == null) { + delay(spawner); + return; + } + + int k = world.a(entity.getClass(), (new AxisAlignedBB( + blockposition.getX(), + blockposition.getY(), + blockposition.getZ(), + blockposition.getX() + 1, + blockposition.getY() + 1, + blockposition.getZ() + 1)) + .g(spawner.spawnRange)).size(); + if (k >= spawner.maxNearbyEntities) { + delay(spawner); + return; + } + + entity.setPositionRotation(entity.locX(), entity.locY(), entity.locZ(), world.random.nextFloat() * 360.0F, 0.0F); + if (entity instanceof EntityInsentient) { + EntityInsentient entityinsentient = (EntityInsentient) entity; + if (!entityinsentient.a(world, EnumMobSpawn.SPAWNER) || !entityinsentient.a(world)) { + break label112; + } + + if (spawner.spawnData.getEntity().e() == 1 && spawner.spawnData.getEntity().hasKeyOfType("id", 8)) { + ((EntityInsentient) entity).prepare(world, world.getDamageScaler(entity.getChunkCoordinates()), EnumMobSpawn.SPAWNER, null, null); + } + + if (entityinsentient.world.spigotConfig.nerfSpawnerMobs) { + entityinsentient.aware = false; + } + } + + if (CraftEventFactory.callSpawnerSpawnEvent(entity, blockposition).isCancelled()) { + Entity vehicle = entity.getVehicle(); + if (vehicle != null) { + vehicle.dead = true; + } + + Entity passenger; + for (Iterator var19 = entity.getAllPassengers().iterator(); var19.hasNext(); passenger.dead = true) { + passenger = var19.next(); + } + } else { + addWithPassengers(spawner, entity); + world.triggerEffect(2004, blockposition, 0); + if (entity instanceof EntityInsentient) { + ((EntityInsentient) entity).doSpawnEffect(); + } + + flag = true; + } + } + } + + ++i; + } + } + } + + /** + * This method is based on {@link MobSpawnerAbstract#i()}. + */ + @SuppressWarnings("JavadocReference") + private void delay(MobSpawnerAbstract spawner) { + if (spawner.maxSpawnDelay <= spawner.minSpawnDelay) { + spawner.spawnDelay = spawner.minSpawnDelay; + } else { + int i = spawner.maxSpawnDelay - spawner.minSpawnDelay; + spawner.spawnDelay = spawner.minSpawnDelay + spawner.a().random.nextInt(i); + } + + if (!spawner.mobs.isEmpty()) { + spawner.setSpawnData(WeightedRandom.a(spawner.a().random, spawner.mobs)); + } + + spawner.a(1); + } + + /** + * This method is based on {@link MobSpawnerAbstract#a(Entity)}. + */ + @SuppressWarnings("JavadocReference") + private void addWithPassengers(MobSpawnerAbstract spawner, Entity entity) { + if (spawner.a().addEntity(entity, CreatureSpawnEvent.SpawnReason.SPAWNER)) { + + for (Entity entity1 : entity.getPassengers()) { + addWithPassengers(spawner, entity1); + } + } + } +} diff --git a/NMS/NMS-v1_16_R2/src/com/songoda/core/nms/v1_16_R2/world/WorldCoreImpl.java b/NMS/NMS-v1_16_R2/src/com/songoda/core/nms/v1_16_R2/world/WorldCoreImpl.java index 17e0a0ad..e35abdbb 100644 --- a/NMS/NMS-v1_16_R2/src/com/songoda/core/nms/v1_16_R2/world/WorldCoreImpl.java +++ b/NMS/NMS-v1_16_R2/src/com/songoda/core/nms/v1_16_R2/world/WorldCoreImpl.java @@ -1,16 +1,28 @@ package com.songoda.core.nms.v1_16_R2.world; import com.songoda.core.nms.world.SItemStack; +import com.songoda.core.nms.ReflectionUtils; +import com.songoda.core.nms.v1_16_R2.world.spawner.BBaseSpawnerImpl; +import com.songoda.core.nms.world.BBaseSpawner; import com.songoda.core.nms.world.SSpawner; import com.songoda.core.nms.world.SWorld; import com.songoda.core.nms.world.WorldCore; +import net.minecraft.server.v1_16_R2.BlockPosition; +import net.minecraft.server.v1_16_R2.Chunk; +import net.minecraft.server.v1_16_R2.ChunkCoordIntPair; +import net.minecraft.server.v1_16_R2.ChunkSection; +import net.minecraft.server.v1_16_R2.Fluid; +import net.minecraft.server.v1_16_R2.GameProfilerFiller; +import net.minecraft.server.v1_16_R2.IBlockData; +import net.minecraft.server.v1_16_R2.MobSpawnerAbstract; +import net.minecraft.server.v1_16_R2.WorldServer; import org.bukkit.Location; import org.bukkit.World; import org.bukkit.block.CreatureSpawner; import org.bukkit.inventory.ItemStack; +import org.bukkit.craftbukkit.v1_16_R2.CraftChunk; public class WorldCoreImpl implements WorldCore { - @Override public SSpawner getSpawner(CreatureSpawner spawner) { return new SSpawnerImpl(spawner.getLocation()); @@ -30,4 +42,57 @@ public class WorldCoreImpl implements WorldCore { public SWorld getWorld(World world) { return new SWorldImpl(); } + + @Override + public BBaseSpawner getBaseSpawner(CreatureSpawner spawner) throws NoSuchFieldException, IllegalAccessException { + Object cTileEntity = ReflectionUtils.getFieldValue(spawner, "tileEntity"); + + return new BBaseSpawnerImpl((MobSpawnerAbstract) ReflectionUtils.getFieldValue(cTileEntity, "a")); + } + + /** + * Method is based on {@link WorldServer#a(Chunk, int)}. + */ + @Override + public void randomTickChunk(org.bukkit.Chunk bukkitChunk, int tickAmount) { + Chunk chunk = ((CraftChunk) bukkitChunk).getHandle(); + + if (tickAmount > 0) { + ChunkCoordIntPair chunkcoordintpair = chunk.getPos(); + int j = chunkcoordintpair.d(); + int k = chunkcoordintpair.e(); + + GameProfilerFiller profiler = chunk.world.getMethodProfiler(); + + profiler.enter("tickBlocks"); + for (ChunkSection chunksection : chunk.getSections()) { + if (chunksection != Chunk.a && chunksection.d()) { + int j1 = chunksection.getYPosition(); + + for (int i = 0; i < tickAmount; ++i) { + BlockPosition blockposition2 = chunk.world.a(j, j1, k, 15); + profiler.enter("randomTick"); + + IBlockData iblockdata = chunksection.getType( + blockposition2.getX() - j, + blockposition2.getY() - j1, + blockposition2.getZ() - k); + + if (iblockdata.isTicking()) { + iblockdata.b(chunk.world, blockposition2, chunk.world.random); + } + + Fluid fluid = iblockdata.getFluid(); + if (fluid.f()) { + fluid.b(chunk.world, blockposition2, chunk.world.random); + } + + profiler.exit(); + } + } + } + + profiler.exit(); + } + } } diff --git a/NMS/NMS-v1_16_R2/src/com/songoda/core/nms/v1_16_R2/world/spawner/BBaseSpawnerImpl.java b/NMS/NMS-v1_16_R2/src/com/songoda/core/nms/v1_16_R2/world/spawner/BBaseSpawnerImpl.java new file mode 100644 index 00000000..75e1b9ea --- /dev/null +++ b/NMS/NMS-v1_16_R2/src/com/songoda/core/nms/v1_16_R2/world/spawner/BBaseSpawnerImpl.java @@ -0,0 +1,195 @@ +package com.songoda.core.nms.v1_16_R2.world.spawner; + +import com.songoda.core.nms.ReflectionUtils; +import com.songoda.core.nms.world.BBaseSpawner; +import net.minecraft.server.v1_16_R2.AxisAlignedBB; +import net.minecraft.server.v1_16_R2.BlockPosition; +import net.minecraft.server.v1_16_R2.Entity; +import net.minecraft.server.v1_16_R2.EntityInsentient; +import net.minecraft.server.v1_16_R2.EntityPositionTypes; +import net.minecraft.server.v1_16_R2.EntityTypes; +import net.minecraft.server.v1_16_R2.EnumMobSpawn; +import net.minecraft.server.v1_16_R2.MobSpawnerAbstract; +import net.minecraft.server.v1_16_R2.NBTTagCompound; +import net.minecraft.server.v1_16_R2.NBTTagList; +import net.minecraft.server.v1_16_R2.Particles; +import net.minecraft.server.v1_16_R2.WeightedRandom; +import net.minecraft.server.v1_16_R2.WorldServer; +import org.bukkit.craftbukkit.v1_16_R2.event.CraftEventFactory; +import org.bukkit.event.entity.CreatureSpawnEvent; + +import java.util.Iterator; +import java.util.Optional; + +public class BBaseSpawnerImpl implements BBaseSpawner { + private final MobSpawnerAbstract spawner; + + public BBaseSpawnerImpl(MobSpawnerAbstract spawner) { + this.spawner = spawner; + } + + /** + * This method is based on {@link MobSpawnerAbstract#h()}. + */ + @SuppressWarnings("JavadocReference") + @Override + public boolean isNearPlayer() { + BlockPosition blockposition = spawner.b(); + + return spawner.a().isPlayerNearby( + (double) blockposition.getX() + .5D, + (double) blockposition.getY() + .5D, + (double) blockposition.getZ() + .5D, + spawner.requiredPlayerRange); + } + + /** + * This method is based on {@link MobSpawnerAbstract#c()}. + */ + @Override + public void tick() throws NoSuchFieldException, IllegalAccessException { + net.minecraft.server.v1_16_R2.World world = spawner.a(); + BlockPosition blockposition = spawner.b(); + + if (!(world instanceof WorldServer)) { + double d0 = (double) blockposition.getX() + world.random.nextDouble(); + double d1 = (double) blockposition.getY() + world.random.nextDouble(); + double d2 = (double) blockposition.getZ() + world.random.nextDouble(); + world.addParticle(Particles.SMOKE, d0, d1, d2, 0.0D, 0.0D, 0.0D); + world.addParticle(Particles.FLAME, d0, d1, d2, 0.0D, 0.0D, 0.0D); + if (spawner.spawnDelay > 0) { + --spawner.spawnDelay; + } + + double spawnerE = (double) ReflectionUtils.getFieldValue(spawner, "e"); + ReflectionUtils.setFieldValue(spawner, "f", spawnerE); + ReflectionUtils.setFieldValue(spawner, "e", (spawnerE + (double) (1000F / ((float) spawner.spawnDelay + 200F))) % 360D); + } else { + if (spawner.spawnDelay == -1) { + delay(spawner); + } + + if (spawner.spawnDelay > 0) { + --spawner.spawnDelay; + return; + } + + boolean flag = false; + int i = 0; + + while (true) { + if (i >= spawner.spawnCount) { + if (flag) { + delay(spawner); + } + + break; + } + + NBTTagCompound nbttagcompound = spawner.spawnData.getEntity(); + Optional> optional = EntityTypes.a(nbttagcompound); + if (!optional.isPresent()) { + delay(spawner); + return; + } + + NBTTagList nbttaglist = nbttagcompound.getList("Pos", 6); + int j = nbttaglist.size(); + double d3 = j >= 1 ? nbttaglist.h(0) : (double) blockposition.getX() + (world.random.nextDouble() - world.random.nextDouble()) * (double) spawner.spawnRange + .5D; + double d4 = j >= 2 ? nbttaglist.h(1) : (double) (blockposition.getY() + world.random.nextInt(3) - 1); + double d5 = j >= 3 ? nbttaglist.h(2) : (double) blockposition.getZ() + (world.random.nextDouble() - world.random.nextDouble()) * (double) spawner.spawnRange + .5D; + if (world.b(optional.get().a(d3, d4, d5))) { + WorldServer worldserver = (WorldServer) world; + if (EntityPositionTypes.a(optional.get(), worldserver, EnumMobSpawn.SPAWNER, new BlockPosition(d3, d4, d5), world.getRandom())) { + label116: + { + Entity entity = EntityTypes.a(nbttagcompound, world, (entity1) -> { + entity1.setPositionRotation(d3, d4, d5, entity1.yaw, entity1.pitch); + return entity1; + }); + if (entity == null) { + delay(spawner); + return; + } + + int k = world.a(entity.getClass(), (new AxisAlignedBB( + blockposition.getX(), + blockposition.getY(), + blockposition.getZ(), + blockposition.getX() + 1, + blockposition.getY() + 1, + blockposition.getZ() + 1)) + .g(spawner.spawnRange)).size(); + + if (k >= spawner.maxNearbyEntities) { + delay(spawner); + return; + } + + entity.setPositionRotation(entity.locX(), entity.locY(), entity.locZ(), world.random.nextFloat() * 360.0F, 0.0F); + if (entity instanceof EntityInsentient) { + EntityInsentient entityinsentient = (EntityInsentient) entity; + if (!entityinsentient.a(world, EnumMobSpawn.SPAWNER) || !entityinsentient.a(world)) { + break label116; + } + + if (spawner.spawnData.getEntity().e() == 1 && spawner.spawnData.getEntity().hasKeyOfType("id", 8)) { + ((EntityInsentient) entity).prepare(worldserver, world.getDamageScaler(entity.getChunkCoordinates()), EnumMobSpawn.SPAWNER, null, null); + } + + if (entityinsentient.world.spigotConfig.nerfSpawnerMobs) { + entityinsentient.aware = false; + } + } + + if (CraftEventFactory.callSpawnerSpawnEvent(entity, blockposition).isCancelled()) { + Entity vehicle = entity.getVehicle(); + if (vehicle != null) { + vehicle.dead = true; + } + + Entity passenger; + for (Iterator var20 = entity.getAllPassengers().iterator(); var20.hasNext(); passenger.dead = true) { + passenger = var20.next(); + } + } else { + if (!worldserver.addAllEntitiesSafely(entity, CreatureSpawnEvent.SpawnReason.SPAWNER)) { + delay(spawner); + return; + } + + world.triggerEffect(2004, blockposition, 0); + if (entity instanceof EntityInsentient) { + ((EntityInsentient) entity).doSpawnEffect(); + } + + flag = true; + } + } + } + } + + ++i; + } + } + } + + /** + * This method is based on {@link MobSpawnerAbstract#i()}. + */ + @SuppressWarnings("JavadocReference") + private void delay(MobSpawnerAbstract spawner) { + if (spawner.maxSpawnDelay <= spawner.minSpawnDelay) { + spawner.spawnDelay = spawner.minSpawnDelay; + } else { + int i = spawner.maxSpawnDelay - spawner.minSpawnDelay; + spawner.spawnDelay = spawner.minSpawnDelay + spawner.a().random.nextInt(i); + } + + if (!spawner.mobs.isEmpty()) { + spawner.setSpawnData(WeightedRandom.a(spawner.a().random, spawner.mobs)); + } + + spawner.a(1); + } +} diff --git a/NMS/NMS-v1_16_R3/src/com/songoda/core/nms/v1_16_R3/world/WorldCoreImpl.java b/NMS/NMS-v1_16_R3/src/com/songoda/core/nms/v1_16_R3/world/WorldCoreImpl.java index 80fec184..5b254bb7 100644 --- a/NMS/NMS-v1_16_R3/src/com/songoda/core/nms/v1_16_R3/world/WorldCoreImpl.java +++ b/NMS/NMS-v1_16_R3/src/com/songoda/core/nms/v1_16_R3/world/WorldCoreImpl.java @@ -1,16 +1,28 @@ package com.songoda.core.nms.v1_16_R3.world; import com.songoda.core.nms.world.SItemStack; +import com.songoda.core.nms.ReflectionUtils; +import com.songoda.core.nms.v1_16_R3.world.spawner.BBaseSpawnerImpl; +import com.songoda.core.nms.world.BBaseSpawner; import com.songoda.core.nms.world.SSpawner; import com.songoda.core.nms.world.SWorld; import com.songoda.core.nms.world.WorldCore; +import net.minecraft.server.v1_16_R3.BlockPosition; +import net.minecraft.server.v1_16_R3.Chunk; +import net.minecraft.server.v1_16_R3.ChunkCoordIntPair; +import net.minecraft.server.v1_16_R3.ChunkSection; +import net.minecraft.server.v1_16_R3.Fluid; +import net.minecraft.server.v1_16_R3.GameProfilerFiller; +import net.minecraft.server.v1_16_R3.IBlockData; +import net.minecraft.server.v1_16_R3.MobSpawnerAbstract; +import net.minecraft.server.v1_16_R3.WorldServer; import org.bukkit.Location; import org.bukkit.World; import org.bukkit.block.CreatureSpawner; import org.bukkit.inventory.ItemStack; +import org.bukkit.craftbukkit.v1_16_R3.CraftChunk; public class WorldCoreImpl implements WorldCore { - @Override public SSpawner getSpawner(CreatureSpawner spawner) { return new SSpawnerImpl(spawner.getLocation()); @@ -30,4 +42,58 @@ public class WorldCoreImpl implements WorldCore { public SWorld getWorld(World world) { return new SWorldImpl(); } + + @Override + public BBaseSpawner getBaseSpawner(CreatureSpawner spawner) throws NoSuchFieldException, IllegalAccessException { + Object cTileEntity = ReflectionUtils.getFieldValue(spawner, "tileEntity"); + + return new BBaseSpawnerImpl((MobSpawnerAbstract) ReflectionUtils.getFieldValue(cTileEntity, "a")); + } + + /** + * Method is based on {@link WorldServer#a(Chunk, int)}. + */ + @Override + public void randomTickChunk(org.bukkit.Chunk bukkitChunk, int tickAmount) { + Chunk chunk = ((CraftChunk) bukkitChunk).getHandle(); + + if (tickAmount > 0) { + GameProfilerFiller profiler = chunk.world.getMethodProfiler(); + + ChunkCoordIntPair chunkPos = chunk.getPos(); + int minBlockX = chunkPos.d(); + int minBlockZ = chunkPos.e(); + + profiler.enter("tickBlocks"); + for (ChunkSection cSection : chunk.getSections()) { + if (cSection != Chunk.a && // cSection != Chunk.EMPTY_SECTION + cSection.d()) { // #isRandomlyTicking() + int bottomBlockY = cSection.getYPosition(); + + for (int i = 0; i < tickAmount; ++i) { + BlockPosition randomBlockPos = chunk.world.a(minBlockX, bottomBlockY, minBlockZ, 15); // getBlockRandomPos + profiler.enter("randomTick"); + + IBlockData blockState = cSection.getType( + randomBlockPos.getX() - minBlockX, + randomBlockPos.getY() - bottomBlockY, + randomBlockPos.getZ() - minBlockZ); // #getBlockState + + if (blockState.isTicking()) { // #isRandomlyTicking() + blockState.b(chunk.world, randomBlockPos, chunk.world.random); // #randomTick + } + + Fluid fluidState = blockState.getFluid(); // #getFluidState() + if (fluidState.f()) { // #isRandomlyTicking() + fluidState.b(chunk.world, randomBlockPos, chunk.world.random); // #randomTick + } + + profiler.exit(); + } + } + } + + profiler.exit(); + } + } } diff --git a/NMS/NMS-v1_16_R3/src/com/songoda/core/nms/v1_16_R3/world/spawner/BBaseSpawnerImpl.java b/NMS/NMS-v1_16_R3/src/com/songoda/core/nms/v1_16_R3/world/spawner/BBaseSpawnerImpl.java new file mode 100644 index 00000000..e493bee6 --- /dev/null +++ b/NMS/NMS-v1_16_R3/src/com/songoda/core/nms/v1_16_R3/world/spawner/BBaseSpawnerImpl.java @@ -0,0 +1,198 @@ +package com.songoda.core.nms.v1_16_R3.world.spawner; + +import com.songoda.core.nms.ReflectionUtils; +import com.songoda.core.nms.world.BBaseSpawner; +import net.minecraft.server.v1_16_R3.AxisAlignedBB; +import net.minecraft.server.v1_16_R3.BlockPosition; +import net.minecraft.server.v1_16_R3.Entity; +import net.minecraft.server.v1_16_R3.EntityInsentient; +import net.minecraft.server.v1_16_R3.EntityPositionTypes; +import net.minecraft.server.v1_16_R3.EntityTypes; +import net.minecraft.server.v1_16_R3.EnumMobSpawn; +import net.minecraft.server.v1_16_R3.MobSpawnerAbstract; +import net.minecraft.server.v1_16_R3.NBTTagCompound; +import net.minecraft.server.v1_16_R3.NBTTagList; +import net.minecraft.server.v1_16_R3.Particles; +import net.minecraft.server.v1_16_R3.WeightedRandom; +import net.minecraft.server.v1_16_R3.WorldServer; +import org.bukkit.craftbukkit.v1_16_R3.event.CraftEventFactory; +import org.bukkit.event.entity.CreatureSpawnEvent; + +import java.util.Iterator; +import java.util.Optional; + +public class BBaseSpawnerImpl implements BBaseSpawner { + private final MobSpawnerAbstract spawner; + + public BBaseSpawnerImpl(MobSpawnerAbstract spawner) { + this.spawner = spawner; + } + + /** + * This method is based on {@link MobSpawnerAbstract#h()}. + */ + @SuppressWarnings("JavadocReference") + @Override + public boolean isNearPlayer() { + BlockPosition blockposition = spawner.b(); + + return spawner.a() + .isPlayerNearby((double) blockposition.getX() + 0.5D, + (double) blockposition.getY() + 0.5D, + (double) blockposition.getZ() + 0.5D, + spawner.requiredPlayerRange); + } + + /** + * This method is based on {@link MobSpawnerAbstract#c()}. + */ + @Override + public void tick() throws NoSuchFieldException, IllegalAccessException { + net.minecraft.server.v1_16_R3.World world = spawner.a(); + BlockPosition blockposition = spawner.b(); + + if (!(world instanceof WorldServer)) { + double d0 = (double) blockposition.getX() + world.random.nextDouble(); + double d1 = (double) blockposition.getY() + world.random.nextDouble(); + double d2 = (double) blockposition.getZ() + world.random.nextDouble(); + + world.addParticle(Particles.SMOKE, d0, d1, d2, 0.0D, 0.0D, 0.0D); + world.addParticle(Particles.FLAME, d0, d1, d2, 0.0D, 0.0D, 0.0D); + + if (spawner.spawnDelay > 0) { + --spawner.spawnDelay; + } + + double spawnerE = (double) ReflectionUtils.getFieldValue(spawner, "e"); + ReflectionUtils.setFieldValue(spawner, "f", spawnerE); + ReflectionUtils.setFieldValue(spawner, "e", (spawnerE + (double) (1000F / ((float) spawner.spawnDelay + 200F))) % 360D); + } else { + if (spawner.spawnDelay == -1) { + delay(spawner); + } + + if (spawner.spawnDelay > 0) { + --spawner.spawnDelay; + return; + } + + boolean flag = false; + int i = 0; + + while (true) { + if (i >= spawner.spawnCount) { + if (flag) { + delay(spawner); + } + + break; + } + + NBTTagCompound nbttagcompound = spawner.spawnData.getEntity(); + Optional> optional = EntityTypes.a(nbttagcompound); + if (!optional.isPresent()) { + delay(spawner); + return; + } + + NBTTagList nbttaglist = nbttagcompound.getList("Pos", 6); + int j = nbttaglist.size(); + double d3 = j >= 1 ? nbttaglist.h(0) : (double) blockposition.getX() + (world.random.nextDouble() - world.random.nextDouble()) * (double) spawner.spawnRange + .5D; + double d4 = j >= 2 ? nbttaglist.h(1) : (double) (blockposition.getY() + world.random.nextInt(3) - 1); + double d5 = j >= 3 ? nbttaglist.h(2) : (double) blockposition.getZ() + (world.random.nextDouble() - world.random.nextDouble()) * (double) spawner.spawnRange + .5D; + + if (world.b(optional.get().a(d3, d4, d5))) { + WorldServer worldserver = (WorldServer) world; + if (EntityPositionTypes.a(optional.get(), worldserver, EnumMobSpawn.SPAWNER, new BlockPosition(d3, d4, d5), world.getRandom())) { + label116: + { + Entity entity = EntityTypes.a(nbttagcompound, world, (entity1) -> { + entity1.setPositionRotation(d3, d4, d5, entity1.yaw, entity1.pitch); + return entity1; + }); + if (entity == null) { + delay(spawner); + return; + } + + int k = world.a(entity.getClass(), (new AxisAlignedBB( + blockposition.getX(), + blockposition.getY(), + blockposition.getZ(), + blockposition.getX() + 1, + blockposition.getY() + 1, + blockposition.getZ() + 1)) + .g(spawner.spawnRange)).size(); + + if (k >= spawner.maxNearbyEntities) { + delay(spawner); + return; + } + + entity.setPositionRotation(entity.locX(), entity.locY(), entity.locZ(), world.random.nextFloat() * 360F, 0F); + if (entity instanceof EntityInsentient) { + EntityInsentient entityinsentient = (EntityInsentient) entity; + if (!entityinsentient.a(world, EnumMobSpawn.SPAWNER) || !entityinsentient.a(world)) { + break label116; + } + + if (spawner.spawnData.getEntity().e() == 1 && spawner.spawnData.getEntity().hasKeyOfType("id", 8)) { + ((EntityInsentient) entity).prepare(worldserver, world.getDamageScaler(entity.getChunkCoordinates()), EnumMobSpawn.SPAWNER, null, null); + } + + if (entityinsentient.world.spigotConfig.nerfSpawnerMobs) { + entityinsentient.aware = false; + } + } + + if (CraftEventFactory.callSpawnerSpawnEvent(entity, blockposition).isCancelled()) { + Entity vehicle = entity.getVehicle(); + if (vehicle != null) { + vehicle.dead = true; + } + + Entity passenger; + for (Iterator var20 = entity.getAllPassengers().iterator(); var20.hasNext(); passenger.dead = true) { + passenger = var20.next(); + } + } else { + if (!worldserver.addAllEntitiesSafely(entity, CreatureSpawnEvent.SpawnReason.SPAWNER)) { + delay(spawner); + return; + } + + world.triggerEffect(2004, blockposition, 0); + if (entity instanceof EntityInsentient) { + ((EntityInsentient) entity).doSpawnEffect(); + } + + flag = true; + } + } + } + } + + ++i; + } + } + } + + /** + * This method is based on {@link MobSpawnerAbstract#i()}. + */ + @SuppressWarnings("JavadocReference") + private void delay(MobSpawnerAbstract spawner) { + if (spawner.maxSpawnDelay <= spawner.minSpawnDelay) { + spawner.spawnDelay = spawner.minSpawnDelay; + } else { + int i = spawner.maxSpawnDelay - spawner.minSpawnDelay; + spawner.spawnDelay = spawner.minSpawnDelay + spawner.a().random.nextInt(i); + } + + if (!spawner.mobs.isEmpty()) { + spawner.setSpawnData(WeightedRandom.a(spawner.a().random, spawner.mobs)); + } + + spawner.a(1); + } +} diff --git a/NMS/NMS-v1_17_R1/src/com/songoda/core/nms/v1_17_R1/world/WorldCoreImpl.java b/NMS/NMS-v1_17_R1/src/com/songoda/core/nms/v1_17_R1/world/WorldCoreImpl.java index 7152abfe..3b4ba2f3 100644 --- a/NMS/NMS-v1_17_R1/src/com/songoda/core/nms/v1_17_R1/world/WorldCoreImpl.java +++ b/NMS/NMS-v1_17_R1/src/com/songoda/core/nms/v1_17_R1/world/WorldCoreImpl.java @@ -1,12 +1,25 @@ package com.songoda.core.nms.v1_17_R1.world; +import com.songoda.core.nms.ReflectionUtils; +import com.songoda.core.nms.v1_17_R1.world.spawner.BBaseSpawnerImpl; +import com.songoda.core.nms.world.BBaseSpawner; import com.songoda.core.nms.world.SItemStack; import com.songoda.core.nms.world.SSpawner; import com.songoda.core.nms.world.SWorld; import com.songoda.core.nms.world.WorldCore; +import net.minecraft.core.BlockPosition; +import net.minecraft.server.level.WorldServer; +import net.minecraft.util.profiling.GameProfilerFiller; +import net.minecraft.world.level.ChunkCoordIntPair; +import net.minecraft.world.level.MobSpawnerAbstract; +import net.minecraft.world.level.block.state.IBlockData; +import net.minecraft.world.level.chunk.Chunk; +import net.minecraft.world.level.chunk.ChunkSection; +import net.minecraft.world.level.material.Fluid; import org.bukkit.Location; import org.bukkit.World; import org.bukkit.block.CreatureSpawner; +import org.bukkit.craftbukkit.v1_17_R1.CraftChunk; import org.bukkit.inventory.ItemStack; public class WorldCoreImpl implements WorldCore { @@ -30,4 +43,56 @@ public class WorldCoreImpl implements WorldCore { public SWorld getWorld(World world) { return new SWorldImpl(world); } + + @Override + public BBaseSpawner getBaseSpawner(CreatureSpawner spawner) throws NoSuchFieldException, IllegalAccessException { + Object cTileEntity = ReflectionUtils.getFieldValue(spawner, "tileEntity"); + + return new BBaseSpawnerImpl(spawner, (MobSpawnerAbstract) ReflectionUtils.getFieldValue(cTileEntity, "a")); + } + + /** + * Method is based on {@link WorldServer#a(Chunk, int)}. + */ + @Override + public void randomTickChunk(org.bukkit.Chunk bukkitChunk, int tickAmount) { + Chunk chunk = ((CraftChunk) bukkitChunk).getHandle(); + WorldServer world = (WorldServer) chunk.getWorld(); + + if (tickAmount > 0) { + GameProfilerFiller profiler = world.getMethodProfiler(); + + ChunkCoordIntPair chunkPos = chunk.getPos(); + int minBlockX = chunkPos.d(); + int minBlockZ = chunkPos.e(); + + profiler.enter("tickBlocks"); + for (ChunkSection cSection : chunk.getSections()) { + if (cSection != Chunk.a && // cSection != Chunk.EMPTY_SECTION + cSection.d()) { // #isRandomlyTicking + int bottomBlockY = cSection.getYPosition(); + + for (int k1 = 0; k1 < tickAmount; ++k1) { + BlockPosition bPos = world.a(minBlockX, bottomBlockY, minBlockZ, 15); + profiler.enter("randomTick"); + + IBlockData blockState = cSection.getType(bPos.getX() - minBlockX, bPos.getY() - bottomBlockY, bPos.getZ() - minBlockZ); + + if (blockState.isTicking()) { + blockState.b(world, bPos, chunk.getWorld().w); // #randomTick + } + + Fluid fluid = blockState.getFluid(); + if (fluid.f()) { // #isRandomlyTicking + fluid.b(world, bPos, chunk.getWorld().w); // #randomTick + } + + profiler.exit(); + } + } + } + + profiler.exit(); + } + } } diff --git a/NMS/NMS-v1_17_R1/src/com/songoda/core/nms/v1_17_R1/world/spawner/BBaseSpawnerImpl.java b/NMS/NMS-v1_17_R1/src/com/songoda/core/nms/v1_17_R1/world/spawner/BBaseSpawnerImpl.java new file mode 100644 index 00000000..4a06dc0a --- /dev/null +++ b/NMS/NMS-v1_17_R1/src/com/songoda/core/nms/v1_17_R1/world/spawner/BBaseSpawnerImpl.java @@ -0,0 +1,171 @@ +package com.songoda.core.nms.v1_17_R1.world.spawner; + +import com.songoda.core.nms.world.BBaseSpawner; +import net.minecraft.core.BlockPosition; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.nbt.NBTTagList; +import net.minecraft.server.level.WorldServer; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.EntityInsentient; +import net.minecraft.world.entity.EntityPositionTypes; +import net.minecraft.world.entity.EntityTypes; +import net.minecraft.world.entity.EnumMobSpawn; +import net.minecraft.world.level.MobSpawnerAbstract; +import net.minecraft.world.level.World; +import net.minecraft.world.phys.AxisAlignedBB; +import org.bukkit.block.CreatureSpawner; +import org.bukkit.craftbukkit.v1_17_R1.CraftWorld; +import org.bukkit.craftbukkit.v1_17_R1.block.CraftCreatureSpawner; +import org.bukkit.craftbukkit.v1_17_R1.event.CraftEventFactory; +import org.bukkit.event.entity.CreatureSpawnEvent; + +import java.util.Optional; +import java.util.Random; + +public class BBaseSpawnerImpl implements BBaseSpawner { + private final CreatureSpawner bukkitSpawner; + private final MobSpawnerAbstract spawner; + + private static final Random spawnerFieldP = new Random(); // Field p in MobSpawnerAbstract is private - We use one random for *all* our spawners (should be fine, right?) + + public BBaseSpawnerImpl(CreatureSpawner bukkitSpawner, MobSpawnerAbstract spawner) { + this.bukkitSpawner = bukkitSpawner; + this.spawner = spawner; + } + + /** + * This method is based on {@link MobSpawnerAbstract#c(World, BlockPosition)}. + */ + @SuppressWarnings("JavadocReference") + @Override + public boolean isNearPlayer() { + BlockPosition bPos = getBlockPosition(); + + return getWorld().isPlayerNearby((double) bPos.getX() + 0.5D, (double) bPos.getY() + 0.5D, (double) bPos.getZ() + 0.5D, this.spawner.n); + } + + /** + * This method is based on {@link MobSpawnerAbstract#a(WorldServer, BlockPosition)}. + */ + @Override + public void tick() { + WorldServer world = getWorld(); + BlockPosition bPos = getBlockPosition(); + + if (this.spawner.d == -1) { + this.delay(world, bPos); + } + + if (this.spawner.d > 0) { + --this.spawner.d; + } else { + boolean flag = false; + int i = 0; + + while (true) { + if (i >= this.spawner.k) { + if (flag) { + this.delay(world, bPos); + } + break; + } + + NBTTagCompound nbttagcompound = this.spawner.f.getEntity(); + Optional> optional = EntityTypes.a(nbttagcompound); + if (optional.isEmpty()) { + this.delay(world, bPos); + return; + } + + NBTTagList nbttaglist = nbttagcompound.getList("Pos", 6); + int j = nbttaglist.size(); + double d0 = j >= 1 ? nbttaglist.h(0) : (double) bPos.getX() + (world.w.nextDouble() - world.w.nextDouble()) * (double) this.spawner.o + 0.5D; + double d1 = j >= 2 ? nbttaglist.h(1) : (double) (bPos.getY() + world.w.nextInt(3) - 1); + double d2 = j >= 3 ? nbttaglist.h(2) : (double) bPos.getZ() + (world.w.nextDouble() - world.w.nextDouble()) * (double) this.spawner.o + 0.5D; + if (world.b(optional.get().a(d0, d1, d2)) && EntityPositionTypes.a((EntityTypes) optional.get(), world, EnumMobSpawn.c, new BlockPosition(d0, d1, d2), world.getRandom())) { + label107: + { + Entity entity = EntityTypes.a(nbttagcompound, world, (entity1) -> { + entity1.setPositionRotation(d0, d1, d2, entity1.getYRot(), entity1.getXRot()); + return entity1; + }); + if (entity == null) { + this.delay(world, bPos); + return; + } + + int k = world.a(entity.getClass(), (new AxisAlignedBB(bPos.getX(), bPos.getY(), bPos.getZ(), bPos.getX() + 1, bPos.getY() + 1, bPos.getZ() + 1)).g(this.spawner.o)).size(); + if (k >= this.spawner.m) { + this.delay(world, bPos); + return; + } + + entity.setPositionRotation(entity.locX(), entity.locY(), entity.locZ(), world.w.nextFloat() * 360.0F, 0.0F); + if (entity instanceof EntityInsentient entityinsentient) { + if (!entityinsentient.a(world, EnumMobSpawn.c) || !entityinsentient.a(world)) { + break label107; + } + + if (this.spawner.f.getEntity().e() == 1 && this.spawner.f.getEntity().hasKeyOfType("id", 8)) { + ((EntityInsentient) entity).prepare(world, world.getDamageScaler(entity.getChunkCoordinates()), EnumMobSpawn.c, null, null); + } + + if (entityinsentient.t.spigotConfig.nerfSpawnerMobs) { + entityinsentient.aware = false; + } + } + + if (CraftEventFactory.callSpawnerSpawnEvent(entity, bPos).isCancelled()) { + Entity vehicle = entity.getVehicle(); + if (vehicle != null) { + vehicle.die(); + } + + for (Entity passenger : entity.getAllPassengers()) { + passenger.die(); + } + } else { + if (!world.addAllEntitiesSafely(entity, CreatureSpawnEvent.SpawnReason.SPAWNER)) { + this.delay(world, bPos); + return; + } + + world.triggerEffect(2004, bPos, 0); + if (entity instanceof EntityInsentient) { + ((EntityInsentient) entity).doSpawnEffect(); + } + + flag = true; + } + } + } + + ++i; + } + } + } + + /** + * This method is based on {@link MobSpawnerAbstract#d(World, BlockPosition)}. + */ + @SuppressWarnings("JavadocReference") + private void delay(WorldServer world, BlockPosition bPos) { + if (this.spawner.j <= this.spawner.i) { + this.spawner.d = this.spawner.i; + } else { + this.spawner.d = this.spawner.i + spawnerFieldP.nextInt(this.spawner.j - this.spawner.i); + } + + this.spawner.e.b(spawnerFieldP) + .ifPresent((mobspawnerdata) -> this.spawner.setSpawnData(world, bPos, mobspawnerdata)); + this.spawner.a(world, getBlockPosition(), 1); + } + + private WorldServer getWorld() { + return ((CraftWorld) this.bukkitSpawner.getWorld()).getHandle(); + } + + private BlockPosition getBlockPosition() { + return ((CraftCreatureSpawner) this.bukkitSpawner).getPosition(); + } +} diff --git a/NMS/NMS-v1_8_R1/src/com/songoda/core/nms/v1_8_R1/world/WorldCoreImpl.java b/NMS/NMS-v1_8_R1/src/com/songoda/core/nms/v1_8_R1/world/WorldCoreImpl.java index ef77f758..33364b37 100644 --- a/NMS/NMS-v1_8_R1/src/com/songoda/core/nms/v1_8_R1/world/WorldCoreImpl.java +++ b/NMS/NMS-v1_8_R1/src/com/songoda/core/nms/v1_8_R1/world/WorldCoreImpl.java @@ -1,16 +1,26 @@ package com.songoda.core.nms.v1_8_R1.world; import com.songoda.core.nms.world.SItemStack; +import com.songoda.core.nms.ReflectionUtils; +import com.songoda.core.nms.v1_8_R1.world.spawner.BBaseSpawnerImpl; +import com.songoda.core.nms.world.BBaseSpawner; import com.songoda.core.nms.world.SSpawner; import com.songoda.core.nms.world.SWorld; import com.songoda.core.nms.world.WorldCore; +import net.minecraft.server.v1_8_R1.Block; +import net.minecraft.server.v1_8_R1.BlockPosition; +import net.minecraft.server.v1_8_R1.Chunk; +import net.minecraft.server.v1_8_R1.ChunkSection; +import net.minecraft.server.v1_8_R1.IBlockData; +import net.minecraft.server.v1_8_R1.MobSpawnerAbstract; +import net.minecraft.server.v1_8_R1.WorldServer; import org.bukkit.Location; import org.bukkit.World; import org.bukkit.block.CreatureSpawner; import org.bukkit.inventory.ItemStack; +import org.bukkit.craftbukkit.v1_8_R1.CraftChunk; public class WorldCoreImpl implements WorldCore { - @Override public SSpawner getSpawner(CreatureSpawner spawner) { return new SSpawnerImpl(spawner.getLocation()); @@ -30,4 +40,50 @@ public class WorldCoreImpl implements WorldCore { public SWorld getWorld(World world) { return new SWorldImpl(); } + + @Override + public BBaseSpawner getBaseSpawner(CreatureSpawner spawner) throws NoSuchFieldException, IllegalAccessException { + Object cTileEntity = ReflectionUtils.getFieldValue(spawner, "spawner"); + + return new BBaseSpawnerImpl((MobSpawnerAbstract) ReflectionUtils.getFieldValue(cTileEntity, "a")); + } + + /** + * Method is based on {@link WorldServer#h()}. + */ + @SuppressWarnings("JavadocReference") + @Override + public void randomTickChunk(org.bukkit.Chunk bukkitChunk, int tickAmount) throws NoSuchFieldException, IllegalAccessException { + Chunk chunk = ((CraftChunk) bukkitChunk).getHandle(); + + if (tickAmount > 0) { + int k = chunk.locX * 16; + int l = chunk.locZ * 16; + + for (ChunkSection cSection : chunk.getSections()) { + if (cSection != null && cSection.shouldTick()) { + + for (int i = 0; i < tickAmount; ++i) { + int m = (int) ReflectionUtils.getFieldValue(chunk.world, "m"); + + m = m * 3 + 1013904223; + ReflectionUtils.setFieldValue(chunk.world, "m", m); + + int i2 = m >> 2; + int j2 = i2 & 15; + int k2 = i2 >> 8 & 15; + int l2 = i2 >> 16 & 15; + + BlockPosition blockposition2 = new BlockPosition(j2 + k, l2 + cSection.getYPosition(), k2 + l); + IBlockData iblockdata = cSection.getType(j2, l2, k2); + Block block = iblockdata.getBlock(); + + if (block.isTicking()) { + block.a(chunk.world, blockposition2, iblockdata, chunk.world.random); + } + } + } + } + } + } } diff --git a/NMS/NMS-v1_8_R1/src/com/songoda/core/nms/v1_8_R1/world/spawner/BBaseSpawnerImpl.java b/NMS/NMS-v1_8_R1/src/com/songoda/core/nms/v1_8_R1/world/spawner/BBaseSpawnerImpl.java new file mode 100644 index 00000000..69237cf4 --- /dev/null +++ b/NMS/NMS-v1_8_R1/src/com/songoda/core/nms/v1_8_R1/world/spawner/BBaseSpawnerImpl.java @@ -0,0 +1,146 @@ +package com.songoda.core.nms.v1_8_R1.world.spawner; + +import com.songoda.core.nms.ReflectionUtils; +import com.songoda.core.nms.world.BBaseSpawner; +import net.minecraft.server.v1_8_R1.AxisAlignedBB; +import net.minecraft.server.v1_8_R1.BlockPosition; +import net.minecraft.server.v1_8_R1.Entity; +import net.minecraft.server.v1_8_R1.EntityInsentient; +import net.minecraft.server.v1_8_R1.EntityTypes; +import net.minecraft.server.v1_8_R1.EnumParticle; +import net.minecraft.server.v1_8_R1.MobSpawnerAbstract; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; + +public class BBaseSpawnerImpl implements BBaseSpawner { + private static Method aEntityBooleanMethod, gMethod, hMethod; + + private final MobSpawnerAbstract spawner; + + static { + try { + aEntityBooleanMethod = MobSpawnerAbstract.class.getDeclaredMethod("a", Entity.class, boolean.class); + aEntityBooleanMethod.setAccessible(true); + + gMethod = MobSpawnerAbstract.class.getDeclaredMethod("g"); + gMethod.setAccessible(true); + + hMethod = MobSpawnerAbstract.class.getDeclaredMethod("h"); + hMethod.setAccessible(true); + } catch (NoSuchMethodException ex) { + ex.printStackTrace(); + } + } + + public BBaseSpawnerImpl(MobSpawnerAbstract spawner) { + this.spawner = spawner; + } + + /** + * This method calls {@link MobSpawnerAbstract#g()} using Reflections. + */ + @SuppressWarnings("JavadocReference") + @Override + public boolean isNearPlayer() throws InvocationTargetException, IllegalAccessException { + return (boolean) gMethod.invoke(spawner); + } + + /** + * This method is based on {@link MobSpawnerAbstract#c()}. + */ + @Override + public void tick() throws NoSuchFieldException, IllegalAccessException, InvocationTargetException { + BlockPosition blockposition = spawner.b(); + + if (spawner.a().isStatic) { + double d1 = (float) blockposition.getX() + spawner.a().random.nextFloat(); + double d2 = (float) blockposition.getY() + spawner.a().random.nextFloat(); + double d0 = (float) blockposition.getZ() + spawner.a().random.nextFloat(); + + spawner.a().addParticle(EnumParticle.SMOKE_NORMAL, d1, d2, d0, 0D, 0D, 0D); + spawner.a().addParticle(EnumParticle.FLAME, d1, d2, d0, 0D, 0D, 0D); + + if (spawner.spawnDelay > 0) { + --spawner.spawnDelay; + } + + double spawnerE = (double) ReflectionUtils.getFieldValue(spawner, "e"); + + ReflectionUtils.setFieldValue(spawner, "f", spawnerE); + ReflectionUtils.setFieldValue(spawner, "e", (spawnerE + (double) (1000F / ((float) spawner.spawnDelay + 200F))) % 360D); + } else { + if (spawner.spawnDelay == -1) { + delay(spawner); + } + + if (spawner.spawnDelay > 0) { + --spawner.spawnDelay; + return; + } + + boolean flag = false; + int i = 0; + + int spawnCount = (int) ReflectionUtils.getFieldValue(spawner, "spawnCount"); + int spawnRange = (int) ReflectionUtils.getFieldValue(spawner, "spawnRange"); + int maxNearbyEntities = (int) ReflectionUtils.getFieldValue(spawner, "maxNearbyEntities"); + while (true) { + if (i >= spawnCount) { + if (flag) { + delay(spawner); + } + + break; + } + + Entity entity = EntityTypes.createEntityByName(spawner.getMobName(), spawner.a()); + if (entity == null) { + return; + } + + int j = spawner.a() + .a(entity.getClass(), (new AxisAlignedBB(blockposition.getX(), + blockposition.getY(), + blockposition.getZ(), + blockposition.getX() + 1, + blockposition.getY() + 1, + blockposition.getZ() + 1)) + .grow(spawnRange, spawnRange, spawnRange)).size(); + + if (j >= maxNearbyEntities) { + delay(spawner); + return; + } + + double d0 = (double) blockposition.getX() + (spawner.a().random.nextDouble() - spawner.a().random.nextDouble()) * (double) spawnRange + 0.5D; + double d3 = blockposition.getY() + spawner.a().random.nextInt(3) - 1; + double d4 = (double) blockposition.getZ() + (spawner.a().random.nextDouble() - spawner.a().random.nextDouble()) * (double) spawnRange + 0.5D; + + EntityInsentient entityinsentient = entity instanceof EntityInsentient ? (EntityInsentient) entity : null; + entity.setPositionRotation(d0, d3, d4, spawner.a().random.nextFloat() * 360.0F, 0.0F); + + if (entityinsentient == null || entityinsentient.bQ() && entityinsentient.canSpawn()) { + aEntityBooleanMethod.invoke(spawner, entity, true); + spawner.a().triggerEffect(2004, blockposition, 0); + + if (entityinsentient != null) { + entityinsentient.y(); + } + + flag = true; + } + + ++i; + } + } + } + + /** + * This method calls {@link MobSpawnerAbstract#h()} using Reflections. + */ + @SuppressWarnings("JavadocReference") + private void delay(MobSpawnerAbstract spawner) throws InvocationTargetException, IllegalAccessException { + hMethod.invoke(spawner); + } +} diff --git a/NMS/NMS-v1_8_R2/src/com/songoda/core/nms/v1_8_R2/world/WorldCoreImpl.java b/NMS/NMS-v1_8_R2/src/com/songoda/core/nms/v1_8_R2/world/WorldCoreImpl.java index c7b8ffe2..aabaa81f 100644 --- a/NMS/NMS-v1_8_R2/src/com/songoda/core/nms/v1_8_R2/world/WorldCoreImpl.java +++ b/NMS/NMS-v1_8_R2/src/com/songoda/core/nms/v1_8_R2/world/WorldCoreImpl.java @@ -1,16 +1,28 @@ package com.songoda.core.nms.v1_8_R2.world; import com.songoda.core.nms.world.SItemStack; +import com.songoda.core.nms.ReflectionUtils; +import com.songoda.core.nms.v1_8_R2.world.spawner.BBaseSpawnerImpl; +import com.songoda.core.nms.world.BBaseSpawner; import com.songoda.core.nms.world.SSpawner; import com.songoda.core.nms.world.SWorld; import com.songoda.core.nms.world.WorldCore; +import net.minecraft.server.v1_8_R2.Block; +import net.minecraft.server.v1_8_R2.BlockPosition; +import net.minecraft.server.v1_8_R2.Chunk; +import net.minecraft.server.v1_8_R2.ChunkSection; +import net.minecraft.server.v1_8_R2.IBlockData; +import net.minecraft.server.v1_8_R2.MobSpawnerAbstract; +import net.minecraft.server.v1_8_R2.WorldServer; import org.bukkit.Location; import org.bukkit.World; import org.bukkit.block.CreatureSpawner; import org.bukkit.inventory.ItemStack; +import org.bukkit.craftbukkit.v1_8_R2.CraftChunk; + +import java.lang.reflect.Method; public class WorldCoreImpl implements WorldCore { - @Override public SSpawner getSpawner(CreatureSpawner spawner) { return new SSpawnerImpl(spawner.getLocation()); @@ -30,4 +42,49 @@ public class WorldCoreImpl implements WorldCore { public SWorld getWorld(World world) { return new SWorldImpl(); } + + @Override + public BBaseSpawner getBaseSpawner(CreatureSpawner spawner) throws NoSuchFieldException, IllegalAccessException { + Object cTileEntity = ReflectionUtils.getFieldValue(spawner, "spawner"); + + return new BBaseSpawnerImpl((MobSpawnerAbstract) ReflectionUtils.getFieldValue(cTileEntity, "a")); + } + + /** + * Method is based on {@link WorldServer#h()}. + */ + @SuppressWarnings("JavadocReference") + @Override + public void randomTickChunk(org.bukkit.Chunk bukkitChunk, int tickAmount) throws NoSuchFieldException, IllegalAccessException { + Chunk chunk = ((CraftChunk) bukkitChunk).getHandle(); + + if (tickAmount > 0) { + int k = chunk.locX * 16; + int l = chunk.locZ * 16; + + for (ChunkSection cSection : chunk.getSections()) { + if (cSection != null && cSection.shouldTick()) { + for (int i = 0; i < tickAmount; ++i) { + int m = (int) ReflectionUtils.getFieldValue(chunk.world, "m"); + + m = m * 3 + 1013904223; + ReflectionUtils.setFieldValue(chunk.world, "m", m); + + int i2 = m >> 2; + int j2 = i2 & 15; + int k2 = i2 >> 8 & 15; + int l2 = i2 >> 16 & 15; + + BlockPosition blockposition2 = new BlockPosition(j2 + k, l2 + cSection.getYPosition(), k2 + l); + IBlockData iblockdata = cSection.getType(j2, l2, k2); + Block block = iblockdata.getBlock(); + + if (block.isTicking()) { + block.a(chunk.world, blockposition2, iblockdata, chunk.world.random); + } + } + } + } + } + } } diff --git a/NMS/NMS-v1_8_R2/src/com/songoda/core/nms/v1_8_R2/world/spawner/BBaseSpawnerImpl.java b/NMS/NMS-v1_8_R2/src/com/songoda/core/nms/v1_8_R2/world/spawner/BBaseSpawnerImpl.java new file mode 100644 index 00000000..d9b6cabd --- /dev/null +++ b/NMS/NMS-v1_8_R2/src/com/songoda/core/nms/v1_8_R2/world/spawner/BBaseSpawnerImpl.java @@ -0,0 +1,139 @@ +package com.songoda.core.nms.v1_8_R2.world.spawner; + +import com.songoda.core.nms.ReflectionUtils; +import com.songoda.core.nms.world.BBaseSpawner; +import net.minecraft.server.v1_8_R2.AxisAlignedBB; +import net.minecraft.server.v1_8_R2.BlockPosition; +import net.minecraft.server.v1_8_R2.Entity; +import net.minecraft.server.v1_8_R2.EntityInsentient; +import net.minecraft.server.v1_8_R2.EntityTypes; +import net.minecraft.server.v1_8_R2.EnumParticle; +import net.minecraft.server.v1_8_R2.MobSpawnerAbstract; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; + +public class BBaseSpawnerImpl implements BBaseSpawner { + private static Method aEntityBooleanMethod, gMethod, hMethod; + private final MobSpawnerAbstract spawner; + + static { + try { + aEntityBooleanMethod = MobSpawnerAbstract.class.getDeclaredMethod("a", Entity.class, boolean.class); + aEntityBooleanMethod.setAccessible(true); + + gMethod = MobSpawnerAbstract.class.getDeclaredMethod("g"); + gMethod.setAccessible(true); + + hMethod = MobSpawnerAbstract.class.getDeclaredMethod("h"); + hMethod.setAccessible(true); + } catch (NoSuchMethodException ex) { + ex.printStackTrace(); + } + } + + public BBaseSpawnerImpl(MobSpawnerAbstract spawner) { + this.spawner = spawner; + } + + /** + * This method calls {@link MobSpawnerAbstract#g()} using Reflections. + */ + @SuppressWarnings("JavadocReference") + @Override + public boolean isNearPlayer() throws InvocationTargetException, IllegalAccessException { + return (boolean) gMethod.invoke(spawner); + } + + /** + * This method is based on {@link MobSpawnerAbstract#c()}. + */ + @Override + public void tick() throws NoSuchFieldException, IllegalAccessException, InvocationTargetException { + BlockPosition blockposition = spawner.b(); + + if (spawner.a().isClientSide) { + double d1 = (float) blockposition.getX() + spawner.a().random.nextFloat(); + double d2 = (float) blockposition.getY() + spawner.a().random.nextFloat(); + double d0 = (float) blockposition.getZ() + spawner.a().random.nextFloat(); + spawner.a().addParticle(EnumParticle.SMOKE_NORMAL, d1, d2, d0, 0.0D, 0.0D, 0.0D); + spawner.a().addParticle(EnumParticle.FLAME, d1, d2, d0, 0.0D, 0.0D, 0.0D); + if (spawner.spawnDelay > 0) { + --spawner.spawnDelay; + } + + double spawnerE = (double) ReflectionUtils.getFieldValue(spawner, "e"); + + ReflectionUtils.setFieldValue(spawner, "f", spawnerE); + ReflectionUtils.setFieldValue(spawner, "e", (spawnerE + (double) (1000F / ((float) spawner.spawnDelay + 200.0F))) % 360D); + } else { + if (spawner.spawnDelay == -1) { + delay(spawner); + } + + if (spawner.spawnDelay > 0) { + --spawner.spawnDelay; + return; + } + + boolean flag = false; + int i = 0; + + int spawnCount = (int) ReflectionUtils.getFieldValue(spawner, "spawnCount"); + int spawnRange = (int) ReflectionUtils.getFieldValue(spawner, "spawnRange"); + int maxNearbyEntities = (int) ReflectionUtils.getFieldValue(spawner, "maxNearbyEntities"); + + while (true) { + if (i >= spawnCount) { + if (flag) { + delay(spawner); + } + break; + } + + Entity entity = EntityTypes.createEntityByName(spawner.getMobName(), spawner.a()); + if (entity == null) { + return; + } + + int j = spawner.a().a(entity.getClass(), (new AxisAlignedBB( + blockposition.getX(), + blockposition.getY(), + blockposition.getZ(), + blockposition.getX() + 1, + blockposition.getY() + 1, + blockposition.getZ() + 1)) + .grow(spawnRange, spawnRange, spawnRange)).size(); + if (j >= maxNearbyEntities) { + delay(spawner); + return; + } + + double d0 = (double) blockposition.getX() + (spawner.a().random.nextDouble() - spawner.a().random.nextDouble()) * (double) spawnRange + .5D; + double d3 = blockposition.getY() + spawner.a().random.nextInt(3) - 1; + double d4 = (double) blockposition.getZ() + (spawner.a().random.nextDouble() - spawner.a().random.nextDouble()) * (double) spawnRange + .5D; + EntityInsentient entityinsentient = entity instanceof EntityInsentient ? (EntityInsentient) entity : null; + entity.setPositionRotation(d0, d3, d4, spawner.a().random.nextFloat() * 360F, 0F); + if (entityinsentient == null || entityinsentient.bR() && entityinsentient.canSpawn()) { + aEntityBooleanMethod.invoke(spawner, entity, true); + spawner.a().triggerEffect(2004, blockposition, 0); + if (entityinsentient != null) { + entityinsentient.y(); + } + + flag = true; + } + + ++i; + } + } + } + + /** + * This method calls {@link MobSpawnerAbstract#h()} using Reflections. + */ + @SuppressWarnings("JavadocReference") + private void delay(MobSpawnerAbstract spawner) throws InvocationTargetException, IllegalAccessException { + hMethod.invoke(spawner); + } +} \ No newline at end of file diff --git a/NMS/NMS-v1_8_R3/src/com/songoda/core/nms/v1_8_R3/world/WorldCoreImpl.java b/NMS/NMS-v1_8_R3/src/com/songoda/core/nms/v1_8_R3/world/WorldCoreImpl.java index d0c61449..fd5a3919 100644 --- a/NMS/NMS-v1_8_R3/src/com/songoda/core/nms/v1_8_R3/world/WorldCoreImpl.java +++ b/NMS/NMS-v1_8_R3/src/com/songoda/core/nms/v1_8_R3/world/WorldCoreImpl.java @@ -1,16 +1,26 @@ package com.songoda.core.nms.v1_8_R3.world; import com.songoda.core.nms.world.SItemStack; +import com.songoda.core.nms.ReflectionUtils; +import com.songoda.core.nms.v1_8_R3.world.spawner.BBaseSpawnerImpl; +import com.songoda.core.nms.world.BBaseSpawner; import com.songoda.core.nms.world.SSpawner; import com.songoda.core.nms.world.SWorld; import com.songoda.core.nms.world.WorldCore; +import net.minecraft.server.v1_8_R3.Block; +import net.minecraft.server.v1_8_R3.BlockPosition; +import net.minecraft.server.v1_8_R3.Chunk; +import net.minecraft.server.v1_8_R3.ChunkSection; +import net.minecraft.server.v1_8_R3.IBlockData; +import net.minecraft.server.v1_8_R3.MobSpawnerAbstract; +import net.minecraft.server.v1_8_R3.WorldServer; import org.bukkit.Location; import org.bukkit.World; import org.bukkit.block.CreatureSpawner; import org.bukkit.inventory.ItemStack; +import org.bukkit.craftbukkit.v1_8_R3.CraftChunk; public class WorldCoreImpl implements WorldCore { - @Override public SSpawner getSpawner(CreatureSpawner spawner) { return new SSpawnerImpl(spawner.getLocation()); @@ -30,4 +40,48 @@ public class WorldCoreImpl implements WorldCore { public SWorld getWorld(World world) { return new SWorldImpl(); } + + @Override + public BBaseSpawner getBaseSpawner(CreatureSpawner spawner) throws NoSuchFieldException, IllegalAccessException { + Object cTileEntity = ReflectionUtils.getFieldValue(spawner, "spawner"); + + return new BBaseSpawnerImpl((MobSpawnerAbstract) ReflectionUtils.getFieldValue(cTileEntity, "a")); + } + + /** + * Method is based on {@link WorldServer#h()}. + */ + @SuppressWarnings("JavadocReference") + @Override + public void randomTickChunk(org.bukkit.Chunk bukkitChunk, int tickAmount) throws NoSuchFieldException, IllegalAccessException { + Chunk chunk = ((CraftChunk) bukkitChunk).getHandle(); + + if (tickAmount > 0) { + int k = chunk.locX * 16; + int l = chunk.locZ * 16; + + for (ChunkSection chunksection : chunk.getSections()) { + if (chunksection != null && chunksection.shouldTick()) { + for (int l1 = 0; l1 < tickAmount; ++l1) { + int m = (int) ReflectionUtils.getFieldValue(chunk.world, "m"); + + m = m * 3 + 1013904223; + ReflectionUtils.setFieldValue(chunk.world, "m", m); + + int i2 = m >> 2; + int j2 = i2 & 15; + int k2 = i2 >> 8 & 15; + int l2 = i2 >> 16 & 15; + + IBlockData iblockdata = chunksection.getType(j2, l2, k2); + Block block = iblockdata.getBlock(); + + if (block.isTicking()) { + block.a(chunk.world, new BlockPosition(j2 + k, l2 + chunksection.getYPosition(), k2 + l), iblockdata, chunk.world.random); + } + } + } + } + } + } } diff --git a/NMS/NMS-v1_8_R3/src/com/songoda/core/nms/v1_8_R3/world/spawner/BBaseSpawnerImpl.java b/NMS/NMS-v1_8_R3/src/com/songoda/core/nms/v1_8_R3/world/spawner/BBaseSpawnerImpl.java new file mode 100644 index 00000000..f65e5502 --- /dev/null +++ b/NMS/NMS-v1_8_R3/src/com/songoda/core/nms/v1_8_R3/world/spawner/BBaseSpawnerImpl.java @@ -0,0 +1,143 @@ +package com.songoda.core.nms.v1_8_R3.world.spawner; + +import com.songoda.core.nms.ReflectionUtils; +import com.songoda.core.nms.world.BBaseSpawner; +import net.minecraft.server.v1_8_R3.AxisAlignedBB; +import net.minecraft.server.v1_8_R3.BlockPosition; +import net.minecraft.server.v1_8_R3.Entity; +import net.minecraft.server.v1_8_R3.EntityInsentient; +import net.minecraft.server.v1_8_R3.EntityTypes; +import net.minecraft.server.v1_8_R3.EnumParticle; +import net.minecraft.server.v1_8_R3.MobSpawnerAbstract; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; + +public class BBaseSpawnerImpl implements BBaseSpawner { + private static Method aEntityBooleanMethod, gMethod, hMethod; + + private final MobSpawnerAbstract spawner; + + static { + try { + aEntityBooleanMethod = MobSpawnerAbstract.class.getDeclaredMethod("a", Entity.class, boolean.class); + aEntityBooleanMethod.setAccessible(true); + + gMethod = MobSpawnerAbstract.class.getDeclaredMethod("g"); + gMethod.setAccessible(true); + + hMethod = MobSpawnerAbstract.class.getDeclaredMethod("h"); + hMethod.setAccessible(true); + } catch (NoSuchMethodException ex) { + ex.printStackTrace(); + } + } + + public BBaseSpawnerImpl(MobSpawnerAbstract spawner) { + this.spawner = spawner; + } + + /** + * This method calls {@link MobSpawnerAbstract#g()} using Reflections. + */ + @SuppressWarnings("JavadocReference") + @Override + public boolean isNearPlayer() throws InvocationTargetException, IllegalAccessException { + return (boolean) gMethod.invoke(spawner); + } + + /** + * This method is based on {@link MobSpawnerAbstract#c()}. + */ + @Override + public void tick() throws NoSuchFieldException, IllegalAccessException, InvocationTargetException { + + BlockPosition blockposition = spawner.b(); + + if (spawner.a().isClientSide) { + double d1 = (float) blockposition.getX() + spawner.a().random.nextFloat(); + double d2 = (float) blockposition.getY() + spawner.a().random.nextFloat(); + double d0 = (float) blockposition.getZ() + spawner.a().random.nextFloat(); + spawner.a().addParticle(EnumParticle.SMOKE_NORMAL, d1, d2, d0, 0D, 0D, 0D); + spawner.a().addParticle(EnumParticle.FLAME, d1, d2, d0, 0D, 0D, 0D); + if (spawner.spawnDelay > 0) { + --spawner.spawnDelay; + } + + double spawnerE = (double) ReflectionUtils.getFieldValue(spawner, "e"); + + ReflectionUtils.setFieldValue(spawner, "f", spawnerE); + ReflectionUtils.setFieldValue(spawner, "e", (spawnerE + (double) (1000F / ((float) spawner.spawnDelay + 200F))) % 360D); + } else { + if (spawner.spawnDelay == -1) { + delay(spawner); + } + + if (spawner.spawnDelay > 0) { + --spawner.spawnDelay; + return; + } + + boolean flag = false; + int i = 0; + + int spawnCount = (int) ReflectionUtils.getFieldValue(spawner, "spawnCount"); + int spawnRange = (int) ReflectionUtils.getFieldValue(spawner, "spawnRange"); + int maxNearbyEntities = (int) ReflectionUtils.getFieldValue(spawner, "maxNearbyEntities"); + + while (true) { + if (i >= spawnCount) { + if (flag) { + delay(spawner); + } + break; + } + + Entity entity = EntityTypes.createEntityByName(spawner.getMobName(), spawner.a()); + if (entity == null) { + return; + } + + int j = spawner.a().a(entity.getClass(), (new AxisAlignedBB( + blockposition.getX(), + blockposition.getY(), + blockposition.getZ(), + blockposition.getX() + 1, + blockposition.getY() + 1, + blockposition.getZ() + 1)) + .grow(spawnRange, spawnRange, spawnRange)).size(); + if (j >= maxNearbyEntities) { + delay(spawner); + return; + } + + double d0 = (double) blockposition.getX() + (spawner.a().random.nextDouble() - spawner.a().random.nextDouble()) * (double) spawnRange + .5D; + double d3 = blockposition.getY() + spawner.a().random.nextInt(3) - 1; + double d4 = (double) blockposition.getZ() + (spawner.a().random.nextDouble() - spawner.a().random.nextDouble()) * (double) spawnRange + .5D; + + EntityInsentient entityinsentient = entity instanceof EntityInsentient ? (EntityInsentient) entity : null; + entity.setPositionRotation(d0, d3, d4, spawner.a().random.nextFloat() * 360F, 0F); + + if (entityinsentient == null || entityinsentient.bR() && entityinsentient.canSpawn()) { + aEntityBooleanMethod.invoke(spawner, entity, true); + spawner.a().triggerEffect(2004, blockposition, 0); + if (entityinsentient != null) { + entityinsentient.y(); + } + + flag = true; + } + + ++i; + } + } + } + + /** + * This method calls {@link MobSpawnerAbstract#h()} using Reflections. + */ + @SuppressWarnings("JavadocReference") + private void delay(MobSpawnerAbstract spawner) throws InvocationTargetException, IllegalAccessException { + hMethod.invoke(spawner); + } +} \ No newline at end of file diff --git a/NMS/NMS-v1_9_R1/src/com/songoda/core/nms/v1_9_R1/world/WorldCoreImpl.java b/NMS/NMS-v1_9_R1/src/com/songoda/core/nms/v1_9_R1/world/WorldCoreImpl.java index c98c70c0..74d6c9b2 100644 --- a/NMS/NMS-v1_9_R1/src/com/songoda/core/nms/v1_9_R1/world/WorldCoreImpl.java +++ b/NMS/NMS-v1_9_R1/src/com/songoda/core/nms/v1_9_R1/world/WorldCoreImpl.java @@ -1,16 +1,26 @@ package com.songoda.core.nms.v1_9_R1.world; import com.songoda.core.nms.world.SItemStack; +import com.songoda.core.nms.ReflectionUtils; +import com.songoda.core.nms.v1_9_R1.world.spawner.BBaseSpawnerImpl; +import com.songoda.core.nms.world.BBaseSpawner; import com.songoda.core.nms.world.SSpawner; import com.songoda.core.nms.world.SWorld; import com.songoda.core.nms.world.WorldCore; +import net.minecraft.server.v1_9_R1.Block; +import net.minecraft.server.v1_9_R1.BlockPosition; +import net.minecraft.server.v1_9_R1.Chunk; +import net.minecraft.server.v1_9_R1.ChunkSection; +import net.minecraft.server.v1_9_R1.IBlockData; +import net.minecraft.server.v1_9_R1.MobSpawnerAbstract; +import net.minecraft.server.v1_9_R1.WorldServer; import org.bukkit.Location; import org.bukkit.World; import org.bukkit.block.CreatureSpawner; import org.bukkit.inventory.ItemStack; +import org.bukkit.craftbukkit.v1_9_R1.CraftChunk; public class WorldCoreImpl implements WorldCore { - @Override public SSpawner getSpawner(CreatureSpawner spawner) { return new SSpawnerImpl(spawner.getLocation()); @@ -30,4 +40,48 @@ public class WorldCoreImpl implements WorldCore { public SWorld getWorld(World world) { return new SWorldImpl(); } + + @Override + public BBaseSpawner getBaseSpawner(CreatureSpawner spawner) throws NoSuchFieldException, IllegalAccessException { + Object cTileEntity = ReflectionUtils.getFieldValue(spawner, "spawner"); + + return new BBaseSpawnerImpl((MobSpawnerAbstract) ReflectionUtils.getFieldValue(cTileEntity, "a")); + } + + /** + * Method is based on {@link WorldServer#j()}. + */ + @SuppressWarnings("JavadocReference") + @Override + public void randomTickChunk(org.bukkit.Chunk bukkitChunk, int tickAmount) throws NoSuchFieldException, IllegalAccessException { + Chunk chunk = ((CraftChunk) bukkitChunk).getHandle(); + + if (tickAmount > 0) { + int j = chunk.locX * 16; + int k = chunk.locZ * 16; + + for (ChunkSection chunksection : chunk.getSections()) { + if (chunksection != net.minecraft.server.v1_9_R1.Chunk.a && chunksection.shouldTick()) { + for (int i = 0; i < tickAmount; ++i) { + int worldL = (int) ReflectionUtils.getFieldValue(chunk.world, "l"); + + worldL = worldL * 3 + 1013904223; + ReflectionUtils.setFieldValue(chunk.world, "l", worldL); + + int l1 = worldL >> 2; + int i2 = l1 & 15; + int j2 = l1 >> 8 & 15; + int k2 = l1 >> 16 & 15; + + IBlockData iblockdata = chunksection.getType(i2, k2, j2); + Block block = iblockdata.getBlock(); + + if (block.isTicking()) { + block.a(chunk.world, new BlockPosition(i2 + j, k2 + chunksection.getYPosition(), j2 + k), iblockdata, chunk.world.random); + } + } + } + } + } + } } diff --git a/NMS/NMS-v1_9_R1/src/com/songoda/core/nms/v1_9_R1/world/spawner/BBaseSpawnerImpl.java b/NMS/NMS-v1_9_R1/src/com/songoda/core/nms/v1_9_R1/world/spawner/BBaseSpawnerImpl.java new file mode 100644 index 00000000..da587db1 --- /dev/null +++ b/NMS/NMS-v1_9_R1/src/com/songoda/core/nms/v1_9_R1/world/spawner/BBaseSpawnerImpl.java @@ -0,0 +1,156 @@ +package com.songoda.core.nms.v1_9_R1.world.spawner; + +import com.songoda.core.nms.ReflectionUtils; +import com.songoda.core.nms.world.BBaseSpawner; +import net.minecraft.server.v1_9_R1.AxisAlignedBB; +import net.minecraft.server.v1_9_R1.BlockPosition; +import net.minecraft.server.v1_9_R1.ChunkRegionLoader; +import net.minecraft.server.v1_9_R1.Entity; +import net.minecraft.server.v1_9_R1.EntityInsentient; +import net.minecraft.server.v1_9_R1.EnumParticle; +import net.minecraft.server.v1_9_R1.MobSpawnerAbstract; +import net.minecraft.server.v1_9_R1.MobSpawnerData; +import net.minecraft.server.v1_9_R1.NBTTagCompound; +import net.minecraft.server.v1_9_R1.NBTTagList; +import org.bukkit.craftbukkit.v1_9_R1.event.CraftEventFactory; +import org.bukkit.event.entity.CreatureSpawnEvent; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; + +public class BBaseSpawnerImpl implements BBaseSpawner { + private static Method iMethod, hMethod; + + private final MobSpawnerAbstract spawner; + + static { + try { + iMethod = MobSpawnerAbstract.class.getDeclaredMethod("i"); + iMethod.setAccessible(true); + + hMethod = MobSpawnerAbstract.class.getDeclaredMethod("h"); + hMethod.setAccessible(true); + } catch (NoSuchMethodException ex) { + ex.printStackTrace(); + } + } + + public BBaseSpawnerImpl(MobSpawnerAbstract spawner) { + this.spawner = spawner; + } + + /** + * This method calls {@link MobSpawnerAbstract#h()} using Reflections. + */ + @SuppressWarnings("JavadocReference") + @Override + public boolean isNearPlayer() throws InvocationTargetException, IllegalAccessException { + return (boolean) hMethod.invoke(spawner); + } + + /** + * This method is based on {@link MobSpawnerAbstract#c()}. + */ + @Override + public void tick() throws NoSuchFieldException, IllegalAccessException, InvocationTargetException { + BlockPosition blockposition = spawner.b(); + if (spawner.a().isClientSide) { + double d0 = (float) blockposition.getX() + spawner.a().random.nextFloat(); + double d1 = (float) blockposition.getY() + spawner.a().random.nextFloat(); + double d2 = (float) blockposition.getZ() + spawner.a().random.nextFloat(); + spawner.a().addParticle(EnumParticle.SMOKE_NORMAL, d0, d1, d2, 0D, 0D, 0D); + spawner.a().addParticle(EnumParticle.FLAME, d0, d1, d2, 0D, 0D, 0D); + if (spawner.spawnDelay > 0) { + --spawner.spawnDelay; + } + + double spawnerD = (double) ReflectionUtils.getFieldValue(spawner, "d"); + + ReflectionUtils.setFieldValue(spawner, "e", spawnerD); + ReflectionUtils.setFieldValue(spawner, "d", (spawnerD + (double) (1000F / ((float) spawner.spawnDelay + 200F))) % 360D); + } else { + if (spawner.spawnDelay == -1) { + delay(spawner); + } + + if (spawner.spawnDelay > 0) { + --spawner.spawnDelay; + return; + } + + boolean flag = false; + int i = 0; + + int spawnCount = (int) ReflectionUtils.getFieldValue(spawner, "spawnCount"); + int spawnRange = (int) ReflectionUtils.getFieldValue(spawner, "spawnRange"); + int maxNearbyEntities = (int) ReflectionUtils.getFieldValue(spawner, "maxNearbyEntities"); + MobSpawnerData spawnData = (MobSpawnerData) ReflectionUtils.getFieldValue(spawner, "spawnData"); + + while (true) { + if (i >= spawnCount) { + if (flag) { + delay(spawner); + } + break; + } + + NBTTagCompound nbttagcompound = spawnData.b(); + NBTTagList nbttaglist = nbttagcompound.getList("Pos", 6); + net.minecraft.server.v1_9_R1.World world = spawner.a(); + int j = nbttaglist.size(); + double d3 = j >= 1 ? nbttaglist.e(0) : (double) blockposition.getX() + (world.random.nextDouble() - world.random.nextDouble()) * (double) spawnRange + .5D; + double d4 = j >= 2 ? nbttaglist.e(1) : (double) (blockposition.getY() + world.random.nextInt(3) - 1); + double d5 = j >= 3 ? nbttaglist.e(2) : (double) blockposition.getZ() + (world.random.nextDouble() - world.random.nextDouble()) * (double) spawnRange + .5D; + Entity entity = ChunkRegionLoader.a(nbttagcompound, world, d3, d4, d5, false); + if (entity == null) { + return; + } + + int k = world.a(entity.getClass(), (new AxisAlignedBB( + blockposition.getX(), + blockposition.getY(), + blockposition.getZ(), + blockposition.getX() + 1, + blockposition.getY() + 1, + blockposition.getZ() + 1)) + .g(spawnRange)).size(); + if (k >= maxNearbyEntities) { + delay(spawner); + return; + } + + EntityInsentient entityinsentient = entity instanceof EntityInsentient ? (EntityInsentient) entity : null; + entity.setPositionRotation(entity.locX, entity.locY, entity.locZ, world.random.nextFloat() * 360F, 0F); + if (entityinsentient == null || entityinsentient.cF() && entityinsentient.canSpawn()) { + if (spawnData.b().d() == 1 && spawnData.b().hasKeyOfType("id", 8) && entity instanceof EntityInsentient) { + ((EntityInsentient) entity).prepare(world.D(new BlockPosition(entity)), null); + } + + if (entity.world.spigotConfig.nerfSpawnerMobs) { + entity.fromMobSpawner = true; + } + + if (!CraftEventFactory.callSpawnerSpawnEvent(entity, blockposition).isCancelled()) { + ChunkRegionLoader.a(entity, world, CreatureSpawnEvent.SpawnReason.SPAWNER); + world.triggerEffect(2004, blockposition, 0); + if (entityinsentient != null) { + entityinsentient.doSpawnEffect(); + } + + flag = true; + } + } + + ++i; + } + } + } + + /** + * This method calls {@link MobSpawnerAbstract#i()} using Reflections. + */ + @SuppressWarnings("JavadocReference") + private void delay(MobSpawnerAbstract spawner) throws InvocationTargetException, IllegalAccessException { + iMethod.invoke(spawner); + } +} \ No newline at end of file diff --git a/NMS/NMS-v1_9_R2/src/com/songoda/core/nms/v1_9_R2/world/WorldCoreImpl.java b/NMS/NMS-v1_9_R2/src/com/songoda/core/nms/v1_9_R2/world/WorldCoreImpl.java index 4ab75b8b..00908f5d 100644 --- a/NMS/NMS-v1_9_R2/src/com/songoda/core/nms/v1_9_R2/world/WorldCoreImpl.java +++ b/NMS/NMS-v1_9_R2/src/com/songoda/core/nms/v1_9_R2/world/WorldCoreImpl.java @@ -1,16 +1,26 @@ package com.songoda.core.nms.v1_9_R2.world; import com.songoda.core.nms.world.SItemStack; +import com.songoda.core.nms.ReflectionUtils; +import com.songoda.core.nms.v1_9_R2.world.spawner.BBaseSpawnerImpl; +import com.songoda.core.nms.world.BBaseSpawner; import com.songoda.core.nms.world.SSpawner; import com.songoda.core.nms.world.SWorld; import com.songoda.core.nms.world.WorldCore; +import net.minecraft.server.v1_9_R2.Block; +import net.minecraft.server.v1_9_R2.BlockPosition; +import net.minecraft.server.v1_9_R2.Chunk; +import net.minecraft.server.v1_9_R2.ChunkSection; +import net.minecraft.server.v1_9_R2.IBlockData; +import net.minecraft.server.v1_9_R2.MobSpawnerAbstract; +import net.minecraft.server.v1_9_R2.WorldServer; import org.bukkit.Location; import org.bukkit.World; import org.bukkit.block.CreatureSpawner; import org.bukkit.inventory.ItemStack; +import org.bukkit.craftbukkit.v1_9_R2.CraftChunk; public class WorldCoreImpl implements WorldCore { - @Override public SSpawner getSpawner(CreatureSpawner spawner) { return new SSpawnerImpl(spawner.getLocation()); @@ -30,4 +40,47 @@ public class WorldCoreImpl implements WorldCore { public SWorld getWorld(World world) { return new SWorldImpl(); } + + @Override + public BBaseSpawner getBaseSpawner(CreatureSpawner spawner) throws NoSuchFieldException, IllegalAccessException { + Object cTileEntity = ReflectionUtils.getFieldValue(spawner, "spawner"); + + return new BBaseSpawnerImpl((MobSpawnerAbstract) ReflectionUtils.getFieldValue(cTileEntity, "a")); + } + + /** + * Method is based on {@link WorldServer#j()}. + */ + @SuppressWarnings("JavadocReference") + @Override + public void randomTickChunk(org.bukkit.Chunk bukkitChunk, int tickAmount) throws NoSuchFieldException, IllegalAccessException { + Chunk chunk = ((CraftChunk) bukkitChunk).getHandle(); + + if (tickAmount > 0) { + int j = chunk.locX * 16; + int k = chunk.locZ * 16; + + for (ChunkSection chunksection : chunk.getSections()) { + if (chunksection != net.minecraft.server.v1_9_R2.Chunk.a && chunksection.shouldTick()) { + for (int k1 = 0; k1 < tickAmount; ++k1) { + int worldL = (int) ReflectionUtils.getFieldValue(chunk.world, "l"); + worldL = worldL * 3 + 1013904223; + ReflectionUtils.setFieldValue(chunk.world, "l", worldL); + + int l1 = worldL >> 2; + int i2 = l1 & 15; + int j2 = l1 >> 8 & 15; + int k2 = l1 >> 16 & 15; + + IBlockData iblockdata = chunksection.getType(i2, k2, j2); + Block block = iblockdata.getBlock(); + + if (block.isTicking()) { + block.a(chunk.world, new BlockPosition(i2 + j, k2 + chunksection.getYPosition(), j2 + k), iblockdata, chunk.world.random); + } + } + } + } + } + } } diff --git a/NMS/NMS-v1_9_R2/src/com/songoda/core/nms/v1_9_R2/world/spawner/BBaseSpawnerImpl.java b/NMS/NMS-v1_9_R2/src/com/songoda/core/nms/v1_9_R2/world/spawner/BBaseSpawnerImpl.java new file mode 100644 index 00000000..d6a95f09 --- /dev/null +++ b/NMS/NMS-v1_9_R2/src/com/songoda/core/nms/v1_9_R2/world/spawner/BBaseSpawnerImpl.java @@ -0,0 +1,159 @@ +package com.songoda.core.nms.v1_9_R2.world.spawner; + +import com.songoda.core.nms.ReflectionUtils; +import com.songoda.core.nms.world.BBaseSpawner; +import net.minecraft.server.v1_9_R2.AxisAlignedBB; +import net.minecraft.server.v1_9_R2.BlockPosition; +import net.minecraft.server.v1_9_R2.ChunkRegionLoader; +import net.minecraft.server.v1_9_R2.Entity; +import net.minecraft.server.v1_9_R2.EntityInsentient; +import net.minecraft.server.v1_9_R2.EnumParticle; +import net.minecraft.server.v1_9_R2.MobSpawnerAbstract; +import net.minecraft.server.v1_9_R2.MobSpawnerData; +import net.minecraft.server.v1_9_R2.NBTTagCompound; +import net.minecraft.server.v1_9_R2.NBTTagList; +import org.bukkit.craftbukkit.v1_9_R2.event.CraftEventFactory; +import org.bukkit.event.entity.CreatureSpawnEvent; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; + +public class BBaseSpawnerImpl implements BBaseSpawner { + private static Method iMethod, hMethod; + + private final MobSpawnerAbstract spawner; + + static { + try { + iMethod = MobSpawnerAbstract.class.getDeclaredMethod("i"); + iMethod.setAccessible(true); + + hMethod = MobSpawnerAbstract.class.getDeclaredMethod("h"); + hMethod.setAccessible(true); + } catch (NoSuchMethodException ex) { + ex.printStackTrace(); + } + } + + public BBaseSpawnerImpl(MobSpawnerAbstract spawner) { + this.spawner = spawner; + } + + /** + * This method calls {@link MobSpawnerAbstract#h()} using Reflections. + */ + @SuppressWarnings("JavadocReference") + @Override + public boolean isNearPlayer() throws InvocationTargetException, IllegalAccessException { + return (boolean) hMethod.invoke(spawner); + } + + /** + * This method is based on {@link MobSpawnerAbstract#c()}. + */ + @Override + public void tick() throws NoSuchFieldException, IllegalAccessException, InvocationTargetException { + BlockPosition blockposition = spawner.b(); + + if (spawner.a().isClientSide) { + double d0 = (float) blockposition.getX() + spawner.a().random.nextFloat(); + double d1 = (float) blockposition.getY() + spawner.a().random.nextFloat(); + double d2 = (float) blockposition.getZ() + spawner.a().random.nextFloat(); + + spawner.a().addParticle(EnumParticle.SMOKE_NORMAL, d0, d1, d2, 0D, 0D, 0D); + spawner.a().addParticle(EnumParticle.FLAME, d0, d1, d2, 0D, 0D, 0D); + + if (spawner.spawnDelay > 0) { + --spawner.spawnDelay; + } + + double spawnerD = (double) ReflectionUtils.getFieldValue(spawner, "d"); + + ReflectionUtils.setFieldValue(spawner, "e", spawnerD); + ReflectionUtils.setFieldValue(spawner, "d", (spawnerD + (double) (1000F / ((float) spawner.spawnDelay + 200F))) % 360D); + } else { + if (spawner.spawnDelay == -1) { + delay(spawner); + } + + if (spawner.spawnDelay > 0) { + --spawner.spawnDelay; + return; + } + + boolean flag = false; + int i = 0; + + int spawnCount = (int) ReflectionUtils.getFieldValue(spawner, "spawnCount"); + int spawnRange = (int) ReflectionUtils.getFieldValue(spawner, "spawnRange"); + int maxNearbyEntities = (int) ReflectionUtils.getFieldValue(spawner, "maxNearbyEntities"); + MobSpawnerData spawnData = (MobSpawnerData) ReflectionUtils.getFieldValue(spawner, "spawnData"); + + while (true) { + if (i >= spawnCount) { + if (flag) { + delay(spawner); + } + break; + } + + NBTTagCompound nbttagcompound = spawnData.b(); + NBTTagList nbttaglist = nbttagcompound.getList("Pos", 6); + net.minecraft.server.v1_9_R2.World world = spawner.a(); + int j = nbttaglist.size(); + double d3 = j >= 1 ? nbttaglist.e(0) : (double) blockposition.getX() + (world.random.nextDouble() - world.random.nextDouble()) * (double) spawnRange + .5D; + double d4 = j >= 2 ? nbttaglist.e(1) : (double) (blockposition.getY() + world.random.nextInt(3) - 1); + double d5 = j >= 3 ? nbttaglist.e(2) : (double) blockposition.getZ() + (world.random.nextDouble() - world.random.nextDouble()) * (double) spawnRange + .5D; + Entity entity = ChunkRegionLoader.a(nbttagcompound, world, d3, d4, d5, false); + if (entity == null) { + return; + } + + int k = world.a(entity.getClass(), (new AxisAlignedBB( + blockposition.getX(), + blockposition.getY(), + blockposition.getZ(), + blockposition.getX() + 1, + blockposition.getY() + 1, + blockposition.getZ() + 1)) + .g(spawnRange)).size(); + if (k >= maxNearbyEntities) { + delay(spawner); + return; + } + + EntityInsentient entityinsentient = entity instanceof EntityInsentient ? (EntityInsentient) entity : null; + entity.setPositionRotation(entity.locX, entity.locY, entity.locZ, world.random.nextFloat() * 360.0F, 0.0F); + if (entityinsentient == null || entityinsentient.cG() && entityinsentient.canSpawn()) { + if (spawnData.b().d() == 1 && spawnData.b().hasKeyOfType("id", 8) && entity instanceof EntityInsentient) { + ((EntityInsentient) entity).prepare(world.D(new BlockPosition(entity)), null); + } + + if (entity.world.spigotConfig.nerfSpawnerMobs) { + entity.fromMobSpawner = true; + } + + if (!CraftEventFactory.callSpawnerSpawnEvent(entity, blockposition).isCancelled()) { + ChunkRegionLoader.a(entity, world, CreatureSpawnEvent.SpawnReason.SPAWNER); + world.triggerEffect(2004, blockposition, 0); + if (entityinsentient != null) { + entityinsentient.doSpawnEffect(); + } + + flag = true; + } + } + + ++i; + } + } + } + + /** + * This method calls {@link MobSpawnerAbstract#i()} using Reflections. + */ + @SuppressWarnings("JavadocReference") + private void delay(MobSpawnerAbstract spawner) throws InvocationTargetException, IllegalAccessException { + iMethod.invoke(spawner); + } +} \ No newline at end of file