From 57def5aaac7d6bbad2d19a90a41064cb8794bd0f Mon Sep 17 00:00:00 2001 From: TheMode Date: Sun, 18 Aug 2019 20:38:09 +0200 Subject: [PATCH] Update --- .../minestom/entity/EntityManager.java | 1 + .../fr/themode/minestom/entity/Player.java | 35 ++- .../fr/themode/minestom/instance/Block.java | 30 +- .../themode/minestom/instance/BlockBatch.java | 8 +- .../fr/themode/minestom/instance/Chunk.java | 12 +- .../themode/minestom/instance/Instance.java | 4 +- .../minestom/inventory/PlayerInventory.java | 262 +++++++++++++++++- .../packet/client/login/LoginStartPacket.java | 16 +- .../client/play/ClientChatMessagePacket.java | 4 +- .../client/play/ClientClickWindowPacket.java | 19 +- .../packet/client/play/ClientCloseWindow.java | 5 +- .../play/ClientHeldItemChangePacket.java | 2 +- .../ClientPlayerBlockPlacementPacket.java | 15 +- .../play/ClientPlayerDiggingPacket.java | 12 +- .../play/AcknowledgePlayerDiggingPacket.java | 28 ++ .../play/BlockBreakAnimationPacket.java | 25 ++ .../packet/server/play/ChunkDataPacket.java | 9 +- .../server/play/EntityEffectPacket.java | 28 ++ .../server/play/RemoveEntityEffectPacket.java | 22 ++ .../fr/themode/minestom/utils/Position.java | 5 + .../java/fr/themode/minestom/utils/Utils.java | 13 +- 21 files changed, 472 insertions(+), 83 deletions(-) create mode 100644 src/main/java/fr/themode/minestom/net/packet/server/play/AcknowledgePlayerDiggingPacket.java create mode 100644 src/main/java/fr/themode/minestom/net/packet/server/play/BlockBreakAnimationPacket.java create mode 100644 src/main/java/fr/themode/minestom/net/packet/server/play/EntityEffectPacket.java create mode 100644 src/main/java/fr/themode/minestom/net/packet/server/play/RemoveEntityEffectPacket.java diff --git a/src/main/java/fr/themode/minestom/entity/EntityManager.java b/src/main/java/fr/themode/minestom/entity/EntityManager.java index 56e13e460..922dafabc 100644 --- a/src/main/java/fr/themode/minestom/entity/EntityManager.java +++ b/src/main/java/fr/themode/minestom/entity/EntityManager.java @@ -16,6 +16,7 @@ public class EntityManager { public void update() { for (Instance instance : instanceManager.getInstances()) { + // TODO loop chunks and entities on it instead of individual (to have more non-blocking operation) // Creatures for (EntityCreature creature : instance.getCreatures()) { diff --git a/src/main/java/fr/themode/minestom/entity/Player.java b/src/main/java/fr/themode/minestom/entity/Player.java index 1741e9816..f6b2faf04 100644 --- a/src/main/java/fr/themode/minestom/entity/Player.java +++ b/src/main/java/fr/themode/minestom/entity/Player.java @@ -6,6 +6,7 @@ import fr.themode.minestom.inventory.PlayerInventory; import fr.themode.minestom.item.ItemStack; import fr.themode.minestom.net.packet.server.play.*; import fr.themode.minestom.net.player.PlayerConnection; +import fr.themode.minestom.utils.Position; import java.util.UUID; @@ -24,6 +25,9 @@ public class Player extends LivingEntity { private short heldSlot; private Inventory openInventory; + private Position targetBlockPosition; + private long targetBlockTime; + // TODO set proper UUID public Player(UUID uuid, String username, PlayerConnection playerConnection) { this.uuid = uuid; @@ -35,7 +39,26 @@ public class Player extends LivingEntity { @Override public void update() { - // System.out.println("Je suis l'update"); + + // Target block stage + if (instance != null && targetBlockPosition != null) { + int timeBreak = 750; // In ms + int animationCount = 10; + long since = System.currentTimeMillis() - targetBlockTime; + byte stage = (byte) (since / (timeBreak / animationCount)); + BlockBreakAnimationPacket breakAnimationPacket = new BlockBreakAnimationPacket(); + breakAnimationPacket.entityId = getEntityId() + 1; + breakAnimationPacket.blockPosition = targetBlockPosition; + breakAnimationPacket.destroyStage = stage; + if (stage > 9) { + instance.setBlock(targetBlockPosition.getX(), targetBlockPosition.getY(), targetBlockPosition.getZ(), (short) 0); + refreshTargetBlock(null); + } + playerConnection.sendPacket(breakAnimationPacket); // TODO send to all online players + } + + + // Multiplayer sync EntityTeleportPacket entityTeleportPacket = new EntityTeleportPacket(); entityTeleportPacket.entityId = getEntityId(); entityTeleportPacket.x = x; @@ -51,6 +74,11 @@ public class Player extends LivingEntity { playerConnection.sendPacket(new UpdateViewPositionPacket(Math.floorDiv((int) x, 16), Math.floorDiv((int) z, 16))); } + public void sendMessage(String message) { + ChatMessagePacket chatMessagePacket = new ChatMessagePacket("{\"text\": \"" + message + "\"}", ChatMessagePacket.Position.CHAT); + playerConnection.sendPacket(chatMessagePacket); + } + public void teleport(double x, double y, double z) { PlayerPositionAndLookPacket positionAndLookPacket = new PlayerPositionAndLookPacket(); positionAndLookPacket.x = x; @@ -172,6 +200,11 @@ public class Player extends LivingEntity { this.openInventory = openInventory; } + public void refreshTargetBlock(Position targetBlockPosition) { + this.targetBlockPosition = targetBlockPosition; + this.targetBlockTime = targetBlockPosition == null ? 0 : System.currentTimeMillis(); + } + public long getLastKeepAlive() { return lastKeepAlive; } diff --git a/src/main/java/fr/themode/minestom/instance/Block.java b/src/main/java/fr/themode/minestom/instance/Block.java index 7b9dc42d4..219e3d3a8 100644 --- a/src/main/java/fr/themode/minestom/instance/Block.java +++ b/src/main/java/fr/themode/minestom/instance/Block.java @@ -2,36 +2,22 @@ package fr.themode.minestom.instance; public class Block { - private short typeAndDamage; + private short type; - public Block(int type) { - this.typeAndDamage = (short) (type & 0x0FFF); - this.typeAndDamage |= (0 << 12) & 0xF000; + public Block(short type) { + this.type = type; } - public Block(int type, int damage) { - this.typeAndDamage = (short) (type & 0x0FFF); - this.typeAndDamage |= (damage << 12) & 0xF000; + public short getType() { + return type; } - public int getType() { - return typeAndDamage & 0x0FFF; - } - - public void setType(int type) { - this.typeAndDamage |= type & 0x0FFF; - } - - public int getDamage() { - return (typeAndDamage & 0xF000) >>> 12; - } - - public void setDamage(int damage) { - this.typeAndDamage |= (damage << 12) & 0xF000; + public void setType(short type) { + this.type = type; } @Override public String toString() { - return String.format("CustomBlock{type=%s, damage=%s}", getType(), getDamage()); + return String.format("CustomBlock{type=%s}", type); } } diff --git a/src/main/java/fr/themode/minestom/instance/BlockBatch.java b/src/main/java/fr/themode/minestom/instance/BlockBatch.java index f1a552211..f7ba906fd 100644 --- a/src/main/java/fr/themode/minestom/instance/BlockBatch.java +++ b/src/main/java/fr/themode/minestom/instance/BlockBatch.java @@ -19,7 +19,7 @@ public class BlockBatch { this.instance = instance; } - public synchronized void setBlock(int x, int y, int z, Block block) { + public synchronized void setBlock(int x, int y, int z, short blockId) { final int chunkX = Math.floorDiv(x, 16); final int chunkZ = Math.floorDiv(z, 16); Chunk chunk = this.instance.getChunk(chunkX, chunkZ); @@ -31,7 +31,7 @@ public class BlockBatch { data.x = x % 16; data.y = y; data.z = z % 16; - data.block = block; + data.blockId = blockId; blockData.add(data); @@ -56,10 +56,10 @@ public class BlockBatch { private class BlockData { private int x, y, z; - private Block block; + private short blockId; public void apply(Chunk chunk) { - chunk.setBlock(x, y, z, block); + chunk.setBlock(x, y, z, blockId); } } diff --git a/src/main/java/fr/themode/minestom/instance/Chunk.java b/src/main/java/fr/themode/minestom/instance/Chunk.java index e32033fe7..6c7f353c1 100644 --- a/src/main/java/fr/themode/minestom/instance/Chunk.java +++ b/src/main/java/fr/themode/minestom/instance/Chunk.java @@ -15,7 +15,7 @@ public class Chunk { protected Set players = new CopyOnWriteArraySet<>(); private int chunkX, chunkZ; private Biome biome; - private HashMap blocks = new HashMap<>(); + private HashMap blocks = new HashMap<>(); // Index/BlockID public Chunk(Biome biome, int chunkX, int chunkZ) { this.biome = biome; @@ -23,18 +23,18 @@ public class Chunk { this.chunkZ = chunkZ; } - protected void setBlock(int x, int y, int z, Block block) { + protected void setBlock(int x, int y, int z, short blockId) { short index = (short) (x & 0x000F); index |= (y << 4) & 0x0FF0; index |= (z << 12) & 0xF000; - this.blocks.put(index, block); + this.blocks.put(index, blockId); } - public Block getBlock(int x, int y, int z) { + public short getBlockId(int x, int y, int z) { short index = (short) (x & 0x000F); index |= (y << 4) & 0x0FF0; index |= (z << 12) & 0xF000; - return this.blocks.getOrDefault(index, new Block(0)); + return this.blocks.getOrDefault(index, (short) 0); } public void addEntity(Entity entity) { @@ -65,7 +65,7 @@ public class Chunk { } } - public HashMap getBlocks() { + public HashMap getBlocks() { return blocks; } diff --git a/src/main/java/fr/themode/minestom/instance/Instance.java b/src/main/java/fr/themode/minestom/instance/Instance.java index 77a9ac510..c38ee220a 100644 --- a/src/main/java/fr/themode/minestom/instance/Instance.java +++ b/src/main/java/fr/themode/minestom/instance/Instance.java @@ -26,7 +26,7 @@ public class Instance { } // TODO BlockBatch with pool - public synchronized void setBlock(int x, int y, int z, Block block) { + public synchronized void setBlock(int x, int y, int z, short blockId) { final int chunkX = Math.floorDiv(x, 16); final int chunkZ = Math.floorDiv(z, 16); Chunk chunk = getChunk(chunkX, chunkZ); @@ -34,7 +34,7 @@ public class Instance { chunk = createChunk(Biome.VOID, chunkX, chunkZ); } synchronized (chunk) { - chunk.setBlock(x % 16, y, z % 16, block); + chunk.setBlock(x % 16, y, z % 16, blockId); sendChunkUpdate(chunk); } } diff --git a/src/main/java/fr/themode/minestom/inventory/PlayerInventory.java b/src/main/java/fr/themode/minestom/inventory/PlayerInventory.java index 8432e7ae6..a0f8fb64e 100644 --- a/src/main/java/fr/themode/minestom/inventory/PlayerInventory.java +++ b/src/main/java/fr/themode/minestom/inventory/PlayerInventory.java @@ -8,10 +8,14 @@ import fr.themode.minestom.net.player.PlayerConnection; import java.util.Arrays; -public class PlayerInventory implements InventoryModifier { +public class PlayerInventory implements InventoryModifier, InventoryClickHandler { public static final int INVENTORY_SIZE = 46; + private static final byte ITEM_MAX_SIZE = 127; + + private static final int OFFSET = 9; + private static final int CRAFT_SLOT_1 = 36; private static final int CRAFT_SLOT_2 = 37; private static final int CRAFT_SLOT_3 = 38; @@ -25,6 +29,7 @@ public class PlayerInventory implements InventoryModifier { private Player player; private ItemStack[] items = new ItemStack[INVENTORY_SIZE]; + private ItemStack cursorItem = ItemStack.AIR_ITEM; public PlayerInventory(Player player) { this.player = player; @@ -56,15 +61,14 @@ public class PlayerInventory implements InventoryModifier { setItemStack(i, itemStack); return true; } else if (itemStack.isSimilar(item)) { - // TODO check max stack size int itemAmount = item.getAmount(); - if (itemAmount == 64) + if (itemAmount == ITEM_MAX_SIZE) continue; int totalAmount = itemStack.getAmount() + itemAmount; - if (totalAmount > 64) { - item.setAmount((byte) 64); + if (totalAmount > ITEM_MAX_SIZE) { + item.setAmount((byte) ITEM_MAX_SIZE); sendSlotRefresh((short) convertToPacketSlot(i), item); - itemStack.setAmount((byte) (totalAmount - 64)); + itemStack.setAmount((byte) (totalAmount - ITEM_MAX_SIZE)); } else { item.setAmount((byte) totalAmount); sendSlotRefresh((short) convertToPacketSlot(i), item); @@ -105,12 +109,25 @@ public class PlayerInventory implements InventoryModifier { playerConnection.sendPacket(createWindowItemsPacket()); } + public void refreshSlot(int slot) { + sendSlotRefresh((short) convertToPacketSlot(slot), getItemStack(slot)); + } + + public ItemStack getCursorItem() { + return cursorItem; + } + + public void setCursorItem(ItemStack cursorItem) { + this.cursorItem = cursorItem; + } + private void safeItemInsert(int slot, ItemStack itemStack) { synchronized (this) { itemStack = itemStack == null ? ItemStack.AIR_ITEM : itemStack; this.items[slot] = itemStack; - System.out.println("INSERT: " + slot); - sendSlotRefresh((short) slot, itemStack); + // System.out.println("INSERT: " + slot); + //sendSlotRefresh((short) slot, itemStack); + update(); } } @@ -126,6 +143,17 @@ public class PlayerInventory implements InventoryModifier { protected int convertSlot(int slot, int offset) { + switch (slot) { + case 1: + return CRAFT_SLOT_1 + 1; + case 2: + return CRAFT_SLOT_2 + 1; + case 3: + return CRAFT_SLOT_3 + 1; + case 4: + return CRAFT_SLOT_4 + 1; + } + //System.out.println("ENTRY: " + slot + " | " + offset); final int rowSize = 9; slot -= offset; if (slot >= rowSize * 3 && slot < rowSize * 4) { @@ -133,6 +161,7 @@ public class PlayerInventory implements InventoryModifier { } else { slot = slot + rowSize; } + //System.out.println("CONVERT: " + slot); return slot; } @@ -161,7 +190,6 @@ public class PlayerInventory implements InventoryModifier { private WindowItemsPacket createWindowItemsPacket() { ItemStack[] convertedSlots = new ItemStack[INVENTORY_SIZE]; - Arrays.fill(convertedSlots, ItemStack.AIR_ITEM); // TODO armor and craft for (int i = 0; i < items.length; i++) { int slot = convertToPacketSlot(i); @@ -175,4 +203,220 @@ public class PlayerInventory implements InventoryModifier { return windowItemsPacket; } + @Override + public void leftClick(Player player, int slot) { + ItemStack cursorItem = getCursorItem(); + ItemStack clicked = getItemStack(convertSlot(slot, OFFSET)); + + if (!cursorItem.isAir()) { + if (slot == 0 || slot == 6 || slot == 7 || slot == 8) { + return; // Disable putting item on CRAFTING_RESULT and chestplate/leggings/boots slots + } + } + + if (cursorItem.isAir() && clicked.isAir()) + return; + + ItemStack resultCursor; + ItemStack resultClicked; + + if (cursorItem.isSimilar(clicked)) { + resultCursor = cursorItem.clone(); + resultClicked = clicked.clone(); + int totalAmount = cursorItem.getAmount() + clicked.getAmount(); + if (totalAmount > ITEM_MAX_SIZE) { + resultCursor.setAmount((byte) (totalAmount - ITEM_MAX_SIZE)); + resultClicked.setAmount((byte) ITEM_MAX_SIZE); + } else { + resultCursor = ItemStack.AIR_ITEM; + resultClicked.setAmount((byte) totalAmount); + } + } else { + resultCursor = clicked.clone(); + resultClicked = cursorItem.clone(); + } + + setItemStack(slot, OFFSET, resultClicked); + setCursorItem(resultCursor); + } + + @Override + public void rightClick(Player player, int slot) { + ItemStack cursorItem = getCursorItem(); + ItemStack clicked = getItemStack(slot, OFFSET); + + if (!cursorItem.isAir()) { + if (slot == 0 || slot == 6 || slot == 7 || slot == 8) { + return; // Disable putting item on CRAFTING_RESULT and chestplate/leggings/boots slots + } + } + + if (cursorItem.isAir() && clicked.isAir()) + return; + + ItemStack resultCursor; + ItemStack resultClicked; + + if (cursorItem.isSimilar(clicked)) { + resultClicked = clicked.clone(); + int amount = clicked.getAmount() + 1; + if (amount > ITEM_MAX_SIZE) { + return; + } else { + resultCursor = cursorItem.clone(); + resultCursor.setAmount((byte) (resultCursor.getAmount() - 1)); + if (resultCursor.getAmount() < 1) + resultCursor = ItemStack.AIR_ITEM; + resultClicked.setAmount((byte) amount); + } + } else { + if (cursorItem.isAir()) { + int amount = (int) Math.ceil((double) clicked.getAmount() / 2d); + resultCursor = clicked.clone(); + resultCursor.setAmount((byte) amount); + resultClicked = clicked.clone(); + resultClicked.setAmount((byte) (clicked.getAmount() / 2)); + } else { + if (clicked.isAir()) { + int amount = cursorItem.getAmount(); + resultCursor = cursorItem.clone(); + resultCursor.setAmount((byte) (amount - 1)); + if (resultCursor.getAmount() < 1) + resultCursor = ItemStack.AIR_ITEM; + resultClicked = cursorItem.clone(); + resultClicked.setAmount((byte) 1); + } else { + resultCursor = clicked.clone(); + resultClicked = cursorItem.clone(); + } + } + } + + setItemStack(slot, OFFSET, resultClicked); + setCursorItem(resultCursor); + } + + @Override + public void shiftClick(Player player, int slot) { + ItemStack clicked = getItemStack(slot, OFFSET); + + if (clicked.isAir()) + return; + + ItemStack resultClicked = clicked.clone(); + boolean filled = false; + for (int i = 0; i < items.length; i++) { + int index = i < 9 ? i + 9 : i - 9; + ItemStack item = items[index]; + if (item.isSimilar(clicked)) { + int amount = item.getAmount(); + if (amount == ITEM_MAX_SIZE) + continue; + int totalAmount = resultClicked.getAmount() + amount; + if (totalAmount > ITEM_MAX_SIZE) { + item.setAmount((byte) ITEM_MAX_SIZE); + setItemStack(index, item); + resultClicked.setAmount((byte) (totalAmount - ITEM_MAX_SIZE)); + filled = false; + continue; + } else { + resultClicked.setAmount((byte) totalAmount); + setItemStack(index, resultClicked); + setItemStack(slot, OFFSET, ItemStack.AIR_ITEM); + filled = true; + break; + } + } else if (item.isAir()) { + // Switch + setItemStack(index, resultClicked); + setItemStack(slot, OFFSET, ItemStack.AIR_ITEM); + filled = true; + break; + } + } + if (!filled) { + setItemStack(slot, OFFSET, resultClicked); + } + } + + @Override + public void changeHeld(Player player, int slot, int key) { + if (!getCursorItem().isAir()) + return; + + ItemStack heldItem = getItemStack(key); + ItemStack clicked = getItemStack(slot, OFFSET); + + ItemStack resultClicked; + ItemStack resultHeld; + + if (clicked.isAir()) { + // Set held item [key] to slot + resultClicked = ItemStack.AIR_ITEM; + resultHeld = clicked.clone(); + } else { + if (heldItem.isAir()) { + // if held item [key] is air then set clicked to held + resultClicked = ItemStack.AIR_ITEM; + resultHeld = clicked.clone(); + } else { + // Otherwise replace held item and held + resultClicked = heldItem.clone(); + resultHeld = clicked.clone(); + } + } + + setItemStack(slot, OFFSET, resultClicked); + setItemStack(key, resultHeld); + } + + @Override + public void middleClick(Player player, int slot) { + + } + + @Override + public void dropOne(Player player, int slot) { + + } + + @Override + public void dropItemStack(Player player, int slot) { + + } + + @Override + public void doubleClick(Player player, int slot) { + ItemStack cursorItem = getCursorItem().clone(); + if (cursorItem.isAir()) + return; + + int amount = cursorItem.getAmount(); + + if (amount == ITEM_MAX_SIZE) + return; + + for (int i = 0; i < items.length; i++) { + int index = i < 9 ? i + 9 : i - 9; + if (index == slot) + continue; + if (amount == ITEM_MAX_SIZE) + break; + ItemStack item = items[index]; + if (cursorItem.isSimilar(item)) { + int totalAmount = amount + item.getAmount(); + if (totalAmount > ITEM_MAX_SIZE) { + cursorItem.setAmount((byte) ITEM_MAX_SIZE); + item.setAmount((byte) (totalAmount - ITEM_MAX_SIZE)); + setItemStack(index, item); + } else { + cursorItem.setAmount((byte) totalAmount); + setItemStack(index, ItemStack.AIR_ITEM); + } + amount = cursorItem.getAmount(); + } + } + + setCursorItem(cursorItem); + } } 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 d93484ef5..4af48a6aa 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 @@ -5,7 +5,6 @@ import fr.themode.minestom.Main; import fr.themode.minestom.entity.GameMode; import fr.themode.minestom.entity.Player; import fr.themode.minestom.entity.demo.ChickenCreature; -import fr.themode.minestom.instance.Block; import fr.themode.minestom.instance.Instance; import fr.themode.minestom.inventory.Inventory; import fr.themode.minestom.inventory.InventoryType; @@ -16,10 +15,7 @@ import fr.themode.minestom.net.ConnectionState; import fr.themode.minestom.net.packet.client.ClientPreplayPacket; import fr.themode.minestom.net.packet.server.login.JoinGamePacket; import fr.themode.minestom.net.packet.server.login.LoginSuccessPacket; -import fr.themode.minestom.net.packet.server.play.PlayerInfoPacket; -import fr.themode.minestom.net.packet.server.play.PlayerPositionAndLookPacket; -import fr.themode.minestom.net.packet.server.play.SpawnPlayerPacket; -import fr.themode.minestom.net.packet.server.play.SpawnPositionPacket; +import fr.themode.minestom.net.packet.server.play.*; import fr.themode.minestom.net.player.PlayerConnection; import fr.themode.minestom.utils.Utils; import fr.themode.minestom.world.Dimension; @@ -38,7 +34,7 @@ public class LoginStartPacket implements ClientPreplayPacket { instance = Main.getInstanceManager().createInstance(); for (int x = -64; x < 64; x++) for (int z = -64; z < 64; z++) { - instance.setBlock(x, 4, z, new Block(10)); + instance.setBlock(x, 4, z, (short) 10); } } @@ -153,6 +149,14 @@ public class LoginStartPacket implements ClientPreplayPacket { inv.setItemStack(1, new ItemStack(1, (byte) 2)); inv.updateItems(); + + EntityEffectPacket entityEffectPacket = new EntityEffectPacket(); + entityEffectPacket.entityId = player.getEntityId(); + entityEffectPacket.effectId = 4; + entityEffectPacket.amplifier = -1; + entityEffectPacket.duration = 3600; + entityEffectPacket.flags = 0; + connection.sendPacket(entityEffectPacket); } @Override diff --git a/src/main/java/fr/themode/minestom/net/packet/client/play/ClientChatMessagePacket.java b/src/main/java/fr/themode/minestom/net/packet/client/play/ClientChatMessagePacket.java index cfc6c15a4..e40f54b0f 100644 --- a/src/main/java/fr/themode/minestom/net/packet/client/play/ClientChatMessagePacket.java +++ b/src/main/java/fr/themode/minestom/net/packet/client/play/ClientChatMessagePacket.java @@ -4,7 +4,6 @@ import fr.adamaq01.ozao.net.Buffer; import fr.themode.minestom.Main; import fr.themode.minestom.entity.Player; import fr.themode.minestom.net.packet.client.ClientPlayPacket; -import fr.themode.minestom.net.packet.server.play.ChatMessagePacket; import fr.themode.minestom.utils.Utils; public class ClientChatMessagePacket implements ClientPlayPacket { @@ -13,8 +12,7 @@ public class ClientChatMessagePacket implements ClientPlayPacket { @Override public void process(Player player) { - ChatMessagePacket chatMessagePacket = new ChatMessagePacket(String.format("{\"text\": \"<%s> %s\"}", player.getUsername(), message), ChatMessagePacket.Position.CHAT); - Main.getConnectionManager().getOnlinePlayers().forEach(player1 -> player1.getPlayerConnection().sendPacket(chatMessagePacket)); + Main.getConnectionManager().getOnlinePlayers().forEach(p -> p.sendMessage(String.format("<%s> %s", player.getUsername(), message))); } @Override diff --git a/src/main/java/fr/themode/minestom/net/packet/client/play/ClientClickWindowPacket.java b/src/main/java/fr/themode/minestom/net/packet/client/play/ClientClickWindowPacket.java index ef67da6a9..950a6b073 100644 --- a/src/main/java/fr/themode/minestom/net/packet/client/play/ClientClickWindowPacket.java +++ b/src/main/java/fr/themode/minestom/net/packet/client/play/ClientClickWindowPacket.java @@ -3,6 +3,8 @@ package fr.themode.minestom.net.packet.client.play; import fr.adamaq01.ozao.net.Buffer; import fr.themode.minestom.entity.Player; import fr.themode.minestom.inventory.Inventory; +import fr.themode.minestom.inventory.InventoryClickHandler; +import fr.themode.minestom.inventory.PlayerInventory; import fr.themode.minestom.item.ItemStack; import fr.themode.minestom.net.packet.client.ClientPlayPacket; import fr.themode.minestom.net.packet.server.play.ConfirmTransactionPacket; @@ -20,7 +22,10 @@ public class ClientClickWindowPacket implements ClientPlayPacket { @Override public void process(Player player) { - Inventory inventory = player.getOpenInventory(); + InventoryClickHandler clickHandler = player.getOpenInventory(); + if (clickHandler == null) { + clickHandler = player.getInventory(); + } System.out.println("Window id: " + windowId + " | slot: " + slot + " | button: " + button + " | mode: " + mode); ConfirmTransactionPacket confirmTransactionPacket = new ConfirmTransactionPacket(); @@ -33,19 +38,19 @@ public class ClientClickWindowPacket implements ClientPlayPacket { switch (button) { case 0: // Left click - inventory.leftClick(player, slot); + clickHandler.leftClick(player, slot); break; case 1: // Right click - inventory.rightClick(player, slot); + clickHandler.rightClick(player, slot); break; } break; case 1: - inventory.shiftClick(player, slot); // Shift + left/right have identical behavior + clickHandler.shiftClick(player, slot); // Shift + left/right have identical behavior break; case 2: - inventory.changeHeld(player, slot, button); + clickHandler.changeHeld(player, slot, button); break; case 3: // Middle click (only creative players in non-player inventories) @@ -57,11 +62,11 @@ public class ClientClickWindowPacket implements ClientPlayPacket { // Dragging break; case 6: - inventory.doubleClick(player, slot); + clickHandler.doubleClick(player, slot); break; } - ItemStack cursorItem = inventory.getCursorItem(player); + ItemStack cursorItem = clickHandler instanceof Inventory ? ((Inventory) clickHandler).getCursorItem(player) : ((PlayerInventory) clickHandler).getCursorItem(); SetSlotPacket setSlotPacket = new SetSlotPacket(); setSlotPacket.windowId = -1; setSlotPacket.slot = -1; diff --git a/src/main/java/fr/themode/minestom/net/packet/client/play/ClientCloseWindow.java b/src/main/java/fr/themode/minestom/net/packet/client/play/ClientCloseWindow.java index a95ad38bb..b3e2f5f05 100644 --- a/src/main/java/fr/themode/minestom/net/packet/client/play/ClientCloseWindow.java +++ b/src/main/java/fr/themode/minestom/net/packet/client/play/ClientCloseWindow.java @@ -2,7 +2,6 @@ package fr.themode.minestom.net.packet.client.play; import fr.adamaq01.ozao.net.Buffer; import fr.themode.minestom.entity.Player; -import fr.themode.minestom.inventory.Inventory; import fr.themode.minestom.net.packet.client.ClientPlayPacket; import fr.themode.minestom.utils.Utils; @@ -12,10 +11,8 @@ public class ClientCloseWindow implements ClientPlayPacket { @Override public void process(Player player) { - Inventory openInventory = player.getOpenInventory(); // if windowId == 0 then it is player's inventory, meaning that they hadn't been any open inventory packet - if (openInventory != null) - player.closeInventory(); + player.closeInventory(); } @Override diff --git a/src/main/java/fr/themode/minestom/net/packet/client/play/ClientHeldItemChangePacket.java b/src/main/java/fr/themode/minestom/net/packet/client/play/ClientHeldItemChangePacket.java index 94733cddd..52c9eaab9 100644 --- a/src/main/java/fr/themode/minestom/net/packet/client/play/ClientHeldItemChangePacket.java +++ b/src/main/java/fr/themode/minestom/net/packet/client/play/ClientHeldItemChangePacket.java @@ -17,6 +17,6 @@ public class ClientHeldItemChangePacket implements ClientPlayPacket { @Override public void read(Buffer buffer) { - buffer.getShort(); + this.slot = buffer.getShort(); } } diff --git a/src/main/java/fr/themode/minestom/net/packet/client/play/ClientPlayerBlockPlacementPacket.java b/src/main/java/fr/themode/minestom/net/packet/client/play/ClientPlayerBlockPlacementPacket.java index cc617d1c4..ca682ad5c 100644 --- a/src/main/java/fr/themode/minestom/net/packet/client/play/ClientPlayerBlockPlacementPacket.java +++ b/src/main/java/fr/themode/minestom/net/packet/client/play/ClientPlayerBlockPlacementPacket.java @@ -2,15 +2,11 @@ package fr.themode.minestom.net.packet.client.play; import fr.adamaq01.ozao.net.Buffer; import fr.themode.minestom.entity.Player; -import fr.themode.minestom.instance.Block; -import fr.themode.minestom.instance.BlockBatch; import fr.themode.minestom.instance.Instance; import fr.themode.minestom.net.packet.client.ClientPlayPacket; import fr.themode.minestom.utils.Position; import fr.themode.minestom.utils.Utils; -import java.util.Random; - public class ClientPlayerBlockPlacementPacket implements ClientPlayPacket { public Hand hand; @@ -25,14 +21,21 @@ public class ClientPlayerBlockPlacementPacket implements ClientPlayPacket { if (instance == null) return; - Random random = new Random(); + int offsetX = blockFace == ClientPlayerDiggingPacket.BlockFace.WEST ? -1 : blockFace == ClientPlayerDiggingPacket.BlockFace.EAST ? 1 : 0; + int offsetY = blockFace == ClientPlayerDiggingPacket.BlockFace.BOTTOM ? -1 : blockFace == ClientPlayerDiggingPacket.BlockFace.TOP ? 1 : 0; + int offsetZ = blockFace == ClientPlayerDiggingPacket.BlockFace.NORTH ? -1 : blockFace == ClientPlayerDiggingPacket.BlockFace.SOUTH ? 1 : 0; + + instance.setBlock(position.getX() + offsetX, position.getY() + offsetY, position.getZ() + offsetZ, (short) 1); + player.getInventory().refreshSlot(player.getHeldSlot()); + // TODO consume block in hand for survival players + /*Random random = new Random(); BlockBatch blockBatch = instance.createBlockBatch(); for (int x = -64; x < 64; x++) for (int z = -64; z < 64; z++) { if (random.nextInt(100) > 75) blockBatch.setBlock(x, position.getY() + 1, z, new Block(1)); } - blockBatch.flush(); + blockBatch.flush();*/ } @Override diff --git a/src/main/java/fr/themode/minestom/net/packet/client/play/ClientPlayerDiggingPacket.java b/src/main/java/fr/themode/minestom/net/packet/client/play/ClientPlayerDiggingPacket.java index 0a1c1e390..6069d89fc 100644 --- a/src/main/java/fr/themode/minestom/net/packet/client/play/ClientPlayerDiggingPacket.java +++ b/src/main/java/fr/themode/minestom/net/packet/client/play/ClientPlayerDiggingPacket.java @@ -3,7 +3,6 @@ package fr.themode.minestom.net.packet.client.play; import fr.adamaq01.ozao.net.Buffer; import fr.themode.minestom.entity.GameMode; import fr.themode.minestom.entity.Player; -import fr.themode.minestom.instance.Block; import fr.themode.minestom.instance.Instance; import fr.themode.minestom.net.packet.client.ClientPlayPacket; import fr.themode.minestom.utils.Position; @@ -22,10 +21,19 @@ public class ClientPlayerDiggingPacket implements ClientPlayPacket { if (player.getGameMode() == GameMode.CREATIVE) { Instance instance = player.getInstance(); if (instance != null) { - instance.setBlock(position.getX(), position.getY(), position.getZ(), new Block(0)); + instance.setBlock(position.getX(), position.getY(), position.getZ(), (short) 0); } + } else if (player.getGameMode() == GameMode.SURVIVAL) { + player.refreshTargetBlock(position); + // TODO survival mining } break; + case CANCELLED_DIGGING: + player.refreshTargetBlock(null); + break; + case FINISHED_DIGGING: + player.refreshTargetBlock(null); + break; } } diff --git a/src/main/java/fr/themode/minestom/net/packet/server/play/AcknowledgePlayerDiggingPacket.java b/src/main/java/fr/themode/minestom/net/packet/server/play/AcknowledgePlayerDiggingPacket.java new file mode 100644 index 000000000..703d65512 --- /dev/null +++ b/src/main/java/fr/themode/minestom/net/packet/server/play/AcknowledgePlayerDiggingPacket.java @@ -0,0 +1,28 @@ +package fr.themode.minestom.net.packet.server.play; + +import fr.adamaq01.ozao.net.Buffer; +import fr.themode.minestom.net.packet.client.play.ClientPlayerDiggingPacket; +import fr.themode.minestom.net.packet.server.ServerPacket; +import fr.themode.minestom.utils.Position; +import fr.themode.minestom.utils.Utils; + +public class AcknowledgePlayerDiggingPacket implements ServerPacket { + + public Position position; + public int blockStateId; + public ClientPlayerDiggingPacket.Status status; + public boolean successful; + + @Override + public void write(Buffer buffer) { + Utils.writePosition(buffer, position); + Utils.writeVarInt(buffer, blockStateId); + Utils.writeVarInt(buffer, status.ordinal()); + buffer.putBoolean(successful); + } + + @Override + public int getId() { + return 0x5c; + } +} diff --git a/src/main/java/fr/themode/minestom/net/packet/server/play/BlockBreakAnimationPacket.java b/src/main/java/fr/themode/minestom/net/packet/server/play/BlockBreakAnimationPacket.java new file mode 100644 index 000000000..ba8895cef --- /dev/null +++ b/src/main/java/fr/themode/minestom/net/packet/server/play/BlockBreakAnimationPacket.java @@ -0,0 +1,25 @@ +package fr.themode.minestom.net.packet.server.play; + +import fr.adamaq01.ozao.net.Buffer; +import fr.themode.minestom.net.packet.server.ServerPacket; +import fr.themode.minestom.utils.Position; +import fr.themode.minestom.utils.Utils; + +public class BlockBreakAnimationPacket implements ServerPacket { + + public int entityId; + public Position blockPosition; + public byte destroyStage; + + @Override + public void write(Buffer buffer) { + Utils.writeVarInt(buffer, entityId); + Utils.writePosition(buffer, blockPosition); + buffer.putByte(destroyStage); + } + + @Override + public int getId() { + return 0x08; + } +} \ No newline at end of file diff --git a/src/main/java/fr/themode/minestom/net/packet/server/play/ChunkDataPacket.java b/src/main/java/fr/themode/minestom/net/packet/server/play/ChunkDataPacket.java index 1a26880be..9f81c3871 100644 --- a/src/main/java/fr/themode/minestom/net/packet/server/play/ChunkDataPacket.java +++ b/src/main/java/fr/themode/minestom/net/packet/server/play/ChunkDataPacket.java @@ -1,7 +1,6 @@ package fr.themode.minestom.net.packet.server.play; import fr.adamaq01.ozao.net.Buffer; -import fr.themode.minestom.instance.Block; import fr.themode.minestom.instance.Chunk; import fr.themode.minestom.net.packet.server.ServerPacket; import fr.themode.minestom.utils.Utils; @@ -30,7 +29,7 @@ public class ChunkDataPacket implements ServerPacket { for (int i = 0; i < 16; i++) { // TODO if fullchunk is false then only send changed sections mask |= 1 << i; - Block[] section = getSection(chunk, i); + Short[] section = getSection(chunk, i); Utils.writeBlocks(blocks, section, 14); } // Biome data @@ -73,13 +72,13 @@ public class ChunkDataPacket implements ServerPacket { Utils.writeVarInt(buffer, 0); } - private Block[] getSection(Chunk chunk, int section) { - Block[] blocks = new Block[16 * 16 * 16]; + private Short[] getSection(Chunk chunk, int section) { + Short[] blocks = new Short[16 * 16 * 16]; for (int y = 0; y < 16; y++) { for (int x = 0; x < 16; x++) { for (int z = 0; z < 16; z++) { int index = (((y * 16) + x) * 16) + z; - blocks[index] = chunk.getBlock(x, y + 16 * section, z); + blocks[index] = chunk.getBlockId(x, y + 16 * section, z); } } } diff --git a/src/main/java/fr/themode/minestom/net/packet/server/play/EntityEffectPacket.java b/src/main/java/fr/themode/minestom/net/packet/server/play/EntityEffectPacket.java new file mode 100644 index 000000000..9746f9db5 --- /dev/null +++ b/src/main/java/fr/themode/minestom/net/packet/server/play/EntityEffectPacket.java @@ -0,0 +1,28 @@ +package fr.themode.minestom.net.packet.server.play; + +import fr.adamaq01.ozao.net.Buffer; +import fr.themode.minestom.net.packet.server.ServerPacket; +import fr.themode.minestom.utils.Utils; + +public class EntityEffectPacket implements ServerPacket { + + public int entityId; + public byte effectId; + public byte amplifier; + public int duration; + public byte flags; + + @Override + public void write(Buffer buffer) { + Utils.writeVarInt(buffer, entityId); + buffer.putByte(effectId); + buffer.putByte(amplifier); + Utils.writeVarInt(buffer, duration); + buffer.putByte(flags); + } + + @Override + public int getId() { + return 0x59; + } +} diff --git a/src/main/java/fr/themode/minestom/net/packet/server/play/RemoveEntityEffectPacket.java b/src/main/java/fr/themode/minestom/net/packet/server/play/RemoveEntityEffectPacket.java new file mode 100644 index 000000000..34b7e8c04 --- /dev/null +++ b/src/main/java/fr/themode/minestom/net/packet/server/play/RemoveEntityEffectPacket.java @@ -0,0 +1,22 @@ +package fr.themode.minestom.net.packet.server.play; + +import fr.adamaq01.ozao.net.Buffer; +import fr.themode.minestom.net.packet.server.ServerPacket; +import fr.themode.minestom.utils.Utils; + +public class RemoveEntityEffectPacket implements ServerPacket { + + public int entityId; + public byte effectId; + + @Override + public void write(Buffer buffer) { + Utils.writeVarInt(buffer, entityId); + buffer.putByte(effectId); + } + + @Override + public int getId() { + return 0x38; + } +} diff --git a/src/main/java/fr/themode/minestom/utils/Position.java b/src/main/java/fr/themode/minestom/utils/Position.java index 9ef537750..129a0e869 100644 --- a/src/main/java/fr/themode/minestom/utils/Position.java +++ b/src/main/java/fr/themode/minestom/utils/Position.java @@ -33,4 +33,9 @@ public class Position { public void setZ(int z) { this.z = z; } + + @Override + public String toString() { + return "Position[" + x + ":" + y + ":" + z + "]"; + } } diff --git a/src/main/java/fr/themode/minestom/utils/Utils.java b/src/main/java/fr/themode/minestom/utils/Utils.java index 0453f4e51..220c2964a 100644 --- a/src/main/java/fr/themode/minestom/utils/Utils.java +++ b/src/main/java/fr/themode/minestom/utils/Utils.java @@ -1,7 +1,6 @@ package fr.themode.minestom.utils; import fr.adamaq01.ozao.net.Buffer; -import fr.themode.minestom.instance.Block; import fr.themode.minestom.item.ItemStack; import java.io.UnsupportedEncodingException; @@ -122,7 +121,11 @@ public class Utils { } public static void writePosition(Buffer buffer, int x, int y, int z) { - buffer.putLong(((x & 0x3FFFFFF) << 38) | ((z & 0x3FFFFFF) << 12) | (y & 0xFFF)); + buffer.putLong((((long) x & 0x3FFFFFF) << 38) | (((long) z & 0x3FFFFFF) << 12) | ((long) y & 0xFFF)); + } + + public static void writePosition(Buffer buffer, Position position) { + writePosition(buffer, position.getX(), position.getY(), position.getZ()); } public static Position readPosition(Buffer buffer) { @@ -144,8 +147,8 @@ public class Utils { } } - public static void writeBlocks(Buffer buffer, Block[] blocks, int bitsPerEntry) { - buffer.putShort((short) Arrays.stream(blocks).filter(customBlock -> customBlock.getType() != 0).collect(Collectors.toList()).size()); + public static void writeBlocks(Buffer buffer, Short[] blocksId, int bitsPerEntry) { + buffer.putShort((short) Arrays.stream(blocksId).filter(customBlock -> customBlock != 0).collect(Collectors.toList()).size()); buffer.putByte((byte) bitsPerEntry); int[] blocksData = new int[16 * 16 * 16]; for (int y = 0; y < 16; y++) { @@ -153,7 +156,7 @@ public class Utils { for (int z = 0; z < 16; z++) { int sectionIndex = (((y * 16) + x) * 16) + z; int index = y << 8 | z << 4 | x; - blocksData[index] = blocks[sectionIndex].getType(); + blocksData[index] = blocksId[sectionIndex]; } } }