Compare commits

..

10 Commits

Author SHA1 Message Date
bendude56
a4805dbd77 Allow teleportation of entities on vehicles. Fixes BUKKIT-4210
Up until Minecraft version 1.5 it was not possible to teleport entities
within vehicles. With the 1.5 update came the change in the Minecraft
teleportation logic to dismount before teleporting the entity, if
applicable.

This commit ammends the existing CraftBukkit logic for rejecting
teleportation for entities in vehicles to permit the action. Due to this
change, CraftBukkit is now in-line with Minecraft 1.5 teleportation logic.
2014-08-17 11:49:27 -06:00
Jerom van der Sar
80e8f2ab87 Implement ability to keep items on death via plugins. Adds BUKKIT-5724
When a player dies their inventory is normally scattered over the the area
in which they died. Plugins should be able to modify this behaviour by
defining whether or not the player's inventory will be dropped on the ground or waiting for the player when they eventually respawn.

This commit implements the methods included in the Bukkit half for the new
behaviour by acting upon the boolean flag. The boolean flag is tested
prior to clearing the inventory as well as prior to dropping the items on
the ground. If the flag is true (indicating "keep inventory"), the items
are not removed from the player's inventory and are not dropped on the
ground.
2014-08-17 11:41:40 -06:00
Starbuck Johnson
3626720d53 Modify the invalid item set to permit command blocks. Fixes BUKKIT-4342
When using a "vanilla" Minecraft server using the "pick block" key on a
command block yields the invoker with a command block within their
inventory while in creative mode. Implications of the invalid items set
containing the command block also include having a "ghost" item that
cannot be placed due to it not actually existing.

This commit resolves the problem and brings Craftbukkit closer to vanilla
behaviour by removing the command block item ID, 137, from the invalid
items set.
2014-08-17 11:23:28 -06:00
myiume
4507cec090 Fix PlayerFishEvent not correctly cancelling. Fixes BUKKIT-5396
Prior to this commit cancelling the PlayerFishEvent would cause various
states of the fishing routine to be incorrectly or wrongly fired. This
incorrect behaviour was due to the miscommunication between the server and
client regarding the fishing state. When the event was cancelled, the
bobber entity was removed and caused the client to incorrectly determine
what the "next state" was to logically be.

This commit resolves the issue by ensuring the client is made aware of the
correct changes at the correct time regarding the bobber entity, therefore
keeping the logical steps of "fishing" proper and in-tact.
2014-08-17 00:17:02 -06:00
Wesley Wolfe
b3e83b00fc Implement deprecated methods. Adds BUKKIT-5752 2014-08-07 19:35:16 -05:00
Wesley Wolfe
1f0c791444 Use sensible AssertionError instead of ambiguous RuntimeException 2014-08-07 19:29:35 -05:00
ase34
87f6fa7bc9 Fix cancelling PlayerDropItemEvent. Fixes BUKKIT-3313
Up until this commit the PlayerDropItemEvent, if cancelled, would return
items to the first available slot in the inventory - which is clearly
undesirable as a player and plugin author to deal with.

This commit changes that by ensuring that the item is returned to where
it came from in the player's inventory. This still supports modifying the
drop from the player and will default to "first available slot" if the
item has changed since the event was fired. Other remaining behaviour of
the event is still in tact and has not been modified.
2014-08-04 12:27:50 -06:00
feildmaster
971329c42b Fix removal of items from Item Frames. Fixes BUKKIT-5736 2014-08-02 16:12:03 -05:00
Travis Watkins
594d7cb8c9 Don't confuse client with sound coordinates outside view distance. 2014-07-15 21:28:10 -05:00
Wesley Wolfe
c7398b9fdf Provide modifier functions to EntityDamageEvent. Fixes BUKKIT-5688 2014-07-13 00:07:38 -05:00
12 changed files with 163 additions and 26 deletions

View File

