Merge pull request #230 from FatSaw/ver/1.12.2

More fixes and optimisations
This commit is contained in:
josephworks
2022-08-27 23:14:58 -07:00
committed by GitHub
25 changed files with 6078 additions and 45 deletions

View File

@@ -0,0 +1,479 @@
package net.minecraft.server;
import java.util.Iterator;
import javax.annotation.Nullable;
public class BlockChest extends BlockTileEntity {
public static final BlockStateDirection FACING = BlockFacingHorizontal.FACING;
protected static final AxisAlignedBB b = new AxisAlignedBB(0.0625D, 0.0D, 0.0D, 0.9375D, 0.875D, 0.9375D);
protected static final AxisAlignedBB c = new AxisAlignedBB(0.0625D, 0.0D, 0.0625D, 0.9375D, 0.875D, 1.0D);
protected static final AxisAlignedBB d = new AxisAlignedBB(0.0D, 0.0D, 0.0625D, 0.9375D, 0.875D, 0.9375D);
protected static final AxisAlignedBB e = new AxisAlignedBB(0.0625D, 0.0D, 0.0625D, 1.0D, 0.875D, 0.9375D);
protected static final AxisAlignedBB f = new AxisAlignedBB(0.0625D, 0.0D, 0.0625D, 0.9375D, 0.875D, 0.9375D);
public final BlockChest.Type g;
protected BlockChest(BlockChest.Type blockchest_type) {
super(Material.WOOD);
this.w(this.blockStateList.getBlockData().set(BlockChest.FACING, EnumDirection.NORTH));
this.g = blockchest_type;
this.a(blockchest_type == BlockChest.Type.TRAP ? CreativeModeTab.d : CreativeModeTab.c);
}
public boolean b(IBlockData iblockdata) {
return false;
}
public boolean c(IBlockData iblockdata) {
return false;
}
public EnumRenderType a(IBlockData iblockdata) {
return EnumRenderType.ENTITYBLOCK_ANIMATED;
}
public AxisAlignedBB b(IBlockData iblockdata, IBlockAccess iblockaccess, BlockPosition blockposition) {
return iblockaccess.getType(blockposition.north()).getBlock() == this ? BlockChest.b : (iblockaccess.getType(blockposition.south()).getBlock() == this ? BlockChest.c : (iblockaccess.getType(blockposition.west()).getBlock() == this ? BlockChest.d : (iblockaccess.getType(blockposition.east()).getBlock() == this ? BlockChest.e : BlockChest.f)));
}
public void onPlace(World world, BlockPosition blockposition, IBlockData iblockdata) {
this.e(world, blockposition, iblockdata);
Iterator iterator = EnumDirection.EnumDirectionLimit.HORIZONTAL.iterator();
while (iterator.hasNext()) {
EnumDirection enumdirection = (EnumDirection) iterator.next();
BlockPosition blockposition1 = blockposition.shift(enumdirection);
// NeonPaper start - Dont load chunks for chests
final IBlockData iblockdata1 = world.isLoaded(blockposition1) ? world.getType(blockposition1) : null;
if (iblockdata1 == null) {
continue;
}
// NeonPaper end
if (iblockdata1.getBlock() == this) {
this.e(world, blockposition1, iblockdata1);
}
}
}
public IBlockData getPlacedState(World world, BlockPosition blockposition, EnumDirection enumdirection, float f, float f1, float f2, int i, EntityLiving entityliving) {
return this.getBlockData().set(BlockChest.FACING, entityliving.getDirection());
}
public void postPlace(World world, BlockPosition blockposition, IBlockData iblockdata, EntityLiving entityliving, ItemStack itemstack) {
EnumDirection enumdirection = EnumDirection.fromType2(MathHelper.floor((double) (entityliving.yaw * 4.0F / 360.0F) + 0.5D) & 3).opposite();
iblockdata = iblockdata.set(BlockChest.FACING, enumdirection);
BlockPosition blockposition1 = blockposition.north();
BlockPosition blockposition2 = blockposition.south();
BlockPosition blockposition3 = blockposition.west();
BlockPosition blockposition4 = blockposition.east();
boolean flag = this == world.getType(blockposition1).getBlock();
boolean flag1 = this == world.getType(blockposition2).getBlock();
boolean flag2 = this == world.getType(blockposition3).getBlock();
boolean flag3 = this == world.getType(blockposition4).getBlock();
if (!flag && !flag1 && !flag2 && !flag3) {
world.setTypeAndData(blockposition, iblockdata, 3);
} else if (enumdirection.k() == EnumDirection.EnumAxis.X && (flag || flag1)) {
if (flag) {
world.setTypeAndData(blockposition1, iblockdata, 3);
} else {
world.setTypeAndData(blockposition2, iblockdata, 3);
}
world.setTypeAndData(blockposition, iblockdata, 3);
} else if (enumdirection.k() == EnumDirection.EnumAxis.Z && (flag2 || flag3)) {
if (flag2) {
world.setTypeAndData(blockposition3, iblockdata, 3);
} else {
world.setTypeAndData(blockposition4, iblockdata, 3);
}
world.setTypeAndData(blockposition, iblockdata, 3);
}
if (itemstack.hasName()) {
TileEntity tileentity = world.getTileEntity(blockposition);
if (tileentity instanceof TileEntityChest) {
((TileEntityChest) tileentity).setCustomName(itemstack.getName());
}
}
}
public IBlockData e(World world, BlockPosition blockposition, IBlockData iblockdata) {
if (world.isClientSide) {
return iblockdata;
} else {
IBlockData iblockdata1 = world.getType(blockposition.north());
IBlockData iblockdata2 = world.getType(blockposition.south());
IBlockData iblockdata3 = world.getType(blockposition.west());
IBlockData iblockdata4 = world.getType(blockposition.east());
EnumDirection enumdirection = (EnumDirection) iblockdata.get(BlockChest.FACING);
if (iblockdata1.getBlock() != this && iblockdata2.getBlock() != this) {
boolean flag = iblockdata1.b();
boolean flag1 = iblockdata2.b();
if (iblockdata3.getBlock() == this || iblockdata4.getBlock() == this) {
BlockPosition blockposition1 = iblockdata3.getBlock() == this ? blockposition.west() : blockposition.east();
IBlockData iblockdata5 = world.getType(blockposition1.north());
IBlockData iblockdata6 = world.getType(blockposition1.south());
enumdirection = EnumDirection.SOUTH;
EnumDirection enumdirection1;
if (iblockdata3.getBlock() == this) {
enumdirection1 = (EnumDirection) iblockdata3.get(BlockChest.FACING);
} else {
enumdirection1 = (EnumDirection) iblockdata4.get(BlockChest.FACING);
}
if (enumdirection1 == EnumDirection.NORTH) {
enumdirection = EnumDirection.NORTH;
}
if ((flag || iblockdata5.b()) && !flag1 && !iblockdata6.b()) {
enumdirection = EnumDirection.SOUTH;
}
if ((flag1 || iblockdata6.b()) && !flag && !iblockdata5.b()) {
enumdirection = EnumDirection.NORTH;
}
}
} else {
BlockPosition blockposition2 = iblockdata1.getBlock() == this ? blockposition.north() : blockposition.south();
IBlockData iblockdata7 = world.getType(blockposition2.west());
IBlockData iblockdata8 = world.getType(blockposition2.east());
enumdirection = EnumDirection.EAST;
EnumDirection enumdirection2;
if (iblockdata1.getBlock() == this) {
enumdirection2 = (EnumDirection) iblockdata1.get(BlockChest.FACING);
} else {
enumdirection2 = (EnumDirection) iblockdata2.get(BlockChest.FACING);
}
if (enumdirection2 == EnumDirection.WEST) {
enumdirection = EnumDirection.WEST;
}
if ((iblockdata3.b() || iblockdata7.b()) && !iblockdata4.b() && !iblockdata8.b()) {
enumdirection = EnumDirection.EAST;
}
if ((iblockdata4.b() || iblockdata8.b()) && !iblockdata3.b() && !iblockdata7.b()) {
enumdirection = EnumDirection.WEST;
}
}
iblockdata = iblockdata.set(BlockChest.FACING, enumdirection);
world.setTypeAndData(blockposition, iblockdata, 3);
return iblockdata;
}
}
public IBlockData f(World world, BlockPosition blockposition, IBlockData iblockdata) {
EnumDirection enumdirection = null;
Iterator iterator = EnumDirection.EnumDirectionLimit.HORIZONTAL.iterator();
while (iterator.hasNext()) {
EnumDirection enumdirection1 = (EnumDirection) iterator.next();
IBlockData iblockdata1 = world.getType(blockposition.shift(enumdirection1));
if (iblockdata1.getBlock() == this) {
return iblockdata;
}
if (iblockdata1.b()) {
if (enumdirection != null) {
enumdirection = null;
break;
}
enumdirection = enumdirection1;
}
}
if (enumdirection != null) {
return iblockdata.set(BlockChest.FACING, enumdirection.opposite());
} else {
EnumDirection enumdirection2 = (EnumDirection) iblockdata.get(BlockChest.FACING);
if (world.getType(blockposition.shift(enumdirection2)).b()) {
enumdirection2 = enumdirection2.opposite();
}
if (world.getType(blockposition.shift(enumdirection2)).b()) {
enumdirection2 = enumdirection2.e();
}
if (world.getType(blockposition.shift(enumdirection2)).b()) {
enumdirection2 = enumdirection2.opposite();
}
return iblockdata.set(BlockChest.FACING, enumdirection2);
}
}
public boolean canPlace(World world, BlockPosition blockposition) {
int i = 0;
BlockPosition blockposition1 = blockposition.west();
BlockPosition blockposition2 = blockposition.east();
BlockPosition blockposition3 = blockposition.north();
BlockPosition blockposition4 = blockposition.south();
if (world.getType(blockposition1).getBlock() == this) {
if (this.d(world, blockposition1)) {
return false;
}
++i;
}
if (world.getType(blockposition2).getBlock() == this) {
if (this.d(world, blockposition2)) {
return false;
}
++i;
}
if (world.getType(blockposition3).getBlock() == this) {
if (this.d(world, blockposition3)) {
return false;
}
++i;
}
if (world.getType(blockposition4).getBlock() == this) {
if (this.d(world, blockposition4)) {
return false;
}
++i;
}
return i <= 1;
}
private boolean d(World world, BlockPosition blockposition) {
if (world.getType(blockposition).getBlock() != this) {
return false;
} else {
Iterator iterator = EnumDirection.EnumDirectionLimit.HORIZONTAL.iterator();
EnumDirection enumdirection;
do {
if (!iterator.hasNext()) {
return false;
}
enumdirection = (EnumDirection) iterator.next();
} while (world.getType(blockposition.shift(enumdirection)).getBlock() != this);
return true;
}
}
public void a(IBlockData iblockdata, World world, BlockPosition blockposition, Block block, BlockPosition blockposition1) {
super.a(iblockdata, world, blockposition, block, blockposition1);
TileEntity tileentity = world.getTileEntity(blockposition);
if (tileentity instanceof TileEntityChest) {
tileentity.invalidateBlockCache();
}
}
public void remove(World world, BlockPosition blockposition, IBlockData iblockdata) {
TileEntity tileentity = world.getTileEntity(blockposition);
if (tileentity instanceof IInventory) {
InventoryUtils.dropInventory(world, blockposition, (IInventory) tileentity);
world.updateAdjacentComparators(blockposition, this);
}
super.remove(world, blockposition, iblockdata);
}
public boolean interact(World world, BlockPosition blockposition, IBlockData iblockdata, EntityHuman entityhuman, EnumHand enumhand, EnumDirection enumdirection, float f, float f1, float f2) {
if (world.isClientSide) {
return true;
} else {
ITileInventory itileinventory = this.getInventory(world, blockposition);
if (itileinventory != null) {
entityhuman.openContainer(itileinventory);
if (this.g == BlockChest.Type.BASIC) {
entityhuman.b(StatisticList.aa);
} else if (this.g == BlockChest.Type.TRAP) {
entityhuman.b(StatisticList.U);
}
}
return true;
}
}
@Nullable
public ITileInventory getInventory(World world, BlockPosition blockposition) {
return this.a(world, blockposition, false);
}
@Nullable
public ITileInventory a(World world, BlockPosition blockposition, boolean flag) {
TileEntity tileentity = world.getTileEntity(blockposition);
if (!(tileentity instanceof TileEntityChest)) {
return null;
} else {
Object object = (TileEntityChest) tileentity;
if (!flag && this.e(world, blockposition)) {
return null;
} else {
Iterator iterator = EnumDirection.EnumDirectionLimit.HORIZONTAL.iterator();
while (iterator.hasNext()) {
EnumDirection enumdirection = (EnumDirection) iterator.next();
BlockPosition blockposition1 = blockposition.shift(enumdirection);
// Paper start - don't load chunks if the other side of the chest is in unloaded chunk
final IBlockData type = world.getTypeIfLoaded(blockposition1); // Paper
if (type == null) {
continue;
}
Block block = type.getBlock();
// Paper end
if (block == this) {
if (!flag && this.e(world, blockposition1)) { // Paper - check for allowBlocked flag - MC-99321
return null;
}
TileEntity tileentity1 = world.getTileEntity(blockposition1);
if (tileentity1 instanceof TileEntityChest) {
if (enumdirection != EnumDirection.WEST && enumdirection != EnumDirection.NORTH) {
object = new InventoryLargeChest("container.chestDouble", (ITileInventory) object, (TileEntityChest) tileentity1);
} else {
object = new InventoryLargeChest("container.chestDouble", (TileEntityChest) tileentity1, (ITileInventory) object);
}
}
}
}
return (ITileInventory) object;
}
}
}
public TileEntity a(World world, int i) {
return new TileEntityChest();
}
public boolean isPowerSource(IBlockData iblockdata) {
return this.g == BlockChest.Type.TRAP;
}
public int b(IBlockData iblockdata, IBlockAccess iblockaccess, BlockPosition blockposition, EnumDirection enumdirection) {
if (!iblockdata.m()) {
return 0;
} else {
int i = 0;
TileEntity tileentity = iblockaccess.getTileEntity(blockposition);
if (tileentity instanceof TileEntityChest) {
i = ((TileEntityChest) tileentity).l;
}
return MathHelper.clamp(i, 0, 15);
}
}
public int c(IBlockData iblockdata, IBlockAccess iblockaccess, BlockPosition blockposition, EnumDirection enumdirection) {
return enumdirection == EnumDirection.UP ? iblockdata.a(iblockaccess, blockposition, enumdirection) : 0;
}
private boolean e(World world, BlockPosition blockposition) {
return this.i(world, blockposition) || this.j(world, blockposition);
}
private boolean i(World world, BlockPosition blockposition) {
return world.getType(blockposition.up()).l();
}
private boolean j(World world, BlockPosition blockposition) {
// Paper start - Option ti dsiable chest cat detection
if (world.paperConfig.disableChestCatDetection) {
return false;
}
// Paper end
Iterator iterator = world.a(EntityOcelot.class, new AxisAlignedBB((double) blockposition.getX(), (double) (blockposition.getY() + 1), (double) blockposition.getZ(), (double) (blockposition.getX() + 1), (double) (blockposition.getY() + 2), (double) (blockposition.getZ() + 1))).iterator();
EntityOcelot entityocelot;
do {
if (!iterator.hasNext()) {
return false;
}
Entity entity = (Entity) iterator.next();
entityocelot = (EntityOcelot) entity;
} while (!entityocelot.isSitting());
return true;
}
public boolean isComplexRedstone(IBlockData iblockdata) {
return true;
}
public int c(IBlockData iblockdata, World world, BlockPosition blockposition) {
return Container.b((IInventory) this.getInventory(world, blockposition));
}
public IBlockData fromLegacyData(int i) {
EnumDirection enumdirection = EnumDirection.fromType1(i);
if (enumdirection.k() == EnumDirection.EnumAxis.Y) {
enumdirection = EnumDirection.NORTH;
}
return this.getBlockData().set(BlockChest.FACING, enumdirection);
}
public int toLegacyData(IBlockData iblockdata) {
return ((EnumDirection) iblockdata.get(BlockChest.FACING)).a();
}
public IBlockData a(IBlockData iblockdata, EnumBlockRotation enumblockrotation) {
return iblockdata.set(BlockChest.FACING, enumblockrotation.a((EnumDirection) iblockdata.get(BlockChest.FACING)));
}
public IBlockData a(IBlockData iblockdata, EnumBlockMirror enumblockmirror) {
return iblockdata.a(enumblockmirror.a((EnumDirection) iblockdata.get(BlockChest.FACING)));
}
protected BlockStateList getStateList() {
return new BlockStateList(this, new IBlockState[] { BlockChest.FACING});
}
public EnumBlockFaceShape a(IBlockAccess iblockaccess, IBlockData iblockdata, BlockPosition blockposition, EnumDirection enumdirection) {
return EnumBlockFaceShape.UNDEFINED;
}
public static enum Type {
BASIC, TRAP;
private Type() {}
}
}

View File

@@ -0,0 +1,118 @@
package net.minecraft.server;
import java.util.Random;
import org.bukkit.craftbukkit.event.CraftEventFactory; // CraftBukkit
public class BlockStationary extends BlockFluids {
protected BlockStationary(Material material) {
super(material);
this.a(false);
if (material == Material.LAVA) {
this.a(true);
}
}
public void a(IBlockData iblockdata, World world, BlockPosition blockposition, Block block, BlockPosition blockposition1) {
if (!this.e(world, blockposition, iblockdata)) {
this.f(world, blockposition, iblockdata);
}
}
private void f(World world, BlockPosition blockposition, IBlockData iblockdata) {
BlockFlowing blockflowing = a(this.material);
world.setTypeAndData(blockposition, blockflowing.getBlockData().set(BlockStationary.LEVEL, iblockdata.get(BlockStationary.LEVEL)), 2);
world.a(blockposition, (Block) blockflowing, this.a(world));
}
public void b(World world, BlockPosition blockposition, IBlockData iblockdata, Random random) {
if (this.material == Material.LAVA) {
if (world.getGameRules().getBoolean("doFireTick")) {
int i = random.nextInt(3);
if (i > 0) {
BlockPosition blockposition1 = blockposition;
for (int j = 0; j < i; ++j) {
blockposition1 = blockposition1.a(random.nextInt(3) - 1, 1, random.nextInt(3) - 1);
if (blockposition1.getY() >= 0 && blockposition1.getY() < 256 && !world.isLoaded(blockposition1)) {
return;
}
Block block = world.getType(blockposition1).getBlock();
if (block.material == Material.AIR) {
if (this.c(world, blockposition1)) {
// CraftBukkit start - Prevent lava putting something on fire
if (world.getType(blockposition1) != Blocks.FIRE) {
if (CraftEventFactory.callBlockIgniteEvent(world, blockposition1.getX(), blockposition1.getY(), blockposition1.getZ(), blockposition.getX(), blockposition.getY(), blockposition.getZ()).isCancelled()) {
continue;
}
}
// CraftBukkit end
world.setTypeUpdate(blockposition1, Blocks.FIRE.getBlockData());
return;
}
} else if (block.material.isSolid()) {
return;
}
}
} else {
for (int k = 0; k < 3; ++k) {
BlockPosition blockposition2 = blockposition.a(random.nextInt(3) - 1, 0, random.nextInt(3) - 1);
if (blockposition2.getY() >= 0 && blockposition2.getY() < 256 && !world.isLoaded(blockposition2)) {
return;
}
if (world.isEmpty(blockposition2.up()) && this.d(world, blockposition2)) {
// CraftBukkit start - Prevent lava putting something on fire
BlockPosition up = blockposition2.up();
if (world.getType(up) != Blocks.FIRE) {
if (CraftEventFactory.callBlockIgniteEvent(world, up.getX(), up.getY(), up.getZ(), blockposition.getX(), blockposition.getY(), blockposition.getZ()).isCancelled()) {
continue;
}
}
// CraftBukkit end
world.setTypeUpdate(blockposition2.up(), Blocks.FIRE.getBlockData());
}
}
}
}
}
}
protected boolean c(World world, BlockPosition blockposition) {
EnumDirection[] aenumdirection = EnumDirection.values();
int i = aenumdirection.length;
for (int j = 0; j < i; ++j) {
EnumDirection enumdirection = aenumdirection[j];
if (this.d(world, blockposition.shift(enumdirection))) {
return true;
}
}
return false;
}
private boolean d(World world, BlockPosition blockposition) {
// Dionysus start - improve fire spread checks
if (blockposition.getY() >= 0 && blockposition.getY() < 256) {
IBlockData blockData = world.getTypeIfLoaded(blockposition);
if (blockData != null) {
return blockData.getMaterial().isBurnable();
}
}
return false;
// Dionysus end
}
}

View File

