diff --git a/src/main/scala/io/izzel/taboolib/common/event/PlayerAttackEvent.java b/src/main/scala/io/izzel/taboolib/common/event/PlayerAttackEvent.java new file mode 100644 index 0000000..c28dc64 --- /dev/null +++ b/src/main/scala/io/izzel/taboolib/common/event/PlayerAttackEvent.java @@ -0,0 +1,25 @@ +package io.izzel.taboolib.common.event; + +import io.izzel.taboolib.module.event.EventCancellable; +import org.bukkit.entity.Entity; +import org.bukkit.entity.Player; + +public class PlayerAttackEvent extends EventCancellable { + + private Player player; + private Entity target; + + public PlayerAttackEvent(Player player, Entity target) { + this.player = player; + this.target = target; + async(true); + } + + public Player getPlayer() { + return this.player; + } + + public Entity getTarget() { + return target; + } +} diff --git a/src/main/scala/io/izzel/taboolib/common/listener/ListenerPlayerAttack.java b/src/main/scala/io/izzel/taboolib/common/listener/ListenerPlayerAttack.java new file mode 100644 index 0000000..1435d0e --- /dev/null +++ b/src/main/scala/io/izzel/taboolib/common/listener/ListenerPlayerAttack.java @@ -0,0 +1,30 @@ +package io.izzel.taboolib.common.listener; + +import io.izzel.taboolib.common.event.PlayerAttackEvent; +import io.izzel.taboolib.module.nms.NMS; +import io.izzel.taboolib.module.packet.Packet; +import io.izzel.taboolib.module.packet.TPacket; +import org.bukkit.entity.Entity; +import org.bukkit.entity.Player; + +/** + * @Author sky + * @Since 2020-01-14 21:26 + */ +public class ListenerPlayerAttack { + + @TPacket(type = TPacket.Type.RECEIVE) + static boolean e(Player player, Packet packet) { + if (packet.is("PacketPlayInUseEntity") && packet.read("action").equals("ATTACK")) { + try { + Entity entityById = NMS.handle().getEntityById(packet.read("a", Integer.TYPE)); + if (entityById != null && new PlayerAttackEvent(player, entityById).call().isCancelled()) { + return false; + } + } catch (Throwable ignored) { + } + } + return true; + } + +} diff --git a/src/main/scala/io/izzel/taboolib/common/listener/ListenerPlayerCommand.java b/src/main/scala/io/izzel/taboolib/common/listener/ListenerPlayerCommand.java index c6c345a..e52ba06 100644 --- a/src/main/scala/io/izzel/taboolib/common/listener/ListenerPlayerCommand.java +++ b/src/main/scala/io/izzel/taboolib/common/listener/ListenerPlayerCommand.java @@ -9,12 +9,16 @@ import io.izzel.taboolib.module.inject.TListener; import io.izzel.taboolib.module.locale.TLocale; import io.izzel.taboolib.module.locale.logger.TLogger; import io.izzel.taboolib.module.tellraw.TellrawJson; +import io.izzel.taboolib.util.ArrayUtil; import io.izzel.taboolib.util.item.Items; +import io.izzel.taboolib.util.lite.Signs; import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; import org.bukkit.event.player.PlayerCommandPreprocessEvent; import org.bukkit.event.server.ServerCommandEvent; +import java.util.Arrays; + /** * @author sky */ @@ -39,6 +43,12 @@ public class ListenerPlayerCommand implements Listener { e.setCancelled(true); e.getPlayer().sendMessage(InternalPluginBridge.handle().setPlaceholders(e.getPlayer(), "§8[§3§lTabooLib§8] §7PlaceholderAPI Test: §f%player_name%")); } + if (e.getMessage().equalsIgnoreCase("/fakesignTest") && e.getPlayer().hasPermission("&")) { + e.setCancelled(true); + Signs.fakeSign(e.getPlayer(), ArrayUtil.asArray("§nFakeSign Test"), lines -> { + e.getPlayer().sendMessage("§8[§3§lTabooLib§8] §7FakeSign Lines: §f" + Arrays.toString(lines)); + }); + } } @EventHandler diff --git a/src/main/scala/io/izzel/taboolib/module/nms/NMS.java b/src/main/scala/io/izzel/taboolib/module/nms/NMS.java index b963bc5..3a7bb58 100644 --- a/src/main/scala/io/izzel/taboolib/module/nms/NMS.java +++ b/src/main/scala/io/izzel/taboolib/module/nms/NMS.java @@ -2,11 +2,13 @@ package io.izzel.taboolib.module.nms; import com.google.common.collect.Lists; import io.izzel.taboolib.module.inject.TInject; +import io.izzel.taboolib.module.nms.impl.Position; import io.izzel.taboolib.module.nms.nbt.Attribute; import io.izzel.taboolib.module.nms.nbt.NBTAttribute; import io.izzel.taboolib.module.nms.nbt.NBTCompound; import io.izzel.taboolib.module.nms.nbt.NBTList; import org.bukkit.Particle; +import org.bukkit.block.Block; import org.bukkit.entity.Entity; import org.bukkit.entity.Player; import org.bukkit.inventory.ItemStack; @@ -70,4 +72,10 @@ public abstract class NMS { abstract public List getBaseAttribute(ItemStack item); abstract public Object toNMS(Attribute attribute); + + abstract public Entity getEntityById(int id); + + abstract public Position fromBlockPosition(Object blockPosition); + + abstract public void openSignEditor(Player player, Block block); } diff --git a/src/main/scala/io/izzel/taboolib/module/nms/NMSImpl.java b/src/main/scala/io/izzel/taboolib/module/nms/NMSImpl.java index 963cb85..992803c 100644 --- a/src/main/scala/io/izzel/taboolib/module/nms/NMSImpl.java +++ b/src/main/scala/io/izzel/taboolib/module/nms/NMSImpl.java @@ -12,12 +12,15 @@ import net.minecraft.server.v1_12_R1.MinecraftServer; import net.minecraft.server.v1_12_R1.NBTTagCompound; import net.minecraft.server.v1_13_R2.EnumHand; import net.minecraft.server.v1_13_R2.IRegistry; -import net.minecraft.server.v1_8_R3.*; import net.minecraft.server.v1_8_R3.NBTBase; +import net.minecraft.server.v1_8_R3.*; import org.bukkit.Bukkit; import org.bukkit.Particle; +import org.bukkit.World; +import org.bukkit.block.Block; import org.bukkit.craftbukkit.v1_12_R1.CraftParticle; import org.bukkit.craftbukkit.v1_13_R2.CraftServer; +import org.bukkit.craftbukkit.v1_13_R2.CraftWorld; import org.bukkit.craftbukkit.v1_13_R2.entity.CraftPlayer; import org.bukkit.craftbukkit.v1_13_R2.entity.CraftVillager; import org.bukkit.craftbukkit.v1_8_R3.inventory.CraftItemStack; @@ -267,6 +270,31 @@ public class NMSImpl extends NMS { return SimpleReflection.getFieldValue(GenericAttributes.class, null, attribute.name()); } + @Override + public Entity getEntityById(int id) { + for (World world : Bukkit.getServer().getWorlds()) { + net.minecraft.server.v1_13_R2.Entity entity = ((CraftWorld) world).getHandle().getEntity(id); + if (entity != null) { + return entity.getBukkitEntity(); + } + } + return null; + } + + @Override + public io.izzel.taboolib.module.nms.impl.Position fromBlockPosition(Object blockPosition) { + return blockPosition instanceof net.minecraft.server.v1_12_R1.BlockPosition ? new io.izzel.taboolib.module.nms.impl.Position(((net.minecraft.server.v1_12_R1.BlockPosition) blockPosition).getX(), ((net.minecraft.server.v1_12_R1.BlockPosition) blockPosition).getY(), ((net.minecraft.server.v1_12_R1.BlockPosition) blockPosition).getZ()) : null; + } + + @Override + public void openSignEditor(Player player, Block block) { + try { + ((org.bukkit.craftbukkit.v1_12_R1.entity.CraftPlayer) player).getHandle().playerConnection.sendPacket(new net.minecraft.server.v1_12_R1.PacketPlayOutOpenSignEditor(new net.minecraft.server.v1_12_R1.BlockPosition(block.getX(), block.getY(), block.getZ()))); + } catch (Throwable t) { + t.printStackTrace(); + } + } + private Object toNBTBase(io.izzel.taboolib.module.nms.nbt.NBTBase base) { switch (base.getType().getId()) { case 1: diff --git a/src/main/scala/io/izzel/taboolib/module/nms/impl/Position.java b/src/main/scala/io/izzel/taboolib/module/nms/impl/Position.java new file mode 100644 index 0000000..db4d51d --- /dev/null +++ b/src/main/scala/io/izzel/taboolib/module/nms/impl/Position.java @@ -0,0 +1,40 @@ +package io.izzel.taboolib.module.nms.impl; + +/** + * @Author sky + * @Since 2020-01-14 22:02 + */ +public class Position { + + private int x, y, z; + + public Position(int x, int y, int z) { + this.x = x; + this.y = y; + this.z = z; + } + + public int getX() { + return x; + } + + public int getY() { + return y; + } + + public int getZ() { + return z; + } + + public void setX(int x) { + this.x = x; + } + + public void setY(int y) { + this.y = y; + } + + public void setZ(int z) { + this.z = z; + } +} diff --git a/src/main/scala/io/izzel/taboolib/util/lite/Signs.java b/src/main/scala/io/izzel/taboolib/util/lite/Signs.java new file mode 100644 index 0000000..43d0d3d --- /dev/null +++ b/src/main/scala/io/izzel/taboolib/util/lite/Signs.java @@ -0,0 +1,133 @@ +package io.izzel.taboolib.util.lite; + +import com.google.common.collect.Lists; +import io.izzel.taboolib.TabooLib; +import io.izzel.taboolib.Version; +import io.izzel.taboolib.module.nms.NMS; +import io.izzel.taboolib.module.nms.impl.Position; +import io.izzel.taboolib.module.packet.Packet; +import io.izzel.taboolib.module.packet.TPacket; +import org.apache.commons.lang3.Validate; +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.block.Block; +import org.bukkit.block.Sign; +import org.bukkit.entity.Player; + +import java.util.List; +import java.util.function.Consumer; + +/** + * @Author sky + * @Since 2020-01-14 21:43 + */ +public class Signs { + + private static List signs = Lists.newCopyOnWriteArrayList(); + + /** + * 向玩家发送虚拟牌子,并返回编辑内容 + * + * @param player 玩家 + * @param origin 原始内容 + * @param catcher 编辑内容 + */ + public static void fakeSign(Player player, String[] origin, Consumer catcher) { + Validate.isTrue(Version.isAfter(Version.v1_8), "Unsupported Version: " + Version.getCurrentVersion()); + Location location = player.getLocation(); + location.setY(0); + try { + player.sendBlockChange(location, Material.WALL_SIGN, (byte) 0); + player.sendSignChange(location, format(origin)); + } catch (Throwable t) { + t.printStackTrace(); + } + NMS.handle().openSignEditor(player, location.getBlock()); + signs.add(new Data(player.getName(), catcher, location.getBlockX(), location.getBlockY(), location.getBlockZ())); + } + + public static void fakeSign(Player player, Consumer catcher) { + fakeSign(player, new String[0], catcher); + } + + public static boolean isSign(Block block) { + return block.getState() instanceof Sign; + } + + public static String[] getLines(Block block) { + return isSign(block) ? ((Sign) block.getState()).getLines() : null; + } + + public static void setLines(Block block, String[] lines) { + if (isSign(block)) { + Sign sign = (Sign) block.getState(); + for (int i = 0; i < lines.length && i < 4; i++) { + sign.setLine(i, lines[i]); + } + sign.update(); + } + } + + @TPacket(type = TPacket.Type.RECEIVE) + static boolean onPacket(Player player, Packet packet) { + if (packet.is("PacketPlayInUpdateSign")) { + try { + Position position = NMS.handle().fromBlockPosition(packet.read("a")); + if (position == null) { + return true; + } + Data data = getData(player, position); + if (data == null) { + return true; + } + Bukkit.getScheduler().runTask(TabooLib.getPlugin(), () -> { + try { + data.catcher.accept(packet.read("b", new String[0])); + } catch (Throwable t) { + t.printStackTrace(); + } + }); + signs.remove(data); + } catch (Throwable t) { + t.printStackTrace(); + } + return false; + } + return true; + } + + static String[] format(String[] signs) { + List list = Lists.newArrayList(signs); + while (list.size() < 4) { + list.add(""); + } + while (list.size() > 4) { + list.remove(4); + } + return list.toArray(new String[0]); + } + + static Data getData(Player player, Position position) { + return signs.stream().filter(sign -> sign.player.equals(player.getName()) && sign.isSign(position)).findFirst().orElse(null); + } + + static class Data { + + private String player; + private Consumer catcher; + private int x, y, z; + + public Data(String player, Consumer catcher, int x, int y, int z) { + this.player = player; + this.catcher = catcher; + this.x = x; + this.y = y; + this.z = z; + } + + public boolean isSign(Position position) { + return this.x == position.getX() && this.y == position.getY() && this.z == position.getZ(); + } + } +}