@@ -544,7 +544,23 @@ public class EntityEnderDragon extends EntityInsentient implements IComplex, IMo
}
if (this.bB == 1) {
this.world.b(1018, (int) this.locX, (int) this.locY, (int) this.locZ, 0);
// CraftBukkit start - Use relative location for far away sounds
//this.world.b(1018, (int) this.locX, (int) this.locY, (int) this.locZ, 0);
int viewDistance = ((WorldServer) this.world).getServer().getViewDistance() * 16;
for (EntityPlayer player : (List<EntityPlayer>) this.world.players) {
double deltaX = this.locX - player.locX;
double deltaZ = this.locZ - player.locZ;
double distanceSquared = deltaX * deltaX + deltaZ * deltaZ;
if (distanceSquared > viewDistance * viewDistance) {
double deltaLength = Math.sqrt(distanceSquared);
double relativeX = player.locX + (deltaX / deltaLength) * viewDistance;
double relativeZ = player.locZ + (deltaZ / deltaLength) * viewDistance;
player.playerConnection.sendPacket(new PacketPlayOutWorldEvent(1018, (int) relativeX, (int) this.locY, (int) relativeZ, 0, true));
} else {
player.playerConnection.sendPacket(new PacketPlayOutWorldEvent(1018, (int) this.locX, (int) this.locY, (int) this.locZ, 0, true));
}
}
// CraftBukkit end
}
}

View File