@@ -1000,7 +1000,6 @@ public class Chunk {
for (int k = i; k <= j; ++k) { for (int k = i; k <= j; ++k) {
if (!this.entitySlices[k].isEmpty()) { if (!this.entitySlices[k].isEmpty()) {
Iterator iterator = this.entitySlices[k].iterator();
// Paper start - Don't search for inventories if we have none, and that is all we want // Paper start - Don't search for inventories if we have none, and that is all we want
/* /*
@@ -1011,6 +1010,7 @@ public class Chunk {
*/ */
if (predicate == IEntitySelector.c && inventoryEntityCounts[k] <= 0) continue; if (predicate == IEntitySelector.c && inventoryEntityCounts[k] <= 0) continue;
// Paper end // Paper end
Iterator iterator = this.entitySlices[k].iterator();
while (iterator.hasNext()) { while (iterator.hasNext()) {
Entity entity1 = (Entity) iterator.next(); Entity entity1 = (Entity) iterator.next();
@@ -1548,4 +1548,14 @@ public class Chunk {
private EnumTileEntityState() {} private EnumTileEntityState() {}
} }
// FlamePaper start - Hopper item lookup optimization
public int getItemCount(BlockPosition blockPosition) {
int k = MathHelper.floor(blockPosition.getY() / 16.0D);
k = Math.max(0, k);
k = Math.min(this.entitySlices.length - 1, k);
return itemCounts[k];
}
// FlamePaper end - Hopper item lookup optimization
} }

View File

@@ -0,0 +1,115 @@
package net.minecraft.server;
// CraftBukkit start
import org.bukkit.craftbukkit.inventory.CraftInventoryView;
import org.bukkit.inventory.InventoryView;
// CraftBukkit end
public class ContainerHorse extends Container {
private final IInventory a;
private final EntityHorseAbstract f;
// CraftBukkit start
org.bukkit.craftbukkit.inventory.CraftInventoryView bukkitEntity;
PlayerInventory player;
@Override
public InventoryView getBukkitView() {
if (bukkitEntity != null) {
return bukkitEntity;
}
return bukkitEntity = new CraftInventoryView(player.player.getBukkitEntity(), a.getOwner().getInventory(), this);
}
public ContainerHorse(IInventory iinventory, final IInventory iinventory1, final EntityHorseAbstract entityhorseabstract, EntityHuman entityhuman) {
player = (PlayerInventory) iinventory;
// CraftBukkit end
this.a = iinventory1;
this.f = entityhorseabstract;
boolean flag = true;
iinventory1.startOpen(entityhuman);
boolean flag1 = true;
this.a(new Slot(iinventory1, 0, 8, 18) {
public boolean isAllowed(ItemStack itemstack) {
return itemstack.getItem() == Items.SADDLE && !this.hasItem() && entityhorseabstract.dF();
}
});
this.a(new Slot(iinventory1, 1, 8, 36) {
public boolean isAllowed(ItemStack itemstack) {
return entityhorseabstract.f(itemstack);
}
public int getMaxStackSize() {
return 1;
}
});
int i;
int j;
if (entityhorseabstract instanceof EntityHorseChestedAbstract && ((EntityHorseChestedAbstract) entityhorseabstract).isCarryingChest()) {
for (i = 0; i < 3; ++i) {
for (j = 0; j < ((EntityHorseChestedAbstract) entityhorseabstract).dt(); ++j) {
this.a(new Slot(iinventory1, 2 + j + i * ((EntityHorseChestedAbstract) entityhorseabstract).dt(), 80 + j * 18, 18 + i * 18));
}
}
}
for (i = 0; i < 3; ++i) {
for (j = 0; j < 9; ++j) {
this.a(new Slot(iinventory, j + i * 9 + 9, 8 + j * 18, 102 + i * 18 + -18));
}
}
for (i = 0; i < 9; ++i) {
this.a(new Slot(iinventory, i, 8 + i * 18, 142));
}
}
public boolean canUse(EntityHuman entityhuman) {
return this.a.a(entityhuman) && this.f.isAlive() && this.f.valid && this.f.g((Entity) entityhuman) < 8.0F; // NeonPaper! - Fix MC-161754
}
public ItemStack shiftClick(EntityHuman entityhuman, int i) {
ItemStack itemstack = ItemStack.a;
Slot slot = (Slot) this.slots.get(i);
if (slot != null && slot.hasItem()) {
ItemStack itemstack1 = slot.getItem();
itemstack = itemstack1.cloneItemStack();
if (i < this.a.getSize()) {
if (!this.a(itemstack1, this.a.getSize(), this.slots.size(), true)) {
return ItemStack.a;
}
} else if (this.getSlot(1).isAllowed(itemstack1) && !this.getSlot(1).hasItem()) {
if (!this.a(itemstack1, 1, 2, false)) {
return ItemStack.a;
}
} else if (this.getSlot(0).isAllowed(itemstack1)) {
if (!this.a(itemstack1, 0, 1, false)) {
return ItemStack.a;
}
} else if (this.a.getSize() <= 2 || !this.a(itemstack1, 2, this.a.getSize(), false)) {
return ItemStack.a;
}
if (itemstack1.isEmpty()) {
slot.set(ItemStack.a);
} else {
slot.f();
}
}
return itemstack;
}
public void b(EntityHuman entityhuman) {
super.b(entityhuman);
this.a.closeContainer(entityhuman);
}
}

View File

@@ -118,6 +118,7 @@ public class EnchantmentManager {
EnchantmentManager.a.a = 0; EnchantmentManager.a.a = 0;
EnchantmentManager.a.b = damagesource; EnchantmentManager.a.b = damagesource;
a(EnchantmentManager.a, iterable); a(EnchantmentManager.a, iterable);
EnchantmentManager.a.b = null; // Reaper - Fix MC-128547
return EnchantmentManager.a.a; return EnchantmentManager.a.a;
} }
@@ -145,6 +146,11 @@ public class EnchantmentManager {
a(EnchantmentManager.c, entityliving.getItemInMainHand()); a(EnchantmentManager.c, entityliving.getItemInMainHand());
} }
// Reaper start - Fix MC-128547
EnchantmentManager.c.b = null;
EnchantmentManager.c.a = null;
// Reaper end
} }
public static void b(EntityLiving entityliving, Entity entity) { public static void b(EntityLiving entityliving, Entity entity) {
@@ -157,7 +163,10 @@ public class EnchantmentManager {
if (entityliving instanceof EntityHuman) { if (entityliving instanceof EntityHuman) {
a(EnchantmentManager.d, entityliving.getItemInMainHand()); a(EnchantmentManager.d, entityliving.getItemInMainHand());
} }
// Reaper start - Fix MC-128547
EnchantmentManager.d.b = null;
EnchantmentManager.d.a = null;
// Reaper end
} }
public static int a(Enchantment enchantment, EntityLiving entityliving) { public static int a(Enchantment enchantment, EntityLiving entityliving) {

View File

@@ -45,6 +45,10 @@ import org.bukkit.event.entity.EntityPortalEvent;
import org.bukkit.plugin.PluginManager; import org.bukkit.plugin.PluginManager;
// CraftBukkit end // CraftBukkit end
// Dionysus start
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
// Dionysus end
/** /**
* Akarin Changes Note * Akarin Changes Note
* 1) Random -> LightRandom (performance) * 1) Random -> LightRandom (performance)
@@ -91,7 +95,7 @@ public abstract class Entity implements ICommandListener, KeyedObject { // Paper
private static int entityCount = 1; // Paper - MC-111480 - ID 0 is treated as special for DataWatchers, start 1 private static int entityCount = 1; // Paper - MC-111480 - ID 0 is treated as special for DataWatchers, start 1
private int id; private int id;
public boolean i; public boolean blocksEntitySpawning() { return i; } // Paper - OBFHELPER public boolean i; public boolean blocksEntitySpawning() { return i; } // Paper - OBFHELPER
public final List<Entity> passengers; public final ObjectArrayList<Entity> passengers; // Dionysus
protected int j; protected int j;
private Entity au;public void setVehicle(Entity entity) { this.au = entity; } // Paper // OBFHELPER private Entity au;public void setVehicle(Entity entity) { this.au = entity; } // Paper // OBFHELPER
public boolean attachedToPlayer; public boolean attachedToPlayer;
@@ -205,7 +209,7 @@ public abstract class Entity implements ICommandListener, KeyedObject { // Paper
public Entity(World world) { public Entity(World world) {
this.id = Entity.entityCount++; this.id = Entity.entityCount++;
this.passengers = Lists.newArrayList(); this.passengers = new ObjectArrayList<>(); // Dionysus
this.boundingBox = Entity.c; this.boundingBox = Entity.c;
this.width = 0.6F; this.width = 0.6F;
this.length = 1.8F; this.length = 1.8F;
@@ -1383,37 +1387,33 @@ public abstract class Entity implements ICommandListener, KeyedObject { // Paper
public void d(EntityHuman entityhuman) {} public void d(EntityHuman entityhuman) {}
public void collide(Entity entity) { public void collide(Entity entity) {
if (!this.x(entity)) { if (entity.noclip || this.noclip || this.x(entity)) return; // NeonPaper - Test this earlier
if (!entity.noclip && !this.noclip) { double d0 = entity.locX - this.locX;
double d0 = entity.locX - this.locX; double d1 = entity.locZ - this.locZ;
double d1 = entity.locZ - this.locZ; double d2 = MathHelper.a(d0, d1);
double d2 = MathHelper.a(d0, d1);
if (d2 >= 0.009999999776482582D) { if (d2 >= 0.009999999776482582D) {
d2 = (double) MathHelper.sqrt(d2); d2 = (double) MathHelper.sqrt(d2);
d0 /= d2; d0 /= d2;
d1 /= d2; d1 /= d2;
double d3 = 1.0D / d2; double d3 = 1.0D / d2;
if (d3 > 1.0D) { if (d3 > 1.0D) {
d3 = 1.0D; d3 = 1.0D;
} }
d0 *= d3; d0 *= d3;
d1 *= d3; d1 *= d3;
d0 *= 0.05000000074505806D; d0 *= 0.05000000074505806D;
d1 *= 0.05000000074505806D; d1 *= 0.05000000074505806D;
d0 *= (double) (1.0F - this.R); d0 *= (double) (1.0F - this.R);
d1 *= (double) (1.0F - this.R); d1 *= (double) (1.0F - this.R);
if (!this.isVehicle()) { if (!this.isVehicle()) {
this.f(-d0, 0.0D, -d1); this.f(-d0, 0.0D, -d1);
} }
if (!entity.isVehicle()) {
entity.f(d0, 0.0D, d1);
}
}
if (!entity.isVehicle()) {
entity.f(d0, 0.0D, d1);
} }
} }
} }
@@ -2881,7 +2881,7 @@ public abstract class Entity implements ICommandListener, KeyedObject { // Paper
} }
public List<Entity> bF() { public List<Entity> bF() {
return (List) (this.passengers.isEmpty() ? Collections.emptyList() : Lists.newArrayList(this.passengers)); return (List) (this.passengers.isEmpty() ? Collections.emptyList() : new ObjectArrayList<>(this.passengers)); // Dionysus
} }
public boolean w(Entity entity) { public boolean w(Entity entity) {

View File

@@ -0,0 +1,476 @@
package net.minecraft.server;
import com.destroystokyo.paper.event.entity.EndermanEscapeEvent;
import com.google.common.base.Function;
import com.google.common.base.Optional;
import com.google.common.base.Predicate;
import com.google.common.collect.Sets;
import org.bukkit.event.entity.EntityTargetEvent;
import java.util.Random;
import java.util.Set;
import java.util.UUID;
import javax.annotation.Nullable;
public class EntityEnderman extends EntityMonster {
private static final UUID a = UUID.fromString("020E0DFB-87AE-4653-9556-831010E291A0");
private static final AttributeModifier b = (new AttributeModifier(EntityEnderman.a, "Attacking speed boost", 0.15000000596046448D, 0)).a(false);
private static final Set<Block> c = Sets.newIdentityHashSet();
private static final DataWatcherObject<Optional<IBlockData>> bx = DataWatcher.a(EntityEnderman.class, DataWatcherRegistry.g);
private static final DataWatcherObject<Boolean> by = DataWatcher.a(EntityEnderman.class, DataWatcherRegistry.h);
private int bz;
private int bA;
public EntityEnderman(World world) {
super(world);
this.setSize(0.6F, 2.9F);
this.P = 1.0F;
this.a(PathType.WATER, -1.0F);
}
protected void r() {
this.goalSelector.a(0, new PathfinderGoalFloat(this));
this.goalSelector.a(2, new PathfinderGoalMeleeAttack(this, 1.0D, false));
this.goalSelector.a(7, new PathfinderGoalRandomStrollLand(this, 1.0D, 0.0F));
this.goalSelector.a(8, new PathfinderGoalLookAtPlayer(this, EntityHuman.class, 8.0F));
this.goalSelector.a(8, new PathfinderGoalRandomLookaround(this));
this.goalSelector.a(10, new EntityEnderman.PathfinderGoalEndermanPlaceBlock(this));
this.goalSelector.a(11, new EntityEnderman.PathfinderGoalEndermanPickupBlock(this));
this.targetSelector.a(1, new EntityEnderman.PathfinderGoalPlayerWhoLookedAtTarget(this));
this.targetSelector.a(2, new PathfinderGoalHurtByTarget(this, false, new Class[0]));
this.targetSelector.a(3, new PathfinderGoalNearestAttackableTarget(this, EntityEndermite.class, 10, true, false, new Predicate() {
public boolean a(@Nullable EntityEndermite entityendermite) {
return entityendermite.p();
}
public boolean apply(@Nullable Object object) {
return this.a((EntityEndermite) object);
}
}));
}
protected void initAttributes() {
super.initAttributes();
this.getAttributeInstance(GenericAttributes.maxHealth).setValue(40.0D);
this.getAttributeInstance(GenericAttributes.MOVEMENT_SPEED).setValue(0.30000001192092896D);
this.getAttributeInstance(GenericAttributes.ATTACK_DAMAGE).setValue(7.0D);
this.getAttributeInstance(GenericAttributes.FOLLOW_RANGE).setValue(64.0D);
}
public void setGoalTarget(@Nullable EntityLiving entityliving) {
// CraftBukkit start - fire event
setGoalTarget(entityliving, EntityTargetEvent.TargetReason.UNKNOWN, true);
}
// Paper start
private boolean tryEscape(EndermanEscapeEvent.Reason reason) {
return new EndermanEscapeEvent((org.bukkit.craftbukkit.entity.CraftEnderman) this.getBukkitEntity(), reason).callEvent();
}
// Paper end
@Override
public boolean setGoalTarget(EntityLiving entityliving, org.bukkit.event.entity.EntityTargetEvent.TargetReason reason, boolean fireEvent) {
if (!super.setGoalTarget(entityliving, reason, fireEvent)) {
return false;
}
entityliving = getGoalTarget();
// CraftBukkit end
AttributeInstance attributeinstance = this.getAttributeInstance(GenericAttributes.MOVEMENT_SPEED);
if (entityliving == null) {
this.bA = 0;
this.datawatcher.set(EntityEnderman.by, Boolean.valueOf(false));
attributeinstance.c(EntityEnderman.b);
} else {
this.bA = this.ticksLived;
this.datawatcher.set(EntityEnderman.by, Boolean.valueOf(true));
if (!attributeinstance.a(EntityEnderman.b)) {
attributeinstance.b(EntityEnderman.b);
}
}
return true;
}
protected void i() {
super.i();
this.datawatcher.register(EntityEnderman.bx, Optional.absent());
this.datawatcher.register(EntityEnderman.by, Boolean.valueOf(false));
}
public void p() {
if (this.ticksLived >= this.bz + 400) {
this.bz = this.ticksLived;
if (!this.isSilent()) {
this.world.a(this.locX, this.locY + (double) this.getHeadHeight(), this.locZ, SoundEffects.bh, this.bK(), 2.5F, 1.0F, false);
}
}
}
public void a(DataWatcherObject<?> datawatcherobject) {
if (EntityEnderman.by.equals(datawatcherobject) && this.do_() && this.world.isClientSide) {
this.p();
}
super.a(datawatcherobject);
}
public static void a(DataConverterManager dataconvertermanager) {
EntityInsentient.a(dataconvertermanager, EntityEnderman.class);
}
public void b(NBTTagCompound nbttagcompound) {
super.b(nbttagcompound);
IBlockData iblockdata = this.getCarried();
if (iblockdata != null) {
nbttagcompound.setShort("carried", (short) Block.getId(iblockdata.getBlock()));
nbttagcompound.setShort("carriedData", (short) iblockdata.getBlock().toLegacyData(iblockdata));
}
}
public void a(NBTTagCompound nbttagcompound) {
super.a(nbttagcompound);
IBlockData iblockdata;
if (nbttagcompound.hasKeyOfType("carried", 8)) {
iblockdata = Block.getByName(nbttagcompound.getString("carried")).fromLegacyData(nbttagcompound.getShort("carriedData") & '\uffff');
} else {
iblockdata = Block.getById(nbttagcompound.getShort("carried")).fromLegacyData(nbttagcompound.getShort("carriedData") & '\uffff');
}
if (iblockdata == null || iblockdata.getBlock() == null || iblockdata.getMaterial() == Material.AIR) {
iblockdata = null;
}
this.setCarried(iblockdata);
}
// Paper start - OBFHELPER - ok not really, but verify this on updates
private boolean f(EntityHuman entityhuman) {
boolean shouldAttack = f_real(entityhuman);
com.destroystokyo.paper.event.entity.EndermanAttackPlayerEvent event = new com.destroystokyo.paper.event.entity.EndermanAttackPlayerEvent((org.bukkit.entity.Enderman) getBukkitEntity(), (org.bukkit.entity.Player) entityhuman.getBukkitEntity());
event.setCancelled(!shouldAttack);
return event.callEvent();
}
private boolean f_real(EntityHuman entityhuman) {
// Paper end
ItemStack itemstack = (ItemStack) entityhuman.inventory.armor.get(3);
if (itemstack.getItem() == Item.getItemOf(Blocks.PUMPKIN)) {
return false;
} else {
Vec3D vec3d = entityhuman.e(1.0F).a();
Vec3D vec3d1 = new Vec3D(this.locX - entityhuman.locX, this.getBoundingBox().b + (double) this.getHeadHeight() - (entityhuman.locY + (double) entityhuman.getHeadHeight()), this.locZ - entityhuman.locZ);
double d0 = vec3d1.b();
vec3d1 = vec3d1.a();
double d1 = vec3d.b(vec3d1);
return d1 > 1.0D - 0.025D / d0 ? entityhuman.hasLineOfSight(this) : false;
}
}
public float getHeadHeight() {
return 2.55F;
}
public void n() {
if (this.world.isClientSide) {
for (int i = 0; i < 2; ++i) {
this.world.addParticle(EnumParticle.PORTAL, this.locX + (this.random.nextDouble() - 0.5D) * (double) this.width, this.locY + this.random.nextDouble() * (double) this.length - 0.25D, this.locZ + (this.random.nextDouble() - 0.5D) * (double) this.width, (this.random.nextDouble() - 0.5D) * 2.0D, -this.random.nextDouble(), (this.random.nextDouble() - 0.5D) * 2.0D, new int[0]);
}
}
this.bd = false;
super.n();
}
protected void M() {
if (this.an()) {
this.damageEntity(DamageSource.DROWN, 1.0F);
}
if (this.world.D() && this.ticksLived >= this.bA + 600) {
float f = this.aw();
if (f > 0.5F && this.world.h(new BlockPosition(this)) && this.random.nextFloat() * 30.0F < (f - 0.4F) * 2.0F && tryEscape(EndermanEscapeEvent.Reason.RUNAWAY)) { // Paper
this.setGoalTarget((EntityLiving) null);
this.dm();
}
}
super.M();
}
public boolean teleportRandomly() { return dm(); } // Paper - OBFHELPER
protected boolean dm() {
double d0 = this.locX + (this.random.nextDouble() - 0.5D) * 64.0D;
double d1 = this.locY + (double) (this.random.nextInt(64) - 32);
double d2 = this.locZ + (this.random.nextDouble() - 0.5D) * 64.0D;
return this.k(d0, d1, d2);
}
protected boolean a(Entity entity) {
Vec3D vec3d = new Vec3D(this.locX - entity.locX, this.getBoundingBox().b + (double) (this.length / 2.0F) - entity.locY + (double) entity.getHeadHeight(), this.locZ - entity.locZ);
vec3d = vec3d.a();
double d0 = 16.0D;
double d1 = this.locX + (this.random.nextDouble() - 0.5D) * 8.0D - vec3d.x * 16.0D;
double d2 = this.locY + (double) (this.random.nextInt(16) - 8) - vec3d.y * 16.0D;
double d3 = this.locZ + (this.random.nextDouble() - 0.5D) * 8.0D - vec3d.z * 16.0D;
return this.k(d1, d2, d3);
}
private boolean k(double d0, double d1, double d2) {
boolean flag = this.j(d0, d1, d2);
if (flag) {
this.world.a((EntityHuman) null, this.lastX, this.lastY, this.lastZ, SoundEffects.bi, this.bK(), 1.0F, 1.0F);
this.a(SoundEffects.bi, 1.0F, 1.0F);
}
return flag;
}
protected SoundEffect F() {
return this.do_() ? SoundEffects.bg : SoundEffects.bd;
}
protected SoundEffect d(DamageSource damagesource) {
return SoundEffects.bf;
}
protected SoundEffect cf() {
return SoundEffects.be;
}
protected void dropEquipment(boolean flag, int i) {
super.dropEquipment(flag, i);
IBlockData iblockdata = this.getCarried();
if (iblockdata != null) {
Item item = Item.getItemOf(iblockdata.getBlock());
int j = item.k() ? iblockdata.getBlock().toLegacyData(iblockdata) : 0;
this.a(new ItemStack(item, 1, j), 0.0F);
}
}
@Nullable
protected MinecraftKey J() {
return LootTables.w;
}
public void setCarried(@Nullable IBlockData iblockdata) {
this.datawatcher.set(EntityEnderman.bx, Optional.fromNullable(iblockdata));
}
@Nullable
public IBlockData getCarried() {
return (IBlockData) ((Optional) this.datawatcher.get(EntityEnderman.bx)).orNull();
}
public boolean damageEntity(DamageSource damagesource, float f) {
if (this.isInvulnerable(damagesource)) {
return false;
} else if (damagesource instanceof EntityDamageSourceIndirect && tryEscape(EndermanEscapeEvent.Reason.INDIRECT)) { // Paper
for (int i = 0; i < 64; ++i) {
if (this.dm()) {
return true;
}
}
return false;
} else {
boolean flag = super.damageEntity(damagesource, f);
if (damagesource.ignoresArmor() && this.random.nextInt(10) != 0 && tryEscape(damagesource == DamageSource.DROWN ? EndermanEscapeEvent.Reason.DROWN : EndermanEscapeEvent.Reason.CRITICAL_HIT)) { // Paper
this.dm();
}
return flag;
}
}
public boolean do_() {
return ((Boolean) this.datawatcher.get(EntityEnderman.by)).booleanValue();
}
static {
EntityEnderman.c.add(Blocks.GRASS);
EntityEnderman.c.add(Blocks.DIRT);
EntityEnderman.c.add(Blocks.SAND);
EntityEnderman.c.add(Blocks.GRAVEL);
EntityEnderman.c.add(Blocks.YELLOW_FLOWER);
EntityEnderman.c.add(Blocks.RED_FLOWER);
EntityEnderman.c.add(Blocks.BROWN_MUSHROOM);
EntityEnderman.c.add(Blocks.RED_MUSHROOM);
EntityEnderman.c.add(Blocks.TNT);
EntityEnderman.c.add(Blocks.CACTUS);
EntityEnderman.c.add(Blocks.CLAY);
EntityEnderman.c.add(Blocks.PUMPKIN);
EntityEnderman.c.add(Blocks.MELON_BLOCK);
EntityEnderman.c.add(Blocks.MYCELIUM);
EntityEnderman.c.add(Blocks.NETHERRACK);
}
static class PathfinderGoalEndermanPickupBlock extends PathfinderGoal {
private final EntityEnderman enderman;
public PathfinderGoalEndermanPickupBlock(EntityEnderman entityenderman) {
this.enderman = entityenderman;
}
public boolean a() {
return this.enderman.getCarried() != null ? false : (!this.enderman.world.getGameRules().getBoolean("mobGriefing") ? false : this.enderman.getRandom().nextInt(20) == 0);
}
public void e() {
Random random = this.enderman.getRandom();
World world = this.enderman.world;
int i = MathHelper.floor(this.enderman.locX - 2.0D + random.nextDouble() * 4.0D);
int j = MathHelper.floor(this.enderman.locY + random.nextDouble() * 3.0D);
int k = MathHelper.floor(this.enderman.locZ - 2.0D + random.nextDouble() * 4.0D);
BlockPosition blockposition = new BlockPosition(i, j, k);
IBlockData iblockdata = world.getTypeIfLoaded(blockposition); // NeonPaper
if (iblockdata == null) return; // NeonPaper
Block block = iblockdata.getBlock();
MovingObjectPosition movingobjectposition = world.rayTrace(new Vec3D((double) ((float) MathHelper.floor(this.enderman.locX) + 0.5F), (double) ((float) j + 0.5F), (double) ((float) MathHelper.floor(this.enderman.locZ) + 0.5F)), new Vec3D((double) ((float) i + 0.5F), (double) ((float) j + 0.5F), (double) ((float) k + 0.5F)), false, true, false);
boolean flag = movingobjectposition != null && movingobjectposition.a().equals(blockposition);
if (EntityEnderman.c.contains(block) && flag) {
// CraftBukkit start - Pickup event
if (!org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(this.enderman, this.enderman.world.getWorld().getBlockAt(blockposition.getX(), blockposition.getY(), blockposition.getZ()), org.bukkit.Material.AIR).isCancelled()) {
this.enderman.setCarried(iblockdata);
world.setAir(blockposition);
}
// CraftBukkit end
}
}
}
static class PathfinderGoalEndermanPlaceBlock extends PathfinderGoal {
private final EntityEnderman a;
public PathfinderGoalEndermanPlaceBlock(EntityEnderman entityenderman) {
this.a = entityenderman;
}
public boolean a() {
return this.a.getCarried() == null ? false : (!this.a.world.getGameRules().getBoolean("mobGriefing") ? false : this.a.getRandom().nextInt(2000) == 0);
}
public void e() {
Random random = this.a.getRandom();
World world = this.a.world;
int i = MathHelper.floor(this.a.locX - 1.0D + random.nextDouble() * 2.0D);
int j = MathHelper.floor(this.a.locY + random.nextDouble() * 2.0D);
int k = MathHelper.floor(this.a.locZ - 1.0D + random.nextDouble() * 2.0D);
BlockPosition blockposition = new BlockPosition(i, j, k);
IBlockData iblockdata = world.getTypeIfLoaded(blockposition); // NeonPaper
if (iblockdata == null) return; // NeonPaper
IBlockData iblockdata1 = world.getType(blockposition.down());
IBlockData iblockdata2 = this.a.getCarried();
if (iblockdata2 != null && this.a(world, blockposition, iblockdata2.getBlock(), iblockdata, iblockdata1)) {
// CraftBukkit start - Place event
if (!org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(this.a, blockposition, this.a.getCarried().getBlock(), this.a.getCarried().getBlock().toLegacyData(this.a.getCarried())).isCancelled()) {
world.setTypeAndData(blockposition, iblockdata2, 3);
this.a.setCarried((IBlockData) null);
}
// CraftBukkit end
}
}
private boolean a(World world, BlockPosition blockposition, Block block, IBlockData iblockdata, IBlockData iblockdata1) {
return !block.canPlace(world, blockposition) ? false : (iblockdata.getMaterial() != Material.AIR ? false : (iblockdata1.getMaterial() == Material.AIR ? false : iblockdata1.g()));
}
}
static class PathfinderGoalPlayerWhoLookedAtTarget extends PathfinderGoalNearestAttackableTarget<EntityHuman> {
private final EntityEnderman i; public EntityEnderman getEnderman() { return i; } // Paper - OBFHELPER
private EntityHuman j;
private int k;
private int l;
public PathfinderGoalPlayerWhoLookedAtTarget(EntityEnderman entityenderman) {
super(entityenderman, EntityHuman.class, false);
this.i = entityenderman;
}
public boolean a() {
double d0 = this.i();
this.j = this.i.world.a(this.i.locX, this.i.locY, this.i.locZ, d0, d0, (Function) null, new Predicate() {
public boolean a(@Nullable EntityHuman entityhuman) {
return entityhuman != null && PathfinderGoalPlayerWhoLookedAtTarget.this.i.f(entityhuman);
}
public boolean apply(@Nullable Object object) {
return this.a((EntityHuman) object);
}
});
return this.j != null;
}
public void c() {
this.k = 5;
this.l = 0;
}
public void d() {
this.j = null;
super.d();
}
public boolean b() {
if (this.j != null) {
if (!this.i.f(this.j)) {
return false;
} else {
this.i.a((Entity) this.j, 10.0F, 10.0F);
return true;
}
} else {
return this.d != null && ((EntityHuman) this.d).isAlive() ? true : super.b();
}
}
public void e() {
if (this.j != null) {
if (--this.k <= 0) {
this.d = this.j;
this.j = null;
super.c();
}
} else {
if (this.d != null) {
if (this.i.f((EntityHuman) this.d)) {
if (((EntityHuman) this.d).h(this.i) < 16.0D && this.getEnderman().tryEscape(EndermanEscapeEvent.Reason.STARE)) { // Paper
this.i.dm();
}
this.l = 0;
} else if (((EntityHuman) this.d).h(this.i) > 256.0D && this.l++ >= 30 && this.i.a((Entity) this.d)) {
this.l = 0;
}
}
super.e();
}
}
}
}

View File

@@ -0,0 +1,538 @@
package net.minecraft.server;
import java.util.Iterator;
import java.util.List;
// CraftBukkit start
import org.bukkit.entity.Player;
import org.bukkit.entity.Fish;
import org.bukkit.event.player.PlayerFishEvent;
// CraftBukkit end
public class EntityFishingHook extends Entity {
private static final DataWatcherObject<Integer> b = DataWatcher.a(EntityFishingHook.class, DataWatcherRegistry.b);
private boolean isInGround;
private int d;
public EntityHuman owner;
private int f;
private int g;
private int h;
private int at;
private float au;
public Entity hooked;
private EntityFishingHook.HookState av;
private int aw;
private int ax;
public EntityFishingHook(World world, EntityHuman entityhuman) {
super(world);
this.av = EntityFishingHook.HookState.FLYING;
this.a(entityhuman);
this.n();
}
private void a(EntityHuman entityhuman) {
this.setSize(0.25F, 0.25F);
this.ah = true;
this.owner = entityhuman;
this.owner.hookedFish = this;
}
public void a(int i) {
this.ax = i;
}
public void c(int i) {
this.aw = i;
}
private void n() {
float f = this.owner.lastPitch + (this.owner.pitch - this.owner.lastPitch);
float f1 = this.owner.lastYaw + (this.owner.yaw - this.owner.lastYaw);
float f2 = MathHelper.cos(-f1 * 0.017453292F - 3.1415927F);
float f3 = MathHelper.sin(-f1 * 0.017453292F - 3.1415927F);
float f4 = -MathHelper.cos(-f * 0.017453292F);
float f5 = MathHelper.sin(-f * 0.017453292F);
double d0 = this.owner.lastX + (this.owner.locX - this.owner.lastX) - (double) f3 * 0.3D;
double d1 = this.owner.lastY + (this.owner.locY - this.owner.lastY) + (double) this.owner.getHeadHeight();
double d2 = this.owner.lastZ + (this.owner.locZ - this.owner.lastZ) - (double) f2 * 0.3D;
this.setPositionRotation(d0, d1, d2, f1, f);
this.motX = (double) (-f3);
this.motY = (double) MathHelper.a(-(f5 / f4), -5.0F, 5.0F);
this.motZ = (double) (-f2);
float f6 = MathHelper.sqrt(this.motX * this.motX + this.motY * this.motY + this.motZ * this.motZ);
this.motX *= 0.6D / (double) f6 + 0.5D + this.random.nextGaussian() * 0.0045D;
this.motY *= 0.6D / (double) f6 + 0.5D + this.random.nextGaussian() * 0.0045D;
this.motZ *= 0.6D / (double) f6 + 0.5D + this.random.nextGaussian() * 0.0045D;
float f7 = MathHelper.sqrt(this.motX * this.motX + this.motZ * this.motZ);
this.yaw = (float) (MathHelper.c(this.motX, this.motZ) * 57.2957763671875D);
this.pitch = (float) (MathHelper.c(this.motY, (double) f7) * 57.2957763671875D);
this.lastYaw = this.yaw;
this.lastPitch = this.pitch;
}
protected void i() {
this.getDataWatcher().register(EntityFishingHook.b, Integer.valueOf(0));
}
public void a(DataWatcherObject<?> datawatcherobject) {
if (EntityFishingHook.b.equals(datawatcherobject)) {
int i = ((Integer) this.getDataWatcher().get(EntityFishingHook.b)).intValue();
this.hooked = i > 0 ? this.world.getEntity(i - 1) : null;
}
super.a(datawatcherobject);
}
public void B_() {
super.B_();
if (this.owner == null) {
this.die();
} else if (this.world.isClientSide || !this.p()) {
if (this.isInGround) {
++this.d;
if (this.d >= 1200) {
this.die();
return;
}
}
float f = 0.0F;
BlockPosition blockposition = new BlockPosition(this);
IBlockData iblockdata = this.world.getType(blockposition);
if (iblockdata.getMaterial() == Material.WATER) {
f = BlockFluids.g(iblockdata, this.world, blockposition);
}
double d0;
if (this.av == EntityFishingHook.HookState.FLYING) {
if (this.hooked != null) {
this.motX = 0.0D;
this.motY = 0.0D;
this.motZ = 0.0D;
this.av = EntityFishingHook.HookState.HOOKED_IN_ENTITY;
return;
}
if (f > 0.0F) {
this.motX *= 0.3D;
this.motY *= 0.2D;
this.motZ *= 0.3D;
this.av = EntityFishingHook.HookState.BOBBING;
return;
}
if (!this.world.isClientSide) {
this.r();
}
if (!this.isInGround && !this.onGround && !this.positionChanged) {
++this.f;
} else {
this.f = 0;
this.motX = 0.0D;
this.motY = 0.0D;
this.motZ = 0.0D;
}
} else {
if (this.av == EntityFishingHook.HookState.HOOKED_IN_ENTITY) {
if (this.hooked != null) {
if (this.hooked.dead) {
this.hooked = null;
this.av = EntityFishingHook.HookState.FLYING;
} else {
this.locX = this.hooked.locX;
double d1 = (double) this.hooked.length;
this.locY = this.hooked.getBoundingBox().b + d1 * 0.8D;
this.locZ = this.hooked.locZ;
this.setPosition(this.locX, this.locY, this.locZ);
if (this.ak) this.die(); // NeonPaper - Prevent going through portals
}
}
return;
}
if (this.av == EntityFishingHook.HookState.BOBBING) {
this.motX *= 0.9D;
this.motZ *= 0.9D;
d0 = this.locY + this.motY - (double) blockposition.getY() - (double) f;
if (Math.abs(d0) < 0.01D) {
d0 += Math.signum(d0) * 0.1D;
}
this.motY -= d0 * (double) this.random.nextFloat() * 0.2D;
if (!this.world.isClientSide && f > 0.0F) {
this.a(blockposition);
}
}
}
if (iblockdata.getMaterial() != Material.WATER) {
this.motY -= 0.03D;
}
this.move(EnumMoveType.SELF, this.motX, this.motY, this.motZ);
this.q();
d0 = 0.92D;
this.motX *= 0.92D;
this.motY *= 0.92D;
this.motZ *= 0.92D;
this.setPosition(this.locX, this.locY, this.locZ);
// Paper start - These shouldn't be going through portals
if (this.inPortal()) {
this.die();
}
// Paper end
}
}
private boolean p() {
ItemStack itemstack = this.owner.getItemInMainHand();
ItemStack itemstack1 = this.owner.getItemInOffHand();
boolean flag = itemstack.getItem() == Items.FISHING_ROD;
boolean flag1 = itemstack1.getItem() == Items.FISHING_ROD;
if (!this.owner.dead && this.owner.isAlive() && (flag || flag1) && this.h(this.owner) <= 1024.0D) {
return false;
} else {
this.die();
return true;
}
}
private void q() {
float f = MathHelper.sqrt(this.motX * this.motX + this.motZ * this.motZ);
this.yaw = (float) (MathHelper.c(this.motX, this.motZ) * 57.2957763671875D);
for (this.pitch = (float) (MathHelper.c(this.motY, (double) f) * 57.2957763671875D); this.pitch - this.lastPitch < -180.0F; this.lastPitch -= 360.0F) {
;
}
while (this.pitch - this.lastPitch >= 180.0F) {
this.lastPitch += 360.0F;
}
while (this.yaw - this.lastYaw < -180.0F) {
this.lastYaw -= 360.0F;
}
while (this.yaw - this.lastYaw >= 180.0F) {
this.lastYaw += 360.0F;
}
this.pitch = this.lastPitch + (this.pitch - this.lastPitch) * 0.2F;
this.yaw = this.lastYaw + (this.yaw - this.lastYaw) * 0.2F;
}
private void r() {
Vec3D vec3d = new Vec3D(this.locX, this.locY, this.locZ);
Vec3D vec3d1 = new Vec3D(this.locX + this.motX, this.locY + this.motY, this.locZ + this.motZ);
MovingObjectPosition movingobjectposition = this.world.rayTrace(vec3d, vec3d1, false, true, false);
vec3d = new Vec3D(this.locX, this.locY, this.locZ);
vec3d1 = new Vec3D(this.locX + this.motX, this.locY + this.motY, this.locZ + this.motZ);
// Paper start - Call ProjectileCollideEvent
if (movingobjectposition != null && movingobjectposition.entity != null) {
com.destroystokyo.paper.event.entity.ProjectileCollideEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callProjectileCollideEvent(this, movingobjectposition);
if (event.isCancelled()) {
movingobjectposition = null;
}
}
// Paper end
if (movingobjectposition != null) {
vec3d1 = new Vec3D(movingobjectposition.pos.x, movingobjectposition.pos.y, movingobjectposition.pos.z);
}
Entity entity = null;
List list = this.world.getEntities(this, this.getBoundingBox().b(this.motX, this.motY, this.motZ).g(1.0D));
double d0 = 0.0D;
Iterator iterator = list.iterator();
while (iterator.hasNext()) {
Entity entity1 = (Entity) iterator.next();
if (this.a(entity1) && (entity1 != this.owner || this.f >= 5)) {
AxisAlignedBB axisalignedbb = entity1.getBoundingBox().g(0.30000001192092896D);
MovingObjectPosition movingobjectposition1 = axisalignedbb.b(vec3d, vec3d1);
if (movingobjectposition1 != null) {
double d1 = vec3d.distanceSquared(movingobjectposition1.pos);
if (d1 < d0 || d0 == 0.0D) {
entity = entity1;
d0 = d1;
}
}
}
}
if (entity != null) {
movingobjectposition = new MovingObjectPosition(entity);
}
if (movingobjectposition != null && movingobjectposition.type != MovingObjectPosition.EnumMovingObjectType.MISS) {
org.bukkit.craftbukkit.event.CraftEventFactory.callProjectileHitEvent(this, movingobjectposition); // Craftbukkit - Call event
if (movingobjectposition.type == MovingObjectPosition.EnumMovingObjectType.ENTITY) {
this.hooked = movingobjectposition.entity;
this.s();
} else {
this.isInGround = true;
}
}
}
private void s() {
this.getDataWatcher().set(EntityFishingHook.b, Integer.valueOf(this.hooked.getId() + 1));
}
private void a(BlockPosition blockposition) {
WorldServer worldserver = (WorldServer) this.world;
int i = 1;
BlockPosition blockposition1 = blockposition.up();
if (this.random.nextFloat() < 0.25F && this.world.isRainingAt(blockposition1)) {
++i;
}
if (this.random.nextFloat() < 0.5F && !this.world.h(blockposition1)) {
--i;
}
if (this.g > 0) {
--this.g;
if (this.g <= 0) {
this.h = 0;
this.at = 0;
// CraftBukkit start
PlayerFishEvent playerFishEvent = new PlayerFishEvent((Player) this.owner.getBukkitEntity(), null, (Fish) this.getBukkitEntity(), PlayerFishEvent.State.FAILED_ATTEMPT);
this.world.getServer().getPluginManager().callEvent(playerFishEvent);
// CraftBukkit end
} else {
this.motY -= 0.2D * (double) this.random.nextFloat() * (double) this.random.nextFloat();
}
} else {
float f;
float f1;
float f2;
double d0;
double d1;
double d2;
Block block;
if (this.at > 0) {
this.at -= i;
if (this.at > 0) {
this.au = (float) ((double) this.au + this.random.nextGaussian() * 4.0D);
f = this.au * 0.017453292F;
f1 = MathHelper.sin(f);
f2 = MathHelper.cos(f);
d0 = this.locX + (double) (f1 * (float) this.at * 0.1F);
d1 = (double) ((float) MathHelper.floor(this.getBoundingBox().b) + 1.0F);
d2 = this.locZ + (double) (f2 * (float) this.at * 0.1F);
block = worldserver.getType(new BlockPosition(d0, d1 - 1.0D, d2)).getBlock();
if (block == Blocks.WATER || block == Blocks.FLOWING_WATER) {
if (this.random.nextFloat() < 0.15F) {
worldserver.a(EnumParticle.WATER_BUBBLE, d0, d1 - 0.10000000149011612D, d2, 1, (double) f1, 0.1D, (double) f2, 0.0D, new int[0]);
}
float f3 = f1 * 0.04F;
float f4 = f2 * 0.04F;
worldserver.a(EnumParticle.WATER_WAKE, d0, d1, d2, 0, (double) f4, 0.01D, (double) (-f3), 1.0D, new int[0]);
worldserver.a(EnumParticle.WATER_WAKE, d0, d1, d2, 0, (double) (-f4), 0.01D, (double) f3, 1.0D, new int[0]);
}
} else {
// CraftBukkit start
PlayerFishEvent playerFishEvent = new PlayerFishEvent((Player) this.owner.getBukkitEntity(), null, (Fish) this.getBukkitEntity(), PlayerFishEvent.State.BITE);
this.world.getServer().getPluginManager().callEvent(playerFishEvent);
if (playerFishEvent.isCancelled()) {
return;
}
// CraftBukkit end
this.motY = (double) (-0.4F * MathHelper.a(this.random, 0.6F, 1.0F));
this.a(SoundEffects.K, 0.25F, 1.0F + (this.random.nextFloat() - this.random.nextFloat()) * 0.4F);
double d3 = this.getBoundingBox().b + 0.5D;
worldserver.a(EnumParticle.WATER_BUBBLE, this.locX, d3, this.locZ, (int) (1.0F + this.width * 20.0F), (double) this.width, 0.0D, (double) this.width, 0.20000000298023224D, new int[0]);
worldserver.a(EnumParticle.WATER_WAKE, this.locX, d3, this.locZ, (int) (1.0F + this.width * 20.0F), (double) this.width, 0.0D, (double) this.width, 0.20000000298023224D, new int[0]);
this.g = MathHelper.nextInt(this.random, 20, 40);
}
} else if (this.h > 0) {
this.h -= i;
f = 0.15F;
if (this.h < 20) {
f = (float) ((double) f + (double) (20 - this.h) * 0.05D);
} else if (this.h < 40) {
f = (float) ((double) f + (double) (40 - this.h) * 0.02D);
} else if (this.h < 60) {
f = (float) ((double) f + (double) (60 - this.h) * 0.01D);
}
if (this.random.nextFloat() < f) {
f1 = MathHelper.a(this.random, 0.0F, 360.0F) * 0.017453292F;
f2 = MathHelper.a(this.random, 25.0F, 60.0F);
d0 = this.locX + (double) (MathHelper.sin(f1) * f2 * 0.1F);
d1 = (double) ((float) MathHelper.floor(this.getBoundingBox().b) + 1.0F);
d2 = this.locZ + (double) (MathHelper.cos(f1) * f2 * 0.1F);
block = worldserver.getType(new BlockPosition((int) d0, (int) d1 - 1, (int) d2)).getBlock();
if (block == Blocks.WATER || block == Blocks.FLOWING_WATER) {
worldserver.a(EnumParticle.WATER_SPLASH, d0, d1, d2, 2 + this.random.nextInt(2), 0.10000000149011612D, 0.0D, 0.10000000149011612D, 0.0D, new int[0]);
}
}
if (this.h <= 0) {
this.au = MathHelper.a(this.random, 0.0F, 360.0F);
this.at = MathHelper.nextInt(this.random, 20, 80);
}
} else {
this.h = MathHelper.nextInt(this.random, world.paperConfig.fishingMinTicks, world.paperConfig.fishingMaxTicks); // Paper
this.h -= this.ax * 20 * 5;
}
}
}
protected boolean a(Entity entity) {
return entity.isInteractable() || entity instanceof EntityItem;
}
public void b(NBTTagCompound nbttagcompound) {}
public void a(NBTTagCompound nbttagcompound) {}
public int j() {
if (!this.world.isClientSide && this.owner != null) {
int i = 0;
if (this.hooked != null) {
// CraftBukkit start
PlayerFishEvent playerFishEvent = new PlayerFishEvent((Player) this.owner.getBukkitEntity(), this.hooked.getBukkitEntity(), (Fish) this.getBukkitEntity(), PlayerFishEvent.State.CAUGHT_ENTITY);
this.world.getServer().getPluginManager().callEvent(playerFishEvent);
if (playerFishEvent.isCancelled()) {
return 0;
}
// CraftBukkit end
this.k();
this.world.broadcastEntityEffect(this, (byte) 31);
i = this.hooked instanceof EntityItem ? 3 : 5;
} else if (this.g > 0) {
LootTableInfo.a loottableinfo_a = new LootTableInfo.a((WorldServer) this.world);
loottableinfo_a.a((float) this.aw + this.owner.du());
Iterator iterator = this.world.getLootTableRegistry().a(LootTables.aA).a(this.random, loottableinfo_a.a()).iterator();
while (iterator.hasNext()) {
ItemStack itemstack = (ItemStack) iterator.next();
EntityItem entityitem = new EntityItem(this.world, this.locX, this.locY, this.locZ, itemstack);
// CraftBukkit start
PlayerFishEvent playerFishEvent = new PlayerFishEvent((Player) this.owner.getBukkitEntity(), entityitem.getBukkitEntity(), (Fish) this.getBukkitEntity(), PlayerFishEvent.State.CAUGHT_FISH);
playerFishEvent.setExpToDrop(this.random.nextInt(6) + 1);
this.world.getServer().getPluginManager().callEvent(playerFishEvent);
if (playerFishEvent.isCancelled()) {
return 0;
}
// CraftBukkit end
double d0 = this.owner.locX - this.locX;
double d1 = this.owner.locY - this.locY;
double d2 = this.owner.locZ - this.locZ;
double d3 = (double) MathHelper.sqrt(d0 * d0 + d1 * d1 + d2 * d2);
double d4 = 0.1D;
entityitem.motX = d0 * 0.1D;
entityitem.motY = d1 * 0.1D + (double) MathHelper.sqrt(d3) * 0.08D;
entityitem.motZ = d2 * 0.1D;
this.world.addEntity(entityitem);
// CraftBukkit start - this.random.nextInt(6) + 1 -> playerFishEvent.getExpToDrop()
if (playerFishEvent.getExpToDrop() > 0) {
this.owner.world.addEntity(new EntityExperienceOrb(this.owner.world, this.owner.locX, this.owner.locY + 0.5D, this.owner.locZ + 0.5D, playerFishEvent.getExpToDrop(), org.bukkit.entity.ExperienceOrb.SpawnReason.FISHING, this.owner, this)); // Paper
}
// CraftBukkit end
Item item = itemstack.getItem();
if (item == Items.FISH || item == Items.COOKED_FISH) {
this.owner.a(StatisticList.E, 1);
}
}
i = 1;
}
if (this.isInGround) {
// CraftBukkit start
PlayerFishEvent playerFishEvent = new PlayerFishEvent((Player) this.owner.getBukkitEntity(), null, (Fish) this.getBukkitEntity(), PlayerFishEvent.State.IN_GROUND);
this.world.getServer().getPluginManager().callEvent(playerFishEvent);
if (playerFishEvent.isCancelled()) {
return 0;
}
// CraftBukkit end
i = 2;
}
// CraftBukkit start
if (i == 0) {
PlayerFishEvent playerFishEvent = new PlayerFishEvent((Player) this.owner.getBukkitEntity(), null, (Fish) this.getBukkitEntity(), PlayerFishEvent.State.FAILED_ATTEMPT);
this.world.getServer().getPluginManager().callEvent(playerFishEvent);
if (playerFishEvent.isCancelled()) {
return 0;
}
}
// CraftBukkit end
this.die();
return i;
} else {
return 0;
}
}
protected void k() {
if (this.owner != null) {
double d0 = this.owner.locX - this.locX;
double d1 = this.owner.locY - this.locY;
double d2 = this.owner.locZ - this.locZ;
double d3 = 0.1D;
this.hooked.motX += d0 * 0.1D;
this.hooked.motY += d1 * 0.1D;
this.hooked.motZ += d2 * 0.1D;
}
}
protected boolean playStepSound() {
return false;
}
public void die() {
super.die();
if (this.owner != null) {
this.owner.hookedFish = null;
}
}
public EntityHuman l() {
return this.owner;
}
static enum HookState {
FLYING, HOOKED_IN_ENTITY, BOBBING;
private HookState() {}
}
}

View File

@@ -0,0 +1,84 @@
package net.minecraft.server;
import javax.annotation.Nullable;
import org.bukkit.event.player.PlayerShearEntityEvent; // CraftBukkit
public class EntityMushroomCow extends EntityCow {
public EntityMushroomCow(World world) {
super(world);
this.setSize(0.9F, 1.4F);
this.bA = Blocks.MYCELIUM;
}
public static void c(DataConverterManager dataconvertermanager) {
EntityInsentient.a(dataconvertermanager, EntityMushroomCow.class);
}
public boolean a(EntityHuman entityhuman, EnumHand enumhand) {
ItemStack itemstack = entityhuman.b(enumhand);
if (itemstack.getItem() == Items.BOWL && this.getAge() >= 0 && !entityhuman.abilities.canInstantlyBuild) {
itemstack.subtract(1);
if (itemstack.isEmpty()) {
entityhuman.a(enumhand, new ItemStack(Items.MUSHROOM_STEW));
} else if (!entityhuman.inventory.pickup(new ItemStack(Items.MUSHROOM_STEW))) {
entityhuman.drop(new ItemStack(Items.MUSHROOM_STEW), false);
}
return true;
} else if (itemstack.getItem() == Items.SHEARS && this.getAge() >= 0) {
if (this.dead) return false; // Reaper - Fix cow dupe
// CraftBukkit start
PlayerShearEntityEvent event = new PlayerShearEntityEvent((org.bukkit.entity.Player) entityhuman.getBukkitEntity(), this.getBukkitEntity());
this.world.getServer().getPluginManager().callEvent(event);
if (event.isCancelled()) {
return false;
}
// CraftBukkit end
this.die();
this.world.addParticle(EnumParticle.EXPLOSION_LARGE, this.locX, this.locY + (double) (this.length / 2.0F), this.locZ, 0.0D, 0.0D, 0.0D, new int[0]);
if (!this.world.isClientSide) {
EntityCow entitycow = new EntityCow(this.world);
entitycow.setPositionRotation(this.locX, this.locY, this.locZ, this.yaw, this.pitch);
entitycow.setHealth(this.getHealth());
entitycow.aN = this.aN;
if (this.hasCustomName()) {
entitycow.setCustomName(this.getCustomName());
}
this.world.addEntity(entitycow);
for (int i = 0; i < 5; ++i) {
this.world.addEntity(new EntityItem(this.world, this.locX, this.locY + (double) this.length, this.locZ, new ItemStack(Blocks.RED_MUSHROOM)));
}
itemstack.damage(1, entityhuman);
this.a(SoundEffects.ei, 1.0F, 1.0F);
}
return true;
} else {
return super.a(entityhuman, enumhand);
}
}
public EntityMushroomCow c(EntityAgeable entityageable) {
return new EntityMushroomCow(this.world);
}
@Nullable
protected MinecraftKey J() {
return LootTables.M;
}
public EntityCow b(EntityAgeable entityageable) {
return this.c(entityageable);
}
public EntityAgeable createChild(EntityAgeable entityageable) {
return this.c(entityageable);
}
}

View File

@@ -784,7 +784,7 @@ public class EntityPlayer extends EntityHuman implements ICrafting {
protected void a(double d0, boolean flag, IBlockData iblockdata, BlockPosition blockposition) {} protected void a(double d0, boolean flag, IBlockData iblockdata, BlockPosition blockposition) {}
protected void b(BlockPosition blockposition) { protected void b(BlockPosition blockposition) {
if (!this.isSpectator()) { if (valid && (!this.isSpectator() || this.world.isLoaded(new BlockPosition(this)))) { // Dionysus - don't tick dead players that are not in the world currently (pending respawn)
super.b(blockposition); super.b(blockposition);
} }
@@ -1156,6 +1156,7 @@ public class EntityPlayer extends EntityHuman implements ICrafting {
this.getDataWatcher().set(EntityPlayer.br, entityplayer.getDataWatcher().get(EntityPlayer.br)); this.getDataWatcher().set(EntityPlayer.br, entityplayer.getDataWatcher().get(EntityPlayer.br));
this.lastSentExp = -1; this.lastSentExp = -1;
this.lastHealthSent = -1.0F; this.lastHealthSent = -1.0F;
setSneaking(false); // NeonPaper - fix MC-10657
this.ch = -1; this.ch = -1;
// this.cr.a((RecipeBook) entityplayer.cr); // CraftBukkit // this.cr.a((RecipeBook) entityplayer.cr); // CraftBukkit
// Paper start - Optimize remove queue // Paper start - Optimize remove queue

View File

@@ -0,0 +1,654 @@
package net.minecraft.server;
import com.google.common.collect.Sets;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
// CraftBukkit start
import org.bukkit.entity.Player;
import org.bukkit.event.player.PlayerVelocityEvent;
// CraftBukkit end
public class EntityTrackerEntry {
private static final Logger c = LogManager.getLogger();
private final Entity tracker;
private final int e;
private int f;
private final int g;
private long xLoc;
private long yLoc;
private long zLoc;
private int yRot;
private int xRot;
private int headYaw;
private double n;
private double o;
private double p;
public int a;
private double q;
private double r;
private double s;
private boolean isMoving;
private final boolean u;
private int v;
private List<Entity> w = Collections.emptyList();
private boolean x;
private boolean y;
public boolean b;
// Paper start
// Replace trackedPlayers Set with a Map. The value is true until the player receives
// their first update (which is forced to have absolute coordinates), false afterward.
public java.util.Map<EntityPlayer, Boolean> trackedPlayerMap = new java.util.HashMap<EntityPlayer, Boolean>();
public Set<EntityPlayer> trackedPlayers = trackedPlayerMap.keySet();
// Paper end
public EntityTrackerEntry(Entity entity, int i, int j, int k, boolean flag) {
entity.tracker = this; // Paper
this.tracker = entity;
this.e = i;
this.f = j;
this.g = k;
this.u = flag;
this.xLoc = EntityTracker.a(entity.locX);
this.yLoc = EntityTracker.a(entity.locY);
this.zLoc = EntityTracker.a(entity.locZ);
this.yRot = MathHelper.d(entity.yaw * 256.0F / 360.0F);
this.xRot = MathHelper.d(entity.pitch * 256.0F / 360.0F);
this.headYaw = MathHelper.d(entity.getHeadRotation() * 256.0F / 360.0F);
this.y = entity.onGround;
}
public boolean equals(Object object) {
return object instanceof EntityTrackerEntry ? ((EntityTrackerEntry) object).tracker.getId() == this.tracker.getId() : false;
}
public int hashCode() {
return this.tracker.getId();
}
public void track(List<EntityHuman> list) {
this.b = false;
if (!this.isMoving || this.tracker.d(this.q, this.r, this.s) > 16.0D) {
this.q = this.tracker.locX;
this.r = this.tracker.locY;
this.s = this.tracker.locZ;
this.isMoving = true;
this.b = true;
this.scanPlayers(list);
}
List list1 = this.tracker.bF();
if (!list1.equals(this.w)) {
this.w = list1;
this.broadcastIncludingSelf(new PacketPlayOutMount(this.tracker)); // CraftBukkit
}
// PAIL : rename
if (this.tracker instanceof EntityItemFrame && this.a % 20 == 0) { // Paper
EntityItemFrame entityitemframe = (EntityItemFrame) this.tracker;
ItemStack itemstack = entityitemframe.getItem();
if (itemstack != null && itemstack.getItem() instanceof ItemWorldMap) { // Paper - moved back up
WorldMap worldmap = Items.FILLED_MAP.getSavedMap(itemstack, this.tracker.world);
Iterator iterator = this.trackedPlayers.iterator(); // CraftBukkit
while (iterator.hasNext()) {
EntityHuman entityhuman = (EntityHuman) iterator.next();
EntityPlayer entityplayer = (EntityPlayer) entityhuman;
worldmap.a(entityplayer, itemstack);
Packet packet = Items.FILLED_MAP.a(itemstack, this.tracker.world, (EntityHuman) entityplayer);
if (packet != null) {
entityplayer.playerConnection.sendPacket(packet);
}
}
}
this.d();
}
if (this.a % this.g == 0 || this.tracker.impulse || this.tracker.getDataWatcher().a()) {
int i;
if (this.tracker.isPassenger()) {
i = MathHelper.d(this.tracker.yaw * 256.0F / 360.0F);
int j = MathHelper.d(this.tracker.pitch * 256.0F / 360.0F);
boolean flag = Math.abs(i - this.yRot) >= 1 || Math.abs(j - this.xRot) >= 1;
if (flag) {
this.broadcast(new PacketPlayOutEntity.PacketPlayOutEntityLook(this.tracker.getId(), (byte) i, (byte) j, this.tracker.onGround));
this.yRot = i;
this.xRot = j;
}
this.xLoc = EntityTracker.a(this.tracker.locX);
this.yLoc = EntityTracker.a(this.tracker.locY);
this.zLoc = EntityTracker.a(this.tracker.locZ);
this.d();
this.x = true;
} else {
++this.v;
long k = EntityTracker.a(this.tracker.locX);
long l = EntityTracker.a(this.tracker.locY);
long i1 = EntityTracker.a(this.tracker.locZ);
int j1 = MathHelper.d(this.tracker.yaw * 256.0F / 360.0F);
int k1 = MathHelper.d(this.tracker.pitch * 256.0F / 360.0F);
long l1 = k - this.xLoc;
long i2 = l - this.yLoc;
long j2 = i1 - this.zLoc;
Object object = null;
boolean flag1 = l1 * l1 + i2 * i2 + j2 * j2 >= 128L || this.a % 60 == 0;
boolean flag2 = Math.abs(j1 - this.yRot) >= 1 || Math.abs(k1 - this.xRot) >= 1;
if (this.a > 0 || this.tracker instanceof EntityArrow) { // Paper - Moved up
// CraftBukkit start - Code moved from below
if (flag1) {
this.xLoc = k;
this.yLoc = l;
this.zLoc = i1;
}
if (flag2) {
this.yRot = j1;
this.xRot = k1;
}
// CraftBukkit end
if (l1 >= -32768L && l1 < 32768L && i2 >= -32768L && i2 < 32768L && j2 >= -32768L && j2 < 32768L && this.v <= 400 && !this.x && this.y == this.tracker.onGround) {
if ((!flag1 || !flag2) && !(this.tracker instanceof EntityArrow)) {
if (flag1) {
object = new PacketPlayOutEntity.PacketPlayOutRelEntityMove(this.tracker.getId(), l1, i2, j2, this.tracker.onGround);
} else if (flag2) {
object = new PacketPlayOutEntity.PacketPlayOutEntityLook(this.tracker.getId(), (byte) j1, (byte) k1, this.tracker.onGround);
}
} else {
object = new PacketPlayOutEntity.PacketPlayOutRelEntityMoveLook(this.tracker.getId(), l1, i2, j2, (byte) j1, (byte) k1, this.tracker.onGround);
}
} else {
this.y = this.tracker.onGround;
this.v = 0;
// CraftBukkit start - Refresh list of who can see a player before sending teleport packet
if (this.tracker instanceof EntityPlayer) {
this.scanPlayers(new java.util.ArrayList(this.trackedPlayers));
}
// CraftBukkit end
this.c();
object = new PacketPlayOutEntityTeleport(this.tracker);
}
}
boolean flag3 = this.u;
if (this.tracker instanceof EntityLiving && ((EntityLiving) this.tracker).cP()) {
flag3 = true;
}
if (flag3 && this.a > 0) {
double d0 = this.tracker.motX - this.n;
double d1 = this.tracker.motY - this.o;
double d2 = this.tracker.motZ - this.p;
double d3 = 0.02D;
double d4 = d0 * d0 + d1 * d1 + d2 * d2;
if (d4 > 4.0E-4D || d4 > 0.0D && this.tracker.motX == 0.0D && this.tracker.motY == 0.0D && this.tracker.motZ == 0.0D) {
this.n = this.tracker.motX;
this.o = this.tracker.motY;
this.p = this.tracker.motZ;
this.broadcast(new PacketPlayOutEntityVelocity(this.tracker.getId(), this.n, this.o, this.p));
}
}
if (object != null) {
// Paper start - ensure fresh viewers get an absolute position on their first update,
// since we can't be certain what position they received in the spawn packet.
if (object instanceof PacketPlayOutEntityTeleport) {
this.broadcast((Packet) object);
} else {
PacketPlayOutEntityTeleport teleportPacket = null;
for (java.util.Map.Entry<EntityPlayer, Boolean> viewer : trackedPlayerMap.entrySet()) {
if (viewer.getValue()) {
viewer.setValue(false);
if (teleportPacket == null) {
teleportPacket = new PacketPlayOutEntityTeleport(this.tracker);
}
viewer.getKey().playerConnection.sendPacket(teleportPacket);
} else {
viewer.getKey().playerConnection.sendPacket((Packet) object);
}
}
}
// Paper end
}
this.d();
/* CraftBukkit start - Code moved up
if (flag1) {
this.xLoc = k;
this.yLoc = l;
this.zLoc = i1;
}
if (flag2) {
this.yRot = j1;
this.xRot = k1;
}
// CraftBukkit end */
this.x = false;
}
i = MathHelper.d(this.tracker.getHeadRotation() * 256.0F / 360.0F);
if (Math.abs(i - this.headYaw) >= 1) {
this.broadcast(new PacketPlayOutEntityHeadRotation(this.tracker, (byte) i));
this.headYaw = i;
}
this.tracker.impulse = false;
}
++this.a;
if (this.tracker.velocityChanged) {
// CraftBukkit start - Create PlayerVelocity event
boolean cancelled = false;
if (this.tracker instanceof EntityPlayer) {
Player player = (Player) this.tracker.getBukkitEntity();
org.bukkit.util.Vector velocity = player.getVelocity();
PlayerVelocityEvent event = new PlayerVelocityEvent(player, velocity.clone());
this.tracker.world.getServer().getPluginManager().callEvent(event);
if (event.isCancelled()) {
cancelled = true;
} else if (!velocity.equals(event.getVelocity())) {
player.setVelocity(event.getVelocity());
}
}
if (!cancelled) {
this.broadcastIncludingSelf(new PacketPlayOutEntityVelocity(this.tracker));
}
// CraftBukkit end
this.tracker.velocityChanged = false;
}
}
private void d() {
DataWatcher datawatcher = this.tracker.getDataWatcher();
if (datawatcher.a()) {
this.broadcastIncludingSelf(new PacketPlayOutEntityMetadata(this.tracker.getId(), datawatcher, false));
}
if (this.tracker instanceof EntityLiving) {
AttributeMapServer attributemapserver = (AttributeMapServer) ((EntityLiving) this.tracker).getAttributeMap();
Set set = attributemapserver.getAttributes();
if (!set.isEmpty()) {
// CraftBukkit start - Send scaled max health
if (this.tracker instanceof EntityPlayer) {
((EntityPlayer) this.tracker).getBukkitEntity().injectScaledMaxHealth(set, false);
}
// CraftBukkit end
this.broadcastIncludingSelf(new PacketPlayOutUpdateAttributes(this.tracker.getId(), set));
}
set.clear();
}
}
public void broadcast(Packet<?> packet) {
Iterator iterator = this.trackedPlayers.iterator();
while (iterator.hasNext()) {
EntityPlayer entityplayer = (EntityPlayer) iterator.next();
entityplayer.playerConnection.sendPacket(packet);
}
}
public void broadcastIncludingSelf(Packet<?> packet) {
this.broadcast(packet);
if (this.tracker instanceof EntityPlayer) {
((EntityPlayer) this.tracker).playerConnection.sendPacket(packet);
}
}
public void a() {
Iterator iterator = this.trackedPlayers.iterator();
while (iterator.hasNext()) {
EntityPlayer entityplayer = (EntityPlayer) iterator.next();
this.tracker.c(entityplayer);
entityplayer.c(this.tracker);
}
}
public void a(EntityPlayer entityplayer) {
if (this.trackedPlayers.contains(entityplayer)) {
this.tracker.c(entityplayer);
entityplayer.c(this.tracker);
this.trackedPlayers.remove(entityplayer);
}
}
public void updatePlayer(EntityPlayer entityplayer) {
org.spigotmc.AsyncCatcher.catchOp( "player tracker update"); // Spigot
if (entityplayer != this.tracker) {
if (this.c(entityplayer)) {
if (!this.trackedPlayers.contains(entityplayer) && (this.e(entityplayer) || this.tracker.attachedToPlayer)) {
// CraftBukkit start - respect vanish API
if (this.tracker instanceof EntityPlayer) {
Player player = ((EntityPlayer) this.tracker).getBukkitEntity();
if (!entityplayer.getBukkitEntity().canSee(player)) {
return;
}
}
entityplayer.removeQueue.remove(Integer.valueOf(this.tracker.getId()));
// CraftBukkit end
this.trackedPlayerMap.put(entityplayer, true); // Paper
Packet packet = this.e();
entityplayer.playerConnection.sendPacket(packet);
if (!this.tracker.getDataWatcher().d()) {
entityplayer.playerConnection.sendPacket(new PacketPlayOutEntityMetadata(this.tracker.getId(), this.tracker.getDataWatcher(), true));
}
boolean flag = this.u;
if (this.tracker instanceof EntityLiving) {
AttributeMapServer attributemapserver = (AttributeMapServer) ((EntityLiving) this.tracker).getAttributeMap();
Collection collection = attributemapserver.c();
// CraftBukkit start - If sending own attributes send scaled health instead of current maximum health
if (this.tracker.getId() == entityplayer.getId()) {
((EntityPlayer) this.tracker).getBukkitEntity().injectScaledMaxHealth(collection, false);
}
// CraftBukkit end
if (!collection.isEmpty()) {
entityplayer.playerConnection.sendPacket(new PacketPlayOutUpdateAttributes(this.tracker.getId(), collection));
}
if (((EntityLiving) this.tracker).cP()) {
flag = true;
}
}
this.n = this.tracker.motX;
this.o = this.tracker.motY;
this.p = this.tracker.motZ;
if (flag && !(packet instanceof PacketPlayOutSpawnEntityLiving)) {
entityplayer.playerConnection.sendPacket(new PacketPlayOutEntityVelocity(this.tracker.getId(), this.tracker.motX, this.tracker.motY, this.tracker.motZ));
}
if (this.tracker instanceof EntityLiving) {
EnumItemSlot[] aenumitemslot = EnumItemSlot.values();
int i = aenumitemslot.length;
for (int j = 0; j < i; ++j) {
EnumItemSlot enumitemslot = aenumitemslot[j];
ItemStack itemstack = ((EntityLiving) this.tracker).getEquipment(enumitemslot);
if (!itemstack.isEmpty()) {
entityplayer.playerConnection.sendPacket(new PacketPlayOutEntityEquipment(this.tracker.getId(), enumitemslot, itemstack));
}
}
}
if (this.tracker instanceof EntityHuman) {
EntityHuman entityhuman = (EntityHuman) this.tracker;
if (entityhuman.isSleeping()) {
entityplayer.playerConnection.sendPacket(new PacketPlayOutBed(entityhuman, new BlockPosition(this.tracker)));
}
}
if (this.tracker instanceof EntityLiving) {
// CraftBukkit start - Fix for nonsensical head yaw
this.headYaw = MathHelper.d(this.tracker.getHeadRotation() * 256.0F / 360.0F);
this.broadcast(new PacketPlayOutEntityHeadRotation(this.tracker, (byte) headYaw));
// CraftBukkit end
EntityLiving entityliving = (EntityLiving) this.tracker;
Iterator iterator = entityliving.getEffects().iterator();
while (iterator.hasNext()) {
MobEffect mobeffect = (MobEffect) iterator.next();
entityplayer.playerConnection.sendPacket(new PacketPlayOutEntityEffect(this.tracker.getId(), mobeffect));
}
}
if (!this.tracker.bF().isEmpty()) {
entityplayer.playerConnection.sendPacket(new PacketPlayOutMount(this.tracker));
}
if (this.tracker.isPassenger()) {
entityplayer.playerConnection.sendPacket(new PacketPlayOutMount(this.tracker.bJ()));
}
this.tracker.b(entityplayer);
entityplayer.d(this.tracker);
updatePassengers(entityplayer); // Paper
}
} else if (this.trackedPlayers.contains(entityplayer)) {
this.trackedPlayers.remove(entityplayer);
this.tracker.c(entityplayer);
entityplayer.c(this.tracker);
updatePassengers(entityplayer); // Paper
}
}
}
public boolean c(EntityPlayer entityplayer) {
// Paper start
if (tracker.isPassenger()) {
return isTrackedBy(tracker.getVehicle(), entityplayer);
} else if (hasPassengerInRange(tracker, entityplayer)) {
return true;
}
return isInRangeOfPlayer(entityplayer);
}
private static boolean hasPassengerInRange(Entity entity, EntityPlayer entityplayer) {
if (!entity.isVehicle()) {
return false;
}
for (Entity passenger : entity.passengers) {
if (passenger.tracker != null && passenger.tracker.isInRangeOfPlayer(entityplayer)) {
return true;
}
if (passenger.isVehicle()) {
if (hasPassengerInRange(passenger, entityplayer)) {
return true;
}
}
}
return false;
}
private static boolean isTrackedBy(Entity entity, EntityPlayer entityplayer) {
return entity == entityplayer || entity.tracker != null && entity.tracker.trackedPlayers.contains(entityplayer);
}
private void updatePassengers(EntityPlayer player) {
if (tracker.isVehicle()) {
tracker.passengers.forEach((e) -> {
if (e.tracker != null) {
e.tracker.updatePlayer(player);
}
});
player.playerConnection.sendPacket(new PacketPlayOutMount(this.tracker));
}
}
private boolean isInRangeOfPlayer(EntityPlayer entityplayer) {
// Paper end
double d0 = entityplayer.locX - (double) this.xLoc / 4096.0D;
double d1 = entityplayer.locZ - (double) this.zLoc / 4096.0D;
int i = Math.min(this.e, this.f);
return d0 >= (double) (-i) && d0 <= (double) i && d1 >= (double) (-i) && d1 <= (double) i && this.tracker.a(entityplayer);
}
private boolean e(EntityPlayer entityplayer) {
return entityplayer.x().getPlayerChunkMap().a(entityplayer, this.tracker.ab, this.tracker.ad);
}
public void scanPlayers(List<EntityHuman> list) {
for (int i = 0; i < list.size(); ++i) {
this.updatePlayer((EntityPlayer) list.get(i));
}
}
private Packet<?> e() {
if (this.tracker.dead) {
// CraftBukkit start - Remove useless error spam, just return
// EntityTrackerEntry.d.warn("Fetching addPacket for removed entity");
return null;
// CraftBukkit end
}
if (this.tracker instanceof EntityPlayer) {
return new PacketPlayOutNamedEntitySpawn((EntityHuman) this.tracker);
} else if (this.tracker instanceof IAnimal) {
this.headYaw = MathHelper.d(this.tracker.getHeadRotation() * 256.0F / 360.0F);
return new PacketPlayOutSpawnEntityLiving((EntityLiving) this.tracker);
} else if (this.tracker instanceof EntityPainting) {
return new PacketPlayOutSpawnEntityPainting((EntityPainting) this.tracker);
} else if (this.tracker instanceof EntityItem) {
return new PacketPlayOutSpawnEntity(this.tracker, 2, 1);
} else if (this.tracker instanceof EntityMinecartAbstract) {
EntityMinecartAbstract entityminecartabstract = (EntityMinecartAbstract) this.tracker;
return new PacketPlayOutSpawnEntity(this.tracker, 10, entityminecartabstract.v().a());
} else if (this.tracker instanceof EntityBoat) {
return new PacketPlayOutSpawnEntity(this.tracker, 1);
} else if (this.tracker instanceof EntityExperienceOrb) {
return new PacketPlayOutSpawnEntityExperienceOrb((EntityExperienceOrb) this.tracker);
} else if (this.tracker instanceof EntityFishingHook) {
EntityHuman entityhuman = ((EntityFishingHook) this.tracker).l();
return new PacketPlayOutSpawnEntity(this.tracker, 90, entityhuman == null ? this.tracker.getId() : entityhuman.getId());
} else {
Entity entity;
if (this.tracker instanceof EntitySpectralArrow) {
entity = ((EntitySpectralArrow) this.tracker).shooter;
return new PacketPlayOutSpawnEntity(this.tracker, 91, 1 + (entity == null ? this.tracker.getId() : entity.getId()));
} else if (this.tracker instanceof EntityTippedArrow) {
entity = ((EntityArrow) this.tracker).shooter;
return new PacketPlayOutSpawnEntity(this.tracker, 60, 1 + (entity == null ? this.tracker.getId() : entity.getId()));
} else if (this.tracker instanceof EntitySnowball) {
return new PacketPlayOutSpawnEntity(this.tracker, 61);
} else if (this.tracker instanceof EntityLlamaSpit) {
return new PacketPlayOutSpawnEntity(this.tracker, 68);
} else if (this.tracker instanceof EntityPotion) {
return new PacketPlayOutSpawnEntity(this.tracker, 73);
} else if (this.tracker instanceof EntityThrownExpBottle) {
return new PacketPlayOutSpawnEntity(this.tracker, 75);
} else if (this.tracker instanceof EntityEnderPearl) {
return new PacketPlayOutSpawnEntity(this.tracker, 65);
} else if (this.tracker instanceof EntityEnderSignal) {
return new PacketPlayOutSpawnEntity(this.tracker, 72);
} else if (this.tracker instanceof EntityFireworks) {
return new PacketPlayOutSpawnEntity(this.tracker, 76);
} else if (this.tracker instanceof EntityFireball) {
EntityFireball entityfireball = (EntityFireball) this.tracker;
PacketPlayOutSpawnEntity packetplayoutspawnentity = null;
byte b0 = 63;
if (this.tracker instanceof EntitySmallFireball) {
b0 = 64;
} else if (this.tracker instanceof EntityDragonFireball) {
b0 = 93;
} else if (this.tracker instanceof EntityWitherSkull) {
b0 = 66;
}
if (entityfireball.shooter != null) {
packetplayoutspawnentity = new PacketPlayOutSpawnEntity(this.tracker, b0, ((EntityFireball) this.tracker).shooter.getId());
} else {
packetplayoutspawnentity = new PacketPlayOutSpawnEntity(this.tracker, b0, 0);
}
packetplayoutspawnentity.a((int) (entityfireball.dirX * 8000.0D));
packetplayoutspawnentity.b((int) (entityfireball.dirY * 8000.0D));
packetplayoutspawnentity.c((int) (entityfireball.dirZ * 8000.0D));
return packetplayoutspawnentity;
} else if (this.tracker instanceof EntityShulkerBullet) {
PacketPlayOutSpawnEntity packetplayoutspawnentity1 = new PacketPlayOutSpawnEntity(this.tracker, 67, 0);
packetplayoutspawnentity1.a((int) (this.tracker.motX * 8000.0D));
packetplayoutspawnentity1.b((int) (this.tracker.motY * 8000.0D));
packetplayoutspawnentity1.c((int) (this.tracker.motZ * 8000.0D));
return packetplayoutspawnentity1;
} else if (this.tracker instanceof EntityEgg) {
return new PacketPlayOutSpawnEntity(this.tracker, 62);
} else if (this.tracker instanceof EntityEvokerFangs) {
return new PacketPlayOutSpawnEntity(this.tracker, 79);
} else if (this.tracker instanceof EntityTNTPrimed) {
return new PacketPlayOutSpawnEntity(this.tracker, 50);
} else if (this.tracker instanceof EntityEnderCrystal) {
return new PacketPlayOutSpawnEntity(this.tracker, 51);
} else if (this.tracker instanceof EntityFallingBlock) {
EntityFallingBlock entityfallingblock = (EntityFallingBlock) this.tracker;
return new PacketPlayOutSpawnEntity(this.tracker, 70, Block.getCombinedId(entityfallingblock.getBlock()));
} else if (this.tracker instanceof EntityArmorStand) {
return new PacketPlayOutSpawnEntity(this.tracker, 78);
} else if (this.tracker instanceof EntityItemFrame) {
EntityItemFrame entityitemframe = (EntityItemFrame) this.tracker;
return new PacketPlayOutSpawnEntity(this.tracker, 71, entityitemframe.direction.get2DRotationValue(), entityitemframe.getBlockPosition());
} else if (this.tracker instanceof EntityLeash) {
EntityLeash entityleash = (EntityLeash) this.tracker;
return new PacketPlayOutSpawnEntity(this.tracker, 77, 0, entityleash.getBlockPosition());
} else if (this.tracker instanceof EntityAreaEffectCloud) {
return new PacketPlayOutSpawnEntity(this.tracker, 3);
} else {
throw new IllegalArgumentException("Don\'t know how to add " + this.tracker.getClass() + "!");
}
}
}
public void clear(EntityPlayer entityplayer) {
org.spigotmc.AsyncCatcher.catchOp( "player tracker clear"); // Spigot
if (this.trackedPlayers.contains(entityplayer)) {
this.trackedPlayers.remove(entityplayer);
this.tracker.c(entityplayer);
entityplayer.c(this.tracker);
updatePassengers(entityplayer); // Paper
}
}
public Entity b() {
return this.tracker;
}
public void a(int i) {
this.f = i;
}
public void c() {
this.isMoving = false;
}
}

