From 3b06c5b9ef95c7d2e7acf2b0ee28ca9a507d3ef3 Mon Sep 17 00:00:00 2001 From: Felix Cravic Date: Sun, 5 Apr 2020 10:15:21 +0200 Subject: [PATCH] Update --- build.gradle | 4 +- src/main/java/fr/themode/demo/Main.java | 13 +- src/main/java/fr/themode/demo/PlayerInit.java | 12 +- .../themode/demo/commands/HealthCommand.java | 78 ++++++++ .../themode/demo/commands/SimpleCommand.java | 17 ++ .../minestom/command/CommandManager.java | 170 ++++++++++++++++++ .../minestom/command/CommandProcessor.java | 10 ++ .../minestom/entity/EntityCreature.java | 10 +- .../themode/minestom/entity/LivingEntity.java | 12 +- .../fr/themode/minestom/entity/Player.java | 10 +- .../minestom/event/PlayerCommandEvent.java | 26 +++ .../listener/ChatMessageListener.java | 18 ++ .../minestom/listener/RecipeListener.java | 15 ++ .../manager/PacketListenerManager.java | 1 + .../handler/ClientPlayPacketsHandler.java | 1 + .../packet/client/login/LoginStartPacket.java | 33 +--- .../client/play/ClientCraftRecipeRequest.java | 21 +++ .../server/play/CraftRecipeResponse.java | 22 +++ .../server/play/PluginMessagePacket.java | 22 +++ .../fr/themode/minestom/utils/ArrayUtils.java | 10 ++ 20 files changed, 450 insertions(+), 55 deletions(-) create mode 100644 src/main/java/fr/themode/demo/commands/HealthCommand.java create mode 100644 src/main/java/fr/themode/demo/commands/SimpleCommand.java create mode 100644 src/main/java/fr/themode/minestom/command/CommandManager.java create mode 100644 src/main/java/fr/themode/minestom/command/CommandProcessor.java create mode 100644 src/main/java/fr/themode/minestom/event/PlayerCommandEvent.java create mode 100644 src/main/java/fr/themode/minestom/listener/RecipeListener.java create mode 100644 src/main/java/fr/themode/minestom/net/packet/client/play/ClientCraftRecipeRequest.java create mode 100644 src/main/java/fr/themode/minestom/net/packet/server/play/CraftRecipeResponse.java create mode 100644 src/main/java/fr/themode/minestom/net/packet/server/play/PluginMessagePacket.java diff --git a/build.gradle b/build.gradle index d63424e23..81b7b9807 100644 --- a/build.gradle +++ b/build.gradle @@ -11,7 +11,6 @@ sourceCompatibility = 1.11 repositories { mavenCentral() maven { url 'https://jitpack.io'} - maven { url "https://libraries.minecraft.net"} } @@ -36,6 +35,7 @@ dependencies { implementation 'com.github.LynnOwens:starlite:9971b899f7' // https://mvnrepository.com/artifact/com.google.code.gson/gson implementation group: 'com.google.code.gson', name: 'gson', version: '2.8.5' - compile 'com.mojang:brigadier:1.0.17' + + implementation 'com.github.TheMode:CommandBuilder:e70e2bd6b7' } diff --git a/src/main/java/fr/themode/demo/Main.java b/src/main/java/fr/themode/demo/Main.java index adb0f513f..bbb61e152 100644 --- a/src/main/java/fr/themode/demo/Main.java +++ b/src/main/java/fr/themode/demo/Main.java @@ -1,13 +1,14 @@ package fr.themode.demo; -import com.mojang.brigadier.CommandDispatcher; import fr.themode.demo.blocks.StoneBlock; import fr.themode.demo.blocks.UpdatableBlockDemo; +import fr.themode.demo.commands.HealthCommand; +import fr.themode.demo.commands.SimpleCommand; import fr.themode.minestom.MinecraftServer; import fr.themode.minestom.command.CommandManager; -import fr.themode.minestom.entity.Player; import fr.themode.minestom.instance.block.BlockManager; import fr.themode.minestom.item.ItemStack; +import fr.themode.minestom.item.Material; import fr.themode.minestom.net.packet.server.play.DeclareRecipesPacket; import fr.themode.minestom.recipe.RecipeManager; import fr.themode.minestom.recipe.ShapelessRecipe; @@ -23,14 +24,14 @@ public class Main { blockManager.registerCustomBlock(new UpdatableBlockDemo()); CommandManager commandManager = MinecraftServer.getCommandManager(); - CommandDispatcher dispatcher = commandManager.getDispatcher(); - // TODO register command + commandManager.register(new HealthCommand()); + commandManager.register(new SimpleCommand()); RecipeManager recipeManager = MinecraftServer.getRecipeManager(); ShapelessRecipe shapelessRecipe = new ShapelessRecipe("test", "groupname"); - shapelessRecipe.setResult(new ItemStack(50, (byte) 1)); + shapelessRecipe.setResult(new ItemStack(Material.STONE, (byte) 1)); DeclareRecipesPacket.Ingredient ingredient = new DeclareRecipesPacket.Ingredient(); - ingredient.items = new ItemStack[]{new ItemStack(2, (byte) 3)}; + ingredient.items = new ItemStack[]{new ItemStack(Material.STONE, (byte) 3)}; shapelessRecipe.addIngredient(ingredient); recipeManager.addRecipe(shapelessRecipe); diff --git a/src/main/java/fr/themode/demo/PlayerInit.java b/src/main/java/fr/themode/demo/PlayerInit.java index 252386302..2e405b457 100644 --- a/src/main/java/fr/themode/demo/PlayerInit.java +++ b/src/main/java/fr/themode/demo/PlayerInit.java @@ -3,6 +3,7 @@ package fr.themode.demo; import fr.themode.demo.entity.ChickenCreature; import fr.themode.demo.generator.ChunkGeneratorDemo; import fr.themode.minestom.MinecraftServer; +import fr.themode.minestom.command.CommandManager; import fr.themode.minestom.entity.Entity; import fr.themode.minestom.entity.EntityCreature; import fr.themode.minestom.entity.GameMode; @@ -50,7 +51,7 @@ public class PlayerInit { Vector velocity = player.getPosition().clone().getDirection().multiply(4); velocity.setY(3.5f); target.setVelocity(velocity, 150); - target.damage(2); + target.damage(1); player.sendMessage("ATTACK"); } }); @@ -69,8 +70,13 @@ public class PlayerInit { }); - player.setEventCallback(PlayerUseItemEvent.class, event -> { - System.out.println("CALLBACK EVENT"); + player.setEventCallback(PlayerChatEvent.class, event -> { + String message = event.getMessage(); + System.out.println("Chat: " + message); + CommandManager commandManager = MinecraftServer.getCommandManager(); + boolean result = commandManager.execute(event.getSender(), message); + if (!result) + player.sendMessage("No command found"); }); player.setEventCallback(PickupItemEvent.class, event -> { diff --git a/src/main/java/fr/themode/demo/commands/HealthCommand.java b/src/main/java/fr/themode/demo/commands/HealthCommand.java new file mode 100644 index 000000000..732a6000d --- /dev/null +++ b/src/main/java/fr/themode/demo/commands/HealthCommand.java @@ -0,0 +1,78 @@ +package fr.themode.demo.commands; + +import fr.themode.command.Arguments; +import fr.themode.command.Command; +import fr.themode.command.arguments.Argument; +import fr.themode.command.arguments.ArgumentType; +import fr.themode.command.arguments.number.ArgumentNumber; +import fr.themode.minestom.entity.Player; + +public class HealthCommand extends Command { + + public HealthCommand() { + super("health", "h", "healthbar"); + + setCondition(this::condition); + + setDefaultExecutor(this::defaultExecutor); + + Argument arg0 = ArgumentType.Word("mode").from("set", "add"); + + Argument arg1 = ArgumentType.Integer("value").between(0, 100); + + addCallback(this::modeCallback, arg0); + addCallback(this::valueCallback, arg1); + + addSyntax(this::execute, arg0); + addSyntax(this::execute2, arg0, arg1); + } + + private boolean condition(Player player) { + // Your custom condition, called no matter the syntax used + boolean hasPerm = true; + if (!hasPerm) { + player.sendMessage("You do not have permission !"); + return false; + } + return true; + } + + private void defaultExecutor(Player player, Arguments args) { + player.sendMessage("Correct usage: health [set/add] [number]"); + } + + private void modeCallback(Player player, String value, int error) { + System.out.println("SYNTAX ERROR: '" + value + "' should be replaced by 'set' or 'add'"); + } + + private void valueCallback(Player player, String value, int error) { + switch (error) { + case ArgumentNumber.NOT_NUMBER_ERROR: + player.sendMessage("SYNTAX ERROR: '" + value + "' isn't a number!"); + break; + case ArgumentNumber.RANGE_ERROR: + player.sendMessage("SYNTAX ERROR: " + value + " is not between 0 and 100"); + break; + } + } + + private void execute(Player player, Arguments args) { + player.sendMessage("/health " + args.getWord("mode") + " [Integer]"); + } + + private void execute2(Player player, Arguments args) { + String mode = args.getWord("mode"); + int value = args.getInteger("value"); + + switch (mode.toLowerCase()) { + case "set": + player.setHealth(value); + break; + case "add": + player.setHealth(player.getHealth() + value); + break; + } + player.sendMessage("You have now " + player.getHealth() + " health"); + } + +} \ No newline at end of file diff --git a/src/main/java/fr/themode/demo/commands/SimpleCommand.java b/src/main/java/fr/themode/demo/commands/SimpleCommand.java new file mode 100644 index 000000000..d326148a4 --- /dev/null +++ b/src/main/java/fr/themode/demo/commands/SimpleCommand.java @@ -0,0 +1,17 @@ +package fr.themode.demo.commands; + +import fr.themode.minestom.command.CommandProcessor; +import fr.themode.minestom.entity.Player; + +public class SimpleCommand implements CommandProcessor { + @Override + public String getCommandName() { + return "test"; + } + + @Override + public boolean process(Player player, String command, String[] args) { + player.sendMessage("You tried the sample command!"); + return true; + } +} diff --git a/src/main/java/fr/themode/minestom/command/CommandManager.java b/src/main/java/fr/themode/minestom/command/CommandManager.java new file mode 100644 index 000000000..64f56359e --- /dev/null +++ b/src/main/java/fr/themode/minestom/command/CommandManager.java @@ -0,0 +1,170 @@ +package fr.themode.minestom.command; + +import fr.themode.command.Command; +import fr.themode.command.CommandDispatcher; +import fr.themode.command.CommandSyntax; +import fr.themode.command.arguments.*; +import fr.themode.command.arguments.number.ArgumentDouble; +import fr.themode.command.arguments.number.ArgumentFloat; +import fr.themode.command.arguments.number.ArgumentInteger; +import fr.themode.minestom.entity.Player; +import fr.themode.minestom.net.packet.server.play.DeclareCommandsPacket; +import fr.themode.minestom.utils.ArrayUtils; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class CommandManager { + + private String commandPrefix = "/"; + + private CommandDispatcher dispatcher = new CommandDispatcher<>(); + private Map commandProcessorMap = new HashMap<>(); + + private DeclareCommandsPacket declareCommandsPacket = new DeclareCommandsPacket(); + + public void register(Command command) { + this.dispatcher.register(command); + } + + public void register(CommandProcessor commandProcessor) { + this.commandProcessorMap.put(commandProcessor.getCommandName().toLowerCase(), commandProcessor); + } + + public boolean execute(Player source, String command) { + if (source == null) + throw new NullPointerException("Source cannot be null"); + if (command == null) + throw new NullPointerException("Command string cannot be null"); + + try { + this.dispatcher.execute(source, command); + return true; + } catch (NullPointerException e) { + String[] splitted = command.split(" "); + String commandName = splitted[0]; + CommandProcessor commandProcessor = commandProcessorMap.get(commandName.toLowerCase()); + if (commandProcessor == null) + return false; + + String[] args = command.substring(command.indexOf(" ") + 1).split(" "); + + return commandProcessor.process(source, commandName, args); + + } + } + + public String getCommandPrefix() { + return commandPrefix; + } + + public void setCommandPrefix(String commandPrefix) { + this.commandPrefix = commandPrefix; + } + + public DeclareCommandsPacket getDeclareCommandsPacket() { + return declareCommandsPacket; + } + + private void refreshPacket() { + + List nodes = new ArrayList<>(); + ArrayList rootChildren = new ArrayList<>(); + + for (Command command : dispatcher.getCommands()) { + ArrayList cmdChildren = new ArrayList<>(); + + String name = command.getName(); + + DeclareCommandsPacket.Node literalNode = new DeclareCommandsPacket.Node(); + literalNode.flags = 0b1; + literalNode.name = name; + + rootChildren.add(nodes.size()); + nodes.add(literalNode); + + for (CommandSyntax syntax : command.getSyntaxes()) { + ArrayList argChildren = cmdChildren; + + for (Argument argument : syntax.getArguments()) { + + DeclareCommandsPacket.Node argumentNode = toNode(argument); + + argChildren.add(nodes.size()); + nodes.add(argumentNode); + System.out.println("size: " + argChildren.size()); + argumentNode.children = ArrayUtils.toArray(argChildren); + argChildren = new ArrayList<>(); + } + + } + System.out.println("test " + cmdChildren.size() + " : " + cmdChildren.get(0)); + literalNode.children = ArrayUtils.toArray(cmdChildren); + + } + + + DeclareCommandsPacket.Node rootNode = new DeclareCommandsPacket.Node(); + rootNode.flags = 0; + rootNode.children = ArrayUtils.toArray(rootChildren); + + nodes.add(rootNode); + + declareCommandsPacket.nodes = nodes.toArray(new DeclareCommandsPacket.Node[nodes.size()]); + declareCommandsPacket.rootIndex = nodes.size() - 1; + } + + private DeclareCommandsPacket.Node toNode(Argument argument) { + DeclareCommandsPacket.Node argumentNode = new DeclareCommandsPacket.Node(); + argumentNode.flags = 0b1010; + argumentNode.name = argument.getId(); + + if (argument instanceof ArgumentBoolean) { + argumentNode.parser = "brigadier:bool"; + argumentNode.properties = packetWriter -> packetWriter.writeByte((byte) 0); + } else if (argument instanceof ArgumentDouble) { + ArgumentDouble argumentDouble = (ArgumentDouble) argument; + argumentNode.parser = "brigadier:double"; + argumentNode.properties = packetWriter -> { + packetWriter.writeByte((byte) 0b11); + packetWriter.writeDouble(argumentDouble.min); + packetWriter.writeDouble(argumentDouble.max); + }; + } else if (argument instanceof ArgumentFloat) { + ArgumentFloat argumentFloat = (ArgumentFloat) argument; + argumentNode.parser = "brigadier:float"; + argumentNode.properties = packetWriter -> { + packetWriter.writeByte((byte) 0b11); + packetWriter.writeFloat(argumentFloat.min); + packetWriter.writeFloat(argumentFloat.max); + }; + } else if (argument instanceof ArgumentInteger) { + ArgumentInteger argumentInteger = (ArgumentInteger) argument; + argumentNode.parser = "brigadier:integer"; + argumentNode.properties = packetWriter -> { + packetWriter.writeByte((byte) 0b11); + packetWriter.writeInt(argumentInteger.min); + packetWriter.writeInt(argumentInteger.max); + }; + } else if (argument instanceof ArgumentWord) { + argumentNode.parser = "brigadier:string"; + argumentNode.properties = packetWriter -> { + packetWriter.writeVarInt(0); // Single word + }; + } else if (argument instanceof ArgumentString) { + argumentNode.parser = "brigadier:string"; + argumentNode.properties = packetWriter -> { + packetWriter.writeVarInt(1); // Quotable phrase + }; + } else if (argument instanceof ArgumentStringArray) { + argumentNode.parser = "brigadier:string"; + argumentNode.properties = packetWriter -> { + packetWriter.writeVarInt(2); // Greedy phrase + }; + } + + return argumentNode; + } +} diff --git a/src/main/java/fr/themode/minestom/command/CommandProcessor.java b/src/main/java/fr/themode/minestom/command/CommandProcessor.java new file mode 100644 index 000000000..79a4f8bb8 --- /dev/null +++ b/src/main/java/fr/themode/minestom/command/CommandProcessor.java @@ -0,0 +1,10 @@ +package fr.themode.minestom.command; + +import fr.themode.minestom.entity.Player; + +public interface CommandProcessor { + + String getCommandName(); + + boolean process(Player player, String command, String[] args); +} diff --git a/src/main/java/fr/themode/minestom/entity/EntityCreature.java b/src/main/java/fr/themode/minestom/entity/EntityCreature.java index 7100746c5..994924d1a 100644 --- a/src/main/java/fr/themode/minestom/entity/EntityCreature.java +++ b/src/main/java/fr/themode/minestom/entity/EntityCreature.java @@ -1,6 +1,5 @@ package fr.themode.minestom.entity; -import fr.themode.minestom.event.DeathEvent; import fr.themode.minestom.net.packet.server.play.*; import fr.themode.minestom.net.player.PlayerConnection; import fr.themode.minestom.utils.ChunkUtils; @@ -83,11 +82,10 @@ public abstract class EntityCreature extends LivingEntity { @Override public void kill() { - this.isDead = true; // So the entity isn't killed over and over again - triggerStatus((byte) 3); // Start death animation status - scheduleRemove(1000); // Needed for proper death animation (wait for it to finish before destroying the entity) - DeathEvent deathEvent = new DeathEvent(); - callEvent(DeathEvent.class, deathEvent); + super.kill(); + + // Needed for proper death animation (wait for it to finish before destroying the entity) + scheduleRemove(1000); } @Override diff --git a/src/main/java/fr/themode/minestom/entity/LivingEntity.java b/src/main/java/fr/themode/minestom/entity/LivingEntity.java index 2f8a85dbc..c84af996a 100644 --- a/src/main/java/fr/themode/minestom/entity/LivingEntity.java +++ b/src/main/java/fr/themode/minestom/entity/LivingEntity.java @@ -3,6 +3,7 @@ package fr.themode.minestom.entity; import com.github.simplenet.packet.Packet; import fr.themode.minestom.collision.BoundingBox; import fr.themode.minestom.entity.property.Attribute; +import fr.themode.minestom.event.DeathEvent; import fr.themode.minestom.event.PickupItemEvent; import fr.themode.minestom.instance.Chunk; import fr.themode.minestom.item.ItemStack; @@ -40,7 +41,14 @@ public abstract class LivingEntity extends Entity { this(entityType, new Position()); } - public abstract void kill(); + public void kill() { + System.out.println("KILL"); + this.isDead = true; // So the entity isn't killed over and over again + setHealth(0); + triggerStatus((byte) 3); // Start death animation status + DeathEvent deathEvent = new DeathEvent(); + callEvent(DeathEvent.class, deathEvent); + } @Override public void update() { @@ -111,7 +119,7 @@ public abstract class LivingEntity extends Entity { health = Math.min(health, getMaxHealth()); this.health = health; - if (this.health <= 0) { + if (this.health <= 0 && !isDead) { kill(); } } diff --git a/src/main/java/fr/themode/minestom/entity/Player.java b/src/main/java/fr/themode/minestom/entity/Player.java index 62797aa26..bd03c9710 100644 --- a/src/main/java/fr/themode/minestom/entity/Player.java +++ b/src/main/java/fr/themode/minestom/entity/Player.java @@ -93,6 +93,8 @@ public class Player extends LivingEntity { playerConnection.sendPacket(getPropertiesPacket()); // Send default properties refreshHealth(); + refreshAbilities(); + this.settings = new PlayerSettings(); this.inventory = new PlayerInventory(this); @@ -333,14 +335,8 @@ public class Player extends LivingEntity { @Override public void kill() { - this.isDead = true; + super.kill(); refreshIsDead(true); - EntityStatusPacket entityStatusPacket = new EntityStatusPacket(); - entityStatusPacket.entityId = getEntityId(); - entityStatusPacket.status = 3; // Death sound/animation - sendPacketToViewers(entityStatusPacket); - DeathEvent deathEvent = new DeathEvent(); - callEvent(DeathEvent.class, deathEvent); } public void sendBlockBreakAnimation(BlockPosition blockPosition, byte destroyStage) { diff --git a/src/main/java/fr/themode/minestom/event/PlayerCommandEvent.java b/src/main/java/fr/themode/minestom/event/PlayerCommandEvent.java new file mode 100644 index 000000000..23df78fc2 --- /dev/null +++ b/src/main/java/fr/themode/minestom/event/PlayerCommandEvent.java @@ -0,0 +1,26 @@ +package fr.themode.minestom.event; + +import fr.themode.minestom.entity.Player; + +public class PlayerCommandEvent extends CancellableEvent { + + private Player player; + private String command; + + public PlayerCommandEvent(Player player, String command) { + this.player = player; + this.command = command; + } + + public Player getPlayer() { + return player; + } + + public String getCommand() { + return command; + } + + public void setCommand(String command) { + this.command = command; + } +} diff --git a/src/main/java/fr/themode/minestom/listener/ChatMessageListener.java b/src/main/java/fr/themode/minestom/listener/ChatMessageListener.java index 621ec0664..41ff74fc2 100644 --- a/src/main/java/fr/themode/minestom/listener/ChatMessageListener.java +++ b/src/main/java/fr/themode/minestom/listener/ChatMessageListener.java @@ -3,8 +3,10 @@ package fr.themode.minestom.listener; import club.thectm.minecraft.text.*; import fr.themode.minestom.MinecraftServer; import fr.themode.minestom.chat.Chat; +import fr.themode.minestom.command.CommandManager; import fr.themode.minestom.entity.Player; import fr.themode.minestom.event.PlayerChatEvent; +import fr.themode.minestom.event.PlayerCommandEvent; import fr.themode.minestom.net.packet.client.play.ClientChatMessagePacket; import java.util.function.Function; @@ -14,6 +16,22 @@ public class ChatMessageListener { public static void listener(ClientChatMessagePacket packet, Player player) { String message = Chat.uncoloredLegacyText(packet.message); + CommandManager commandManager = MinecraftServer.getCommandManager(); + String cmdPrefix = commandManager.getCommandPrefix(); + if (message.startsWith(cmdPrefix)) { + // The message is a command + message = message.replaceFirst(cmdPrefix, ""); + + PlayerCommandEvent playerCommandEvent = new PlayerCommandEvent(player, message); + player.callCancellableEvent(PlayerCommandEvent.class, playerCommandEvent, () -> { + commandManager.execute(player, playerCommandEvent.getCommand()); + }); + + // Do not call chat event + return; + } + + PlayerChatEvent playerChatEvent = new PlayerChatEvent(player, MinecraftServer.getConnectionManager().getOnlinePlayers(), message); // Default format diff --git a/src/main/java/fr/themode/minestom/listener/RecipeListener.java b/src/main/java/fr/themode/minestom/listener/RecipeListener.java new file mode 100644 index 000000000..0501942b3 --- /dev/null +++ b/src/main/java/fr/themode/minestom/listener/RecipeListener.java @@ -0,0 +1,15 @@ +package fr.themode.minestom.listener; + +import fr.themode.minestom.entity.Player; +import fr.themode.minestom.net.packet.client.play.ClientCraftRecipeRequest; +import fr.themode.minestom.net.packet.server.play.CraftRecipeResponse; + +public class RecipeListener { + + public static void listener(ClientCraftRecipeRequest packet, Player player) { + CraftRecipeResponse recipeResponse = new CraftRecipeResponse(); + recipeResponse.windowId = packet.windowId; + recipeResponse.recipe = packet.recipe; + player.getPlayerConnection().sendPacket(recipeResponse); + } +} diff --git a/src/main/java/fr/themode/minestom/listener/manager/PacketListenerManager.java b/src/main/java/fr/themode/minestom/listener/manager/PacketListenerManager.java index 80980ea6c..848884d24 100644 --- a/src/main/java/fr/themode/minestom/listener/manager/PacketListenerManager.java +++ b/src/main/java/fr/themode/minestom/listener/manager/PacketListenerManager.java @@ -33,6 +33,7 @@ public class PacketListenerManager { addListener(ClientStatusPacket.class, StatusListener::listener); addListener(ClientSettingsPacket.class, SettingsListener::listener); addListener(ClientCreativeInventoryActionPacket.class, CreativeInventoryActionListener::listener); + addListener(ClientCraftRecipeRequest.class, RecipeListener::listener); } public void process(T packet, Player player) { diff --git a/src/main/java/fr/themode/minestom/net/packet/client/handler/ClientPlayPacketsHandler.java b/src/main/java/fr/themode/minestom/net/packet/client/handler/ClientPlayPacketsHandler.java index b9b93d5d3..e6fdb5ace 100644 --- a/src/main/java/fr/themode/minestom/net/packet/client/handler/ClientPlayPacketsHandler.java +++ b/src/main/java/fr/themode/minestom/net/packet/client/handler/ClientPlayPacketsHandler.java @@ -21,6 +21,7 @@ public class ClientPlayPacketsHandler extends ClientPacketsHandler { register(0x12, ClientPlayerPositionAndLookPacket.class); register(0x13, ClientPlayerLookPacket.class); register(0x14, ClientPlayerPacket.class); + register(0x18, ClientCraftRecipeRequest.class); register(0x19, ClientPlayerAbilitiesPacket.class); register(0x1A, ClientPlayerDiggingPacket.class); register(0x1B, ClientEntityActionPacket.class); diff --git a/src/main/java/fr/themode/minestom/net/packet/client/login/LoginStartPacket.java b/src/main/java/fr/themode/minestom/net/packet/client/login/LoginStartPacket.java index c6906de89..e66daba6b 100644 --- a/src/main/java/fr/themode/minestom/net/packet/client/login/LoginStartPacket.java +++ b/src/main/java/fr/themode/minestom/net/packet/client/login/LoginStartPacket.java @@ -1,6 +1,5 @@ package fr.themode.minestom.net.packet.client.login; -import com.mojang.brigadier.CommandDispatcher; import fr.themode.minestom.MinecraftServer; import fr.themode.minestom.command.CommandManager; import fr.themode.minestom.entity.GameMode; @@ -74,8 +73,6 @@ public class LoginStartPacket implements ClientPreplayPacket { // TODO send server difficulty - // TODO player abilities - SpawnPositionPacket spawnPositionPacket = new SpawnPositionPacket(); spawnPositionPacket.x = 0; @@ -99,35 +96,13 @@ public class LoginStartPacket implements ClientPreplayPacket { { CommandManager commandManager = MinecraftServer.getCommandManager(); - CommandDispatcher dispatcher = commandManager.getDispatcher(); - String[] usages = dispatcher.getAllUsage(dispatcher.getRoot(), player, true); - for (String usage : usages) { - System.out.println("USAGE: " + usage); - } + DeclareCommandsPacket declareCommandsPacket = commandManager.getDeclareCommandsPacket(); + + // FIXME + //connection.sendPacket(declareCommandsPacket); } - DeclareCommandsPacket declareCommandsPacket = new DeclareCommandsPacket(); - DeclareCommandsPacket.Node argumentNode = new DeclareCommandsPacket.Node(); - argumentNode.flags = 0b1010; - argumentNode.children = new int[0]; - argumentNode.name = "arg name"; - argumentNode.parser = "minecraft:nbt_path"; - DeclareCommandsPacket.Node literalNode = new DeclareCommandsPacket.Node(); - literalNode.flags = 0b1; - literalNode.children = new int[]{2}; - literalNode.name = "hey"; - DeclareCommandsPacket.Node rootNode = new DeclareCommandsPacket.Node(); - rootNode.flags = 0; - rootNode.children = new int[]{1}; - - declareCommandsPacket.nodes = new DeclareCommandsPacket.Node[]{rootNode, literalNode, argumentNode}; - declareCommandsPacket.rootIndex = 0; - - - connection.sendPacket(declareCommandsPacket); - - { RecipeManager recipeManager = MinecraftServer.getRecipeManager(); DeclareRecipesPacket declareRecipesPacket = recipeManager.getDeclareRecipesPacket(); diff --git a/src/main/java/fr/themode/minestom/net/packet/client/play/ClientCraftRecipeRequest.java b/src/main/java/fr/themode/minestom/net/packet/client/play/ClientCraftRecipeRequest.java new file mode 100644 index 000000000..2b498a95a --- /dev/null +++ b/src/main/java/fr/themode/minestom/net/packet/client/play/ClientCraftRecipeRequest.java @@ -0,0 +1,21 @@ +package fr.themode.minestom.net.packet.client.play; + +import fr.themode.minestom.net.packet.PacketReader; +import fr.themode.minestom.net.packet.client.ClientPlayPacket; + +public class ClientCraftRecipeRequest extends ClientPlayPacket { + + public byte windowId; + public String recipe; + public boolean makeAll; + + @Override + public void read(PacketReader reader, Runnable callback) { + reader.readByte(value -> windowId = value); + reader.readSizedString((string, length) -> recipe = string); + reader.readBoolean(value -> { + makeAll = value; + callback.run(); + }); + } +} diff --git a/src/main/java/fr/themode/minestom/net/packet/server/play/CraftRecipeResponse.java b/src/main/java/fr/themode/minestom/net/packet/server/play/CraftRecipeResponse.java new file mode 100644 index 000000000..a54493cb0 --- /dev/null +++ b/src/main/java/fr/themode/minestom/net/packet/server/play/CraftRecipeResponse.java @@ -0,0 +1,22 @@ +package fr.themode.minestom.net.packet.server.play; + +import fr.themode.minestom.net.packet.PacketWriter; +import fr.themode.minestom.net.packet.server.ServerPacket; +import fr.themode.minestom.net.packet.server.ServerPacketIdentifier; + +public class CraftRecipeResponse implements ServerPacket { + + public byte windowId; + public String recipe; + + @Override + public void write(PacketWriter writer) { + writer.writeByte(windowId); + writer.writeSizedString(recipe); + } + + @Override + public int getId() { + return ServerPacketIdentifier.CRAFT_RECIPE_RESPONSE; + } +} diff --git a/src/main/java/fr/themode/minestom/net/packet/server/play/PluginMessagePacket.java b/src/main/java/fr/themode/minestom/net/packet/server/play/PluginMessagePacket.java new file mode 100644 index 000000000..fedc923f3 --- /dev/null +++ b/src/main/java/fr/themode/minestom/net/packet/server/play/PluginMessagePacket.java @@ -0,0 +1,22 @@ +package fr.themode.minestom.net.packet.server.play; + +import fr.themode.minestom.net.packet.PacketWriter; +import fr.themode.minestom.net.packet.server.ServerPacket; +import fr.themode.minestom.net.packet.server.ServerPacketIdentifier; + +public class PluginMessagePacket implements ServerPacket { + + public String channel; + public byte[] data; + + @Override + public void write(PacketWriter writer) { + writer.writeSizedString(channel); + writer.writeBytes(data); + } + + @Override + public int getId() { + return ServerPacketIdentifier.PLUGIN_MESSAGE; + } +} diff --git a/src/main/java/fr/themode/minestom/utils/ArrayUtils.java b/src/main/java/fr/themode/minestom/utils/ArrayUtils.java index 7b533f715..b4897464d 100644 --- a/src/main/java/fr/themode/minestom/utils/ArrayUtils.java +++ b/src/main/java/fr/themode/minestom/utils/ArrayUtils.java @@ -1,5 +1,7 @@ package fr.themode.minestom.utils; +import java.util.ArrayList; + public class ArrayUtils { public static byte[] concenateByteArrays(byte[]... arrays) { @@ -51,4 +53,12 @@ public class ArrayUtils { return result; } + public static int[] toArray(ArrayList list) { + int[] array = new int[list.size()]; + for (int i = 0; i < array.length; i++) { + array[i] = list.get(i); + } + return array; + } + }