Enhanced inventory creation & listener

This commit is contained in:
TheMode 2019-08-13 17:52:09 +02:00
parent 349de8773f
commit e2e7d67013
23 changed files with 752 additions and 42 deletions

View File

@ -1,6 +1,7 @@
package fr.themode.minestom.entity;
import fr.themode.minestom.Main;
import fr.themode.minestom.inventory.Inventory;
import fr.themode.minestom.inventory.PlayerInventory;
import fr.themode.minestom.item.ItemStack;
import fr.themode.minestom.net.packet.server.play.*;
@ -21,6 +22,7 @@ public class Player extends LivingEntity {
private GameMode gameMode;
private PlayerInventory inventory;
private short heldSlot;
private Inventory openInventory;
// TODO set proper UUID
public Player(UUID uuid, String username, PlayerConnection playerConnection) {
@ -102,6 +104,40 @@ public class Player extends LivingEntity {
return inventory.getItemStack(heldSlot);
}
public Inventory getOpenInventory() {
return openInventory;
}
public void openInventory(Inventory inventory) {
if (inventory == null)
throw new IllegalArgumentException("Inventory cannot be null, use Player#closeInventory() to close current");
if (getOpenInventory() != null) {
getOpenInventory().removeViewer(this);
}
OpenWindowPacket openWindowPacket = new OpenWindowPacket();
openWindowPacket.windowId = inventory.getUniqueId();
openWindowPacket.windowType = inventory.getInventoryType().getWindowType();
openWindowPacket.title = inventory.getTitle();
playerConnection.sendPacket(openWindowPacket);
inventory.addViewer(this);
refreshOpenInventory(inventory);
}
public void closeInventory() {
Inventory openInventory = getOpenInventory();
CloseWindowPacket closeWindowPacket = new CloseWindowPacket();
if (openInventory == null) {
closeWindowPacket.windowId = 0;
} else {
closeWindowPacket.windowId = openInventory.getUniqueId();
openInventory.removeViewer(this);
refreshOpenInventory(null);
}
playerConnection.sendPacket(closeWindowPacket);
}
public void refreshGameMode(GameMode gameMode) {
this.gameMode = gameMode;
}
@ -131,6 +167,10 @@ public class Player extends LivingEntity {
this.heldSlot = slot;
}
public void refreshOpenInventory(Inventory openInventory) {
this.openInventory = openInventory;
}
public long getLastKeepAlive() {
return lastKeepAlive;
}

View File

@ -47,7 +47,7 @@ public class BlockBatch {
for (BlockData data : dataList) {
data.apply(chunk);
}
instance.sendChunkUpdate(chunk);
instance.sendChunkUpdate(chunk); // TODO partial chunk data
});
}
}
@ -59,7 +59,7 @@ public class BlockBatch {
private Block block;
public void apply(Chunk chunk) {
chunk.setBlock(x % 16, y, z % 16, block);
chunk.setBlock(x, y, z, block);
}
}

View File