View File

@@ -0,0 +1,504 @@
package net.minecraft.server;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import it.unimi.dsi.fastutil.longs.LongOpenHashSet;
import javax.annotation.Nullable;
import java.util.*;
import java.util.function.Predicate;
// CraftBukkit start
import org.bukkit.craftbukkit.event.CraftEventFactory;
import org.bukkit.event.entity.EntityExplodeEvent;
import org.bukkit.Location;
import org.bukkit.event.block.BlockExplodeEvent;
// CraftBukkit end
public class Explosion {
private final boolean a;
private final boolean b;
private final Random c = new Random();
private final World world;
private final double posX;
private final double posY;
private final double posZ;
public final Entity source;
private final float size;
private final ArrayList<BlockPosition> blocks = Lists.newArrayList();
private final Map<EntityHuman, Vec3D> k = Maps.newHashMap();
public boolean wasCanceled = false; // CraftBukkit - add field
// Dionysus start
private final BlockPosition.MutableBlockPosition cachedPos = new BlockPosition.MutableBlockPosition();
// The chunk coordinate of the most recently stepped through block.
private int prevChunkX = Integer.MIN_VALUE;
private int prevChunkZ = Integer.MIN_VALUE;
// The chunk belonging to prevChunkPos.
private Chunk prevChunk;
private static final com.google.common.base.Predicate<Entity> hitPredicate = entity -> IEntitySelector.d.apply(entity) && !entity.dead; // Dionysus - Paper - don't hit dead entities
// Dionysus end
public Explosion(World world, Entity entity, double d0, double d1, double d2, float f, boolean flag, boolean flag1) {
this.world = world;
this.source = entity;
this.size = (float) Math.max(f, 0.0); // CraftBukkit - clamp bad values
this.posX = d0;
this.posY = d1;
this.posZ = d2;
this.a = flag;
this.b = flag1;
}
public void a() {
// CraftBukkit start
if (this.size < 0.1F) {
return;
}
// CraftBukkit end
// Dionysus start - optimize memory usage from explosions
// CaffeineMC optimized raytracing loop
// @author JellySquid
// @author nopjmp
// https://github.com/CaffeineMC/lithium-fabric
// Using integer encoding for the block positions provides a massive speedup and prevents us from needing to
// allocate a block position for every step we make along each ray, eliminating essentially all the memory
// allocations of this function. The overhead of packing block positions into integer format is negligible
// compared to a memory allocation and associated overhead of hashing real objects in a set.
final LongOpenHashSet touched = new LongOpenHashSet(0);
final Random random = this.world.random;
for (int rayX = 0; rayX < 16; ++rayX) {
boolean xPlane = rayX == 0 || rayX == 15;
double vecX = (((float) rayX / 15.0F) * 2.0F) - 1.0F;
for (int rayY = 0; rayY < 16; ++rayY) {
boolean yPlane = rayY == 0 || rayY == 15;
double vecY = (((float) rayY / 15.0F) * 2.0F) - 1.0F;
for (int rayZ = 0; rayZ < 16; ++rayZ) {
boolean zPlane = rayZ == 0 || rayZ == 15;
// We only fire rays from the surface of our origin volume
if (xPlane || yPlane || zPlane) {
double vecZ = (((float) rayZ / 15.0F) * 2.0F) - 1.0F;
this.performRayCast(random, vecX, vecY, vecZ, touched);
}
}
}
}
// We can now iterate back over the set of positions we modified and re-build BlockPos objects from them
// This will only allocate as many objects as there are in the set, where otherwise we would allocate them
// each step of a every ray.
blocks.ensureCapacity(touched.size());
for (Long longPos : touched) {
blocks.add(BlockPosition.fromLong(longPos));
}
float f3 = this.size * 2.0F;
int i = MathHelper.floor(this.posX - (double) f3 - 1.0D);
int j = MathHelper.floor(this.posX + (double) f3 + 1.0D);
int l = MathHelper.floor(this.posY - (double) f3 - 1.0D);
int i1 = MathHelper.floor(this.posY + (double) f3 + 1.0D);
int j1 = MathHelper.floor(this.posZ - (double) f3 - 1.0D);
int k1 = MathHelper.floor(this.posZ + (double) f3 + 1.0D);
// Paper start - Fix lag from explosions processing dead entities
List<Entity> list = this.world.getEntities(this.source, new AxisAlignedBB(i, l, j1, j, i1, k1), hitPredicate);
// Paper end
Vec3D vec3d = new Vec3D(this.posX, this.posY, this.posZ);
for (Entity entity : list) {
if (!entity.bB()) {
double d7 = entity.e(this.posX, this.posY, this.posZ) / (double) f3;
if (d7 <= 1.0D) {
double d8 = entity.locX - this.posX;
double d9 = entity.locY + (double) entity.getHeadHeight() - this.posY;
double d10 = entity.locZ - this.posZ;
double d11 = MathHelper.sqrt(d8 * d8 + d9 * d9 + d10 * d10);
if (d11 != 0.0D) {
d8 /= d11;
d9 /= d11;
d10 /= d11;
double d12 = this.getBlockDensity(vec3d, entity.getBoundingBox()); // Paper - Optimize explosions
double d13 = (1.0D - d7) * d12;
// CraftBukkit start
// entity.damageEntity(DamageSource.explosion(this), (float) ((int) ((d13 * d13 + d13) / 2.0D * 7.0D * (double) f3 + 1.0D)));
CraftEventFactory.entityDamage = source;
entity.forceExplosionKnockback = false;
boolean wasDamaged = entity.damageEntity(DamageSource.explosion(this), (float) ((int) ((d13 * d13 + d13) / 2.0D * 7.0D * (double) f3 + 1.0D)));
CraftEventFactory.entityDamage = null;
if (!wasDamaged && !(entity instanceof EntityTNTPrimed || entity instanceof EntityFallingBlock) && !entity.forceExplosionKnockback) {
continue;
}
// CraftBukkit end
double d14 = d13;
if (entity instanceof EntityLiving) {
d14 = entity instanceof EntityHuman && world.paperConfig.disableExplosionKnockback ? 0 : EnchantmentProtection.a((EntityLiving) entity, d13); // Paper - Disable explosion knockback
}
entity.motX += d8 * d14;
entity.motY += d9 * d14;
entity.motZ += d10 * d14;
if (entity instanceof EntityHuman) {
EntityHuman entityhuman = (EntityHuman) entity;
if (!entityhuman.isSpectator() && (!entityhuman.z() && !world.paperConfig.disableExplosionKnockback || !entityhuman.abilities.isFlying)) { // Paper - Disable explosion knockback
this.k.put(entityhuman, new Vec3D(d8 * d13, d9 * d13, d10 * d13));
}
}
}
}
}
}
}
private void performRayCast(Random random, double vecX, double vecY, double vecZ, LongOpenHashSet touched) {
double dist = Math.sqrt((vecX * vecX) + (vecY * vecY) + (vecZ * vecZ));
double normX = (vecX / dist) * 0.3D;
double normY = (vecY / dist) * 0.3D;
double normZ = (vecZ / dist) * 0.3D;
float strength = this.size * (0.7F + (random.nextFloat() * 0.6F));
double stepX = this.posX;
double stepY = this.posY;
double stepZ = this.posZ;
int prevX = Integer.MIN_VALUE;
int prevY = Integer.MIN_VALUE;
int prevZ = Integer.MIN_VALUE;
float prevResistance = 0.0F;
// Step through the ray until it is finally stopped
while (strength > 0.0F) {
int blockX = MathHelper.floor(stepX);
int blockY = MathHelper.floor(stepY);
int blockZ = MathHelper.floor(stepZ);
float resistance;
// Check whether or not we have actually moved into a new block this step. Due to how rays are stepped through,
// over-sampling of the same block positions will occur. Changing this behaviour would introduce differences in
// aliasing and sampling, which is unacceptable for our purposes. As a band-aid, we can simply re-use the
// previous result and get a decent boost.
if (prevX != blockX || prevY != blockY || prevZ != blockZ) {
resistance = this.traverseBlock(strength, blockX, blockY, blockZ, touched);
prevX = blockX;
prevY = blockY;
prevZ = blockZ;
prevResistance = resistance;
} else {
resistance = prevResistance;
}
strength -= resistance;
// Apply a constant fall-off
strength -= 0.22500001F;
stepX += normX;
stepY += normY;
stepZ += normZ;
}
}
/**
* Called for every step made by a ray being cast by an explosion.
*
* @param strength The strength of the ray during this step
* @param blockX The x-coordinate of the block the ray is inside of
* @param blockY The y-coordinate of the block the ray is inside of
* @param blockZ The z-coordinate of the block the ray is inside of
* @return The resistance of the current block space to the ray
*/
private float traverseBlock(float strength, int blockX, int blockY, int blockZ, LongOpenHashSet touched) {
cachedPos.c(blockX, blockY, blockZ);
IBlockData iblockdata = this.world.getType(cachedPos);
// Early-exit if the y-coordinate is out of bounds.
if (cachedPos.isInvalidYLocation()) {
if (iblockdata.getMaterial() != Material.AIR) {
float blastResistance = this.source != null ? this.source.a(this, this.world, cachedPos, iblockdata) : iblockdata.getBlock().a((Entity) null);
return (blastResistance + 0.3F) * 0.3F;
}
return 0.0F;
}
int chunkX = blockX >> 4;
int chunkZ = blockZ >> 4;
// Avoid calling into the chunk manager as much as possible through managing chunks locally
if (this.prevChunkX != chunkX || this.prevChunkZ != chunkZ) {
this.prevChunk = this.world.getChunkAt(chunkX, chunkZ);
this.prevChunkX = chunkX;
this.prevChunkZ = chunkZ;
}
final Chunk chunk = this.prevChunk;
float totalResistance = 0.0F;
Optional<Float> blastResistance = Optional.empty();
// If the chunk is missing or out of bounds, assume that it is air
if (chunk != null) {
// We operate directly on chunk sections to avoid interacting with BlockPos and to squeeze out as much
// performance as possible here
ChunkSection section = chunk.getSections()[blockY >> 4];
// If the section doesn't exist or it's empty, assume that the block is air
if (section != null && !section.a()) {
// Retrieve the block state from the chunk section directly to avoid associated overhead
IBlockData blockState = section.getType(blockX & 15, blockY & 15, blockZ & 15);
// If the block state is air, it cannot have fluid or any kind of resistance, so just leave
if (blockState.getBlock() != Blocks.AIR) {
// Get the explosion resistance like vanilla
blastResistance = Optional.of(this.source != null ? this.source.a(this, this.world, cachedPos, iblockdata) : iblockdata.getBlock().a((Entity) null));
}
}
}
// Calculate how much this block will resist an explosion's ray
if (blastResistance.isPresent()) {
totalResistance = (blastResistance.get() + 0.3F) * 0.3F;
}
// Check if this ray is still strong enough to break blocks, and if so, add this position to the set
// of positions to destroy
float reducedStrength = strength - totalResistance;
if (reducedStrength > 0.0F && (this.a || iblockdata.getMaterial() != Material.AIR)) {
if ((this.source == null || this.source.a(this, this.world, cachedPos, iblockdata, reducedStrength)) && cachedPos.getY() < 256 && cachedPos.getY() >= 0) {
touched.add(cachedPos.asLong());
}
}
return totalResistance;
}
// Dionysus end
public void a(boolean flag) {
this.world.a((EntityHuman) null, this.posX, this.posY, this.posZ, SoundEffects.bV, SoundCategory.BLOCKS, 4.0F, (1.0F + (this.world.random.nextFloat() - this.world.random.nextFloat()) * 0.2F) * 0.7F);
if (this.size >= 2.0F && this.b) {
this.world.addParticle(EnumParticle.EXPLOSION_HUGE, this.posX, this.posY, this.posZ, 1.0D, 0.0D, 0.0D);
} else {
this.world.addParticle(EnumParticle.EXPLOSION_LARGE, this.posX, this.posY, this.posZ, 1.0D, 0.0D, 0.0D);
}
Iterator iterator;
BlockPosition blockposition;
if (this.b) {
// CraftBukkit start
org.bukkit.World bworld = this.world.getWorld();
org.bukkit.entity.Entity explode = this.source == null ? null : this.source.getBukkitEntity();
Location location = new Location(bworld, this.posX, this.posY, this.posZ);
List<org.bukkit.block.Block> blockList = Lists.newArrayList();
for (int i1 = this.blocks.size() - 1; i1 >= 0; i1--) {
BlockPosition cpos = (BlockPosition) this.blocks.get(i1);
org.bukkit.block.Block bblock = bworld.getBlockAt(cpos.getX(), cpos.getY(), cpos.getZ());
if (bblock.getType() != org.bukkit.Material.AIR) {
blockList.add(bblock);
}
}
boolean cancelled;
List<org.bukkit.block.Block> bukkitBlocks;
float yield;
if (explode != null) {
EntityExplodeEvent event = new EntityExplodeEvent(explode, location, blockList, 1.0F / this.size);
this.world.getServer().getPluginManager().callEvent(event);
cancelled = event.isCancelled();
bukkitBlocks = event.blockList();
yield = event.getYield();
} else {
BlockExplodeEvent event = new BlockExplodeEvent(location.getBlock(), blockList, 1.0F / this.size);
this.world.getServer().getPluginManager().callEvent(event);
cancelled = event.isCancelled();
bukkitBlocks = event.blockList();
yield = event.getYield();
}
this.blocks.clear();
this.blocks.ensureCapacity(bukkitBlocks.size());
for (org.bukkit.block.Block bblock : bukkitBlocks) {
BlockPosition coords = new BlockPosition(bblock.getX(), bblock.getY(), bblock.getZ());
blocks.add(coords);
}
if (cancelled) {
this.wasCanceled = true;
return;
}
// CraftBukkit end
iterator = this.blocks.iterator();
while (iterator.hasNext()) {
blockposition = (BlockPosition) iterator.next();
IBlockData iblockdata = this.world.getType(blockposition);
Block block = iblockdata.getBlock();
this.world.chunkPacketBlockController.updateNearbyBlocks(this.world, blockposition); // Paper - Anti-Xray
if (flag) {
double d0 = (double) ((float) blockposition.getX() + this.world.random.nextFloat());
double d1 = (double) ((float) blockposition.getY() + this.world.random.nextFloat());
double d2 = (double) ((float) blockposition.getZ() + this.world.random.nextFloat());
double d3 = d0 - this.posX;
double d4 = d1 - this.posY;
double d5 = d2 - this.posZ;
double d6 = (double) MathHelper.sqrt(d3 * d3 + d4 * d4 + d5 * d5);
d3 /= d6;
d4 /= d6;
d5 /= d6;
double d7 = 0.5D / (d6 / (double) this.size + 0.1D);
d7 *= (double) (this.world.random.nextFloat() * this.world.random.nextFloat() + 0.3F);
d3 *= d7;
d4 *= d7;
d5 *= d7;
this.world.addParticle(EnumParticle.EXPLOSION_NORMAL, (d0 + this.posX) / 2.0D, (d1 + this.posY) / 2.0D, (d2 + this.posZ) / 2.0D, d3, d4, d5);
this.world.addParticle(EnumParticle.SMOKE_NORMAL, d0, d1, d2, d3, d4, d5);
}
if (iblockdata.getMaterial() != Material.AIR) {
if (block.a(this)) {
// CraftBukkit - add yield
block.dropNaturally(this.world, blockposition, this.world.getType(blockposition), yield, 0);
}
this.world.setTypeAndData(blockposition, Blocks.AIR.getBlockData(), 3);
block.wasExploded(this.world, blockposition, this);
}
}
}
if (this.a) {
iterator = this.blocks.iterator();
while (iterator.hasNext()) {
blockposition = (BlockPosition) iterator.next();
if (this.world.getType(blockposition).getMaterial() == Material.AIR && this.world.getType(blockposition.down()).b() && this.c.nextInt(3) == 0) {
// CraftBukkit start - Ignition by explosion
if (!CraftEventFactory.callBlockIgniteEvent(this.world, blockposition.getX(), blockposition.getY(), blockposition.getZ(), this).isCancelled()) {
this.world.setTypeUpdate(blockposition, Blocks.FIRE.getBlockData());
}
// CraftBukkit end
}
}
}
}
public Map<EntityHuman, Vec3D> b() {
return this.k;
}
@Nullable
public EntityLiving getSource() {
// CraftBukkit start - obtain Fireball shooter for explosion tracking
return this.source == null ? null : (this.source instanceof EntityTNTPrimed ? ((EntityTNTPrimed) this.source).getSource() : (this.source instanceof EntityLiving ? (EntityLiving) this.source : (this.source instanceof EntityFireball ? ((EntityFireball) this.source).shooter : null)));
// CraftBukkit end
}
public void clearBlocks() {
this.blocks.clear();
}
public List<BlockPosition> getBlocks() {
return this.blocks;
}
// Paper start - Optimize explosions
private float getBlockDensity(Vec3D vec3d, AxisAlignedBB aabb) {
if (!this.world.paperConfig.optimizeExplosions) {
return this.world.a(vec3d, aabb);
}
CacheKey key = new CacheKey(this, aabb);
return this.world.explosionDensityCache.computeIfAbsent(key, k1 -> this.world.a(vec3d, aabb));
}
static class CacheKey {
private final World world;
private final double posX, posY, posZ;
private final double minX, minY, minZ;
private final double maxX, maxY, maxZ;
public CacheKey(Explosion explosion, AxisAlignedBB aabb) {
this.world = explosion.world;
this.posX = explosion.posX;
this.posY = explosion.posY;
this.posZ = explosion.posZ;
this.minX = aabb.a;
this.minY = aabb.b;
this.minZ = aabb.c;
this.maxX = aabb.d;
this.maxY = aabb.e;
this.maxZ = aabb.f;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
CacheKey cacheKey = (CacheKey) o;
if (Double.compare(cacheKey.posX, posX) != 0) return false;
if (Double.compare(cacheKey.posY, posY) != 0) return false;
if (Double.compare(cacheKey.posZ, posZ) != 0) return false;
if (Double.compare(cacheKey.minX, minX) != 0) return false;
if (Double.compare(cacheKey.minY, minY) != 0) return false;
if (Double.compare(cacheKey.minZ, minZ) != 0) return false;
if (Double.compare(cacheKey.maxX, maxX) != 0) return false;
if (Double.compare(cacheKey.maxY, maxY) != 0) return false;
if (Double.compare(cacheKey.maxZ, maxZ) != 0) return false;
return world.equals(cacheKey.world);
}
@Override
public int hashCode() {
int result;
long temp;
result = world.hashCode();
temp = Double.doubleToLongBits(posX);
result = 31 * result + (int) (temp ^ (temp >>> 32));
temp = Double.doubleToLongBits(posY);
result = 31 * result + (int) (temp ^ (temp >>> 32));
temp = Double.doubleToLongBits(posZ);
result = 31 * result + (int) (temp ^ (temp >>> 32));
temp = Double.doubleToLongBits(minX);
result = 31 * result + (int) (temp ^ (temp >>> 32));
temp = Double.doubleToLongBits(minY);
result = 31 * result + (int) (temp ^ (temp >>> 32));
temp = Double.doubleToLongBits(minZ);
result = 31 * result + (int) (temp ^ (temp >>> 32));
temp = Double.doubleToLongBits(maxX);
result = 31 * result + (int) (temp ^ (temp >>> 32));
temp = Double.doubleToLongBits(maxY);
result = 31 * result + (int) (temp ^ (temp >>> 32));
temp = Double.doubleToLongBits(maxZ);
result = 31 * result + (int) (temp ^ (temp >>> 32));
return result;
}
}
// Paper end
}