@@ -370,8 +370,6 @@ public class EntityFishingHook extends Entity {
this.world.getServer().getPluginManager().callEvent(playerFishEvent);
if (playerFishEvent.isCancelled()) {
this.die();
this.owner.hookedFish = null;
return 0;
}
// CraftBukkit end
@@ -394,8 +392,6 @@ public class EntityFishingHook extends Entity {
this.world.getServer().getPluginManager().callEvent(playerFishEvent);
if (playerFishEvent.isCancelled()) {
this.die();
this.owner.hookedFish = null;
return 0;
}
// CraftBukkit end
@@ -421,8 +417,6 @@ public class EntityFishingHook extends Entity {
this.world.getServer().getPluginManager().callEvent(playerFishEvent);
if (playerFishEvent.isCancelled()) {
this.die();
this.owner.hookedFish = null;
return 0;
}
// CraftBukkit end
@@ -434,6 +428,9 @@ public class EntityFishingHook extends Entity {
if (b0 == 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

View File

@@ -514,6 +514,7 @@ public abstract class EntityHuman extends EntityLiving implements ICommandListen
}
public EntityItem a(boolean flag) {
// Called only when dropped by Q or CTRL-Q
return this.a(this.inventory.splitStack(this.inventory.itemInHandIndex, flag && this.inventory.getItemInHand() != null ? this.inventory.getItemInHand().count : 1), false, true);
}
@@ -565,7 +566,18 @@ public abstract class EntityHuman extends EntityLiving implements ICommandListen
this.world.getServer().getPluginManager().callEvent(event);
if (event.isCancelled()) {
player.getInventory().addItem(drop.getItemStack());
org.bukkit.inventory.ItemStack cur = player.getInventory().getItemInHand();
if (flag1 && (cur == null || cur.getAmount() == 0)) {
// The complete stack was dropped
player.getInventory().setItemInHand(drop.getItemStack());
} else if (flag1 && cur.isSimilar(drop.getItemStack()) && drop.getItemStack().getAmount() == 1) {
// Only one item is dropped
cur.setAmount(cur.getAmount() + 1);
player.getInventory().setItemInHand(cur);
} else {
// Fallback
player.getInventory().addItem(drop.getItemStack());
}
return null;
}
// CraftBukkit end

View File

@@ -24,7 +24,7 @@ public class EntityItemFrame extends EntityHanging {
} else if (this.getItem() != null) {
if (!this.world.isStatic) {
// CraftBukkit start - fire EntityDamageEvent
if (org.bukkit.craftbukkit.event.CraftEventFactory.handleNonLivingEntityDamageEvent(this, damagesource, f) || this.dead) {
if (org.bukkit.craftbukkit.event.CraftEventFactory.handleNonLivingEntityDamageEvent(this, damagesource, f, false) || this.dead) {
return true;
}
// CraftBukkit end

View File

@@ -63,7 +63,24 @@ public class EntityLightning extends EntityWeather {
public void h() {
super.h();
if (this.lifeTicks == 2) {
this.world.makeSound(this.locX, this.locY, this.locZ, "ambient.weather.thunder", 10000.0F, 0.8F + this.random.nextFloat() * 0.2F);
// CraftBukkit start - Use relative location for far away sounds
//this.world.makeSound(this.locX, this.locY, this.locZ, "ambient.weather.thunder", 10000.0F, 0.8F + this.random.nextFloat() * 0.2F);
float pitch = 0.8F + this.random.nextFloat() * 0.2F;
int viewDistance = ((WorldServer) this.world).getServer().getViewDistance() * 16;
for (EntityPlayer player : (List<EntityPlayer>) this.world.players) {
double deltaX = this.locX - player.locX;
double deltaZ = this.locZ - player.locZ;
double distanceSquared = deltaX * deltaX + deltaZ * deltaZ;
if (distanceSquared > viewDistance * viewDistance) {
double deltaLength = Math.sqrt(distanceSquared);
double relativeX = player.locX + (deltaX / deltaLength) * viewDistance;
double relativeZ = player.locZ + (deltaZ / deltaLength) * viewDistance;
player.playerConnection.sendPacket(new PacketPlayOutNamedSoundEffect("ambient.weather.thunder", relativeX, this.locY, relativeZ, 10000.0F, pitch));
} else {
player.playerConnection.sendPacket(new PacketPlayOutNamedSoundEffect("ambient.weather.thunder", this.locX, this.locY, this.locZ, 10000.0F, pitch));
}
}
// CraftBukkit end
this.world.makeSound(this.locX, this.locY, this.locZ, "random.explode", 2.0F, 0.5F + this.random.nextFloat() * 0.2F);
}

View File

@@ -366,7 +366,7 @@ public class EntityPlayer extends EntityHuman implements ICrafting {
IChatBaseComponent chatmessage = this.aW().b();
String deathmessage = chatmessage.c();
org.bukkit.event.entity.PlayerDeathEvent event = CraftEventFactory.callPlayerDeathEvent(this, loot, deathmessage);
org.bukkit.event.entity.PlayerDeathEvent event = CraftEventFactory.callPlayerDeathEvent(this, loot, deathmessage, keepInventory);
String deathMessage = event.getDeathMessage();
@@ -379,7 +379,7 @@ public class EntityPlayer extends EntityHuman implements ICrafting {
}
// we clean the player's inventory after the EntityDeathEvent is called so plugins can get the exact state of the inventory.
if (!keepInventory) {
if (!event.getKeepInventory()) {
for (int i = 0; i < this.inventory.items.length; ++i) {
this.inventory.items[i] = null;
}

View File

@@ -173,7 +173,23 @@ public class EntityWither extends EntityMonster implements IRangedEntity {
// CraftBukkit end
this.world.createExplosion(this, this.locX, this.locY + (double) this.getHeadHeight(), this.locZ, 7.0F, false, this.world.getGameRules().getBoolean("mobGriefing"));
this.world.b(1013, (int) this.locX, (int) this.locY, (int) this.locZ, 0);
// CraftBukkit start - Use relative location for far away sounds
//this.world.b(1013, (int) this.locX, (int) this.locY, (int) this.locZ, 0);
int viewDistance = ((WorldServer) this.world).getServer().getViewDistance() * 16;
for (EntityPlayer player : (List<EntityPlayer>) this.world.players) {
double deltaX = this.locX - player.locX;
double deltaZ = this.locZ - player.locZ;
double distanceSquared = deltaX * deltaX + deltaZ * deltaZ;
if (distanceSquared > viewDistance * viewDistance) {
double deltaLength = Math.sqrt(distanceSquared);
double relativeX = player.locX + (deltaX / deltaLength) * viewDistance;
double relativeZ = player.locZ + (deltaZ / deltaLength) * viewDistance;
player.playerConnection.sendPacket(new PacketPlayOutWorldEvent(1013, (int) relativeX, (int) this.locY, (int) relativeZ, 0, true));
} else {
player.playerConnection.sendPacket(new PacketPlayOutWorldEvent(1013, (int) this.locX, (int) this.locY, (int) this.locZ, 0, true));
}
}
// CraftBukkit end
}
this.s(i);

View File

@@ -116,7 +116,7 @@ public class PlayerConnection implements PacketPlayInListener {
public CraftPlayer getPlayer() {
return (this.player == null) ? null : (CraftPlayer) this.player.getBukkitEntity();
}
private final static HashSet<Integer> invalidItems = new HashSet<Integer>(java.util.Arrays.asList(8, 9, 10, 11, 26, 34, 36, 43, 51, 52, 55, 59, 60, 62, 63, 64, 68, 71, 74, 75, 83, 90, 92, 93, 94, 104, 105, 115, 117, 118, 119, 125, 127, 132, 137, 140, 141, 142, 144)); // TODO: Check after every update.
private final static HashSet<Integer> invalidItems = new HashSet<Integer>(java.util.Arrays.asList(8, 9, 10, 11, 26, 34, 36, 43, 51, 52, 55, 59, 60, 62, 63, 64, 68, 71, 74, 75, 83, 90, 92, 93, 94, 104, 105, 115, 117, 118, 119, 125, 127, 132, 140, 141, 142, 144)); // TODO: Check after every update.
// CraftBukkit end
public void a() {

View File

@@ -201,10 +201,13 @@ public abstract class CraftEntity implements org.bukkit.entity.Entity {
}
public boolean teleport(Location location, TeleportCause cause) {
if (entity.vehicle != null || entity.passenger != null || entity.dead) {
if (entity.passenger != null || entity.dead) {
return false;
}
// If this entity is riding another entity, we must dismount before teleporting.
entity.mount(null);
entity.world = ((CraftWorld) location.getWorld()).getHandle();
entity.setLocation(location.getX(), location.getY(), location.getZ(), location.getYaw(), location.getPitch());
// entity.setLocation() throws no event, and so cannot be cancelled

View File

@@ -458,7 +458,7 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
return false;
}
if (entity.vehicle != null || entity.passenger != null) {
if (entity.passenger != null) {
return false;
}
@@ -475,6 +475,9 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
return false;
}
// If this player is riding another entity, we must dismount before teleporting.
entity.mount(null);
// Update the From Location
from = event.getFrom();
// Grab the new To Location dependent on whether the event was cancelled.

View File

@@ -8,6 +8,7 @@ import java.util.Map;
import com.google.common.base.Function;
import com.google.common.base.Functions;
import net.minecraft.server.ChunkCoordinates;
import net.minecraft.server.Container;
import net.minecraft.server.DamageSource;
@@ -80,8 +81,6 @@ import org.bukkit.event.server.ServerListPingEvent;
import org.bukkit.inventory.InventoryView;
import org.bukkit.inventory.meta.BookMeta;
import com.google.common.collect.ImmutableMap;
public class CraftEventFactory {
public static final DamageSource MELTING = CraftDamageSource.copyOf(DamageSource.BURN);
public static final DamageSource POISON = CraftDamageSource.copyOf(DamageSource.MAGIC);
@@ -191,7 +190,7 @@ public class CraftEventFactory {
*/
public static PlayerInteractEvent callPlayerInteractEvent(EntityHuman who, Action action, ItemStack itemstack) {
if (action != Action.LEFT_CLICK_AIR && action != Action.RIGHT_CLICK_AIR) {
throw new IllegalArgumentException();
throw new AssertionError(String.format("%s performing %s with %s", who, action, itemstack));
}
return callPlayerInteractEvent(who, action, 0, 256, 0, 0, itemstack);
}
@@ -373,9 +372,10 @@ public class CraftEventFactory {
return event;
}
public static PlayerDeathEvent callPlayerDeathEvent(EntityPlayer victim, List<org.bukkit.inventory.ItemStack> drops, String deathMessage) {
public static PlayerDeathEvent callPlayerDeathEvent(EntityPlayer victim, List<org.bukkit.inventory.ItemStack> drops, String deathMessage, boolean keepInventory) {
CraftPlayer entity = victim.getBukkitEntity();
PlayerDeathEvent event = new PlayerDeathEvent(entity, drops, victim.getExpReward(), 0, deathMessage);
event.setKeepInventory(keepInventory);
org.bukkit.World world = entity.getWorld();
Bukkit.getServer().getPluginManager().callEvent(event);
@@ -385,6 +385,10 @@ public class CraftEventFactory {
victim.expToDrop = event.getDroppedExp();
victim.newExp = event.getNewExp();
if (event.getKeepInventory()) {
return event;
}
for (org.bukkit.inventory.ItemStack stack : event.getDrops()) {
if (stack == null || stack.getType() == Material.AIR) continue;
@@ -463,7 +467,7 @@ public class CraftEventFactory {
if (source == DamageSource.CACTUS) {
cause = DamageCause.CONTACT;
} else {
throw new RuntimeException("Unhandled entity damage");
throw new AssertionError(String.format("Unhandled damage of %s by %s from %s", entity, damager, source.translationIndex));
}
EntityDamageEvent event = callEvent(new EntityDamageByBlockEvent(damager, entity.getBukkitEntity(), cause, modifiers, modifierFunctions));
if (!event.isCancelled()) {
@@ -481,7 +485,7 @@ public class CraftEventFactory {
} else if (source == DamageSource.FALL) {
cause = DamageCause.FALL;
} else {
throw new RuntimeException("Unhandled entity damage");
throw new AssertionError(String.format("Unhandled damage of %s by %s from %s", entity, damager.getHandle(), source.translationIndex));
}
EntityDamageEvent event = callEvent(new EntityDamageByEntityEvent(damager, entity.getBukkitEntity(), cause, modifiers, modifierFunctions));
if (!event.isCancelled()) {
@@ -519,7 +523,7 @@ public class CraftEventFactory {
return callEntityDamageEvent(null, entity, cause, modifiers, modifierFunctions);
}
throw new RuntimeException("Unhandled entity damage");
throw new AssertionError(String.format("Unhandled damage of %s from %s", entity, source.translationIndex));
}
private static EntityDamageEvent callEntityDamageEvent(Entity damager, Entity damagee, DamageCause cause, Map<DamageModifier, Double> modifiers, Map<DamageModifier, Function<? super Double, Double>> modifierFunctions) {
@@ -565,16 +569,27 @@ public class CraftEventFactory {
return handleEntityDamageEvent(damagee, source, modifiers, modifierFunctions);
}
// Non-Living Entities such as EntityEnderCrystal, EntityItemFrame, and EntityFireball need to call this
// Non-Living Entities such as EntityEnderCrystal and EntityFireball need to call this
public static boolean handleNonLivingEntityDamageEvent(Entity entity, DamageSource source, double damage) {
return handleNonLivingEntityDamageEvent(entity, source, damage, true);
}
public static boolean handleNonLivingEntityDamageEvent(Entity entity, DamageSource source, double damage, boolean cancelOnZeroDamage) {
if (entity instanceof EntityEnderCrystal && !(source instanceof EntityDamageSource)) {
return false;
}
EntityDamageEvent event = handleEntityDamageEvent(entity, source, new EnumMap<DamageModifier, Double>(ImmutableMap.of(DamageModifier.BASE, (double) damage)), null);
final EnumMap<DamageModifier, Double> modifiers = new EnumMap<DamageModifier, Double>(DamageModifier.class);
final EnumMap<DamageModifier, Function<? super Double, Double>> functions = new EnumMap(DamageModifier.class);
modifiers.put(DamageModifier.BASE, damage);
functions.put(DamageModifier.BASE, ZERO);
final EntityDamageEvent event = handleEntityDamageEvent(entity, source, modifiers, functions);
if (event == null) {
return false;
}
return event.isCancelled() || event.getDamage() == 0;
return event.isCancelled() || (cancelOnZeroDamage && event.getDamage() == 0);
}
public static PlayerLevelChangeEvent callPlayerLevelChangeEvent(Player player, int oldLevel, int newLevel) {

View File

@@ -17,6 +17,7 @@ import java.util.logging.Level;
import org.apache.commons.lang.Validate;
import org.bukkit.plugin.IllegalPluginAccessException;
import org.bukkit.plugin.Plugin;
import org.bukkit.scheduler.BukkitRunnable;
import org.bukkit.scheduler.BukkitScheduler;
import org.bukkit.scheduler.BukkitTask;
import org.bukkit.scheduler.BukkitWorker;
@@ -88,6 +89,7 @@ public class CraftScheduler implements BukkitScheduler {
return runTaskLater(plugin, runnable, 0l);
}
@Deprecated
public int scheduleAsyncDelayedTask(final Plugin plugin, final Runnable task) {
return this.scheduleAsyncDelayedTask(plugin, task, 0l);
}
@@ -104,6 +106,7 @@ public class CraftScheduler implements BukkitScheduler {
return runTaskTimer(plugin, runnable, delay, -1l);
}
@Deprecated
public int scheduleAsyncDelayedTask(final Plugin plugin, final Runnable task, final long delay) {
return this.scheduleAsyncRepeatingTask(plugin, task, delay, -1l);
}
@@ -129,6 +132,7 @@ public class CraftScheduler implements BukkitScheduler {
return handle(new CraftTask(plugin, runnable, nextId(), period), delay);
}
@Deprecated
public int scheduleAsyncRepeatingTask(final Plugin plugin, final Runnable runnable, long delay, long period) {
return runTaskTimerAsynchronously(plugin, runnable, delay, period).getTaskId();
}
@@ -431,4 +435,58 @@ public class CraftScheduler implements BukkitScheduler {
debugHead.debugTo(string);
return string.append('}').toString();
}
@Deprecated
@Override
public int scheduleSyncDelayedTask(Plugin plugin, BukkitRunnable task, long delay) {
return scheduleSyncDelayedTask(plugin, (Runnable) task, delay);
}
@Deprecated
@Override
public int scheduleSyncDelayedTask(Plugin plugin, BukkitRunnable task) {
return scheduleSyncDelayedTask(plugin, (Runnable) task);
}
@Deprecated
@Override
public int scheduleSyncRepeatingTask(Plugin plugin, BukkitRunnable task, long delay, long period) {
return scheduleSyncRepeatingTask(plugin, (Runnable) task, delay, period);
}
@Deprecated
@Override
public BukkitTask runTask(Plugin plugin, BukkitRunnable task) throws IllegalArgumentException {
return runTask(plugin, (Runnable) task);
}
@Deprecated
@Override
public BukkitTask runTaskAsynchronously(Plugin plugin, BukkitRunnable task) throws IllegalArgumentException {
return runTaskAsynchronously(plugin, (Runnable) task);
}
@Deprecated
@Override
public BukkitTask runTaskLater(Plugin plugin, BukkitRunnable task, long delay) throws IllegalArgumentException {
return runTaskLater(plugin, (Runnable) task, delay);
}
@Deprecated
@Override
public BukkitTask runTaskLaterAsynchronously(Plugin plugin, BukkitRunnable task, long delay) throws IllegalArgumentException {
return runTaskLaterAsynchronously(plugin, (Runnable) task, delay);
}
@Deprecated
@Override
public BukkitTask runTaskTimer(Plugin plugin, BukkitRunnable task, long delay, long period) throws IllegalArgumentException {
return runTaskTimer(plugin, (Runnable) task, delay, period);
}
@Deprecated
@Override
public BukkitTask runTaskTimerAsynchronously(Plugin plugin, BukkitRunnable task, long delay, long period) throws IllegalArgumentException {
return runTaskTimerAsynchronously(plugin, (Runnable) task, delay, period);
}
}