Paper/nms-patches/EntityPlayer.patch
Phoenix616 1e76d09fad
#724: Re-implement player portal event search radius and creation API
This also fixes that the nether/end portals would be created even if the
event was cancelled as well as that the EntityPortalEvent would be
called for player portal usage which is not according to its API
specification
2020-08-14 08:26:40 +10:00

984 lines
44 KiB
Diff

--- a/net/minecraft/server/EntityPlayer.java
+++ b/net/minecraft/server/EntityPlayer.java
@@ -15,6 +15,27 @@
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
+// CraftBukkit start
+import org.bukkit.Bukkit;
+import org.bukkit.GameMode;
+import org.bukkit.Location;
+import org.bukkit.WeatherType;
+import org.bukkit.craftbukkit.CraftWorld;
+import org.bukkit.craftbukkit.entity.CraftPlayer;
+import org.bukkit.craftbukkit.event.CraftEventFactory;
+import org.bukkit.craftbukkit.event.CraftPortalEvent;
+import org.bukkit.craftbukkit.inventory.CraftItemStack;
+import org.bukkit.event.inventory.InventoryType;
+import org.bukkit.event.player.PlayerChangedMainHandEvent;
+import org.bukkit.event.player.PlayerChangedWorldEvent;
+import org.bukkit.event.player.PlayerGameModeChangeEvent;
+import org.bukkit.event.player.PlayerLocaleChangeEvent;
+import org.bukkit.event.player.PlayerPortalEvent;
+import org.bukkit.event.player.PlayerTeleportEvent;
+import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause;
+import org.bukkit.inventory.MainHand;
+// CraftBukkit end
+
public class EntityPlayer extends EntityHuman implements ICrafting {
private static final Logger LOGGER = LogManager.getLogger();
@@ -58,6 +79,20 @@
public int ping;
public boolean viewingCredits;
+ // CraftBukkit start
+ public String displayName;
+ public IChatBaseComponent listName;
+ public org.bukkit.Location compassTarget;
+ public int newExp = 0;
+ public int newLevel = 0;
+ public int newTotalExp = 0;
+ public boolean keepLevel = false;
+ public double maxHealthCache;
+ public boolean joining = true;
+ public boolean sentListPacket = false;
+ public Integer clientViewDistance;
+ // CraftBukkit end
+
public EntityPlayer(MinecraftServer minecraftserver, WorldServer worldserver, GameProfile gameprofile, PlayerInteractManager playerinteractmanager) {
super(worldserver, worldserver.getSpawn(), worldserver.v(), gameprofile);
this.spawnDimension = World.OVERWORLD;
@@ -68,12 +103,56 @@
this.advancementDataPlayer = minecraftserver.getPlayerList().f(this);
this.G = 1.0F;
this.c(worldserver);
+
+ // CraftBukkit start
+ this.displayName = this.getName();
+ this.canPickUpLoot = true;
+ this.maxHealthCache = this.getMaxHealth();
+ }
+
+ // Yes, this doesn't match Vanilla, but it's the best we can do for now.
+ // If this is an issue, PRs are welcome
+ public final BlockPosition getSpawnPoint(WorldServer worldserver) {
+ BlockPosition blockposition = worldserver.getSpawn();
+
+ if (worldserver.getDimensionManager().hasSkyLight() && worldserver.worldDataServer.getGameType() != EnumGamemode.ADVENTURE) {
+ int i = Math.max(0, this.server.a(worldserver));
+ int j = MathHelper.floor(worldserver.getWorldBorder().b((double) blockposition.getX(), (double) blockposition.getZ()));
+
+ if (j < i) {
+ i = j;
+ }
+
+ if (j <= 1) {
+ i = 1;
+ }
+
+ long k = (long) (i * 2 + 1);
+ long l = k * k;
+ int i1 = l > 2147483647L ? Integer.MAX_VALUE : (int) l;
+ int j1 = this.u(i1);
+ int k1 = (new Random()).nextInt(i1);
+
+ for (int l1 = 0; l1 < i1; ++l1) {
+ int i2 = (k1 + j1 * l1) % i1;
+ int j2 = i2 % (i * 2 + 1);
+ int k2 = i2 / (i * 2 + 1);
+ BlockPosition blockposition1 = WorldProviderNormal.a(worldserver, blockposition.getX() + j2 - i, blockposition.getZ() + k2 - i, false);
+
+ if (blockposition1 != null) {
+ return blockposition1;
+ }
+ }
+ }
+
+ return blockposition;
}
+ // CraftBukkit end
private void c(WorldServer worldserver) {
BlockPosition blockposition = worldserver.getSpawn();
- if (worldserver.getDimensionManager().hasSkyLight() && worldserver.getMinecraftServer().getSaveData().getGameType() != EnumGamemode.ADVENTURE) {
+ if (worldserver.getDimensionManager().hasSkyLight() && worldserver.worldDataServer.getGameType() != EnumGamemode.ADVENTURE) { // CraftBukkit
int i = Math.max(0, this.server.a(worldserver));
int j = MathHelper.floor(worldserver.getWorldBorder().b((double) blockposition.getX(), (double) blockposition.getZ()));
@@ -139,11 +218,20 @@
if (nbttagcompound.hasKeyOfType("recipeBook", 10)) {
this.recipeBook.a(nbttagcompound.getCompound("recipeBook"), this.server.getCraftingManager());
}
+ this.getBukkitEntity().readExtraData(nbttagcompound); // CraftBukkit
if (this.isSleeping()) {
this.entityWakeup();
}
+ // CraftBukkit start
+ String spawnWorld = nbttagcompound.getString("SpawnWorld");
+ CraftWorld oldWorld = (CraftWorld) Bukkit.getWorld(spawnWorld);
+ if (oldWorld != null) {
+ this.spawnDimension = oldWorld.getHandle().getDimensionKey();
+ }
+ // CraftBukkit end
+
if (nbttagcompound.hasKeyOfType("SpawnX", 99) && nbttagcompound.hasKeyOfType("SpawnY", 99) && nbttagcompound.hasKeyOfType("SpawnZ", 99)) {
this.spawn = new BlockPosition(nbttagcompound.getInt("SpawnX"), nbttagcompound.getInt("SpawnY"), nbttagcompound.getInt("SpawnZ"));
this.spawnForced = nbttagcompound.getBoolean("SpawnForced");
@@ -177,7 +265,20 @@
Entity entity = this.getRootVehicle();
Entity entity1 = this.getVehicle();
- if (entity1 != null && entity != this && entity.hasSinglePlayerPassenger()) {
+ // CraftBukkit start - handle non-persistent vehicles
+ boolean persistVehicle = true;
+ if (entity1 != null) {
+ Entity vehicle;
+ for (vehicle = entity1; vehicle != null; vehicle = vehicle.getVehicle()) {
+ if (!vehicle.persist) {
+ persistVehicle = false;
+ break;
+ }
+ }
+ }
+
+ if (persistVehicle && entity1 != null && entity != this && entity.hasSinglePlayerPassenger()) {
+ // CraftBukkit end
NBTTagCompound nbttagcompound2 = new NBTTagCompound();
NBTTagCompound nbttagcompound3 = new NBTTagCompound();
@@ -195,7 +296,7 @@
nbttagcompound.setInt("SpawnZ", this.spawn.getZ());
nbttagcompound.setBoolean("SpawnForced", this.spawnForced);
nbttagcompound.setFloat("SpawnAngle", this.spawnAngle);
- DataResult dataresult = MinecraftKey.a.encodeStart(DynamicOpsNBT.a, this.spawnDimension.a());
+ DataResult<NBTBase> dataresult = MinecraftKey.a.encodeStart(DynamicOpsNBT.a, this.spawnDimension.a()); // CraftBukkit - decompile error
Logger logger = EntityPlayer.LOGGER;
logger.getClass();
@@ -203,9 +304,33 @@
nbttagcompound.set("SpawnDimension", nbtbase);
});
}
+ this.getBukkitEntity().setExtraData(nbttagcompound); // CraftBukkit
}
+ // CraftBukkit start - World fallback code, either respawn location or global spawn
+ public void spawnIn(World world) {
+ super.spawnIn(world);
+ if (world == null) {
+ this.dead = false;
+ Vec3D position = null;
+ if (this.spawnDimension != null) {
+ world = this.getWorldServer().getServer().getHandle().getServer().getWorldServer(this.spawnDimension);
+ if (world != null && this.getSpawn() != null) {
+ position = EntityHuman.getBed((WorldServer) world, this.getSpawn(), this.getSpawnAngle(), false, false).orElse(null);
+ }
+ }
+ if (world == null || position == null) {
+ world = ((CraftWorld) Bukkit.getServer().getWorlds().get(0)).getHandle();
+ position = Vec3D.a(((WorldServer) world).getSpawn());
+ }
+ this.world = world;
+ this.setPosition(position.getX(), position.getY(), position.getZ());
+ }
+ this.playerInteractManager.a((WorldServer) world);
+ }
+ // CraftBukkit end
+
public void a(int i) {
float f = (float) this.getExpToLevel();
float f1 = (f - 1.0F) / f;
@@ -259,6 +384,11 @@
@Override
public void tick() {
+ // CraftBukkit start
+ if (this.joining) {
+ this.joining = false;
+ }
+ // CraftBukkit end
this.playerInteractManager.a();
--this.invulnerableTicks;
if (this.noDamageTicks > 0) {
@@ -326,7 +456,7 @@
}
if (this.getHealth() != this.lastHealthSent || this.lastFoodSent != this.foodData.getFoodLevel() || this.foodData.getSaturationLevel() == 0.0F != this.lastSentSaturationZero) {
- this.playerConnection.sendPacket(new PacketPlayOutUpdateHealth(this.getHealth(), this.foodData.getFoodLevel(), this.foodData.getSaturationLevel()));
+ this.playerConnection.sendPacket(new PacketPlayOutUpdateHealth(this.getBukkitEntity().getScaledHealth(), this.foodData.getFoodLevel(), this.foodData.getSaturationLevel())); // CraftBukkit
this.lastHealthSent = this.getHealth();
this.lastFoodSent = this.foodData.getFoodLevel();
this.lastSentSaturationZero = this.foodData.getSaturationLevel() == 0.0F;
@@ -357,6 +487,12 @@
this.a(IScoreboardCriteria.XP, MathHelper.f((float) this.lastExpTotalScored));
}
+ // CraftBukkit start - Force max health updates
+ if (this.maxHealthCache != this.getMaxHealth()) {
+ this.getBukkitEntity().updateScaledHealth();
+ }
+ // CraftBukkit end
+
if (this.expLevel != this.lastExpLevelScored) {
this.lastExpLevelScored = this.expLevel;
this.a(IScoreboardCriteria.LEVEL, MathHelper.f((float) this.lastExpLevelScored));
@@ -371,6 +507,16 @@
CriterionTriggers.p.a(this);
}
+ // CraftBukkit start - initialize oldLevel and fire PlayerLevelChangeEvent
+ if (this.oldLevel == -1) {
+ this.oldLevel = this.expLevel;
+ }
+
+ if (this.oldLevel != this.expLevel) {
+ CraftEventFactory.callPlayerLevelChangeEvent(this.world.getServer().getPlayer((EntityPlayer) this), this.oldLevel, this.expLevel);
+ this.oldLevel = this.expLevel;
+ }
+ // CraftBukkit end
} catch (Throwable throwable) {
CrashReport crashreport = CrashReport.a(throwable, "Ticking player");
CrashReportSystemDetails crashreportsystemdetails = crashreport.a("Player being ticked");
@@ -381,7 +527,8 @@
}
private void a(IScoreboardCriteria iscoreboardcriteria, int i) {
- this.getScoreboard().getObjectivesForCriteria(iscoreboardcriteria, this.getName(), (scoreboardscore) -> {
+ // CraftBukkit - Use our scores instead
+ this.world.getServer().getScoreboardManager().getScoreboardScores(iscoreboardcriteria, this.getName(), (scoreboardscore) -> {
scoreboardscore.setScore(i);
});
}
@@ -389,9 +536,46 @@
@Override
public void die(DamageSource damagesource) {
boolean flag = this.world.getGameRules().getBoolean(GameRules.SHOW_DEATH_MESSAGES);
+ // CraftBukkit start - fire PlayerDeathEvent
+ if (this.dead) {
+ return;
+ }
+ java.util.List<org.bukkit.inventory.ItemStack> loot = new java.util.ArrayList<org.bukkit.inventory.ItemStack>(this.inventory.getSize());
+ boolean keepInventory = this.world.getGameRules().getBoolean(GameRules.KEEP_INVENTORY) || this.isSpectator();
+
+ if (!keepInventory) {
+ for (ItemStack item : this.inventory.getContents()) {
+ if (!item.isEmpty() && !EnchantmentManager.shouldNotDrop(item)) {
+ loot.add(CraftItemStack.asCraftMirror(item));
+ }
+ }
+ }
+ // SPIGOT-5071: manually add player loot tables (SPIGOT-5195 - ignores keepInventory rule)
+ this.a(damagesource, this.lastDamageByPlayerTime > 0);
+ for (org.bukkit.inventory.ItemStack item : this.drops) {
+ loot.add(item);
+ }
+ this.drops.clear(); // SPIGOT-5188: make sure to clear
- if (flag) {
- IChatBaseComponent ichatbasecomponent = this.getCombatTracker().getDeathMessage();
+ IChatBaseComponent defaultMessage = this.getCombatTracker().getDeathMessage();
+
+ String deathmessage = defaultMessage.getString();
+ org.bukkit.event.entity.PlayerDeathEvent event = CraftEventFactory.callPlayerDeathEvent(this, loot, deathmessage, keepInventory);
+
+ // SPIGOT-943 - only call if they have an inventory open
+ if (this.activeContainer != this.defaultContainer) {
+ this.closeInventory();
+ }
+
+ String deathMessage = event.getDeathMessage();
+
+ if (deathMessage != null && deathMessage.length() > 0 && flag) { // TODO: allow plugins to override?
+ IChatBaseComponent ichatbasecomponent;
+ if (deathMessage.equals(deathmessage)) {
+ ichatbasecomponent = this.getCombatTracker().getDeathMessage();
+ } else {
+ ichatbasecomponent = org.bukkit.craftbukkit.util.CraftChatMessage.fromStringOrNull(deathMessage);
+ }
this.playerConnection.a((Packet) (new PacketPlayOutCombatEvent(this.getCombatTracker(), PacketPlayOutCombatEvent.EnumCombatEventType.ENTITY_DIED, ichatbasecomponent)), (future) -> {
if (!future.isSuccess()) {
@@ -425,12 +609,18 @@
if (this.world.getGameRules().getBoolean(GameRules.FORGIVE_DEAD_PLAYERS)) {
this.eV();
}
-
- if (!this.isSpectator()) {
- this.d(damagesource);
+ // SPIGOT-5478 must be called manually now
+ this.dropExperience();
+ // we clean the player's inventory after the EntityDeathEvent is called so plugins can get the exact state of the inventory.
+ if (!event.getKeepInventory()) {
+ this.inventory.clear();
}
- this.getScoreboard().getObjectivesForCriteria(IScoreboardCriteria.DEATH_COUNT, this.getName(), ScoreboardScore::incrementScore);
+ this.setSpectatorTarget(this); // Remove spectated target
+ // CraftBukkit end
+
+ // CraftBukkit - Get our scores instead
+ this.world.getServer().getScoreboardManager().getScoreboardScores(IScoreboardCriteria.DEATH_COUNT, this.getName(), ScoreboardScore::incrementScore);
EntityLiving entityliving = this.getKillingEntity();
if (entityliving != null) {
@@ -466,10 +656,12 @@
String s = this.getName();
String s1 = entity.getName();
- this.getScoreboard().getObjectivesForCriteria(IScoreboardCriteria.TOTAL_KILL_COUNT, s, ScoreboardScore::incrementScore);
+ // CraftBukkit - Get our scores instead
+ this.world.getServer().getScoreboardManager().getScoreboardScores(IScoreboardCriteria.TOTAL_KILL_COUNT, s, ScoreboardScore::incrementScore);
if (entity instanceof EntityHuman) {
this.a(StatisticList.PLAYER_KILLS);
- this.getScoreboard().getObjectivesForCriteria(IScoreboardCriteria.PLAYER_KILL_COUNT, s, ScoreboardScore::incrementScore);
+ // CraftBukkit - Get our scores instead
+ this.world.getServer().getScoreboardManager().getScoreboardScores(IScoreboardCriteria.PLAYER_KILL_COUNT, s, ScoreboardScore::incrementScore);
} else {
this.a(StatisticList.MOB_KILLS);
}
@@ -487,7 +679,8 @@
int i = scoreboardteam.getColor().b();
if (i >= 0 && i < aiscoreboardcriteria.length) {
- this.getScoreboard().getObjectivesForCriteria(aiscoreboardcriteria[i], s, ScoreboardScore::incrementScore);
+ // CraftBukkit - Get our scores instead
+ this.world.getServer().getScoreboardManager().getScoreboardScores(aiscoreboardcriteria[i], s, ScoreboardScore::incrementScore);
}
}
@@ -531,7 +724,8 @@
}
private boolean canPvP() {
- return this.server.getPVP();
+ // CraftBukkit - this.server.getPvP() -> this.world.pvpMode
+ return this.world.pvpMode;
}
@Nullable
@@ -539,10 +733,10 @@
protected ShapeDetectorShape a(WorldServer worldserver) {
ShapeDetectorShape shapedetectorshape = super.a(worldserver);
- if (shapedetectorshape != null && this.world.getDimensionKey() == World.OVERWORLD && worldserver.getDimensionKey() == World.THE_END) {
+ if (shapedetectorshape != null && this.world.getTypeKey() == DimensionManager.OVERWORLD && worldserver != null && worldserver.getTypeKey() == DimensionManager.THE_END) { // CraftBukkit
Vec3D vec3d = shapedetectorshape.position.add(0.0D, -1.0D, 0.0D);
- return new ShapeDetectorShape(vec3d, Vec3D.a, 90.0F, 0.0F);
+ return new ShapeDetectorShape(vec3d, Vec3D.a, 90.0F, 0.0F, worldserver, shapedetectorshape.portalEventInfo); // CraftBukkit
} else {
return shapedetectorshape;
}
@@ -551,11 +745,20 @@
@Nullable
@Override
public Entity b(WorldServer worldserver) {
- this.worldChangeInvuln = true;
+ // CraftBukkit start
+ return b(worldserver, TeleportCause.UNKNOWN);
+ }
+
+ @Nullable
+ public Entity b(WorldServer worldserver, PlayerTeleportEvent.TeleportCause cause) {
+ // CraftBukkit end
+ if (this.isSleeping()) return this; // CraftBukkit - SPIGOT-3154
+ // this.worldChangeInvuln = true; // CraftBukkit - Moved down and into PlayerList#changeDimension
WorldServer worldserver1 = this.getWorldServer();
- ResourceKey<World> resourcekey = worldserver1.getDimensionKey();
+ ResourceKey<DimensionManager> resourcekey = worldserver1.getTypeKey(); // CraftBukkit
- if (resourcekey == World.THE_END && worldserver.getDimensionKey() == World.OVERWORLD) {
+ if (resourcekey == DimensionManager.THE_END && worldserver != null && worldserver.getTypeKey() == DimensionManager.OVERWORLD) { // CraftBukkit
+ this.worldChangeInvuln = true; // CraftBukkit - Moved down from above
this.decouple();
this.getWorldServer().removePlayer(this);
if (!this.viewingCredits) {
@@ -566,6 +769,8 @@
return this;
} else {
+ // CraftBukkit start
+ /*
WorldData worlddata = worldserver.getWorldData();
this.playerConnection.sendPacket(new PacketPlayOutRespawn(worldserver.getDimensionManager(), worldserver.getDimensionKey(), BiomeManager.a(worldserver.getSeed()), this.playerInteractManager.getGameMode(), this.playerInteractManager.c(), worldserver.isDebugWorld(), worldserver.isFlatWorld(), true));
@@ -575,22 +780,52 @@
playerlist.d(this);
worldserver1.removePlayer(this);
this.dead = false;
+ */
+ // CraftBukkit end
ShapeDetectorShape shapedetectorshape = this.a(worldserver);
if (shapedetectorshape != null) {
worldserver1.getMethodProfiler().enter("moving");
- if (resourcekey == World.OVERWORLD && worldserver.getDimensionKey() == World.THE_NETHER) {
+ worldserver = shapedetectorshape.world; // CraftBukkit
+ if (worldserver == null) { } else // CraftBukkit - empty to fall through to null to event
+ if (resourcekey == DimensionManager.OVERWORLD && worldserver.getTypeKey() == DimensionManager.THE_NETHER) { // CraftBukkit
this.ci = this.getPositionVector();
- } else if (worldserver.getDimensionKey() == World.THE_END) {
+ } else if (worldserver.getTypeKey() == DimensionManager.THE_END && shapedetectorshape.portalEventInfo != null && shapedetectorshape.portalEventInfo.getCanCreatePortal()) { // CraftBukkit
this.a(worldserver, new BlockPosition(shapedetectorshape.position));
}
+ // CraftBukkit start
+ } else {
+ return null;
+ }
+ Location enter = this.getBukkitEntity().getLocation();
+ Location exit = (worldserver == null) ? null : new Location(worldserver.getWorld(), shapedetectorshape.position.x, shapedetectorshape.position.y, shapedetectorshape.position.z, shapedetectorshape.yaw, shapedetectorshape.pitch);
+ PlayerTeleportEvent tpEvent = new PlayerTeleportEvent(this.getBukkitEntity(), enter, exit, cause);
+ Bukkit.getServer().getPluginManager().callEvent(tpEvent);
+ if (tpEvent.isCancelled() || tpEvent.getTo() == null) {
+ return null;
+ }
+ exit = tpEvent.getTo();
+ worldserver = ((CraftWorld) exit.getWorld()).getHandle();
+ // CraftBukkit end
+
+ worldserver1.getMethodProfiler().exit();
+ worldserver1.getMethodProfiler().enter("placing");
+ if (true) { // CraftBukkit
+ this.worldChangeInvuln = true; // CraftBukkit - Set teleport invulnerability only if player changing worlds
+
+ this.playerConnection.sendPacket(new PacketPlayOutRespawn(worldserver.getDimensionManager(), worldserver.getDimensionKey(), BiomeManager.a(worldserver.getSeed()), this.playerInteractManager.getGameMode(), this.playerInteractManager.c(), worldserver.isDebugWorld(), worldserver.isFlatWorld(), true));
+ this.playerConnection.sendPacket(new PacketPlayOutServerDifficulty(this.world.getDifficulty(), this.world.getWorldData().isDifficultyLocked()));
+ PlayerList playerlist = this.server.getPlayerList();
+
+ playerlist.d(this);
+ worldserver1.removePlayer(this);
+ this.dead = false;
- worldserver1.getMethodProfiler().exit();
- worldserver1.getMethodProfiler().enter("placing");
+ // CraftBukkit end
this.spawnIn(worldserver);
worldserver.addPlayerPortal(this);
- this.setYawPitch(shapedetectorshape.yaw, shapedetectorshape.pitch);
- this.teleportAndSync(shapedetectorshape.position.x, shapedetectorshape.position.y, shapedetectorshape.position.z);
+ this.playerConnection.teleport(exit); // CraftBukkit - use internal teleport without event
+ this.playerConnection.syncPosition(); // CraftBukkit - sync position after changing it (from PortalTravelAgent#findAndteleport)
worldserver1.getMethodProfiler().exit();
this.triggerDimensionAdvancements(worldserver1);
this.playerInteractManager.a(worldserver);
@@ -609,12 +844,31 @@
this.lastSentExp = -1;
this.lastHealthSent = -1.0F;
this.lastFoodSent = -1;
+
+ // CraftBukkit start
+ PlayerChangedWorldEvent changeEvent = new PlayerChangedWorldEvent(this.getBukkitEntity(), worldserver1.getWorld());
+ this.world.getServer().getPluginManager().callEvent(changeEvent);
+ // CraftBukkit end
}
return this;
}
}
+ // CraftBukkit start
+ @Override
+ protected CraftPortalEvent callPortalEvent(Entity entity, WorldServer exitWorldServer, BlockPosition exitPosition, TeleportCause cause, int searchRadius, int creationRadius) {
+ Location enter = this.getBukkitEntity().getLocation();
+ Location exit = new Location(exitWorldServer.getWorld(), exitPosition.getX(), exitPosition.getY(), exitPosition.getZ(), yaw, pitch);
+ PlayerPortalEvent event = new PlayerPortalEvent(this.getBukkitEntity(), enter, exit, cause, 128, true, creationRadius);
+ Bukkit.getServer().getPluginManager().callEvent(event);
+ if (event.isCancelled() || event.getTo() == null || event.getTo().getWorld() == null) {
+ return null;
+ }
+ return new CraftPortalEvent(event);
+ }
+ // CraftBukkit end
+
private void a(WorldServer worldserver, BlockPosition blockposition) {
BlockPosition.MutableBlockPosition blockposition_mutableblockposition = blockposition.i();
@@ -631,14 +885,14 @@
}
@Override
- protected Optional<BlockUtil.Rectangle> a(WorldServer worldserver, BlockPosition blockposition, boolean flag) {
- Optional<BlockUtil.Rectangle> optional = super.a(worldserver, blockposition, flag);
+ protected Optional<BlockUtil.Rectangle> a(WorldServer worldserver, BlockPosition blockposition, boolean flag, int searchRadius, boolean canCreatePortal, int createRadius) { // CraftBukkit // PAIL rename findOrCreatePortal
+ Optional<BlockUtil.Rectangle> optional = super.a(worldserver, blockposition, flag, searchRadius, canCreatePortal, createRadius); // CraftBukkit
- if (optional.isPresent()) {
+ if (optional.isPresent() || !canCreatePortal) { // CraftBukkit
return optional;
} else {
EnumDirection.EnumAxis enumdirection_enumaxis = (EnumDirection.EnumAxis) this.world.getType(this.ac).d(BlockPortal.AXIS).orElse(EnumDirection.EnumAxis.X);
- Optional<BlockUtil.Rectangle> optional1 = worldserver.getTravelAgent().createPortal(blockposition, enumdirection_enumaxis);
+ Optional<BlockUtil.Rectangle> optional1 = worldserver.getTravelAgent().createPortal(blockposition, enumdirection_enumaxis, this, createRadius); // CraftBukkit
if (!optional1.isPresent()) {
EntityPlayer.LOGGER.error("Unable to create a portal, likely target out of worldborder");
@@ -685,10 +939,8 @@
this.activeContainer.c();
}
- @Override
- public Either<EntityHuman.EnumBedResult, Unit> sleep(BlockPosition blockposition) {
- EnumDirection enumdirection = (EnumDirection) this.world.getType(blockposition).get(BlockFacingHorizontal.FACING);
-
+ // CraftBukkit start - moved bed result checks from below into separate method
+ private Either<EntityHuman.EnumBedResult, Unit> getBedResult(BlockPosition blockposition, EnumDirection enumdirection) {
if (!this.isSleeping() && this.isAlive()) {
if (!this.world.getDimensionManager().isNatural()) {
return Either.left(EntityHuman.EnumBedResult.NOT_POSSIBLE_HERE);
@@ -714,7 +966,36 @@
}
}
- Either<EntityHuman.EnumBedResult, Unit> either = super.sleep(blockposition).ifRight((unit) -> {
+ return Either.right(Unit.INSTANCE);
+ }
+ }
+ } else {
+ return Either.left(EntityHuman.EnumBedResult.OTHER_PROBLEM);
+ }
+ }
+
+ @Override
+ public Either<EntityHuman.EnumBedResult, Unit> sleep(BlockPosition blockposition, boolean force) {
+ EnumDirection enumdirection = (EnumDirection) this.world.getType(blockposition).get(BlockFacingHorizontal.FACING);
+ Either<EntityHuman.EnumBedResult, Unit> bedResult = this.getBedResult(blockposition, enumdirection);
+
+ if (bedResult.left().orElse(null) == EntityHuman.EnumBedResult.OTHER_PROBLEM) {
+ return bedResult; // return immediately if the result is not bypassable by plugins
+ }
+
+ if (force) {
+ bedResult = Either.right(Unit.INSTANCE);
+ }
+
+ bedResult = org.bukkit.craftbukkit.event.CraftEventFactory.callPlayerBedEnterEvent(this, blockposition, bedResult);
+ if (bedResult.left().isPresent()) {
+ return bedResult;
+ }
+
+ {
+ {
+ {
+ Either<EntityHuman.EnumBedResult, Unit> either = super.sleep(blockposition, force).ifRight((unit) -> {
this.a(StatisticList.SLEEP_IN_BED);
CriterionTriggers.q.a(this);
});
@@ -723,9 +1004,8 @@
return either;
}
}
- } else {
- return Either.left(EntityHuman.EnumBedResult.OTHER_PROBLEM);
}
+ // CraftBukkit end
}
@Override
@@ -752,6 +1032,7 @@
@Override
public void wakeup(boolean flag, boolean flag1) {
+ if (!this.isSleeping()) return; // CraftBukkit - Can't leave bed if not in one!
if (this.isSleeping()) {
this.getWorldServer().getChunkProvider().broadcastIncludingSelf(this, new PacketPlayOutAnimation(this, 2));
}
@@ -823,8 +1104,9 @@
this.playerConnection.sendPacket(new PacketPlayOutOpenSignEditor(tileentitysign.getPosition()));
}
- public void nextContainerCounter() {
+ public int nextContainerCounter() { // CraftBukkit - void -> int
this.containerCounter = this.containerCounter % 100 + 1;
+ return containerCounter; // CraftBukkit
}
@Override
@@ -839,6 +1121,24 @@
this.nextContainerCounter();
Container container = itileinventory.createMenu(this.containerCounter, this.inventory, this);
+ // CraftBukkit start - Inventory open hook
+ if (container != null) {
+ container.setTitle(itileinventory.getScoreboardDisplayName());
+
+ boolean cancelled = false;
+ container = CraftEventFactory.callInventoryOpenEvent(this, container, cancelled);
+ if (container == null && !cancelled) { // Let pre-cancelled events fall through
+ // SPIGOT-5263 - close chest if cancelled
+ if (itileinventory instanceof IInventory) {
+ ((IInventory) itileinventory).closeContainer(this);
+ } else if (itileinventory instanceof BlockChest.DoubleInventory) {
+ // SPIGOT-5355 - double chests too :(
+ ((BlockChest.DoubleInventory) itileinventory).inventorylargechest.closeContainer(this);
+ }
+ return OptionalInt.empty();
+ }
+ }
+ // CraftBukkit end
if (container == null) {
if (this.isSpectator()) {
this.a((IChatBaseComponent) (new ChatMessage("container.spectatorCantOpen")).a(EnumChatFormat.RED), true);
@@ -846,9 +1146,11 @@
return OptionalInt.empty();
} else {
- this.playerConnection.sendPacket(new PacketPlayOutOpenWindow(container.windowId, container.getType(), itileinventory.getScoreboardDisplayName()));
- container.addSlotListener(this);
+ // CraftBukkit start
this.activeContainer = container;
+ this.playerConnection.sendPacket(new PacketPlayOutOpenWindow(container.windowId, container.getType(), container.getTitle()));
+ // CraftBukkit end
+ container.addSlotListener(this);
return OptionalInt.of(this.containerCounter);
}
}
@@ -861,13 +1163,24 @@
@Override
public void openHorseInventory(EntityHorseAbstract entityhorseabstract, IInventory iinventory) {
+ // CraftBukkit start - Inventory open hook
+ this.nextContainerCounter();
+ Container container = new ContainerHorse(this.containerCounter, this.inventory, iinventory, entityhorseabstract);
+ container.setTitle(entityhorseabstract.getScoreboardDisplayName());
+ container = CraftEventFactory.callInventoryOpenEvent(this, container);
+
+ if (container == null) {
+ iinventory.closeContainer(this);
+ return;
+ }
+ // CraftBukkit end
if (this.activeContainer != this.defaultContainer) {
this.closeInventory();
}
- this.nextContainerCounter();
+ // this.nextContainerCounter(); // CraftBukkit - moved up
this.playerConnection.sendPacket(new PacketPlayOutOpenWindowHorse(this.containerCounter, iinventory.getSize(), entityhorseabstract.getId()));
- this.activeContainer = new ContainerHorse(this.containerCounter, this.inventory, iinventory, entityhorseabstract);
+ this.activeContainer = container; // CraftBukkit
this.activeContainer.addSlotListener(this);
}
@@ -912,6 +1225,11 @@
public void a(Container container, NonNullList<ItemStack> nonnulllist) {
this.playerConnection.sendPacket(new PacketPlayOutWindowItems(container.windowId, nonnulllist));
this.playerConnection.sendPacket(new PacketPlayOutSetSlot(-1, -1, this.inventory.getCarried()));
+ // CraftBukkit start - Send a Set Slot to update the crafting result slot
+ if (java.util.EnumSet.of(InventoryType.CRAFTING,InventoryType.WORKBENCH).contains(container.getBukkitView().getType())) {
+ this.playerConnection.sendPacket(new PacketPlayOutSetSlot(container.windowId, 0, container.getSlot(0).getItem()));
+ }
+ // CraftBukkit end
}
@Override
@@ -921,6 +1239,7 @@
@Override
public void closeInventory() {
+ CraftEventFactory.handleInventoryCloseEvent(this); // CraftBukkit
this.playerConnection.sendPacket(new PacketPlayOutCloseWindow(this.activeContainer.windowId));
this.o();
}
@@ -955,7 +1274,7 @@
@Override
public void a(Statistic<?> statistic, int i) {
this.serverStatisticManager.b(this, statistic, i);
- this.getScoreboard().getObjectivesForCriteria(statistic, this.getName(), (scoreboardscore) -> {
+ this.world.getServer().getScoreboardManager().getScoreboardScores(statistic, this.getName(), (scoreboardscore) -> { // CraftBukkit - Get our scores instead
scoreboardscore.addScore(i);
});
}
@@ -963,7 +1282,7 @@
@Override
public void a(Statistic<?> statistic) {
this.serverStatisticManager.setStatistic(this, statistic, 0);
- this.getScoreboard().getObjectivesForCriteria(statistic, this.getName(), ScoreboardScore::c);
+ this.world.getServer().getScoreboardManager().getScoreboardScores(statistic, this.getName(), ScoreboardScore::c); // CraftBukkit - Get our scores instead
}
@Override
@@ -1012,8 +1331,17 @@
public void triggerHealthUpdate() {
this.lastHealthSent = -1.0E8F;
+ this.lastSentExp = -1; // CraftBukkit - Added to reset
}
+ // CraftBukkit start - Support multi-line messages
+ public void sendMessage(IChatBaseComponent[] ichatbasecomponent) {
+ for (IChatBaseComponent component : ichatbasecomponent) {
+ this.sendMessage(component, SystemUtils.b);
+ }
+ }
+ // CraftBukkit end
+
@Override
public void a(IChatBaseComponent ichatbasecomponent, boolean flag) {
this.playerConnection.sendPacket(new PacketPlayOutChat(ichatbasecomponent, flag ? ChatMessageType.GAME_INFO : ChatMessageType.CHAT, SystemUtils.b));
@@ -1065,12 +1393,13 @@
this.lastSentExp = -1;
this.lastHealthSent = -1.0F;
this.lastFoodSent = -1;
- this.recipeBook.a((RecipeBook) entityplayer.recipeBook);
+ // this.recipeBook.a((RecipeBook) entityplayer.recipeBook); // CraftBukkit
this.removeQueue.addAll(entityplayer.removeQueue);
this.cd = entityplayer.cd;
this.ci = entityplayer.ci;
this.setShoulderEntityLeft(entityplayer.getShoulderEntityLeft());
this.setShoulderEntityRight(entityplayer.getShoulderEntityRight());
+
}
@Override
@@ -1138,6 +1467,18 @@
@Override
public void a(EnumGamemode enumgamemode) {
+ // CraftBukkit start
+ if (enumgamemode == this.playerInteractManager.getGameMode()) {
+ return;
+ }
+
+ PlayerGameModeChangeEvent event = new PlayerGameModeChangeEvent(getBukkitEntity(), GameMode.getByValue(enumgamemode.getId()));
+ world.getServer().getPluginManager().callEvent(event);
+ if (event.isCancelled()) {
+ return;
+ }
+ // CraftBukkit end
+
this.playerInteractManager.setGameMode(enumgamemode);
this.playerConnection.sendPacket(new PacketPlayOutGameStateChange(PacketPlayOutGameStateChange.d, (float) enumgamemode.getId()));
if (enumgamemode == EnumGamemode.SPECTATOR) {
@@ -1187,7 +1528,20 @@
return s;
}
+ public String locale = "en_us"; // CraftBukkit - add, lowercase
public void a(PacketPlayInSettings packetplayinsettings) {
+ // CraftBukkit start
+ if (getMainHand() != packetplayinsettings.getMainHand()) {
+ PlayerChangedMainHandEvent event = new PlayerChangedMainHandEvent(getBukkitEntity(), getMainHand() == EnumMainHand.LEFT ? MainHand.LEFT : MainHand.RIGHT);
+ this.server.server.getPluginManager().callEvent(event);
+ }
+ if (!this.locale.equals(packetplayinsettings.locale)) {
+ PlayerLocaleChangeEvent event = new PlayerLocaleChangeEvent(getBukkitEntity(), packetplayinsettings.locale);
+ this.server.server.getPluginManager().callEvent(event);
+ }
+ this.locale = packetplayinsettings.locale;
+ this.clientViewDistance = packetplayinsettings.viewDistance;
+ // CraftBukkit end
this.bY = packetplayinsettings.d();
this.bZ = packetplayinsettings.e();
this.getDataWatcher().set(EntityPlayer.bi, (byte) packetplayinsettings.f());
@@ -1223,13 +1577,13 @@
if (entity instanceof EntityHuman) {
this.playerConnection.sendPacket(new PacketPlayOutEntityDestroy(new int[]{entity.getId()}));
} else {
- this.removeQueue.add(entity.getId());
+ this.removeQueue.add((Integer) entity.getId()); // CraftBukkit - decompile error
}
}
public void d(Entity entity) {
- this.removeQueue.remove(entity.getId());
+ this.removeQueue.remove((Integer) entity.getId()); // CraftBukkit - decompile error
}
@Override
@@ -1253,7 +1607,7 @@
this.spectatedEntity = (Entity) (entity == null ? this : entity);
if (entity1 != this.spectatedEntity) {
this.playerConnection.sendPacket(new PacketPlayOutCamera(this.spectatedEntity));
- this.enderTeleportTo(this.spectatedEntity.locX(), this.spectatedEntity.locY(), this.spectatedEntity.locZ());
+ this.playerConnection.a(this.spectatedEntity.locX(), this.spectatedEntity.locY(), this.spectatedEntity.locZ(), this.yaw, this.pitch, TeleportCause.SPECTATE); // CraftBukkit
}
}
@@ -1282,7 +1636,7 @@
@Nullable
public IChatBaseComponent getPlayerListName() {
- return null;
+ return listName; // CraftBukkit
}
@Override
@@ -1303,9 +1657,16 @@
return this.advancementDataPlayer;
}
+ // CraftBukkit start
public void a(WorldServer worldserver, double d0, double d1, double d2, float f, float f1) {
+ this.a(worldserver, d0, d1, d2, f, f1, org.bukkit.event.player.PlayerTeleportEvent.TeleportCause.UNKNOWN);
+ }
+
+ public void a(WorldServer worldserver, double d0, double d1, double d2, float f, float f1, org.bukkit.event.player.PlayerTeleportEvent.TeleportCause cause) {
+ // CraftBukkit end
this.setSpectatorTarget(this);
this.stopRiding();
+ /* CraftBukkit start - replace with bukkit handling for multi-world
if (worldserver == this.world) {
this.playerConnection.a(d0, d1, d2, f, f1);
} else {
@@ -1326,6 +1687,9 @@
this.server.getPlayerList().a(this, worldserver);
this.server.getPlayerList().updateClient(this);
}
+ */
+ this.getBukkitEntity().teleport(new Location(worldserver.getWorld(), d0, d1, d2, f, f1), cause);
+ // CraftBukkit end
}
@@ -1418,4 +1782,144 @@
return entityitem;
}
}
+
+ // CraftBukkit start - Add per-player time and weather.
+ public long timeOffset = 0;
+ public boolean relativeTime = true;
+
+ public long getPlayerTime() {
+ if (this.relativeTime) {
+ // Adds timeOffset to the current server time.
+ return this.world.getDayTime() + this.timeOffset;
+ } else {
+ // Adds timeOffset to the beginning of this day.
+ return this.world.getDayTime() - (this.world.getDayTime() % 24000) + this.timeOffset;
+ }
+ }
+
+ public WeatherType weather = null;
+
+ public WeatherType getPlayerWeather() {
+ return this.weather;
+ }
+
+ public void setPlayerWeather(WeatherType type, boolean plugin) {
+ if (!plugin && this.weather != null) {
+ return;
+ }
+
+ if (plugin) {
+ this.weather = type;
+ }
+
+ if (type == WeatherType.DOWNFALL) {
+ this.playerConnection.sendPacket(new PacketPlayOutGameStateChange(PacketPlayOutGameStateChange.c, 0));
+ } else {
+ this.playerConnection.sendPacket(new PacketPlayOutGameStateChange(PacketPlayOutGameStateChange.b, 0));
+ }
+ }
+
+ private float pluginRainPosition;
+ private float pluginRainPositionPrevious;
+
+ public void updateWeather(float oldRain, float newRain, float oldThunder, float newThunder) {
+ if (this.weather == null) {
+ // Vanilla
+ if (oldRain != newRain) {
+ this.playerConnection.sendPacket(new PacketPlayOutGameStateChange(PacketPlayOutGameStateChange.h, newRain));
+ }
+ } else {
+ // Plugin
+ if (pluginRainPositionPrevious != pluginRainPosition) {
+ this.playerConnection.sendPacket(new PacketPlayOutGameStateChange(PacketPlayOutGameStateChange.h, pluginRainPosition));
+ }
+ }
+
+ if (oldThunder != newThunder) {
+ if (weather == WeatherType.DOWNFALL || weather == null) {
+ this.playerConnection.sendPacket(new PacketPlayOutGameStateChange(PacketPlayOutGameStateChange.i, newThunder));
+ } else {
+ this.playerConnection.sendPacket(new PacketPlayOutGameStateChange(PacketPlayOutGameStateChange.i, 0));
+ }
+ }
+ }
+
+ public void tickWeather() {
+ if (this.weather == null) return;
+
+ pluginRainPositionPrevious = pluginRainPosition;
+ if (weather == WeatherType.DOWNFALL) {
+ pluginRainPosition += 0.01;
+ } else {
+ pluginRainPosition -= 0.01;
+ }
+
+ pluginRainPosition = MathHelper.a(pluginRainPosition, 0.0F, 1.0F);
+ }
+
+ public void resetPlayerWeather() {
+ this.weather = null;
+ this.setPlayerWeather(this.world.getWorldData().hasStorm() ? WeatherType.DOWNFALL : WeatherType.CLEAR, false);
+ }
+
+ @Override
+ public String toString() {
+ return super.toString() + "(" + this.getName() + " at " + this.locX() + "," + this.locY() + "," + this.locZ() + ")";
+ }
+
+ // SPIGOT-1903, MC-98153
+ public void forceSetPositionRotation(double x, double y, double z, float yaw, float pitch) {
+ this.setPositionRotation(x, y, z, yaw, pitch);
+ this.playerConnection.syncPosition();
+ }
+
+ @Override
+ protected boolean isFrozen() {
+ return super.isFrozen() || !getBukkitEntity().isOnline();
+ }
+
+ @Override
+ public Scoreboard getScoreboard() {
+ return getBukkitEntity().getScoreboard().getHandle();
+ }
+
+ public void reset() {
+ float exp = 0;
+ boolean keepInventory = this.world.getGameRules().getBoolean(GameRules.KEEP_INVENTORY);
+
+ if (this.keepLevel || keepInventory) {
+ exp = this.exp;
+ this.newTotalExp = this.expTotal;
+ this.newLevel = this.expLevel;
+ }
+
+ this.setHealth(this.getMaxHealth());
+ this.fireTicks = 0;
+ this.fallDistance = 0;
+ this.foodData = new FoodMetaData(this);
+ this.expLevel = this.newLevel;
+ this.expTotal = this.newTotalExp;
+ this.exp = 0;
+ this.deathTicks = 0;
+ this.setArrowCount(0);
+ this.removeAllEffects(org.bukkit.event.entity.EntityPotionEffectEvent.Cause.DEATH);
+ this.updateEffects = true;
+ this.activeContainer = this.defaultContainer;
+ this.killer = null;
+ this.lastDamager = null;
+ this.combatTracker = new CombatTracker(this);
+ this.lastSentExp = -1;
+ if (this.keepLevel || keepInventory) {
+ this.exp = exp;
+ } else {
+ this.giveExp(this.newExp);
+ }
+ this.keepLevel = false;
+ }
+
+ @Override
+ public CraftPlayer getBukkitEntity() {
+ return (CraftPlayer) super.getBukkitEntity();
+ }
+ // CraftBukkit end
}