View File

@@ -0,0 +1,113 @@
package net.minecraft.server;
// NeonPaper start
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
import java.lang.ref.WeakReference;
import java.util.Iterator;
import java.util.List;
// NeonPaper end
public class IntCache {
// NeonPaper start - Refactored IntCache to be thread local instead of static
private static final ThreadLocal<IntCache> caches = new ThreadLocal<IntCache>() {
@Override
protected IntCache initialValue() {
IntCache cache = new IntCache();
synchronized (ALL_CACHES) {
ALL_CACHES.add(new WeakReference<>(cache));
}
return new IntCache();
}
};
private static final List<WeakReference<IntCache>> ALL_CACHES = new ObjectArrayList<>();
private int a = 256;
private final List<int[]> b = new ObjectArrayList<>();
private final List<int[]> c = new ObjectArrayList<>();
private final List<int[]> d = new ObjectArrayList<>();
private final List<int[]> e = new ObjectArrayList<>();
private final int cacheLimit = org.spigotmc.SpigotConfig.intCacheLimit;
public static int[] a(int i) {
return caches.get().aNonStatic(i);
}
public int[] aNonStatic(int i) {
int[] aint;
if (i <= 256) {
if (this.b.isEmpty()) {
aint = new int[256];
if (c.size() < cacheLimit) this.c.add(aint);
return aint;
} else {
aint = this.b.remove(this.b.size() - 1);
if (c.size() < cacheLimit) this.c.add(aint);
return aint;
}
} else if (i > this.a) {
this.a = i;
this.d.clear();
this.e.clear();
aint = new int[this.a];
if (e.size() < cacheLimit) this.e.add(aint);
return aint;
} else if (this.d.isEmpty()) {
aint = new int[this.a];
if (e.size() < cacheLimit) this.e.add(aint);
return aint;
} else {
aint = this.d.remove(this.d.size() - 1);
if (e.size() < cacheLimit) this.e.add(aint);
return aint;
}
}
public static void a() {
caches.get().aNonStatic();
}
public void aNonStatic() {
if (!this.d.isEmpty()) {
this.d.remove(this.d.size() - 1);
}
if (!this.b.isEmpty()) {
this.b.remove(this.b.size() - 1);
}
this.d.addAll(this.e);
this.b.addAll(this.c);
this.e.clear();
this.c.clear();
}
public static String b() {
int cache = 0;
int tcache = 0;
int allocated = 0;
int tallocated = 0;
int numberOfCaches;
synchronized (ALL_CACHES) {
numberOfCaches = ALL_CACHES.size();
Iterator<WeakReference<IntCache>> iter = ALL_CACHES.iterator();
while (iter.hasNext()) {
WeakReference<IntCache> reference = iter.next();
IntCache intcache = reference.get();
if (intcache != null) {
cache += intcache.d.size();
tcache += intcache.b.size();
allocated += intcache.e.size();
tallocated += intcache.c.size();
} else {
iter.remove();
}
}
}
return numberOfCaches + " IntCaches. In Total => cache: " + cache + ", tcache: " + tcache + ", allocated: " + allocated + ", tallocated: " + tallocated;
}
// NeonPaper end
}

