diff --git a/src/main/java/de/hglabor/utils/noriskutils/ClientPayloadBuffer.java b/src/main/java/de/hglabor/utils/noriskutils/ClientPayloadBuffer.java new file mode 100644 index 0000000..db178af --- /dev/null +++ b/src/main/java/de/hglabor/utils/noriskutils/ClientPayloadBuffer.java @@ -0,0 +1,122 @@ +package de.hglabor.utils.noriskutils; + +import io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; +import io.netty.handler.codec.DecoderException; +import io.netty.handler.codec.EncoderException; + +import java.nio.charset.StandardCharsets; + +/** + * Payload buffer to encode or decode + * client plugin messages + * Encoding and decoding flow from + * wiki.vg + * + * @version 1.0 + */ +public final class ClientPayloadBuffer { //final because it seems to be convention in here + + /** + * The bytebuffer to store the bytes + */ + private final ByteBuf byteBuf; + + /** + * Constructor to create a buffer out of an existing + * payload + * + * @param payload The payload byte array + */ + public ClientPayloadBuffer(byte[] payload) { + this.byteBuf = Unpooled.wrappedBuffer(payload); + } + + /** + * Constructor for creating a new + * buffer being empty + */ + public ClientPayloadBuffer() { + //Creating new buffer + this.byteBuf = Unpooled.buffer(); + } + + /** + * Getter for the byte buf + * because it's needed to send it to the player + * + * @return The bytebuf of the buffer + */ + public ByteBuf getByteBuf() { + return this.byteBuf; + } + + /** + * Writing a string into the buffer + * + * @param stringToWrite The string to write + */ + public void writeString(String stringToWrite) { + byte[] stringBytes = stringToWrite.getBytes(StandardCharsets.UTF_8); + + if (stringBytes.length > Short.MAX_VALUE) { + throw new EncoderException("String was too big"); + } + this.writeLengthVarInt(stringBytes.length); + this.byteBuf.writeBytes(stringBytes); + } + + /** + * Writing the length as varint into the buffer + * code of minecraft protocol + * + * @param length The length of the string byte + */ + private void writeLengthVarInt(int length) { + while ((length & -128) != 0) { + this.byteBuf.writeByte(length & 127 | 128); + length >>>= 7; + } + this.byteBuf.writeByte(length); + } + + /** + * Reading the length out of a varInt + * using mc protocol decoding + * + * @return The length + */ + private int readLengthVarInt() { + int readCount = 0; + int result = 0; + byte readByte; + + do { + readByte = this.byteBuf.readByte(); + result |= (readByte & 127) << readCount++ * 7; + if (readCount > 5) { + throw new DecoderException("Invalid war int size"); + } + } while ((readByte & 128) == 128); + + return result; + } + + /** + * Reading a string out of + * the byte buf + * + * @return The read string + */ + public String readString() { + int stringByteArrayLength = this.readLengthVarInt(); + + if (stringByteArrayLength < 0 || stringByteArrayLength > 4 * Short.MAX_VALUE) { + throw new DecoderException("Invalid string length"); + } + byte[] stringBytes = new byte[stringByteArrayLength]; + this.byteBuf.readBytes(stringBytes); + + return new String(stringBytes, StandardCharsets.UTF_8); + } +} diff --git a/src/main/java/de/hglabor/utils/noriskutils/listener/LabyModOldPvP.java b/src/main/java/de/hglabor/utils/noriskutils/listener/LabyModOldPvP.java new file mode 100644 index 0000000..148e70f --- /dev/null +++ b/src/main/java/de/hglabor/utils/noriskutils/listener/LabyModOldPvP.java @@ -0,0 +1,120 @@ +package de.hglabor.utils.noriskutils.listener; + +import com.google.gson.JsonObject; +import de.hglabor.utils.noriskutils.ClientPayloadBuffer; +import de.hglabor.utils.noriskutils.NMSUtils; +import net.minecraft.server.v1_16_R3.MinecraftKey; +import net.minecraft.server.v1_16_R3.PacketDataSerializer; +import net.minecraft.server.v1_16_R3.PacketPlayOutCustomPayload; +import org.bukkit.entity.Player; +import org.bukkit.plugin.java.JavaPlugin; +import org.bukkit.plugin.messaging.PluginMessageListener; +import org.jetbrains.annotations.NotNull; + +/** + * Implementation for LabyMods new combat system + * in the 1.16.5 for HGLabor.de + * + * Use `new LabyModOldPvP(plugin);` to register listening + * + * @author Raik + * @version 1.0 + */ +public class LabyModOldPvP implements PluginMessageListener { + + /** + * Channel name used by LabyMod for communication + */ + private static final String CHANNEL_NAME = "labymod3:main"; + + /** + * Constructor setting up the the listening + * + * @param plugin The plugin instance + */ + public LabyModOldPvP(JavaPlugin plugin) { + //Register listening + plugin.getServer().getMessenger().registerIncomingPluginChannel(plugin, CHANNEL_NAME, this); + } + + + /** + * A method that will be thrown when a PluginMessageSource sends a plugin + * message on a registered channel. + * Catching labymods join message to send perm message + * + * @param channel Channel that the message was sent through. + * @param player Source of the message. + * @param message The raw message that was sent. + */ + @Override + public void onPluginMessageReceived(@NotNull String channel, @NotNull Player player, byte[] message) { + if (!channel.equals(CHANNEL_NAME)) { + return; + } + + ClientPayloadBuffer payloadBuffer = new ClientPayloadBuffer(message); + //Only execute on join / INFO message + if (payloadBuffer.readString().equals("INFO")) { + this.sendPermissions(player); + } + } + + /** + * Send the permission to the player + * using plugin channels + * + * @param receiver The receiver of the permissions + */ + private void sendPermissions(Player receiver) { + ClientPayloadBuffer payloadBuffer = new ClientPayloadBuffer(); + //Set permission key + payloadBuffer.writeString("PERMISSIONS"); + //Set permission + payloadBuffer.writeString(LabyModSettings.getSettingsAsJsonString()); + + //Creating packet + PacketPlayOutCustomPayload payloadPacket = new PacketPlayOutCustomPayload(new MinecraftKey(CHANNEL_NAME) + , new PacketDataSerializer(payloadBuffer.getByteBuf())); + + //Sending packet + NMSUtils.sendPacket(receiver, payloadPacket); + } + + /** + * Enum containing every changed + * settings which will be transmitted to the player + */ + private enum LabyModSettings { + IMPROVED_LAVA(true), //Minecraft bug fix provided by LabyMod + RANGE(true), //Adding 1.8 Range to 1.16 + SLOWDOWN(true); //Adding slowdown on blocking + + /** + * The state whether a features is enabled or not + */ + private final boolean state; + + LabyModSettings(boolean state) { + this.state = state; + } + + /** + * Getting all Settings as Json String + * using JsonObject and looping through + * als set values + * + * @return The json srting + */ + public static String getSettingsAsJsonString() { + JsonObject settings = new JsonObject(); + + //Looping through settings to add them + for (LabyModSettings setting: values()) { + settings.addProperty(setting.name(), setting.state); + } + + return settings.toString(); + } + } +}