mirror of https://github.com/Minestom/Minestom.git
Update
This commit is contained in:
parent
8ddfdbb42a
commit
c407e384ab
|
@ -55,15 +55,16 @@ public class Main {
|
|||
public void onDisconnect(Server server, Connection connection) {
|
||||
System.out.println("A DISCONNECTION");
|
||||
if (packetProcessor.hasPlayerConnection(connection)) {
|
||||
if (connectionManager.getPlayer(packetProcessor.getPlayerConnection(connection)) != null) {
|
||||
Player player = connectionManager.getPlayer(packetProcessor.getPlayerConnection(connection));
|
||||
player.remove();
|
||||
Player player = connectionManager.getPlayer(packetProcessor.getPlayerConnection(connection));
|
||||
if (player != null) {
|
||||
|
||||
Instance instance = player.getInstance();
|
||||
if (instance != null) {
|
||||
instance.removeEntity(player);
|
||||
}
|
||||
|
||||
player.remove();
|
||||
|
||||
connectionManager.removePlayer(packetProcessor.getPlayerConnection(connection));
|
||||
}
|
||||
packetProcessor.removePlayerConnection(connection);
|
||||
|
@ -112,6 +113,7 @@ public class Main {
|
|||
|
||||
// Sleep until next tick
|
||||
long sleepTime = (tickDistance - (System.nanoTime() - currentTime)) / 1000000;
|
||||
sleepTime = Math.max(1, sleepTime);
|
||||
|
||||
//String perfMessage = "Online: " + getConnectionManager().getOnlinePlayers().size() + " Tick time: " + (TICK_MS - sleepTime) + " ms";
|
||||
//getConnectionManager().getOnlinePlayers().forEach(player -> player.sendMessage(perfMessage));
|
||||
|
|
|
@ -18,14 +18,30 @@ public interface Viewable {
|
|||
}
|
||||
|
||||
default void sendPacketToViewers(ServerPacket packet) {
|
||||
if (getViewers().isEmpty())
|
||||
return;
|
||||
|
||||
//Packet p = PacketUtils.writePacket(packet);
|
||||
getViewers().forEach(player -> player.getPlayerConnection().sendPacket(packet));
|
||||
}
|
||||
|
||||
default void sendPacketsToViewers(ServerPacket... packets) {
|
||||
getViewers().forEach(player -> {
|
||||
for (ServerPacket packet : packets)
|
||||
player.getPlayerConnection().sendPacket(packet);
|
||||
});
|
||||
if (getViewers().isEmpty())
|
||||
return;
|
||||
|
||||
for (ServerPacket packet : packets) {
|
||||
//Packet p = PacketUtils.writePacket(packet);
|
||||
getViewers().forEach(player -> player.getPlayerConnection().sendPacket(packet));
|
||||
}
|
||||
}
|
||||
|
||||
default void sendPacketToViewersAndSelf(ServerPacket packet) {
|
||||
if (this instanceof Player) {
|
||||
//Packet p = PacketUtils.writePacket(packet);
|
||||
((Player) this).getPlayerConnection().sendPacket(packet);
|
||||
if (!getViewers().isEmpty())
|
||||
getViewers().forEach(player -> player.getPlayerConnection().sendPacket(packet));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -93,6 +93,8 @@ public abstract class Entity implements Viewable {
|
|||
if (isChunkUnloaded(position.getX(), position.getZ()))
|
||||
return;
|
||||
|
||||
refreshPosition(position.getX(), position.getY(), position.getZ());
|
||||
refreshView(position.getYaw(), position.getPitch());
|
||||
EntityTeleportPacket entityTeleportPacket = new EntityTeleportPacket();
|
||||
entityTeleportPacket.entityId = getEntityId();
|
||||
entityTeleportPacket.position = position;
|
||||
|
@ -289,13 +291,21 @@ public abstract class Entity implements Viewable {
|
|||
this.scheduledRemoveTime = System.currentTimeMillis() + delay;
|
||||
}
|
||||
|
||||
public EntityMetaDataPacket getMetadataPacket() {
|
||||
EntityMetaDataPacket metaDataPacket = new EntityMetaDataPacket();
|
||||
metaDataPacket.entityId = getEntityId();
|
||||
metaDataPacket.data = getMetadataBuffer();
|
||||
return metaDataPacket;
|
||||
}
|
||||
|
||||
public Buffer getMetadataBuffer() {
|
||||
Buffer buffer = Buffer.create();
|
||||
fillMetadataIndex(buffer, 0);
|
||||
fillMetadataIndex(buffer, 1);
|
||||
return buffer;
|
||||
}
|
||||
|
||||
protected void sendMetadata(int index) {
|
||||
private void sendMetadata(int index) {
|
||||
Buffer buffer = Buffer.create();
|
||||
fillMetadataIndex(buffer, index);
|
||||
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
package fr.themode.minestom.entity;
|
||||
|
||||
import fr.themode.minestom.net.packet.server.play.EntityMetaDataPacket;
|
||||
import fr.themode.minestom.net.packet.server.play.EntityPacket;
|
||||
import fr.themode.minestom.net.packet.server.play.EntityRelativeMovePacket;
|
||||
import fr.themode.minestom.net.packet.server.play.SpawnMobPacket;
|
||||
|
@ -51,11 +50,8 @@ public abstract class EntityCreature extends LivingEntity {
|
|||
spawnMobPacket.entityType = getEntityType();
|
||||
spawnMobPacket.position = getPosition();
|
||||
spawnMobPacket.headPitch = 0;
|
||||
EntityMetaDataPacket entityMetaDataPacket = new EntityMetaDataPacket();
|
||||
entityMetaDataPacket.entityId = getEntityId();
|
||||
entityMetaDataPacket.data = getMetadataBuffer();
|
||||
playerConnection.sendPacket(entityPacket);
|
||||
playerConnection.sendPacket(spawnMobPacket);
|
||||
playerConnection.sendPacket(entityMetaDataPacket);
|
||||
playerConnection.sendPacket(getMetadataPacket());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,6 +17,7 @@ public class EntityManager {
|
|||
private ExecutorService creaturesPool = Executors.newFixedThreadPool(2);
|
||||
private ExecutorService playersPool = Executors.newFixedThreadPool(2);
|
||||
|
||||
// TODO API for custom thread division (
|
||||
public void update() {
|
||||
for (Instance instance : instanceManager.getInstances()) {
|
||||
testTick2(instance); // TODO optimize update engine for when there are too many entities on one chunk
|
||||
|
|
|
@ -1,12 +1,40 @@
|
|||
package fr.themode.minestom.entity;
|
||||
|
||||
import fr.adamaq01.ozao.net.Buffer;
|
||||
|
||||
// TODO attributes https://wiki.vg/Protocol#Entity_Properties
|
||||
public abstract class LivingEntity extends Entity {
|
||||
|
||||
protected boolean onGround;
|
||||
|
||||
private boolean isHandActive;
|
||||
private boolean activeHand;
|
||||
private boolean riptideSpinAttack;
|
||||
|
||||
public LivingEntity(int entityType) {
|
||||
super(entityType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Buffer getMetadataBuffer() {
|
||||
Buffer buffer = super.getMetadataBuffer();
|
||||
buffer.putByte((byte) 7);
|
||||
buffer.putByte(METADATA_BYTE);
|
||||
byte activeHandValue = 0;
|
||||
if (isHandActive) {
|
||||
activeHandValue += 1;
|
||||
if (activeHand)
|
||||
activeHandValue += 2;
|
||||
if (riptideSpinAttack)
|
||||
activeHandValue += 4;
|
||||
}
|
||||
buffer.putByte(activeHandValue);
|
||||
return buffer;
|
||||
}
|
||||
|
||||
public void refreshActiveHand(boolean isHandActive, boolean offHand, boolean riptideSpinAttack) {
|
||||
this.isHandActive = isHandActive;
|
||||
this.activeHand = offHand;
|
||||
this.riptideSpinAttack = riptideSpinAttack;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
package fr.themode.minestom.entity;
|
||||
|
||||
import fr.themode.minestom.Viewable;
|
||||
import fr.themode.minestom.net.packet.server.play.EntityMetaDataPacket;
|
||||
import fr.themode.minestom.net.packet.server.play.SpawnObjectPacket;
|
||||
import fr.themode.minestom.net.player.PlayerConnection;
|
||||
|
||||
|
@ -21,7 +20,7 @@ public abstract class ObjectEntity extends Entity implements Viewable {
|
|||
|
||||
@Override
|
||||
public void addViewer(Player player) {
|
||||
this.viewers.add(player);
|
||||
super.addViewer(player);
|
||||
PlayerConnection playerConnection = player.getPlayerConnection();
|
||||
|
||||
SpawnObjectPacket spawnObjectPacket = new SpawnObjectPacket();
|
||||
|
@ -30,16 +29,13 @@ public abstract class ObjectEntity extends Entity implements Viewable {
|
|||
spawnObjectPacket.type = getEntityType();
|
||||
spawnObjectPacket.position = getPosition();
|
||||
spawnObjectPacket.data = getData();
|
||||
EntityMetaDataPacket entityMetaDataPacket = new EntityMetaDataPacket();
|
||||
entityMetaDataPacket.entityId = getEntityId();
|
||||
entityMetaDataPacket.data = getMetadataBuffer();
|
||||
playerConnection.sendPacket(spawnObjectPacket);
|
||||
playerConnection.sendPacket(entityMetaDataPacket);
|
||||
playerConnection.sendPacket(getMetadataPacket());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeViewer(Player player) {
|
||||
this.viewers.remove(player);
|
||||
super.removeViewer(player);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -3,6 +3,7 @@ package fr.themode.minestom.entity;
|
|||
import fr.themode.minestom.bossbar.BossBar;
|
||||
import fr.themode.minestom.chat.Chat;
|
||||
import fr.themode.minestom.event.AttackEvent;
|
||||
import fr.themode.minestom.event.BlockPlaceEvent;
|
||||
import fr.themode.minestom.event.PickupItemEvent;
|
||||
import fr.themode.minestom.instance.Chunk;
|
||||
import fr.themode.minestom.instance.CustomBlock;
|
||||
|
@ -43,6 +44,7 @@ public class Player extends LivingEntity {
|
|||
private CustomBlock targetCustomBlock;
|
||||
private BlockPosition targetBlockPosition;
|
||||
private long targetBlockTime;
|
||||
private byte targetLastStage;
|
||||
|
||||
private Set<BossBar> bossBars = new CopyOnWriteArraySet<>();
|
||||
|
||||
|
@ -91,6 +93,10 @@ public class Player extends LivingEntity {
|
|||
updateHealthPacket.foodSaturation = 0;
|
||||
playerConnection.sendPacket(updateHealthPacket);*/
|
||||
});
|
||||
|
||||
setEventCallback(BlockPlaceEvent.class, event -> {
|
||||
sendMessage("Placed block!");
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -108,7 +114,10 @@ public class Player extends LivingEntity {
|
|||
int animationCount = 10;
|
||||
long since = System.currentTimeMillis() - targetBlockTime;
|
||||
byte stage = (byte) (since / (timeBreak / animationCount));
|
||||
sendBlockBreakAnimation(targetBlockPosition, stage);// TODO send to all near players
|
||||
if (stage != targetLastStage) {
|
||||
sendBlockBreakAnimation(targetBlockPosition, stage);
|
||||
}
|
||||
this.targetLastStage = stage;
|
||||
if (stage > 9) {
|
||||
instance.breakBlock(this, targetBlockPosition, targetCustomBlock);
|
||||
resetTargetBlock();
|
||||
|
@ -138,8 +147,7 @@ public class Player extends LivingEntity {
|
|||
collectItemPacket.collectedEntityId = itemEntity.getEntityId();
|
||||
collectItemPacket.collectorEntityId = getEntityId();
|
||||
collectItemPacket.pickupItemCount = item.getAmount();
|
||||
playerConnection.sendPacket(collectItemPacket);
|
||||
sendPacketToViewers(collectItemPacket);
|
||||
sendPacketToViewersAndSelf(collectItemPacket);
|
||||
objectEntity.remove();
|
||||
}
|
||||
});
|
||||
|
@ -220,7 +228,7 @@ public class Player extends LivingEntity {
|
|||
for (Player viewer : getViewers()) {
|
||||
EntityTeleportPacket teleportPacket = new EntityTeleportPacket();
|
||||
teleportPacket.entityId = viewer.getEntityId();
|
||||
teleportPacket.position = getPosition();
|
||||
teleportPacket.position = viewer.getPosition();
|
||||
teleportPacket.onGround = viewer.onGround;
|
||||
playerConnection.sendPacket(teleportPacket);
|
||||
}
|
||||
|
@ -264,8 +272,7 @@ public class Player extends LivingEntity {
|
|||
breakAnimationPacket.entityId = getEntityId() + 1;
|
||||
breakAnimationPacket.blockPosition = blockPosition;
|
||||
breakAnimationPacket.destroyStage = destroyStage;
|
||||
playerConnection.sendPacket(breakAnimationPacket);
|
||||
sendPacketToViewers(breakAnimationPacket);
|
||||
sendPacketToViewersAndSelf(breakAnimationPacket);
|
||||
}
|
||||
|
||||
public void sendMessage(String message) {
|
||||
|
@ -275,13 +282,16 @@ public class Player extends LivingEntity {
|
|||
|
||||
@Override
|
||||
public void teleport(Position position) {
|
||||
if (isChunkUnloaded(position.getX(), position.getZ()))
|
||||
return;
|
||||
|
||||
refreshPosition(position.getX(), position.getY(), position.getZ());
|
||||
refreshView(position.getYaw(), position.getPitch());
|
||||
PlayerPositionAndLookPacket positionAndLookPacket = new PlayerPositionAndLookPacket();
|
||||
positionAndLookPacket.position = position;
|
||||
positionAndLookPacket.flags = 0x00;
|
||||
positionAndLookPacket.teleportId = 67;
|
||||
getPlayerConnection().sendPacket(positionAndLookPacket);
|
||||
playerConnection.sendPacket(positionAndLookPacket);
|
||||
}
|
||||
|
||||
public String getUsername() {
|
||||
|
|
|
@ -1,14 +1,22 @@
|
|||
package fr.themode.minestom.event;
|
||||
|
||||
import fr.themode.minestom.utils.BlockPosition;
|
||||
|
||||
public class BlockPlaceEvent extends CancellableEvent {
|
||||
|
||||
private short blockId;
|
||||
private BlockPosition blockPosition;
|
||||
|
||||
public BlockPlaceEvent(short blockId) {
|
||||
public BlockPlaceEvent(short blockId, BlockPosition blockPosition) {
|
||||
this.blockId = blockId;
|
||||
this.blockPosition = blockPosition;
|
||||
}
|
||||
|
||||
public short getBlockId() {
|
||||
return blockId;
|
||||
}
|
||||
|
||||
public BlockPosition getBlockPosition() {
|
||||
return blockPosition;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -55,14 +55,14 @@ public class BlockBatch implements BlockModifier {
|
|||
for (Map.Entry<Chunk, List<BlockData>> entry : data.entrySet()) {
|
||||
Chunk chunk = entry.getKey();
|
||||
List<BlockData> dataList = entry.getValue();
|
||||
synchronized (chunk) {
|
||||
batchesPool.submit(() -> {
|
||||
batchesPool.submit(() -> {
|
||||
synchronized (chunk) {
|
||||
for (BlockData data : dataList) {
|
||||
data.apply(chunk);
|
||||
}
|
||||
instance.sendChunkUpdate(chunk); // TODO partial chunk data
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,8 +1,19 @@
|
|||
package fr.themode.minestom.instance;
|
||||
|
||||
import fr.themode.minestom.utils.BlockPosition;
|
||||
|
||||
public interface BlockModifier {
|
||||
|
||||
void setBlock(int x, int y, int z, short blockId);
|
||||
|
||||
void setBlock(int x, int y, int z, String blockId);
|
||||
|
||||
default void setBlock(BlockPosition blockPosition, short blockId) {
|
||||
setBlock(blockPosition.getX(), blockPosition.getY(), blockPosition.getZ(), blockId);
|
||||
}
|
||||
|
||||
default void setBlock(BlockPosition blockPosition, String blockId) {
|
||||
setBlock(blockPosition.getX(), blockPosition.getY(), blockPosition.getZ(), blockId);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -23,6 +23,9 @@ public class Chunk {
|
|||
private short[] blocksId = new short[CHUNK_SIZE];
|
||||
private short[] customBlocks = new short[CHUNK_SIZE];
|
||||
|
||||
// Block entities
|
||||
private Set<Integer> blockEntities = new CopyOnWriteArraySet<>();
|
||||
|
||||
public Chunk(Biome biome, int chunkX, int chunkZ) {
|
||||
this.biome = biome;
|
||||
this.chunkX = chunkX;
|
||||
|
@ -30,9 +33,7 @@ public class Chunk {
|
|||
}
|
||||
|
||||
protected void setBlock(byte x, byte y, byte z, short blockId) {
|
||||
int index = getIndex(x, y, z);
|
||||
this.blocksId[index] = blockId;
|
||||
this.customBlocks[index] = 0;
|
||||
setBlock(x, y, z, blockId, (short) 0);
|
||||
}
|
||||
|
||||
protected void setBlock(byte x, byte y, byte z, String blockId) {
|
||||
|
@ -40,9 +41,18 @@ public class Chunk {
|
|||
if (customBlock == null)
|
||||
throw new IllegalArgumentException("The block " + blockId + " does not exist or isn't registered");
|
||||
|
||||
setBlock(x, y, z, customBlock.getType(), customBlock.getId());
|
||||
}
|
||||
|
||||
private void setBlock(byte x, byte y, byte z, short blockType, short customId) {
|
||||
int index = getIndex(x, y, z);
|
||||
this.blocksId[index] = customBlock.getType();
|
||||
this.customBlocks[index] = customBlock.getId();
|
||||
this.blocksId[index] = blockType;
|
||||
this.customBlocks[index] = customId;
|
||||
if (isBlockEntity(blockType)) {
|
||||
blockEntities.add(index);
|
||||
} else {
|
||||
blockEntities.remove(index);
|
||||
}
|
||||
}
|
||||
|
||||
public short getBlockId(byte x, byte y, byte z) {
|
||||
|
@ -120,6 +130,15 @@ public class Chunk {
|
|||
return Collections.unmodifiableSet(players);
|
||||
}
|
||||
|
||||
private boolean isBlockEntity(short blockId) {
|
||||
// TODO complete
|
||||
return blockId == 2033;
|
||||
}
|
||||
|
||||
public Set<Integer> getBlockEntities() {
|
||||
return blockEntities;
|
||||
}
|
||||
|
||||
private int getIndex(byte x, byte y, byte z) {
|
||||
short index = (short) (x & 0x000F);
|
||||
index |= (y << 4) & 0x0FF0;
|
||||
|
|
|
@ -60,7 +60,7 @@ public class Instance implements BlockModifier {
|
|||
int y = blockPosition.getY();
|
||||
int z = blockPosition.getZ();
|
||||
setBlock(x, y, z, (short) 0);
|
||||
ParticlePacket particlePacket = new ParticlePacket(); // TODO change by a proper particle API
|
||||
ParticlePacket particlePacket = new ParticlePacket(); // TODO change to a proper particle API
|
||||
particlePacket.particleId = 3; // Block particle
|
||||
particlePacket.longDistance = false;
|
||||
particlePacket.x = x + 0.5f;
|
||||
|
@ -107,7 +107,7 @@ public class Instance implements BlockModifier {
|
|||
}
|
||||
|
||||
public Chunk getChunk(int chunkX, int chunkZ) {
|
||||
return chunks.getOrDefault(getChunkKey(chunkX, chunkZ), null);
|
||||
return chunks.get(getChunkKey(chunkX, chunkZ));
|
||||
}
|
||||
|
||||
public Chunk getChunkAt(double x, double z) {
|
||||
|
@ -144,6 +144,7 @@ public class Instance implements BlockModifier {
|
|||
if (entity instanceof Player) {
|
||||
Player player = (Player) entity;
|
||||
sendChunks(player);
|
||||
getObjectEntities().forEach(objectEntity -> objectEntity.addViewer(player));
|
||||
getCreatures().forEach(entityCreature -> entityCreature.addViewer(player));
|
||||
getPlayers().forEach(p -> p.addViewer(player));
|
||||
}
|
||||
|
@ -164,6 +165,13 @@ public class Instance implements BlockModifier {
|
|||
destroyEntitiesPacket.entityIds = new int[]{entity.getEntityId()};
|
||||
|
||||
entity.getViewers().forEach(p -> p.getPlayerConnection().sendPacket(destroyEntitiesPacket)); // TODO destroy batch
|
||||
} else {
|
||||
// TODO optimize (cache all entities that the player see)
|
||||
Player player = (Player) entity;
|
||||
getObjectEntities().forEach(objectEntity -> objectEntity.removeViewer(player));
|
||||
getCreatures().forEach(entityCreature -> entityCreature.removeViewer(player));
|
||||
getPlayers().forEach(p -> p.removeViewer(player));
|
||||
|
||||
}
|
||||
|
||||
Chunk chunk = getChunkAt(entity.getPosition());
|
||||
|
@ -190,7 +198,7 @@ public class Instance implements BlockModifier {
|
|||
ChunkDataPacket chunkDataPacket = new ChunkDataPacket();
|
||||
chunkDataPacket.fullChunk = false;
|
||||
chunkDataPacket.chunk = chunk;
|
||||
player.getPlayerConnection().sendPacket(chunkDataPacket);
|
||||
player.getPlayerConnection().sendPacket(chunkDataPacket); // TODO write packet buffer in another thread (Chunk packets are heavy)
|
||||
}
|
||||
|
||||
protected Chunk createChunk(int chunkX, int chunkZ) {
|
||||
|
@ -216,7 +224,7 @@ public class Instance implements BlockModifier {
|
|||
ChunkDataPacket chunkDataPacket = new ChunkDataPacket();
|
||||
chunkDataPacket.fullChunk = false;
|
||||
chunkDataPacket.chunk = chunk;
|
||||
getPlayers().forEach(player -> player.getPlayerConnection().sendPacket(chunkDataPacket));
|
||||
getPlayers().forEach(player -> player.getPlayerConnection().sendPacket(chunkDataPacket)); // TODO write packet buffer in another thread (Chunk packets are heavy)
|
||||
}
|
||||
|
||||
private void sendChunks(Player player) {
|
||||
|
@ -224,7 +232,7 @@ public class Instance implements BlockModifier {
|
|||
chunkDataPacket.fullChunk = true;
|
||||
for (Chunk chunk : getChunks()) {
|
||||
chunkDataPacket.chunk = chunk;
|
||||
player.getPlayerConnection().sendPacket(chunkDataPacket);
|
||||
player.getPlayerConnection().sendPacket(chunkDataPacket); // TODO write packet buffer in another thread (Chunk packets are heavy)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -14,7 +14,7 @@ public class ChunkGeneratorDemo extends ChunkGenerator {
|
|||
public void generateChunkData(ChunkBatch batch, int chunkX, int chunkZ) {
|
||||
for (byte x = 0; x < 16; x++)
|
||||
for (byte z = 0; z < 16; z++) {
|
||||
if (random.nextInt(2) == 1) {
|
||||
if (random.nextInt(10) > 5) {
|
||||
batch.setBlock(x, (byte) 4, z, (short) 10);
|
||||
} else {
|
||||
batch.setBlock(x, (byte) 4, z, "custom_block");
|
||||
|
|
|
@ -7,7 +7,7 @@ public class StoneBlock extends CustomBlock {
|
|||
|
||||
@Override
|
||||
public short getType() {
|
||||
return 117;
|
||||
return 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -4,35 +4,61 @@ public class ItemStack {
|
|||
|
||||
public static final ItemStack AIR_ITEM = new ItemStack(0, (byte) 1);
|
||||
|
||||
private int itemId;
|
||||
private Material material;
|
||||
private byte amount;
|
||||
|
||||
public ItemStack(int itemId, byte amount) {
|
||||
this.itemId = itemId;
|
||||
private String displayName;
|
||||
private boolean unbreakable;
|
||||
|
||||
public ItemStack(Material material, byte amount) {
|
||||
this.material = material;
|
||||
this.amount = amount;
|
||||
}
|
||||
|
||||
public ItemStack(int id, byte amount) {
|
||||
this(Material.fromId(id), amount);
|
||||
}
|
||||
|
||||
public boolean isAir() {
|
||||
return itemId == 0;
|
||||
return material == Material.AIR;
|
||||
}
|
||||
|
||||
public boolean isSimilar(ItemStack itemStack) {
|
||||
return itemStack.getItemId() == itemId;
|
||||
return itemStack.getMaterial() == material && itemStack.getDisplayName() == displayName && itemStack.isUnbreakable() == unbreakable;
|
||||
}
|
||||
|
||||
public byte getAmount() {
|
||||
return amount;
|
||||
}
|
||||
|
||||
public int getItemId() {
|
||||
return itemId;
|
||||
public Material getMaterial() {
|
||||
return material;
|
||||
}
|
||||
|
||||
public void setAmount(byte amount) {
|
||||
this.amount = amount;
|
||||
}
|
||||
|
||||
public String getDisplayName() {
|
||||
return displayName;
|
||||
}
|
||||
|
||||
public void setDisplayName(String displayName) {
|
||||
this.displayName = displayName;
|
||||
}
|
||||
|
||||
public boolean isUnbreakable() {
|
||||
return unbreakable;
|
||||
}
|
||||
|
||||
public void setUnbreakable(boolean unbreakable) {
|
||||
this.unbreakable = unbreakable;
|
||||
}
|
||||
|
||||
public ItemStack clone() {
|
||||
return new ItemStack(itemId, amount);
|
||||
ItemStack itemStack = new ItemStack(material, amount);
|
||||
itemStack.setDisplayName(displayName);
|
||||
itemStack.setUnbreakable(unbreakable);
|
||||
return itemStack;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,42 @@
|
|||
package fr.themode.minestom.item;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public enum Material {
|
||||
|
||||
AIR(0),
|
||||
STONE(1),
|
||||
BOW(525),
|
||||
ARROW(526);
|
||||
|
||||
private static Map<Integer, Material> idToMaterial = new HashMap<>();
|
||||
|
||||
static {
|
||||
for (Material material : values()) {
|
||||
idToMaterial.put(material.id, material);
|
||||
}
|
||||
}
|
||||
|
||||
private int id;
|
||||
|
||||
Material(int id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public static Material fromId(int id) {
|
||||
return idToMaterial.get(id);
|
||||
}
|
||||
|
||||
public boolean isBlock() {
|
||||
return false; // TODO
|
||||
}
|
||||
|
||||
public boolean isFood() {
|
||||
return false; // TODO
|
||||
}
|
||||
|
||||
public int getId() {
|
||||
return id;
|
||||
}
|
||||
}
|
|
@ -22,24 +22,17 @@ public class BlockPlacementListener {
|
|||
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;
|
||||
|
||||
BlockPlaceEvent blockPlaceEvent = new BlockPlaceEvent((short) 10);
|
||||
blockPosition.add(offsetX, offsetY, offsetZ);
|
||||
BlockPlaceEvent blockPlaceEvent = new BlockPlaceEvent((short) 10, blockPosition);
|
||||
player.callEvent(BlockPlaceEvent.class, blockPlaceEvent);
|
||||
if (!blockPlaceEvent.isCancelled()) {
|
||||
instance.setBlock(blockPosition.getX() + offsetX, blockPosition.getY() + offsetY, blockPosition.getZ() + offsetZ, "custom_block");
|
||||
instance.setBlock(blockPosition, "custom_block");
|
||||
// TODO consume block in hand for survival players
|
||||
} else {
|
||||
Chunk chunk = instance.getChunkAt(blockPosition);
|
||||
instance.sendChunkUpdate(player, chunk);
|
||||
}
|
||||
player.getInventory().refreshSlot(player.getHeldSlot());
|
||||
/*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();*/
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -57,6 +57,11 @@ public class PlayerDiggingListener {
|
|||
}
|
||||
}
|
||||
break;
|
||||
case UPDATE_ITEM_STATE:
|
||||
// TODO check if is updatable item
|
||||
//player.refreshActiveHand(false, false, false);
|
||||
//player.sendPacketToViewers(player.getMetadataPacket());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -13,6 +13,12 @@ public class UseItemListener {
|
|||
Player.Hand hand = packet.hand;
|
||||
ItemStack itemStack = hand == Player.Hand.MAIN ? inventory.getItemInMainHand() : inventory.getItemInOffHand();
|
||||
UseItemEvent useItemEvent = new UseItemEvent(hand, itemStack);
|
||||
player.callEvent(UseItemEvent.class, useItemEvent);
|
||||
|
||||
// TODO check if item in main or off hand is food or item with animation (bow/crossbow/riptide)
|
||||
// TODO in material enum?
|
||||
//player.refreshActiveHand(true, false, false);
|
||||
//player.sendPacketToViewers(player.getMetadataPacket());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -45,7 +45,7 @@ public class PacketProcessor {
|
|||
public void process(Connection connection, Packet packet) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
|
||||
int id = packet.get(PACKET_ID_IDENTIFIER);
|
||||
if (!printBlackList.contains(id)) {
|
||||
System.out.println("RECEIVED ID: " + id);
|
||||
//System.out.println("RECEIVED ID: 0x" + Integer.toHexString(id));
|
||||
}
|
||||
Buffer buffer = packet.getPayload();
|
||||
connectionPlayerConnectionMap.get(connection);
|
||||
|
|
|
@ -13,6 +13,7 @@ import fr.themode.minestom.instance.Instance;
|
|||
import fr.themode.minestom.instance.demo.ChunkGeneratorDemo;
|
||||
import fr.themode.minestom.inventory.PlayerInventory;
|
||||
import fr.themode.minestom.item.ItemStack;
|
||||
import fr.themode.minestom.item.Material;
|
||||
import fr.themode.minestom.net.ConnectionManager;
|
||||
import fr.themode.minestom.net.ConnectionState;
|
||||
import fr.themode.minestom.net.packet.client.ClientPreplayPacket;
|
||||
|
@ -30,17 +31,12 @@ import java.util.UUID;
|
|||
|
||||
public class LoginStartPacket implements ClientPreplayPacket {
|
||||
|
||||
private String username;
|
||||
|
||||
// Test
|
||||
private static Instance instance;
|
||||
|
||||
static {
|
||||
ChunkGeneratorDemo chunkGeneratorDemo = new ChunkGeneratorDemo();
|
||||
instance = Main.getInstanceManager().createInstance();
|
||||
instance.setChunkGenerator(chunkGeneratorDemo);
|
||||
int loopStart = -4;
|
||||
int loopEnd = 4;
|
||||
int loopStart = -2;
|
||||
int loopEnd = 2;
|
||||
long time = System.currentTimeMillis();
|
||||
for (int x = loopStart; x < loopEnd; x++)
|
||||
for (int z = loopStart; z < loopEnd; z++) {
|
||||
|
@ -49,6 +45,11 @@ public class LoginStartPacket implements ClientPreplayPacket {
|
|||
System.out.println("Time to load all chunks: " + (System.currentTimeMillis() - time) + " ms");
|
||||
}
|
||||
|
||||
// Test
|
||||
private static Instance instance;
|
||||
|
||||
public String username;
|
||||
|
||||
@Override
|
||||
public void process(PlayerConnection connection, ConnectionManager connectionManager) {
|
||||
String property = "eyJ0aW1lc3RhbXAiOjE1NjU0ODMwODQwOTYsInByb2ZpbGVJZCI6ImFiNzBlY2I0MjM0NjRjMTRhNTJkN2EwOTE1MDdjMjRlIiwicHJvZmlsZU5hbWUiOiJUaGVNb2RlOTExIiwidGV4dHVyZXMiOnsiU0tJTiI6eyJ1cmwiOiJodHRwOi8vdGV4dHVyZXMubWluZWNyYWZ0Lm5ldC90ZXh0dXJlL2RkOTE2NzJiNTE0MmJhN2Y3MjA2ZTRjN2IwOTBkNzhlM2Y1ZDc2NDdiNWFmZDIyNjFhZDk4OGM0MWI2ZjcwYTEifX19";
|
||||
|
@ -128,16 +129,15 @@ public class LoginStartPacket implements ClientPreplayPacket {
|
|||
}
|
||||
|
||||
PlayerInventory inventory = player.getInventory();
|
||||
for (int i = 0; i < 20; i++) {
|
||||
inventory.addItemStack(new ItemStack(1, (byte) 64));
|
||||
}
|
||||
inventory.addItemStack(new ItemStack(Material.BOW, (byte) 1));
|
||||
inventory.addItemStack(new ItemStack(Material.ARROW, (byte) 100));
|
||||
|
||||
/*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));*/
|
||||
|
||||
BossBar bossBar = new BossBar("Le titre", BarColor.BLUE, BarDivision.SEGMENT_12);
|
||||
BossBar bossBar = new BossBar("Bossbar Title", BarColor.BLUE, BarDivision.SEGMENT_12);
|
||||
bossBar.setProgress(0.75f);
|
||||
bossBar.addViewer(player);
|
||||
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
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.BlockPosition;
|
||||
import fr.themode.minestom.utils.Utils;
|
||||
|
||||
public class BlockActionPacket implements ServerPacket {
|
||||
|
||||
public BlockPosition blockPosition;
|
||||
public byte actionId;
|
||||
public byte actionParam;
|
||||
public int blockId;
|
||||
|
||||
@Override
|
||||
public void write(Buffer buffer) {
|
||||
Utils.writePosition(buffer, blockPosition);
|
||||
buffer.putByte(actionId);
|
||||
buffer.putByte(actionParam);
|
||||
Utils.writeVarInt(buffer, blockId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getId() {
|
||||
return 0x0A;
|
||||
}
|
||||
}
|
|
@ -3,13 +3,16 @@ package fr.themode.minestom.net.packet.server.play;
|
|||
import fr.adamaq01.ozao.net.Buffer;
|
||||
import fr.themode.minestom.instance.Chunk;
|
||||
import fr.themode.minestom.net.packet.server.ServerPacket;
|
||||
import fr.themode.minestom.utils.BlockPosition;
|
||||
import fr.themode.minestom.utils.Utils;
|
||||
import net.querz.nbt.CompoundTag;
|
||||
import net.querz.nbt.DoubleTag;
|
||||
import net.querz.nbt.LongArrayTag;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.Set;
|
||||
|
||||
public class ChunkDataPacket implements ServerPacket {
|
||||
|
||||
|
@ -55,21 +58,43 @@ public class ChunkDataPacket implements ServerPacket {
|
|||
worldSurface[x + z * 16] = 5;
|
||||
}
|
||||
}
|
||||
CompoundTag compound = new CompoundTag();
|
||||
compound.put("MOTION_BLOCKING", new LongArrayTag(Utils.encodeBlocks(motionBlocking, 9)));
|
||||
compound.put("WORLD_SURFACE", new LongArrayTag(Utils.encodeBlocks(worldSurface, 9)));
|
||||
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
|
||||
try {
|
||||
compound.serialize(new DataOutputStream(outputStream), 100);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
|
||||
{
|
||||
CompoundTag compound = new CompoundTag();
|
||||
compound.put("MOTION_BLOCKING", new LongArrayTag(Utils.encodeBlocks(motionBlocking, 9)));
|
||||
compound.put("WORLD_SURFACE", new LongArrayTag(Utils.encodeBlocks(worldSurface, 9)));
|
||||
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
|
||||
try {
|
||||
compound.serialize(new DataOutputStream(outputStream), 100);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
byte[] data = outputStream.toByteArray();
|
||||
buffer.putBytes(data);
|
||||
}
|
||||
byte[] data = outputStream.toByteArray();
|
||||
buffer.putBytes(data);
|
||||
|
||||
Utils.writeVarInt(buffer, blocks.length());
|
||||
buffer.putBuffer(blocks);
|
||||
Utils.writeVarInt(buffer, 0);
|
||||
|
||||
// Block entities
|
||||
Set<Integer> blockEntities = chunk.getBlockEntities();
|
||||
Utils.writeVarInt(buffer, blockEntities.size());
|
||||
|
||||
for (Integer index : blockEntities) {
|
||||
BlockPosition blockPosition = indexToBlockPosition(index);
|
||||
CompoundTag blockEntity = new CompoundTag();
|
||||
blockEntity.put("x", new DoubleTag(blockPosition.getX()));
|
||||
blockEntity.put("y", new DoubleTag(blockPosition.getY()));
|
||||
blockEntity.put("z", new DoubleTag(blockPosition.getZ()));
|
||||
ByteArrayOutputStream os = new ByteArrayOutputStream();
|
||||
try {
|
||||
blockEntity.serialize(new DataOutputStream(os), 100);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
byte[] d = os.toByteArray();
|
||||
buffer.putBytes(d);
|
||||
}
|
||||
}
|
||||
|
||||
private short[] getSection(Chunk chunk, int section) {
|
||||
|
@ -85,6 +110,13 @@ public class ChunkDataPacket implements ServerPacket {
|
|||
return blocks;
|
||||
}
|
||||
|
||||
private BlockPosition indexToBlockPosition(int index) {
|
||||
byte z = (byte) (index >> 12 & 0xF);
|
||||
byte y = (byte) (index >> 4 & 0xFF);
|
||||
byte x = (byte) (index >> 0 & 0xF);
|
||||
return new BlockPosition(x + 16 * chunk.getChunkX(), y, z + 16 * chunk.getChunkZ());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getId() {
|
||||
return 0x21;
|
||||
|
|
|
@ -1,12 +1,10 @@
|
|||
package fr.themode.minestom.net.player;
|
||||
|
||||
import fr.adamaq01.ozao.net.Buffer;
|
||||
import fr.adamaq01.ozao.net.packet.Packet;
|
||||
import fr.adamaq01.ozao.net.server.Connection;
|
||||
import fr.themode.minestom.net.ConnectionState;
|
||||
import fr.themode.minestom.net.packet.server.ServerPacket;
|
||||
|
||||
import static fr.themode.minestom.net.protocol.MinecraftProtocol.PACKET_ID_IDENTIFIER;
|
||||
import fr.themode.minestom.utils.PacketUtils;
|
||||
|
||||
public class PlayerConnection {
|
||||
|
||||
|
@ -18,15 +16,14 @@ public class PlayerConnection {
|
|||
this.connectionState = ConnectionState.UNKNOWN;
|
||||
}
|
||||
|
||||
public void sendPacket(ServerPacket serverPacket) {
|
||||
Packet packet = Packet.create();
|
||||
Buffer buffer = packet.getPayload();
|
||||
serverPacket.write(buffer);
|
||||
packet.put(PACKET_ID_IDENTIFIER, serverPacket.getId());
|
||||
|
||||
public void sendPacket(Packet packet) {
|
||||
this.connection.sendPacket(packet);
|
||||
}
|
||||
|
||||
public void sendPacket(ServerPacket serverPacket) {
|
||||
sendPacket(PacketUtils.writePacket(serverPacket));
|
||||
}
|
||||
|
||||
public Connection getConnection() {
|
||||
return connection;
|
||||
}
|
||||
|
|
|
@ -10,6 +10,12 @@ public class BlockPosition {
|
|||
this.z = z;
|
||||
}
|
||||
|
||||
public void add(int x, int y, int z) {
|
||||
this.x += x;
|
||||
this.y += y;
|
||||
this.z += z;
|
||||
}
|
||||
|
||||
public int getX() {
|
||||
return x;
|
||||
}
|
||||
|
@ -34,6 +40,7 @@ public class BlockPosition {
|
|||
this.z = z;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Position[" + x + ":" + y + ":" + z + "]";
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
package fr.themode.minestom.utils;
|
||||
|
||||
import fr.adamaq01.ozao.net.Buffer;
|
||||
import fr.adamaq01.ozao.net.packet.Packet;
|
||||
import fr.themode.minestom.net.packet.server.ServerPacket;
|
||||
|
||||
import static fr.themode.minestom.net.protocol.MinecraftProtocol.PACKET_ID_IDENTIFIER;
|
||||
|
||||
public class PacketUtils {
|
||||
|
||||
public static Packet writePacket(ServerPacket serverPacket) {
|
||||
int id = serverPacket.getId();
|
||||
Packet packet = Packet.create();
|
||||
Buffer buffer = packet.getPayload();
|
||||
serverPacket.write(buffer);
|
||||
/*if (id != 40 && id != 64)
|
||||
System.out.println("ID: 0x" + Integer.toHexString(id));*/
|
||||
packet.put(PACKET_ID_IDENTIFIER, id);
|
||||
return packet;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,6 +1,7 @@
|
|||
package fr.themode.minestom.utils;
|
||||
|
||||
import fr.adamaq01.ozao.net.Buffer;
|
||||
import fr.themode.minestom.chat.Chat;
|
||||
import fr.themode.minestom.item.ItemStack;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
|
@ -145,10 +146,39 @@ public class Utils {
|
|||
buffer.putBoolean(false);
|
||||
} else {
|
||||
buffer.putBoolean(true);
|
||||
Utils.writeVarInt(buffer, itemStack.getItemId());
|
||||
Utils.writeVarInt(buffer, itemStack.getMaterial().getId());
|
||||
buffer.putByte(itemStack.getAmount());
|
||||
|
||||
buffer.putByte((byte) 0x0A); // Compound
|
||||
buffer.putShort((short) 0);
|
||||
|
||||
// Unbreakable
|
||||
if (itemStack.isUnbreakable()) {
|
||||
buffer.putByte((byte) 0x03); // Integer
|
||||
buffer.putString("Unbreakable");
|
||||
buffer.putInt(1);
|
||||
}
|
||||
|
||||
// Display
|
||||
buffer.putByte((byte) 0x0A); // Compound
|
||||
buffer.putString("display");
|
||||
|
||||
if (itemStack.getDisplayName() != null) {
|
||||
buffer.putByte((byte) 0x08);
|
||||
buffer.putString("Name");
|
||||
buffer.putString(Chat.rawText(itemStack.getDisplayName()));
|
||||
}
|
||||
|
||||
// TODO lore
|
||||
buffer.putByte((byte) 0x08);
|
||||
buffer.putString("Lore");
|
||||
buffer.putString(Chat.rawText("a line"));
|
||||
|
||||
buffer.putByte((byte) 0); // End display compound
|
||||
|
||||
buffer.putByte((byte) 0); // End nbt TODO
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static void writeBlocks(Buffer buffer, short[] blocksId, int bitsPerEntry) {
|
||||
|
|
Loading…
Reference in New Issue