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() {
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()) {

View File

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

View File

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

View File

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

View File

@ -15,7 +15,7 @@ public class Chunk {
protected Set<Player> players = new CopyOnWriteArraySet<>();
private int chunkX, chunkZ;
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) {
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<Short, Block> getBlocks() {
public HashMap<Short, Short> getBlocks() {
return blocks;
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -17,6 +17,6 @@ public class ClientHeldItemChangePacket implements ClientPlayPacket {
@Override
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.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

View File

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

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

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) {
this.z = z;
}
@Override
public String toString() {
return "Position[" + x + ":" + y + ":" + z + "]";
}
}

View File

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