This commit is contained in:
TheMode 2019-08-18 20:38:09 +02:00
parent 2da2823cbd
commit 57def5aaac
21 changed files with 472 additions and 83 deletions

View File

@ -16,6 +16,7 @@ public class EntityManager {
public void update() { public void update() {
for (Instance instance : instanceManager.getInstances()) { for (Instance instance : instanceManager.getInstances()) {
// TODO loop chunks and entities on it instead of individual (to have more non-blocking operation)
// Creatures // Creatures
for (EntityCreature creature : instance.getCreatures()) { for (EntityCreature creature : instance.getCreatures()) {

View File

@ -6,6 +6,7 @@ import fr.themode.minestom.inventory.PlayerInventory;
import fr.themode.minestom.item.ItemStack; import fr.themode.minestom.item.ItemStack;
import fr.themode.minestom.net.packet.server.play.*; import fr.themode.minestom.net.packet.server.play.*;
import fr.themode.minestom.net.player.PlayerConnection; import fr.themode.minestom.net.player.PlayerConnection;
import fr.themode.minestom.utils.Position;
import java.util.UUID; import java.util.UUID;
@ -24,6 +25,9 @@ public class Player extends LivingEntity {
private short heldSlot; private short heldSlot;
private Inventory openInventory; private Inventory openInventory;
private Position targetBlockPosition;
private long targetBlockTime;
// TODO set proper UUID // TODO set proper UUID
public Player(UUID uuid, String username, PlayerConnection playerConnection) { public Player(UUID uuid, String username, PlayerConnection playerConnection) {
this.uuid = uuid; this.uuid = uuid;
@ -35,7 +39,26 @@ public class Player extends LivingEntity {
@Override @Override
public void update() { 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 entityTeleportPacket = new EntityTeleportPacket();
entityTeleportPacket.entityId = getEntityId(); entityTeleportPacket.entityId = getEntityId();
entityTeleportPacket.x = x; 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))); 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) { public void teleport(double x, double y, double z) {
PlayerPositionAndLookPacket positionAndLookPacket = new PlayerPositionAndLookPacket(); PlayerPositionAndLookPacket positionAndLookPacket = new PlayerPositionAndLookPacket();
positionAndLookPacket.x = x; positionAndLookPacket.x = x;
@ -172,6 +200,11 @@ public class Player extends LivingEntity {
this.openInventory = openInventory; this.openInventory = openInventory;
} }
public void refreshTargetBlock(Position targetBlockPosition) {
this.targetBlockPosition = targetBlockPosition;
this.targetBlockTime = targetBlockPosition == null ? 0 : System.currentTimeMillis();
}
public long getLastKeepAlive() { public long getLastKeepAlive() {
return lastKeepAlive; return lastKeepAlive;
} }

View File

@ -2,36 +2,22 @@ package fr.themode.minestom.instance;
public class Block { public class Block {
private short typeAndDamage; private short type;
public Block(int type) { public Block(short type) {
this.typeAndDamage = (short) (type & 0x0FFF); this.type = type;
this.typeAndDamage |= (0 << 12) & 0xF000;
} }
public Block(int type, int damage) { public short getType() {
this.typeAndDamage = (short) (type & 0x0FFF); return type;
this.typeAndDamage |= (damage << 12) & 0xF000;
} }
public int getType() { public void setType(short type) {
return typeAndDamage & 0x0FFF; this.type = type;
}
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;
} }
@Override @Override
public String toString() { public String toString() {
return String.format("CustomBlock{type=%s, damage=%s}", getType(), getDamage()); return String.format("CustomBlock{type=%s}", type);
} }
} }

View File

@ -19,7 +19,7 @@ public class BlockBatch {
this.instance = instance; 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 chunkX = Math.floorDiv(x, 16);
final int chunkZ = Math.floorDiv(z, 16); final int chunkZ = Math.floorDiv(z, 16);
Chunk chunk = this.instance.getChunk(chunkX, chunkZ); Chunk chunk = this.instance.getChunk(chunkX, chunkZ);
@ -31,7 +31,7 @@ public class BlockBatch {
data.x = x % 16; data.x = x % 16;
data.y = y; data.y = y;
data.z = z % 16; data.z = z % 16;
data.block = block; data.blockId = blockId;
blockData.add(data); blockData.add(data);
@ -56,10 +56,10 @@ public class BlockBatch {
private class BlockData { private class BlockData {
private int x, y, z; private int x, y, z;
private Block block; private short blockId;
public void apply(Chunk chunk) { public void apply(Chunk chunk) {
chunk.setBlock(x, y, z, block); chunk.setBlock(x, y, z, blockId);
} }
} }

View File

@ -15,7 +15,7 @@ public class Chunk {
protected Set<Player> players = new CopyOnWriteArraySet<>(); protected Set<Player> players = new CopyOnWriteArraySet<>();
private int chunkX, chunkZ; private int chunkX, chunkZ;
private Biome biome; private Biome biome;
private HashMap<Short, Block> blocks = new HashMap<>(); private HashMap<Short, Short> blocks = new HashMap<>(); // Index/BlockID
public Chunk(Biome biome, int chunkX, int chunkZ) { public Chunk(Biome biome, int chunkX, int chunkZ) {
this.biome = biome; this.biome = biome;
@ -23,18 +23,18 @@ public class Chunk {
this.chunkZ = chunkZ; 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); short index = (short) (x & 0x000F);
index |= (y << 4) & 0x0FF0; index |= (y << 4) & 0x0FF0;
index |= (z << 12) & 0xF000; 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); short index = (short) (x & 0x000F);
index |= (y << 4) & 0x0FF0; index |= (y << 4) & 0x0FF0;
index |= (z << 12) & 0xF000; index |= (z << 12) & 0xF000;
return this.blocks.getOrDefault(index, new Block(0)); return this.blocks.getOrDefault(index, (short) 0);
} }
public void addEntity(Entity entity) { public void addEntity(Entity entity) {
@ -65,7 +65,7 @@ public class Chunk {
} }
} }
public HashMap<Short, Block> getBlocks() { public HashMap<Short, Short> getBlocks() {
return blocks; return blocks;
} }

View File

@ -26,7 +26,7 @@ public class Instance {
} }
// TODO BlockBatch with pool // 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 chunkX = Math.floorDiv(x, 16);
final int chunkZ = Math.floorDiv(z, 16); final int chunkZ = Math.floorDiv(z, 16);
Chunk chunk = getChunk(chunkX, chunkZ); Chunk chunk = getChunk(chunkX, chunkZ);
@ -34,7 +34,7 @@ public class Instance {
chunk = createChunk(Biome.VOID, chunkX, chunkZ); chunk = createChunk(Biome.VOID, chunkX, chunkZ);
} }
synchronized (chunk) { synchronized (chunk) {
chunk.setBlock(x % 16, y, z % 16, block); chunk.setBlock(x % 16, y, z % 16, blockId);
sendChunkUpdate(chunk); sendChunkUpdate(chunk);
} }
} }

View File

@ -8,10 +8,14 @@ import fr.themode.minestom.net.player.PlayerConnection;
import java.util.Arrays; import java.util.Arrays;
public class PlayerInventory implements InventoryModifier { public class PlayerInventory implements InventoryModifier, InventoryClickHandler {
public static final int INVENTORY_SIZE = 46; 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_1 = 36;
private static final int CRAFT_SLOT_2 = 37; private static final int CRAFT_SLOT_2 = 37;
private static final int CRAFT_SLOT_3 = 38; private static final int CRAFT_SLOT_3 = 38;
@ -25,6 +29,7 @@ public class PlayerInventory implements InventoryModifier {
private Player player; private Player player;
private ItemStack[] items = new ItemStack[INVENTORY_SIZE]; private ItemStack[] items = new ItemStack[INVENTORY_SIZE];
private ItemStack cursorItem = ItemStack.AIR_ITEM;
public PlayerInventory(Player player) { public PlayerInventory(Player player) {
this.player = player; this.player = player;
@ -56,15 +61,14 @@ public class PlayerInventory implements InventoryModifier {
setItemStack(i, itemStack); setItemStack(i, itemStack);
return true; return true;
} else if (itemStack.isSimilar(item)) { } else if (itemStack.isSimilar(item)) {
// TODO check max stack size
int itemAmount = item.getAmount(); int itemAmount = item.getAmount();
if (itemAmount == 64) if (itemAmount == ITEM_MAX_SIZE)
continue; continue;
int totalAmount = itemStack.getAmount() + itemAmount; int totalAmount = itemStack.getAmount() + itemAmount;
if (totalAmount > 64) { if (totalAmount > ITEM_MAX_SIZE) {
item.setAmount((byte) 64); item.setAmount((byte) ITEM_MAX_SIZE);
sendSlotRefresh((short) convertToPacketSlot(i), item); sendSlotRefresh((short) convertToPacketSlot(i), item);
itemStack.setAmount((byte) (totalAmount - 64)); itemStack.setAmount((byte) (totalAmount - ITEM_MAX_SIZE));
} else { } else {
item.setAmount((byte) totalAmount); item.setAmount((byte) totalAmount);
sendSlotRefresh((short) convertToPacketSlot(i), item); sendSlotRefresh((short) convertToPacketSlot(i), item);
@ -105,12 +109,25 @@ public class PlayerInventory implements InventoryModifier {
playerConnection.sendPacket(createWindowItemsPacket()); 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) { private void safeItemInsert(int slot, ItemStack itemStack) {
synchronized (this) { synchronized (this) {
itemStack = itemStack == null ? ItemStack.AIR_ITEM : itemStack; itemStack = itemStack == null ? ItemStack.AIR_ITEM : itemStack;
this.items[slot] = itemStack; this.items[slot] = itemStack;
System.out.println("INSERT: " + slot); // System.out.println("INSERT: " + slot);
sendSlotRefresh((short) slot, itemStack); //sendSlotRefresh((short) slot, itemStack);
update();
} }
} }
@ -126,6 +143,17 @@ public class PlayerInventory implements InventoryModifier {
protected int convertSlot(int slot, int offset) { 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; final int rowSize = 9;
slot -= offset; slot -= offset;
if (slot >= rowSize * 3 && slot < rowSize * 4) { if (slot >= rowSize * 3 && slot < rowSize * 4) {
@ -133,6 +161,7 @@ public class PlayerInventory implements InventoryModifier {
} else { } else {
slot = slot + rowSize; slot = slot + rowSize;
} }
//System.out.println("CONVERT: " + slot);
return slot; return slot;
} }
@ -161,7 +190,6 @@ public class PlayerInventory implements InventoryModifier {
private WindowItemsPacket createWindowItemsPacket() { private WindowItemsPacket createWindowItemsPacket() {
ItemStack[] convertedSlots = new ItemStack[INVENTORY_SIZE]; ItemStack[] convertedSlots = new ItemStack[INVENTORY_SIZE];
Arrays.fill(convertedSlots, ItemStack.AIR_ITEM); // TODO armor and craft
for (int i = 0; i < items.length; i++) { for (int i = 0; i < items.length; i++) {
int slot = convertToPacketSlot(i); int slot = convertToPacketSlot(i);
@ -175,4 +203,220 @@ public class PlayerInventory implements InventoryModifier {
return windowItemsPacket; 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);
}
} }

View File

@ -5,7 +5,6 @@ import fr.themode.minestom.Main;
import fr.themode.minestom.entity.GameMode; import fr.themode.minestom.entity.GameMode;
import fr.themode.minestom.entity.Player; import fr.themode.minestom.entity.Player;
import fr.themode.minestom.entity.demo.ChickenCreature; import fr.themode.minestom.entity.demo.ChickenCreature;
import fr.themode.minestom.instance.Block;
import fr.themode.minestom.instance.Instance; import fr.themode.minestom.instance.Instance;
import fr.themode.minestom.inventory.Inventory; import fr.themode.minestom.inventory.Inventory;
import fr.themode.minestom.inventory.InventoryType; 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.client.ClientPreplayPacket;
import fr.themode.minestom.net.packet.server.login.JoinGamePacket; 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.login.LoginSuccessPacket;
import fr.themode.minestom.net.packet.server.play.PlayerInfoPacket; import fr.themode.minestom.net.packet.server.play.*;
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.player.PlayerConnection; import fr.themode.minestom.net.player.PlayerConnection;
import fr.themode.minestom.utils.Utils; import fr.themode.minestom.utils.Utils;
import fr.themode.minestom.world.Dimension; import fr.themode.minestom.world.Dimension;
@ -38,7 +34,7 @@ public class LoginStartPacket implements ClientPreplayPacket {
instance = Main.getInstanceManager().createInstance(); instance = Main.getInstanceManager().createInstance();
for (int x = -64; x < 64; x++) for (int x = -64; x < 64; x++)
for (int z = -64; z < 64; z++) { 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.setItemStack(1, new ItemStack(1, (byte) 2));
inv.updateItems(); 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 @Override

View File

@ -4,7 +4,6 @@ import fr.adamaq01.ozao.net.Buffer;
import fr.themode.minestom.Main; import fr.themode.minestom.Main;
import fr.themode.minestom.entity.Player; import fr.themode.minestom.entity.Player;
import fr.themode.minestom.net.packet.client.ClientPlayPacket; import fr.themode.minestom.net.packet.client.ClientPlayPacket;
import fr.themode.minestom.net.packet.server.play.ChatMessagePacket;
import fr.themode.minestom.utils.Utils; import fr.themode.minestom.utils.Utils;
public class ClientChatMessagePacket implements ClientPlayPacket { public class ClientChatMessagePacket implements ClientPlayPacket {
@ -13,8 +12,7 @@ public class ClientChatMessagePacket implements ClientPlayPacket {
@Override @Override
public void process(Player player) { public void process(Player player) {
ChatMessagePacket chatMessagePacket = new ChatMessagePacket(String.format("{\"text\": \"<%s> %s\"}", player.getUsername(), message), ChatMessagePacket.Position.CHAT); Main.getConnectionManager().getOnlinePlayers().forEach(p -> p.sendMessage(String.format("<%s> %s", player.getUsername(), message)));
Main.getConnectionManager().getOnlinePlayers().forEach(player1 -> player1.getPlayerConnection().sendPacket(chatMessagePacket));
} }
@Override @Override

View File

@ -3,6 +3,8 @@ package fr.themode.minestom.net.packet.client.play;
import fr.adamaq01.ozao.net.Buffer; import fr.adamaq01.ozao.net.Buffer;
import fr.themode.minestom.entity.Player; import fr.themode.minestom.entity.Player;
import fr.themode.minestom.inventory.Inventory; 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.item.ItemStack;
import fr.themode.minestom.net.packet.client.ClientPlayPacket; 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.ConfirmTransactionPacket;
@ -20,7 +22,10 @@ public class ClientClickWindowPacket implements ClientPlayPacket {
@Override @Override
public void process(Player player) { 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); System.out.println("Window id: " + windowId + " | slot: " + slot + " | button: " + button + " | mode: " + mode);
ConfirmTransactionPacket confirmTransactionPacket = new ConfirmTransactionPacket(); ConfirmTransactionPacket confirmTransactionPacket = new ConfirmTransactionPacket();
@ -33,19 +38,19 @@ public class ClientClickWindowPacket implements ClientPlayPacket {
switch (button) { switch (button) {
case 0: case 0:
// Left click // Left click
inventory.leftClick(player, slot); clickHandler.leftClick(player, slot);
break; break;
case 1: case 1:
// Right click // Right click
inventory.rightClick(player, slot); clickHandler.rightClick(player, slot);
break; break;
} }
break; break;
case 1: case 1:
inventory.shiftClick(player, slot); // Shift + left/right have identical behavior clickHandler.shiftClick(player, slot); // Shift + left/right have identical behavior
break; break;
case 2: case 2:
inventory.changeHeld(player, slot, button); clickHandler.changeHeld(player, slot, button);
break; break;
case 3: case 3:
// Middle click (only creative players in non-player inventories) // Middle click (only creative players in non-player inventories)
@ -57,11 +62,11 @@ public class ClientClickWindowPacket implements ClientPlayPacket {
// Dragging // Dragging
break; break;
case 6: case 6:
inventory.doubleClick(player, slot); clickHandler.doubleClick(player, slot);
break; break;
} }
ItemStack cursorItem = inventory.getCursorItem(player); ItemStack cursorItem = clickHandler instanceof Inventory ? ((Inventory) clickHandler).getCursorItem(player) : ((PlayerInventory) clickHandler).getCursorItem();
SetSlotPacket setSlotPacket = new SetSlotPacket(); SetSlotPacket setSlotPacket = new SetSlotPacket();
setSlotPacket.windowId = -1; setSlotPacket.windowId = -1;
setSlotPacket.slot = -1; setSlotPacket.slot = -1;

View File

@ -2,7 +2,6 @@ package fr.themode.minestom.net.packet.client.play;
import fr.adamaq01.ozao.net.Buffer; import fr.adamaq01.ozao.net.Buffer;
import fr.themode.minestom.entity.Player; import fr.themode.minestom.entity.Player;
import fr.themode.minestom.inventory.Inventory;
import fr.themode.minestom.net.packet.client.ClientPlayPacket; import fr.themode.minestom.net.packet.client.ClientPlayPacket;
import fr.themode.minestom.utils.Utils; import fr.themode.minestom.utils.Utils;
@ -12,10 +11,8 @@ public class ClientCloseWindow implements ClientPlayPacket {
@Override @Override
public void process(Player player) { 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 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 @Override

View File

@ -17,6 +17,6 @@ public class ClientHeldItemChangePacket implements ClientPlayPacket {
@Override @Override
public void read(Buffer buffer) { public void read(Buffer buffer) {
buffer.getShort(); this.slot = buffer.getShort();
} }
} }

View File

@ -2,15 +2,11 @@ package fr.themode.minestom.net.packet.client.play;
import fr.adamaq01.ozao.net.Buffer; import fr.adamaq01.ozao.net.Buffer;
import fr.themode.minestom.entity.Player; 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.instance.Instance;
import fr.themode.minestom.net.packet.client.ClientPlayPacket; import fr.themode.minestom.net.packet.client.ClientPlayPacket;
import fr.themode.minestom.utils.Position; import fr.themode.minestom.utils.Position;
import fr.themode.minestom.utils.Utils; import fr.themode.minestom.utils.Utils;
import java.util.Random;
public class ClientPlayerBlockPlacementPacket implements ClientPlayPacket { public class ClientPlayerBlockPlacementPacket implements ClientPlayPacket {
public Hand hand; public Hand hand;
@ -25,14 +21,21 @@ public class ClientPlayerBlockPlacementPacket implements ClientPlayPacket {
if (instance == null) if (instance == null)
return; 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(); BlockBatch blockBatch = instance.createBlockBatch();
for (int x = -64; x < 64; x++) for (int x = -64; x < 64; x++)
for (int z = -64; z < 64; z++) { for (int z = -64; z < 64; z++) {
if (random.nextInt(100) > 75) if (random.nextInt(100) > 75)
blockBatch.setBlock(x, position.getY() + 1, z, new Block(1)); blockBatch.setBlock(x, position.getY() + 1, z, new Block(1));
} }
blockBatch.flush(); blockBatch.flush();*/
} }
@Override @Override

View File

@ -3,7 +3,6 @@ package fr.themode.minestom.net.packet.client.play;
import fr.adamaq01.ozao.net.Buffer; import fr.adamaq01.ozao.net.Buffer;
import fr.themode.minestom.entity.GameMode; import fr.themode.minestom.entity.GameMode;
import fr.themode.minestom.entity.Player; import fr.themode.minestom.entity.Player;
import fr.themode.minestom.instance.Block;
import fr.themode.minestom.instance.Instance; import fr.themode.minestom.instance.Instance;
import fr.themode.minestom.net.packet.client.ClientPlayPacket; import fr.themode.minestom.net.packet.client.ClientPlayPacket;
import fr.themode.minestom.utils.Position; import fr.themode.minestom.utils.Position;
@ -22,10 +21,19 @@ public class ClientPlayerDiggingPacket implements ClientPlayPacket {
if (player.getGameMode() == GameMode.CREATIVE) { if (player.getGameMode() == GameMode.CREATIVE) {
Instance instance = player.getInstance(); Instance instance = player.getInstance();
if (instance != null) { 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; break;
case CANCELLED_DIGGING:
player.refreshTargetBlock(null);
break;
case FINISHED_DIGGING:
player.refreshTargetBlock(null);
break;
} }
} }

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -1,7 +1,6 @@
package fr.themode.minestom.net.packet.server.play; package fr.themode.minestom.net.packet.server.play;
import fr.adamaq01.ozao.net.Buffer; import fr.adamaq01.ozao.net.Buffer;
import fr.themode.minestom.instance.Block;
import fr.themode.minestom.instance.Chunk; import fr.themode.minestom.instance.Chunk;
import fr.themode.minestom.net.packet.server.ServerPacket; import fr.themode.minestom.net.packet.server.ServerPacket;
import fr.themode.minestom.utils.Utils; import fr.themode.minestom.utils.Utils;
@ -30,7 +29,7 @@ public class ChunkDataPacket implements ServerPacket {
for (int i = 0; i < 16; i++) { for (int i = 0; i < 16; i++) {
// TODO if fullchunk is false then only send changed sections // TODO if fullchunk is false then only send changed sections
mask |= 1 << i; mask |= 1 << i;
Block[] section = getSection(chunk, i); Short[] section = getSection(chunk, i);
Utils.writeBlocks(blocks, section, 14); Utils.writeBlocks(blocks, section, 14);
} }
// Biome data // Biome data
@ -73,13 +72,13 @@ public class ChunkDataPacket implements ServerPacket {
Utils.writeVarInt(buffer, 0); Utils.writeVarInt(buffer, 0);
} }
private Block[] getSection(Chunk chunk, int section) { private Short[] getSection(Chunk chunk, int section) {
Block[] blocks = new Block[16 * 16 * 16]; Short[] blocks = new Short[16 * 16 * 16];
for (int y = 0; y < 16; y++) { for (int y = 0; y < 16; y++) {
for (int x = 0; x < 16; x++) { for (int x = 0; x < 16; x++) {
for (int z = 0; z < 16; z++) { for (int z = 0; z < 16; z++) {
int index = (((y * 16) + x) * 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);
} }
} }
} }

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -33,4 +33,9 @@ public class Position {
public void setZ(int z) { public void setZ(int z) {
this.z = z; this.z = z;
} }
@Override
public String toString() {
return "Position[" + x + ":" + y + ":" + z + "]";
}
} }

View File

@ -1,7 +1,6 @@
package fr.themode.minestom.utils; package fr.themode.minestom.utils;
import fr.adamaq01.ozao.net.Buffer; import fr.adamaq01.ozao.net.Buffer;
import fr.themode.minestom.instance.Block;
import fr.themode.minestom.item.ItemStack; import fr.themode.minestom.item.ItemStack;
import java.io.UnsupportedEncodingException; import java.io.UnsupportedEncodingException;
@ -122,7 +121,11 @@ public class Utils {
} }
public static void writePosition(Buffer buffer, int x, int y, int z) { 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) { public static Position readPosition(Buffer buffer) {
@ -144,8 +147,8 @@ public class Utils {
} }
} }
public static void writeBlocks(Buffer buffer, Block[] blocks, int bitsPerEntry) { public static void writeBlocks(Buffer buffer, Short[] blocksId, int bitsPerEntry) {
buffer.putShort((short) Arrays.stream(blocks).filter(customBlock -> customBlock.getType() != 0).collect(Collectors.toList()).size()); buffer.putShort((short) Arrays.stream(blocksId).filter(customBlock -> customBlock != 0).collect(Collectors.toList()).size());
buffer.putByte((byte) bitsPerEntry); buffer.putByte((byte) bitsPerEntry);
int[] blocksData = new int[16 * 16 * 16]; int[] blocksData = new int[16 * 16 * 16];
for (int y = 0; y < 16; y++) { for (int y = 0; y < 16; y++) {
@ -153,7 +156,7 @@ public class Utils {
for (int z = 0; z < 16; z++) { for (int z = 0; z < 16; z++) {
int sectionIndex = (((y * 16) + x) * 16) + z; int sectionIndex = (((y * 16) + x) * 16) + z;
int index = y << 8 | z << 4 | x; int index = y << 8 | z << 4 | x;
blocksData[index] = blocks[sectionIndex].getType(); blocksData[index] = blocksId[sectionIndex];
} }
} }
} }