Compare commits
38 Commits
1.12.2-R0.
...
dependabot
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8a0951bd4c | ||
|
|
7dcfc130d2 | ||
|
|
0e9940771e | ||
|
|
ee8e09fe58 | ||
|
|
b74ec9aa2e | ||
|
|
ea8292aaf9 | ||
|
|
7b47710c42 | ||
|
|
d34531aa84 | ||
|
|
30bb7a43fb | ||
|
|
9a54ba116e | ||
|
|
a3cc630375 | ||
|
|
e5081d4575 | ||
|
|
852acc0d65 | ||
|
|
7e756e786d | ||
|
|
62848df6de | ||
|
|
f5a531a15c | ||
|
|
ba3d1c9672 | ||
|
|
fa08306751 | ||
|
|
9a8d4c35a9 | ||
|
|
adf961666a | ||
|
|
947b22892c | ||
|
|
0d9f04a748 | ||
|
|
26652d43fc | ||
|
|
ac24d10a57 | ||
|
|
f220a6a153 | ||
|
|
233aab099e | ||
|
|
5268e9a55a | ||
|
|
83c30311d0 | ||
|
|
6a7f2b8699 | ||
|
|
cb55572504 | ||
|
|
9d5c535d18 | ||
|
|
b46cddd84d | ||
|
|
936cf720f4 | ||
|
|
9b6412766f | ||
|
|
d847e87c65 | ||
|
|
ff8c0cd3be | ||
|
|
19991463bf | ||
|
|
c2931e362e |
@@ -66,7 +66,7 @@
|
||||
<dependency>
|
||||
<groupId>mysql</groupId>
|
||||
<artifactId>mysql-connector-java</artifactId>
|
||||
<version>5.1.45</version>
|
||||
<version>8.0.28</version>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
|
||||
479
sources/src/main/java/net/minecraft/server/BlockChest.java
Normal file
479
sources/src/main/java/net/minecraft/server/BlockChest.java
Normal 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() {}
|
||||
}
|
||||
}
|
||||
118
sources/src/main/java/net/minecraft/server/BlockStationary.java
Normal file
118
sources/src/main/java/net/minecraft/server/BlockStationary.java
Normal 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
|
||||
}
|
||||
}
|
||||
@@ -1000,7 +1000,6 @@ public class Chunk {
|
||||
|
||||
for (int k = i; k <= j; ++k) {
|
||||
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
|
||||
/*
|
||||
@@ -1011,6 +1010,7 @@ public class Chunk {
|
||||
*/
|
||||
if (predicate == IEntitySelector.c && inventoryEntityCounts[k] <= 0) continue;
|
||||
// Paper end
|
||||
Iterator iterator = this.entitySlices[k].iterator();
|
||||
while (iterator.hasNext()) {
|
||||
Entity entity1 = (Entity) iterator.next();
|
||||
|
||||
@@ -1548,4 +1548,14 @@ public class Chunk {
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
115
sources/src/main/java/net/minecraft/server/ContainerHorse.java
Normal file
115
sources/src/main/java/net/minecraft/server/ContainerHorse.java
Normal 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);
|
||||
}
|
||||
}
|
||||
@@ -118,6 +118,7 @@ public class EnchantmentManager {
|
||||
EnchantmentManager.a.a = 0;
|
||||
EnchantmentManager.a.b = damagesource;
|
||||
a(EnchantmentManager.a, iterable);
|
||||
EnchantmentManager.a.b = null; // Reaper - Fix MC-128547
|
||||
return EnchantmentManager.a.a;
|
||||
}
|
||||
|
||||
@@ -145,6 +146,11 @@ public class EnchantmentManager {
|
||||
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) {
|
||||
@@ -157,7 +163,10 @@ public class EnchantmentManager {
|
||||
if (entityliving instanceof EntityHuman) {
|
||||
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) {
|
||||
|
||||
@@ -45,6 +45,10 @@ import org.bukkit.event.entity.EntityPortalEvent;
|
||||
import org.bukkit.plugin.PluginManager;
|
||||
// CraftBukkit end
|
||||
|
||||
// Dionysus start
|
||||
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
|
||||
// Dionysus end
|
||||
|
||||
/**
|
||||
* Akarin Changes Note
|
||||
* 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 int id;
|
||||
public boolean i; public boolean blocksEntitySpawning() { return i; } // Paper - OBFHELPER
|
||||
public final List<Entity> passengers;
|
||||
public final ObjectArrayList<Entity> passengers; // Dionysus
|
||||
protected int j;
|
||||
private Entity au;public void setVehicle(Entity entity) { this.au = entity; } // Paper // OBFHELPER
|
||||
public boolean attachedToPlayer;
|
||||
@@ -205,7 +209,7 @@ public abstract class Entity implements ICommandListener, KeyedObject { // Paper
|
||||
|
||||
public Entity(World world) {
|
||||
this.id = Entity.entityCount++;
|
||||
this.passengers = Lists.newArrayList();
|
||||
this.passengers = new ObjectArrayList<>(); // Dionysus
|
||||
this.boundingBox = Entity.c;
|
||||
this.width = 0.6F;
|
||||
this.length = 1.8F;
|
||||
@@ -1383,8 +1387,7 @@ public abstract class Entity implements ICommandListener, KeyedObject { // Paper
|
||||
public void d(EntityHuman entityhuman) {}
|
||||
|
||||
public void collide(Entity entity) {
|
||||
if (!this.x(entity)) {
|
||||
if (!entity.noclip && !this.noclip) {
|
||||
if (entity.noclip || this.noclip || this.x(entity)) return; // NeonPaper - Test this earlier
|
||||
double d0 = entity.locX - this.locX;
|
||||
double d1 = entity.locZ - this.locZ;
|
||||
double d2 = MathHelper.a(d0, d1);
|
||||
@@ -1413,9 +1416,6 @@ public abstract class Entity implements ICommandListener, KeyedObject { // Paper
|
||||
entity.f(d0, 0.0D, d1);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void f(double d0, double d1, double d2) {
|
||||
@@ -2881,7 +2881,7 @@ public abstract class Entity implements ICommandListener, KeyedObject { // Paper
|
||||
}
|
||||
|
||||
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) {
|
||||
|
||||
476
sources/src/main/java/net/minecraft/server/EntityEnderman.java
Normal file
476
sources/src/main/java/net/minecraft/server/EntityEnderman.java
Normal 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();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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() {}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -784,7 +784,7 @@ public class EntityPlayer extends EntityHuman implements ICrafting {
|
||||
protected void a(double d0, boolean flag, IBlockData iblockdata, 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);
|
||||
}
|
||||
|
||||
@@ -1156,6 +1156,7 @@ public class EntityPlayer extends EntityHuman implements ICrafting {
|
||||
this.getDataWatcher().set(EntityPlayer.br, entityplayer.getDataWatcher().get(EntityPlayer.br));
|
||||
this.lastSentExp = -1;
|
||||
this.lastHealthSent = -1.0F;
|
||||
setSneaking(false); // NeonPaper - fix MC-10657
|
||||
this.ch = -1;
|
||||
// this.cr.a((RecipeBook) entityplayer.cr); // CraftBukkit
|
||||
// Paper start - Optimize remove queue
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
504
sources/src/main/java/net/minecraft/server/Explosion.java
Normal file
504
sources/src/main/java/net/minecraft/server/Explosion.java
Normal 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
|
||||
}
|
||||
113
sources/src/main/java/net/minecraft/server/IntCache.java
Normal file
113
sources/src/main/java/net/minecraft/server/IntCache.java
Normal 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
|
||||
}
|
||||
367
sources/src/main/java/net/minecraft/server/ItemWorldMap.java
Normal file
367
sources/src/main/java/net/minecraft/server/ItemWorldMap.java
Normal 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
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -365,8 +365,11 @@ public class NetworkManager extends SimpleChannelInboundHandler<Packet<?>> {
|
||||
|
||||
@Override
|
||||
protected void channelRead0(ChannelHandlerContext channelhandlercontext, Packet object) throws Exception { // CraftBukkit - fix decompile error
|
||||
// FlamePaper - Check if channel is opened before reading packet
|
||||
if (isConnected()) {
|
||||
this.a(channelhandlercontext, object);
|
||||
}
|
||||
}
|
||||
|
||||
public static class QueuedPacket { // Akarin - default -> public
|
||||
|
||||
|
||||
@@ -916,6 +916,11 @@ public class PlayerConnection implements PacketListenerPlayIn, ITickable {
|
||||
case START_DESTROY_BLOCK:
|
||||
case ABORT_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 d1 = this.player.locY - ((double) blockposition.getY() + 0.5D) + 1.5D;
|
||||
double d2 = this.player.locZ - ((double) blockposition.getZ() + 0.5D);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -558,9 +558,10 @@ public abstract class PlayerList {
|
||||
Player player = entity.getBukkitEntity();
|
||||
PlayerLoginEvent event = new PlayerLoginEvent(player, hostname, ((java.net.InetSocketAddress) socketaddress).getAddress(), ((java.net.InetSocketAddress) loginlistener.networkManager.getRawAddress()).getAddress());
|
||||
String s;
|
||||
|
||||
if (getProfileBans().isBanned(gameprofile) && !getProfileBans().get(gameprofile).hasExpired()) {
|
||||
GameProfileBanEntry gameprofilebanentry = this.k.get(gameprofile);
|
||||
// NeonPaper start - Fix MC-158900
|
||||
GameProfileBanEntry gameprofilebanentry;
|
||||
if (getProfileBans().isBanned(gameprofile) && (gameprofilebanentry = getProfileBans().get(gameprofile)) != null) {
|
||||
// NeonPaper end
|
||||
|
||||
s = LocaleI18n.a(AkarinGlobalConfig.messageBan,
|
||||
gameprofilebanentry.getReason().equals(Akari.EMPTY_STRING) ? Akari.EMPTY_STRING : AkarinGlobalConfig.messageBanReason + gameprofilebanentry.getReason(),
|
||||
|
||||
356
sources/src/main/java/net/minecraft/server/SpawnerCreature.java
Normal file
356
sources/src/main/java/net/minecraft/server/SpawnerCreature.java
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
784
sources/src/main/java/net/minecraft/server/TileEntityHopper.java
Normal file
784
sources/src/main/java/net/minecraft/server/TileEntityHopper.java
Normal 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;
|
||||
}
|
||||
}
|
||||
@@ -587,7 +587,9 @@ public abstract class World implements IBlockAccess {
|
||||
|
||||
public void a(BlockPosition blockposition, final Block block, BlockPosition blockposition1) {
|
||||
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 {
|
||||
// CraftBukkit start
|
||||
@@ -697,7 +699,7 @@ public abstract class World implements IBlockAccess {
|
||||
if (blockposition.getY() >= 256) {
|
||||
blockposition = new BlockPosition(blockposition.getX(), 255, blockposition.getZ());
|
||||
}
|
||||
|
||||
if (!this.isLoaded(blockposition)) return 0; // Paper
|
||||
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) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
101
sources/src/main/java/net/minecraft/server/WorldManager.java
Normal file
101
sources/src/main/java/net/minecraft/server/WorldManager.java
Normal 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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
317
sources/src/main/java/org/bukkit/craftbukkit/CraftChunk.java
Normal file
317
sources/src/main/java/org/bukkit/craftbukkit/CraftChunk.java
Normal 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);
|
||||
}
|
||||
}
|
||||
@@ -1488,11 +1488,16 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
|
||||
|
||||
@Override
|
||||
public int getNoDamageTicks() {
|
||||
// TacoSpigot start - fix incorrect calculation of getNoDamageTicks
|
||||
/*
|
||||
if (getHandle().invulnerableTicks > 0) {
|
||||
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
|
||||
|
||||
Reference in New Issue
Block a user