blob: 11743c435fa88e6246e733dc10824fbfb600488f [file] [log] [blame] [raw]
package net.glowstone.entity;
import net.glowstone.*;
import net.glowstone.block.GlowBlockState;
import net.glowstone.inventory.GlowInventory;
import net.glowstone.inventory.GlowItemStack;
import net.glowstone.inventory.GlowPlayerInventory;
import net.glowstone.inventory.InventoryViewer;
import net.glowstone.io.StorageOperation;
import net.glowstone.msg.*;
import net.glowstone.net.ProtocolState;
import net.glowstone.net.Session;
import net.glowstone.net.message.game.*;
import net.glowstone.net.message.login.LoginSuccessMessage;
import net.glowstone.util.Parameter;
import net.glowstone.util.Position;
import net.glowstone.util.TextWrapper;
import org.bukkit.*;
import org.bukkit.configuration.serialization.DelegateDeserialization;
import org.bukkit.conversations.Conversation;
import org.bukkit.conversations.ConversationAbandonedEvent;
import org.bukkit.entity.Player;
import org.bukkit.event.player.PlayerChatEvent;
import org.bukkit.event.player.PlayerTeleportEvent;
import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.InventoryView;
import org.bukkit.inventory.ItemStack;
import org.bukkit.map.MapView;
import org.bukkit.plugin.Plugin;
import org.bukkit.scoreboard.Scoreboard;
import java.net.InetSocketAddress;
import java.util.*;
import java.util.logging.Level;
/**
* Represents an in-game player.
* @author Graham Edgecombe
*/
@DelegateDeserialization(GlowOfflinePlayer.class)
public final class GlowPlayer extends GlowHumanEntity implements Player, InventoryViewer {
/**
* The normal height of a player's eyes above their feet.
*/
public static final double EYE_HEIGHT = 1.62D;
/**
* This player's session.
*/
private final Session session;
/**
* This player's unique id.
*/
private final UUID uuid;
/**
* Cumulative amount of experience points the player has collected.
*/
private int experience = 0;
/**
* The current level (or skill point amount) of the player.
*/
private int level = 0;
/**
* The player's current exhaustion level.
*/
private float exhaustion = 0;
/**
* The player's current saturation level.
*/
private float saturation = 0;
/**
* This player's current time offset.
*/
private long timeOffset = 0;
/**
* Whether the time offset is relative.
*/
private boolean timeRelative = true;
/**
* The display name of this player, for chat purposes.
*/
private String displayName;
/**
* The player's compass target.
*/
private Location compassTarget;
/**
* The entities that the client knows about.
*/
private Set<GlowEntity> knownEntities = new HashSet<GlowEntity>();
/**
* The chunks that the client knows about.
*/
private final Set<GlowChunk.Key> knownChunks = new HashSet<GlowChunk.Key>();
/**
* The lock used to prevent chunks from unloading near the player.
*/
private ChunkManager.ChunkLock chunkLock;
/**
* The item the player has on their cursor.
*/
private GlowItemStack itemOnCursor;
/**
* Whether the player is sneaking.
*/
private boolean sneaking = false;
/**
* The human entity's current food level
*/
private int food = 20;
/**
* Whether to use the display name when sending spawn messages to
*/
private boolean dispNameAsEntityName = false;
/**
* The bed spawn location of a player
*/
private Location bedSpawn;
/**
* The name a player has in the player list
*/
private String playerListName;
/**
* Creates a new player and adds it to the world.
* @param session The player's session.
* @param name The player's name.
*/
public GlowPlayer(Session session, String name, UUID uuid) {
super(session.getServer(), (GlowWorld) session.getServer().getWorlds().get(0), name);
this.session = session;
this.uuid = uuid;
chunkLock = world.newChunkLock(getName());
// send login response
session.send(new LoginSuccessMessage(uuid.toString().replace("-", ""), name));
session.setState(ProtocolState.PLAY);
// send join game
// in future, handle hardcore, difficulty, and level type
String type = "default";//world.getWorldType().getName().toLowerCase();
int gameMode = getGameMode().getValue();
if (server.isHardcore()) {
gameMode |= 0x8;
}
session.send(new JoinGameMessage(getEntityId(), gameMode, world.getEnvironment().getId(), world.getDifficulty().getValue(), session.getServer().getMaxPlayers(), type));
streamBlocks(); // stream the initial set of blocks
setCompassTarget(world.getSpawnLocation()); // set our compass target
session.send(new StateChangeMessage(getWorld().hasStorm() ? 1 : 2, 0)); // send the world's weather
getInventory().addViewer(this);
getInventory().getCraftingInventory().addViewer(this);
loadData();
saveData();
}
// -- Various internal mechanisms
/**
* Destroys this entity by removing it from the world and marking it as not
* being active.
*/
@Override
public void remove() {
knownChunks.clear();
chunkLock.clear();
saveData();
getInventory().removeViewer(this);
getInventory().getCraftingInventory().removeViewer(this);
super.remove();
}
@Override
public void pulse() {
super.pulse();
streamBlocks();
for (Iterator<GlowEntity> it = knownEntities.iterator(); it.hasNext(); ) {
GlowEntity entity = it.next();
boolean withinDistance = !entity.isDead() && isWithinDistance(entity);
if (withinDistance) {
Message msg = entity.createUpdateMessage();
if (msg != null)
session.send(msg);
} else {
session.send(new DestroyEntityMessage(entity.getEntityId()));
it.remove();
}
}
for (GlowEntity entity : world.getEntityManager()) {
if (entity == this)
continue;
boolean withinDistance = !entity.isDead() && isWithinDistance(entity);
if (withinDistance && !knownEntities.contains(entity)) {
knownEntities.add(entity);
session.send(entity.createSpawnMessage());
}
}
}
/**
* Streams chunks to the player's client.
*/
private void streamBlocks() {
Set<GlowChunk.Key> previousChunks = new HashSet<GlowChunk.Key>(knownChunks);
ArrayList<GlowChunk.Key> newChunks = new ArrayList<GlowChunk.Key>();
int centralX = location.getBlockX() >> 4;
int centralZ = location.getBlockZ() >> 4;
int radius = server.getViewDistance();
for (int x = (centralX - radius); x <= (centralX + radius); x++) {
for (int z = (centralZ - radius); z <= (centralZ + radius); z++) {
GlowChunk.Key key = new GlowChunk.Key(x, z);
if (knownChunks.contains(key)) {
previousChunks.remove(key);
} else {
newChunks.add(key);
}
}
}
if (newChunks.size() == 0 && previousChunks.size() == 0) {
return;
}
Collections.sort(newChunks, new Comparator<GlowChunk.Key>() {
public int compare(GlowChunk.Key a, GlowChunk.Key b) {
double dx = 16 * a.getX() + 8 - location.getX();
double dz = 16 * a.getZ() + 8 - location.getZ();
double da = dx * dx + dz * dz;
dx = 16 * b.getX() + 8 - location.getX();
dz = 16 * b.getZ() + 8 - location.getZ();
double db = dx * dx + dz * dz;
return Double.compare(da, db);
}
});
List<GlowChunk> bulkChunks = null;
if (newChunks.size() > knownChunks.size() * 2 / 5) {
// send a bulk message
bulkChunks = new LinkedList<GlowChunk>();
GlowServer.logger.info("Sending bulk to: " + getName());
}
for (GlowChunk.Key key : newChunks) {
world.getChunkManager().forcePopulation(key.getX(), key.getZ());
GlowChunk chunk = world.getChunkAt(key.getX(), key.getZ());
if (bulkChunks == null) {
session.send(chunk.toMessage());
} else {
bulkChunks.add(chunk);
}
knownChunks.add(key);
chunkLock.acquire(key);
}
if (bulkChunks != null) {
boolean skylight = world.getEnvironment() == World.Environment.NORMAL;
session.send(new ChunkBulkMessage(skylight, bulkChunks));
}
for (GlowChunk.Key key : newChunks) {
GlowChunk chunk = world.getChunkAt(key.getX(), key.getZ());
for (GlowBlockState state : chunk.getTileEntities()) {
state.update(this);
}
}
for (GlowChunk.Key key : previousChunks) {
session.send(ChunkDataMessage.empty(key.getX(), key.getZ()));
knownChunks.remove(key);
chunkLock.release(key);
}
previousChunks.clear();
}
/**
* Checks whether the player can see the given chunk.
* @return If the chunk is known to the player's client.
*/
public boolean canSee(GlowChunk.Key chunk) {
return knownChunks.contains(chunk);
}
/**
* Checks whether the player can see the given entity.
* @return If the entity is known to the player's client.
*/
public boolean canSee(GlowEntity entity) {
return knownEntities.contains(entity);
}
// -- Basic getters
/**
* Gets the session.
* @return The session.
*/
public Session getSession() {
return session;
}
public boolean isOnline() {
return true;
}
@Override
public UUID getUniqueId() {
return uuid;
}
public boolean isBanned() {
return server.getBanManager().isBanned(getName());
}
public void setBanned(boolean banned) {
server.getBanManager().setBanned(getName(), banned);
}
public boolean isWhitelisted() {
return !server.hasWhitelist() || server.getWhitelist().contains(getName());
}
public void setWhitelisted(boolean value) {
if (value) {
server.getWhitelist().add(getName());
} else {
server.getWhitelist().remove(getName());
}
}
public Player getPlayer() {
return this;
}
public InetSocketAddress getAddress() {
return session.getAddress();
}
@Override
public boolean isOp() {
return getServer().getOpsList().contains(getName());
}
@Override
public void setOp(boolean value) {
if (value) {
getServer().getOpsList().add(getName());
} else {
getServer().getOpsList().remove(getName());
}
permissions.recalculatePermissions();
}
// -- Malleable properties
public String getDisplayName() {
return displayName == null ? getName() : displayName;
}
public void setDisplayName(String name) {
displayName = name;
}
public String getPlayerListName() {
return playerListName == null || "".equals(playerListName) ? getName() : playerListName;
}
public void setPlayerListName(String name) {
if (name.length() > 15) throw new IllegalArgumentException("The given name was " + name.length() + " chars long, longer than the maximum of 16");
for (Player player : server.getOnlinePlayers()) {
if (player.getPlayerListName().equals(getPlayerListName())) throw new IllegalArgumentException("The name given, " + name + ", is already used by " + player.getName() + ".");
}
Message removeMessage = new UserListItemMessage(getPlayerListName(), false, (short)0);
playerListName = name;
Message reAddMessage = new UserListItemMessage(getPlayerListName(), true, (short)0);
for (Player player : server.getOnlinePlayers()) {
((GlowPlayer) player).getSession().send(removeMessage);
((GlowPlayer) player).getSession().send(reAddMessage);
}
}
public Location getCompassTarget() {
return compassTarget;
}
public void setCompassTarget(Location loc) {
compassTarget = loc;
session.send(new SpawnPositionMessage(loc.getBlockX(), loc.getBlockY(), loc.getBlockZ()));
}
public boolean isSneaking() {
return sneaking;
}
public void setSneaking(boolean sneak) {
if (EventFactory.onPlayerToggleSneak(this, sneak).isCancelled()) {
return;
}
this.sneaking = sneak;
setMetadata(new Parameter<Byte>(Parameter.TYPE_BYTE, 0, (byte) (this.sneaking ? 0x02: 0)));
// FIXME: other bits in the bitmask would be wiped out
EntityMetadataMessage message = new EntityMetadataMessage(id, metadata);
for (Player player : world.getPlayers()) {
if (player != this && canSee((GlowEntity) player)) {
((GlowPlayer) player).session.send(message);
}
}
}
public boolean isSprinting() {
throw new UnsupportedOperationException("Not supported yet.");
}
public void setSprinting(boolean sprinting) {
throw new UnsupportedOperationException("Not supported yet.");
}
public boolean isSleepingIgnored() {
throw new UnsupportedOperationException("Not supported yet.");
}
public void setSleepingIgnored(boolean isSleeping) {
throw new UnsupportedOperationException("Not supported yet.");
}
@Override
public void setGameMode(GameMode mode) {
boolean changed = getGameMode() != mode;
super.setGameMode(mode);
if (changed) session.send(new StateChangeMessage(3, mode.getValue()));
}
public int getExperience() {
return experience % ((getLevel() + 1) * 7);
}
public void setExperience(int exp) {
setTotalExperience(experience - getExperience() + exp);
}
public int getLevel() {
return level;
}
public void setLevel(int level) {
int calcExperience = getExperience();
this.level = level;
for (int i = 0; i <= level; i++) {
calcExperience += (level + 1) * 7;
}
setExperience(calcExperience);
session.send(createExperienceMessage());
}
public int getTotalExperience() {
return experience;
}
public void setTotalExperience(int exp) {
int calcExperience = exp;
this.experience = exp;
level = 0;
while ((calcExperience -= (getLevel() + 1) * 7) > 0) ++level;
session.send(createExperienceMessage());
}
/**
* Add xp to Player.
* @param xp to add
*/
public void giveExp(int xp) {
experience += xp;
while(experience > (getLevel() + 1) * 7){
experience -= (getLevel() + 1) * 7;
++level;
}
session.send(createExperienceMessage());
}
/**
* Get the percent to level for player.
* @return value between 0 and 1: percent to next level.
*/
public float getExp() {
float xpToLevel = (getLevel() + 1) * 7;
return (float)experience/xpToLevel;
}
/**
* Set the experience progress to next level.
* 0 sets to current level, 1 is next level
* Values greater than 1 or less that 0 are undefined.
* TODO Test boundary conditions.
* @param percentToLevel
*/
public void setExp(float percentToLevel) {
float xpToLevel = (getLevel() + 1) * 7;
experience = (int)(percentToLevel * xpToLevel);
}
public float getExhaustion() {
return exhaustion;
}
public void setExhaustion(float value) {
exhaustion = value;
}
public float getSaturation() {
return saturation;
}
public void setSaturation(float value) {
saturation = value;
session.send(createHealthMessage());
}
// -- Actions
/**
* Teleport the player.
* @param location The destination to teleport to.
* @return Whether the teleport was a success.
*/
@Override
public boolean teleport(Location location) {
return teleport(location, TeleportCause.UNKNOWN);
}
@Override
public boolean teleport(Location location, TeleportCause cause) {
if (this.location != null && this.location.getWorld() != null) {
PlayerTeleportEvent event = EventFactory.onPlayerTeleport(this, getLocation(), location, cause);
if (event.isCancelled()) return false;
location = event.getTo();
}
if (location.getWorld() != world) {
GlowWorld oldWorld = world;
world.getEntityManager().deallocate(this);
world = (GlowWorld) location.getWorld();
world.getEntityManager().allocate(this);
for (GlowChunk.Key key : knownChunks) {
session.send(ChunkDataMessage.empty(key.getX(), key.getZ()));
}
knownChunks.clear();
chunkLock.clear();
chunkLock = world.newChunkLock(getName());
session.send(new RespawnMessage((byte) world.getEnvironment().getId(), (byte)1, (byte) getGameMode().getValue(), (short) world.getMaxHeight(), world.getSeed()));
streamBlocks(); // stream blocks
setCompassTarget(world.getSpawnLocation()); // set our compass target
this.session.send(new PositionRotationMessage(location, true));
this.location = location; // take us to spawn position
session.send(new StateChangeMessage((byte)(getWorld().hasStorm() ? 1 : 2), (byte)0)); // send the world's weather
reset();
EventFactory.onPlayerChangedWorld(this, oldWorld);
} else {
this.session.send(new PositionRotationMessage(location, true));
this.location = location;
reset();
}
return true;
}
public void sendMessage(String message) {
for (String line : TextWrapper.wrapText(message)) {
sendRawMessage(line);
}
}
public void sendRawMessage(String message) {
session.send(new ChatMessage(message.length() <= 119 ? message : message.substring(0, 119)));
}
public void kickPlayer(String message) {
session.disconnect(message == null ? "" : message);
}
public boolean performCommand(String command) {
return getServer().dispatchCommand(this, command);
}
/**
* Says a message (or runs a command).
*
* @param text message to print
*/
public void chat(String text) {
if (text.startsWith("/")) {
try {
if (EventFactory.onPlayerCommand(this, text).isCancelled()) {
return;
}
if (!performCommand(text.substring(1))) {
String firstword = text.substring(1);
if (firstword.indexOf(' ') >= 0) {
firstword = firstword.substring(0, firstword.indexOf(' '));
}
sendMessage(ChatColor.GRAY + "Command not found: " + firstword);
}
}
catch (Exception ex) {
sendMessage(ChatColor.RED + "An internal error occured while executing your command.");
getServer().getLogger().log(Level.SEVERE, "Exception while executing command: {0}", ex.getMessage());
ex.printStackTrace();
}
} else {
PlayerChatEvent event = EventFactory.onPlayerChat(this, text);
if (event.isCancelled()) {
return;
}
String message = String.format(event.getFormat(), event.getPlayer().getDisplayName(), event.getMessage());
getServer().getLogger().info(message);
for (Player recipient : event.getRecipients()) {
recipient.sendMessage(message);
}
}
}
public void saveData() {
saveData(true);
}
public void saveData(boolean async) {
final GlowWorld dataWorld = (GlowWorld) server.getWorlds().get(0);
if (async) {
final GlowPlayer player = this;
server.getStorageQueue().queue(new StorageOperation() {
@Override
public boolean isParallel() {
return true;
}
@Override
public String getGroup() {
return getName() + "_" + getWorld().getName();
}
@Override
public boolean queueMultiple() {
return true;
}
@Override
public String getOperation() {
return "player-data-save";
}
public void run() {
dataWorld.getMetadataService().writePlayerData(player);
}
});
} else {
dataWorld.getMetadataService().writePlayerData(this);
}
}
public void loadData() {
GlowWorld dataWorld = (GlowWorld)server.getWorlds().get(0);
dataWorld.getMetadataService().readPlayerData(this);
}
// -- Data transmission
public void playNote(Location loc, Instrument instrument, Note note) {
playNote(loc, instrument.getType(), note.getId());
}
public void playNote(Location loc, byte instrument, byte note) {
session.send(new PlayNoteMessage(loc.getBlockX(), loc.getBlockY(), loc.getBlockZ(), instrument, note));
}
public void playEffect(Location loc, Effect effect, int data) {
session.send(new PlayEffectMessage(effect.getId(), loc.getBlockX(), loc.getBlockY(), loc.getBlockZ(), data));
}
public void sendBlockChange(Location loc, Material material, byte data) {
sendBlockChange(loc, material.getId(), data);
}
public void sendBlockChange(Location loc, int material, byte data) {
sendBlockChange(new BlockChangeMessage(loc.getBlockX(), loc.getBlockY(), loc.getBlockZ(), material, data));
}
public void sendBlockChange(BlockChangeMessage message) {
// only send message if the chunk is within visible range
GlowChunk.Key key = new GlowChunk.Key(message.getX() >> 4, message.getZ() >> 4);
if (canSee(key)) {
session.send(message);
}
}
public boolean sendChunkChange(Location loc, int sx, int sy, int sz, byte[] data) {
throw new UnsupportedOperationException("Not supported yet.");
}
// -- Achievements & Statistics [mostly borrowed from CraftBukkit]
public void awardAchievement(Achievement achievement) {
//sendStatistic(achievement.getId(), 1);
}
public void incrementStatistic(Statistic statistic) {
incrementStatistic(statistic, 1);
}
public void incrementStatistic(Statistic statistic, int amount) {
//sendStatistic(statistic.getId(), amount);
}
public void incrementStatistic(Statistic statistic, Material material) {
incrementStatistic(statistic, material, 1);
}
public void incrementStatistic(Statistic statistic, Material material, int amount) {
if (!statistic.isSubstatistic()) {
throw new IllegalArgumentException("Given statistic is not a substatistic");
}
if (statistic.isBlock() != material.isBlock()) {
throw new IllegalArgumentException("Given material is not valid for this substatistic");
}
int mat = material.getId();
if (!material.isBlock()) {
mat -= 255;
}
//sendStatistic(statistic.getId() + mat, amount);
}
private void sendStatistic(int id, int amount) {
while (amount > Byte.MAX_VALUE) {
sendStatistic(id, Byte.MAX_VALUE);
amount -= Byte.MAX_VALUE;
}
if (amount > 0) {
session.send(new StatisticMessage(id, (byte) amount));
}
}
// -- Inventory
public void updateInventory() {
getInventory().setContents(getInventory().getContents());
}
/**
* Get the current item on the player's cursor, for inventory screen purposes.
* @return The ItemStack the player is holding.
*/
public ItemStack getItemOnCursor() {
return itemOnCursor;
}
/**
* Set the item on the player's cursor, for inventory screen purposes.
* @param item The ItemStack to set the cursor to.
*/
public void setItemOnCursor(GlowItemStack item) {
itemOnCursor = item;
if (item == null) {
session.send(new SetWindowSlotMessage(-1, -1));
} else {
session.send(new SetWindowSlotMessage(-1, -1, item.getTypeId(), item.getAmount(), item.getDurability(), item.getNbtData()));
}
}
/**
* Inform the client that an item has changed.
* @param inventory The GlowInventory in which a slot has changed.
* @param slot The slot number which has changed.
* @param item The ItemStack which the slot has changed to.
*/
public void onSlotSet(GlowInventory inventory, int slot, GlowItemStack item) {
if (inventory == getInventory()) {
int type = item == null ? -1 : item.getTypeId();
int data = item == null ? 0 : item.getDurability();
int equipSlot = -1;
if (slot == getInventory().getHeldItemSlot()) {
equipSlot = EntityEquipmentMessage.HELD_ITEM;
} else if (slot == GlowPlayerInventory.HELMET_SLOT) {
equipSlot = EntityEquipmentMessage.HELMET_SLOT;
} else if (slot == GlowPlayerInventory.CHESTPLATE_SLOT) {
equipSlot = EntityEquipmentMessage.CHESTPLATE_SLOT;
} else if (slot == GlowPlayerInventory.LEGGINGS_SLOT) {
equipSlot = EntityEquipmentMessage.LEGGINGS_SLOT;
} else if (slot == GlowPlayerInventory.BOOTS_SLOT) {
equipSlot = EntityEquipmentMessage.BOOTS_SLOT;
}
if (equipSlot >= 0) {
EntityEquipmentMessage message = new EntityEquipmentMessage(getEntityId(), equipSlot, type, data);
for (GlowPlayer player : new ArrayList<GlowPlayer>(getWorld().getRawPlayers())) {
if (player != this && player.canSee((GlowEntity) this)) {
player.getSession().send(message);
}
}
}
}
if (item == null) {
session.send(new SetWindowSlotMessage(inventory.getId(), inventory.getNetworkSlot(slot)));
} else {
session.send(new SetWindowSlotMessage(inventory.getId(), inventory.getNetworkSlot(slot), item.getTypeId(), item.getAmount(), item.getDurability(), item.getNbtData()));
}
}
// -- Goofy relative time stuff --
/**
* Sets the current time on the player's client. When relative is true the player's time
* will be kept synchronized to its world time with the specified offset.
*
* When using non relative time the player's time will stay fixed at the specified time parameter. It's up to
* the caller to continue updating the player's time. To restore player time to normal use resetPlayerTime().
*
* @param time The current player's perceived time or the player's time offset from the server time.
* @param relative When true the player time is kept relative to its world time.
*/
public void setPlayerTime(long time, boolean relative) {
timeOffset = time % 24000;
timeRelative = relative;
if (timeOffset < 0) timeOffset += 24000;
}
/**
* Returns the player's current timestamp.
*
* @return
*/
public long getPlayerTime() {
if (timeRelative) {
// add timeOffset ticks to current time
return (world.getTime() + timeOffset) % 24000;
} else {
// return time offset
return timeOffset % 24000;
}
}
/**
* Returns the player's current time offset relative to server time, or the current player's fixed time
* if the player's time is absolute.
*
* @return
*/
public long getPlayerTimeOffset() {
return timeOffset;
}
/**
* Returns true if the player's time is relative to the server time, otherwise the player's time is absolute and
* will not change its current time unless done so with setPlayerTime().
*
* @return true if the player's time is relative to the server time.
*/
public boolean isPlayerTimeRelative() {
return timeRelative;
}
/**
* Restores the normal condition where the player's time is synchronized with the server time.
* Equivalent to calling setPlayerTime(0, true).
*/
public void resetPlayerTime() {
setPlayerTime(0, true);
}
/**
* Render a map and send it to the player in its entirety. This may be used
* when streaming the map in the normal manner is not desirbale.
*
* @param map The map to be sent
*/
public void sendMap(MapView map) {
throw new UnsupportedOperationException("Not supported yet.");
}
@Override
public void setHealth(double health) {
super.setHealth(health);
session.send(createHealthMessage());
}
@Override
public Message createSpawnMessage() {
int x = Position.getIntX(location);
int y = Position.getIntY(location);
int z = Position.getIntZ(location);
int yaw = Position.getIntYaw(location);
int pitch = Position.getIntPitch(location);
return new SpawnPlayerMessage(id, dispNameAsEntityName ? displayName : getName(), x, y, z, yaw, pitch, 0);
}
public int getFoodLevel() {
return food;
}
public void setFoodLevel(int food) {
this.food = Math.min(food, 20);
session.send(createHealthMessage());
}
public Message createHealthMessage() {
return new HealthMessage((int) getHealth(), getFoodLevel(), getSaturation());
}
public Message createExperienceMessage() {
return new ExperienceMessage((byte)getExperience(), (byte)getLevel(), (short)getTotalExperience());
}
public Map<String, Object> serialize() {
Map<String, Object> ret = new HashMap<String, Object>();
ret.put("name", getName());
return ret;
}
// NEW STUFF
@Override
public void playSound(Location location, Sound sound, float volume, float pitch) {
}
@Override
public void playSound(Location location, String sound, float volume, float pitch) {
}
@Override
public <T> void playEffect(Location loc, Effect effect, T data) {
}
@Override
public void setPlayerWeather(WeatherType type) {
}
@Override
public WeatherType getPlayerWeather() {
return null;
}
@Override
public void resetPlayerWeather() {
}
@Override
public void giveExpLevels(int amount) {
}
@Override
public void setBedSpawnLocation(Location location, boolean force) {
}
@Override
public boolean getAllowFlight() {
return false;
}
@Override
public void setAllowFlight(boolean flight) {
}
@Override
public void hidePlayer(Player player) {
}
@Override
public void showPlayer(Player player) {
}
@Override
public boolean canSee(Player player) {
return false;
}
@Override
public boolean isFlying() {
return false;
}
@Override
public void setFlying(boolean value) {
}
@Override
public void setFlySpeed(float value) throws IllegalArgumentException {
}
@Override
public void setWalkSpeed(float value) throws IllegalArgumentException {
}
@Override
public float getFlySpeed() {
return 0;
}
@Override
public float getWalkSpeed() {
return 0;
}
@Override
public void setTexturePack(String url) {
}
@Override
public void setResourcePack(String url) {
}
@Override
public Scoreboard getScoreboard() {
return null;
}
@Override
public void setScoreboard(Scoreboard scoreboard) throws IllegalArgumentException, IllegalStateException {
}
@Override
public boolean isHealthScaled() {
return false;
}
@Override
public void setHealthScaled(boolean scale) {
}
@Override
public void setHealthScale(double scale) throws IllegalArgumentException {
}
@Override
public double getHealthScale() {
return 0;
}
@Override
public void sendMessage(String[] messages) {
}
@Override
public boolean isConversing() {
return false;
}
@Override
public void acceptConversationInput(String input) {
}
@Override
public boolean beginConversation(Conversation conversation) {
return false;
}
@Override
public void abandonConversation(Conversation conversation) {
}
@Override
public void abandonConversation(Conversation conversation, ConversationAbandonedEvent details) {
}
@Override
public Inventory getEnderChest() {
return null;
}
@Override
public boolean setWindowProperty(InventoryView.Property prop, int value) {
return false;
}
@Override
public InventoryView getOpenInventory() {
return null;
}
@Override
public InventoryView openInventory(Inventory inventory) {
return null;
}
@Override
public InventoryView openWorkbench(Location location, boolean force) {
return null;
}
@Override
public InventoryView openEnchanting(Location location, boolean force) {
return null;
}
@Override
public void openInventory(InventoryView inventory) {
}
@Override
public void closeInventory() {
}
@Override
public void setItemOnCursor(ItemStack item) {
}
@Override
public boolean isBlocking() {
return false;
}
@Override
public int getExpToLevel() {
return 0;
}
@Override
public long getFirstPlayed() {
return 0;
}
@Override
public long getLastPlayed() {
return 0;
}
@Override
public boolean hasPlayedBefore() {
return false;
}
@Override
public void sendPluginMessage(Plugin source, String channel, byte[] message) {
}
@Override
public Set<String> getListeningPluginChannels() {
return null;
}
}