1.9 support

This commit is contained in:
filoghost 2016-03-04 11:35:45 +01:00
parent 87bc0922ed
commit 707268c0b5
38 changed files with 2349 additions and 64 deletions

View File

@ -7,7 +7,6 @@ import org.bukkit.plugin.java.JavaPlugin;
import com.gmail.filoghost.holographicdisplays.SimpleUpdater.ResponseHandler;
import com.gmail.filoghost.holographicdisplays.bridge.bungeecord.BungeeServerTracker;
import com.gmail.filoghost.holographicdisplays.bridge.protocollib.ProtocolLibHook;
import com.gmail.filoghost.holographicdisplays.commands.main.HologramsCommandHandler;
import com.gmail.filoghost.holographicdisplays.disk.Configuration;
import com.gmail.filoghost.holographicdisplays.disk.HologramDatabase;
@ -39,7 +38,10 @@ public class HolographicDisplays extends JavaPlugin {
private HologramsCommandHandler commandHandler;
// Since 1.8 we use armor stands instead of wither skulls.
private static boolean is1_8;
private static boolean is18orGreater;
// Since 1.9 there is a different offset for the nametag.
private static boolean is19orGreater;
// Used for the server pinger.
private static boolean isPreNetty;
@ -120,20 +122,24 @@ public class HolographicDisplays extends JavaPlugin {
} else if ("v1_7_R4".equals(version)) {
nmsManager = new com.gmail.filoghost.holographicdisplays.nms.v1_7_R4.NmsManagerImpl();
} else if ("v1_8_R1".equals(version)) {
is1_8 = true;
is18orGreater = true;
nmsManager = new com.gmail.filoghost.holographicdisplays.nms.v1_8_R1.NmsManagerImpl();
} else if ("v1_8_R2".equals(version)) {
is1_8 = true;
is18orGreater = true;
nmsManager = new com.gmail.filoghost.holographicdisplays.nms.v1_8_R2.NmsManagerImpl();
} else if ("v1_8_R3".equals(version)) {
is1_8 = true;
is18orGreater = true;
nmsManager = new com.gmail.filoghost.holographicdisplays.nms.v1_8_R3.NmsManagerImpl();
} else if ("v1_9_R1".equals(version)) {
is18orGreater = true;
is19orGreater = true;
nmsManager = new com.gmail.filoghost.holographicdisplays.nms.v1_9_R1.NmsManagerImpl();
} else {
printWarnAndDisable(
"******************************************************",
" This version of HolographicDisplays can",
" only work on these server versions:",
" from 1.6.4 to 1.8.8.",
" from 1.6.4 to 1.9.",
" The plugin will be disabled.",
"******************************************************"
);
@ -157,7 +163,7 @@ public class HolographicDisplays extends JavaPlugin {
"******************************************************",
" HolographicDisplays was unable to register",
" custom entities, the plugin will be disabled.",
" Are you using the correct Bukkit version?",
" Are you using the correct Bukkit/Spigot version?",
"******************************************************"
);
return;
@ -166,7 +172,11 @@ public class HolographicDisplays extends JavaPlugin {
// ProtocolLib check.
try {
if (Bukkit.getPluginManager().isPluginEnabled("ProtocolLib")) {
useProtocolLib = ProtocolLibHook.load(nmsManager, this, is1_8);
if (is19orGreater) {
useProtocolLib = com.gmail.filoghost.holographicdisplays.bridge.protocollib.current.ProtocolLibHook.load(nmsManager, this);
} else {
useProtocolLib = com.gmail.filoghost.holographicdisplays.bridge.protocollib.pre1_9.ProtocolLibHook.load(nmsManager, this, is18orGreater);
}
}
} catch (Exception ex) {
ex.printStackTrace();
@ -214,8 +224,8 @@ public class HolographicDisplays extends JavaPlugin {
"******************************************************",
" HolographicDisplays was unable to register",
" the command \"holograms\". Do not modify",
" plugin.yml removing commands, if you're",
" doing so.",
" plugin.yml removing commands, if this is",
" the case.",
"******************************************************"
);
return;
@ -249,8 +259,12 @@ public class HolographicDisplays extends JavaPlugin {
return commandHandler;
}
public static boolean is1_8() {
return is1_8;
public static boolean is18orGreater() {
return is18orGreater;
}
public static boolean is19orGreater() {
return is19orGreater;
}
public static boolean isPreNetty() {

View File

@ -6,6 +6,7 @@ import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.EOFException;
import java.io.IOException;
import java.util.Collection;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
@ -14,6 +15,7 @@ import org.bukkit.plugin.messaging.PluginMessageListener;
import com.gmail.filoghost.holographicdisplays.HolographicDisplays;
import com.gmail.filoghost.holographicdisplays.disk.Configuration;
import com.gmail.filoghost.holographicdisplays.util.VersionUtils;
public class BungeeChannel implements PluginMessageListener {
@ -80,7 +82,7 @@ public class BungeeChannel implements PluginMessageListener {
}
}
@SuppressWarnings("deprecation")
public void askPlayerCount(String server) {
ByteArrayOutputStream b = new ByteArrayOutputStream();
DataOutputStream out = new DataOutputStream(b);
@ -95,9 +97,9 @@ public class BungeeChannel implements PluginMessageListener {
}
// OR, if you don't need to send it to a specific player
Player[] players = Bukkit.getOnlinePlayers();
if (players.length > 0) {
players[0].sendPluginMessage(HolographicDisplays.getInstance(), Configuration.useRedisBungee ? "RedisBungee" : "BungeeCord", b.toByteArray());
Collection<? extends Player> players = VersionUtils.getOnlinePlayers();
if (players.size() > 0) {
players.iterator().next().sendPluginMessage(HolographicDisplays.getInstance(), Configuration.useRedisBungee ? "RedisBungee" : "BungeeCord", b.toByteArray());
}
}
}

View File

@ -0,0 +1,82 @@
/*
* PacketWrapper - Contains wrappers for each packet in Minecraft.
* Copyright (C) 2012 Kristian S. Stangeland
*
* This program is free software; you can redistribute it and/or modify it under the terms of the
* GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with this program;
* if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
* 02111-1307 USA
*/
package com.gmail.filoghost.holographicdisplays.bridge.protocollib.current;
import java.lang.reflect.InvocationTargetException;
import org.bukkit.entity.Player;
import com.comphenix.protocol.PacketType;
import com.comphenix.protocol.ProtocolLibrary;
import com.comphenix.protocol.events.PacketContainer;
import com.google.common.base.Objects;
public abstract class AbstractPacket {
// The packet we will be modifying
protected PacketContainer handle;
/**
* Constructs a new strongly typed wrapper for the given packet.
* @param handle - handle to the raw packet data.
* @param type - the packet type.
*/
protected AbstractPacket(PacketContainer handle, PacketType type) {
// Make sure we're given a valid packet
if (handle == null)
throw new IllegalArgumentException("Packet handle cannot be NULL.");
if (!Objects.equal(handle.getType(), type))
throw new IllegalArgumentException(
handle.getHandle() + " is not a packet of type " + type);
this.handle = handle;
}
/**
* Retrieve a handle to the raw packet data.
* @return Raw packet data.
*/
public PacketContainer getHandle() {
return handle;
}
/**
* Send the current packet to the given receiver.
* @param receiver - the receiver.
* @throws RuntimeException If the packet cannot be sent.
*/
public void sendPacket(Player receiver) {
try {
ProtocolLibrary.getProtocolManager().sendServerPacket(receiver, getHandle());
} catch (InvocationTargetException e) {
throw new RuntimeException("Cannot send packet.", e);
}
}
/**
* Simulate receiving the current packet from the given sender.
* @param sender - the sender.
* @throws RuntimeException If the packet cannot be received.
*/
public void recievePacket(Player sender) {
try {
ProtocolLibrary.getProtocolManager().recieveClientPacket(sender, getHandle());
} catch (Exception e) {
throw new RuntimeException("Cannot recieve packet.", e);
}
}
}

View File

@ -0,0 +1,287 @@
package com.gmail.filoghost.holographicdisplays.bridge.protocollib.current;
import java.util.List;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.entity.Entity;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.Player;
import org.bukkit.plugin.Plugin;
import com.comphenix.protocol.PacketType;
import com.comphenix.protocol.ProtocolLibrary;
import com.comphenix.protocol.events.ListenerPriority;
import com.comphenix.protocol.events.PacketAdapter;
import com.comphenix.protocol.events.PacketContainer;
import com.comphenix.protocol.events.PacketEvent;
import com.comphenix.protocol.wrappers.WrappedDataWatcher;
import com.comphenix.protocol.wrappers.WrappedWatchableObject;
import com.gmail.filoghost.holographicdisplays.bridge.protocollib.current.WrapperPlayServerSpawnEntity.ObjectTypes;
import com.gmail.filoghost.holographicdisplays.nms.interfaces.NMSManager;
import com.gmail.filoghost.holographicdisplays.nms.interfaces.entity.NMSEntityBase;
import com.gmail.filoghost.holographicdisplays.object.CraftHologram;
import com.gmail.filoghost.holographicdisplays.object.line.CraftHologramLine;
import com.gmail.filoghost.holographicdisplays.object.line.CraftItemLine;
import com.gmail.filoghost.holographicdisplays.object.line.CraftTextLine;
import com.gmail.filoghost.holographicdisplays.object.line.CraftTouchSlimeLine;
import com.gmail.filoghost.holographicdisplays.object.line.CraftTouchableLine;
import com.gmail.filoghost.holographicdisplays.util.Utils;
public class ProtocolLibHook {
private static boolean hasProtocolLib;
private static NMSManager nmsManager;
public static boolean load(NMSManager nmsManager, Plugin plugin) {
ProtocolLibHook.nmsManager = nmsManager;
if (Bukkit.getPluginManager().isPluginEnabled("ProtocolLib")) {
//TODO
Bukkit.getConsoleSender().sendMessage(
ChatColor.RED + "[Holographic Displays] Detected development version of ProtocolLib, support disabled. " +
"Related functions (the placeholders {player} {displayname} and the visibility API) will not work.\n" +
"The reason is that this version of ProtocolLib is unstable and partly broken. " +
"A new version of Holographic Displays will be out when ProtocolLib gets fixed.");
return false;
/*
hasProtocolLib = true;
plugin.getLogger().info("Found ProtocolLib, adding support for player relative variables.");
ProtocolLibrary.getProtocolManager().addPacketListener(new PacketAdapter(plugin, ListenerPriority.NORMAL, PacketType.Play.Server.SPAWN_ENTITY_LIVING, PacketType.Play.Server.SPAWN_ENTITY, PacketType.Play.Server.ENTITY_METADATA) {
@Override
public void onPacketSending(PacketEvent event) {
PacketContainer packet = event.getPacket();
// Spawn entity packet
if (packet.getType() == PacketType.Play.Server.SPAWN_ENTITY_LIVING) {
WrapperPlayServerSpawnEntityLiving spawnEntityPacket = new WrapperPlayServerSpawnEntityLiving(packet);
Entity entity = spawnEntityPacket.getEntity(event);
if (entity == null || !isHologramType(entity.getType())) {
return;
}
CraftHologram hologram = getHologram(entity);
if (hologram == null) {
return;
}
Player player = event.getPlayer();
if (!hologram.getVisibilityManager().isVisibleTo(player)) {
event.setCancelled(true);
return;
}
WrappedDataWatcher dataWatcher = spawnEntityPacket.getMetadata();
String customName = dataWatcher.getString(2);
if (customName == null) {
return;
}
if (customName.contains("{player}") || customName.contains("{displayname}")) {
WrappedDataWatcher dataWatcherClone = dataWatcher.deepClone();
dataWatcherClone.setObject(2, customName.replace("{player}", player.getName()).replace("{displayname}", player.getDisplayName()));
spawnEntityPacket.setMetadata(dataWatcherClone);
event.setPacket(spawnEntityPacket.getHandle());
}
} else if (packet.getType() == PacketType.Play.Server.SPAWN_ENTITY) {
WrapperPlayServerSpawnEntity spawnEntityPacket = new WrapperPlayServerSpawnEntity(packet);
int objectId = spawnEntityPacket.getType();
if (objectId != ObjectTypes.ITEM_STACK && objectId != ObjectTypes.ARMOR_STAND) {
return;
}
Entity entity = spawnEntityPacket.getEntity(event);
if (entity == null) {
return;
}
CraftHologram hologram = getHologram(entity);
if (hologram == null) {
return;
}
Player player = event.getPlayer();
if (!hologram.getVisibilityManager().isVisibleTo(player)) {
event.setCancelled(true);
return;
}
} else if (packet.getType() == PacketType.Play.Server.ENTITY_METADATA) {
WrapperPlayServerEntityMetadata entityMetadataPacket = new WrapperPlayServerEntityMetadata(packet);
Entity entity = entityMetadataPacket.getEntity(event);
if (entity == null) {
return;
}
if (entity.getType() != EntityType.ARMOR_STAND) {
// Enough, only armorstands are used with custom names.
return;
}
CraftHologram hologram = getHologram(entity);
if (hologram == null) {
return;
}
Player player = event.getPlayer();
if (!hologram.getVisibilityManager().isVisibleTo(player)) {
event.setCancelled(true);
return;
}
List<WrappedWatchableObject> dataWatcherValues = entityMetadataPacket.getEntityMetadata();
for (int i = 0; i < dataWatcherValues.size(); i++) {
if (dataWatcherValues.get(i).getIndex() == 2 && dataWatcherValues.get(i).getValue() != null) {
Object customNameObject = dataWatcherValues.get(i).deepClone().getValue();
if (customNameObject == null || customNameObject instanceof String == false) {
return;
}
String customName = (String) customNameObject;
if (customName.contains("{player}") || customName.contains("{displayname}")) {
entityMetadataPacket = new WrapperPlayServerEntityMetadata(packet.deepClone());
List<WrappedWatchableObject> clonedList = entityMetadataPacket.getEntityMetadata();
WrappedWatchableObject clonedElement = clonedList.get(i);
clonedElement.setValue(customName.replace("{player}", player.getName()).replace("{displayname}", player.getDisplayName()));
entityMetadataPacket.setEntityMetadata(clonedList);
event.setPacket(entityMetadataPacket.getHandle());
return;
}
}
}
}
}
});
return true;
*/
}
return false;
}
public static void sendDestroyEntitiesPacket(Player player, CraftHologram hologram) {
if (!hasProtocolLib) {
return;
}
List<Integer> ids = Utils.newList();
for (CraftHologramLine line : hologram.getLinesUnsafe()) {
if (line.isSpawned()) {
for (int id : line.getEntitiesIDs()) {
ids.add(id);
}
}
}
if (!ids.isEmpty()) {
WrapperPlayServerEntityDestroy packet = new WrapperPlayServerEntityDestroy();
packet.setEntities(ids);
packet.sendPacket(player);
}
}
public static void sendCreateEntitiesPacket(Player player, CraftHologram hologram) {
if (!hasProtocolLib) {
return;
}
for (CraftHologramLine line : hologram.getLinesUnsafe()) {
if (line.isSpawned()) {
if (line instanceof CraftTextLine) {
CraftTextLine textLine = (CraftTextLine) line;
if (textLine.isSpawned()) {
AbstractPacket nameablePacket = new WrapperPlayServerSpawnEntityLiving(textLine.getNmsNameble().getBukkitEntityNMS());
nameablePacket.sendPacket(player);
}
} else if (line instanceof CraftItemLine) {
CraftItemLine itemLine = (CraftItemLine) line;
if (itemLine.isSpawned()) {
AbstractPacket itemPacket = new WrapperPlayServerSpawnEntity(itemLine.getNmsItem().getBukkitEntityNMS(), ObjectTypes.ITEM_STACK, 1);
itemPacket.sendPacket(player);
AbstractPacket vehiclePacket = new WrapperPlayServerSpawnEntityLiving(itemLine.getNmsVehicle().getBukkitEntityNMS());
vehiclePacket.sendPacket(player);
WrapperPlayServerMount attachPacket = new WrapperPlayServerMount();
attachPacket.setVehicleId(itemLine.getNmsVehicle().getIdNMS());
attachPacket.setPassengers(new int[] {itemLine.getNmsItem().getIdNMS()});
attachPacket.sendPacket(player);
WrapperPlayServerEntityMetadata itemDataPacket = new WrapperPlayServerEntityMetadata();
List<WrappedWatchableObject> metadata = Utils.newList();
metadata.add(new WrappedWatchableObject(10, itemLine.getItemStack()));
metadata.add(new WrappedWatchableObject(1, (short) 300));
metadata.add(new WrappedWatchableObject(0, (byte) 0));
itemDataPacket.setEntityMetadata(metadata);
itemDataPacket.setEntityId(itemLine.getNmsItem().getIdNMS());
itemDataPacket.sendPacket(player);
}
}
// Unsafe cast, however both CraftTextLine and CraftItemLine are touchable.
CraftTouchableLine touchableLine = (CraftTouchableLine) line;
if (touchableLine.isSpawned() && touchableLine.getTouchSlime() != null) {
CraftTouchSlimeLine touchSlime = touchableLine.getTouchSlime();
if (touchSlime.isSpawned()) {
AbstractPacket vehiclePacket = new WrapperPlayServerSpawnEntityLiving(touchSlime.getNmsVehicle().getBukkitEntityNMS());
vehiclePacket.sendPacket(player);
AbstractPacket slimePacket = new WrapperPlayServerSpawnEntityLiving(touchSlime.getNmsSlime().getBukkitEntityNMS());
slimePacket.sendPacket(player);
WrapperPlayServerMount attachPacket = new WrapperPlayServerMount();
attachPacket.setVehicleId(touchSlime.getNmsVehicle().getIdNMS());
attachPacket.setPassengers(new int[] {touchSlime.getNmsSlime().getIdNMS()});
attachPacket.sendPacket(player);
}
}
}
}
}
private static boolean isHologramType(EntityType type) {
return type == EntityType.ARMOR_STAND || type == EntityType.DROPPED_ITEM || type == EntityType.SLIME;
}
private static CraftHologram getHologram(Entity bukkitEntity) {
NMSEntityBase entity = nmsManager.getNMSEntityBase(bukkitEntity);
if (entity != null) {
return entity.getHologramLine().getParent();
}
return null;
}
}

View File

@ -0,0 +1,61 @@
/*
* PacketWrapper - Contains wrappers for each packet in Minecraft.
* Copyright (C) 2012 Kristian S. Stangeland
*
* This program is free software; you can redistribute it and/or modify it under the terms of the
* GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with this program;
* if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
* 02111-1307 USA
*/
package com.gmail.filoghost.holographicdisplays.bridge.protocollib.current;
import java.util.List;
import com.comphenix.protocol.PacketType;
import com.comphenix.protocol.events.PacketContainer;
import com.google.common.primitives.Ints;
public class WrapperPlayServerEntityDestroy extends AbstractPacket {
public static final PacketType TYPE = PacketType.Play.Server.ENTITY_DESTROY;
public WrapperPlayServerEntityDestroy() {
super(new PacketContainer(TYPE), TYPE);
handle.getModifier().writeDefaults();
}
public WrapperPlayServerEntityDestroy(PacketContainer packet) {
super(packet, TYPE);
}
/**
* Retrieve the IDs of the entities that will be destroyed.
* @return The current entities.
*/
public List<Integer> getEntities() {
return Ints.asList(handle.getIntegerArrays().read(0));
}
/**
* Set the entities that will be destroyed.
* @param value - new value.
*/
public void setEntities(int[] entities) {
handle.getIntegerArrays().write(0, entities);
}
/**
* Set the entities that will be destroyed.
* @param value - new value.
*/
public void setEntities(List<Integer> entities) {
setEntities(Ints.toArray(entities));
}
}

View File

@ -0,0 +1,94 @@
/*
* PacketWrapper - Contains wrappers for each packet in Minecraft.
* Copyright (C) 2012 Kristian S. Stangeland
*
* This program is free software; you can redistribute it and/or modify it under the terms of the
* GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with this program;
* if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
* 02111-1307 USA
*/
package com.gmail.filoghost.holographicdisplays.bridge.protocollib.current;
import java.util.List;
import org.bukkit.World;
import org.bukkit.entity.Entity;
import com.comphenix.protocol.PacketType;
import com.comphenix.protocol.events.PacketContainer;
import com.comphenix.protocol.events.PacketEvent;
import com.comphenix.protocol.wrappers.WrappedDataWatcher;
import com.comphenix.protocol.wrappers.WrappedWatchableObject;
public class WrapperPlayServerEntityMetadata extends AbstractPacket {
public static final PacketType TYPE = PacketType.Play.Server.ENTITY_METADATA;
public WrapperPlayServerEntityMetadata() {
super(new PacketContainer(TYPE), TYPE);
handle.getModifier().writeDefaults();
}
public WrapperPlayServerEntityMetadata(PacketContainer packet) {
super(packet, TYPE);
}
/**
* Retrieve unique entity ID to update.
* @return The current Entity ID
*/
public int getEntityId() {
return handle.getIntegers().read(0);
}
/**
* Set unique entity ID to update.
* @param value - new value.
*/
public void setEntityId(int value) {
handle.getIntegers().write(0, value);
}
/**
* Retrieve the entity.
* @param world - the current world of the entity.
* @return The entity.
*/
public Entity getEntity(World world) {
return handle.getEntityModifier(world).read(0);
}
/**
* Retrieve the entity.
* @param event - the packet event.
* @return The entity.
*/
public Entity getEntity(PacketEvent event) {
return getEntity(event.getPlayer().getWorld());
}
/**
* Retrieve a list of all the watchable objects.
* <p>
* This can be converted to a data watcher using {@link WrappedDataWatcher#WrappedDataWatcher(List) WrappedDataWatcher(List)}
* @return The current metadata
*/
public List<WrappedWatchableObject> getEntityMetadata() {
return handle.getWatchableCollectionModifier().read(0);
}
/**
* Set the list of the watchable objects (meta data).
* @param value - new value.
*/
public void setEntityMetadata(List<WrappedWatchableObject> value) {
handle.getWatchableCollectionModifier().write(0, value);
}
}

View File

@ -0,0 +1,78 @@
/*
* PacketWrapper - Contains wrappers for each packet in Minecraft.
* Copyright (C) 2012 Kristian S. Stangeland
*
* This program is free software; you can redistribute it and/or modify it under the terms of the
* GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with this program;
* if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
* 02111-1307 USA
*/
package com.gmail.filoghost.holographicdisplays.bridge.protocollib.current;
import java.util.List;
import com.comphenix.protocol.PacketType;
import com.comphenix.protocol.events.PacketContainer;
import com.google.common.primitives.Ints;
public class WrapperPlayServerMount extends AbstractPacket {
public static final PacketType TYPE = PacketType.Play.Server.MOUNT;
public WrapperPlayServerMount() {
super(new PacketContainer(TYPE), TYPE);
handle.getModifier().writeDefaults();
}
public WrapperPlayServerMount(PacketContainer packet) {
super(packet, TYPE);
}
/**
* Retrieve the player entity ID being attached.
* @return The current Entity ID
*/
public int getVehicleId() {
return handle.getIntegers().read(0);
}
/**
* Set the player entity ID being attached.
* @param value - new value.
*/
public void setVehicleId(int value) {
handle.getIntegers().write(0, value);
}
/**
* Retrieve the IDs of the entities that will be destroyed.
* @return The current entities.
*/
public List<Integer> getPassengers() {
return Ints.asList(handle.getIntegerArrays().read(0));
}
/**
* Set the entities that will be destroyed.
* @param value - new value.
*/
public void setPassengers(int[] entities) {
handle.getIntegerArrays().write(0, entities);
}
/**
* Set the entities that will be destroyed.
* @param value - new value.
*/
public void setPassengers(List<Integer> entities) {
setPassengers(Ints.toArray(entities));
}
}

View File

@ -0,0 +1,148 @@
/*
* PacketWrapper - Contains wrappers for each packet in Minecraft.
* Copyright (C) 2012 Kristian S. Stangeland
*
* This program is free software; you can redistribute it and/or modify it under the terms of the
* GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with this program;
* if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
* 02111-1307 USA
*/
package com.gmail.filoghost.holographicdisplays.bridge.protocollib.current;
import org.bukkit.World;
import org.bukkit.entity.Entity;
import com.comphenix.protocol.PacketType;
import com.comphenix.protocol.ProtocolLibrary;
import com.comphenix.protocol.events.PacketContainer;
import com.comphenix.protocol.events.PacketEvent;
import com.comphenix.protocol.injector.PacketConstructor;
import com.comphenix.protocol.reflect.IntEnum;
public class WrapperPlayServerSpawnEntity extends AbstractPacket {
public static final PacketType TYPE = PacketType.Play.Server.SPAWN_ENTITY;
private static PacketConstructor entityConstructor;
/**
* Represents the different object types.
*
* @author Kristian
*/
public static class ObjectTypes extends IntEnum {
public static final int BOAT = 1;
public static final int ITEM_STACK = 2;
public static final int MINECART = 10;
public static final int MINECART_STORAGE = 11;
public static final int MINECART_POWERED = 12;
public static final int ACTIVATED_TNT = 50;
public static final int ENDER_CRYSTAL = 51;
public static final int ARROW_PROJECTILE = 60;
public static final int SNOWBALL_PROJECTILE = 61;
public static final int EGG_PROJECTILE = 62;
public static final int FIRE_BALL_GHAST = 63;
public static final int FIRE_BALL_BLAZE = 64;
public static final int THROWN_ENDERPEARL = 65;
public static final int WITHER_SKULL = 66;
public static final int FALLING_BLOCK = 70;
public static final int ITEM_FRAME = 71;
public static final int EYE_OF_ENDER = 72;
public static final int THROWN_POTION = 73;
public static final int FALLING_DRAGON_EGG = 74;
public static final int THROWN_EXP_BOTTLE = 75;
public static final int FIREWORK = 76;
public static final int ARMOR_STAND = 78;
public static final int FISHING_FLOAT = 90;
/**
* The singleton instance. Can also be retrieved from the parent class.
*/
private static ObjectTypes INSTANCE = new ObjectTypes();
/**
* Retrieve an instance of the object types enum.
* @return Object type enum.
*/
public static ObjectTypes getInstance() {
return INSTANCE;
}
}
public WrapperPlayServerSpawnEntity() {
super(new PacketContainer(TYPE), TYPE);
handle.getModifier().writeDefaults();
}
public WrapperPlayServerSpawnEntity(PacketContainer packet) {
super(packet, TYPE);
}
public WrapperPlayServerSpawnEntity(Entity entity, int type, int objectData) {
super(fromEntity(entity, type, objectData), TYPE);
}
// Useful constructor
private static PacketContainer fromEntity(Entity entity, int type, int objectData) {
if (entityConstructor == null)
entityConstructor = ProtocolLibrary.getProtocolManager().createPacketConstructor(TYPE, entity, type, objectData);
return entityConstructor.createPacket(entity, type, objectData);
}
/**
* Retrieve entity ID of the Object.
* @return The current EID
*/
public int getEntityID() {
return handle.getIntegers().read(0);
}
/**
* Retrieve the entity that will be spawned.
* @param world - the current world of the entity.
* @return The spawned entity.
*/
public Entity getEntity(World world) {
return handle.getEntityModifier(world).read(0);
}
/**
* Retrieve the entity that will be spawned.
* @param event - the packet event.
* @return The spawned entity.
*/
public Entity getEntity(PacketEvent event) {
return getEntity(event.getPlayer().getWorld());
}
/**
* Set entity ID of the Object.
* @param value - new value.
*/
public void setEntityID(int value) {
handle.getIntegers().write(0, value);
}
/**
* Retrieve the type of object. See {@link ObjectTypes}
* @return The current Type
*/
public int getType() {
return handle.getIntegers().read(6);
}
/**
* Set the type of object. See {@link ObjectTypes}.
* @param value - new value.
*/
public void setType(int value) {
handle.getIntegers().write(6, value);
}
}

View File

@ -0,0 +1,125 @@
/*
* PacketWrapper - Contains wrappers for each packet in Minecraft.
* Copyright (C) 2012 Kristian S. Stangeland
*
* This program is free software; you can redistribute it and/or modify it under the terms of the
* GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with this program;
* if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
* 02111-1307 USA
*/
package com.gmail.filoghost.holographicdisplays.bridge.protocollib.current;
import org.bukkit.World;
import org.bukkit.entity.Entity;
import org.bukkit.entity.EntityType;
import com.comphenix.protocol.PacketType;
import com.comphenix.protocol.ProtocolLibrary;
import com.comphenix.protocol.events.PacketContainer;
import com.comphenix.protocol.events.PacketEvent;
import com.comphenix.protocol.injector.PacketConstructor;
import com.comphenix.protocol.wrappers.WrappedDataWatcher;
public class WrapperPlayServerSpawnEntityLiving extends AbstractPacket {
public static final PacketType TYPE = PacketType.Play.Server.SPAWN_ENTITY_LIVING;
private static PacketConstructor entityConstructor;
public WrapperPlayServerSpawnEntityLiving() {
super(new PacketContainer(TYPE), TYPE);
handle.getModifier().writeDefaults();
}
public WrapperPlayServerSpawnEntityLiving(PacketContainer packet) {
super(packet, TYPE);
}
public WrapperPlayServerSpawnEntityLiving(Entity entity) {
super(fromEntity(entity), TYPE);
}
// Useful constructor
private static PacketContainer fromEntity(Entity entity) {
if (entityConstructor == null)
entityConstructor = ProtocolLibrary.getProtocolManager().createPacketConstructor(TYPE, entity);
return entityConstructor.createPacket(entity);
}
/**
* Retrieve entity ID.
* @return The current EID
*/
public int getEntityID() {
return handle.getIntegers().read(0);
}
/**
* Retrieve the entity that will be spawned.
* @param world - the current world of the entity.
* @return The spawned entity.
*/
public Entity getEntity(World world) {
return handle.getEntityModifier(world).read(0);
}
/**
* Retrieve the entity that will be spawned.
* @param event - the packet event.
* @return The spawned entity.
*/
public Entity getEntity(PacketEvent event) {
return getEntity(event.getPlayer().getWorld());
}
/**
* Set entity ID.
* @param value - new value.
*/
public void setEntityID(int value) {
handle.getIntegers().write(0, value);
}
/**
* Retrieve the type of mob.
* @return The current Type
*/
@SuppressWarnings("deprecation")
public EntityType getType() {
return EntityType.fromId(handle.getIntegers().read(1));
}
/**
* Set the type of mob.
* @param value - new value.
*/
@SuppressWarnings("deprecation")
public void setType(EntityType value) {
handle.getIntegers().write(1, (int) value.getTypeId());
}
/**
* Retrieve the data watcher.
* <p>
* Content varies by mob, see Entities.
* @return The current Metadata
*/
public WrappedDataWatcher getMetadata() {
return handle.getDataWatcherModifier().read(0);
}
/**
* Set the data watcher.
* @param value - new value.
*/
public void setMetadata(WrappedDataWatcher value) {
handle.getDataWatcherModifier().write(0, value);
}
}

View File

@ -15,7 +15,7 @@
* 02111-1307 USA
*/
package com.gmail.filoghost.holographicdisplays.bridge.protocollib;
package com.gmail.filoghost.holographicdisplays.bridge.protocollib.pre1_9;
import java.lang.reflect.InvocationTargetException;

View File

@ -1,4 +1,4 @@
package com.gmail.filoghost.holographicdisplays.bridge.protocollib;
package com.gmail.filoghost.holographicdisplays.bridge.protocollib.pre1_9;
import java.util.List;
@ -17,7 +17,7 @@ import com.comphenix.protocol.events.PacketEvent;
import com.comphenix.protocol.wrappers.WrappedDataWatcher;
import com.comphenix.protocol.wrappers.WrappedWatchableObject;
import com.gmail.filoghost.holographicdisplays.HolographicDisplays;
import com.gmail.filoghost.holographicdisplays.bridge.protocollib.WrapperPlayServerSpawnEntity.ObjectTypes;
import com.gmail.filoghost.holographicdisplays.bridge.protocollib.pre1_9.WrapperPlayServerSpawnEntity.ObjectTypes;
import com.gmail.filoghost.holographicdisplays.nms.interfaces.NMSManager;
import com.gmail.filoghost.holographicdisplays.nms.interfaces.entity.NMSEntityBase;
import com.gmail.filoghost.holographicdisplays.object.CraftHologram;
@ -236,7 +236,7 @@ public class ProtocolLibHook {
itemPacket.sendPacket(player);
AbstractPacket vehiclePacket;
if (HolographicDisplays.is1_8()) {
if (HolographicDisplays.is18orGreater()) {
// In 1.8 we have armor stands, that are living entities.
vehiclePacket = new WrapperPlayServerSpawnEntityLiving(itemLine.getNmsVehicle().getBukkitEntityNMS());
} else {
@ -272,7 +272,7 @@ public class ProtocolLibHook {
if (touchSlime.isSpawned()) {
AbstractPacket vehiclePacket;
if (HolographicDisplays.is1_8()) {
if (HolographicDisplays.is18orGreater()) {
// Armor stand vehicle
vehiclePacket = new WrapperPlayServerSpawnEntityLiving(touchSlime.getNmsVehicle().getBukkitEntityNMS());
} else {

View File

@ -15,7 +15,7 @@
* 02111-1307 USA
*/
package com.gmail.filoghost.holographicdisplays.bridge.protocollib;
package com.gmail.filoghost.holographicdisplays.bridge.protocollib.pre1_9;
import org.bukkit.World;
import org.bukkit.entity.Entity;

View File

@ -15,7 +15,7 @@
* 02111-1307 USA
*/
package com.gmail.filoghost.holographicdisplays.bridge.protocollib;
package com.gmail.filoghost.holographicdisplays.bridge.protocollib.pre1_9;
import java.util.List;

View File

@ -15,7 +15,7 @@
* 02111-1307 USA
*/
package com.gmail.filoghost.holographicdisplays.bridge.protocollib;
package com.gmail.filoghost.holographicdisplays.bridge.protocollib.pre1_9;
import java.util.List;

View File

@ -15,7 +15,7 @@
* 02111-1307 USA
*/
package com.gmail.filoghost.holographicdisplays.bridge.protocollib;
package com.gmail.filoghost.holographicdisplays.bridge.protocollib.pre1_9;
import org.bukkit.World;
import org.bukkit.entity.Entity;

View File

@ -15,7 +15,7 @@
* 02111-1307 USA
*/
package com.gmail.filoghost.holographicdisplays.bridge.protocollib;
package com.gmail.filoghost.holographicdisplays.bridge.protocollib.pre1_9;
import org.bukkit.World;
import org.bukkit.entity.Entity;

View File

@ -37,7 +37,7 @@ public class FixCommand extends HologramSubCommand {
@Override
public void execute(CommandSender sender, String label, String[] args) throws CommandException {
CommandValidator.isTrue(!HolographicDisplays.is1_8(), "This command is no longer necessary in 1.8+. The holograms already use the correct ambient light.");
CommandValidator.isTrue(!HolographicDisplays.is18orGreater(), "This command is no longer necessary in 1.8+. The holograms already use the correct ambient light.");
NamedHologram hologram = NamedHologramManager.getHologram(args[0].toLowerCase());
CommandValidator.notNull(hologram, Strings.noSuchHologram(args[0].toLowerCase()));
@ -70,7 +70,11 @@ public class FixCommand extends HologramSubCommand {
@Override
public SubCommandType getType() {
return SubCommandType.GENERIC;
if (HolographicDisplays.is18orGreater()) {
return SubCommandType.HIDDEN;
} else {
return SubCommandType.GENERIC;
}
}
}

View File

@ -95,16 +95,16 @@ public class MainListener implements Listener {
public void onSlimeInteract(PlayerInteractEntityEvent event) {
if (event.getRightClicked().getType() == EntityType.SLIME) {
Player clicker = event.getPlayer();
NMSEntityBase entityBase = nmsManager.getNMSEntityBase(event.getRightClicked());
if (entityBase == null) return;
if (entityBase.getHologramLine() instanceof CraftTouchSlimeLine) {
if (entityBase != null && entityBase.getHologramLine() instanceof CraftTouchSlimeLine && !isSpectatorMode(clicker)) {
CraftTouchSlimeLine touchSlime = (CraftTouchSlimeLine) entityBase.getHologramLine();
if (touchSlime.getTouchablePiece().getTouchHandler() != null && touchSlime.getParent().getVisibilityManager().isVisibleTo(event.getPlayer())) {
if (touchSlime.getTouchablePiece().getTouchHandler() != null && touchSlime.getParent().getVisibilityManager().isVisibleTo(clicker)) {
Long lastClick = anticlickSpam.get(event.getPlayer());
Long lastClick = anticlickSpam.get(clicker);
if (lastClick != null && System.currentTimeMillis() - lastClick.longValue() < 100) {
return;
}
@ -117,11 +117,15 @@ public class MainListener implements Listener {
Plugin plugin = touchSlime.getParent() instanceof PluginHologram ? ((PluginHologram) touchSlime.getParent()).getOwner() : HolographicDisplays.getInstance();
HolographicDisplays.getInstance().getLogger().log(Level.WARNING, "The plugin " + plugin.getName() + " generated an exception when the player " + event.getPlayer().getName() + " touched a hologram.", ex);
}
}
}
}
}
}
public static boolean isSpectatorMode(Player player) {
return player.getGameMode().toString().equals("SPECTATOR");
}
public static void handleItemLinePickup(Player player, PickupHandler pickupHandler, CraftHologram hologram) {
try {
if (hologram.getVisibilityManager().isVisibleTo(player)) {

View File

@ -35,6 +35,8 @@ import org.bukkit.plugin.Plugin;
import org.bukkit.plugin.PluginDescriptionFile;
import org.bukkit.scheduler.BukkitTask;
import com.gmail.filoghost.holographicdisplays.util.VersionUtils;
import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.File;
@ -277,7 +279,6 @@ public class MetricsLite {
/**
* Generic method that posts a plugin to the metrics website
*/
@SuppressWarnings("deprecation")
private void postPlugin(boolean isPing) throws IOException {
// Server software specific section
PluginDescriptionFile description = plugin.getDescription();
@ -285,7 +286,7 @@ public class MetricsLite {
boolean onlineMode = Bukkit.getServer().getOnlineMode(); // TRUE if online mode is enabled
String pluginVersion = description.getVersion();
String serverVersion = Bukkit.getVersion();
int playersOnline = Bukkit.getServer().getOnlinePlayers().length;
int playersOnline = VersionUtils.getOnlinePlayers().size();
// END server software specific section -- all code below does not use any code outside of this class / Java

View File

@ -0,0 +1,68 @@
package com.gmail.filoghost.holographicdisplays.nms.v1_9_R1;
import java.util.Collection;
import org.bukkit.EntityEffect;
import org.bukkit.Location;
import org.bukkit.craftbukkit.v1_9_R1.CraftServer;
import org.bukkit.craftbukkit.v1_9_R1.entity.CraftArmorStand;
import org.bukkit.entity.Entity;
import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause;
import org.bukkit.inventory.ItemStack;
import org.bukkit.potion.PotionEffect;
import org.bukkit.util.EulerAngle;
import org.bukkit.util.Vector;
public class CraftNMSArmorStand extends CraftArmorStand {
public CraftNMSArmorStand(CraftServer server, EntityNMSArmorStand entity) {
super(server, entity);
}
// Disallow all the bukkit methods.
@Override
public void remove() {
// Cannot be removed, this is the most important to override.
}
// Methods from Armor stand class
@Override public void setArms(boolean arms) { }
@Override public void setBasePlate(boolean basePlate) { }
@Override public void setBodyPose(EulerAngle pose) { }
@Override public void setBoots(ItemStack item) { }
@Override public void setChestplate(ItemStack item) { }
@Override public void setGravity(boolean gravity) { }
@Override public void setHeadPose(EulerAngle pose) { }
@Override public void setHelmet(ItemStack item) { }
@Override public void setItemInHand(ItemStack item) { }
@Override public void setLeftArmPose(EulerAngle pose) { }
@Override public void setLeftLegPose(EulerAngle pose) { }
@Override public void setLeggings(ItemStack item) { }
@Override public void setRightArmPose(EulerAngle pose) { }
@Override public void setRightLegPose(EulerAngle pose) { }
@Override public void setSmall(boolean small) { }
@Override public void setVisible(boolean visible) { }
@Override public void setMarker(boolean marker) { }
// Methods from LivingEntity class
@Override public boolean addPotionEffect(PotionEffect effect) { return false; }
@Override public boolean addPotionEffect(PotionEffect effect, boolean param) { return false; }
@Override public boolean addPotionEffects(Collection<PotionEffect> effects) { return false; }
@Override public void setRemoveWhenFarAway(boolean remove) { }
// Methods from Entity
@Override public void setVelocity(Vector vel) { }
@Override public boolean teleport(Location loc) { return false; }
@Override public boolean teleport(Entity entity) { return false; }
@Override public boolean teleport(Location loc, TeleportCause cause) { return false; }
@Override public boolean teleport(Entity entity, TeleportCause cause) { return false; }
@Override public void setFireTicks(int ticks) { }
@Override public boolean setPassenger(Entity entity) { return false; }
@Override public boolean eject() { return false; }
@Override public boolean leaveVehicle() { return false; }
@Override public void playEffect(EntityEffect effect) { }
@Override public void setCustomName(String name) { }
@Override public void setCustomNameVisible(boolean flag) { }
}

View File

@ -0,0 +1,43 @@
package com.gmail.filoghost.holographicdisplays.nms.v1_9_R1;
import org.bukkit.EntityEffect;
import org.bukkit.Location;
import org.bukkit.craftbukkit.v1_9_R1.CraftServer;
import org.bukkit.craftbukkit.v1_9_R1.entity.CraftItem;
import org.bukkit.entity.Entity;
import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause;
import org.bukkit.inventory.ItemStack;
import org.bukkit.util.Vector;
public class CraftNMSItem extends CraftItem {
public CraftNMSItem(CraftServer server, EntityNMSItem entity) {
super(server, entity);
}
// Disallow all the bukkit methods.
@Override
public void remove() {
// Cannot be removed, this is the most important to override.
}
// Methods from Entity
@Override public void setVelocity(Vector vel) { }
@Override public boolean teleport(Location loc) { return false; }
@Override public boolean teleport(Entity entity) { return false; }
@Override public boolean teleport(Location loc, TeleportCause cause) { return false; }
@Override public boolean teleport(Entity entity, TeleportCause cause) { return false; }
@Override public void setFireTicks(int ticks) { }
@Override public boolean setPassenger(Entity entity) { return false; }
@Override public boolean eject() { return false; }
@Override public boolean leaveVehicle() { return false; }
@Override public void playEffect(EntityEffect effect) { }
@Override public void setCustomName(String name) { }
@Override public void setCustomNameVisible(boolean flag) { }
// Methods from Item
@Override public void setItemStack(ItemStack stack) { }
@Override public void setPickupDelay(int delay) { }
}

View File

@ -0,0 +1,50 @@
package com.gmail.filoghost.holographicdisplays.nms.v1_9_R1;
import java.util.Collection;
import org.bukkit.EntityEffect;
import org.bukkit.Location;
import org.bukkit.craftbukkit.v1_9_R1.CraftServer;
import org.bukkit.craftbukkit.v1_9_R1.entity.CraftSlime;
import org.bukkit.entity.Entity;
import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause;
import org.bukkit.potion.PotionEffect;
import org.bukkit.util.Vector;
public class CraftNMSSlime extends CraftSlime {
public CraftNMSSlime(CraftServer server, EntityNMSSlime entity) {
super(server, entity);
}
// Disallow all the bukkit methods.
@Override
public void remove() {
// Cannot be removed, this is the most important to override.
}
// Methods from LivingEntity class
@Override public boolean addPotionEffect(PotionEffect effect) { return false; }
@Override public boolean addPotionEffect(PotionEffect effect, boolean param) { return false; }
@Override public boolean addPotionEffects(Collection<PotionEffect> effects) { return false; }
@Override public void setRemoveWhenFarAway(boolean remove) { }
// Methods from Entity
@Override public void setVelocity(Vector vel) { }
@Override public boolean teleport(Location loc) { return false; }
@Override public boolean teleport(Entity entity) { return false; }
@Override public boolean teleport(Location loc, TeleportCause cause) { return false; }
@Override public boolean teleport(Entity entity, TeleportCause cause) { return false; }
@Override public void setFireTicks(int ticks) { }
@Override public boolean setPassenger(Entity entity) { return false; }
@Override public boolean eject() { return false; }
@Override public boolean leaveVehicle() { return false; }
@Override public void playEffect(EntityEffect effect) { }
@Override public void setCustomName(String name) { }
@Override public void setCustomNameVisible(boolean flag) { }
// Methods from Slime
@Override public void setSize(int size) { }
}

View File

@ -0,0 +1,236 @@
package com.gmail.filoghost.holographicdisplays.nms.v1_9_R1;
import net.minecraft.server.v1_9_R1.AxisAlignedBB;
import net.minecraft.server.v1_9_R1.DamageSource;
import net.minecraft.server.v1_9_R1.EntityArmorStand;
import net.minecraft.server.v1_9_R1.EntityHuman;
import net.minecraft.server.v1_9_R1.EntityPlayer;
import net.minecraft.server.v1_9_R1.EnumHand;
import net.minecraft.server.v1_9_R1.EnumInteractionResult;
import net.minecraft.server.v1_9_R1.EnumItemSlot;
import net.minecraft.server.v1_9_R1.ItemStack;
import net.minecraft.server.v1_9_R1.NBTTagCompound;
import net.minecraft.server.v1_9_R1.PacketPlayOutEntityTeleport;
import net.minecraft.server.v1_9_R1.SoundEffect;
import net.minecraft.server.v1_9_R1.Vec3D;
import net.minecraft.server.v1_9_R1.World;
import org.bukkit.craftbukkit.v1_9_R1.entity.CraftEntity;
import com.gmail.filoghost.holographicdisplays.nms.interfaces.entity.NMSArmorStand;
import com.gmail.filoghost.holographicdisplays.object.line.CraftHologramLine;
import com.gmail.filoghost.holographicdisplays.util.ReflectionUtils;
import com.gmail.filoghost.holographicdisplays.util.Utils;
public class EntityNMSArmorStand extends EntityArmorStand implements NMSArmorStand {
private boolean lockTick;
private CraftHologramLine parentPiece;
public EntityNMSArmorStand(World world, CraftHologramLine parentPiece) {
super(world);
super.setInvisible(true);
super.setSmall(true);
super.setArms(false);
super.setGravity(true);
super.setBasePlate(true);
super.setMarker(true);
this.parentPiece = parentPiece;
try {
ReflectionUtils.setPrivateField(EntityArmorStand.class, this, "bz", Integer.MAX_VALUE);
} catch (Exception e) {
// There's still the overridden method.
}
forceSetBoundingBox(new NullBoundingBox());
}
@Override
public void b(NBTTagCompound nbttagcompound) {
// Do not save NBT.
}
@Override
public boolean c(NBTTagCompound nbttagcompound) {
// Do not save NBT.
return false;
}
@Override
public boolean d(NBTTagCompound nbttagcompound) {
// Do not save NBT.
return false;
}
@Override
public void e(NBTTagCompound nbttagcompound) {
// Do not save NBT.
}
@Override
public void f(NBTTagCompound nbttagcompound) {
// Do not load NBT.
}
@Override
public void a(NBTTagCompound nbttagcompound) {
// Do not load NBT.
}
@Override
public boolean isInvulnerable(DamageSource source) {
/*
* The field Entity.invulnerable is private.
* It's only used while saving NBTTags, but since the entity would be killed
* on chunk unload, we prefer to override isInvulnerable().
*/
return true;
}
@Override
public boolean isCollidable() {
return false;
}
@Override
public void setCustomName(String customName) {
// Locks the custom name.
}
@Override
public void setCustomNameVisible(boolean visible) {
// Locks the custom name.
}
@Override
public EnumInteractionResult a(EntityHuman human, Vec3D vec3d, ItemStack itemstack, EnumHand enumhand) {
// Prevent stand being equipped
return EnumInteractionResult.PASS;
}
@Override
public boolean c(int i, ItemStack item) {
// Prevent stand being equipped
return false;
}
@Override
public void setSlot(EnumItemSlot enumitemslot, ItemStack itemstack) {
// Prevent stand being equipped
}
@Override
public void a(AxisAlignedBB boundingBox) {
// Do not change it!
}
public void forceSetBoundingBox(AxisAlignedBB boundingBox) {
super.a(boundingBox);
}
@Override
public int getId() {
StackTraceElement[] elements = Thread.currentThread().getStackTrace();
if (elements.length > 2 && elements[2] != null && elements[2].getFileName().equals("EntityTrackerEntry.java") && elements[2].getLineNumber() > 142 && elements[2].getLineNumber() < 152) {
// Then this method is being called when creating a new packet, we return a fake ID!
return -1;
}
return super.getId();
}
@Override
public void m() {
if (!lockTick) {
super.m();
}
}
@Override
public void a(SoundEffect soundeffect, float f, float f1) {
// Remove sounds.
}
@Override
public void setCustomNameNMS(String name) {
if (name != null && name.length() > 300) {
name = name.substring(0, 300);
}
super.setCustomName(name);
super.setCustomNameVisible(name != null && !name.isEmpty());
}
@Override
public String getCustomNameNMS() {
return super.getCustomName();
}
public void callSuperTick() {
super.h();
}
@Override
public void setLockTick(boolean lock) {
lockTick = lock;
}
@Override
public void die() {
// Prevent being killed.
}
@Override
public CraftEntity getBukkitEntity() {
if (super.bukkitEntity == null) {
super.bukkitEntity = new CraftNMSArmorStand(super.world.getServer(), this);
}
return super.bukkitEntity;
}
@Override
public void killEntityNMS() {
super.dead = true;
}
@Override
public void setLocationNMS(double x, double y, double z) {
super.setPosition(x, y, z);
// Send a packet near to update the position.
PacketPlayOutEntityTeleport teleportPacket = new PacketPlayOutEntityTeleport(this);
for (Object obj : super.world.players) {
if (obj instanceof EntityPlayer) {
EntityPlayer nmsPlayer = (EntityPlayer) obj;
double distanceSquared = Utils.square(nmsPlayer.locX - super.locX) + Utils.square(nmsPlayer.locZ - super.locZ);
if (distanceSquared < 8192 && nmsPlayer.playerConnection != null) {
nmsPlayer.playerConnection.sendPacket(teleportPacket);
}
}
}
}
@Override
public boolean isDeadNMS() {
return super.dead;
}
@Override
public int getIdNMS() {
return super.getId(); // Return the real ID without checking the stack trace.
}
@Override
public CraftHologramLine getHologramLine() {
return parentPiece;
}
@Override
public org.bukkit.entity.Entity getBukkitEntityNMS() {
return getBukkitEntity();
}
}

View File

@ -0,0 +1,261 @@
package com.gmail.filoghost.holographicdisplays.nms.v1_9_R1;
import net.minecraft.server.v1_9_R1.Entity;
import net.minecraft.server.v1_9_R1.Blocks;
import net.minecraft.server.v1_9_R1.DamageSource;
import net.minecraft.server.v1_9_R1.EntityHuman;
import net.minecraft.server.v1_9_R1.EntityItem;
import net.minecraft.server.v1_9_R1.EntityPlayer;
import net.minecraft.server.v1_9_R1.ItemStack;
import net.minecraft.server.v1_9_R1.NBTTagCompound;
import net.minecraft.server.v1_9_R1.NBTTagList;
import net.minecraft.server.v1_9_R1.NBTTagString;
import net.minecraft.server.v1_9_R1.PacketPlayOutMount;
import net.minecraft.server.v1_9_R1.World;
import org.bukkit.craftbukkit.v1_9_R1.entity.CraftEntity;
import org.bukkit.craftbukkit.v1_9_R1.inventory.CraftItemStack;
import org.bukkit.entity.Player;
import com.gmail.filoghost.holographicdisplays.listener.MainListener;
import com.gmail.filoghost.holographicdisplays.nms.interfaces.entity.NMSEntityBase;
import com.gmail.filoghost.holographicdisplays.nms.interfaces.entity.NMSItem;
import com.gmail.filoghost.holographicdisplays.object.line.CraftItemLine;
import com.gmail.filoghost.holographicdisplays.util.DebugHandler;
import com.gmail.filoghost.holographicdisplays.util.ItemUtils;
import com.gmail.filoghost.holographicdisplays.util.ReflectionUtils;
import com.gmail.filoghost.holographicdisplays.util.Utils;
public class EntityNMSItem extends EntityItem implements NMSItem {
private boolean lockTick;
private CraftItemLine parentPiece;
private int resendMountPacketTicks;
public EntityNMSItem(World world, CraftItemLine piece) {
super(world);
super.pickupDelay = Integer.MAX_VALUE;
this.parentPiece = piece;
}
@Override
public void m() {
// So it won't get removed.
ticksLived = 0;
if (resendMountPacketTicks++ > 20) {
resendMountPacketTicks = 0;
if (by() != null) {
// Send a packet near to "remind" players that the item is riding the armor stand (Spigot bug or client bug)
PacketPlayOutMount mountPacket = new PacketPlayOutMount(by());
for (Object obj : super.world.players) {
if (obj instanceof EntityPlayer) {
EntityPlayer nmsPlayer = (EntityPlayer) obj;
double distanceSquared = Utils.square(nmsPlayer.locX - super.locX) + Utils.square(nmsPlayer.locZ - super.locZ);
if (distanceSquared < 1024 && nmsPlayer.playerConnection != null) {
nmsPlayer.playerConnection.sendPacket(mountPacket);
}
}
}
}
}
if (!lockTick) {
super.m();
}
}
@Override
public ItemStack getItemStack() {
// Dirty method to check if the icon is being picked up
StackTraceElement[] stacktrace = Thread.currentThread().getStackTrace();
if (stacktrace.length > 2 && stacktrace[2].getClassName().contains("EntityInsentient")) {
return null; // Try to pickup this, dear entity ignoring the pickupDelay!
}
return super.getItemStack();
}
// Method called when a player is near.
@Override
public void d(EntityHuman human) {
if (human.locY < super.locY - 1.5 || human.locY > super.locY + 1.0) {
// Too low or too high, it's a bit weird.
return;
}
if (parentPiece.getPickupHandler() != null && human instanceof EntityPlayer) {
MainListener.handleItemLinePickup((Player) human.getBukkitEntity(), parentPiece.getPickupHandler(), parentPiece.getParent());
// It is never added to the inventory.
}
}
@Override
public void b(NBTTagCompound nbttagcompound) {
// Do not save NBT.
}
@Override
public boolean c(NBTTagCompound nbttagcompound) {
// Do not save NBT.
return false;
}
@Override
public boolean d(NBTTagCompound nbttagcompound) {
// Do not save NBT.
return false;
}
@Override
public void e(NBTTagCompound nbttagcompound) {
// Do not save NBT.
}
@Override
public void f(NBTTagCompound nbttagcompound) {
// Do not load NBT.
}
@Override
public void a(NBTTagCompound nbttagcompound) {
// Do not load NBT.
}
@Override
public boolean isInvulnerable(DamageSource source) {
/*
* The field Entity.invulnerable is private.
* It's only used while saving NBTTags, but since the entity would be killed
* on chunk unload, we prefer to override isInvulnerable().
*/
return true;
}
@Override
public boolean isCollidable() {
return false;
}
@Override
public void inactiveTick() {
// Check inactive ticks.
if (!lockTick) {
super.inactiveTick();
}
}
@Override
public void setLockTick(boolean lock) {
lockTick = lock;
}
@Override
public void die() {
// Prevent being killed.
}
@Override
public CraftEntity getBukkitEntity() {
if (super.bukkitEntity == null) {
super.bukkitEntity = new CraftNMSItem(super.world.getServer(), this);
}
return super.bukkitEntity;
}
@Override
public boolean isDeadNMS() {
return super.dead;
}
@Override
public void killEntityNMS() {
super.dead = true;
}
@Override
public void setLocationNMS(double x, double y, double z) {
super.setPosition(x, y, z);
}
@Override
public void setItemStackNMS(org.bukkit.inventory.ItemStack stack) {
ItemStack newItem = CraftItemStack.asNMSCopy(stack);
if (newItem == null) {
newItem = new ItemStack(Blocks.BEDROCK);
}
if (newItem.getTag() == null) {
newItem.setTag(new NBTTagCompound());
}
NBTTagCompound display = newItem.getTag().getCompound("display");
if (!newItem.getTag().hasKey("display")) {
newItem.getTag().set("display", display);
}
NBTTagList tagList = new NBTTagList();
tagList.add(new NBTTagString(ItemUtils.ANTISTACK_LORE)); // Antistack lore
display.set("Lore", tagList);
newItem.count = 0;
setItemStack(newItem);
}
@Override
public int getIdNMS() {
return super.getId();
}
@Override
public CraftItemLine getHologramLine() {
return parentPiece;
}
@Override
public void allowPickup(boolean pickup) {
if (pickup) {
super.pickupDelay = 0;
} else {
super.pickupDelay = Integer.MAX_VALUE;
}
}
@Override
public org.bukkit.entity.Entity getBukkitEntityNMS() {
return getBukkitEntity();
}
@Override
public void setPassengerOfNMS(NMSEntityBase vehicleBase) {
if (vehicleBase == null || !(vehicleBase instanceof Entity)) {
// It should never dismount
return;
}
Entity entity = (Entity) vehicleBase;
try {
if (super.by() != null) {
Entity oldVehicle = super.by();
ReflectionUtils.setPrivateField(Entity.class, this, "as", null);
oldVehicle.passengers.remove(this);
}
ReflectionUtils.setPrivateField(Entity.class, this, "as", entity);
entity.passengers.clear();
entity.passengers.add(this);
} catch (Exception ex) {
DebugHandler.handleDebugException(ex);
}
}
}

View File

@ -0,0 +1,228 @@
package com.gmail.filoghost.holographicdisplays.nms.v1_9_R1;
import net.minecraft.server.v1_9_R1.EntityDamageSource;
import net.minecraft.server.v1_9_R1.EntityPlayer;
import net.minecraft.server.v1_9_R1.AxisAlignedBB;
import net.minecraft.server.v1_9_R1.DamageSource;
import net.minecraft.server.v1_9_R1.Entity;
import net.minecraft.server.v1_9_R1.EntitySlime;
import net.minecraft.server.v1_9_R1.NBTTagCompound;
import net.minecraft.server.v1_9_R1.PacketPlayOutMount;
import net.minecraft.server.v1_9_R1.SoundEffect;
import net.minecraft.server.v1_9_R1.World;
import org.bukkit.Bukkit;
import org.bukkit.craftbukkit.v1_9_R1.entity.CraftEntity;
import org.bukkit.event.player.PlayerInteractEntityEvent;
import com.gmail.filoghost.holographicdisplays.nms.interfaces.entity.NMSEntityBase;
import com.gmail.filoghost.holographicdisplays.nms.interfaces.entity.NMSSlime;
import com.gmail.filoghost.holographicdisplays.object.line.CraftHologramLine;
import com.gmail.filoghost.holographicdisplays.object.line.CraftTouchSlimeLine;
import com.gmail.filoghost.holographicdisplays.util.DebugHandler;
import com.gmail.filoghost.holographicdisplays.util.ReflectionUtils;
import com.gmail.filoghost.holographicdisplays.util.Utils;
public class EntityNMSSlime extends EntitySlime implements NMSSlime {
private boolean lockTick;
private CraftTouchSlimeLine parentPiece;
private int resendMountPacketTicks;
public EntityNMSSlime(World world, CraftTouchSlimeLine parentPiece) {
super(world);
super.persistent = true;
a(0.0F, 0.0F);
setSize(1);
setInvisible(true);
this.parentPiece = parentPiece;
forceSetBoundingBox(new NullBoundingBox());
}
@Override
public void a(AxisAlignedBB boundingBox) {
// Do not change it!
}
public void forceSetBoundingBox(AxisAlignedBB boundingBox) {
super.a(boundingBox);
}
@Override
public void m() {
// So it won't get removed.
ticksLived = 0;
if (resendMountPacketTicks++ > 20) {
resendMountPacketTicks = 0;
if (by() != null) {
// Send a packet near to "remind" players that the slime is riding the armor stand (Spigot bug or client bug)
PacketPlayOutMount mountPacket = new PacketPlayOutMount(by());
for (Object obj : super.world.players) {
if (obj instanceof EntityPlayer) {
EntityPlayer nmsPlayer = (EntityPlayer) obj;
double distanceSquared = Utils.square(nmsPlayer.locX - super.locX) + Utils.square(nmsPlayer.locZ - super.locZ);
if (distanceSquared < 1024 && nmsPlayer.playerConnection != null) {
nmsPlayer.playerConnection.sendPacket(mountPacket);
}
}
}
}
}
if (!lockTick) {
super.m();
}
}
@Override
public void b(NBTTagCompound nbttagcompound) {
// Do not save NBT.
}
@Override
public boolean c(NBTTagCompound nbttagcompound) {
// Do not save NBT.
return false;
}
@Override
public boolean d(NBTTagCompound nbttagcompound) {
// Do not save NBT.
return false;
}
@Override
public void e(NBTTagCompound nbttagcompound) {
// Do not save NBT.
}
@Override
public void f(NBTTagCompound nbttagcompound) {
// Do not load NBT.
}
@Override
public void a(NBTTagCompound nbttagcompound) {
// Do not load NBT.
}
@Override
public boolean damageEntity(DamageSource damageSource, float amount) {
if (damageSource instanceof EntityDamageSource) {
EntityDamageSource entityDamageSource = (EntityDamageSource) damageSource;
if (entityDamageSource.getEntity() instanceof EntityPlayer) {
Bukkit.getPluginManager().callEvent(new PlayerInteractEntityEvent(((EntityPlayer) entityDamageSource.getEntity()).getBukkitEntity(), getBukkitEntity())); // Bukkit takes care of the exceptions
}
}
return false;
}
@Override
public boolean isInvulnerable(DamageSource source) {
/*
* The field Entity.invulnerable is private.
* It's only used while saving NBTTags, but since the entity would be killed
* on chunk unload, we prefer to override isInvulnerable().
*/
return true;
}
@Override
public boolean isCollidable() {
return false;
}
@Override
public void setCustomName(String customName) {
// Locks the custom name.
}
@Override
public void setCustomNameVisible(boolean visible) {
// Locks the custom name.
}
@Override
public void a(SoundEffect soundeffect, float f, float f1) {
// Remove sounds.
}
@Override
public void setLockTick(boolean lock) {
lockTick = lock;
}
@Override
public void die() {
// Prevent being killed.
}
@Override
public CraftEntity getBukkitEntity() {
if (super.bukkitEntity == null) {
super.bukkitEntity = new CraftNMSSlime(super.world.getServer(), this);
}
return super.bukkitEntity;
}
@Override
public boolean isDeadNMS() {
return super.dead;
}
@Override
public void killEntityNMS() {
super.dead = true;
}
@Override
public void setLocationNMS(double x, double y, double z) {
super.setPosition(x, y, z);
}
@Override
public int getIdNMS() {
return super.getId();
}
@Override
public CraftHologramLine getHologramLine() {
return parentPiece;
}
@Override
public org.bukkit.entity.Entity getBukkitEntityNMS() {
return getBukkitEntity();
}
@Override
public void setPassengerOfNMS(NMSEntityBase vehicleBase) {
if (vehicleBase == null || !(vehicleBase instanceof Entity)) {
// It should never dismount
return;
}
Entity entity = (Entity) vehicleBase;
try {
if (super.by() != null) {
Entity oldVehicle = super.by();
ReflectionUtils.setPrivateField(Entity.class, this, "as", null);
oldVehicle.passengers.remove(this);
}
ReflectionUtils.setPrivateField(Entity.class, this, "as", entity);
entity.passengers.clear();
entity.passengers.add(this);
} catch (Exception ex) {
DebugHandler.handleDebugException(ex);
}
}
}

View File

@ -0,0 +1,170 @@
package com.gmail.filoghost.holographicdisplays.nms.v1_9_R1;
import java.io.IOException;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.List;
import net.minecraft.server.v1_9_R1.IChatBaseComponent;
import net.minecraft.server.v1_9_R1.PacketPlayOutChat;
import org.bukkit.ChatColor;
import com.google.gson.stream.JsonWriter;
import org.bukkit.craftbukkit.v1_9_R1.entity.CraftPlayer;
import org.bukkit.entity.Player;
import com.gmail.filoghost.holographicdisplays.nms.interfaces.FancyMessage;
public class FancyMessageImpl implements FancyMessage {
private List<MessagePart> messageParts;
public FancyMessageImpl(String firstPartText) {
messageParts = new ArrayList<MessagePart>();
messageParts.add(new MessagePart(firstPartText));
}
@Override
public FancyMessageImpl color(ChatColor color) {
if (!color.isColor()) {
throw new IllegalArgumentException(color.name() + " is not a color");
}
latest().color = color;
return this;
}
@Override
public FancyMessageImpl style(ChatColor... styles) {
for (ChatColor style : styles) {
if (!style.isFormat()) {
throw new IllegalArgumentException(style.name() + " is not a style");
}
}
latest().styles = styles;
return this;
}
@Override
public FancyMessageImpl file(String path) {
onClick("open_file", path);
return this;
}
@Override
public FancyMessageImpl link(String url) {
onClick("open_url", url);
return this;
}
@Override
public FancyMessageImpl suggest(String command) {
onClick("suggest_command", command);
return this;
}
@Override
public FancyMessageImpl command(String command) {
onClick("run_command", command);
return this;
}
@Override
public FancyMessageImpl tooltip(String text) {
onHover("show_text", text);
return this;
}
@Override
public FancyMessageImpl then(Object obj) {
messageParts.add(new MessagePart(obj.toString()));
return this;
}
@Override
public String toJSONString() {
StringWriter stringWriter = new StringWriter();
JsonWriter json = new JsonWriter(stringWriter);
try {
if (messageParts.size() == 1) {
latest().writeJson(json);
} else {
json.beginObject().name("text").value("").name("extra").beginArray();
for (MessagePart part : messageParts) {
part.writeJson(json);
}
json.endArray().endObject();
}
} catch (IOException e) {
throw new RuntimeException("invalid message");
}
return stringWriter.toString();
}
@Override
public void send(Player player) {
((CraftPlayer) player).getHandle().playerConnection.sendPacket(new PacketPlayOutChat(IChatBaseComponent.ChatSerializer.a(toJSONString())));
}
private MessagePart latest() {
return messageParts.get(messageParts.size() - 1);
}
private void onClick(String name, String data) {
MessagePart latest = latest();
latest.clickActionName = name;
latest.clickActionData = data;
}
private void onHover(String name, String data) {
MessagePart latest = latest();
latest.hoverActionName = name;
latest.hoverActionData = data;
}
static class MessagePart {
public ChatColor color = null;
public ChatColor[] styles = null;
public String clickActionName = null;
public String clickActionData = null;
public String hoverActionName = null;
public String hoverActionData = null;
public final String text;
public MessagePart(final String text) {
this.text = text;
}
public JsonWriter writeJson(final JsonWriter json) throws IOException {
json.beginObject().name("text").value(text);
if (color != null) {
json.name("color").value(color.name().toLowerCase());
}
if (styles != null) {
for (final ChatColor style : styles) {
json.name(style == ChatColor.UNDERLINE ? "underlined" : style.name().toLowerCase()).value(true);
}
}
if (clickActionName != null && clickActionData != null) {
json.name("clickEvent")
.beginObject()
.name("action").value(clickActionName)
.name("value").value(clickActionData)
.endObject();
}
if (hoverActionName != null && hoverActionData != null) {
json.name("hoverEvent")
.beginObject()
.name("action").value(hoverActionName)
.name("value").value(hoverActionData)
.endObject();
}
return json.endObject();
}
}
}

View File

@ -0,0 +1,152 @@
package com.gmail.filoghost.holographicdisplays.nms.v1_9_R1;
import java.lang.reflect.Method;
import net.minecraft.server.v1_9_R1.Entity;
import net.minecraft.server.v1_9_R1.EntityTypes;
import net.minecraft.server.v1_9_R1.MathHelper;
import net.minecraft.server.v1_9_R1.World;
import net.minecraft.server.v1_9_R1.WorldServer;
import org.apache.commons.lang.NotImplementedException;
import org.bukkit.Bukkit;
import org.bukkit.craftbukkit.v1_9_R1.CraftWorld;
import org.bukkit.craftbukkit.v1_9_R1.entity.CraftEntity;
import org.bukkit.inventory.ItemStack;
import com.gmail.filoghost.holographicdisplays.nms.interfaces.FancyMessage;
import com.gmail.filoghost.holographicdisplays.nms.interfaces.NMSManager;
import com.gmail.filoghost.holographicdisplays.nms.interfaces.entity.NMSArmorStand;
import com.gmail.filoghost.holographicdisplays.nms.interfaces.entity.NMSEntityBase;
import com.gmail.filoghost.holographicdisplays.nms.interfaces.entity.NMSHorse;
import com.gmail.filoghost.holographicdisplays.nms.interfaces.entity.NMSItem;
import com.gmail.filoghost.holographicdisplays.nms.interfaces.entity.NMSWitherSkull;
import com.gmail.filoghost.holographicdisplays.object.line.CraftHologramLine;
import com.gmail.filoghost.holographicdisplays.object.line.CraftItemLine;
import com.gmail.filoghost.holographicdisplays.object.line.CraftTouchSlimeLine;
import com.gmail.filoghost.holographicdisplays.util.DebugHandler;
import com.gmail.filoghost.holographicdisplays.util.ReflectionUtils;
import com.gmail.filoghost.holographicdisplays.util.Validator;
import com.gmail.filoghost.holographicdisplays.util.VersionUtils;
public class NmsManagerImpl implements NMSManager {
private Method validateEntityMethod;
@Override
public void setup() throws Exception {
registerCustomEntity(EntityNMSArmorStand.class, "ArmorStand", 30);
registerCustomEntity(EntityNMSItem.class, "Item", 1);
registerCustomEntity(EntityNMSSlime.class, "Slime", 55);
validateEntityMethod = World.class.getDeclaredMethod("b", Entity.class);
validateEntityMethod.setAccessible(true);
}
@SuppressWarnings("rawtypes")
public void registerCustomEntity(Class entityClass, String name, int id) throws Exception {
if (VersionUtils.isMCPCOrCauldron()) {
// MCPC+ / Cauldron entity registration.
throw new UnsupportedOperationException("MCPC, Cauldron and similar softwares are not supported");
} else {
// Normal entity registration.
ReflectionUtils.putInPrivateStaticMap(EntityTypes.class, "d", entityClass, name);
ReflectionUtils.putInPrivateStaticMap(EntityTypes.class, "f", entityClass, Integer.valueOf(id));
}
}
@Override
public NMSHorse spawnNMSHorse(org.bukkit.World world, double x, double y, double z, CraftHologramLine parentPiece) {
throw new NotImplementedException("Method can only be used on 1.7 or lower");
}
@Override
public NMSWitherSkull spawnNMSWitherSkull(org.bukkit.World bukkitWorld, double x, double y, double z, CraftHologramLine parentPiece) {
throw new NotImplementedException("Method can only be used on 1.7 or lower");
}
@Override
public NMSItem spawnNMSItem(org.bukkit.World bukkitWorld, double x, double y, double z, CraftItemLine parentPiece, ItemStack stack) {
WorldServer nmsWorld = ((CraftWorld) bukkitWorld).getHandle();
EntityNMSItem customItem = new EntityNMSItem(nmsWorld, parentPiece);
customItem.setLocationNMS(x, y, z);
customItem.setItemStackNMS(stack);
if (!addEntityToWorld(nmsWorld, customItem)) {
DebugHandler.handleSpawnFail(parentPiece);
}
return customItem;
}
@Override
public EntityNMSSlime spawnNMSSlime(org.bukkit.World bukkitWorld, double x, double y, double z, CraftTouchSlimeLine parentPiece) {
WorldServer nmsWorld = ((CraftWorld) bukkitWorld).getHandle();
EntityNMSSlime touchSlime = new EntityNMSSlime(nmsWorld, parentPiece);
touchSlime.setLocationNMS(x, y, z);
if (!addEntityToWorld(nmsWorld, touchSlime)) {
DebugHandler.handleSpawnFail(parentPiece);
}
return touchSlime;
}
@Override
public NMSArmorStand spawnNMSArmorStand(org.bukkit.World world, double x, double y, double z, CraftHologramLine parentPiece) {
WorldServer nmsWorld = ((CraftWorld) world).getHandle();
EntityNMSArmorStand invisibleArmorStand = new EntityNMSArmorStand(nmsWorld, parentPiece);
invisibleArmorStand.setLocationNMS(x, y, z);
if (!addEntityToWorld(nmsWorld, invisibleArmorStand)) {
DebugHandler.handleSpawnFail(parentPiece);
}
return invisibleArmorStand;
}
private boolean addEntityToWorld(WorldServer nmsWorld, Entity nmsEntity) {
Validator.isTrue(Bukkit.isPrimaryThread(), "Async entity add");
final int chunkX = MathHelper.floor(nmsEntity.locX / 16.0);
final int chunkZ = MathHelper.floor(nmsEntity.locZ / 16.0);
if (!nmsWorld.getChunkProviderServer().isChunkLoaded(chunkX, chunkZ)) {
// This should never happen
nmsEntity.dead = true;
return false;
}
nmsWorld.getChunkAt(chunkX, chunkZ).a(nmsEntity);
nmsWorld.entityList.add(nmsEntity);
try {
validateEntityMethod.invoke(nmsWorld, nmsEntity);
} catch (Exception e) {
e.printStackTrace();
return false;
}
return true;
}
@Override
public boolean isNMSEntityBase(org.bukkit.entity.Entity bukkitEntity) {
return ((CraftEntity) bukkitEntity).getHandle() instanceof NMSEntityBase;
}
@Override
public NMSEntityBase getNMSEntityBase(org.bukkit.entity.Entity bukkitEntity) {
Entity nmsEntity = ((CraftEntity) bukkitEntity).getHandle();
if (nmsEntity instanceof NMSEntityBase) {
return ((NMSEntityBase) nmsEntity);
}
return null;
}
@Override
public FancyMessage newFancyMessage(String text) {
return new FancyMessageImpl(text);
}
@Override
public boolean hasChatHoverFeature() {
return true;
}
}

View File

@ -0,0 +1,111 @@
package com.gmail.filoghost.holographicdisplays.nms.v1_9_R1;
import net.minecraft.server.v1_9_R1.AxisAlignedBB;
import net.minecraft.server.v1_9_R1.BlockPosition;
import net.minecraft.server.v1_9_R1.MovingObjectPosition;
import net.minecraft.server.v1_9_R1.Vec3D;
public class NullBoundingBox extends AxisAlignedBB {
public NullBoundingBox() {
super(0, 0, 0, 0, 0, 0);
}
@Override
public double a() {
return 0.0;
}
@Override
public double a(AxisAlignedBB arg0, double arg1) {
return 0.0;
}
@Override
public AxisAlignedBB a(AxisAlignedBB arg0) {
return this;
}
@Override
public AxisAlignedBB a(double arg0, double arg1, double arg2) {
return this;
}
@Override
public MovingObjectPosition a(Vec3D arg0, Vec3D arg1) {
return super.a(arg0, arg1);
}
@Override
public boolean a(Vec3D arg0) {
return false;
}
@Override
public double b(AxisAlignedBB arg0, double arg1) {
return 0.0;
}
@Override
public boolean b(AxisAlignedBB arg0) {
return false;
}
@Override
public double c(AxisAlignedBB arg0, double arg1) {
return 0.0;
}
@Override
public AxisAlignedBB c(double arg0, double arg1, double arg2) {
return this;
}
@Override
public AxisAlignedBB grow(double arg0, double arg1, double arg2) {
return this;
}
@Override
public AxisAlignedBB shrink(double arg0) {
return this;
}
@Override
public AxisAlignedBB a(BlockPosition arg0) {
return this;
}
@Override
public boolean a(double arg0, double arg1, double arg2, double arg3, double arg4, double arg5) {
return false;
}
@Override
public boolean b(Vec3D arg0) {
return false;
}
@Override
public boolean c(Vec3D arg0) {
return false;
}
@Override
public boolean d(Vec3D arg0) {
return false;
}
@Override
public AxisAlignedBB e(double arg0) {
return this;
}
@Override
public AxisAlignedBB g(double arg0) {
return this;
}
}

View File

@ -10,8 +10,9 @@ import org.bukkit.entity.Player;
import com.gmail.filoghost.holographicdisplays.HolographicDisplays;
import com.gmail.filoghost.holographicdisplays.api.VisibilityManager;
import com.gmail.filoghost.holographicdisplays.bridge.protocollib.ProtocolLibHook;
import com.gmail.filoghost.holographicdisplays.bridge.protocollib.pre1_9.ProtocolLibHook;
import com.gmail.filoghost.holographicdisplays.util.Validator;
import com.gmail.filoghost.holographicdisplays.util.VersionUtils;
public class CraftVisibilityManager implements VisibilityManager {
@ -32,7 +33,6 @@ public class CraftVisibilityManager implements VisibilityManager {
return visibleByDefault;
}
@SuppressWarnings("deprecation")
@Override
public void setVisibleByDefault(boolean visibleByDefault) {
if (this.visibleByDefault != visibleByDefault) {
@ -40,7 +40,7 @@ public class CraftVisibilityManager implements VisibilityManager {
boolean oldVisibleByDefault = this.visibleByDefault;
this.visibleByDefault = visibleByDefault;
for (Player player : Bukkit.getOnlinePlayers()) {
for (Player player : VersionUtils.getOnlinePlayers()) {
if (playersVisibilityMap != null && playersVisibilityMap.containsKey(player.getName().toLowerCase())) {
// Has a specific value set

View File

@ -61,10 +61,12 @@ public class CraftItemLine extends CraftTouchableLine implements ItemLine {
Location loc = nmsItem.getBukkitEntityNMS().getLocation();
if (HolographicDisplays.is1_8()) {
super.setTouchHandler(touchHandler, loc.getWorld(), loc.getX(), loc.getY() - Offsets.ARMOR_STAND_WITH_ITEM, loc.getZ());
if (HolographicDisplays.is19orGreater()) {
super.setTouchHandler(touchHandler, loc.getWorld(), loc.getX(), loc.getY() - getItemOffset(), loc.getZ());
} else if (HolographicDisplays.is18orGreater()) {
super.setTouchHandler(touchHandler, loc.getWorld(), loc.getX(), loc.getY() - getItemOffset(), loc.getZ());
} else {
super.setTouchHandler(touchHandler, loc.getWorld(), loc.getX(), loc.getY() - Offsets.WITHER_SKULL_WITH_ITEM, loc.getZ());
super.setTouchHandler(touchHandler, loc.getWorld(), loc.getX(), loc.getY() - getItemOffset(), loc.getZ());
}
} else {
@ -78,11 +80,11 @@ public class CraftItemLine extends CraftTouchableLine implements ItemLine {
if (itemStack != null && itemStack.getType() != Material.AIR) {
double offset = HolographicDisplays.is1_8() ? Offsets.ARMOR_STAND_WITH_ITEM : Offsets.WITHER_SKULL_WITH_ITEM;
double offset = getItemOffset();
nmsItem = HolographicDisplays.getNMSManager().spawnNMSItem(world, x, y + offset, z, this, itemStack);
if (HolographicDisplays.is1_8()) {
if (HolographicDisplays.is18orGreater()) {
nmsVehicle = HolographicDisplays.getNMSManager().spawnNMSArmorStand(world, x, y + offset, z, this);
} else {
nmsVehicle = HolographicDisplays.getNMSManager().spawnNMSWitherSkull(world, x, y + offset, z, this);
@ -115,7 +117,7 @@ public class CraftItemLine extends CraftTouchableLine implements ItemLine {
public void teleport(double x, double y, double z) {
super.teleport(x, y, z);
double offset = HolographicDisplays.is1_8() ? Offsets.ARMOR_STAND_WITH_ITEM : Offsets.WITHER_SKULL_WITH_ITEM;
double offset = getItemOffset();
if (nmsVehicle != null) {
nmsVehicle.setLocationNMS(x, y + offset, z);
@ -146,6 +148,16 @@ public class CraftItemLine extends CraftTouchableLine implements ItemLine {
public NMSEntityBase getNmsVehicle() {
return nmsVehicle;
}
private double getItemOffset() {
if (HolographicDisplays.is19orGreater()) {
return Offsets.ARMOR_STAND_WITH_ITEM_1_9;
} else if (HolographicDisplays.is18orGreater()) {
return Offsets.ARMOR_STAND_WITH_ITEM;
} else {
return Offsets.WITHER_SKULL_WITH_ITEM;
}
}
@Override
public String toString() {

View File

@ -59,12 +59,7 @@ public class CraftTextLine extends CraftTouchableLine implements TextLine {
if (nmsNameble != null) {
Location loc = nmsNameble.getBukkitEntityNMS().getLocation();
if (HolographicDisplays.is1_8()) {
super.setTouchHandler(touchHandler, loc.getWorld(), loc.getX(), loc.getY() - Offsets.ARMOR_STAND_ALONE, loc.getZ());
} else {
super.setTouchHandler(touchHandler, loc.getWorld(), loc.getX(), loc.getY() - Offsets.WITHER_SKULL_WITH_HORSE, loc.getZ());
}
super.setTouchHandler(touchHandler, loc.getWorld(), loc.getX(), loc.getY() - getTextOffset(), loc.getZ());
} else {
super.setTouchHandler(touchHandler, null, 0, 0, 0);
@ -75,8 +70,8 @@ public class CraftTextLine extends CraftTouchableLine implements TextLine {
public void spawn(World world, double x, double y, double z) {
super.spawn(world, x, y, z);
if (HolographicDisplays.is1_8()) {
nmsNameble = HolographicDisplays.getNMSManager().spawnNMSArmorStand(world, x, y + Offsets.ARMOR_STAND_ALONE, z, this);
if (HolographicDisplays.is18orGreater()) {
nmsNameble = HolographicDisplays.getNMSManager().spawnNMSArmorStand(world, x, y + getTextOffset(), z, this);
} else {
nmsNameble = HolographicDisplays.getNMSManager().spawnNMSHorse(world, x, y + Offsets.WITHER_SKULL_WITH_HORSE, z, this);
nmsSkullVehicle = HolographicDisplays.getNMSManager().spawnNMSWitherSkull(world, x, y + Offsets.WITHER_SKULL_WITH_HORSE, z, this);
@ -119,7 +114,7 @@ public class CraftTextLine extends CraftTouchableLine implements TextLine {
}
if (nmsNameble != null) {
nmsNameble.setLocationNMS(x, y + (HolographicDisplays.is1_8() ? Offsets.ARMOR_STAND_ALONE : Offsets.WITHER_SKULL_WITH_HORSE), z);
nmsNameble.setLocationNMS(x, y + getTextOffset(), z);
}
}
@ -152,6 +147,15 @@ public class CraftTextLine extends CraftTouchableLine implements TextLine {
return nmsSkullVehicle;
}
private double getTextOffset() {
if (HolographicDisplays.is19orGreater()) {
return Offsets.ARMOR_STAND_ALONE_1_9;
} else if (HolographicDisplays.is18orGreater()) {
return Offsets.ARMOR_STAND_ALONE;
} else {
return Offsets.WITHER_SKULL_WITH_HORSE;
}
}
@Override
public String toString() {

View File

@ -34,11 +34,11 @@ public class CraftTouchSlimeLine extends CraftHologramLine {
public void spawn(World world, double x, double y, double z) {
super.spawn(world, x, y, z);
double offset = HolographicDisplays.is1_8() ? Offsets.ARMOR_STAND_WITH_SLIME : Offsets.WITHER_SKULL_WITH_SLIME;
double offset = getSlimeOffset();
nmsSlime = HolographicDisplays.getNMSManager().spawnNMSSlime(world, x, y + offset, z, this);
if (HolographicDisplays.is1_8()) {
if (HolographicDisplays.is18orGreater()) {
nmsVehicle = HolographicDisplays.getNMSManager().spawnNMSArmorStand(world, x, y + offset, z, this);
} else {
nmsVehicle = HolographicDisplays.getNMSManager().spawnNMSWitherSkull(world, x, y + offset, z, this);
@ -70,7 +70,7 @@ public class CraftTouchSlimeLine extends CraftHologramLine {
@Override
public void teleport(double x, double y, double z) {
double offset = HolographicDisplays.is1_8() ? Offsets.ARMOR_STAND_WITH_SLIME : Offsets.WITHER_SKULL_WITH_SLIME;
double offset = getSlimeOffset();
if (nmsVehicle != null) {
nmsVehicle.setLocationNMS(x, y + offset, z);
@ -97,6 +97,16 @@ public class CraftTouchSlimeLine extends CraftHologramLine {
public NMSEntityBase getNmsVehicle() {
return nmsVehicle;
}
private double getSlimeOffset() {
if (HolographicDisplays.is19orGreater()) {
return Offsets.ARMOR_STAND_WITH_SLIME_1_9;
} else if (HolographicDisplays.is18orGreater()) {
return Offsets.ARMOR_STAND_WITH_SLIME;
} else {
return Offsets.WITHER_SKULL_WITH_SLIME;
}
}
@Override
public String toString() {

View File

@ -12,6 +12,7 @@ import com.gmail.filoghost.holographicdisplays.HolographicDisplays;
import com.gmail.filoghost.holographicdisplays.api.placeholder.PlaceholderReplacer;
import com.gmail.filoghost.holographicdisplays.disk.Configuration;
import com.gmail.filoghost.holographicdisplays.util.Utils;
import com.gmail.filoghost.holographicdisplays.util.VersionUtils;
public class PlaceholdersRegister {
@ -22,10 +23,9 @@ public class PlaceholdersRegister {
register(new Placeholder(HolographicDisplays.getInstance(), "{online}", 1.0, new PlaceholderReplacer() {
@SuppressWarnings("deprecation")
@Override
public String update() {
return String.valueOf(Bukkit.getOnlinePlayers().length);
return String.valueOf(VersionUtils.getOnlinePlayers().size());
}
}));

View File

@ -18,6 +18,16 @@ public class Offsets {
ARMOR_STAND_WITH_ITEM = -1.48,
// For 1.8+, an armor stand holding a slime.
ARMOR_STAND_WITH_SLIME = -1.49;
ARMOR_STAND_WITH_SLIME = -1.49,
// For 1.9+, a single armor stand. As with wither skulls and horses, the bottom part of the nametag should be on the surface of the block.
ARMOR_STAND_ALONE_1_9 = -0.29,
// For 1.9+, an armor stand holding an item.
ARMOR_STAND_WITH_ITEM_1_9 = -0.0,
// For 1.9+, an armor stand holding a slime.
ARMOR_STAND_WITH_SLIME_1_9 = -0.01;
}

View File

@ -18,4 +18,10 @@ public class ReflectionUtils {
field.setAccessible(true);
field.set(handle, value);
}
public static Object getPrivateField(Class<?> clazz, Object handle, String fieldName) throws Exception {
Field field = clazz.getDeclaredField(fieldName);
field.setAccessible(true);
return field.get(handle);
}
}

View File

@ -1,15 +1,22 @@
package com.gmail.filoghost.holographicdisplays.util;
import java.lang.reflect.Method;
import java.util.Collection;
import java.util.Collections;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.bukkit.Bukkit;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.Player;
import com.gmail.filoghost.holographicdisplays.HolographicDisplays;
import com.google.common.collect.ImmutableList;
public class VersionUtils {
private static Method oldGetOnlinePlayersMethod;
/**
* This method uses a regex to get the NMS package part that changes with every update.
* Example: v1_8_R1
@ -47,10 +54,29 @@ public class VersionUtils {
}
public static boolean isArmorstand(EntityType type) {
if (!HolographicDisplays.is1_8()) {
if (!HolographicDisplays.is18orGreater()) {
return false;
}
return type == EntityType.ARMOR_STAND;
}
public static Collection<? extends Player> getOnlinePlayers() {
if (HolographicDisplays.is18orGreater()) {
return Bukkit.getOnlinePlayers();
} else {
try {
if (oldGetOnlinePlayersMethod == null) {
oldGetOnlinePlayersMethod = Bukkit.class.getDeclaredMethod("getOnlinePlayers");
}
Player[] playersArray = (Player[]) oldGetOnlinePlayersMethod.invoke(null);
return ImmutableList.copyOf(playersArray);
} catch (Exception e) {
e.printStackTrace();
return Collections.emptyList();
}
}
}
}

View File

@ -1,6 +1,6 @@
name: HolographicDisplays
main: com.gmail.filoghost.holographicdisplays.HolographicDisplays
version: 2.1.10
version: 2.1.11
softdepend: [Multiverse-Core, MultiWorld, My Worlds, My_Worlds, ProtocolLib]

View File

@ -3,6 +3,4 @@ HolographicDisplays
Bukkit Dev Page: http://dev.bukkit.org/bukkit-plugins/holographic-displays
API tutorial: https://github.com/filoghost/HolographicDisplays/wiki
Old source (deprecated): https://github.com/filoghost/HolographicDisplays/tree/1.x
API tutorial: https://github.com/filoghost/HolographicDisplays/wiki