mirror of
https://github.com/amalthea-mc/ShopChest.git
synced 2024-12-23 09:31:46 +00:00
Client-side shop items
All shop items are now spawned with packets and reflection client-side, so probably duplicated items are history (finally). This also allowed me to remove the ClearLag and LWC dependency, as ClearLag can't remove client-side items and LWC's Magnet Sucker can't suck them inside a chest. I also changed a bit in the classes of the nms package, so all required classes have to be found before attempting to do anything. Fixes #11 and fixes #4
This commit is contained in:
parent
bb54c7da67
commit
a95106a335
17
pom.xml
17
pom.xml
@ -24,10 +24,6 @@
|
||||
<id>spigot-repo</id>
|
||||
<url>https://hub.spigotmc.org/nexus/content/repositories/snapshots/</url>
|
||||
</repository>
|
||||
<repository>
|
||||
<id>shopchest-repo</id>
|
||||
<url>https://epicericee.github.io/ShopChest/maven/</url>
|
||||
</repository>
|
||||
<repository>
|
||||
<id>vault-repo</id>
|
||||
<url>http://nexus.hc.to/content/repositories/pub_releases/</url>
|
||||
@ -41,25 +37,12 @@
|
||||
<version>1.10.2-R0.1-SNAPSHOT</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>net.milkbowl.vault</groupId>
|
||||
<artifactId>VaultAPI</artifactId>
|
||||
<version>1.6</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>me.minebuilders</groupId>
|
||||
<artifactId>clearlag</artifactId>
|
||||
<version>2.9.1</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.griefcraft.lwc</groupId>
|
||||
<artifactId>lwc-entity-locking</artifactId>
|
||||
<version>1.7.3</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<distributionManagement>
|
||||
|
@ -22,9 +22,6 @@ import de.epiceric.shopchest.utils.Utils;
|
||||
import net.milkbowl.vault.economy.Economy;
|
||||
import net.milkbowl.vault.permission.Permission;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.bukkit.entity.Item;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.plugin.RegisteredServiceProvider;
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
@ -41,7 +38,6 @@ public class ShopChest extends JavaPlugin {
|
||||
private Config config = null;
|
||||
private Economy econ = null;
|
||||
private Permission perm = null;
|
||||
private boolean lwc = false;
|
||||
private Database database;
|
||||
private boolean isUpdateNeeded = false;
|
||||
private String latestVersion = "";
|
||||
@ -238,8 +234,6 @@ public class ShopChest extends JavaPlugin {
|
||||
}, config.auto_reload_time * 20, config.auto_reload_time * 20);
|
||||
}
|
||||
|
||||
lwc = getServer().getPluginManager().isPluginEnabled("LWC");
|
||||
|
||||
Bukkit.getScheduler().runTaskAsynchronously(this, new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
@ -254,7 +248,7 @@ public class ShopChest extends JavaPlugin {
|
||||
Bukkit.getConsoleSender().sendMessage("[ShopChest] " + LanguageUtils.getMessage(LocalizedMessage.Message.UPDATE_AVAILABLE, new LocalizedMessage.ReplacedRegex(Regex.VERSION, latestVersion)));
|
||||
|
||||
for (Player p : getServer().getOnlinePlayers()) {
|
||||
if (p.isOp() || perm.has(p, "shopchest.notification.update")) {
|
||||
if (perm.has(p, "shopchest.notification.update")) {
|
||||
JsonBuilder jb = new JsonBuilder(ShopChest.this, LanguageUtils.getMessage(LocalizedMessage.Message.UPDATE_AVAILABLE, new LocalizedMessage.ReplacedRegex(Regex.VERSION, latestVersion)), LanguageUtils.getMessage(LocalizedMessage.Message.UPDATE_CLICK_TO_DOWNLOAD), downloadLink);
|
||||
jb.sendJson(p);
|
||||
}
|
||||
@ -287,16 +281,10 @@ public class ShopChest extends JavaPlugin {
|
||||
|
||||
debug("Registering listeners...");
|
||||
getServer().getPluginManager().registerEvents(new HologramUpdateListener(this), this);
|
||||
getServer().getPluginManager().registerEvents(new ItemProtectListener(this), this);
|
||||
getServer().getPluginManager().registerEvents(new ShopItemListener(this), this);
|
||||
getServer().getPluginManager().registerEvents(new ShopInteractListener(this), this);
|
||||
getServer().getPluginManager().registerEvents(new NotifyUpdateOnJoinListener(this), this);
|
||||
getServer().getPluginManager().registerEvents(new ChestProtectListener(this), this);
|
||||
getServer().getPluginManager().registerEvents(new ItemCustomNameListener(), this);
|
||||
|
||||
if (getServer().getPluginManager().isPluginEnabled("ClearLag"))
|
||||
getServer().getPluginManager().registerEvents(new ClearLagListener(), this);
|
||||
|
||||
if (lwc) new LWCMagnetListener(this).initializeListener();
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -314,38 +302,6 @@ public class ShopChest extends JavaPlugin {
|
||||
}
|
||||
}
|
||||
|
||||
for (World world : Bukkit.getWorlds()) {
|
||||
for (Entity entity : world.getEntities()) {
|
||||
if (entity instanceof Item) {
|
||||
Item item = (Item) entity;
|
||||
if (item.hasMetadata("shopItem")) {
|
||||
if (item.isValid()) {
|
||||
debug("Removing not removed shop item (#" +
|
||||
(item.hasMetadata("shopId") ? item.getMetadata("shopId").get(0).asString() : "?") + ")");
|
||||
|
||||
item.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (config.enable_debug_log) {
|
||||
for (World world : Bukkit.getWorlds()) {
|
||||
for (Entity entity : world.getEntities()) {
|
||||
if (entity instanceof Item) {
|
||||
Item item = (Item) entity;
|
||||
if (item.hasMetadata("shopItem")) {
|
||||
if (item.isValid()) {
|
||||
debug("Shop item still valid (#" +
|
||||
(item.hasMetadata("shopId") ? item.getMetadata("shopId").get(0).asString() : "?") + ")");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
database.disconnect();
|
||||
|
||||
if (fw != null && config.enable_debug_log) {
|
||||
@ -426,13 +382,6 @@ public class ShopChest extends JavaPlugin {
|
||||
return database;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Whether LWC is available
|
||||
*/
|
||||
public boolean hasLWC() {
|
||||
return lwc;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Whether an update is needed (will return false if not checked)
|
||||
*/
|
||||
|
@ -1,25 +0,0 @@
|
||||
package de.epiceric.shopchest.listeners;
|
||||
|
||||
import me.minebuilders.clearlag.events.EntityRemoveEvent;
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.Listener;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class ClearLagListener implements Listener {
|
||||
|
||||
@EventHandler(priority = EventPriority.HIGH)
|
||||
public void onEntityRemove(EntityRemoveEvent e) {
|
||||
ArrayList<Entity> entityList = new ArrayList<>(e.getEntityList());
|
||||
|
||||
for (Entity entity : entityList) {
|
||||
if (entity.hasMetadata("shopItem")) {
|
||||
e.getEntityList().remove(entity);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -1,17 +0,0 @@
|
||||
package de.epiceric.shopchest.listeners;
|
||||
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.entity.ItemSpawnEvent;
|
||||
|
||||
public class ItemCustomNameListener implements Listener {
|
||||
|
||||
@EventHandler(priority = EventPriority.MONITOR)
|
||||
public void onItemSpawn(ItemSpawnEvent e) {
|
||||
if (e.getEntity().hasMetadata("shopItem")) {
|
||||
e.getEntity().setCustomNameVisible(false);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -1,134 +0,0 @@
|
||||
package de.epiceric.shopchest.listeners;
|
||||
|
||||
|
||||
import de.epiceric.shopchest.ShopChest;
|
||||
import de.epiceric.shopchest.utils.ShopUtils;
|
||||
import de.epiceric.shopchest.utils.Utils;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.block.BlockFace;
|
||||
import org.bukkit.block.BlockState;
|
||||
import org.bukkit.entity.Item;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.block.*;
|
||||
import org.bukkit.event.entity.ItemDespawnEvent;
|
||||
import org.bukkit.event.inventory.InventoryPickupItemEvent;
|
||||
import org.bukkit.event.player.PlayerBucketEmptyEvent;
|
||||
import org.bukkit.event.player.PlayerFishEvent;
|
||||
import org.bukkit.event.player.PlayerPickupItemEvent;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
|
||||
public class ItemProtectListener implements Listener {
|
||||
|
||||
private ShopUtils shopUtils;
|
||||
private ShopChest plugin;
|
||||
|
||||
public ItemProtectListener(ShopChest plugin) {
|
||||
this.plugin = plugin;
|
||||
this.shopUtils = plugin.getShopUtils();
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.HIGH)
|
||||
public void onItemDespawn(ItemDespawnEvent e) {
|
||||
Item item = e.getEntity();
|
||||
if (item.hasMetadata("shopItem")) e.setCancelled(true);
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.HIGH)
|
||||
public void onPlayerPickUpItem(PlayerPickupItemEvent e) {
|
||||
if (e.getItem().hasMetadata("shopItem")) e.setCancelled(true);
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.HIGH)
|
||||
public void onItemPickup(InventoryPickupItemEvent e) {
|
||||
if (e.getItem().hasMetadata("shopItem")) e.setCancelled(true);
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.HIGH)
|
||||
public void onBlockPlace(BlockPlaceEvent e) {
|
||||
Block b = e.getBlockPlaced();
|
||||
Block below = b.getRelative(BlockFace.DOWN);
|
||||
|
||||
if (shopUtils.isShop(below.getLocation())) e.setCancelled(true);
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.HIGH)
|
||||
public void onMultiBlockPlace(BlockMultiPlaceEvent e) {
|
||||
for (BlockState blockState : e.getReplacedBlockStates()) {
|
||||
Block below = blockState.getBlock().getRelative(BlockFace.DOWN);
|
||||
if (shopUtils.isShop(below.getLocation())) e.setCancelled(true);
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.HIGH)
|
||||
public void onPistonExtend(BlockPistonExtendEvent e) {
|
||||
// If the piston would only move itself
|
||||
Block airAfterPiston = e.getBlock().getRelative(e.getDirection());
|
||||
Block belowAir = airAfterPiston.getRelative(BlockFace.DOWN);
|
||||
if (shopUtils.isShop(belowAir.getLocation())) {
|
||||
e.setCancelled(true);
|
||||
return;
|
||||
}
|
||||
|
||||
for (Block b : e.getBlocks()) {
|
||||
Block newBlock = b.getRelative(e.getDirection());
|
||||
Block belowNewBlock = newBlock.getRelative(BlockFace.DOWN);
|
||||
if (shopUtils.isShop(belowNewBlock.getLocation())) e.setCancelled(true);
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.HIGH)
|
||||
public void onPistonRetract(BlockPistonRetractEvent e) {
|
||||
for (Block b : e.getBlocks()) {
|
||||
Block newBlock = b.getRelative(e.getDirection());
|
||||
Block belowNewBlock = newBlock.getRelative(BlockFace.DOWN);
|
||||
if (shopUtils.isShop(belowNewBlock.getLocation())) e.setCancelled(true);
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.HIGH)
|
||||
public void onLiquidFlow(BlockFromToEvent e) {
|
||||
Block b = e.getToBlock();
|
||||
Block below = b.getRelative(BlockFace.DOWN);
|
||||
|
||||
if (shopUtils.isShop(below.getLocation())) e.setCancelled(true);
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.HIGH)
|
||||
public void onBucketEmpty(PlayerBucketEmptyEvent e) {
|
||||
Block b = e.getBlockClicked();
|
||||
|
||||
if (shopUtils.isShop(b.getLocation())) e.setCancelled(true);
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.HIGH)
|
||||
public void onPlayerFish(PlayerFishEvent e) {
|
||||
if (e.getState() == PlayerFishEvent.State.CAUGHT_ENTITY) {
|
||||
if (e.getCaught() instanceof Item) {
|
||||
Item item = (Item) e.getCaught();
|
||||
if (item.hasMetadata("shopItem")) {
|
||||
plugin.debug(e.getPlayer().getName() + " tried to fish a shop item");
|
||||
e.setCancelled(true);
|
||||
|
||||
// Use some reflection to get the EntityFishingHook class so the hook can be removed...
|
||||
try {
|
||||
Class<?> craftFishClass = Class.forName("org.bukkit.craftbukkit." + Utils.getServerVersion() + ".entity.CraftFish");
|
||||
Object craftFish = craftFishClass.cast(e.getHook());
|
||||
|
||||
Class<?> entityFishingHookClass = Class.forName("net.minecraft.server." + Utils.getServerVersion() + ".EntityFishingHook");
|
||||
Object entityFishingHook = craftFishClass.getDeclaredMethod("getHandle").invoke(craftFish);
|
||||
|
||||
entityFishingHookClass.getDeclaredMethod("die").invoke(entityFishingHook);
|
||||
} catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException | ClassNotFoundException ex) {
|
||||
plugin.debug("Failed to kill fishing hook with reflection");
|
||||
plugin.debug(ex);
|
||||
ex.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -1,39 +0,0 @@
|
||||
package de.epiceric.shopchest.listeners;
|
||||
|
||||
import com.griefcraft.lwc.LWC;
|
||||
import com.griefcraft.scripting.JavaModule;
|
||||
import com.griefcraft.scripting.event.LWCMagnetPullEvent;
|
||||
import de.epiceric.shopchest.ShopChest;
|
||||
|
||||
public class LWCMagnetListener {
|
||||
|
||||
private ShopChest plugin;
|
||||
|
||||
public LWCMagnetListener(ShopChest plugin) {
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
public void initializeListener() {
|
||||
try {
|
||||
Class.forName("com.griefcraft.scripting.event.LWCMagnetPullEvent");
|
||||
|
||||
LWC.getInstance().getModuleLoader().registerModule(ShopChest.getInstance(), new JavaModule() {
|
||||
|
||||
@Override
|
||||
public void onMagnetPull(LWCMagnetPullEvent event) {
|
||||
if (event.getItem().hasMetadata("shopItem")) {
|
||||
event.setCancelled(true);
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
} catch (ClassNotFoundException ex) {
|
||||
plugin.debug("Using not recommended version of LWC");
|
||||
plugin.getLogger().warning("Shop items can be sucked up by the magnet flag of a protected chest of LWC.");
|
||||
plugin.getLogger().warning("Use 'LWC Unofficial - Entity locking' v1.7.3 or later by 'Me_Goes_RAWR' to prevent this.");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -27,7 +27,7 @@ public class NotifyUpdateOnJoinListener implements Listener {
|
||||
Player p = e.getPlayer();
|
||||
|
||||
if (plugin.isUpdateNeeded()) {
|
||||
if (p.isOp() || perm.has(p, "shopchest.notification.update")) {
|
||||
if (perm.has(p, "shopchest.notification.update")) {
|
||||
JsonBuilder jb = new JsonBuilder(plugin, LanguageUtils.getMessage(LocalizedMessage.Message.UPDATE_AVAILABLE, new LocalizedMessage.ReplacedRegex(Regex.VERSION, plugin.getLatestVersion())), LanguageUtils.getMessage(LocalizedMessage.Message.UPDATE_CLICK_TO_DOWNLOAD), plugin.getDownloadLink());
|
||||
jb.sendJson(p);
|
||||
}
|
||||
|
@ -0,0 +1,126 @@
|
||||
package de.epiceric.shopchest.listeners;
|
||||
|
||||
import de.epiceric.shopchest.ShopChest;
|
||||
import de.epiceric.shopchest.shop.Shop;
|
||||
import de.epiceric.shopchest.utils.ShopUtils;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.block.BlockFace;
|
||||
import org.bukkit.block.BlockState;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.block.*;
|
||||
import org.bukkit.event.player.*;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
|
||||
public class ShopItemListener implements Listener {
|
||||
|
||||
private ShopUtils shopUtils;
|
||||
private ShopChest plugin;
|
||||
|
||||
public ShopItemListener(ShopChest plugin) {
|
||||
this.plugin = plugin;
|
||||
this.shopUtils = plugin.getShopUtils();
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onPlayerJoin(PlayerJoinEvent e) {
|
||||
for (Shop shop : plugin.getShopUtils().getShops()) {
|
||||
shop.getItem().setVisible(e.getPlayer(), true);
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onPlayerLeave(PlayerQuitEvent e) {
|
||||
for (Shop shop : plugin.getShopUtils().getShops()) {
|
||||
shop.getItem().setVisible(e.getPlayer(), false);
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.HIGH)
|
||||
public void onBlockPlace(BlockPlaceEvent e) {
|
||||
Block b = e.getBlockPlaced();
|
||||
Block below = b.getRelative(BlockFace.DOWN);
|
||||
|
||||
if (shopUtils.isShop(below.getLocation())) {
|
||||
shopUtils.getShop(below.getLocation()).getItem().resetForPlayer(e.getPlayer());
|
||||
e.setCancelled(true);
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.HIGH)
|
||||
public void onMultiBlockPlace(BlockMultiPlaceEvent e) {
|
||||
for (BlockState blockState : e.getReplacedBlockStates()) {
|
||||
Block below = blockState.getBlock().getRelative(BlockFace.DOWN);
|
||||
|
||||
if (shopUtils.isShop(below.getLocation())) {
|
||||
shopUtils.getShop(below.getLocation()).getItem().resetForPlayer(e.getPlayer());
|
||||
e.setCancelled(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.HIGH)
|
||||
public void onPistonExtend(BlockPistonExtendEvent e) {
|
||||
// If the piston would only move itself
|
||||
Block airAfterPiston = e.getBlock().getRelative(e.getDirection());
|
||||
Block belowAir = airAfterPiston.getRelative(BlockFace.DOWN);
|
||||
if (shopUtils.isShop(belowAir.getLocation())) {
|
||||
e.setCancelled(true);
|
||||
return;
|
||||
}
|
||||
|
||||
for (Block b : e.getBlocks()) {
|
||||
Block newBlock = b.getRelative(e.getDirection());
|
||||
Block belowNewBlock = newBlock.getRelative(BlockFace.DOWN);
|
||||
if (shopUtils.isShop(belowNewBlock.getLocation())) e.setCancelled(true);
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.HIGH)
|
||||
public void onPistonRetract(BlockPistonRetractEvent e) {
|
||||
for (Block b : e.getBlocks()) {
|
||||
Block newBlock = b.getRelative(e.getDirection());
|
||||
Block belowNewBlock = newBlock.getRelative(BlockFace.DOWN);
|
||||
if (shopUtils.isShop(belowNewBlock.getLocation())) {
|
||||
e.setCancelled(true);
|
||||
for (Player p : Bukkit.getOnlinePlayers()) {
|
||||
shopUtils.getShop(belowNewBlock.getLocation()).getItem().resetForPlayer(p);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.HIGH)
|
||||
public void onLiquidFlow(BlockFromToEvent e) {
|
||||
Block b = e.getToBlock();
|
||||
Block below = b.getRelative(BlockFace.DOWN);
|
||||
|
||||
if (shopUtils.isShop(below.getLocation())) e.setCancelled(true);
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.HIGH)
|
||||
public void onBucketEmpty(PlayerBucketEmptyEvent e) {
|
||||
Block clicked = e.getBlockClicked();
|
||||
Block underWater = clicked.getRelative(BlockFace.DOWN).getRelative(e.getBlockFace());
|
||||
|
||||
if (shopUtils.isShop(clicked.getLocation())) {
|
||||
if (e.getBucket() == Material.LAVA_BUCKET) {
|
||||
shopUtils.getShop(clicked.getLocation()).getItem().resetForPlayer(e.getPlayer());
|
||||
}
|
||||
} else if (shopUtils.isShop(underWater.getLocation())) {
|
||||
if (e.getBucket() == Material.LAVA_BUCKET) {
|
||||
shopUtils.getShop(underWater.getLocation()).getItem().resetForPlayer(e.getPlayer());
|
||||
}
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
e.setCancelled(true);
|
||||
}
|
||||
|
||||
}
|
@ -13,7 +13,6 @@ import java.util.List;
|
||||
|
||||
public class Hologram {
|
||||
|
||||
private Class<?> entityArmorStandClass;
|
||||
private boolean exists = false;
|
||||
private int count;
|
||||
private List<Object> entityList = new ArrayList<>();
|
||||
@ -22,18 +21,27 @@ public class Hologram {
|
||||
private List<Player> visible = new ArrayList<>();
|
||||
private ShopChest plugin;
|
||||
|
||||
private Class<?> entityArmorStandClass = Utils.getNMSClass("EntityArmorStand");
|
||||
private Class<?> nmsWorldClass = Utils.getNMSClass("World");
|
||||
private Class<?> packetPlayOutSpawnEntityLivingClass = Utils.getNMSClass("PacketPlayOutSpawnEntityLiving");
|
||||
private Class<?> packetPlayOutEntityDestroyClass = Utils.getNMSClass("PacketPlayOutEntityDestroy");
|
||||
private Class<?> entityLivingClass = Utils.getNMSClass("EntityLiving");
|
||||
|
||||
public Hologram(ShopChest plugin, String[] text, Location location) {
|
||||
this.plugin = plugin;
|
||||
this.text = text;
|
||||
this.location = location;
|
||||
|
||||
try {
|
||||
entityArmorStandClass = Class.forName("net.minecraft.server." + Utils.getServerVersion() + ".EntityArmorStand");
|
||||
} catch (ClassNotFoundException e) {
|
||||
plugin.debug("Could not find EntityArmorStand class");
|
||||
plugin.debug(e);
|
||||
e.printStackTrace();
|
||||
return;
|
||||
Class[] requiredClasses = new Class[] {
|
||||
nmsWorldClass, entityArmorStandClass, entityLivingClass,
|
||||
packetPlayOutSpawnEntityLivingClass, packetPlayOutEntityDestroyClass,
|
||||
};
|
||||
|
||||
for (Class c : requiredClasses) {
|
||||
if (c == null) {
|
||||
plugin.debug("Failed to create hologram: Could not find all required classes");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
create();
|
||||
@ -42,8 +50,6 @@ public class Hologram {
|
||||
private void create() {
|
||||
for (String text : this.text) {
|
||||
try {
|
||||
Class<?> nmsWorldClass = Class.forName("net.minecraft.server." + Utils.getServerVersion() + ".World");
|
||||
|
||||
Object craftWorld = this.location.getWorld().getClass().cast(this.location.getWorld());
|
||||
Object nmsWorld = nmsWorldClass.cast(craftWorld.getClass().getMethod("getHandle").invoke(craftWorld));
|
||||
|
||||
@ -63,7 +69,7 @@ public class Hologram {
|
||||
entityList.add(entityArmorStand);
|
||||
this.location.subtract(0, 0.25, 0);
|
||||
count++;
|
||||
} catch (ClassNotFoundException | NoSuchMethodException | IllegalAccessException | InvocationTargetException | InstantiationException e) {
|
||||
} catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException | InstantiationException e) {
|
||||
plugin.debug("Could not create Hologram with reflection");
|
||||
plugin.debug(e);
|
||||
e.printStackTrace();
|
||||
@ -93,14 +99,11 @@ public class Hologram {
|
||||
public void showPlayer(Player p) {
|
||||
for (Object o : entityList) {
|
||||
try {
|
||||
Class<?> packetClass = Class.forName("net.minecraft.server." + Utils.getServerVersion() + ".PacketPlayOutSpawnEntityLiving");
|
||||
Class<?> entityLivingClass = Class.forName("net.minecraft.server." + Utils.getServerVersion() + ".EntityLiving");
|
||||
|
||||
Object entityLiving = entityLivingClass.cast(o);
|
||||
Object packet = packetClass.getConstructor(entityLivingClass).newInstance(entityLiving);
|
||||
Object packet = packetPlayOutSpawnEntityLivingClass.getConstructor(entityLivingClass).newInstance(entityLiving);
|
||||
|
||||
Utils.sendPacket(plugin, packet, p);
|
||||
} catch (NoSuchMethodException | InstantiationException | InvocationTargetException | IllegalAccessException | ClassNotFoundException e) {
|
||||
} catch (NoSuchMethodException | InstantiationException | InvocationTargetException | IllegalAccessException e) {
|
||||
plugin.debug("Could not show Hologram to player with reflection");
|
||||
plugin.debug(e);
|
||||
e.printStackTrace();
|
||||
@ -115,14 +118,12 @@ public class Hologram {
|
||||
public void hidePlayer(Player p) {
|
||||
for (Object o : entityList) {
|
||||
try {
|
||||
Class<?> packetClass = Class.forName("net.minecraft.server." + Utils.getServerVersion() + ".PacketPlayOutEntityDestroy");
|
||||
|
||||
int id = (int) entityArmorStandClass.getMethod("getId").invoke(o);
|
||||
|
||||
Object packet = packetClass.getConstructor(int[].class).newInstance((Object) new int[] {id});
|
||||
Object packet = packetPlayOutEntityDestroyClass.getConstructor(int[].class).newInstance((Object) new int[] {id});
|
||||
|
||||
Utils.sendPacket(plugin, packet, p);
|
||||
} catch (NoSuchMethodException | InstantiationException | InvocationTargetException | IllegalAccessException | ClassNotFoundException e) {
|
||||
} catch (NoSuchMethodException | InstantiationException | InvocationTargetException | IllegalAccessException e) {
|
||||
plugin.debug("Could not hide Hologram from player with reflection");
|
||||
plugin.debug(e);
|
||||
e.printStackTrace();
|
||||
|
@ -15,9 +15,30 @@ public class JsonBuilder {
|
||||
private List<String> extras = new ArrayList<>();
|
||||
private ShopChest plugin;
|
||||
|
||||
private Class<?> iChatBaseComponentClass = Utils.getNMSClass("IChatBaseComponent");
|
||||
private Class<?> packetPlayOutChatClass = Utils.getNMSClass("PacketPlayOutChat");
|
||||
private Class<?> chatSerializerClass;
|
||||
|
||||
public JsonBuilder(ShopChest plugin, String text, String hoverText, String downloadLink) {
|
||||
this.plugin = plugin;
|
||||
|
||||
if (Utils.getServerVersion().equals("v1_8_R1")) {
|
||||
chatSerializerClass = Utils.getNMSClass("ChatSerializer");
|
||||
} else {
|
||||
chatSerializerClass = Utils.getNMSClass("ChatBaseComponent$ChatSerializer");
|
||||
}
|
||||
|
||||
Class[] requiredClasses = new Class[] {
|
||||
iChatBaseComponentClass, packetPlayOutChatClass, chatSerializerClass
|
||||
};
|
||||
|
||||
for (Class c : requiredClasses) {
|
||||
if (c == null) {
|
||||
plugin.debug("Failed to instantiate JsonBuilder: Could not find all required classes");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
parse(text, hoverText, downloadLink);
|
||||
}
|
||||
|
||||
@ -90,24 +111,12 @@ public class JsonBuilder {
|
||||
|
||||
public void sendJson(Player p) {
|
||||
try {
|
||||
String version = Utils.getServerVersion();
|
||||
|
||||
Class<?> iChatBaseComponentClass = Class.forName("net.minecraft.server." + version + ".IChatBaseComponent");
|
||||
Class<?> packetPlayOutChatClass = Class.forName("net.minecraft.server." + version + ".PacketPlayOutChat");
|
||||
Class<?> chatSerializerClass;
|
||||
|
||||
if (version.equals("v1_8_R1")) {
|
||||
chatSerializerClass = Class.forName("net.minecraft.server." + version + ".ChatSerializer");
|
||||
} else {
|
||||
chatSerializerClass = Class.forName("net.minecraft.server." + version + ".IChatBaseComponent$ChatSerializer");
|
||||
}
|
||||
|
||||
Object iChatBaseComponent = chatSerializerClass.getMethod("a", String.class).invoke(null, toString());
|
||||
Object packetPlayOutChat = packetPlayOutChatClass.getConstructor(iChatBaseComponentClass).newInstance(iChatBaseComponent);
|
||||
|
||||
Utils.sendPacket(plugin, packetPlayOutChat, p);
|
||||
} catch (InstantiationException | InvocationTargetException |
|
||||
IllegalAccessException | NoSuchMethodException | ClassNotFoundException e) {
|
||||
IllegalAccessException | NoSuchMethodException e) {
|
||||
plugin.debug("Failed to send packet with reflection");
|
||||
plugin.debug(e);
|
||||
e.printStackTrace();
|
||||
|
@ -11,7 +11,12 @@ public class SpawnEggMeta {
|
||||
|
||||
private static String getNBTEntityID(ShopChest plugin, ItemStack stack) {
|
||||
try {
|
||||
Class<?> craftItemStackClass = Class.forName("org.bukkit.craftbukkit." + Utils.getServerVersion() + ".inventory.CraftItemStack");
|
||||
Class<?> craftItemStackClass = Utils.getCraftClass("inventory.CraftItemStack");
|
||||
|
||||
if (craftItemStackClass == null) {
|
||||
plugin.debug("Failed to get NBTEntityID: Could not find CraftItemStack class");
|
||||
return null;
|
||||
}
|
||||
|
||||
Object nmsStack = craftItemStackClass.getMethod("asNMSCopy", ItemStack.class).invoke(null, stack);
|
||||
|
||||
@ -24,7 +29,7 @@ public class SpawnEggMeta {
|
||||
Object id = entityTagCompound.getClass().getMethod("getString", String.class).invoke(entityTagCompound, "id");
|
||||
if (id instanceof String) return (String) id;
|
||||
|
||||
} catch (ClassNotFoundException | NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
|
||||
} catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
|
||||
plugin.debug("Could not get NBTEntityID with reflection");
|
||||
plugin.debug(e);
|
||||
e.printStackTrace();
|
||||
|
@ -5,7 +5,6 @@ import de.epiceric.shopchest.config.Regex;
|
||||
import de.epiceric.shopchest.language.LanguageUtils;
|
||||
import de.epiceric.shopchest.language.LocalizedMessage;
|
||||
import de.epiceric.shopchest.nms.Hologram;
|
||||
import de.epiceric.shopchest.utils.Utils;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Material;
|
||||
@ -14,15 +13,9 @@ import org.bukkit.block.Block;
|
||||
import org.bukkit.block.BlockFace;
|
||||
import org.bukkit.block.Chest;
|
||||
import org.bukkit.block.DoubleChest;
|
||||
import org.bukkit.entity.Item;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.inventory.InventoryHolder;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.inventory.meta.ItemMeta;
|
||||
import org.bukkit.metadata.FixedMetadataValue;
|
||||
import org.bukkit.util.Vector;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
public class Shop {
|
||||
|
||||
@ -32,7 +25,7 @@ public class Shop {
|
||||
private ItemStack product;
|
||||
private Location location;
|
||||
private Hologram hologram;
|
||||
private Item item;
|
||||
private ShopItem item;
|
||||
private double buyPrice;
|
||||
private double sellPrice;
|
||||
private ShopType shopType;
|
||||
@ -71,7 +64,7 @@ public class Shop {
|
||||
}
|
||||
|
||||
if (hologram == null || !hologram.exists()) createHologram();
|
||||
if (item == null || item.isDead()) createItem();
|
||||
if (item == null) createItem();
|
||||
}
|
||||
|
||||
private Shop(OfflinePlayer vendor, ItemStack product, Location location, double buyPrice, double sellPrice, ShopType shopType) {
|
||||
@ -117,25 +110,18 @@ public class Shop {
|
||||
if (plugin.getShopChestConfig().show_shop_items) {
|
||||
plugin.debug("Creating item (#" + id + ")");
|
||||
|
||||
Item item;
|
||||
Location itemLocation;
|
||||
ItemStack itemStack;
|
||||
ItemMeta itemMeta = product.getItemMeta();
|
||||
itemMeta.setDisplayName(UUID.randomUUID().toString());
|
||||
|
||||
itemLocation = new Location(location.getWorld(), hologram.getLocation().getX(), location.getY() + 1, hologram.getLocation().getZ());
|
||||
itemStack = new ItemStack(product);
|
||||
itemStack = product.clone();
|
||||
itemStack.setAmount(1);
|
||||
itemStack.setItemMeta(itemMeta);
|
||||
|
||||
item = location.getWorld().dropItem(itemLocation, itemStack);
|
||||
item.setVelocity(new Vector(0, 0, 0));
|
||||
item.setMetadata("shopItem", new FixedMetadataValue(plugin, true));
|
||||
item.setMetadata("shopId", new FixedMetadataValue(plugin, id));
|
||||
item.setCustomNameVisible(false);
|
||||
item.setPickupDelay(Integer.MAX_VALUE);
|
||||
this.item = new ShopItem(plugin, itemStack, itemLocation);
|
||||
|
||||
this.item = item;
|
||||
for (Player p : Bukkit.getOnlinePlayers()) {
|
||||
item.setVisible(p, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -269,6 +255,13 @@ public class Shop {
|
||||
return hologram;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Floating {@link ShopItem} of the shop
|
||||
*/
|
||||
public ShopItem getItem() {
|
||||
return item;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {@link InventoryHolder} of the shop or <b>null</b> if the shop has no chest.
|
||||
*/
|
||||
|
155
src/main/java/de/epiceric/shopchest/shop/ShopItem.java
Normal file
155
src/main/java/de/epiceric/shopchest/shop/ShopItem.java
Normal file
@ -0,0 +1,155 @@
|
||||
package de.epiceric.shopchest.shop;
|
||||
|
||||
import de.epiceric.shopchest.ShopChest;
|
||||
import de.epiceric.shopchest.utils.Utils;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class ShopItem {
|
||||
|
||||
private ShopChest plugin;
|
||||
private Map<Player, Boolean> visible = new HashMap<>();
|
||||
private ItemStack itemStack;
|
||||
private Location location;
|
||||
|
||||
private Object entityItem;
|
||||
private int entityId;
|
||||
private Object[] creationPackets = new Object[3];
|
||||
|
||||
private Class<?> nmsWorldClass = Utils.getNMSClass("World");
|
||||
private Class<?> craftWorldClass = Utils.getCraftClass("CraftWorld");
|
||||
private Class<?> nmsItemStackClass = Utils.getNMSClass("ItemStack");
|
||||
private Class<?> craftItemStackClass = Utils.getCraftClass("inventory.CraftItemStack");
|
||||
private Class<?> entityItemClass = Utils.getNMSClass("EntityItem");
|
||||
private Class<?> entityClass = Utils.getNMSClass("Entity");
|
||||
private Class<?> packetPlayOutSpawnEntityClass = Utils.getNMSClass("PacketPlayOutSpawnEntity");
|
||||
private Class<?> packetPlayOutEntityMetadataClass = Utils.getNMSClass("PacketPlayOutEntityMetadata");
|
||||
private Class<?> dataWatcherClass = Utils.getNMSClass("DataWatcher");
|
||||
private Class<?> packetPlayOutEntityDestroyClass = Utils.getNMSClass("PacketPlayOutEntityDestroy");
|
||||
private Class<?> packetPlayOutEntityVelocityClass = Utils.getNMSClass("PacketPlayOutEntityVelocity");
|
||||
|
||||
public ShopItem(ShopChest plugin, ItemStack itemStack, Location location) {
|
||||
this.plugin = plugin;
|
||||
this.itemStack = itemStack;
|
||||
this.location = location;
|
||||
|
||||
Class[] requiredClasses = new Class[] {
|
||||
nmsWorldClass, craftWorldClass, nmsItemStackClass, craftItemStackClass, entityItemClass,
|
||||
packetPlayOutSpawnEntityClass, packetPlayOutEntityMetadataClass, dataWatcherClass,
|
||||
packetPlayOutEntityDestroyClass, entityClass, packetPlayOutEntityVelocityClass,
|
||||
};
|
||||
|
||||
for (Class c : requiredClasses) {
|
||||
if (c == null) {
|
||||
plugin.debug("Failed to create shop item: Could not find all required classes");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
create();
|
||||
}
|
||||
|
||||
private void create() {
|
||||
try {
|
||||
Object craftWorld = craftWorldClass.cast(location.getWorld());
|
||||
Object nmsWorld = craftWorldClass.getMethod("getHandle").invoke(craftWorld);
|
||||
|
||||
Object nmsItemStack = craftItemStackClass.getMethod("asNMSCopy", ItemStack.class).invoke(null, itemStack);
|
||||
|
||||
Constructor<?> entityItemConstructor = entityItemClass.getConstructor(nmsWorldClass);
|
||||
entityItem = entityItemConstructor.newInstance(nmsWorld);
|
||||
|
||||
entityItemClass.getMethod("setPosition", double.class, double.class, double.class).invoke(entityItem, location.getX(), location.getY(), location.getZ());
|
||||
entityItemClass.getMethod("setItemStack", nmsItemStackClass).invoke(entityItem, nmsItemStack);
|
||||
|
||||
Field ageField = entityItemClass.getDeclaredField("age");
|
||||
ageField.setAccessible(true);
|
||||
ageField.setInt(entityItem, -32768);
|
||||
|
||||
entityId = (int) entityItemClass.getMethod("getId").invoke(entityItem);
|
||||
Object dataWatcher = entityItemClass.getMethod("getDataWatcher").invoke(entityItem);
|
||||
|
||||
creationPackets[0] = packetPlayOutSpawnEntityClass.getConstructor(entityClass, int.class).newInstance(entityItem, 2);
|
||||
creationPackets[1] = packetPlayOutEntityMetadataClass.getConstructor(int.class, dataWatcherClass, boolean.class).newInstance(entityId, dataWatcher, true);
|
||||
creationPackets[2] = packetPlayOutEntityVelocityClass.getConstructor(int.class, double.class, double.class, double.class).newInstance(entityId, 0D, 0D, 0D);
|
||||
} catch (NoSuchMethodException | NoSuchFieldException | InstantiationException | IllegalAccessException | InvocationTargetException e) {
|
||||
plugin.debug("Failed to create shop item with reflection");
|
||||
plugin.debug(e);
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public void remove() {
|
||||
for (Player p : visible.keySet()) {
|
||||
if (isVisible(p)) setVisible(p, false);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Respawns the item at the set location for a player
|
||||
* @param p Player, for which the item should be reset
|
||||
*/
|
||||
public void resetForPlayer(Player p) {
|
||||
setVisible(p, false);
|
||||
setVisible(p, true);
|
||||
}
|
||||
|
||||
public boolean isVisible(Player p) {
|
||||
return visible.get(p) == null ? false : visible.get(p);
|
||||
}
|
||||
|
||||
public void setVisible(final Player p, boolean visible) {
|
||||
if (this.visible.containsKey(p) && this.visible.get(p) == visible)
|
||||
return;
|
||||
|
||||
if (visible) {
|
||||
for (Object packet : this.creationPackets) {
|
||||
Utils.sendPacket(plugin, packet, p);
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
if (p.isOnline()) {
|
||||
Object packetPlayOutEntityDestroy = packetPlayOutEntityDestroyClass.getConstructor(int[].class).newInstance((Object) new int[]{entityId});
|
||||
Utils.sendPacket(plugin, packetPlayOutEntityDestroy, p);
|
||||
}
|
||||
} catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException | InstantiationException e) {
|
||||
plugin.debug("Failed to destroy shop item with reflection");
|
||||
plugin.debug(e);
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
this.visible.put(p, visible);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return Clone of the location, where the shop item should be (it could have been moved by something, even though it shouldn't)
|
||||
* To get the exact location, use reflection and extract the location of the {@code EntityItem}
|
||||
* which you can get in {@link #getEntityItem()}.
|
||||
*/
|
||||
public Location getLocation() {
|
||||
return location.clone();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {@code net.minecraft.server.[VERSION].EntityItem}
|
||||
*/
|
||||
public Object getEntityItem() {
|
||||
return entityItem;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return A clone of this Item's {@link ItemStack}
|
||||
*/
|
||||
public ItemStack getItemStack() {
|
||||
return itemStack.clone();
|
||||
}
|
||||
}
|
@ -221,36 +221,6 @@ public class ShopUtils {
|
||||
}
|
||||
}
|
||||
|
||||
for (World world : Bukkit.getWorlds()) {
|
||||
for (Entity entity : world.getEntities()) {
|
||||
if (entity instanceof Item) {
|
||||
Item item = (Item) entity;
|
||||
if (item.hasMetadata("shopItem")) {
|
||||
if (item.isValid()) {
|
||||
plugin.debug("Removing not removed shop item (#" +
|
||||
(item.hasMetadata("shopId") ? item.getMetadata("shopId").get(0).asString() : "?") + ")");
|
||||
|
||||
item.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (World world : Bukkit.getWorlds()) {
|
||||
for (Entity entity : world.getEntities()) {
|
||||
if (entity instanceof Item) {
|
||||
Item item = (Item) entity;
|
||||
if (item.hasMetadata("shopItem")) {
|
||||
if (item.isValid()) {
|
||||
plugin.debug("Shop item still valid (#" +
|
||||
(item.hasMetadata("shopId") ? item.getMetadata("shopId").get(0).asString() : "?") + ")");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int count = 0;
|
||||
for (int id = 1; id <= highestId; id++) {
|
||||
|
||||
|
@ -53,6 +53,30 @@ public class Utils {
|
||||
return amount;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param className Name of the class
|
||||
* @return Class in {@code net.minecraft.server.[VERSION]} package with the specified name or {@code null} if the class was not found
|
||||
*/
|
||||
public static Class<?> getNMSClass(String className) {
|
||||
try {
|
||||
return Class.forName("net.minecraft.server." + getServerVersion() + "." + className);
|
||||
} catch (ClassNotFoundException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param className Name of the class
|
||||
* @return Class in {@code org.bukkit.craftbukkit.[VERSION]} package with the specified name or {@code null} if the class was not found
|
||||
*/
|
||||
public static Class<?> getCraftClass(String className) {
|
||||
try {
|
||||
return Class.forName("org.bukkit.craftbukkit." + getServerVersion() + "." + className);
|
||||
} catch (ClassNotFoundException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a packet to a player
|
||||
* @param packet Packet to send
|
||||
|
Loading…
Reference in New Issue
Block a user