@ -23,7 +23,7 @@ public class Chunk {
this.chunkZ = chunkZ;
}
public void setBlock(int x, int y, int z, Block block) {
protected void setBlock(int x, int y, int z, Block block) {
short index = (short) (x & 0x000F);
index |= (y << 4) & 0x0FF0;
index |= (z << 12) & 0xF000;

View File

@ -0,0 +1,235 @@
package fr.themode.minestom.inventory;
import fr.themode.minestom.entity.Player;
import fr.themode.minestom.item.ItemStack;
import fr.themode.minestom.net.packet.server.play.WindowItemsPacket;
import java.util.Arrays;
import java.util.Collections;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArraySet;
import java.util.concurrent.atomic.AtomicInteger;
public class Inventory implements InventoryClickHandler {
private static AtomicInteger lastInventoryId = new AtomicInteger();
private int id;
private InventoryType inventoryType;
private String title;
private int offset;
private ItemStack[] itemStacks;
private Set<Player> viewers = new CopyOnWriteArraySet<>();
private ConcurrentHashMap<Player, ItemStack> cursorPlayersItem = new ConcurrentHashMap<>();
public Inventory(InventoryType inventoryType, String title) {
this.id = generateId();
this.inventoryType = inventoryType;
this.title = title;
this.offset = inventoryType.getAdditionalSlot();
this.itemStacks = new ItemStack[inventoryType.getAdditionalSlot()];
Arrays.fill(itemStacks, ItemStack.AIR_ITEM);
}
private static int generateId() {
return lastInventoryId.incrementAndGet();
}
public InventoryType getInventoryType() {
return inventoryType;
}
public String getTitle() {
return title;
}
public int getUniqueId() {
return id;
}
public void setItemStack(int slot, ItemStack itemStack) {
if (slot < 0 || slot > inventoryType.getAdditionalSlot())
throw new IllegalArgumentException(inventoryType.toString() + " does not have slot " + slot);
safeItemInsert(slot, itemStack);
}
public ItemStack getItemStack(int slot) {
return itemStacks[slot];
}
public void updateItems() {
WindowItemsPacket windowItemsPacket = getWindowItemsPacket();
getViewers().forEach(p -> p.getPlayerConnection().sendPacket(windowItemsPacket));
}
public Set<Player> getViewers() {
return Collections.unmodifiableSet(viewers);
}
public void addViewer(Player player) {
this.viewers.add(player);
WindowItemsPacket windowItemsPacket = getWindowItemsPacket();
player.getPlayerConnection().sendPacket(windowItemsPacket);
}
public void removeViewer(Player player) {
this.viewers.remove(player);
}
public ItemStack getCursorItem(Player player) {
return cursorPlayersItem.getOrDefault(player, ItemStack.AIR_ITEM);
}
private void safeItemInsert(int slot, ItemStack itemStack) {
synchronized (this) {
this.itemStacks[slot] = itemStack == null ? ItemStack.AIR_ITEM : itemStack;
}
}
private WindowItemsPacket getWindowItemsPacket() {
WindowItemsPacket windowItemsPacket = new WindowItemsPacket();
windowItemsPacket.windowId = getUniqueId();
windowItemsPacket.count = (short) itemStacks.length;
windowItemsPacket.items = itemStacks;
return windowItemsPacket;
}
private void setCursorPlayerItem(Player player, ItemStack itemStack) {
this.cursorPlayersItem.put(player, itemStack);
}
private boolean isClickInWindow(int slot) {
return slot < inventoryType.getAdditionalSlot();
}
@Override
public void leftClick(Player player, int slot) {
PlayerInventory playerInventory = player.getInventory();
ItemStack cursorItem = getCursorItem(player);
boolean isInWindow = isClickInWindow(slot);
ItemStack clicked = isInWindow ? getItemStack(slot) : playerInventory.getItemStack(slot, offset);
if (cursorItem.isAir() && clicked.isAir())
return;
ItemStack resultCursor;
ItemStack resultClicked;
if (cursorItem.isSimilar(clicked)) {
resultCursor = cursorItem.clone();
resultClicked = clicked.clone();
int amount = cursorItem.getAmount() + clicked.getAmount();
if (amount > 100) {
resultCursor.setAmount((byte) (amount - 100));
resultClicked.setAmount((byte) 100);
} else {
resultCursor = ItemStack.AIR_ITEM;
resultClicked.setAmount((byte) amount);
}
} else {
resultCursor = clicked.clone();
resultClicked = cursorItem.clone();
}
if (isInWindow) {
setItemStack(slot, resultClicked);
setCursorPlayerItem(player, resultCursor);
updateItems();
} else {
playerInventory.setItemStack(slot, offset, resultClicked);
setCursorPlayerItem(player, resultCursor);
playerInventory.update();
}
}
@Override
public void rightClick(Player player, int slot) {
PlayerInventory playerInventory = player.getInventory();
ItemStack cursorItem = getCursorItem(player);
boolean isInWindow = isClickInWindow(slot);
ItemStack clicked = isInWindow ? getItemStack(slot) : playerInventory.getItemStack(slot, offset);
if (cursorItem.isAir() && clicked.isAir())
return;
ItemStack resultCursor;
ItemStack resultClicked;
if (cursorItem.isSimilar(clicked)) {
resultCursor = cursorItem.clone();
resultClicked = clicked.clone();
int amount = clicked.getAmount() + 1;
if (amount > 100) {
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();
}
}
}
if (isInWindow) {
setItemStack(slot, resultClicked);
setCursorPlayerItem(player, resultCursor);
updateItems();
} else {
playerInventory.setItemStack(slot, offset, resultClicked);
setCursorPlayerItem(player, resultCursor);
playerInventory.update();
}
}
@Override
public void shiftClick(Player player, int slot) {
}
@Override
public void changeHeld(Player player, int slot, int key) {
}
@Override
public void middleClick(Player player, int slot) {
}
@Override
public void dropOne(Player player, int slot) {
}
@Override
public void dropItemStack(Player player, int slot) {
}
}

View File

@ -0,0 +1,21 @@
package fr.themode.minestom.inventory;
import fr.themode.minestom.entity.Player;
public interface InventoryClickHandler {
void leftClick(Player player, int slot);
void rightClick(Player player, int slot);
void shiftClick(Player player, int slot); // shift + left/right click have the same behavior
void changeHeld(Player player, int slot, int key);
void middleClick(Player player, int slot);
void dropOne(Player player, int slot);
void dropItemStack(Player player, int slot);
}

View File

@ -0,0 +1,45 @@
package fr.themode.minestom.inventory;
public enum InventoryType {
CHEST_1_ROW(0, 9),
CHEST_2_ROW(1, 18),
CHEST_3_ROW(2, 27),
CHEST_4_ROW(3, 36),
CHEST_5_ROW(4, 45),
CHEST_6_ROW(5, 54),
WINDOW_3X3(6, 9),
ANVIL(7, 3),
BEACON(8, 1),
BLAST_FURNACE(9, 3),
BREWING_STAND(10, 5),
CRAFTING(11, 10),
ENCHANTMENT(12, 2),
FURNACE(13, 3),
GRINDSTONE(14, 3),
HOPPER(15, 5),
LECTERN(16, 0),
LOOM(17, 4),
MERCHANT(18, 3),
SHULKER_BOX(19, 27),
SMOKER(20, 3),
CARTOGRAPHY(21, 3),
STONE_CUTTER(22, 2);
private int windowType;
private int slot;
InventoryType(int windowType, int slot) {
this.windowType = windowType;
this.slot = slot;
}
public int getWindowType() {
return windowType;
}
public int getAdditionalSlot() {
return slot;
}
}

View File

@ -5,6 +5,8 @@ import fr.themode.minestom.item.ItemStack;
import fr.themode.minestom.net.packet.server.play.WindowItemsPacket;
import fr.themode.minestom.net.player.PlayerConnection;
import java.util.Arrays;
public class PlayerInventory {
private Player player;
@ -12,51 +14,87 @@ public class PlayerInventory {
public PlayerInventory(Player player) {
this.player = player;
Arrays.fill(items, ItemStack.AIR_ITEM);
}
public ItemStack getItemStack(int slot) {
ItemStack item = this.items[convertSlot(slot)];
return item != null ? item : ItemStack.AIR_ITEM;
return this.items[slot];
}
public void setItemStack(int slot, ItemStack itemStack) {
this.items[convertSlot(slot)] = itemStack;
safeItemInsert(slot, itemStack);
}
public void setHelmet(ItemStack itemStack) {
this.items[5] = itemStack;
safeItemInsert(5, itemStack);
}
public void setChestplate(ItemStack itemStack) {
this.items[6] = itemStack;
safeItemInsert(6, itemStack);
}
public void setLeggings(ItemStack itemStack) {
this.items[7] = itemStack;
safeItemInsert(7, itemStack);
}
public void setBoots(ItemStack itemStack) {
this.items[8] = itemStack;
safeItemInsert(8, itemStack);
}
public void update() {
PlayerConnection playerConnection = player.getPlayerConnection();
WindowItemsPacket windowItemsPacket = new WindowItemsPacket();
windowItemsPacket.windowId = 0; // player inventory ID
windowItemsPacket.count = (short) items.length;
windowItemsPacket.items = items;
playerConnection.sendPacket(windowItemsPacket);
playerConnection.sendPacket(createWindowItemsPacket());
}
private int convertSlot(int slot) {
if (slot >= 0 && slot <= 9 * 4) {
int row = slot / 9;
int place = slot % 9;
int converted = 9 * (4 - 1 - row) + place + 9;
return converted;
private void safeItemInsert(int slot, ItemStack itemStack) {
synchronized (this) {
this.items[slot] = itemStack == null ? ItemStack.AIR_ITEM : itemStack;
}
}
protected void setItemStack(int slot, int offset, ItemStack itemStack) {
slot = convertSlot(slot, offset);
// System.out.println("NEWSLOT: "+slot +" : "+itemStack.getItemId());
safeItemInsert(slot, itemStack);
}
protected ItemStack getItemStack(int slot, int offset) {
slot = convertSlot(slot, offset);
return this.items[slot];
}
protected int convertSlot(int slot, int offset) {
final int rowSize = 9;
slot -= offset;
if (slot >= rowSize * 3 && slot < rowSize * 4) {
slot = slot % 9;
} else {
slot = slot + rowSize;
}
System.out.println("DEBUG: " + slot);
return slot;
}
private WindowItemsPacket createWindowItemsPacket() {
ItemStack[] convertedSlots = new ItemStack[45];
Arrays.fill(convertedSlots, ItemStack.AIR_ITEM); // TODO armor and craft
// Hotbar
for (int i = 0; i < 9; i++) {
convertedSlots[36 + i] = items[i];
}
// Inventory
for (int i = 10; i < 9 + 9 * 3; i++) {
convertedSlots[i] = items[i];
}
WindowItemsPacket windowItemsPacket = new WindowItemsPacket();
windowItemsPacket.windowId = 0;
windowItemsPacket.count = 45;
windowItemsPacket.items = convertedSlots;
return windowItemsPacket;
}
}

View File

@ -1,22 +1,38 @@
package fr.themode.minestom.item;
public class ItemStack {
public class ItemStack implements Cloneable {
public static final ItemStack AIR_ITEM = new ItemStack(0, (byte) 1);
private int itemId;
private byte count;
private byte amount;
public ItemStack(int itemId, byte count) {
public ItemStack(int itemId, byte amount) {
this.itemId = itemId;
this.count = count;
this.amount = amount;
}
public boolean isAir() {
return itemId == 0;
}
public boolean isSimilar(ItemStack itemStack) {
return itemStack.getItemId() == itemId;
}
public byte getAmount() {
return amount;
}
public int getItemId() {
return itemId;
}
public byte getCount() {
return count;
public void setAmount(byte amount) {
this.amount = amount;
}
public ItemStack clone() {
return new ItemStack(itemId, amount);
}
}

View File

@ -21,5 +21,8 @@ public class ClientPlayPacketsHandler extends ClientPacketsHandler {
register(0x1A, ClientPlayerDiggingPacket.class);
register(0x2C, ClientPlayerBlockPlacementPacket.class);
register(0x23, ClientHeldItemChangePacket.class);
register(0x09, ClientClickWindowPacket.class);
register(0x0A, ClientCloseWindow.class);
register(0x07, ClientConfirmTransactionPacket.class);
}
}

View File

@ -7,6 +7,8 @@ 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;
import fr.themode.minestom.inventory.PlayerInventory;
import fr.themode.minestom.item.ItemStack;
import fr.themode.minestom.net.ConnectionManager;
@ -56,7 +58,7 @@ public class LoginStartPacket implements ClientPreplayPacket {
connection.setConnectionState(ConnectionState.PLAY);
connectionManager.createPlayer(uuids.get(username), username, connection);
Player player = connectionManager.getPlayer(connection);
GameMode gameMode = GameMode.CREATIVE;
GameMode gameMode = GameMode.SURVIVAL;
player.refreshGameMode(gameMode);
@ -141,9 +143,16 @@ public class LoginStartPacket implements ClientPreplayPacket {
//System.out.println("HAHAHAHHAHHAH " + player.getUuid());
PlayerInventory inventory = player.getInventory();
inventory.setItemStack(1, new ItemStack(1, (byte) 1));
inventory.setItemStack(1, new ItemStack(1, (byte) 32));
inventory.setItemStack(2, new ItemStack(1, (byte) 32));
inventory.update();
Inventory inv = new Inventory(InventoryType.WINDOW_3X3, "Salut je suis le titre");
inv.setItemStack(0, new ItemStack(1, (byte) 1));
player.openInventory(inv);
inv.setItemStack(1, new ItemStack(1, (byte) 2));
inv.updateItems();
}
@Override

View File

@ -0,0 +1,90 @@
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.item.ItemStack;
import fr.themode.minestom.net.packet.client.ClientPlayPacket;
import fr.themode.minestom.net.packet.server.play.ConfirmTransactionPacket;
import fr.themode.minestom.net.packet.server.play.SetSlotPacket;
import fr.themode.minestom.utils.Utils;
public class ClientClickWindowPacket implements ClientPlayPacket {
public byte windowId;
public short slot;
public byte button;
public short actionNumber;
public int mode;
// TODO clicked item
@Override
public void process(Player player) {
Inventory inventory = player.getOpenInventory();
System.out.println("Window id: " + windowId + " | slot: " + slot + " | button: " + button + " | mode: " + mode);
ConfirmTransactionPacket confirmTransactionPacket = new ConfirmTransactionPacket();
confirmTransactionPacket.windowId = windowId;
confirmTransactionPacket.actionNumber = actionNumber;
confirmTransactionPacket.accepted = true; // Change depending on output
switch (mode) {
case 0:
switch (button) {
case 0:
// Left click
inventory.leftClick(player, slot);
break;
case 1:
// Right click
inventory.rightClick(player, slot);
break;
}
break;
case 1:
switch (button) {
case 0:
// Shift + left click
break;
case 1:
// Shift + right click
break;
}
break;
case 2:
// Number key 1-9
break;
case 3:
// Middle click (only creative players in non-player inventories)
break;
case 4:
// Dropping functions
break;
case 5:
// Dragging
break;
case 6:
// Double click (merge similar items)
break;
}
ItemStack cursorItem = inventory.getCursorItem(player);
SetSlotPacket setSlotPacket = new SetSlotPacket();
setSlotPacket.windowId = -1;
setSlotPacket.slot = -1;
setSlotPacket.itemStack = cursorItem;
player.getPlayerConnection().sendPacket(setSlotPacket);
player.getPlayerConnection().sendPacket(confirmTransactionPacket);
}
@Override
public void read(Buffer buffer) {
this.windowId = buffer.getByte();
this.slot = buffer.getShort();
this.button = buffer.getByte();
this.actionNumber = buffer.getShort();
this.mode = Utils.readVarInt(buffer);
// TODO read clicked item
}
}

View File

@ -0,0 +1,26 @@
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;
public class ClientCloseWindow implements ClientPlayPacket {
public int windowId;
@Override
public void process(Player player) {
System.out.println("CLOSED: " + windowId);
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();
}
@Override
public void read(Buffer buffer) {
this.windowId = Utils.readVarInt(buffer);
}
}

View File

@ -0,0 +1,22 @@
package fr.themode.minestom.net.packet.client.play;
import fr.adamaq01.ozao.net.Buffer;
import fr.themode.minestom.entity.Player;
import fr.themode.minestom.net.packet.client.ClientPlayPacket;
public class ClientConfirmTransactionPacket implements ClientPlayPacket {
public int windowId;
public short actionNumber;
public boolean accepted;
@Override
public void process(Player player) {
}
@Override
public void read(Buffer buffer) {
}
}

View File

@ -9,6 +9,8 @@ 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;
@ -23,10 +25,12 @@ public class ClientPlayerBlockPlacementPacket implements ClientPlayPacket {
if (instance == null)
return;
Random random = new Random();
BlockBatch blockBatch = instance.createBlockBatch();
for (int x = -64; x < 64; x++)
for (int z = -64; z < 64; z++) {
blockBatch.setBlock(x, position.getY() + 1, z, new Block(1));
if (random.nextInt(100) > 75)
blockBatch.setBlock(x, position.getY() + 1, z, new Block(1));
}
blockBatch.flush();
}

View File

@ -0,0 +1,23 @@
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 BlockChangePacket implements ServerPacket {
public Position position;
public int blockId;
@Override
public void write(Buffer buffer) {
Utils.writePosition(buffer, position.getX(), position.getY(), position.getZ());
Utils.writeVarInt(buffer, blockId);
}
@Override
public int getId() {
return 0x0B;
}
}

View File

@ -25,7 +25,7 @@ public class ChatMessagePacket implements ServerPacket {
return 0x0E;
}
public static enum Position {
public enum Position {
CHAT,
SYSTEM_MESSAGE,

View File

@ -0,0 +1,20 @@
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 CloseWindowPacket implements ServerPacket {
public int windowId;
@Override
public void write(Buffer buffer) {
Utils.writeVarInt(buffer, windowId);
}
@Override
public int getId() {
return 0x13;
}
}

View File

@ -0,0 +1,24 @@
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 ConfirmTransactionPacket implements ServerPacket {
public int windowId;
public short actionNumber;
public boolean accepted;
@Override
public void write(Buffer buffer) {
Utils.writeVarInt(buffer, windowId);
buffer.putShort(actionNumber);
buffer.putBoolean(accepted);
}
@Override
public int getId() {
return 0x12;
}
}

View File

@ -0,0 +1,40 @@
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 MultiBlockChangePacket implements ServerPacket {
public int chunkX;
public int chunkZ;
public BlockChange[] blockChanges;
@Override
public void write(Buffer buffer) {
buffer.putInt(chunkX);
buffer.putInt(chunkZ);
Utils.writeVarInt(buffer, blockChanges == null ? 0 : blockChanges.length);
if (blockChanges != null) {
for (int i = 0; i < blockChanges.length; i++) {
BlockChange blockChange = blockChanges[i];
buffer.putByte(blockChange.positionXZ);
buffer.putByte(blockChange.positionY);
Utils.writeVarInt(buffer, blockChange.newBlockId);
}
}
}
@Override
public int getId() {
return 0x0F;
}
public static class BlockChange {
public byte positionXZ;
public byte positionY;
public int newBlockId;
}
}

View File

@ -0,0 +1,24 @@
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 OpenWindowPacket implements ServerPacket {
public int windowId;
public int windowType;
public String title;
@Override
public void write(Buffer buffer) {
Utils.writeVarInt(buffer, windowId);
Utils.writeVarInt(buffer, windowType);
Utils.writeString(buffer, "{\"text\": \"" + title + " \"}");
}
@Override
public int getId() {
return 0x2E;
}
}

View File

@ -0,0 +1,25 @@
package fr.themode.minestom.net.packet.server.play;
import fr.adamaq01.ozao.net.Buffer;
import fr.themode.minestom.item.ItemStack;
import fr.themode.minestom.net.packet.server.ServerPacket;
import fr.themode.minestom.utils.Utils;
public class SetSlotPacket implements ServerPacket {
public byte windowId;
public short slot;
public ItemStack itemStack;
@Override
public void write(Buffer buffer) {
buffer.putByte(windowId);
buffer.putShort(slot);
Utils.writeItemStack(buffer, itemStack);
}
@Override
public int getId() {
return 0x16;
}
}

View File

@ -7,7 +7,7 @@ import fr.themode.minestom.utils.Utils;
public class WindowItemsPacket implements ServerPacket {
public byte windowId;
public int windowId;
public short count;
public ItemStack[] items;
@ -15,21 +15,14 @@ public class WindowItemsPacket implements ServerPacket {
@Override
public void write(Buffer buffer) {
buffer.putByte(windowId);
Utils.writeVarInt(buffer, windowId);
buffer.putShort(count);
if (items == null)
return;
for (int i = 0; i < items.length; i++) {
ItemStack item = items[i];
if (item == null) {
buffer.putBoolean(false);
} else {
buffer.putBoolean(true);
Utils.writeVarInt(buffer, item.getItemId());
buffer.putByte(item.getCount());
buffer.putByte((byte) 0); // End nbt TODO
}
Utils.writeItemStack(buffer, item);
}
}

View File

@ -2,6 +2,7 @@ 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;
import java.util.Arrays;
@ -132,6 +133,17 @@ public class Utils {
return new Position(x, y, z);
}
public static void writeItemStack(Buffer buffer, ItemStack itemStack) {
if (itemStack == null) {
buffer.putBoolean(false);
} else {
buffer.putBoolean(true);
Utils.writeVarInt(buffer, itemStack.getItemId());
buffer.putByte(itemStack.getAmount());
buffer.putByte((byte) 0); // End nbt TODO
}
}
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());
buffer.putByte((byte) bitsPerEntry);