View File

@@ -0,0 +1,367 @@
package net.minecraft.server;
import com.google.common.collect.HashMultiset;
import com.google.common.collect.Iterables;
import com.google.common.collect.Multisets;
import javax.annotation.Nullable;
// CraftBukkit start
import org.bukkit.Bukkit;
import org.bukkit.event.server.MapInitializeEvent;
// CraftBukkit end
public class ItemWorldMap extends ItemWorldMapBase {
protected ItemWorldMap() {
this.a(true);
}
public static ItemStack a(World world, double d0, double d1, byte b0, boolean flag, boolean flag1) {
World worldMain = world.getServer().getServer().worlds.get(0); // CraftBukkit - store reference to primary world
ItemStack itemstack = new ItemStack(Items.FILLED_MAP, 1, worldMain.b("map")); // CraftBukkit - use primary world for maps
String s = "map_" + itemstack.getData();
WorldMap worldmap = new WorldMap(s);
worldMain.a(s, (PersistentBase) worldmap); // CraftBukkit
worldmap.scale = b0;
worldmap.a(d0, d1, worldmap.scale);
worldmap.map = (byte) ((WorldServer) world).dimension; // CraftBukkit - use bukkit dimension
worldmap.track = flag;
worldmap.unlimitedTracking = flag1;
worldmap.c();
org.bukkit.craftbukkit.event.CraftEventFactory.callEvent(new org.bukkit.event.server.MapInitializeEvent(worldmap.mapView)); // CraftBukkit
return itemstack;
}
@Nullable
public WorldMap getSavedMap(ItemStack itemstack, World world) {
World worldMain = world.getServer().getServer().worlds.get(0); // CraftBukkit - store reference to primary world
String s = "map_" + itemstack.getData();
WorldMap worldmap = (WorldMap) worldMain.a(WorldMap.class, s); // CraftBukkit - use primary world for maps
if (worldmap == null && !world.isClientSide) {
itemstack.setData(worldMain.b("map")); // CraftBukkit - use primary world for maps
s = "map_" + itemstack.getData();
worldmap = new WorldMap(s);
worldmap.scale = 3;
worldmap.a((double) world.getWorldData().b(), (double) world.getWorldData().d(), worldmap.scale);
worldmap.map = (byte) ((WorldServer) world).dimension; // CraftBukkit - fixes Bukkit multiworld maps
worldmap.c();
worldMain.a(s, (PersistentBase) worldmap); // CraftBukkit - use primary world for maps
// CraftBukkit start
MapInitializeEvent event = new MapInitializeEvent(worldmap.mapView);
Bukkit.getServer().getPluginManager().callEvent(event);
// CraftBukkit end
}
return worldmap;
}
public void a(World world, Entity entity, WorldMap worldmap) {
// CraftBukkit - world.worldProvider -> ((WorldServer) world)
if (((WorldServer) world).dimension == worldmap.map && entity instanceof EntityHuman) {
int i = 1 << worldmap.scale;
int j = worldmap.centerX;
int k = worldmap.centerZ;
int l = MathHelper.floor(entity.locX - (double) j) / i + 64;
int i1 = MathHelper.floor(entity.locZ - (double) k) / i + 64;
int j1 = 128 / i;
if (world.worldProvider.n()) {
j1 /= 2;
}
WorldMap.WorldMapHumanTracker worldmap_worldmaphumantracker = worldmap.a((EntityHuman) entity);
++worldmap_worldmaphumantracker.b;
boolean flag = false;
for (int k1 = l - j1 + 1; k1 < l + j1; ++k1) {
if ((k1 & 15) == (worldmap_worldmaphumantracker.b & 15) || flag) {
flag = false;
double d0 = 0.0D;
for (int l1 = i1 - j1 - 1; l1 < i1 + j1; ++l1) {
if (k1 >= 0 && l1 >= -1 && k1 < 128 && l1 < 128) {
int i2 = k1 - l;
int j2 = l1 - i1;
boolean flag1 = i2 * i2 + j2 * j2 > (j1 - 2) * (j1 - 2);
int k2 = (j / i + k1 - 64) * i;
int l2 = (k / i + l1 - 64) * i;
HashMultiset hashmultiset = HashMultiset.create();
Chunk chunk = world.getChunkIfLoaded(new BlockPosition(k2, 0, l2)); // NeonPaper - Maps shouldn't load chunks
if (chunk != null && !chunk.isEmpty()) { // NeonPaper - Maps shouldn't load chunks
int i3 = k2 & 15;
int j3 = l2 & 15;
int k3 = 0;
double d1 = 0.0D;
if (world.worldProvider.n()) {
int l3 = k2 + l2 * 231871;
l3 = l3 * l3 * 31287121 + l3 * 11;
if ((l3 >> 20 & 1) == 0) {
hashmultiset.add(Blocks.DIRT.getBlockData().set(BlockDirt.VARIANT, BlockDirt.EnumDirtVariant.DIRT).a((IBlockAccess) world, BlockPosition.ZERO), 10);
} else {
hashmultiset.add(Blocks.STONE.getBlockData().set(BlockStone.VARIANT, BlockStone.EnumStoneVariant.STONE).a((IBlockAccess) world, BlockPosition.ZERO), 100);
}
d1 = 100.0D;
} else {
BlockPosition.MutableBlockPosition blockposition_mutableblockposition = new BlockPosition.MutableBlockPosition();
for (int i4 = 0; i4 < i; ++i4) {
for (int j4 = 0; j4 < i; ++j4) {
int k4 = chunk.b(i4 + i3, j4 + j3) + 1;
IBlockData iblockdata = Blocks.AIR.getBlockData();
if (k4 > 1) {
do {
--k4;
iblockdata = chunk.a(i4 + i3, k4, j4 + j3);
blockposition_mutableblockposition.c((chunk.locX << 4) + i4 + i3, k4, (chunk.locZ << 4) + j4 + j3);
} while (iblockdata.a((IBlockAccess) world, blockposition_mutableblockposition) == MaterialMapColor.c && k4 > 0);
if (k4 > 0 && iblockdata.getMaterial().isLiquid()) {
int l4 = k4 - 1;
IBlockData iblockdata1;
do {
iblockdata1 = chunk.a(i4 + i3, l4--, j4 + j3);
++k3;
} while (l4 > 0 && iblockdata1.getMaterial().isLiquid());
}
} else {
iblockdata = Blocks.BEDROCK.getBlockData();
}
d1 += (double) k4 / (double) (i * i);
hashmultiset.add(iblockdata.a((IBlockAccess) world, blockposition_mutableblockposition));
}
}
}
k3 /= i * i;
double d2 = (d1 - d0) * 4.0D / (double) (i + 4) + ((double) (k1 + l1 & 1) - 0.5D) * 0.4D;
byte b0 = 1;
if (d2 > 0.6D) {
b0 = 2;
}
if (d2 < -0.6D) {
b0 = 0;
}
MaterialMapColor materialmapcolor = (MaterialMapColor) Iterables.getFirst(Multisets.copyHighestCountFirst(hashmultiset), MaterialMapColor.c);
if (materialmapcolor == MaterialMapColor.o) {
d2 = (double) k3 * 0.1D + (double) (k1 + l1 & 1) * 0.2D;
b0 = 1;
if (d2 < 0.5D) {
b0 = 2;
}
if (d2 > 0.9D) {
b0 = 0;
}
}
d0 = d1;
if (l1 >= 0 && i2 * i2 + j2 * j2 < j1 * j1 && (!flag1 || (k1 + l1 & 1) != 0)) {
byte b1 = worldmap.colors[k1 + l1 * 128];
byte b2 = (byte) (materialmapcolor.ad * 4 + b0);
if (b1 != b2) {
worldmap.colors[k1 + l1 * 128] = b2;
worldmap.flagDirty(k1, l1);
flag = true;
}
}
}
}
}
}
}
}
}
public static void a(World world, ItemStack itemstack) {
if (itemstack.getItem() == Items.FILLED_MAP) {
WorldMap worldmap = Items.FILLED_MAP.getSavedMap(itemstack, world);
if (worldmap != null) {
if (world.worldProvider.getDimensionManager().getDimensionID() == worldmap.map) {
int i = 1 << worldmap.scale;
int j = worldmap.centerX;
int k = worldmap.centerZ;
BiomeBase[] abiomebase = world.getWorldChunkManager().a((BiomeBase[]) null, (j / i - 64) * i, (k / i - 64) * i, 128 * i, 128 * i, false);
for (int l = 0; l < 128; ++l) {
for (int i1 = 0; i1 < 128; ++i1) {
int j1 = l * i;
int k1 = i1 * i;
BiomeBase biomebase = abiomebase[j1 + k1 * 128 * i];
MaterialMapColor materialmapcolor = MaterialMapColor.c;
int l1 = 3;
int i2 = 8;
if (l > 0 && i1 > 0 && l < 127 && i1 < 127) {
if (abiomebase[(l - 1) * i + (i1 - 1) * i * 128 * i].j() >= 0.0F) {
--i2;
}
if (abiomebase[(l - 1) * i + (i1 + 1) * i * 128 * i].j() >= 0.0F) {
--i2;
}
if (abiomebase[(l - 1) * i + i1 * i * 128 * i].j() >= 0.0F) {
--i2;
}
if (abiomebase[(l + 1) * i + (i1 - 1) * i * 128 * i].j() >= 0.0F) {
--i2;
}
if (abiomebase[(l + 1) * i + (i1 + 1) * i * 128 * i].j() >= 0.0F) {
--i2;
}
if (abiomebase[(l + 1) * i + i1 * i * 128 * i].j() >= 0.0F) {
--i2;
}
if (abiomebase[l * i + (i1 - 1) * i * 128 * i].j() >= 0.0F) {
--i2;
}
if (abiomebase[l * i + (i1 + 1) * i * 128 * i].j() >= 0.0F) {
--i2;
}
if (biomebase.j() < 0.0F) {
materialmapcolor = MaterialMapColor.r;
if (i2 > 7 && i1 % 2 == 0) {
l1 = (l + (int) (MathHelper.sin((float) i1 + 0.0F) * 7.0F)) / 8 % 5;
if (l1 == 3) {
l1 = 1;
} else if (l1 == 4) {
l1 = 0;
}
} else if (i2 > 7) {
materialmapcolor = MaterialMapColor.c;
} else if (i2 > 5) {
l1 = 1;
} else if (i2 > 3) {
l1 = 0;
} else if (i2 > 1) {
l1 = 0;
}
} else if (i2 > 0) {
materialmapcolor = MaterialMapColor.C;
if (i2 > 3) {
l1 = 1;
} else {
l1 = 3;
}
}
}
if (materialmapcolor != MaterialMapColor.c) {
worldmap.colors[l + i1 * 128] = (byte) (materialmapcolor.ad * 4 + l1);
worldmap.flagDirty(l, i1);
}
}
}
}
}
}
}
public void a(ItemStack itemstack, World world, Entity entity, int i, boolean flag) {
if (!world.isClientSide) {
WorldMap worldmap = this.getSavedMap(itemstack, world);
if (entity instanceof EntityHuman) {
EntityHuman entityhuman = (EntityHuman) entity;
worldmap.a(entityhuman, itemstack);
}
if (flag || entity instanceof EntityHuman && ((EntityHuman) entity).getItemInOffHand() == itemstack) {
this.a(world, entity, worldmap);
}
}
}
@Nullable
public Packet<?> a(ItemStack itemstack, World world, EntityHuman entityhuman) {
return this.getSavedMap(itemstack, world).a(itemstack, world, entityhuman);
}
public void b(ItemStack itemstack, World world, EntityHuman entityhuman) {
NBTTagCompound nbttagcompound = itemstack.getTag();
if (nbttagcompound != null) {
if (nbttagcompound.hasKeyOfType("map_scale_direction", 99)) {
a(itemstack, world, nbttagcompound.getInt("map_scale_direction"));
nbttagcompound.remove("map_scale_direction");
} else if (nbttagcompound.getBoolean("map_tracking_position")) {
b(itemstack, world);
nbttagcompound.remove("map_tracking_position");
}
}
}
protected static void a(ItemStack itemstack, World world, int i) {
WorldMap worldmap = Items.FILLED_MAP.getSavedMap(itemstack, world);
world = world.getServer().getServer().worlds.get(0); // CraftBukkit - use primary world for maps
itemstack.setData(world.b("map"));
WorldMap worldmap1 = new WorldMap("map_" + itemstack.getData());
if (worldmap != null) {
worldmap1.scale = (byte) MathHelper.clamp(worldmap.scale + i, 0, 4);
worldmap1.track = worldmap.track;
worldmap1.a((double) worldmap.centerX, (double) worldmap.centerZ, worldmap1.scale);
worldmap1.map = worldmap.map;
worldmap1.c();
world.a("map_" + itemstack.getData(), (PersistentBase) worldmap1);
// CraftBukkit start
MapInitializeEvent event = new MapInitializeEvent(worldmap1.mapView);
Bukkit.getServer().getPluginManager().callEvent(event);
// CraftBukkit end
}
}
protected static void b(ItemStack itemstack, World world) {
WorldMap worldmap = Items.FILLED_MAP.getSavedMap(itemstack, world);
world = world.getServer().getServer().worlds.get(0); // CraftBukkit - use primary world for maps
itemstack.setData(world.b("map"));
WorldMap worldmap1 = new WorldMap("map_" + itemstack.getData());
worldmap1.track = true;
if (worldmap != null) {
worldmap1.centerX = worldmap.centerX;
worldmap1.centerZ = worldmap.centerZ;
worldmap1.scale = worldmap.scale;
worldmap1.map = worldmap.map;
worldmap1.c();
world.a("map_" + itemstack.getData(), (PersistentBase) worldmap1);
// CraftBukkit start
MapInitializeEvent event = new MapInitializeEvent(worldmap1.mapView);
Bukkit.getServer().getPluginManager().callEvent(event);
// CraftBukkit end
}
}
}

View File

