1.15.2 update

This commit is contained in:
Felix Cravic 2020-02-09 15:34:09 +01:00
parent c66020a196
commit b1b41afebb
84 changed files with 353 additions and 213 deletions

View File

@ -24,7 +24,7 @@ dependencies {
apt lombokDependency
// https://mvnrepository.com/artifact/com.github.jhg023/SimpleNet
compile group: 'com.github.jhg023', name: 'SimpleNet', version: '1.5.1'
compile group: 'com.github.jhg023', name: 'SimpleNet', version: '1.6.2'
// https://mvnrepository.com/artifact/it.unimi.dsi/fastutil
compile group: 'it.unimi.dsi', name: 'fastutil', version: '8.3.0'

View File

@ -32,9 +32,9 @@ public class Main {
public static final int THREAD_COUNT_SCHEDULER = 2;
// Can be modified at performance cost when decreased
public static final int TICK_MS = 50;
public static final int TICK_PER_SECOND = 1000 / TICK_MS;
private static final int MS_TO_SEC = 1000;
public static final int TICK_MS = MS_TO_SEC / 20;
public static final int TICK_PER_SECOND = MS_TO_SEC / TICK_MS;
// Config
public static final int CHUNK_VIEW_DISTANCE = 5;
@ -69,7 +69,8 @@ public class Main {
blockManager.registerBlock(new StoneBlock());
blockManager.registerBlock(new UpdatableBlockDemo());
server = new Server(136434);
server = new Server();
//server = new Server(136434);
server.onConnect(client -> {
System.out.println("CONNECTION");
@ -105,17 +106,17 @@ public class Main {
});
});
server.bind("localhost", 25565);
server.bind("localhost", 55555);
System.out.println("Server started");
long tickDistance = TICK_MS * 1000000;
final long tickDistance = TICK_MS * 1000000;
long currentTime;
while (true) {
currentTime = System.nanoTime();
// Keep Alive Handling
for (Player player : getConnectionManager().getOnlinePlayers()) {
long time = System.currentTimeMillis();
long time = currentTime / 1_000_000;
if (time - player.getLastKeepAlive() > 20000) {
player.refreshKeepAlive(time);
KeepAlivePacket keepAlivePacket = new KeepAlivePacket(time);

View File

@ -33,6 +33,13 @@ public class Data {
return (T) data.getOrDefault(key, defaultValue);
}
public Data clone() {
Data data = new Data();
data.data = new ConcurrentHashMap<>(this.data);
data.dataType = new ConcurrentHashMap<>(dataType);
return data;
}
public byte[] getSerializedData() throws IOException {
ByteArrayOutputStream output = new ByteArrayOutputStream();
DataOutputStream dos = new DataOutputStream(output);

View File

@ -183,12 +183,12 @@ public abstract class Entity implements Viewable, DataContainer {
this.data = data;
}
public void tick() {
public void tick(long time) {
if (instance == null)
return;
if (scheduledRemoveTime != 0) { // Any entity with scheduled remove does not update
boolean finished = System.currentTimeMillis() >= scheduledRemoveTime;
boolean finished = time >= scheduledRemoveTime;
if (finished) {
remove();
}
@ -198,8 +198,7 @@ public abstract class Entity implements Viewable, DataContainer {
if (shouldRemove()) {
remove();
return;
} else if (shouldUpdate()) {
long time = System.currentTimeMillis();
} else if (shouldUpdate(time)) {
this.lastUpdate = time;
// Velocity
@ -207,7 +206,7 @@ public abstract class Entity implements Viewable, DataContainer {
if (this instanceof Player) {
sendPacketToViewersAndSelf(getVelocityPacket());
} else {
float tps = Main.TICK_PER_SECOND;
final float tps = Main.TICK_PER_SECOND;
refreshPosition(position.getX() + velocity.getX() / tps, position.getY() + velocity.getY() / tps, position.getZ() + velocity.getZ() / tps);
if (this instanceof ObjectEntity) {
sendPacketToViewers(getVelocityPacket());
@ -256,7 +255,7 @@ public abstract class Entity implements Viewable, DataContainer {
// Scheduled synchronization
if (time - lastSynchronizationTime >= synchronizationDelay) {
lastSynchronizationTime = System.currentTimeMillis();
lastSynchronizationTime = time;
sendSynchronization();
}
}
@ -669,8 +668,8 @@ public abstract class Entity implements Viewable, DataContainer {
sendPacketToViewers(getPassengersPacket());
}
private boolean shouldUpdate() {
return (float) (System.currentTimeMillis() - lastUpdate) >= Main.TICK_MS * 0.9f; // Margin of error
private boolean shouldUpdate(long time) {
return (float) (time - lastUpdate) >= Main.TICK_MS * 0.9f; // Margin of error
}
public enum Pose {

View File

@ -88,15 +88,21 @@ public abstract class EntityCreature extends LivingEntity {
EntityPacket entityPacket = new EntityPacket();
entityPacket.entityId = getEntityId();
SpawnMobPacket spawnMobPacket = new SpawnMobPacket();
spawnMobPacket.entityId = getEntityId();
spawnMobPacket.entityUuid = getUuid();
spawnMobPacket.entityType = getEntityType();
spawnMobPacket.position = getPosition();
spawnMobPacket.headPitch = 0;
spawnMobPacket.consumer = getMetadataConsumer();
EntityMetaDataPacket entityMetaDataPacket = new EntityMetaDataPacket();
entityMetaDataPacket.entityId = getEntityId();
entityMetaDataPacket.consumer = getMetadataConsumer();
playerConnection.sendPacket(entityPacket);
playerConnection.sendPacket(spawnMobPacket);
playerConnection.sendPacket(entityMetaDataPacket);
}
@Override

View File

@ -21,9 +21,11 @@ public class EntityManager {
private ConcurrentLinkedQueue<Player> waitingPlayers = new ConcurrentLinkedQueue<>();
public void update() {
final long time = System.currentTimeMillis();
waitingPlayersTick();
for (Instance instance : instanceManager.getInstances()) {
testTick2(instance);
testTick2(instance, time);
}
}
@ -42,21 +44,21 @@ public class EntityManager {
}
// TODO optimize for when there are too many entities on one chunk
private void testTick2(Instance instance) {
private void testTick2(Instance instance, long time) {
for (Chunk chunk : instance.getChunks()) {
Set<Entity> entities = instance.getChunkEntities(chunk);
if (!entities.isEmpty()) {
entitiesPool.execute(() -> {
for (Entity entity : entities) {
entity.tick();
entity.tick(time);
}
});
}
}
}
private void testTick1(Instance instance) {
private void testTick1(Instance instance, long time) {
Set<ObjectEntity> objects = instance.getObjectEntities();
Set<EntityCreature> creatures = instance.getCreatures();
Set<Player> players = instance.getPlayers();
@ -64,10 +66,10 @@ public class EntityManager {
if (!creatures.isEmpty() || !objects.isEmpty()) {
entitiesPool.execute(() -> {
for (EntityCreature creature : creatures) {
creature.tick();
creature.tick(time);
}
for (ObjectEntity objectEntity : objects) {
objectEntity.tick();
objectEntity.tick(time);
}
});
}
@ -75,7 +77,7 @@ public class EntityManager {
if (!players.isEmpty()) {
playersPool.execute(() -> {
for (Player player : players) {
player.tick();
player.tick(time);
}
});
}

View File

@ -82,6 +82,8 @@ public abstract class LivingEntity extends Entity {
activeHandValue += 4;
}
packet.putByte(activeHandValue);
// TODO all remaining metadata
};
}

View File

@ -5,7 +5,6 @@ import com.google.gson.JsonObject;
import fr.themode.minestom.Main;
import fr.themode.minestom.bossbar.BossBar;
import fr.themode.minestom.chat.Chat;
import fr.themode.minestom.chat.ChatColor;
import fr.themode.minestom.collision.BoundingBox;
import fr.themode.minestom.entity.property.Attribute;
import fr.themode.minestom.event.*;
@ -23,7 +22,6 @@ import fr.themode.minestom.net.packet.server.play.*;
import fr.themode.minestom.net.player.PlayerConnection;
import fr.themode.minestom.scoreboard.BelowNameScoreboard;
import fr.themode.minestom.scoreboard.Team;
import fr.themode.minestom.scoreboard.TeamManager;
import fr.themode.minestom.utils.*;
import fr.themode.minestom.world.Dimension;
import fr.themode.minestom.world.LevelType;
@ -180,7 +178,7 @@ public class Player extends LivingEntity {
getInventory().addItemStack(new ItemStack(1, (byte) 75));
//getInventory().addItemStack(new ItemStack(1, (byte) 100));
TeamManager teamManager = Main.getTeamManager();
/*TeamManager teamManager = Main.getTeamManager();
Team team = teamManager.createTeam(getUsername());
team.setTeamDisplayName("display");
team.setPrefix("[Test] ");
@ -190,16 +188,16 @@ public class Player extends LivingEntity {
setAttribute(Attribute.MAX_HEALTH, 10);
heal();
/*Scoreboard scoreboard = new Scoreboard("Scoreboard Title");
Scoreboard scoreboard = new Scoreboard("Scoreboard Title");
for (int i = 0; i < 15; i++) {
scoreboard.createLine(new Scoreboard.ScoreboardLine("id" + i, "Hey guys " + i, i));
}
scoreboard.addViewer(this);
scoreboard.updateLineContent("id3", "I HAVE BEEN UPDATED &2TEST");*/
scoreboard.updateLineContent("id3", "I HAVE BEEN UPDATED &2TEST");
BelowNameScoreboard belowNameScoreboard = new BelowNameScoreboard();
setBelowNameScoreboard(belowNameScoreboard);
belowNameScoreboard.updateScore(this, 50);
belowNameScoreboard.updateScore(this, 50);*/
});
}
@ -209,7 +207,7 @@ public class Player extends LivingEntity {
// Flush all pending packets
playerConnection.flush();
// Process sent packets
// Process received packets
ClientPlayPacket packet;
while ((packet = packets.poll()) != null) {
packet.process(this);
@ -358,7 +356,7 @@ public class Player extends LivingEntity {
spawnPlayerPacket.position = getPosition();
PlayerInfoPacket pInfoPacket = new PlayerInfoPacket(PlayerInfoPacket.Action.ADD_PLAYER);
PlayerInfoPacket.AddPlayer addP = new PlayerInfoPacket.AddPlayer(getUuid(), getUsername(), GameMode.CREATIVE, 10);
PlayerInfoPacket.AddPlayer addP = new PlayerInfoPacket.AddPlayer(getUuid(), getUsername(), getGameMode(), 10);
PlayerInfoPacket.AddPlayer.Property p = new PlayerInfoPacket.AddPlayer.Property("textures", property);//new PlayerInfoPacket.AddPlayer.Property("textures", properties.get(onlinePlayer.getUsername()));
addP.properties.add(p);
pInfoPacket.playerInfos.add(addP);

View File

@ -189,8 +189,8 @@ public class Chunk implements Viewable {
// Update cooldown
UpdateOption updateOption = customBlock.getUpdateOption();
long lastUpdate = updatableBlocksLastUpdate.get(index);
boolean shouldUpdate = !CooldownUtils.hasCooldown(time, lastUpdate, updateOption.getTimeUnit(), updateOption.getValue());
if (!shouldUpdate)
boolean hasCooldown = CooldownUtils.hasCooldown(time, lastUpdate, updateOption.getTimeUnit(), updateOption.getValue());
if (hasCooldown)
continue;
this.updatableBlocksLastUpdate.put(index, time); // Refresh last update time
@ -242,9 +242,6 @@ public class Chunk implements Viewable {
DataOutputStream dos = new DataOutputStream(output);
dos.writeByte(biome.getId());
// TODO customblock id map (StringId -> short id)
// TODO List of (sectionId;blockcount;blocktype;blockarray)
// TODO block data
for (Int2IntMap.Entry entry : blocks.int2IntEntrySet()) {
int index = entry.getIntKey();
int value = entry.getIntValue();

View File

@ -3,6 +3,7 @@ package fr.themode.minestom.instance;
import com.github.simplenet.packet.Packet;
import fr.themode.minestom.Main;
import fr.themode.minestom.data.Data;
import fr.themode.minestom.data.DataContainer;
import fr.themode.minestom.entity.*;
import fr.themode.minestom.instance.batch.BlockBatch;
import fr.themode.minestom.instance.batch.ChunkBatch;
@ -20,7 +21,7 @@ import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArraySet;
import java.util.function.Consumer;
public abstract class Instance implements BlockModifier {
public abstract class Instance implements BlockModifier, DataContainer {
protected static final ChunkLoaderIO CHUNK_LOADER_IO = new ChunkLoaderIO();
protected static final BlockManager BLOCK_MANAGER = Main.getBlockManager();
@ -34,6 +35,8 @@ public abstract class Instance implements BlockModifier {
protected Map<Long, Set<Entity>> chunkEntities = new ConcurrentHashMap<>();
private UUID uniqueId;
private Data data;
protected Instance(UUID uniqueId) {
this.uniqueId = uniqueId;
}
@ -49,7 +52,9 @@ public abstract class Instance implements BlockModifier {
public abstract Chunk getChunk(int chunkX, int chunkZ);
public abstract void saveToFolder(Runnable callback);
public abstract void saveChunkToFolder(Chunk chunk, Runnable callback);
public abstract void saveChunksToFolder(Runnable callback);
public abstract BlockBatch createBlockBatch();
@ -171,14 +176,28 @@ public abstract class Instance implements BlockModifier {
return getChunkAt(position.getX(), position.getZ());
}
public void saveToFolder() {
saveToFolder(null);
public void saveChunkToFolder(Chunk chunk) {
saveChunkToFolder(chunk, null);
}
public void saveChunksToFolder() {
saveChunksToFolder(null);
}
public UUID getUniqueId() {
return uniqueId;
}
@Override
public Data getData() {
return data;
}
@Override
public void setData(Data data) {
this.data = data;
}
// UNSAFE METHODS (need most of time to be synchronized)
public void addEntity(Entity entity) {

View File

@ -89,11 +89,11 @@ public class InstanceContainer extends Instance {
particlePacket.x = x + 0.5f;
particlePacket.y = y;
particlePacket.z = z + 0.5f;
particlePacket.offsetX = 0.45f;
particlePacket.offsetY = 0.55f;
particlePacket.offsetZ = 0.45f;
particlePacket.offsetX = 0.4f;
particlePacket.offsetY = 0.5f;
particlePacket.offsetZ = 0.4f;
particlePacket.particleData = 0.3f;
particlePacket.particleCount = 100;
particlePacket.particleCount = 125;
particlePacket.blockId = blockId;
chunk.sendPacketToViewers(particlePacket);
} else {
@ -133,7 +133,12 @@ public class InstanceContainer extends Instance {
}
@Override
public void saveToFolder(Runnable callback) {
public void saveChunkToFolder(Chunk chunk, Runnable callback) {
CHUNK_LOADER_IO.saveChunk(chunk, getFolder(), callback);
}
@Override
public void saveChunksToFolder(Runnable callback) {
if (folder == null)
throw new UnsupportedOperationException("You cannot save an instance without setting a folder.");
@ -141,7 +146,7 @@ public class InstanceContainer extends Instance {
while (chunks.hasNext()) {
Chunk chunk = chunks.next();
boolean isLast = !chunks.hasNext();
CHUNK_LOADER_IO.saveChunk(chunk, getFolder(), isLast ? callback : null);
saveChunkToFolder(chunk, isLast ? callback : null);
}
}
@ -204,8 +209,8 @@ public class InstanceContainer extends Instance {
public void sendChunk(Player player, Chunk chunk) {
Packet data = chunk.getFullDataPacket();
if (data == null || !chunk.packetUpdated) {
PacketWriterUtils.writeCallbackPacket(chunk.getFreshFullDataPacket(), buffer -> {
chunk.setFullDataPacket(buffer);
PacketWriterUtils.writeCallbackPacket(chunk.getFreshFullDataPacket(), packet -> {
chunk.setFullDataPacket(packet);
sendChunkUpdate(player, chunk);
});
} else {

View File

@ -44,8 +44,13 @@ public class SharedInstance extends Instance {
}
@Override
public void saveToFolder(Runnable callback) {
instanceContainer.saveToFolder(callback);
public void saveChunkToFolder(Chunk chunk, Runnable callback) {
instanceContainer.saveChunkToFolder(chunk, callback);
}
@Override
public void saveChunksToFolder(Runnable callback) {
instanceContainer.saveChunksToFolder(callback);
}
@Override

View File

@ -23,18 +23,7 @@ public class BlockBatch implements IBatch {
public void setBlock(int x, int y, int z, short blockId, Data data) {
synchronized (this) {
Chunk chunk = this.instance.getChunkAt(x, z);
List<BlockData> blocksData = this.data.getOrDefault(chunk, new ArrayList<>());
BlockData blockData = new BlockData();
blockData.x = x % 16;
blockData.y = y;
blockData.z = z % 16;
blockData.blockId = blockId;
blockData.data = data;
blocksData.add(blockData);
this.data.put(chunk, blocksData);
addBlockData(chunk, x, y, z, false, blockId, data);
}
}
@ -42,22 +31,28 @@ public class BlockBatch implements IBatch {
public void setCustomBlock(int x, int y, int z, short blockId, Data data) {
synchronized (this) {
Chunk chunk = this.instance.getChunkAt(x, z);
List<BlockData> blocksData = this.data.getOrDefault(chunk, new ArrayList<>());
BlockData blockData = new BlockData();
blockData.x = x % 16;
blockData.y = y;
blockData.z = z % 16;
blockData.isCustomBlock = true;
blockData.blockId = blockId;
blockData.data = data;
blocksData.add(blockData);
this.data.put(chunk, blocksData);
addBlockData(chunk, x, y, z, true, blockId, data);
}
}
private void addBlockData(Chunk chunk, int x, int y, int z, boolean customBlock, short blockId, Data data) {
List<BlockData> blocksData = this.data.get(chunk);
if (blocksData == null)
blocksData = new ArrayList<>();
BlockData blockData = new BlockData();
blockData.x = x % 16;
blockData.y = y;
blockData.z = z % 16;
blockData.isCustomBlock = customBlock;
blockData.blockId = blockId;
blockData.data = data;
blocksData.add(blockData);
this.data.put(chunk, blocksData);
}
public void flush(Runnable callback) {
int counter = 0;
for (Map.Entry<Chunk, List<BlockData>> entry : data.entrySet()) {

View File

@ -27,24 +27,20 @@ public class ChunkBatch implements IBatch {
@Override
public void setBlock(int x, int y, int z, short blockId, Data data) {
BlockData blockData = new BlockData();
blockData.x = (byte) x;
blockData.y = (byte) y;
blockData.z = (byte) z;
blockData.isCustomBlock = false;
blockData.blockId = blockId;
blockData.data = data;
this.dataList.add(blockData);
addBlockData((byte) x, (byte) y, (byte) z, false, blockId, data);
}
@Override
public void setCustomBlock(int x, int y, int z, short blockId, Data data) {
addBlockData((byte) x, (byte) y, (byte) z, true, blockId, data);
}
private void addBlockData(byte x, byte y, byte z, boolean customBlock, short blockId, Data data) {
BlockData blockData = new BlockData();
blockData.x = (byte) x;
blockData.y = (byte) y;
blockData.z = (byte) z;
blockData.isCustomBlock = true;
blockData.x = x;
blockData.y = y;
blockData.z = z;
blockData.isCustomBlock = customBlock;
blockData.blockId = blockId;
blockData.data = data;

View File

@ -309,7 +309,7 @@ public class PlayerInventory implements InventoryModifier, InventoryClickHandler
if (!cursorItem.isAir()) {
if (slot == 0 || slot == 6 || slot == 7 || slot == 8) {
return; // Disable putting item on CRAFTING_RESULT and chestplate/leggings/boots slots
return; // Disable putting item on CRAFTING_RESULT and on helmet/chestplate/leggings/boots slots
}
}

View File

@ -77,7 +77,9 @@ public class ItemStack implements DataContainer {
ItemStack itemStack = new ItemStack(material, amount, damage);
itemStack.setDisplayName(displayName);
itemStack.setUnbreakable(unbreakable);
itemStack.setData(getData());
Data data = getData();
if (data != null)
itemStack.setData(data.clone());
return itemStack;
}

View File

@ -5,6 +5,7 @@ import com.github.simplenet.utility.exposed.consumer.BooleanConsumer;
import com.github.simplenet.utility.exposed.consumer.ByteConsumer;
import com.github.simplenet.utility.exposed.consumer.FloatConsumer;
import com.github.simplenet.utility.exposed.consumer.ShortConsumer;
import fr.themode.minestom.item.ItemStack;
import fr.themode.minestom.net.ConnectionUtils;
import fr.themode.minestom.utils.BlockPosition;
import fr.themode.minestom.utils.Utils;
@ -85,4 +86,8 @@ public class PacketReader {
Utils.readPosition(client, consumer);
}
public void readSlot(Consumer<ItemStack> consumer) {
Utils.readItemStack(this, consumer);
}
}

View File

@ -23,9 +23,10 @@ public class ClientPlayPacketsHandler extends ClientPacketsHandler {
register(0x23, ClientHeldItemChangePacket.class);
register(0x09, ClientClickWindowPacket.class);
register(0x0A, ClientCloseWindow.class);
register(0x07, ClientConfirmTransactionPacket.class);
register(0x07, ClientClickWindowButtonPacket.class);
register(0x1C, ClientSteerVehiclePacket.class);
register(0x2D, ClientUseItemPacket.class);
register(0x04, ClientStatusPacket.class);
register(0x26, ClientCreativeInventoryActionPacket.class);
}
}

View File

@ -9,6 +9,7 @@ import fr.themode.minestom.net.packet.PacketReader;
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.DeclareCommandsPacket;
import fr.themode.minestom.net.packet.server.play.PlayerInfoPacket;
import fr.themode.minestom.net.packet.server.play.SpawnPositionPacket;
import fr.themode.minestom.net.player.PlayerConnection;
@ -76,7 +77,7 @@ public class LoginStartPacket implements ClientPreplayPacket {
connection.sendPacket(spawnPositionPacket);
PlayerInfoPacket playerInfoPacket = new PlayerInfoPacket(PlayerInfoPacket.Action.ADD_PLAYER);
PlayerInfoPacket.AddPlayer addPlayer = new PlayerInfoPacket.AddPlayer(player.getUuid(), username, GameMode.CREATIVE, 10);
PlayerInfoPacket.AddPlayer addPlayer = new PlayerInfoPacket.AddPlayer(player.getUuid(), username, player.getGameMode(), 10);
PlayerInfoPacket.AddPlayer.Property prop = new PlayerInfoPacket.AddPlayer.Property("textures", property); //new PlayerInfoPacket.AddPlayer.Property("textures", properties.get(username));
addPlayer.properties.add(prop);
playerInfoPacket.playerInfos.add(addPlayer);
@ -84,7 +85,7 @@ public class LoginStartPacket implements ClientPreplayPacket {
Main.getEntityManager().addWaitingPlayer(player);
/*DeclareCommandsPacket declareCommandsPacket = new DeclareCommandsPacket();
DeclareCommandsPacket declareCommandsPacket = new DeclareCommandsPacket();
DeclareCommandsPacket.Node argumentNode = new DeclareCommandsPacket.Node();
argumentNode.flags = 0b1010;
argumentNode.children = new int[0];
@ -102,7 +103,7 @@ public class LoginStartPacket implements ClientPreplayPacket {
declareCommandsPacket.rootIndex = 0;
connection.sendPacket(declareCommandsPacket);*/
connection.sendPacket(declareCommandsPacket);
}
@Override

View File

@ -0,0 +1,20 @@
package fr.themode.minestom.net.packet.client.play;
import fr.themode.minestom.net.packet.PacketReader;
import fr.themode.minestom.net.packet.client.ClientPlayPacket;
public class ClientClickWindowButtonPacket extends ClientPlayPacket {
public byte windowId;
public byte buttonId;
@Override
public void read(PacketReader reader, Runnable callback) {
// FIXME: 2 packets have the same id (Confirm Transaction / Click window button)
reader.readByte(value -> windowId = value);
reader.readByte(value -> {
buttonId = value;
callback.run();
});
}
}

View File

@ -1,5 +1,6 @@
package fr.themode.minestom.net.packet.client.play;
import fr.themode.minestom.item.ItemStack;
import fr.themode.minestom.net.packet.PacketReader;
import fr.themode.minestom.net.packet.client.ClientPlayPacket;
@ -10,6 +11,7 @@ public class ClientClickWindowPacket extends ClientPlayPacket {
public byte button;
public short actionNumber;
public int mode;
public ItemStack item;
// TODO clicked item
@Override
@ -18,10 +20,10 @@ public class ClientClickWindowPacket extends ClientPlayPacket {
reader.readShort(value -> slot = value);
reader.readByte(value -> button = value);
reader.readShort(value -> actionNumber = value);
reader.readVarInt(value -> {
mode = value;
reader.readVarInt(value -> mode = value);
reader.readSlot(itemStack -> {
item = itemStack;
callback.run();
});
// TODO read clicked item
}
}

View File

@ -1,17 +0,0 @@
package fr.themode.minestom.net.packet.client.play;
import fr.themode.minestom.net.packet.PacketReader;
import fr.themode.minestom.net.packet.client.ClientPlayPacket;
public class ClientConfirmTransactionPacket extends ClientPlayPacket {
public int windowId;
public short actionNumber;
public boolean accepted;
@Override
public void read(PacketReader reader, Runnable callback) {
callback.run();
// TODO
}
}

View File

@ -0,0 +1,20 @@
package fr.themode.minestom.net.packet.client.play;
import fr.themode.minestom.item.ItemStack;
import fr.themode.minestom.net.packet.PacketReader;
import fr.themode.minestom.net.packet.client.ClientPlayPacket;
public class ClientCreativeInventoryActionPacket extends ClientPlayPacket {
public short slot;
public ItemStack item;
@Override
public void read(PacketReader reader, Runnable callback) {
reader.readShort(value -> slot = value);
reader.readSlot(itemStack -> {
item = itemStack;
callback.run();
});
}
}

View File

@ -7,8 +7,8 @@ public class ResponsePacket implements ServerPacket {
private static final String JSON_EXAMPLE = "{\n" +
" \"version\": {\n" +
" \"name\": \"1.14.4\",\n" +
" \"protocol\": 498\n" +
" \"name\": \"1.15.2\",\n" +
" \"protocol\": 578\n" +
" },\n" +
" \"players\": {\n" +
" \"max\": 100,\n" +

View File

@ -11,10 +11,12 @@ public class JoinGamePacket implements ServerPacket {
public int entityId;
public GameMode gameMode = GameMode.SURVIVAL;
public Dimension dimension = Dimension.OVERWORLD;
public long hashedSeed;
public byte maxPlayers = 0; // Unused
public LevelType levelType;
public int viewDistance;
public boolean reducedDebugInfo = false;
public boolean enableRespawnScreen = true;
@Override
public void write(PacketWriter writer) {
@ -25,14 +27,16 @@ public class JoinGamePacket implements ServerPacket {
writer.writeInt(entityId);
writer.writeByte((byte) gameModeId);
writer.writeInt(dimension.getId());
writer.writeLong(hashedSeed);
writer.writeByte(maxPlayers);
writer.writeSizedString(levelType.getType());
writer.writeVarInt(viewDistance);
writer.writeBoolean(reducedDebugInfo);
writer.writeBoolean(enableRespawnScreen);
}
@Override
public int getId() {
return 0x25;
return 0x26;
}
}

View File

@ -22,6 +22,6 @@ public class AcknowledgePlayerDiggingPacket implements ServerPacket {
@Override
public int getId() {
return 0x5c;
return 0x8;
}
}

View File

@ -31,7 +31,7 @@ public class AdvancementsPacket implements ServerPacket {
@Override
public int getId() {
return 0x57;
return 0x58;
}
public enum FrameType {

View File

@ -21,6 +21,6 @@ public class BlockActionPacket implements ServerPacket {
@Override
public int getId() {
return 0x0A;
return 0x0B;
}
}

View File

@ -19,6 +19,6 @@ public class BlockBreakAnimationPacket implements ServerPacket {
@Override
public int getId() {
return 0x08;
return 0x09;
}
}

View File

@ -17,6 +17,6 @@ public class BlockChangePacket implements ServerPacket {
@Override
public int getId() {
return 0x0B;
return 0x0C;
}
}

View File

@ -54,7 +54,7 @@ public class BossBarPacket implements ServerPacket {
@Override
public int getId() {
return 0x0C;
return 0x0D;
}
public enum Action {

View File

@ -16,7 +16,7 @@ public class ChangeGameStatePacket implements ServerPacket {
@Override
public int getId() {
return 0x1E;
return 0x1F;
}
public enum Reason {
@ -30,7 +30,8 @@ public class ChangeGameStatePacket implements ServerPacket {
FADE_VALUE,
FADE_TIME,
PLAY_PUFFERFISH_STING_SOUND,
PLAYER_ELDER_GUARDIAN_MOB_APPEARANCE;
PLAYER_ELDER_GUARDIAN_MOB_APPEARANCE,
ENABLE_RESPAWN_SCREEN;
}
}

View File

@ -21,7 +21,7 @@ public class ChatMessagePacket implements ServerPacket {
@Override
public int getId() {
return 0x0E;
return 0x0F;
}
public enum Position {

View File

@ -49,15 +49,6 @@ public class ChunkDataPacket implements ServerPacket {
}
}
// Biome data
if (fullChunk) {
for (int z = 0; z < 16; z++) {
for (int x = 0; x < 16; x++) {
blocks.putInt(chunk.getBiome().getId());
}
}
}
writer.writeVarInt(mask);
// Heightmap
@ -84,6 +75,15 @@ public class ChunkDataPacket implements ServerPacket {
writer.writeBytes(data);
}
// Biome data
if (fullChunk) {
for (int z = 0; z < 1024; z++) {
writer.writeInt(chunk.getBiome().getId());
//blocks.putInt(chunk.getBiome().getId()); // FIXME
}
}
// Data
writer.writeVarInt(blocks.getSize());
writer.writeBufferAndFree(blocks);
@ -129,6 +129,6 @@ public class ChunkDataPacket implements ServerPacket {
@Override
public int getId() {
return 0x21;
return 0x22;
}
}

View File

@ -14,6 +14,6 @@ public class CloseWindowPacket implements ServerPacket {
@Override
public int getId() {
return 0x13;
return 0x14;
}
}

View File

@ -18,6 +18,6 @@ public class CollectItemPacket implements ServerPacket {
@Override
public int getId() {
return 0x55;
return 0x56;
}
}

View File

@ -18,6 +18,6 @@ public class ConfirmTransactionPacket implements ServerPacket {
@Override
public int getId() {
return 0x12;
return 0x13;
}
}

View File

@ -22,7 +22,7 @@ public class DeclareCommandsPacket implements ServerPacket {
@Override
public int getId() {
return 0x11;
return 0x12;
}
public static class Node {

View File

@ -14,6 +14,6 @@ public class DestroyEntitiesPacket implements ServerPacket {
@Override
public int getId() {
return 0x37;
return 0x38;
}
}

View File

@ -15,6 +15,6 @@ public class DisconnectPacket implements ServerPacket {
@Override
public int getId() {
return 0x1A;
return 0x1B;
}
}

View File

@ -16,6 +16,6 @@ public class DisplayScoreboardPacket implements ServerPacket {
@Override
public int getId() {
return 0x42;
return 0x43;
}
}

View File

@ -22,6 +22,6 @@ public class EntityEffectPacket implements ServerPacket {
@Override
public int getId() {
return 0x59;
return 0x5A;
}
}

View File

@ -19,7 +19,7 @@ public class EntityEquipmentPacket implements ServerPacket {
@Override
public int getId() {
return 0x46;
return 0x47;
}
public enum Slot {

View File

@ -16,6 +16,6 @@ public class EntityHeadLookPacket implements ServerPacket {
@Override
public int getId() {
return 0x3B;
return 0x3C;
}
}

View File

@ -24,6 +24,6 @@ public class EntityLookAndRelativeMovePacket implements ServerPacket {
@Override
public int getId() {
return 0x29;
return 0x2A;
}
}

View File

@ -19,6 +19,6 @@ public class EntityLookPacket implements ServerPacket {
@Override
public int getId() {
return 0x2A;
return 0x2B;
}
}

View File

@ -20,6 +20,6 @@ public class EntityMetaDataPacket implements ServerPacket {
@Override
public int getId() {
return 0x43;
return 0x44;
}
}

View File

@ -14,6 +14,6 @@ public class EntityPacket implements ServerPacket {
@Override
public int getId() {
return 0x2B;
return 0x2C;
}
}

View File

@ -20,7 +20,7 @@ public class EntityPropertiesPacket implements ServerPacket {
@Override
public int getId() {
return 0x58;
return 0x59;
}
public static class Property {

View File

@ -20,6 +20,6 @@ public class EntityRelativeMovePacket implements ServerPacket {
@Override
public int getId() {
return 0x28;
return 0x29;
}
}

View File

@ -16,6 +16,6 @@ public class EntityStatusPacket implements ServerPacket {
@Override
public int getId() {
return 0x1B;
return 0x1C;
}
}

View File

@ -23,6 +23,6 @@ public class EntityTeleportPacket implements ServerPacket {
@Override
public int getId() {
return 0x56;
return 0x57;
}
}

View File

@ -18,6 +18,6 @@ public class EntityVelocityPacket implements ServerPacket {
@Override
public int getId() {
return 0x45;
return 0x46;
}
}

View File

@ -26,6 +26,6 @@ public class ExplosionPacket implements ServerPacket {
@Override
public int getId() {
return 0x1C;
return 0x1D;
}
}

View File

@ -14,6 +14,6 @@ public class HeldItemChangePacket implements ServerPacket {
@Override
public int getId() {
return 0x3F;
return 0x40;
}
}

View File

@ -18,6 +18,6 @@ public class KeepAlivePacket implements ServerPacket {
@Override
public int getId() {
return 0x20;
return 0x21;
}
}

View File

@ -30,7 +30,7 @@ public class MultiBlockChangePacket implements ServerPacket {
@Override
public int getId() {
return 0x0F;
return 0x10;
}
public static class BlockChange {

View File

@ -18,6 +18,6 @@ public class OpenWindowPacket implements ServerPacket {
@Override
public int getId() {
return 0x2E;
return 0x2F;
}
}

View File

@ -7,7 +7,7 @@ public class ParticlePacket implements ServerPacket {
public int particleId;
public boolean longDistance;
public float x, y, z;
public double x, y, z;
public float offsetX, offsetY, offsetZ;
public float particleData;
public int particleCount;
@ -18,9 +18,9 @@ public class ParticlePacket implements ServerPacket {
public void write(PacketWriter writer) {
writer.writeInt(particleId);
writer.writeBoolean(longDistance);
writer.writeFloat(x);
writer.writeFloat(y);
writer.writeFloat(z);
writer.writeDouble(x);
writer.writeDouble(y);
writer.writeDouble(z);
writer.writeFloat(offsetX);
writer.writeFloat(offsetY);
writer.writeFloat(offsetZ);
@ -32,6 +32,6 @@ public class ParticlePacket implements ServerPacket {
@Override
public int getId() {
return 0x23;
return 0x24;
}
}

View File

@ -34,6 +34,6 @@ public class PlayerAbilitiesPacket implements ServerPacket {
@Override
public int getId() {
return 0x31;
return 0x32;
}
}

View File

@ -31,7 +31,7 @@ public class PlayerInfoPacket implements ServerPacket {
@Override
public int getId() {
return 0x33;
return 0x34;
}
public enum Action {

View File

@ -24,6 +24,6 @@ public class PlayerPositionAndLookPacket implements ServerPacket {
@Override
public int getId() {
return 0x35;
return 0x36;
}
}

View File

@ -16,6 +16,6 @@ public class RemoveEntityEffectPacket implements ServerPacket {
@Override
public int getId() {
return 0x38;
return 0x39;
}
}

View File

@ -9,18 +9,20 @@ import fr.themode.minestom.world.LevelType;
public class RespawnPacket implements ServerPacket {
public Dimension dimension;
public long hashedSeed;
public GameMode gameMode;
public LevelType levelType;
@Override
public void write(PacketWriter writer) {
writer.writeByte((byte) gameMode.getId()); // Hardcore flag not included
writer.writeInt(dimension.getId());
writer.writeLong(hashedSeed);
writer.writeByte((byte) gameMode.getId()); // Hardcore flag not included
writer.writeSizedString(levelType.getType());
}
@Override
public int getId() {
return 0x3A;
return 0x3B;
}
}

View File

@ -24,6 +24,6 @@ public class ScoreboardObjectivePacket implements ServerPacket {
@Override
public int getId() {
return 0x49;
return 0x4A;
}
}

View File

@ -18,6 +18,6 @@ public class SetExperiencePacket implements ServerPacket {
@Override
public int getId() {
return 0x47;
return 0x48;
}
}

View File

@ -16,6 +16,6 @@ public class SetPassengersPacket implements ServerPacket {
@Override
public int getId() {
return 0x4A;
return 0x4B;
}
}

View File

@ -19,6 +19,6 @@ public class SetSlotPacket implements ServerPacket {
@Override
public int getId() {
return 0x16;
return 0x17;
}
}

View File

@ -1,12 +1,10 @@
package fr.themode.minestom.net.packet.server.play;
import com.github.simplenet.packet.Packet;
import fr.themode.minestom.net.packet.PacketWriter;
import fr.themode.minestom.net.packet.server.ServerPacket;
import fr.themode.minestom.utils.Position;
import java.util.UUID;
import java.util.function.Consumer;
public class SpawnMobPacket implements ServerPacket {
@ -16,7 +14,6 @@ public class SpawnMobPacket implements ServerPacket {
public Position position;
public float headPitch;
public short velocityX, velocityY, velocityZ;
public Consumer<Packet> consumer;
@Override
public void write(PacketWriter writer) {
@ -32,10 +29,6 @@ public class SpawnMobPacket implements ServerPacket {
writer.writeShort(velocityX);
writer.writeShort(velocityY);
writer.writeShort(velocityZ);
if (consumer != null) {
writer.write(consumer);
}
writer.writeByte((byte) 0xff);
}

View File

@ -1,19 +1,16 @@
package fr.themode.minestom.net.packet.server.play;
import com.github.simplenet.packet.Packet;
import fr.themode.minestom.net.packet.PacketWriter;
import fr.themode.minestom.net.packet.server.ServerPacket;
import fr.themode.minestom.utils.Position;
import java.util.UUID;
import java.util.function.Consumer;
public class SpawnPlayerPacket implements ServerPacket {
public int entityId;
public UUID playerUuid;
public Position position;
public Consumer<Packet> metadataConsumer;
@Override
public void write(PacketWriter writer) {
@ -24,12 +21,6 @@ public class SpawnPlayerPacket implements ServerPacket {
writer.writeDouble(position.getZ());
writer.writeByte((byte) (position.getYaw() * 256f / 360f));
writer.writeByte((byte) (position.getPitch() * 256f / 360f));
if (metadataConsumer != null) {
writer.write(metadataConsumer);
} else {
writer.writeByte((byte) 0xff);
}
}
@Override

View File

@ -14,6 +14,6 @@ public class SpawnPositionPacket implements ServerPacket {
@Override
public int getId() {
return 0x4D;
return 0x4E;
}
}

View File

@ -47,7 +47,7 @@ public class TeamsPacket implements ServerPacket {
@Override
public int getId() {
return 0x4B;
return 0x4C;
}
public enum Action {

View File

@ -28,7 +28,7 @@ public class TradeListPacket implements ServerPacket {
@Override
public int getId() {
return 0x27;
return 0x28;
}
public static class Trade {

View File

@ -15,6 +15,6 @@ public class UnloadChunkPacket implements ServerPacket {
@Override
public int getId() {
return 0x1D;
return 0x1E;
}
}

View File

@ -18,6 +18,6 @@ public class UpdateHealthPacket implements ServerPacket {
@Override
public int getId() {
return 0x48;
return 0x49;
}
}

View File

@ -22,6 +22,6 @@ public class UpdateScorePacket implements ServerPacket {
@Override
public int getId() {
return 0x4C;
return 0x4D;
}
}

View File

@ -20,6 +20,6 @@ public class UpdateViewPositionPacket implements ServerPacket {
@Override
public int getId() {
return 0x40;
return 0x41;
}
}

View File

@ -28,6 +28,6 @@ public class WindowItemsPacket implements ServerPacket {
@Override
public int getId() {
return 0x14;
return 0x15;
}
}

View File

@ -18,6 +18,6 @@ public class WindowPropertyPacket implements ServerPacket {
@Override
public int getId() {
return 0x15;
return 0x16;
}
}

View File

@ -5,6 +5,7 @@ import fr.themode.minestom.utils.thread.MinestomThread;
import fr.themode.minestom.utils.time.CooldownUtils;
import fr.themode.minestom.utils.time.UpdateOption;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.ExecutorService;
@ -16,25 +17,56 @@ public class SchedulerManager {
private static ExecutorService batchesPool = new MinestomThread(Main.THREAD_COUNT_SCHEDULER, "Ms-SchedulerPool");
private List<Task> tasks = new CopyOnWriteArrayList<>();
public void addRepeatingTask(TaskRunnable runnable, UpdateOption updateOption) {
runnable.setId(COUNTER.incrementAndGet());
public int addTask(TaskRunnable runnable, UpdateOption updateOption, int maxCallCount) {
int id = COUNTER.incrementAndGet();
runnable.setId(id);
Task task = new Task(runnable, updateOption);
Task task = new Task(runnable, updateOption, maxCallCount);
this.tasks.add(task);
return id;
}
public int addRepeatingTask(TaskRunnable runnable, UpdateOption updateOption) {
return addTask(runnable, updateOption, 0);
}
public int addDelayedTask(TaskRunnable runnable, UpdateOption updateOption) {
return addTask(runnable, updateOption, 1);
}
public void removeTask(int taskId) {
synchronized (tasks) {
this.tasks.removeIf(task -> task.getId() == taskId);
}
}
public void update() {
long time = System.currentTimeMillis();
batchesPool.execute(() -> {
for (Task task : tasks) {
UpdateOption updateOption = task.getUpdateOption();
long lastUpdate = task.getLastUpdateTime();
boolean hasCooldown = CooldownUtils.hasCooldown(time, lastUpdate, updateOption.getTimeUnit(), updateOption.getValue());
if (!hasCooldown) {
TaskRunnable runnable = task.getRunnable();
runnable.run();
task.refreshLastUpdateTime(time);
synchronized (tasks) {
Iterator<Task> iterator = tasks.iterator();
while (iterator.hasNext()) {
Task task = iterator.next();
UpdateOption updateOption = task.getUpdateOption();
long lastUpdate = task.getLastUpdateTime();
boolean hasCooldown = CooldownUtils.hasCooldown(time, lastUpdate, updateOption.getTimeUnit(), updateOption.getValue());
if (!hasCooldown) {
TaskRunnable runnable = task.getRunnable();
int maxCallCount = task.getMaxCallCount();
int callCount = runnable.getCallCount() + 1;
runnable.setCallCount(callCount);
runnable.run();
task.refreshLastUpdateTime(time);
if (callCount == maxCallCount) {
iterator.remove();
}
}
}
}
});

View File

@ -4,14 +4,21 @@ import fr.themode.minestom.utils.time.UpdateOption;
public class Task {
private int id;
private TaskRunnable runnable;
private UpdateOption updateOption;
private int maxCallCount;
private long lastUpdateTime;
public Task(TaskRunnable runnable, UpdateOption updateOption) {
public Task(TaskRunnable runnable, UpdateOption updateOption, int maxCallCount) {
this.id = runnable.getId();
this.runnable = runnable;
this.updateOption = updateOption;
this.maxCallCount = maxCallCount;
}
protected void refreshLastUpdateTime(long lastUpdateTime) {
@ -22,6 +29,10 @@ public class Task {
return lastUpdateTime;
}
public int getId() {
return id;
}
public TaskRunnable getRunnable() {
return runnable;
}
@ -29,4 +40,8 @@ public class Task {
public UpdateOption getUpdateOption() {
return updateOption;
}
public int getMaxCallCount() {
return maxCallCount;
}
}

View File

@ -3,6 +3,7 @@ package fr.themode.minestom.timer;
public abstract class TaskRunnable {
private int id;
private int callCount;
public abstract void run();
@ -10,7 +11,15 @@ public abstract class TaskRunnable {
return id;
}
public int getCallCount() {
return callCount;
}
protected void setId(int id) {
this.id = id;
}
protected void setCallCount(int callCount) {
this.callCount = callCount;
}
}

View File

@ -15,6 +15,8 @@ public class PacketUtils {
PacketWriter packetWriter = new PacketWriter(packet);
serverPacket.write(packetWriter);
System.out.println("WRITE PACKET: " + id + " " + serverPacket.getClass().getSimpleName());
callback.accept(packet.prepend(p -> {
Utils.writeVarInt(packet, packet.getSize());
}));

View File

@ -5,6 +5,7 @@ import com.github.simplenet.packet.Packet;
import fr.themode.minestom.chat.Chat;
import fr.themode.minestom.item.ItemStack;
import fr.themode.minestom.net.ConnectionUtils;
import fr.themode.minestom.net.packet.PacketReader;
import fr.themode.minestom.utils.buffer.BufferWrapper;
import fr.themode.minestom.utils.consumer.StringConsumer;
@ -136,6 +137,30 @@ public class Utils {
}
}
public static void readItemStack(PacketReader reader, Consumer<ItemStack> consumer) {
// FIXME: need finishing
reader.readBoolean(present -> {
if (!present) {
consumer.accept(ItemStack.AIR_ITEM); // Consume air item if empty
return;
}
reader.readVarInt(id -> {
reader.readByte(count -> {
reader.readByte(nbt -> { // FIXME: assume that there is no NBT data
consumer.accept(new ItemStack(id, count));
});
});
});
});
}
public static void writeBlocks(BufferWrapper buffer, short[] blocksId, int bitsPerEntry) {
short count = 0;
for (short id : blocksId)