mirror of
https://github.com/amalthea-mc/ShopChest.git
synced 2024-12-22 17:11:46 +00:00
Link plugin to nms sub modules
This commit is contained in:
parent
7410f2088d
commit
b46bd953c3
@ -18,6 +18,9 @@ import java.util.stream.Stream;
|
||||
import com.palmergames.bukkit.towny.Towny;
|
||||
import com.wasteofplastic.askyblock.ASkyBlock;
|
||||
|
||||
import de.epiceric.shopchest.nms.Platform;
|
||||
import de.epiceric.shopchest.nms.reflection.PlatformImpl;
|
||||
import de.epiceric.shopchest.nms.reflection.ShopChestDebug;
|
||||
import org.bstats.bukkit.Metrics;
|
||||
import org.bstats.charts.AdvancedPie;
|
||||
import org.bstats.charts.SimplePie;
|
||||
@ -82,6 +85,7 @@ public class ShopChest extends JavaPlugin {
|
||||
private static ShopChest instance;
|
||||
|
||||
private Config config;
|
||||
private Platform platform;
|
||||
private HologramFormat hologramFormat;
|
||||
private ShopCommand shopCommand;
|
||||
private Economy econ = null;
|
||||
@ -188,12 +192,17 @@ public class ShopChest extends JavaPlugin {
|
||||
case "v1_16_R1":
|
||||
case "v1_16_R2":
|
||||
case "v1_16_R3":
|
||||
platform = new PlatformImpl(new ShopChestDebug(getLogger(), this::debug, this::debug));
|
||||
break;
|
||||
case "v1_17_R1":
|
||||
platform = new de.epiceric.shopchest.nms.v1_17_R1.PlatformImpl();
|
||||
break;
|
||||
default:
|
||||
debug("Server version not officially supported: " + Utils.getServerVersion() + "!");
|
||||
debug("Plugin may still work, but more errors are expected!");
|
||||
//debug("Plugin may still work, but more errors are expected!");
|
||||
getLogger().warning("Server version not officially supported: " + Utils.getServerVersion() + "!");
|
||||
getLogger().warning("Plugin may still work, but more errors are expected!");
|
||||
//getLogger().warning("Plugin may still work, but more errors are expected!");
|
||||
getServer().getPluginManager().disablePlugin(this);
|
||||
}
|
||||
|
||||
shopUtils = new ShopUtils(this);
|
||||
@ -559,6 +568,10 @@ public class ShopChest extends JavaPlugin {
|
||||
return shopCreationThreadPool;
|
||||
}
|
||||
|
||||
public Platform getPlatform() {
|
||||
return platform;
|
||||
}
|
||||
|
||||
public HologramFormat getHologramFormat() {
|
||||
return hologramFormat;
|
||||
}
|
||||
|
@ -1,148 +1,57 @@
|
||||
package de.epiceric.shopchest.nms;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import de.epiceric.shopchest.ShopChest;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.UUID;
|
||||
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.entity.EntityType;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.inventivetalent.reflection.resolver.minecraft.NMSClassResolver;
|
||||
|
||||
import de.epiceric.shopchest.ShopChest;
|
||||
import de.epiceric.shopchest.utils.Utils;
|
||||
|
||||
public class ArmorStandWrapper {
|
||||
private final NMSClassResolver nmsClassResolver = new NMSClassResolver();
|
||||
private final Class<?> packetDataSerializerClass = nmsClassResolver.resolveSilent("network.PacketDataSerializer");
|
||||
private final Class<?> packetPlayOutEntityDestroyClass = nmsClassResolver.resolveSilent("network.protocol.game.PacketPlayOutEntityDestroy");
|
||||
private final Class<?> packetPlayOutEntityMetadataClass = nmsClassResolver.resolveSilent("network.protocol.game.PacketPlayOutEntityMetadata");
|
||||
private final Class<?> packetPlayOutEntityTeleportClass = nmsClassResolver.resolveSilent("network.protocol.game.PacketPlayOutEntityTeleport");
|
||||
private final Class<?> dataWatcherClass = nmsClassResolver.resolveSilent("network.syncher.DataWatcher");
|
||||
|
||||
private final UUID uuid = UUID.randomUUID();
|
||||
private final int entityId;
|
||||
private final FakeArmorStand fakeArmorStand;
|
||||
|
||||
private ShopChest plugin;
|
||||
private Location location;
|
||||
private String customName;
|
||||
|
||||
public ArmorStandWrapper(ShopChest plugin, Location location, String customName) {
|
||||
this.plugin = plugin;
|
||||
this.location = location;
|
||||
this.customName = customName;
|
||||
this.entityId = Utils.getFreeEntityId();
|
||||
this.fakeArmorStand = plugin.getPlatform().createFakeArmorStand();
|
||||
}
|
||||
|
||||
public void setVisible(Player player, boolean visible) {
|
||||
try {
|
||||
if (visible) {
|
||||
Object dataWatcher = Utils.createDataWatcher(customName, null);
|
||||
Utils.sendPacket(plugin, Utils.createPacketSpawnEntity(plugin, entityId, uuid, location, EntityType.ARMOR_STAND), player);
|
||||
Utils.sendPacket(plugin, packetPlayOutEntityMetadataClass.getConstructor(int.class, dataWatcherClass, boolean.class)
|
||||
.newInstance(entityId, dataWatcher, true), player);
|
||||
} else if (entityId != -1) {
|
||||
Utils.sendPacket(plugin, packetPlayOutEntityDestroyClass.getConstructor(int[].class).newInstance((Object) new int[]{entityId}), player);
|
||||
}
|
||||
} catch (ReflectiveOperationException e) {
|
||||
plugin.getLogger().severe("Could not change hologram visibility");
|
||||
plugin.debug("Could not change armor stand visibility");
|
||||
plugin.debug(e);
|
||||
final List<Player> receiver = Collections.singletonList(player);
|
||||
if(visible){
|
||||
fakeArmorStand.spawn(uuid, location, receiver);
|
||||
fakeArmorStand.sendData(customName, receiver);
|
||||
}
|
||||
else if(fakeArmorStand.getEntityId() != -1){
|
||||
fakeArmorStand.remove(receiver);
|
||||
}
|
||||
}
|
||||
|
||||
public void setLocation(Location location) {
|
||||
this.location = location;
|
||||
double y = location.getY() + (Utils.getServerVersion().equals("v1_8_R1") ? 0 : 1.975);
|
||||
Object packet;
|
||||
|
||||
try {
|
||||
if (Utils.getMajorVersion() >= 17) {
|
||||
// Empty constructor does not exist anymore in 1.17+ so create packet via serializer
|
||||
Class<?> byteBufClass = Class.forName("io.netty.buffer.ByteBuf");
|
||||
Class<?> unpooledClass = Class.forName("io.netty.buffer.Unpooled");
|
||||
Object buffer = unpooledClass.getMethod("buffer").invoke(null);
|
||||
Object serializer = packetDataSerializerClass.getConstructor(byteBufClass).newInstance(buffer);
|
||||
|
||||
Method d = packetDataSerializerClass.getMethod("d", int.class);
|
||||
Method writeDouble = packetDataSerializerClass.getMethod("writeDouble", double.class);
|
||||
Method writeByte = packetDataSerializerClass.getMethod("writeByte", int.class);
|
||||
Method writeBoolean = packetDataSerializerClass.getMethod("writeBoolean", boolean.class);
|
||||
|
||||
d.invoke(serializer, getEntityId());
|
||||
writeDouble.invoke(serializer, location.getX());
|
||||
writeDouble.invoke(serializer, y);
|
||||
writeDouble.invoke(serializer, location.getZ());
|
||||
writeByte.invoke(serializer, 0);
|
||||
writeByte.invoke(serializer, 0);
|
||||
writeBoolean.invoke(serializer, false);
|
||||
|
||||
packet = packetPlayOutEntityTeleportClass.getConstructor(packetDataSerializerClass).newInstance(serializer);
|
||||
} else {
|
||||
packet = packetPlayOutEntityTeleportClass.getConstructor().newInstance();
|
||||
Field[] fields = packetPlayOutEntityTeleportClass.getDeclaredFields();
|
||||
for (Field field : fields) {
|
||||
field.setAccessible(true);
|
||||
}
|
||||
|
||||
boolean isPre9 = Utils.getMajorVersion() < 9;
|
||||
fields[0].set(packet, entityId);
|
||||
|
||||
if (isPre9) {
|
||||
fields[1].set(packet, (int)(location.getX() * 32));
|
||||
fields[2].set(packet, (int)(y * 32));
|
||||
fields[3].set(packet, (int)(location.getZ() * 32));
|
||||
} else {
|
||||
fields[1].set(packet, location.getX());
|
||||
fields[2].set(packet, y);
|
||||
fields[3].set(packet, location.getZ());
|
||||
}
|
||||
fields[4].set(packet, (byte) 0);
|
||||
fields[5].set(packet, (byte) 0);
|
||||
fields[6].set(packet, true);
|
||||
}
|
||||
|
||||
if (packet == null) {
|
||||
plugin.getLogger().severe("Could not set hologram location");
|
||||
plugin.debug("Could not set armor stand location: Packet is null");
|
||||
return;
|
||||
}
|
||||
|
||||
for (Player player : location.getWorld().getPlayers()) {
|
||||
Utils.sendPacket(plugin, packet, player);
|
||||
}
|
||||
} catch (ReflectiveOperationException e) {
|
||||
plugin.getLogger().severe("Could not set hologram location");
|
||||
plugin.debug("Could not set armor stand location");
|
||||
plugin.debug(e);
|
||||
}
|
||||
fakeArmorStand.setLocation(location, Objects.requireNonNull(location.getWorld()).getPlayers());
|
||||
}
|
||||
|
||||
public void setCustomName(String customName) {
|
||||
this.customName = customName;
|
||||
Object dataWatcher = Utils.createDataWatcher(customName, null);
|
||||
try {
|
||||
Object packet = packetPlayOutEntityMetadataClass.getConstructor(int.class, dataWatcherClass, boolean.class)
|
||||
.newInstance(entityId, dataWatcher, true);
|
||||
|
||||
for (Player player : location.getWorld().getPlayers()) {
|
||||
Utils.sendPacket(plugin, packet, player);
|
||||
}
|
||||
} catch (ReflectiveOperationException e) {
|
||||
plugin.getLogger().severe("Could not set hologram text");
|
||||
plugin.debug("Could not set armor stand custom name");
|
||||
plugin.debug(e);
|
||||
}
|
||||
fakeArmorStand.sendData(customName, Objects.requireNonNull(location.getWorld()).getPlayers());
|
||||
}
|
||||
|
||||
public void remove() {
|
||||
for (Player player : location.getWorld().getPlayers()) {
|
||||
for (Player player : Objects.requireNonNull(location.getWorld()).getPlayers()) {
|
||||
setVisible(player, false);
|
||||
}
|
||||
}
|
||||
|
||||
public int getEntityId() {
|
||||
return entityId;
|
||||
return fakeArmorStand.getEntityId();
|
||||
}
|
||||
|
||||
public UUID getUuid() {
|
||||
|
@ -1,59 +1,28 @@
|
||||
package de.epiceric.shopchest.shop;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import de.epiceric.shopchest.ShopChest;
|
||||
import de.epiceric.shopchest.nms.FakeItem;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.entity.EntityType;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.inventivetalent.reflection.resolver.minecraft.NMSClassResolver;
|
||||
import org.inventivetalent.reflection.resolver.minecraft.OBCClassResolver;
|
||||
|
||||
import de.epiceric.shopchest.ShopChest;
|
||||
import de.epiceric.shopchest.utils.Utils;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
public class ShopItem {
|
||||
private final ShopChest plugin;
|
||||
|
||||
// concurrent since update task is in async thread
|
||||
private final Set<UUID> viewers = ConcurrentHashMap.newKeySet();
|
||||
private final ItemStack itemStack;
|
||||
private final Location location;
|
||||
private final UUID uuid = UUID.randomUUID();
|
||||
private final int entityId;
|
||||
|
||||
private final NMSClassResolver nmsClassResolver = new NMSClassResolver();
|
||||
private final OBCClassResolver obcClassResolver = new OBCClassResolver();
|
||||
private final Class<?> packetPlayOutEntityDestroyClass = nmsClassResolver.resolveSilent("network.protocol.game.PacketPlayOutEntityDestroy");
|
||||
private final Class<?> packetPlayOutEntityVelocityClass = nmsClassResolver.resolveSilent("network.protocol.game.PacketPlayOutEntityVelocity");
|
||||
private final Class<?> packetPlayOutEntityMetadataClass = nmsClassResolver.resolveSilent("network.protocol.game.PacketPlayOutEntityMetadata");
|
||||
private final Class<?> dataWatcherClass = nmsClassResolver.resolveSilent("network.syncher.DataWatcher");
|
||||
private final Class<?> vec3dClass = nmsClassResolver.resolveSilent("world.phys.Vec3D");
|
||||
private final Class<?> craftItemStackClass = obcClassResolver.resolveSilent("inventory.CraftItemStack");
|
||||
private final Class<?> nmsItemStackClass = nmsClassResolver.resolveSilent("world.item.ItemStack");
|
||||
private final FakeItem fakeItem;
|
||||
|
||||
public ShopItem(ShopChest plugin, ItemStack itemStack, Location location) {
|
||||
this.plugin = plugin;
|
||||
this.itemStack = itemStack;
|
||||
this.location = location;
|
||||
this.entityId = Utils.getFreeEntityId();
|
||||
|
||||
Class<?>[] requiredClasses = new Class<?>[] {
|
||||
nmsItemStackClass, craftItemStackClass, packetPlayOutEntityMetadataClass, dataWatcherClass,
|
||||
packetPlayOutEntityDestroyClass, packetPlayOutEntityVelocityClass,
|
||||
};
|
||||
|
||||
for (Class<?> c : requiredClasses) {
|
||||
if (c == null) {
|
||||
plugin.debug("Failed to create shop item: Could not find all required classes");
|
||||
return;
|
||||
}
|
||||
}
|
||||
this.fakeItem = plugin.getPlatform().createFakeItem();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -91,22 +60,10 @@ public class ShopItem {
|
||||
*/
|
||||
public void showPlayer(Player p, boolean force) {
|
||||
if (viewers.add(p.getUniqueId()) || force) {
|
||||
try {
|
||||
Object nmsItemStack = craftItemStackClass.getMethod("asNMSCopy", ItemStack.class).invoke(null, itemStack);
|
||||
Object dataWatcher = Utils.createDataWatcher(null, nmsItemStack);
|
||||
Utils.sendPacket(plugin, Utils.createPacketSpawnEntity(plugin, entityId, uuid, location, EntityType.DROPPED_ITEM), p);
|
||||
Utils.sendPacket(plugin, packetPlayOutEntityMetadataClass.getConstructor(int.class, dataWatcherClass, boolean.class).newInstance(entityId, dataWatcher, true), p);
|
||||
if (Utils.getMajorVersion() < 14) {
|
||||
Utils.sendPacket(plugin, packetPlayOutEntityVelocityClass.getConstructor(int.class, double.class, double.class, double.class).newInstance(entityId, 0D, 0D, 0D), p);
|
||||
} else {
|
||||
Object vec3d = vec3dClass.getConstructor(double.class, double.class, double.class).newInstance(0D, 0D, 0D);
|
||||
Utils.sendPacket(plugin, packetPlayOutEntityVelocityClass.getConstructor(int.class, vec3dClass).newInstance(entityId, vec3d), p);
|
||||
}
|
||||
} catch (NoSuchMethodException | IllegalAccessException | IllegalArgumentException | InvocationTargetException | SecurityException | InstantiationException e) {
|
||||
plugin.getLogger().severe("Failed to create item!");
|
||||
plugin.debug("Failed to create item!");
|
||||
plugin.debug(e);
|
||||
}
|
||||
final List<Player> receiver = Collections.singletonList(p);
|
||||
fakeItem.spawn(uuid, location, receiver);
|
||||
fakeItem.sendData(itemStack, receiver);
|
||||
fakeItem.resetVelocity(receiver);
|
||||
}
|
||||
}
|
||||
|
||||
@ -123,15 +80,8 @@ public class ShopItem {
|
||||
*/
|
||||
public void hidePlayer(Player p, boolean force) {
|
||||
if (viewers.remove(p.getUniqueId()) || force) {
|
||||
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.getLogger().severe("Failed to destroy shop item");
|
||||
plugin.debug("Failed to destroy shop item with reflection");
|
||||
plugin.debug(e);
|
||||
if (p.isOnline()) {
|
||||
fakeItem.remove(Collections.singletonList(p));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user