@@ -365,7 +365,10 @@ public class NetworkManager extends SimpleChannelInboundHandler<Packet<?>> {
@Override @Override
protected void channelRead0(ChannelHandlerContext channelhandlercontext, Packet object) throws Exception { // CraftBukkit - fix decompile error protected void channelRead0(ChannelHandlerContext channelhandlercontext, Packet object) throws Exception { // CraftBukkit - fix decompile error
this.a(channelhandlercontext, object); // FlamePaper - Check if channel is opened before reading packet
if (isConnected()) {
this.a(channelhandlercontext, object);
}
} }
public static class QueuedPacket { // Akarin - default -> public public static class QueuedPacket { // Akarin - default -> public

View File

@@ -916,6 +916,11 @@ public class PlayerConnection implements PacketListenerPlayIn, ITickable {
case START_DESTROY_BLOCK: case START_DESTROY_BLOCK:
case ABORT_DESTROY_BLOCK: case ABORT_DESTROY_BLOCK:
case STOP_DESTROY_BLOCK: case STOP_DESTROY_BLOCK:
// NeonPaper start - Don't allow digging in unloaded chunks
if (!worldserver.isChunkLoaded(blockposition.getX() >> 4, blockposition.getZ() >> 4, true)) {
return;
}
// NeonPaper end - Don't allow digging in unloaded chunks
double d0 = this.player.locX - ((double) blockposition.getX() + 0.5D); double d0 = this.player.locX - ((double) blockposition.getX() + 0.5D);
double d1 = this.player.locY - ((double) blockposition.getY() + 0.5D) + 1.5D; double d1 = this.player.locY - ((double) blockposition.getY() + 0.5D) + 1.5D;
double d2 = this.player.locZ - ((double) blockposition.getZ() + 0.5D); double d2 = this.player.locZ - ((double) blockposition.getZ() + 0.5D);

View File

@@ -0,0 +1,568 @@
package net.minecraft.server;
// CraftBukkit start
import java.util.ArrayList;
import org.bukkit.event.block.BlockBreakEvent;
import org.bukkit.craftbukkit.event.CraftEventFactory;
import org.bukkit.event.Event;
import org.bukkit.event.block.Action;
import org.bukkit.event.player.PlayerInteractEvent;
// CraftBukkit end
public class PlayerInteractManager {
public World world;
public EntityPlayer player;
private EnumGamemode gamemode;
private boolean d;
private int lastDigTick;
private BlockPosition f;
private int currentTick;
private boolean h;
private BlockPosition i;
private int j;
private int k;
public PlayerInteractManager(World world) {
this.gamemode = EnumGamemode.NOT_SET;
this.f = BlockPosition.ZERO;
this.i = BlockPosition.ZERO;
this.k = -1;
this.world = world;
}
public void setGameMode(EnumGamemode enumgamemode) {
this.gamemode = enumgamemode;
enumgamemode.a(this.player.abilities);
this.player.updateAbilities();
this.player.server.getPlayerList().sendAll(new PacketPlayOutPlayerInfo(PacketPlayOutPlayerInfo.EnumPlayerInfoAction.UPDATE_GAME_MODE, new EntityPlayer[] { this.player}), this.player); // CraftBukkit
this.world.everyoneSleeping();
}
public EnumGamemode getGameMode() {
return this.gamemode;
}
public boolean c() {
return this.gamemode.e();
}
public boolean isCreative() {
return this.gamemode.isCreative();
}
public void b(EnumGamemode enumgamemode) {
if (this.gamemode == EnumGamemode.NOT_SET) {
this.gamemode = enumgamemode;
}
this.setGameMode(this.gamemode);
}
public void a() {
this.currentTick = MinecraftServer.currentTick; // CraftBukkit;
float f;
int i;
if (this.h) {
int j = this.currentTick - this.j;
IBlockData iblockdata = this.world.getType(this.i);
if (iblockdata.getMaterial() == Material.AIR) {
this.h = false;
} else {
f = iblockdata.a((EntityHuman) this.player, this.player.world, this.i) * (float) (j + 1);
i = (int) (f * 10.0F);
if (i != this.k) {
this.world.c(this.player.getId(), this.i, i);
this.k = i;
}
if (f >= 1.0F) {
this.h = false;
this.breakBlock(this.i);
}
}
} else if (this.d) {
IBlockData iblockdata1 = this.world.getType(this.f);
if (iblockdata1.getMaterial() == Material.AIR) {
this.world.c(this.player.getId(), this.f, -1);
this.k = -1;
this.d = false;
} else {
int k = this.currentTick - this.lastDigTick;
f = iblockdata1.a((EntityHuman) this.player, this.player.world, this.i) * (float) (k + 1);
i = (int) (f * 10.0F);
if (i != this.k) {
this.world.c(this.player.getId(), this.f, i);
this.k = i;
}
}
}
}
public void a(BlockPosition blockposition, EnumDirection enumdirection) {
// CraftBukkit start
PlayerInteractEvent event = CraftEventFactory.callPlayerInteractEvent(this.player, Action.LEFT_CLICK_BLOCK, blockposition, enumdirection, this.player.inventory.getItemInHand(), EnumHand.MAIN_HAND);
if (event.isCancelled()) {
// Let the client know the block still exists
((EntityPlayer) this.player).playerConnection.sendPacket(new PacketPlayOutBlockChange(this.world, blockposition));
cancelBreakBlock(blockposition, this.world.getType(blockposition)); // Paper - Avoid visual issues on the client
// Update any tile entity data for this block
TileEntity tileentity = this.world.getTileEntity(blockposition);
if (tileentity != null) {
this.player.playerConnection.sendPacket(tileentity.getUpdatePacket());
}
return;
}
// CraftBukkit end
if (this.isCreative()) {
if (!this.world.douseFire((EntityHuman) null, blockposition, enumdirection)) {
this.breakBlock(blockposition);
}
} else {
IBlockData iblockdata = this.world.getType(blockposition);
Block block = iblockdata.getBlock();
if (this.gamemode.c()) {
if (this.gamemode == EnumGamemode.SPECTATOR) {
return;
}
if (!this.player.dk()) {
ItemStack itemstack = this.player.getItemInMainHand();
if (itemstack.isEmpty()) {
return;
}
if (!itemstack.a(block)) {
return;
}
}
}
// this.world.douseFire((EntityHuman) null, blockposition, enumdirection); // CraftBukkit - Moved down
this.lastDigTick = this.currentTick;
float f = 1.0F;
// CraftBukkit start - Swings at air do *NOT* exist.
if (event.useInteractedBlock() == Event.Result.DENY) {
// If we denied a door from opening, we need to send a correcting update to the client, as it already opened the door.
IBlockData data = this.world.getType(blockposition);
if (block == Blocks.WOODEN_DOOR) {
// For some reason *BOTH* the bottom/top part have to be marked updated.
boolean bottom = data.get(BlockDoor.HALF) == BlockDoor.EnumDoorHalf.LOWER;
((EntityPlayer) this.player).playerConnection.sendPacket(new PacketPlayOutBlockChange(this.world, blockposition));
((EntityPlayer) this.player).playerConnection.sendPacket(new PacketPlayOutBlockChange(this.world, bottom ? blockposition.up() : blockposition.down()));
} else if (block == Blocks.TRAPDOOR) {
((EntityPlayer) this.player).playerConnection.sendPacket(new PacketPlayOutBlockChange(this.world, blockposition));
}
} else if (iblockdata.getMaterial() != Material.AIR) {
block.attack(this.world, blockposition, this.player);
f = iblockdata.a((EntityHuman) this.player, this.player.world, blockposition);
// Allow fire punching to be blocked
this.world.douseFire((EntityHuman) null, blockposition, enumdirection);
}
if (event.useItemInHand() == Event.Result.DENY) {
// If we 'insta destroyed' then the client needs to be informed.
if (f > 1.0f) {
((EntityPlayer) this.player).playerConnection.sendPacket(new PacketPlayOutBlockChange(this.world, blockposition));
}
return;
}
org.bukkit.event.block.BlockDamageEvent blockEvent = CraftEventFactory.callBlockDamageEvent(this.player, blockposition.getX(), blockposition.getY(), blockposition.getZ(), this.player.inventory.getItemInHand(), f >= 1.0f);
if (blockEvent.isCancelled()) {
// Let the client know the block still exists
((EntityPlayer) this.player).playerConnection.sendPacket(new PacketPlayOutBlockChange(this.world, blockposition));
return;
}
if (blockEvent.getInstaBreak()) {
f = 2.0f;
}
// CraftBukkit end
if (iblockdata.getMaterial() != Material.AIR && f >= 1.0F) {
this.breakBlock(blockposition);
} else {
this.d = true;
this.f = blockposition;
int i = (int) (f * 10.0F);
this.world.c(this.player.getId(), blockposition, i);
this.player.playerConnection.sendPacket(new PacketPlayOutBlockChange(world, blockposition)); // Paper - MC-54026 - backport from 1.13
this.k = i;
}
}
this.world.chunkPacketBlockController.updateNearbyBlocks(this.world, blockposition); // Paper - Anti-Xray
}
public void a(BlockPosition blockposition) {
if (blockposition.equals(this.f)) {
this.currentTick = MinecraftServer.currentTick; // CraftBukkit
int i = this.currentTick - this.lastDigTick;
IBlockData iblockdata = this.world.getType(blockposition);
if (iblockdata.getMaterial() != Material.AIR) {
float f = iblockdata.a((EntityHuman) this.player, this.player.world, blockposition) * (float) (i + 1);
if (f >= 0.7F) {
this.d = false;
this.world.c(this.player.getId(), blockposition, -1);
this.breakBlock(blockposition);
} else if (!this.h) {
this.d = false;
this.h = true;
this.i = blockposition;
this.j = this.lastDigTick;
}
}
// CraftBukkit start - Force block reset to client
} else {
this.player.playerConnection.sendPacket(new PacketPlayOutBlockChange(this.world, blockposition));
// CraftBukkit end
}
}
public void e() {
this.d = false;
this.world.c(this.player.getId(), this.f, -1);
}
private boolean c(BlockPosition blockposition) {
IBlockData iblockdata = this.world.getType(blockposition);
iblockdata.getBlock().a(this.world, blockposition, iblockdata, (EntityHuman) this.player);
boolean flag = this.world.setAir(blockposition);
if (flag) {
iblockdata.getBlock().postBreak(this.world, blockposition, iblockdata);
}
return flag;
}
// Paper start - Extra method to avoid visual issues on the client when cancelling block breaks
private void cancelBreakBlock(BlockPosition position, IBlockData data) {
Block block = data.getBlock();
// Send other half of the door
if (block instanceof BlockDoor) {
boolean bottom = data.get(BlockDoor.HALF) == BlockDoor.EnumDoorHalf.LOWER;
this.player.playerConnection.sendPacket(new PacketPlayOutBlockChange(world, bottom ? position.up() : position.down()));
} else if (block instanceof BlockTallPlant) {
boolean bottom = data.get(BlockTallPlant.HALF) == BlockTallPlant.EnumTallPlantHalf.LOWER;
this.player.playerConnection.sendPacket(new PacketPlayOutBlockChange(world, bottom ? position.up() : position.down()));
} else if (block instanceof BlockPistonExtension) {
BlockPosition piston = position.shift(data.get(BlockPistonExtension.FACING).opposite());
this.player.playerConnection.sendPacket(new PacketPlayOutBlockChange(world, piston));
} else if (block instanceof BlockBed) {
if (data.get(BlockBed.PART) == BlockBed.EnumBedPart.FOOT) {
// Restore head of bed
BlockPosition head = position.shift(data.get(BlockBed.FACING));
this.player.playerConnection.sendPacket(new PacketPlayOutBlockChange(world, head));
TileEntity tileentity = this.world.getTileEntity(head);
if (tileentity != null) {
this.player.playerConnection.sendPacket(tileentity.getUpdatePacket());
}
}
}
}
// Paper end
public boolean breakBlock(BlockPosition blockposition) {
// CraftBukkit start - fire BlockBreakEvent
BlockBreakEvent event = null;
if (this.player instanceof EntityPlayer) {
org.bukkit.block.Block block = this.world.getWorld().getBlockAt(blockposition.getX(), blockposition.getY(), blockposition.getZ());
// Sword + Creative mode pre-cancel
boolean isSwordNoBreak = this.gamemode.isCreative() && !this.player.getItemInMainHand().isEmpty() && this.player.getItemInMainHand().getItem() instanceof ItemSword;
// Tell client the block is gone immediately then process events
// Don't tell the client if its a creative sword break because its not broken!
if (world.getTileEntity(blockposition) == null && !isSwordNoBreak) {
PacketPlayOutBlockChange packet = new PacketPlayOutBlockChange(this.world, blockposition);
packet.block = Blocks.AIR.getBlockData();
((EntityPlayer) this.player).playerConnection.sendPacket(packet);
}
event = new BlockBreakEvent(block, this.player.getBukkitEntity());
// Sword + Creative mode pre-cancel
event.setCancelled(isSwordNoBreak);
// Calculate default block experience
IBlockData nmsData = this.world.getType(blockposition);
Block nmsBlock = nmsData.getBlock();
ItemStack itemstack = this.player.getEquipment(EnumItemSlot.MAINHAND);
if (nmsBlock != null && !event.isCancelled() && !this.isCreative() && this.player.hasBlock(nmsBlock.getBlockData())) {
// Copied from block.a(World world, EntityHuman entityhuman, BlockPosition blockposition, IBlockData iblockdata, @Nullable TileEntity tileentity, ItemStack itemstack)
// PAIL: checkme each update
if (!(nmsBlock.o() && EnchantmentManager.getEnchantmentLevel(Enchantments.SILK_TOUCH, itemstack) > 0)) {
int bonusLevel = EnchantmentManager.getEnchantmentLevel(Enchantments.LOOT_BONUS_BLOCKS, itemstack);
event.setExpToDrop(nmsBlock.getExpDrop(this.world, nmsData, bonusLevel));
}
}
this.world.getServer().getPluginManager().callEvent(event);
if (event.isCancelled()) {
if (isSwordNoBreak) {
return false;
}
// Let the client know the block still exists
((EntityPlayer) this.player).playerConnection.sendPacket(new PacketPlayOutBlockChange(this.world, blockposition));
cancelBreakBlock(blockposition, nmsData); // Paper - Move cancellation code to extra "cancelBreakBlock" method
// Update any tile entity data for this block
TileEntity tileentity = this.world.getTileEntity(blockposition);
if (tileentity != null) {
this.player.playerConnection.sendPacket(tileentity.getUpdatePacket());
}
return false;
}
}
if (false && this.gamemode.isCreative() && !this.player.getItemInMainHand().isEmpty() && this.player.getItemInMainHand().getItem() instanceof ItemSword) { // CraftBukkit - false
return false;
} else {
IBlockData iblockdata = this.world.getType(blockposition);
if (iblockdata.getBlock() == Blocks.AIR) return false; // CraftBukkit - A plugin set block to air without cancelling
TileEntity tileentity = this.world.getTileEntity(blockposition);
Block block = iblockdata.getBlock();
// CraftBukkit start - Special case skulls, their item data comes from a tile entity (Also check if block should drop items)
if (iblockdata.getBlock() == Blocks.SKULL && !this.isCreative() && event.isDropItems()) {
iblockdata.getBlock().dropNaturally(world, blockposition, iblockdata, 1.0F, 0);
return this.c(blockposition);
}
// And shulker boxes too for duplication on cancel reasons (Also check if block should drop items)
if (iblockdata.getBlock() instanceof BlockShulkerBox && event.isDropItems()) {
iblockdata.getBlock().dropNaturally(world, blockposition, iblockdata, 1.0F, 0);
return this.c(blockposition);
}
// CraftBukkit end
if ((block instanceof BlockCommand || block instanceof BlockStructure) && !this.player.isCreativeAndOp()) {
this.world.notify(blockposition, iblockdata, iblockdata, 3);
return false;
} else {
if (this.gamemode.c()) {
if (this.gamemode == EnumGamemode.SPECTATOR) {
return false;
}
if (!this.player.dk()) {
ItemStack itemstack = this.player.getItemInMainHand();
if (itemstack.isEmpty()) {
return false;
}
if (!itemstack.a(block)) {
return false;
}
}
}
this.world.a(this.player, 2001, blockposition, Block.getCombinedId(iblockdata));
// CraftBukkit start
world.captureDrops = new ArrayList<>();
boolean flag = this.c(blockposition);
if (event.isDropItems()) {
for (EntityItem item : world.captureDrops) {
world.addEntity(item);
}
}
world.captureDrops = null;
// CraftBukkit end
if (this.isCreative()) {
this.player.playerConnection.sendPacket(new PacketPlayOutBlockChange(this.world, blockposition));
} else {
ItemStack itemstack1 = this.player.getItemInMainHand();
//ItemStack itemstack2 = itemstack1.isEmpty() ? ItemStack.a : itemstack1.cloneItemStack(); //NeonPaper move up
boolean flag1 = this.player.hasBlock(iblockdata);
ItemStack itemstack2 = flag && flag1 && event.isDropItems() && !itemstack1.isEmpty() ? itemstack1.cloneItemStack() : ItemStack.a; // NeonPaper - clone before use
if (!itemstack1.isEmpty()) {
itemstack1.a(this.world, iblockdata, blockposition, this.player);
}
// CraftBukkit start - Check if block should drop items
if (flag && flag1 && event.isDropItems()) {
iblockdata.getBlock().a(this.world, this.player, blockposition, iblockdata, tileentity, itemstack2);
}
// CraftBukkit end
}
// CraftBukkit start - Drop event experience
if (flag && event != null) {
iblockdata.getBlock().dropExperience(this.world, blockposition, event.getExpToDrop(), this.player); // Paper
}
// CraftBukkit end
return flag;
}
}
}
public EnumInteractionResult a(EntityHuman entityhuman, World world, ItemStack itemstack, EnumHand enumhand) {
if (this.gamemode == EnumGamemode.SPECTATOR) {
return EnumInteractionResult.PASS;
} else if (entityhuman.getCooldownTracker().a(itemstack.getItem())) {
return EnumInteractionResult.PASS;
} else {
int i = itemstack.getCount();
int j = itemstack.getData();
InteractionResultWrapper interactionresultwrapper = itemstack.a(world, entityhuman, enumhand);
ItemStack itemstack1 = (ItemStack) interactionresultwrapper.b();
if (itemstack1 == itemstack && itemstack1.getCount() == i && itemstack1.m() <= 0 && itemstack1.getData() == j) {
return interactionresultwrapper.a();
} else if (interactionresultwrapper.a() == EnumInteractionResult.FAIL && itemstack1.m() > 0 && !entityhuman.isHandRaised()) {
return interactionresultwrapper.a();
} else {
entityhuman.a(enumhand, itemstack1);
if (this.isCreative()) {
itemstack1.setCount(i);
if (itemstack1.f()) {
itemstack1.setData(j);
}
}
if (itemstack1.isEmpty()) {
entityhuman.a(enumhand, ItemStack.a);
}
if (!entityhuman.isHandRaised()) {
((EntityPlayer) entityhuman).updateInventory(entityhuman.defaultContainer);
}
return interactionresultwrapper.a();
}
}
}
// CraftBukkit start - whole method
public boolean interactResult = false;
public boolean firedInteract = false;
public EnumInteractionResult a(EntityHuman entityhuman, World world, ItemStack itemstack, EnumHand enumhand, BlockPosition blockposition, EnumDirection enumdirection, float f, float f1, float f2) {
IBlockData blockdata = world.getType(blockposition);
EnumInteractionResult enuminteractionresult = EnumInteractionResult.FAIL;
if (blockdata.getBlock() != Blocks.AIR) {
boolean cancelledBlock = false;
if (this.gamemode == EnumGamemode.SPECTATOR) {
TileEntity tileentity = world.getTileEntity(blockposition);
cancelledBlock = !(tileentity instanceof ITileInventory || tileentity instanceof IInventory);
}
if (entityhuman.getCooldownTracker().a(itemstack.getItem())) {
cancelledBlock = true;
}
if (itemstack.getItem() instanceof ItemBlock && !entityhuman.isCreativeAndOp()) {
Block block1 = ((ItemBlock) itemstack.getItem()).getBlock();
if (block1 instanceof BlockCommand || block1 instanceof BlockStructure) {
cancelledBlock = true;
}
}
PlayerInteractEvent event = CraftEventFactory.callPlayerInteractEvent(entityhuman, Action.RIGHT_CLICK_BLOCK, blockposition, enumdirection, itemstack, cancelledBlock, enumhand);
firedInteract = true;
interactResult = event.useItemInHand() == Event.Result.DENY;
if (event.useInteractedBlock() == Event.Result.DENY) {
// If we denied a door from opening, we need to send a correcting update to the client, as it already opened the door.
if (blockdata.getBlock() instanceof BlockDoor) {
boolean bottom = blockdata.get(BlockDoor.HALF) == BlockDoor.EnumDoorHalf.LOWER;
((EntityPlayer) entityhuman).playerConnection.sendPacket(new PacketPlayOutBlockChange(world, bottom ? blockposition.up() : blockposition.down()));
} else if (blockdata.getBlock() instanceof BlockCake) {
((EntityPlayer) entityhuman).getBukkitEntity().sendHealthUpdate(); // SPIGOT-1341 - reset health for cake
// Paper start - extend Player Interact cancellation
} else if (blockdata.getBlock() instanceof BlockStructure) {
((EntityPlayer) entityhuman).playerConnection.sendPacket(new PacketPlayOutCloseWindow());
} else if (blockdata.getBlock() instanceof BlockCommand) {
((EntityPlayer) entityhuman).playerConnection.sendPacket(new PacketPlayOutCloseWindow());
} else if (blockdata.getBlock() instanceof BlockFlowerPot) {
// Send a block change to air and then send back the correct block, just to make the client happy
PacketPlayOutBlockChange packet = new PacketPlayOutBlockChange(this.world, blockposition);
packet.block = Blocks.AIR.getBlockData();
this.player.playerConnection.sendPacket(packet);
this.player.playerConnection.sendPacket(new PacketPlayOutBlockChange(this.world, blockposition));
TileEntity tileentity = this.world.getTileEntity(blockposition);
if (tileentity != null) {
player.playerConnection.sendPacket(tileentity.getUpdatePacket());
}
// Paper end - extend Player Interact cancellation
}
((EntityPlayer) entityhuman).getBukkitEntity().updateInventory(); // SPIGOT-2867
enuminteractionresult = (event.useItemInHand() != Event.Result.ALLOW) ? EnumInteractionResult.SUCCESS : EnumInteractionResult.PASS;
} else if (this.gamemode == EnumGamemode.SPECTATOR) {
TileEntity tileentity = world.getTileEntity(blockposition);
if (tileentity instanceof ITileInventory) {
Block block = world.getType(blockposition).getBlock();
ITileInventory itileinventory = (ITileInventory) tileentity;
if (itileinventory instanceof TileEntityChest && block instanceof BlockChest) {
itileinventory = ((BlockChest) block).getInventory(world, blockposition);
}
if (itileinventory != null) {
entityhuman.openContainer(itileinventory);
return EnumInteractionResult.SUCCESS;
}
} else if (tileentity instanceof IInventory) {
entityhuman.openContainer((IInventory) tileentity);
return EnumInteractionResult.SUCCESS;
}
return EnumInteractionResult.PASS;
} else {
if (!entityhuman.isSneaking() || entityhuman.getItemInMainHand().isEmpty() && entityhuman.getItemInOffHand().isEmpty()) {
IBlockData iblockdata = world.getType(blockposition);
enuminteractionresult = iblockdata.getBlock().interact(world, blockposition, iblockdata, entityhuman, enumhand, enumdirection, f, f1, f2) ? EnumInteractionResult.SUCCESS : EnumInteractionResult.PASS;
}
}
if (!itemstack.isEmpty() && enuminteractionresult != EnumInteractionResult.SUCCESS && !interactResult) { // add !interactResult SPIGOT-764
int i = itemstack.getData();
int j = itemstack.getCount();
enuminteractionresult = itemstack.placeItem(entityhuman, world, blockposition, enumhand, enumdirection, f, f1, f2);
// The item count should not decrement in Creative mode.
if (this.isCreative()) {
itemstack.setData(i);
itemstack.setCount(j);
}
}
}
return enuminteractionresult;
// CraftBukkit end
}
public void a(WorldServer worldserver) {
this.world = worldserver;
}
}

View File

@@ -558,9 +558,10 @@ public abstract class PlayerList {
Player player = entity.getBukkitEntity(); Player player = entity.getBukkitEntity();
PlayerLoginEvent event = new PlayerLoginEvent(player, hostname, ((java.net.InetSocketAddress) socketaddress).getAddress(), ((java.net.InetSocketAddress) loginlistener.networkManager.getRawAddress()).getAddress()); PlayerLoginEvent event = new PlayerLoginEvent(player, hostname, ((java.net.InetSocketAddress) socketaddress).getAddress(), ((java.net.InetSocketAddress) loginlistener.networkManager.getRawAddress()).getAddress());
String s; String s;
// NeonPaper start - Fix MC-158900
if (getProfileBans().isBanned(gameprofile) && !getProfileBans().get(gameprofile).hasExpired()) { GameProfileBanEntry gameprofilebanentry;
GameProfileBanEntry gameprofilebanentry = this.k.get(gameprofile); if (getProfileBans().isBanned(gameprofile) && (gameprofilebanentry = getProfileBans().get(gameprofile)) != null) {
// NeonPaper end
s = LocaleI18n.a(AkarinGlobalConfig.messageBan, s = LocaleI18n.a(AkarinGlobalConfig.messageBan,
gameprofilebanentry.getReason().equals(Akari.EMPTY_STRING) ? Akari.EMPTY_STRING : AkarinGlobalConfig.messageBanReason + gameprofilebanentry.getReason(), gameprofilebanentry.getReason().equals(Akari.EMPTY_STRING) ? Akari.EMPTY_STRING : AkarinGlobalConfig.messageBanReason + gameprofilebanentry.getReason(),

View File

@@ -0,0 +1,356 @@
package net.minecraft.server;
import com.google.common.collect.Sets;
import java.util.Iterator;
import java.util.List;
import java.util.Random;
import java.util.Set;
// CraftBukkit start
import com.destroystokyo.paper.exception.ServerInternalException;
import org.bukkit.craftbukkit.util.LongHash;
import org.bukkit.craftbukkit.util.LongHashSet;
import org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason;
// CraftBukkit end
public final class SpawnerCreature {
private static final int a = (int) Math.pow(17.0D, 2.0D);
private final LongHashSet b = new LongHashSet(); // CraftBukkit
public SpawnerCreature() {}
// Spigot start - get entity count only from chunks being processed in b
private int getEntityCount(WorldServer server, Class oClass)
{
// Paper start - use entire world, not just active chunks. Spigot broke vanilla expectations.
if (true) {
int sum = 0;
for (Chunk c : server.getChunkProviderServer().chunks.values()) {
sum += c.entityCount.get(oClass);
}
return sum;
}
// Paper end
int i = 0;
Iterator<Long> it = this.b.iterator();
while ( it.hasNext() )
{
Long coord = it.next();
int x = LongHash.msw( coord );
int z = LongHash.lsw( coord );
if ( !((ChunkProviderServer)server.chunkProvider).unloadQueue.contains( coord ) && server.isChunkLoaded( x, z, true ) )
{
i += server.getChunkAt( x, z ).entityCount.get( oClass );
}
}
return i;
}
// Spigot end
public int a(WorldServer worldserver, boolean flag, boolean flag1, boolean flag2) {
org.spigotmc.AsyncCatcher.catchOp("check for eligible spawn chunks"); // Paper - At least until we figure out what is calling this async
if (!flag && !flag1) {
return 0;
} else {
this.b.clear();
int i = 0;
Iterator iterator = worldserver.players.iterator();
int j;
int k;
while (iterator.hasNext()) {
EntityHuman entityhuman = (EntityHuman) iterator.next();
if (!entityhuman.isSpectator() && entityhuman.affectsSpawning) {
int l = MathHelper.floor(entityhuman.locX / 16.0D);
j = MathHelper.floor(entityhuman.locZ / 16.0D);
boolean flag3 = true;
// Spigot Start
byte b0 = worldserver.spigotConfig.mobSpawnRange;
b0 = ( b0 > worldserver.spigotConfig.viewDistance ) ? (byte) worldserver.spigotConfig.viewDistance : b0;
b0 = ( b0 > 8 ) ? 8 : b0;
// Paper start
com.destroystokyo.paper.event.entity.PlayerNaturallySpawnCreaturesEvent event;
event = new com.destroystokyo.paper.event.entity.PlayerNaturallySpawnCreaturesEvent(
(org.bukkit.entity.Player) entityhuman.getBukkitEntity(), b0);
if (!event.callEvent()) {
continue;
}
b0 = event.getSpawnRadius();
// Paperr end
for (int i1 = -b0; i1 <= b0; ++i1) {
for (k = -b0; k <= b0; ++k) {
boolean flag4 = i1 == -b0 || i1 == b0 || k == -b0 || k == b0;
// Spigot End
ChunkCoordIntPair chunkcoordintpair = new ChunkCoordIntPair(i1 + l, k + j);
// CraftBukkit start - use LongHash and LongHashSet
long chunkCoords = LongHash.toLong(chunkcoordintpair.x, chunkcoordintpair.z);
if (!this.b.contains(chunkCoords)) {
++i;
if (!flag4 && worldserver.isChunkLoaded(chunkcoordintpair.x, chunkcoordintpair.z, true) && worldserver.getWorldBorder().isInBounds(chunkcoordintpair)) {
PlayerChunk playerchunk = worldserver.getPlayerChunkMap().getChunk(chunkcoordintpair.x, chunkcoordintpair.z);
if (playerchunk != null && playerchunk.e()) {
this.b.add(chunkCoords);
// CraftBukkit end
}
}
}
}
}
}
}
int j1 = 0;
BlockPosition blockposition = worldserver.getSpawn();
EnumCreatureType[] aenumcreaturetype = EnumCreatureType.values();
j = aenumcreaturetype.length;
for (int k1 = 0; k1 < j; ++k1) {
EnumCreatureType enumcreaturetype = aenumcreaturetype[k1];
// CraftBukkit start - Use per-world spawn limits
int limit = enumcreaturetype.b();
switch (enumcreaturetype) {
case MONSTER:
limit = worldserver.getWorld().getMonsterSpawnLimit();
break;
case CREATURE:
limit = worldserver.getWorld().getAnimalSpawnLimit();
break;
case WATER_CREATURE:
limit = worldserver.getWorld().getWaterAnimalSpawnLimit();
break;
case AMBIENT:
limit = worldserver.getWorld().getAmbientSpawnLimit();
break;
}
if (limit == 0) {
continue;
}
int mobcnt = 0; // Spigot
// CraftBukkit end
if ((!enumcreaturetype.d() || flag1) && (enumcreaturetype.d() || flag) && (!enumcreaturetype.e() || flag2)) {
/* Paper start - As far as I can tell neither of these are even used
k = worldserver.a(enumcreaturetype.a());
int l1 = limit * i / a; // CraftBukkit - use per-world limits
*/ // Paper end
if ((mobcnt = getEntityCount(worldserver, enumcreaturetype.a())) <= limit * i / 289) { // Paper - use 17x17 like vanilla (a at top of file)
BlockPosition.MutableBlockPosition blockposition_mutableblockposition = new BlockPosition.MutableBlockPosition();
Iterator iterator1 = this.b.iterator();
int moblimit = (limit * i / 256) - mobcnt + 1; // Spigot - up to 1 more than limit
label120:
while (iterator1.hasNext() && (moblimit > 0)) { // Spigot - while more allowed
// CraftBukkit start = use LongHash and LongObjectHashMap
long key = ((Long) iterator1.next()).longValue();
BlockPosition blockposition1 = getRandomPosition(worldserver, LongHash.msw(key), LongHash.lsw(key));
// CraftBukkit
int i2 = blockposition1.getX();
int j2 = blockposition1.getY();
int k2 = blockposition1.getZ();
IBlockData iblockdata = worldserver.getWorldBorder().isInBounds(blockposition1) ? worldserver.getTypeIfLoaded(blockposition1) : null; // Paper
if (iblockdata != null && !iblockdata.l()) { // Paper
int l2 = 0;
int i3 = 0;
while (i3 < 3) {
int j3 = i2;
int k3 = j2;
int l3 = k2;
boolean flag5 = true;
BiomeBase.BiomeMeta biomebase_biomemeta = null;
GroupDataEntity groupdataentity = null;
int i4 = MathHelper.f(Math.random() * 4.0D);
int j4 = 0;
while (true) {
if (j4 < i4) {
label113: {
j3 += worldserver.random.nextInt(6) - worldserver.random.nextInt(6);
k3 += worldserver.random.nextInt(1) - worldserver.random.nextInt(1);
l3 += worldserver.random.nextInt(6) - worldserver.random.nextInt(6);
blockposition_mutableblockposition.c(j3, k3, l3);
float f = (float) j3 + 0.5F;
float f1 = (float) l3 + 0.5F;
if (worldserver.getWorldBorder().isInBounds(blockposition_mutableblockposition) && worldserver.getChunkIfLoaded(blockposition_mutableblockposition) != null && !worldserver.isPlayerNearby((double) f, (double) k3, (double) f1, 24.0D) && blockposition.distanceSquared((double) f, (double) k3, (double) f1) >= 576.0D) { // Paper - Prevent mob spawning from loading/generating chunks
if (biomebase_biomemeta == null) {
biomebase_biomemeta = worldserver.a(enumcreaturetype, (BlockPosition) blockposition_mutableblockposition);
if (biomebase_biomemeta == null) {
break label113;
}
}
if (worldserver.a(enumcreaturetype, biomebase_biomemeta, (BlockPosition) blockposition_mutableblockposition) && a(EntityPositionTypes.a(biomebase_biomemeta.b), worldserver, blockposition_mutableblockposition)) {
// Paper start
com.destroystokyo.paper.event.entity.PreCreatureSpawnEvent event;
Class<? extends EntityInsentient> cls = biomebase_biomemeta.b;
org.bukkit.entity.EntityType type = EntityTypes.clsToTypeMap.get(cls);
if (type != null) {
event = new com.destroystokyo.paper.event.entity.PreCreatureSpawnEvent(
MCUtil.toLocation(worldserver, blockposition_mutableblockposition),
type, SpawnReason.NATURAL
);
if (!event.callEvent()) {
if (event.shouldAbortSpawn()) {
continue label120;
}
j1 += l2;
++j4;
continue;
}
}
// Paper end
EntityInsentient entityinsentient;
try {
entityinsentient = (EntityInsentient) biomebase_biomemeta.b.getConstructor(new Class[] { World.class}).newInstance(new Object[] { worldserver});
} catch (Exception exception) {
exception.printStackTrace();
ServerInternalException.reportInternalException(exception); // Paper
return j1;
}
entityinsentient.setPositionRotation((double) f, (double) k3, (double) f1, worldserver.random.nextFloat() * 360.0F, 0.0F);
if (entityinsentient.P() && entityinsentient.canSpawn()) {
groupdataentity = entityinsentient.prepare(worldserver.D(new BlockPosition(entityinsentient)), groupdataentity);
if (entityinsentient.canSpawn()) {
// CraftBukkit start
if (worldserver.addEntity(entityinsentient, SpawnReason.NATURAL)) {
++l2;
moblimit--; // Spigot
}
// CraftBukkit end
} else {
entityinsentient.die();
}
// Spigot start
if ( moblimit <= 0 ) {
// If we're past limit, stop spawn
// Spigot end
continue label120;
}
}
j1 += l2;
}
}
++j4;
continue;
}
}
++i3;
break;
}
}
}
}
}
}
}
return j1;
}
}
private static BlockPosition getRandomPosition(World world, int i, int j) {
Chunk chunk = world.getChunkAt(i, j);
int k = i * 16 + world.random.nextInt(16);
int l = j * 16 + world.random.nextInt(16);
int i1 = MathHelper.c(chunk.e(new BlockPosition(k, 0, l)) + 1, 16);
int j1 = world.random.nextInt(i1 > 0 ? i1 : chunk.g() + 16 - 1);
return new BlockPosition(k, j1, l);
}
public static boolean a(IBlockData iblockdata) {
return iblockdata.k() ? false : (iblockdata.m() ? false : (iblockdata.getMaterial().isLiquid() ? false : !BlockMinecartTrackAbstract.i(iblockdata)));
}
public static boolean a(EntityInsentient.EnumEntityPositionType entityinsentient_enumentitypositiontype, World world, BlockPosition blockposition) {
if (!world.getWorldBorder().a(blockposition)) {
return false;
} else {
IBlockData iblockdata = world.getType(blockposition);
if (entityinsentient_enumentitypositiontype == EntityInsentient.EnumEntityPositionType.IN_WATER) {
return iblockdata.getMaterial() == Material.WATER && world.getType(blockposition.down()).getMaterial() == Material.WATER && !world.getType(blockposition.up()).l();
} else {
BlockPosition blockposition1 = blockposition.down();
if (!world.getType(blockposition1).q()) {
return false;
} else {
Block block = world.getType(blockposition1).getBlock();
boolean flag = block != Blocks.BEDROCK && block != Blocks.BARRIER;
return flag && a(iblockdata) && a(world.getType(blockposition.up()));
}
}
}
}
public static void a(World world, BiomeBase biomebase, int i, int j, int k, int l, Random random) {
List list = biomebase.getMobs(EnumCreatureType.CREATURE);
if (!list.isEmpty()) {
while (random.nextFloat() < biomebase.f()) {
BiomeBase.BiomeMeta biomebase_biomemeta = (BiomeBase.BiomeMeta) WeightedRandom.a(world.random, list);
int i1 = biomebase_biomemeta.c + random.nextInt(1 + biomebase_biomemeta.d - biomebase_biomemeta.c);
GroupDataEntity groupdataentity = null;
int j1 = i + random.nextInt(k);
int k1 = j + random.nextInt(l);
int l1 = j1;
int i2 = k1;
for (int j2 = 0; j2 < i1; ++j2) {
boolean flag = false;
for (int k2 = 0; !flag && k2 < 4; ++k2) {
BlockPosition blockposition = world.q(new BlockPosition(j1, 0, k1));
if (a(EntityInsentient.EnumEntityPositionType.ON_GROUND, world, blockposition)) {
EntityInsentient entityinsentient;
try {
entityinsentient = (EntityInsentient) biomebase_biomemeta.b.getConstructor(new Class[] { World.class}).newInstance(new Object[] { world});
} catch (Exception exception) {
exception.printStackTrace();
ServerInternalException.reportInternalException(exception); // Paper
continue;
}
entityinsentient.setPositionRotation((double) ((float) j1 + 0.5F), (double) blockposition.getY(), (double) ((float) k1 + 0.5F), random.nextFloat() * 360.0F, 0.0F);
// CraftBukkit start - Added a reason for spawning this creature, moved entityinsentient.prepare(groupdataentity) up
groupdataentity = entityinsentient.prepare(world.D(new BlockPosition(entityinsentient)), groupdataentity);
world.addEntity(entityinsentient, SpawnReason.CHUNK_GEN);
// CraftBukkit end
flag = true;
}
j1 += random.nextInt(5) - random.nextInt(5);
for (k1 += random.nextInt(5) - random.nextInt(5); j1 < i || j1 >= i + k || k1 < j || k1 >= j + k; k1 = i2 + random.nextInt(5) - random.nextInt(5)) {
j1 = l1 + random.nextInt(5) - random.nextInt(5);
}
}
}
}
}
}
}

View File

@@ -0,0 +1,423 @@
package net.minecraft.server;
import java.util.Iterator;
// CraftBukkit start
import java.util.List;
import org.bukkit.craftbukkit.inventory.CraftItemStack;
import org.bukkit.entity.HumanEntity;
import org.bukkit.event.inventory.FurnaceBurnEvent;
import org.bukkit.event.inventory.FurnaceSmeltEvent;
import org.bukkit.craftbukkit.entity.CraftHumanEntity;
// CraftBukkit end
public class TileEntityFurnace extends TileEntityContainer implements ITickable, IWorldInventory {
private static final int[] a = new int[] { 0};
private static final int[] f = new int[] { 2, 1};
private static final int[] g = new int[] { 1};
private NonNullList<ItemStack> items;
private int burnTime;
private int ticksForCurrentFuel;
private int cookTime;
private int cookTimeTotal;
private String m;
// CraftBukkit start - add fields and methods
private int lastTick = MinecraftServer.currentTick;
private int maxStack = MAX_STACK;
public List<HumanEntity> transaction = new java.util.ArrayList<HumanEntity>();
public List<ItemStack> getContents() {
return this.items;
}
public void onOpen(CraftHumanEntity who) {
transaction.add(who);
}
public void onClose(CraftHumanEntity who) {
transaction.remove(who);
}
public List<HumanEntity> getViewers() {
return transaction;
}
public void setMaxStackSize(int size) {
maxStack = size;
}
// CraftBukkit end
public TileEntityFurnace() {
this.items = NonNullList.a(3, ItemStack.a);
}
public int getSize() {
return this.items.size();
}
public boolean x_() {
Iterator iterator = this.items.iterator();
ItemStack itemstack;
do {
if (!iterator.hasNext()) {
return true;
}
itemstack = (ItemStack) iterator.next();
} while (itemstack.isEmpty());
return false;
}
public ItemStack getItem(int i) {
return (ItemStack) this.items.get(i);
}
public ItemStack splitStack(int i, int j) {
return ContainerUtil.a(this.items, i, j);
}
public ItemStack splitWithoutUpdate(int i) {
return ContainerUtil.a(this.items, i);
}
public void setItem(int i, ItemStack itemstack) {
ItemStack itemstack1 = (ItemStack) this.items.get(i);
boolean flag = !itemstack.isEmpty() && itemstack.doMaterialsMatch(itemstack1) && ItemStack.equals(itemstack, itemstack1);
this.items.set(i, itemstack);
if (itemstack.getCount() > this.getMaxStackSize()) {
itemstack.setCount(this.getMaxStackSize());
}
if (i == 0 && !flag) {
this.cookTimeTotal = this.a(itemstack);
this.cookTime = 0;
this.update();
}
}
public String getName() {
return this.hasCustomName() ? this.m : "container.furnace";
}
public boolean hasCustomName() {
return this.m != null && !this.m.isEmpty();
}
public void setCustomName(String s) {
this.m = s;
}
public static void a(DataConverterManager dataconvertermanager) {
dataconvertermanager.a(DataConverterTypes.BLOCK_ENTITY, (DataInspector) (new DataInspectorItemList(TileEntityFurnace.class, new String[] { "Items"})));
}
public void load(NBTTagCompound nbttagcompound) {
super.load(nbttagcompound);
this.items = NonNullList.a(this.getSize(), ItemStack.a);
ContainerUtil.b(nbttagcompound, this.items);
this.burnTime = nbttagcompound.getShort("BurnTime");
this.cookTime = nbttagcompound.getShort("CookTime");
this.cookTimeTotal = nbttagcompound.getShort("CookTimeTotal");
this.ticksForCurrentFuel = fuelTime((ItemStack) this.items.get(1));
if (nbttagcompound.hasKeyOfType("CustomName", 8)) {
this.m = nbttagcompound.getString("CustomName");
}
}
public NBTTagCompound save(NBTTagCompound nbttagcompound) {
super.save(nbttagcompound);
nbttagcompound.setShort("BurnTime", (short) this.burnTime);
nbttagcompound.setShort("CookTime", (short) this.cookTime);
nbttagcompound.setShort("CookTimeTotal", (short) this.cookTimeTotal);
ContainerUtil.a(nbttagcompound, this.items);
if (this.hasCustomName()) {
nbttagcompound.setString("CustomName", this.m);
}
return nbttagcompound;
}
public int getMaxStackSize() {
return 64;
}
public boolean isBurning() {
return this.burnTime > 0;
}
public void e() {
boolean flag = (this.getBlock() == Blocks.LIT_FURNACE); // CraftBukkit - SPIGOT-844 - Check if furnace block is lit using the block instead of burn time
boolean flag1 = false;
// CraftBukkit start - Use wall time instead of ticks for cooking
int elapsedTicks = MinecraftServer.currentTick - this.lastTick;
this.lastTick = MinecraftServer.currentTick;
// CraftBukkit - moved from below - edited for wall time
if (this.isBurning() && this.canBurn()) {
this.cookTime += elapsedTicks;
if (this.cookTime >= this.cookTimeTotal) {
this.cookTime -= this.cookTimeTotal; // Paper
this.cookTimeTotal = this.a((ItemStack) this.items.get(0));
this.burn();
flag1 = true;
}
} else {
this.cookTime = 0;
}
// CraftBukkit end
if (this.isBurning()) {
this.burnTime -= elapsedTicks; // CraftBukkit - use elapsedTicks in place of constant
}
if (!this.world.isClientSide) {
ItemStack itemstack = (ItemStack) this.items.get(1);
if (!this.isBurning() && (itemstack.isEmpty() || ((ItemStack) this.items.get(0)).isEmpty())) {
if (!this.isBurning() && this.cookTime > 0) {
this.cookTime = MathHelper.clamp(this.cookTime - 2, 0, this.cookTimeTotal);
}
} else if(this.items.get(1) != null && this.items.get(1).getItem() != Items.BUCKET) {
// CraftBukkit start - Handle multiple elapsed ticks
if (this.burnTime <= 0 && this.canBurn()) { // CraftBukkit - == to <=
CraftItemStack fuel = CraftItemStack.asCraftMirror(itemstack);
FurnaceBurnEvent furnaceBurnEvent = new FurnaceBurnEvent(this.world.getWorld().getBlockAt(position.getX(), position.getY(), position.getZ()), fuel, fuelTime(itemstack));
this.world.getServer().getPluginManager().callEvent(furnaceBurnEvent);
if (furnaceBurnEvent.isCancelled()) {
return;
}
this.ticksForCurrentFuel = furnaceBurnEvent.getBurnTime();
this.burnTime += this.ticksForCurrentFuel;
if (this.burnTime > 0 && furnaceBurnEvent.isBurning()) {
// CraftBukkit end
flag1 = true;
if (!itemstack.isEmpty()) {
Item item = itemstack.getItem();
itemstack.subtract(1);
if (itemstack.isEmpty()) {
Item item1 = item.q();
this.items.set(1, item1 == null ? ItemStack.a : new ItemStack(item1));
}
}
}
}
/* CraftBukkit start - Moved up
if (this.isBurning() && this.canBurn()) {
++this.cookTime;
if (this.cookTime == this.cookTimeTotal) {
this.cookTime = 0;
this.cookTimeTotal = this.a((ItemStack) this.items.get(0));
this.burn();
flag1 = true;
}
} else {
this.cookTime = 0;
}
*/
}
if (flag != this.isBurning()) {
flag1 = true;
BlockFurnace.a(this.isBurning(), this.world, this.position);
this.invalidateBlockCache(); // CraftBukkit - Invalidate tile entity's cached block type
}
}
if (flag1) {
this.update();
}
}
public int a(ItemStack itemstack) {
return 200;
}
private boolean canBurn() {
if (((ItemStack) this.items.get(0)).isEmpty()) {
return false;
} else {
ItemStack itemstack = RecipesFurnace.getInstance().getResult((ItemStack) this.items.get(0));
if (itemstack.isEmpty()) {
return false;
} else {
ItemStack itemstack1 = (ItemStack) this.items.get(2);
// CraftBukkit - consider resultant count instead of current count
return itemstack1.isEmpty() ? true : (!itemstack1.doMaterialsMatch(itemstack) ? false : (itemstack1.getCount() + itemstack.getCount() <= this.getMaxStackSize() && itemstack1.getCount() + itemstack.getCount() < itemstack1.getMaxStackSize() ? true : itemstack1.getCount() + itemstack.getCount() <= itemstack.getMaxStackSize()));
}
}
}
public void burn() {
if (this.canBurn()) {
ItemStack itemstack = (ItemStack) this.items.get(0);
ItemStack itemstack1 = RecipesFurnace.getInstance().getResult(itemstack);
ItemStack itemstack2 = (ItemStack) this.items.get(2);
// CraftBukkit start - fire FurnaceSmeltEvent
CraftItemStack source = CraftItemStack.asCraftMirror(itemstack);
org.bukkit.inventory.ItemStack result = CraftItemStack.asBukkitCopy(itemstack1);
FurnaceSmeltEvent furnaceSmeltEvent = new FurnaceSmeltEvent(this.world.getWorld().getBlockAt(position.getX(), position.getY(), position.getZ()), source, result);
this.world.getServer().getPluginManager().callEvent(furnaceSmeltEvent);
if (furnaceSmeltEvent.isCancelled()) {
return;
}
result = furnaceSmeltEvent.getResult();
itemstack1 = CraftItemStack.asNMSCopy(result);
if (!itemstack1.isEmpty()) {
if (itemstack2.isEmpty()) {
this.items.set(2, itemstack1.cloneItemStack());
} else if (CraftItemStack.asCraftMirror(itemstack2).isSimilar(result)) {
itemstack2.add(itemstack1.getCount());
} else {
return;
}
}
/*
if (itemstack2.isEmpty()) {
this.items.set(2, itemstack1.cloneItemStack());
} else if (itemstack2.getItem() == itemstack1.getItem()) {
itemstack2.add(1);
}
*/
// CraftBukkit end
if (itemstack.getItem() == Item.getItemOf(Blocks.SPONGE) && itemstack.getData() == 1 && !((ItemStack) this.items.get(1)).isEmpty() && ((ItemStack) this.items.get(1)).getItem() == Items.BUCKET) {
this.items.set(1, new ItemStack(Items.WATER_BUCKET));
}
itemstack.subtract(1);
}
}
public static int fuelTime(ItemStack itemstack) {
if (itemstack.isEmpty()) {
return 0;
} else {
Item item = itemstack.getItem();
return item == Item.getItemOf(Blocks.WOODEN_SLAB) ? 150 : (item == Item.getItemOf(Blocks.WOOL) ? 100 : (item == Item.getItemOf(Blocks.CARPET) ? 67 : (item == Item.getItemOf(Blocks.LADDER) ? 300 : (item == Item.getItemOf(Blocks.WOODEN_BUTTON) ? 100 : (Block.asBlock(item).getBlockData().getMaterial() == Material.WOOD ? 300 : (item == Item.getItemOf(Blocks.COAL_BLOCK) ? 16000 : (item instanceof ItemTool && "WOOD".equals(((ItemTool) item).h()) ? 200 : (item instanceof ItemSword && "WOOD".equals(((ItemSword) item).h()) ? 200 : (item instanceof ItemHoe && "WOOD".equals(((ItemHoe) item).g()) ? 200 : (item == Items.STICK ? 100 : (item != Items.BOW && item != Items.FISHING_ROD ? (item == Items.SIGN ? 200 : (item == Items.COAL ? 1600 : (item == Items.LAVA_BUCKET ? 20000 : (item != Item.getItemOf(Blocks.SAPLING) && item != Items.BOWL ? (item == Items.BLAZE_ROD ? 2400 : (item instanceof ItemDoor && item != Items.IRON_DOOR ? 200 : (item instanceof ItemBoat ? 400 : 0))) : 100)))) : 300)))))))))));
}
}
public static boolean isFuel(ItemStack itemstack) {
return fuelTime(itemstack) > 0;
}
public boolean a(EntityHuman entityhuman) {
return this.world.getTileEntity(this.position) != this ? false : entityhuman.d((double) this.position.getX() + 0.5D, (double) this.position.getY() + 0.5D, (double) this.position.getZ() + 0.5D) <= 64.0D;
}
public void startOpen(EntityHuman entityhuman) {}
public void closeContainer(EntityHuman entityhuman) {}
public boolean b(int i, ItemStack itemstack) {
if (i == 2) {
return false;
} else if (i != 1) {
return true;
} else {
ItemStack itemstack1 = (ItemStack) this.items.get(1);
return isFuel(itemstack) || SlotFurnaceFuel.d_(itemstack) && itemstack1.getItem() != Items.BUCKET;
}
}
public int[] getSlotsForFace(EnumDirection enumdirection) {
return enumdirection == EnumDirection.DOWN ? TileEntityFurnace.f : (enumdirection == EnumDirection.UP ? TileEntityFurnace.a : TileEntityFurnace.g);
}
public boolean canPlaceItemThroughFace(int i, ItemStack itemstack, EnumDirection enumdirection) {
return this.b(i, itemstack);
}
public boolean canTakeItemThroughFace(int i, ItemStack itemstack, EnumDirection enumdirection) {
if (enumdirection == EnumDirection.DOWN && i == 1) {
Item item = itemstack.getItem();
if (item != Items.WATER_BUCKET && item != Items.BUCKET) {
return false;
}
}
return true;
}
public String getContainerName() {
return "minecraft:furnace";
}
public Container createContainer(PlayerInventory playerinventory, EntityHuman entityhuman) {
return new ContainerFurnace(playerinventory, this);
}
public int getProperty(int i) {
switch (i) {
case 0:
return this.burnTime;
case 1:
return this.ticksForCurrentFuel;
case 2:
return this.cookTime;
case 3:
return this.cookTimeTotal;
default:
return 0;
}
}
public void setProperty(int i, int j) {
switch (i) {
case 0:
this.burnTime = j;
break;
case 1:
this.ticksForCurrentFuel = j;
break;
case 2:
this.cookTime = j;
break;
case 3:
this.cookTimeTotal = j;
}
}
public int h() {
return 4;
}
public void clear() {
this.items.clear();
}
}

View File

@@ -0,0 +1,784 @@
package net.minecraft.server;
import java.util.Iterator;
import java.util.List;
import javax.annotation.Nullable;
// CraftBukkit start
import org.bukkit.craftbukkit.entity.CraftHumanEntity;
import org.bukkit.craftbukkit.inventory.CraftItemStack;
import org.bukkit.entity.HumanEntity;
import org.bukkit.event.inventory.InventoryMoveItemEvent;
import org.bukkit.event.inventory.InventoryPickupItemEvent;
import org.bukkit.inventory.Inventory;
// CraftBukkit end
public class TileEntityHopper extends TileEntityLootable implements IHopper, ITickable {
private NonNullList<ItemStack> items;
private int f;
private long g;
// CraftBukkit start - add fields and methods
public List<HumanEntity> transaction = new java.util.ArrayList<HumanEntity>();
private int maxStack = MAX_STACK;
public List<ItemStack> getContents() {
return this.items;
}
public void onOpen(CraftHumanEntity who) {
transaction.add(who);
}
public void onClose(CraftHumanEntity who) {
transaction.remove(who);
}
public List<HumanEntity> getViewers() {
return transaction;
}
public void setMaxStackSize(int size) {
maxStack = size;
}
// CraftBukkit end
public TileEntityHopper() {
this.items = NonNullList.a(5, ItemStack.a);
this.f = -1;
}
public static void a(DataConverterManager dataconvertermanager) {
dataconvertermanager.a(DataConverterTypes.BLOCK_ENTITY, (DataInspector) (new DataInspectorItemList(TileEntityHopper.class, new String[] { "Items"})));
}
public void load(NBTTagCompound nbttagcompound) {
super.load(nbttagcompound);
this.items = NonNullList.a(this.getSize(), ItemStack.a);
if (!this.c(nbttagcompound)) {
ContainerUtil.b(nbttagcompound, this.items);
}
if (nbttagcompound.hasKeyOfType("CustomName", 8)) {
this.o = nbttagcompound.getString("CustomName");
}
this.f = nbttagcompound.getInt("TransferCooldown");
}
public NBTTagCompound save(NBTTagCompound nbttagcompound) {
super.save(nbttagcompound);
if (!this.d(nbttagcompound)) {
ContainerUtil.a(nbttagcompound, this.items);
}
nbttagcompound.setInt("TransferCooldown", this.f);
if (this.hasCustomName()) {
nbttagcompound.setString("CustomName", this.o);
}
return nbttagcompound;
}
public int getSize() {
return this.items.size();
}
public ItemStack splitStack(int i, int j) {
this.d((EntityHuman) null);
ItemStack itemstack = ContainerUtil.a(this.q(), i, j);
return itemstack;
}
public void setItem(int i, ItemStack itemstack) {
this.d((EntityHuman) null);
this.q().set(i, itemstack);
if (itemstack.getCount() > this.getMaxStackSize()) {
itemstack.setCount(this.getMaxStackSize());
}
}
public String getName() {
return this.hasCustomName() ? this.o : "container.hopper";
}
public int getMaxStackSize() {
return maxStack; // CraftBukkit
}
public void e() {
if (this.world != null && !this.world.isClientSide) {
--this.f;
this.g = this.world.getTime();
if (!this.J()) {
this.setCooldown(0);
// Spigot start
if (!this.o() && this.world.spigotConfig.hopperCheck > 1) {
this.setCooldown(this.world.spigotConfig.hopperCheck);
}
// Spigot end
}
}
}
private boolean o() {
mayAcceptItems = false; // Paper - at the beginning of a tick, assume we can't accept items
if (this.world != null && !this.world.isClientSide) {
if (!this.J() && BlockHopper.f(this.v())) {
boolean flag = false;
if (!this.p()) {
flag = this.s();
}
if (!this.r()) {
mayAcceptItems = true; // Paper - flag this hopper to be able to accept items
flag = a((IHopper) this) || flag;
}
if (flag) {
this.setCooldown(world.spigotConfig.hopperTransfer); // Spigot
this.update();
return true;
}
}
return false;
} else {
return false;
}
}
// Paper start
private boolean mayAcceptItems = false;
public boolean canAcceptItems() {
return mayAcceptItems;
}
// Paper end
private boolean p() {
Iterator iterator = this.items.iterator();
ItemStack itemstack;
do {
if (!iterator.hasNext()) {
return true;
}
itemstack = (ItemStack) iterator.next();
} while (itemstack.isEmpty());
return false;
}
public boolean x_() {
return this.p();
}
private boolean r() {
Iterator iterator = this.items.iterator();
ItemStack itemstack;
do {
if (!iterator.hasNext()) {
return true;
}
itemstack = (ItemStack) iterator.next();
} while (!itemstack.isEmpty() && itemstack.getCount() == itemstack.getMaxStackSize());
return false;
}
// Paper start - Optimize Hoppers
private static boolean skipPullModeEventFire = false;
private static boolean skipPushModeEventFire = false;
static boolean skipHopperEvents = false;
private boolean hopperPush(IInventory iinventory, EnumDirection enumdirection) {
skipPushModeEventFire = skipHopperEvents;
boolean foundItem = false;
for (int i = 0; i < this.getSize(); ++i) {
if (!this.getItem(i).isEmpty()) {
foundItem = true;
ItemStack origItemStack = this.getItem(i);
ItemStack itemstack = origItemStack;
final int origCount = origItemStack.getCount();
final int moved = Math.min(world.spigotConfig.hopperAmount, origCount);
origItemStack.setCount(moved);
// We only need to fire the event once to give protection plugins a chance to cancel this event
// Because nothing uses getItem, every event call should end up the same result.
if (!skipPushModeEventFire) {
itemstack = callPushMoveEvent(iinventory, itemstack);
if (itemstack == null) { // cancelled
origItemStack.setCount(origCount);
return false;
}
}
final ItemStack itemstack2 = addItem(this, iinventory, itemstack, enumdirection);
final int remaining = itemstack2.getCount();
if (remaining != moved) {
origItemStack = origItemStack.cloneItemStack();
origItemStack.setCount(origCount - moved + remaining);
this.setItem(i, origItemStack);
iinventory.update();
return true;
}
origItemStack.setCount(origCount);
}
}
if (foundItem && world.paperConfig.cooldownHopperWhenFull) { // Inventory was full - cooldown
this.setCooldown(world.spigotConfig.hopperTransfer);
}
return false;
}
private static boolean hopperPull(IHopper ihopper, IInventory iinventory, int i) {
ItemStack origItemStack = iinventory.getItem(i);
ItemStack itemstack = origItemStack;
final int origCount = origItemStack.getCount();
final World world = ihopper.getWorld();
final int moved = Math.min(world.spigotConfig.hopperAmount, origCount);
itemstack.setCount(moved);
if (!skipPullModeEventFire) {
itemstack = callPullMoveEvent(ihopper, iinventory, itemstack);
if (itemstack == null) { // cancelled
origItemStack.setCount(origCount);
// Drastically improve performance by returning true.
// No plugin could of relied on the behavior of false as the other call
// site for IMIE did not exhibit the same behavior
return true;
}
}
final ItemStack itemstack2 = addItem(iinventory, ihopper, itemstack, null);
final int remaining = itemstack2.getCount();
if (remaining != moved) {
origItemStack = origItemStack.cloneItemStack();
origItemStack.setCount(origCount - moved + remaining);
IGNORE_TILE_UPDATES = true;
iinventory.setItem(i, origItemStack);
IGNORE_TILE_UPDATES = false;
iinventory.update();
return true;
}
origItemStack.setCount(origCount);
if (world.paperConfig.cooldownHopperWhenFull) {
cooldownHopper(ihopper);
}
return false;
}
private ItemStack callPushMoveEvent(IInventory iinventory, ItemStack itemstack) {
Inventory destinationInventory = getInventory(iinventory);
InventoryMoveItemEvent event = new InventoryMoveItemEvent(this.getOwner(false).getInventory(),
CraftItemStack.asCraftMirror(itemstack), destinationInventory, true);
boolean result = event.callEvent();
if (!event.calledGetItem && !event.calledSetItem) {
skipPushModeEventFire = true;
}
if (!result) {
cooldownHopper(this);
return null;
}
if (event.calledSetItem) {
return CraftItemStack.asNMSCopy(event.getItem());
} else {
return itemstack;
}
}
private static ItemStack callPullMoveEvent(IHopper hopper, IInventory iinventory, ItemStack itemstack) {
Inventory sourceInventory = getInventory(iinventory);
Inventory destination = getInventory(hopper);
InventoryMoveItemEvent event = new InventoryMoveItemEvent(sourceInventory,
// Mirror is safe as we no plugins ever use this item
CraftItemStack.asCraftMirror(itemstack), destination, false);
boolean result = event.callEvent();
if (!event.calledGetItem && !event.calledSetItem) {
skipPullModeEventFire = true;
}
if (!result) {
cooldownHopper(hopper);
return null;
}
if (event.calledSetItem) {
return CraftItemStack.asNMSCopy(event.getItem());
} else {
return itemstack;
}
}
private static Inventory getInventory(IInventory iinventory) {
Inventory sourceInventory;// Have to special case large chests as they work oddly
if (iinventory instanceof InventoryLargeChest) {
sourceInventory = new org.bukkit.craftbukkit.inventory.CraftInventoryDoubleChest((InventoryLargeChest) iinventory);
} else if (iinventory instanceof TileEntity) {
sourceInventory = ((TileEntity) iinventory).getOwner(false).getInventory();
} else {
sourceInventory = iinventory.getOwner().getInventory();
}
return sourceInventory;
}
private static void cooldownHopper(IHopper hopper) {
if (hopper instanceof TileEntityHopper) {
((TileEntityHopper) hopper).setCooldown(hopper.getWorld().spigotConfig.hopperTransfer);
} else if (hopper instanceof EntityMinecartHopper) {
((EntityMinecartHopper) hopper).setCooldown(hopper.getWorld().spigotConfig.hopperTransfer / 2);
}
}
// Paper end
private boolean s() {
IInventory iinventory = this.I();
if (iinventory == null) {
return false;
} else {
EnumDirection enumdirection = BlockHopper.b(this.v()).opposite();
if (this.a(iinventory, enumdirection)) {
return false;
} else {
return hopperPush(iinventory, enumdirection); /* // Paper - disable rest
for (int i = 0; i < this.getSize(); ++i) {
if (!this.getItem(i).isEmpty()) {
ItemStack itemstack = this.getItem(i).cloneItemStack();
// ItemStack itemstack1 = addItem(this, iinventory, this.splitStack(i, 1), enumdirection);
// CraftBukkit start - Call event when pushing items into other inventories
CraftItemStack oitemstack = CraftItemStack.asCraftMirror(this.splitStack(i, world.spigotConfig.hopperAmount)); // Spigot
Inventory destinationInventory;
// Have to special case large chests as they work oddly
if (iinventory instanceof InventoryLargeChest) {
destinationInventory = new org.bukkit.craftbukkit.inventory.CraftInventoryDoubleChest((InventoryLargeChest) iinventory);
} else {
destinationInventory = iinventory.getOwner().getInventory();
}
InventoryMoveItemEvent event = new InventoryMoveItemEvent(this.getOwner().getInventory(), oitemstack.clone(), destinationInventory, true);
this.getWorld().getServer().getPluginManager().callEvent(event);
if (event.isCancelled()) {
this.setItem(i, itemstack);
this.setCooldown(world.spigotConfig.hopperTransfer); // Spigot
return false;
}
int origCount = event.getItem().getAmount(); // Spigot
ItemStack itemstack1 = addItem(this, iinventory, CraftItemStack.asNMSCopy(event.getItem()), enumdirection);
if (itemstack1.isEmpty()) {
if (event.getItem().equals(oitemstack)) {
iinventory.update();
} else {
this.setItem(i, itemstack);
}
// CraftBukkit end
return true;
}
itemstack.subtract(origCount - itemstack1.getCount()); // Spigot
this.setItem(i, itemstack);
}
}
return false;*/ // Paper - end commenting out replaced block for Hopper Optimizations
}
}
}
private boolean a(IInventory iinventory, EnumDirection enumdirection) {
if (iinventory instanceof IWorldInventory) {
IWorldInventory iworldinventory = (IWorldInventory) iinventory;
int[] aint = iworldinventory.getSlotsForFace(enumdirection);
int[] aint1 = aint;
int i = aint.length;
for (int j = 0; j < i; ++j) {
int k = aint1[j];
ItemStack itemstack = iworldinventory.getItem(k);
if (itemstack.isEmpty() || itemstack.getCount() != itemstack.getMaxStackSize()) {
return false;
}
}
} else {
int l = iinventory.getSize();
for (int i1 = 0; i1 < l; ++i1) {
ItemStack itemstack1 = iinventory.getItem(i1);
if (itemstack1.isEmpty() || itemstack1.getCount() != itemstack1.getMaxStackSize()) {
return false;
}
}
}
return true;
}
private static boolean b(IInventory iinventory, EnumDirection enumdirection) {
if (iinventory instanceof IWorldInventory) {
IWorldInventory iworldinventory = (IWorldInventory) iinventory;
int[] aint = iworldinventory.getSlotsForFace(enumdirection);
int[] aint1 = aint;
int i = aint.length;
for (int j = 0; j < i; ++j) {
int k = aint1[j];
if (!iworldinventory.getItem(k).isEmpty()) {
return false;
}
}
} else {
int l = iinventory.getSize();
for (int i1 = 0; i1 < l; ++i1) {
if (!iinventory.getItem(i1).isEmpty()) {
return false;
}
}
}
return true;
}
// Paper start - split methods, and only do entity lookup if in pull mode
public static boolean a(IHopper ihopper) {
IInventory iinventory = getInventory(ihopper, !(ihopper instanceof TileEntityHopper) || !ihopper.getWorld().paperConfig.isHopperPushBased);
return acceptItem(ihopper, iinventory);
}
public static boolean acceptItem(IHopper ihopper, IInventory iinventory) {
// Paper end
if (iinventory != null) {
EnumDirection enumdirection = EnumDirection.DOWN;
if (b(iinventory, enumdirection)) {
return false;
}
skipPullModeEventFire = skipHopperEvents; // Paper
if (iinventory instanceof IWorldInventory) {
IWorldInventory iworldinventory = (IWorldInventory) iinventory;
int[] aint = iworldinventory.getSlotsForFace(enumdirection);
int[] aint1 = aint;
int i = aint.length;
for (int j = 0; j < i; ++j) {
int k = aint1[j];
if (a(ihopper, iinventory, k, enumdirection)) {
return true;
}
}
} else {
int l = iinventory.getSize();
for (int i1 = 0; i1 < l; ++i1) {
if (a(ihopper, iinventory, i1, enumdirection)) {
return true;
}
}
}
} else if (!ihopper.getWorld().paperConfig.isHopperPushBased || !(ihopper instanceof TileEntityHopper)) { // Paper - only search for entities in 'pull mode'
Iterator iterator = a(ihopper.getWorld(), ihopper.E(), ihopper.F(), ihopper.G()).iterator(); // Change getHopperLookupBoundingBox() if this ever changes
while (iterator.hasNext()) {
EntityItem entityitem = (EntityItem) iterator.next();
if (a((IInventory) null, ihopper, entityitem)) {
return true;
}
}
}
return false;
}
private static boolean a(IHopper ihopper, IInventory iinventory, int i, EnumDirection enumdirection) {
ItemStack itemstack = iinventory.getItem(i);
if (!itemstack.isEmpty() && b(iinventory, itemstack, i, enumdirection)) {
return hopperPull(ihopper, iinventory, i); /* // Paper - disable rest
ItemStack itemstack1 = itemstack.cloneItemStack();
// ItemStack itemstack2 = addItem(iinventory, ihopper, iinventory.splitStack(i, 1), (EnumDirection) null);
// CraftBukkit start - Call event on collection of items from inventories into the hopper
CraftItemStack oitemstack = CraftItemStack.asCraftMirror(iinventory.splitStack(i, ihopper.getWorld().spigotConfig.hopperAmount)); // Spigot
Inventory sourceInventory;
// Have to special case large chests as they work oddly
if (iinventory instanceof InventoryLargeChest) {
sourceInventory = new org.bukkit.craftbukkit.inventory.CraftInventoryDoubleChest((InventoryLargeChest) iinventory);
} else {
sourceInventory = iinventory.getOwner().getInventory();
}
InventoryMoveItemEvent event = new InventoryMoveItemEvent(sourceInventory, oitemstack.clone(), ihopper.getOwner().getInventory(), false);
ihopper.getWorld().getServer().getPluginManager().callEvent(event);
if (event.isCancelled()) {
iinventory.setItem(i, itemstack1);
if (ihopper instanceof TileEntityHopper) {
((TileEntityHopper) ihopper).setCooldown(ihopper.getWorld().spigotConfig.hopperTransfer); // Spigot
} else if (ihopper instanceof EntityMinecartHopper) {
((EntityMinecartHopper) ihopper).setCooldown(ihopper.getWorld().spigotConfig.hopperTransfer / 2); // Spigot
}
return false;
}
int origCount = event.getItem().getAmount(); // Spigot
ItemStack itemstack2 = addItem(iinventory, ihopper, CraftItemStack.asNMSCopy(event.getItem()), null);
if (itemstack2.isEmpty()) {
if (event.getItem().equals(oitemstack)) {
iinventory.update();
} else {
iinventory.setItem(i, itemstack1);
}
// CraftBukkit end
return true;
}
itemstack1.subtract(origCount - itemstack2.getCount()); // Spigot
iinventory.setItem(i, itemstack1);*/ // Paper - end commenting out replaced block for Hopper Optimizations
}
return false;
}
public static boolean putDropInInventory(IInventory iinventory, IInventory iinventory1, EntityItem entityitem) { return a(iinventory, iinventory1, entityitem); } // Paper - OBFHELPER
public static boolean a(IInventory iinventory, IInventory iinventory1, EntityItem entityitem) {
boolean flag = false;
if (entityitem == null) {
return false;
} else {
// CraftBukkit start
InventoryPickupItemEvent event = new InventoryPickupItemEvent(getInventory(iinventory1), (org.bukkit.entity.Item) entityitem.getBukkitEntity()); // Paper - avoid snapshot creation
entityitem.world.getServer().getPluginManager().callEvent(event);
if (event.isCancelled()) {
return false;
}
// CraftBukkit end
ItemStack itemstack = entityitem.getItemStack().cloneItemStack();
ItemStack itemstack1 = addItem(iinventory, iinventory1, itemstack, (EnumDirection) null);
if (itemstack1.isEmpty()) {
flag = true;
entityitem.die();
} else {
entityitem.setItemStack(itemstack1);
}
return flag;
}
}
public static ItemStack addItem(IInventory iinventory, IInventory iinventory1, ItemStack itemstack, @Nullable EnumDirection enumdirection) {
if (iinventory1 instanceof IWorldInventory && enumdirection != null) {
IWorldInventory iworldinventory = (IWorldInventory) iinventory1;
int[] aint = iworldinventory.getSlotsForFace(enumdirection);
for (int i = 0; i < aint.length && !itemstack.isEmpty(); ++i) {
itemstack = a(iinventory, iinventory1, itemstack, aint[i], enumdirection);
}
} else {
int j = iinventory1.getSize();
for (int k = 0; k < j && !itemstack.isEmpty(); ++k) {
itemstack = a(iinventory, iinventory1, itemstack, k, enumdirection);
}
}
return itemstack;
}
private static boolean a(IInventory iinventory, ItemStack itemstack, int i, EnumDirection enumdirection) {
return !iinventory.b(i, itemstack) ? false : !(iinventory instanceof IWorldInventory) || ((IWorldInventory) iinventory).canPlaceItemThroughFace(i, itemstack, enumdirection);
}
private static boolean b(IInventory iinventory, ItemStack itemstack, int i, EnumDirection enumdirection) {
return !(iinventory instanceof IWorldInventory) || ((IWorldInventory) iinventory).canTakeItemThroughFace(i, itemstack, enumdirection);
}
private static ItemStack a(IInventory iinventory, IInventory iinventory1, ItemStack itemstack, int i, EnumDirection enumdirection) {
ItemStack itemstack1 = iinventory1.getItem(i);
if (a(iinventory1, itemstack, i, enumdirection)) {
boolean flag = false;
boolean flag1 = iinventory1.x_();
if (itemstack1.isEmpty()) {
IGNORE_TILE_UPDATES = true; // Paper
iinventory1.setItem(i, itemstack);
IGNORE_TILE_UPDATES = false; // Paper
itemstack = ItemStack.a;
flag = true;
} else if (a(itemstack1, itemstack)) {
int j = itemstack.getMaxStackSize() - itemstack1.getCount();
int k = Math.min(itemstack.getCount(), j);
itemstack.subtract(k);
itemstack1.add(k);
flag = k > 0;
}
if (flag) {
if (flag1 && iinventory1 instanceof TileEntityHopper) {
TileEntityHopper tileentityhopper = (TileEntityHopper) iinventory1;
if (!tileentityhopper.K()) {
byte b0 = 0;
if (iinventory != null && iinventory instanceof TileEntityHopper) {
TileEntityHopper tileentityhopper1 = (TileEntityHopper) iinventory;
if (tileentityhopper.g >= tileentityhopper1.g) {
b0 = 1;
}
}
tileentityhopper.setCooldown(tileentityhopper.world.spigotConfig.hopperTransfer - b0); // Spigot
}
}
iinventory1.update();
}
}
return itemstack;
}
private IInventory I() {
EnumDirection enumdirection = BlockHopper.b(this.v());
// Paper start - don't search for entities in push mode
World world = getWorld();
return getInventory(world, this.E() + (double) enumdirection.getAdjacentX(), this.F() + (double) enumdirection.getAdjacentY(), this.G() + (double) enumdirection.getAdjacentZ(), !world.paperConfig.isHopperPushBased);
// Paper end
}
// Paper start - add option to search for entities
public static IInventory b(IHopper hopper) {
return getInventory(hopper, true);
}
public static IInventory getInventory(IHopper ihopper, boolean searchForEntities) {
return getInventory(ihopper.getWorld(), ihopper.E(), ihopper.F() + 1.0D, ihopper.G(), searchForEntities);
// Paper end
}
public static List<EntityItem> a(World world, double d0, double d1, double d2) {
return world.a(EntityItem.class, new AxisAlignedBB(d0 - 0.5D, d1, d2 - 0.5D, d0 + 0.5D, d1 + 1.5D, d2 + 0.5D), IEntitySelector.a); // Change getHopperLookupBoundingBox(double, double, double) if the bounding box calculation is ever changed
}
// Paper start
public AxisAlignedBB getHopperLookupBoundingBox() {
return getHopperLookupBoundingBox(this.getX(), this.getY(), this.getZ());
}
private static AxisAlignedBB getHopperLookupBoundingBox(double d0, double d1, double d2) {
// Change this if a(World, double, double, double) above ever changes
return new AxisAlignedBB(d0 - 0.5D, d1, d2 - 0.5D, d0 + 0.5D, d1 + 1.5D, d2 + 0.5D);
}
// Paper end
// Paper start - add option to searchForEntities
public static IInventory b(World world, double d0, double d1, double d2) {
return getInventory(world, d0, d1, d2, true);
}
public static IInventory getInventory(World world, double d0, double d1, double d2, boolean searchForEntities) {
// Paper end
Object object = null;
int i = MathHelper.floor(d0);
int j = MathHelper.floor(d1);
int k = MathHelper.floor(d2);
BlockPosition blockposition = new BlockPosition(i, j, k);
if ( !world.isLoaded( blockposition ) ) return null; // Spigot
Block block = world.getType(blockposition).getBlock();
if (block.isTileEntity()) {
TileEntity tileentity = world.getTileEntity(blockposition);
if (tileentity instanceof IInventory) {
object = (IInventory) tileentity;
if (object instanceof TileEntityChest && block instanceof BlockChest) {
object = ((BlockChest) block).a(world, blockposition, true);
}
}
}
net.minecraft.server.Chunk chunk = world.getChunkAtWorldCoords(blockposition);
if (object == null && searchForEntities && !org.bukkit.craftbukkit.util.CraftMagicNumbers.getMaterial(block).isOccluding() && chunk.getItemCount(blockposition) > 0) { // Paper - only if searchForEntities
List list = world.getEntities((Entity) null, new AxisAlignedBB(d0 - 0.5D, d1 - 0.5D, d2 - 0.5D, d0 + 0.5D, d1 + 0.5D, d2 + 0.5D), IEntitySelector.c);
if (!list.isEmpty()) {
object = (IInventory) list.get(world.random.nextInt(list.size()));
}
}
return (IInventory) object;
}
private static boolean a(ItemStack itemstack, ItemStack itemstack1) {
return itemstack.getItem() != itemstack1.getItem() ? false : (itemstack.getData() != itemstack1.getData() ? false : (itemstack.getCount() > itemstack.getMaxStackSize() ? false : ItemStack.equals(itemstack, itemstack1)));
}
public double E() {
return (double) this.position.getX() + 0.5D;
}
public double F() {
return (double) this.position.getY() + 0.5D;
}
public double G() {
return (double) this.position.getZ() + 0.5D;
}
private void setCooldown(int i) {
this.f = i;
}
private boolean J() {
return this.f > 0;
}
private boolean K() {
return this.f > 8;
}
public String getContainerName() {
return "minecraft:hopper";
}
public Container createContainer(PlayerInventory playerinventory, EntityHuman entityhuman) {
this.d(entityhuman);
return new ContainerHopper(playerinventory, this, entityhuman);
}
protected NonNullList<ItemStack> q() {
return this.items;
}
}

View File

@@ -587,7 +587,9 @@ public abstract class World implements IBlockAccess {
public void a(BlockPosition blockposition, final Block block, BlockPosition blockposition1) { public void a(BlockPosition blockposition, final Block block, BlockPosition blockposition1) {
if (!this.isClientSide) { if (!this.isClientSide) {
IBlockData iblockdata = this.getType(blockposition); //IBlockData iblockdata = this.getType(blockposition);
IBlockData iblockdata = this.getTypeIfLoaded(blockposition); // NeonPaper Don't load chunks for physics
if (iblockdata == null) return; // NeonPaper Don't load chunks for physics
try { try {
// CraftBukkit start // CraftBukkit start
@@ -697,7 +699,7 @@ public abstract class World implements IBlockAccess {
if (blockposition.getY() >= 256) { if (blockposition.getY() >= 256) {
blockposition = new BlockPosition(blockposition.getX(), 255, blockposition.getZ()); blockposition = new BlockPosition(blockposition.getX(), 255, blockposition.getZ());
} }
if (!this.isLoaded(blockposition)) return 0; // Paper
return this.getChunkAtWorldCoords(blockposition).a(blockposition, 0); return this.getChunkAtWorldCoords(blockposition).a(blockposition, 0);
} }
} }
@@ -1891,7 +1893,7 @@ public abstract class World implements IBlockAccess {
for (int i = 0; i < list.size(); ++i) { for (int i = 0; i < list.size(); ++i) {
Entity entity1 = (Entity) list.get(i); Entity entity1 = (Entity) list.get(i);
if (!entity1.dead && entity1.i && entity1 != entity && (entity == null || entity1.x(entity))) { if (!entity1.dead && entity1.i && entity1 != entity && (entity == null || !entity1.x(entity))) { // Reaper - Fix MC-103516
return false; return false;
} }
} }

View File

@@ -0,0 +1,101 @@
package net.minecraft.server;
import java.util.Iterator;
import javax.annotation.Nullable;
public class WorldManager implements IWorldAccess {
private final MinecraftServer a;
private final WorldServer world;
public WorldManager(MinecraftServer minecraftserver, WorldServer worldserver) {
this.a = minecraftserver;
this.world = worldserver;
}
public void a(int i, boolean flag, double d0, double d1, double d2, double d3, double d4, double d5, int... aint) {}
public void a(int i, boolean flag, boolean flag1, double d0, double d1, double d2, double d3, double d4, double d5, int... aint) {}
public void a(Entity entity) {
this.world.getTracker().track(entity);
if (entity instanceof EntityPlayer) {
this.world.worldProvider.a((EntityPlayer) entity);
}
}
public void b(Entity entity) {
this.world.getTracker().untrackEntity(entity);
this.world.getScoreboard().a(entity);
if (entity instanceof EntityPlayer) {
this.world.worldProvider.b((EntityPlayer) entity);
}
}
public void a(@Nullable EntityHuman entityhuman, SoundEffect soundeffect, SoundCategory soundcategory, double d0, double d1, double d2, float f, float f1) {
// CraftBukkit - this.world.dimension, // Paper - this.world.dimension -> this.world
this.a.getPlayerList().sendPacketNearby(entityhuman, d0, d1, d2, f > 1.0F ? (double) (16.0F * f) : 16.0D, this.world, new PacketPlayOutNamedSoundEffect(soundeffect, soundcategory, d0, d1, d2, f, f1));
}
public void a(int i, int j, int k, int l, int i1, int j1) {}
public void a(World world, BlockPosition blockposition, IBlockData iblockdata, IBlockData iblockdata1, int i) {
this.world.getPlayerChunkMap().flagDirty(blockposition);
}
public void a(BlockPosition blockposition) {}
public void a(SoundEffect soundeffect, BlockPosition blockposition) {}
public void a(EntityHuman entityhuman, int i, BlockPosition blockposition, int j) {
// CraftBukkit - this.world.dimension
this.a.getPlayerList().sendPacketNearby(entityhuman, (double) blockposition.getX(), (double) blockposition.getY(), (double) blockposition.getZ(), 64.0D, this.world, new PacketPlayOutWorldEvent(i, blockposition, j, false));
}
public void a(int i, BlockPosition blockposition, int j) {
this.a.getPlayerList().sendAll(new PacketPlayOutWorldEvent(i, blockposition, j, true));
}
public void b(int i, BlockPosition blockposition, int j) {
// Iterator iterator = this.a.getPlayerList().v().iterator(); // Paper
// CraftBukkit start
EntityHuman entityhuman = null;
Entity entity = world.getEntity(i);
if (entity instanceof EntityHuman) entityhuman = (EntityHuman) entity;
// CraftBukkit end
// Paper start
java.util.List<? extends EntityHuman> list = entity != null ? entity.world.players : this.a.getPlayerList().v();
Iterator<? extends EntityHuman> iterator = list.iterator();
PacketPlayOutBlockBreakAnimation packet = null; // NeonPaper - cache packet
while (iterator.hasNext()) {
EntityHuman human = iterator.next();
if (!(human instanceof EntityPlayer)) continue;
EntityPlayer entityplayer = (EntityPlayer) human;
// Paper end
if (entityplayer != null && entityplayer.world == this.world && entityplayer.getId() != i) {
double d0 = (double) blockposition.getX() - entityplayer.locX;
double d1 = (double) blockposition.getY() - entityplayer.locY;
double d2 = (double) blockposition.getZ() - entityplayer.locZ;
// CraftBukkit start
if (entityhuman != null && entityhuman instanceof EntityPlayer && !entityplayer.getBukkitEntity().canSee(((EntityPlayer) entityhuman).getBukkitEntity())) {
continue;
}
// CraftBukkit end
if (d0 * d0 + d1 * d1 + d2 * d2 < 1024.0D) {
// NeonPaper start
if (packet == null) packet = new PacketPlayOutBlockBreakAnimation(i, blockposition, j);
entityplayer.playerConnection.sendPacket(packet);
// NeonPaper end
}
}
}
}
}

View File

@@ -0,0 +1,317 @@
package org.bukkit.craftbukkit;
import java.lang.ref.WeakReference;
import java.util.Arrays;
import java.util.Random;
import net.minecraft.server.*;
import org.bukkit.Chunk;
import org.bukkit.World;
import org.bukkit.block.Block;
import org.bukkit.block.BlockState;
import org.bukkit.craftbukkit.block.CraftBlock;
import org.bukkit.entity.Entity;
import org.bukkit.ChunkSnapshot;
public class CraftChunk implements Chunk {
private WeakReference<net.minecraft.server.Chunk> weakChunk;
private final WorldServer worldServer;
private final int x;
private final int z;
private static final byte[] emptyData = new byte[2048];
private static final short[] emptyBlockIDs = new short[4096];
private static final byte[] emptySkyLight = new byte[2048];
public CraftChunk(net.minecraft.server.Chunk chunk) {
this.weakChunk = new WeakReference<net.minecraft.server.Chunk>(chunk);
worldServer = (WorldServer) getHandle().world;
x = getHandle().locX;
z = getHandle().locZ;
}
public World getWorld() {
return worldServer.getWorld();
}
public CraftWorld getCraftWorld() {
return (CraftWorld) getWorld();
}
public net.minecraft.server.Chunk getHandle() {
net.minecraft.server.Chunk c = weakChunk.get();
if (c == null) {
c = worldServer.getChunkAt(x, z);
weakChunk = new WeakReference<net.minecraft.server.Chunk>(c);
}
return c;
}
void breakLink() {
weakChunk.clear();
}
public int getX() {
return x;
}
public int getZ() {
return z;
}
@Override
public String toString() {
return "CraftChunk{" + "x=" + getX() + "z=" + getZ() + '}';
}
public Block getBlock(int x, int y, int z) {
return new CraftBlock(this, (getX() << 4) | (x & 0xF), y, (getZ() << 4) | (z & 0xF));
}
public Entity[] getEntities() {
int count = 0, index = 0;
net.minecraft.server.Chunk chunk = getHandle();
for (int i = 0; i < 16; i++) {
count += chunk.entitySlices[i].size();
}
Entity[] entities = new Entity[count];
for (int i = 0; i < 16; i++) {
//for (Object obj : chunk.entitySlices[i].toArray()) {
// if (!(obj instanceof net.minecraft.server.Entity)) {
// NeonPaper start - speed up (was with chunk.entitySlices[i].toArray() and cast checks which costs a lot of performance if called often)
for (net.minecraft.server.Entity entity : chunk.entitySlices[i]) {
if (entity == null) {
continue;
}
//entities[index++] = ((net.minecraft.server.Entity) obj).getBukkitEntity();
entities[index++] = entity.getBukkitEntity();
}
//NeonPaper end
}
return entities;
}
public BlockState[] getTileEntities() {
int index = 0;
net.minecraft.server.Chunk chunk = getHandle();
BlockState[] entities = new BlockState[chunk.tileEntities.size()];
for (Object obj : chunk.tileEntities.keySet().toArray()) {
if (!(obj instanceof BlockPosition)) {
continue;
}
BlockPosition position = (BlockPosition) obj;
entities[index++] = worldServer.getWorld().getBlockAt(position.getX(), position.getY(), position.getZ()).getState();
}
return entities;
}
public boolean isLoaded() {
return getWorld().isChunkLoaded(this);
}
public boolean load() {
return getWorld().loadChunk(getX(), getZ(), true);
}
public boolean load(boolean generate) {
return getWorld().loadChunk(getX(), getZ(), generate);
}
public boolean unload() {
return getWorld().unloadChunk(getX(), getZ());
}
@Override
public boolean isSlimeChunk() {
// 987234911L is deterimined in EntitySlime when seeing if a slime can spawn in a chunk
return getHandle().a(worldServer.spigotConfig.slimeSeed).nextInt(10) == 0;
}
public boolean unload(boolean save) {
return getWorld().unloadChunk(getX(), getZ(), save);
}
public boolean unload(boolean save, boolean safe) {
return getWorld().unloadChunk(getX(), getZ(), save, safe);
}
public ChunkSnapshot getChunkSnapshot() {
return getChunkSnapshot(true, false, false);
}
public ChunkSnapshot getChunkSnapshot(boolean includeMaxBlockY, boolean includeBiome, boolean includeBiomeTempRain) {
net.minecraft.server.Chunk chunk = getHandle();
ChunkSection[] cs = chunk.getSections();
short[][] sectionBlockIDs = new short[cs.length][];
byte[][] sectionBlockData = new byte[cs.length][];
byte[][] sectionSkyLights = new byte[cs.length][];
byte[][] sectionEmitLights = new byte[cs.length][];
boolean[] sectionEmpty = new boolean[cs.length];
for (int i = 0; i < cs.length; i++) {
if (cs[i] == null) { // Section is empty?
sectionBlockIDs[i] = emptyBlockIDs;
sectionBlockData[i] = emptyData;
sectionSkyLights[i] = emptySkyLight;
sectionEmitLights[i] = emptyData;
sectionEmpty[i] = true;
} else { // Not empty
short[] blockids = new short[4096];
byte[] rawIds = new byte[4096];
NibbleArray data = new NibbleArray();
cs[i].getBlocks().exportData(rawIds, data);
byte[] dataValues = sectionBlockData[i] = data.asBytes();
// Copy base IDs
for (int j = 0; j < 4096; j++) {
blockids[j] = (short) (rawIds[j] & 0xFF);
}
sectionBlockIDs[i] = blockids;
if (cs[i].getSkyLightArray() == null) {
sectionSkyLights[i] = emptyData;
} else {
sectionSkyLights[i] = new byte[2048];
System.arraycopy(cs[i].getSkyLightArray().asBytes(), 0, sectionSkyLights[i], 0, 2048);
}
sectionEmitLights[i] = new byte[2048];
System.arraycopy(cs[i].getEmittedLightArray().asBytes(), 0, sectionEmitLights[i], 0, 2048);
}
}
int[] hmap = null;
if (includeMaxBlockY) {
hmap = new int[256]; // Get copy of height map
System.arraycopy(chunk.heightMap, 0, hmap, 0, 256);
}
BiomeBase[] biome = null;
double[] biomeTemp = null;
double[] biomeRain = null;
if (includeBiome || includeBiomeTempRain) {
WorldChunkManager wcm = chunk.world.getWorldChunkManager();
if (includeBiome) {
biome = new BiomeBase[256];
for (int i = 0; i < 256; i++) {
biome[i] = chunk.getBiome(new BlockPosition(i & 0xF, 0, i >> 4), wcm);
}
}
if (includeBiomeTempRain) {
biomeTemp = new double[256];
biomeRain = new double[256];
float[] dat = getTemperatures(wcm, getX() << 4, getZ() << 4);
for (int i = 0; i < 256; i++) {
biomeTemp[i] = dat[i];
}
/* Removed 15w46a
dat = wcm.getWetness(null, getX() << 4, getZ() << 4, 16, 16);
for (int i = 0; i < 256; i++) {
biomeRain[i] = dat[i];
}
*/
}
}
World world = getWorld();
return new CraftChunkSnapshot(getX(), getZ(), world.getName(), world.getFullTime(), sectionBlockIDs, sectionBlockData, sectionSkyLights, sectionEmitLights, sectionEmpty, hmap, biome, biomeTemp, biomeRain);
}
public static ChunkSnapshot getEmptyChunkSnapshot(int x, int z, CraftWorld world, boolean includeBiome, boolean includeBiomeTempRain) {
BiomeBase[] biome = null;
double[] biomeTemp = null;
double[] biomeRain = null;
if (includeBiome || includeBiomeTempRain) {
WorldChunkManager wcm = world.getHandle().getWorldChunkManager();
if (includeBiome) {
biome = new BiomeBase[256];
for (int i = 0; i < 256; i++) {
biome[i] = world.getHandle().getBiome(new BlockPosition((x << 4) + (i & 0xF), 0, (z << 4) + (i >> 4)));
}
}
if (includeBiomeTempRain) {
biomeTemp = new double[256];
biomeRain = new double[256];
float[] dat = getTemperatures(wcm, x << 4, z << 4);
for (int i = 0; i < 256; i++) {
biomeTemp[i] = dat[i];
}
/* Removed 15w46a
dat = wcm.getWetness(null, x << 4, z << 4, 16, 16);
for (int i = 0; i < 256; i++) {
biomeRain[i] = dat[i];
}
*/
}
}
/* Fill with empty data */
int hSection = world.getMaxHeight() >> 4;
short[][] blockIDs = new short[hSection][];
byte[][] skyLight = new byte[hSection][];
byte[][] emitLight = new byte[hSection][];
byte[][] blockData = new byte[hSection][];
boolean[] empty = new boolean[hSection];
for (int i = 0; i < hSection; i++) {
blockIDs[i] = emptyBlockIDs;
skyLight[i] = emptySkyLight;
emitLight[i] = emptyData;
blockData[i] = emptyData;
empty[i] = true;
}
return new CraftChunkSnapshot(x, z, world.getName(), world.getFullTime(), blockIDs, blockData, skyLight, emitLight, empty, new int[256], biome, biomeTemp, biomeRain);
}
private static float[] getTemperatures(WorldChunkManager chunkmanager, int chunkX, int chunkZ) {
BiomeBase[] biomes = chunkmanager.getBiomes(null, chunkX, chunkZ, 16, 16);
float[] temps = new float[biomes.length];
for (int i = 0; i < biomes.length; i++) {
float temp = biomes[i].getTemperature(); // Vanilla of olde: ((int) biomes[i].temperature * 65536.0F) / 65536.0F
if (temp > 1F) {
temp = 1F;
}
temps[i] = temp;
}
return temps;
}
static {
Arrays.fill(emptySkyLight, (byte) 0xFF);
}
}

View File

@@ -1488,11 +1488,16 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
@Override @Override
public int getNoDamageTicks() { public int getNoDamageTicks() {
if (getHandle().invulnerableTicks > 0) { // TacoSpigot start - fix incorrect calculation of getNoDamageTicks
return Math.max(getHandle().invulnerableTicks, getHandle().noDamageTicks); /*
} else { if (getHandle().invulnerableTicks > 0) {
return getHandle().noDamageTicks; return Math.max(getHandle().invulnerableTicks, getHandle().noDamageTicks);
} } else {
return getHandle().noDamageTicks;
}
*/
return Math.max(getHandle().invulnerableTicks, Math.max(0, getHandle().noDamageTicks - (getHandle().maxNoDamageTicks >> 1)));
// TacoSpigot end
} }
@Override @Override