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 apt lombokDependency
// https://mvnrepository.com/artifact/com.github.jhg023/SimpleNet // 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 // https://mvnrepository.com/artifact/it.unimi.dsi/fastutil
compile group: 'it.unimi.dsi', name: 'fastutil', version: '8.3.0' 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; public static final int THREAD_COUNT_SCHEDULER = 2;
// Can be modified at performance cost when decreased // Can be modified at performance cost when decreased
public static final int TICK_MS = 50; 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 = 1000 / TICK_MS; public static final int TICK_PER_SECOND = MS_TO_SEC / TICK_MS;
// Config // Config
public static final int CHUNK_VIEW_DISTANCE = 5; public static final int CHUNK_VIEW_DISTANCE = 5;
@ -69,7 +69,8 @@ public class Main {
blockManager.registerBlock(new StoneBlock()); blockManager.registerBlock(new StoneBlock());
blockManager.registerBlock(new UpdatableBlockDemo()); blockManager.registerBlock(new UpdatableBlockDemo());
server = new Server(136434); server = new Server();
//server = new Server(136434);
server.onConnect(client -> { server.onConnect(client -> {
System.out.println("CONNECTION"); System.out.println("CONNECTION");
@ -105,17 +106,17 @@ public class Main {
}); });
}); });
server.bind("localhost", 25565); server.bind("localhost", 55555);
System.out.println("Server started"); System.out.println("Server started");
long tickDistance = TICK_MS * 1000000; final long tickDistance = TICK_MS * 1000000;
long currentTime; long currentTime;
while (true) { while (true) {
currentTime = System.nanoTime(); currentTime = System.nanoTime();
// Keep Alive Handling // Keep Alive Handling
for (Player player : getConnectionManager().getOnlinePlayers()) { for (Player player : getConnectionManager().getOnlinePlayers()) {
long time = System.currentTimeMillis(); long time = currentTime / 1_000_000;
if (time - player.getLastKeepAlive() > 20000) { if (time - player.getLastKeepAlive() > 20000) {
player.refreshKeepAlive(time); player.refreshKeepAlive(time);
KeepAlivePacket keepAlivePacket = new KeepAlivePacket(time); KeepAlivePacket keepAlivePacket = new KeepAlivePacket(time);

View File

@ -33,6 +33,13 @@ public class Data {
return (T) data.getOrDefault(key, defaultValue); 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 { public byte[] getSerializedData() throws IOException {
ByteArrayOutputStream output = new ByteArrayOutputStream(); ByteArrayOutputStream output = new ByteArrayOutputStream();
DataOutputStream dos = new DataOutputStream(output); DataOutputStream dos = new DataOutputStream(output);

View File

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

View File

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

View File

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

View File

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

View File

@ -189,8 +189,8 @@ public class Chunk implements Viewable {
// Update cooldown // Update cooldown
UpdateOption updateOption = customBlock.getUpdateOption(); UpdateOption updateOption = customBlock.getUpdateOption();
long lastUpdate = updatableBlocksLastUpdate.get(index); long lastUpdate = updatableBlocksLastUpdate.get(index);
boolean shouldUpdate = !CooldownUtils.hasCooldown(time, lastUpdate, updateOption.getTimeUnit(), updateOption.getValue()); boolean hasCooldown = CooldownUtils.hasCooldown(time, lastUpdate, updateOption.getTimeUnit(), updateOption.getValue());
if (!shouldUpdate) if (hasCooldown)
continue; continue;
this.updatableBlocksLastUpdate.put(index, time); // Refresh last update time this.updatableBlocksLastUpdate.put(index, time); // Refresh last update time
@ -242,9 +242,6 @@ public class Chunk implements Viewable {
DataOutputStream dos = new DataOutputStream(output); DataOutputStream dos = new DataOutputStream(output);
dos.writeByte(biome.getId()); 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()) { for (Int2IntMap.Entry entry : blocks.int2IntEntrySet()) {
int index = entry.getIntKey(); int index = entry.getIntKey();
int value = entry.getIntValue(); int value = entry.getIntValue();

View File

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

View File

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

View File

@ -44,8 +44,13 @@ public class SharedInstance extends Instance {
} }
@Override @Override
public void saveToFolder(Runnable callback) { public void saveChunkToFolder(Chunk chunk, Runnable callback) {
instanceContainer.saveToFolder(callback); instanceContainer.saveChunkToFolder(chunk, callback);
}
@Override
public void saveChunksToFolder(Runnable callback) {
instanceContainer.saveChunksToFolder(callback);
} }
@Override @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) { public void setBlock(int x, int y, int z, short blockId, Data data) {
synchronized (this) { synchronized (this) {
Chunk chunk = this.instance.getChunkAt(x, z); Chunk chunk = this.instance.getChunkAt(x, z);
List<BlockData> blocksData = this.data.getOrDefault(chunk, new ArrayList<>()); addBlockData(chunk, x, y, z, false, blockId, data);
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);
} }
} }
@ -42,13 +31,20 @@ public class BlockBatch implements IBatch {
public void setCustomBlock(int x, int y, int z, short blockId, Data data) { public void setCustomBlock(int x, int y, int z, short blockId, Data data) {
synchronized (this) { synchronized (this) {
Chunk chunk = this.instance.getChunkAt(x, z); Chunk chunk = this.instance.getChunkAt(x, z);
List<BlockData> blocksData = this.data.getOrDefault(chunk, new ArrayList<>()); 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 blockData = new BlockData();
blockData.x = x % 16; blockData.x = x % 16;
blockData.y = y; blockData.y = y;
blockData.z = z % 16; blockData.z = z % 16;
blockData.isCustomBlock = true; blockData.isCustomBlock = customBlock;
blockData.blockId = blockId; blockData.blockId = blockId;
blockData.data = data; blockData.data = data;
@ -56,7 +52,6 @@ public class BlockBatch implements IBatch {
this.data.put(chunk, blocksData); this.data.put(chunk, blocksData);
} }
}
public void flush(Runnable callback) { public void flush(Runnable callback) {
int counter = 0; int counter = 0;

View File

@ -27,24 +27,20 @@ public class ChunkBatch implements IBatch {
@Override @Override
public void setBlock(int x, int y, int z, short blockId, Data data) { public void setBlock(int x, int y, int z, short blockId, Data data) {
BlockData blockData = new BlockData(); addBlockData((byte) x, (byte) y, (byte) z, false, blockId, data);
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);
} }
@Override @Override
public void setCustomBlock(int x, int y, int z, short blockId, Data data) { 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 blockData = new BlockData();
blockData.x = (byte) x; blockData.x = x;
blockData.y = (byte) y; blockData.y = y;
blockData.z = (byte) z; blockData.z = z;
blockData.isCustomBlock = true; blockData.isCustomBlock = customBlock;
blockData.blockId = blockId; blockData.blockId = blockId;
blockData.data = data; blockData.data = data;

View File

@ -309,7 +309,7 @@ public class PlayerInventory implements InventoryModifier, InventoryClickHandler
if (!cursorItem.isAir()) { if (!cursorItem.isAir()) {
if (slot == 0 || slot == 6 || slot == 7 || slot == 8) { 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 itemStack = new ItemStack(material, amount, damage);
itemStack.setDisplayName(displayName); itemStack.setDisplayName(displayName);
itemStack.setUnbreakable(unbreakable); itemStack.setUnbreakable(unbreakable);
itemStack.setData(getData()); Data data = getData();
if (data != null)
itemStack.setData(data.clone());
return itemStack; 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.ByteConsumer;
import com.github.simplenet.utility.exposed.consumer.FloatConsumer; import com.github.simplenet.utility.exposed.consumer.FloatConsumer;
import com.github.simplenet.utility.exposed.consumer.ShortConsumer; import com.github.simplenet.utility.exposed.consumer.ShortConsumer;
import fr.themode.minestom.item.ItemStack;
import fr.themode.minestom.net.ConnectionUtils; import fr.themode.minestom.net.ConnectionUtils;
import fr.themode.minestom.utils.BlockPosition; import fr.themode.minestom.utils.BlockPosition;
import fr.themode.minestom.utils.Utils; import fr.themode.minestom.utils.Utils;
@ -85,4 +86,8 @@ public class PacketReader {
Utils.readPosition(client, consumer); 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(0x23, ClientHeldItemChangePacket.class);
register(0x09, ClientClickWindowPacket.class); register(0x09, ClientClickWindowPacket.class);
register(0x0A, ClientCloseWindow.class); register(0x0A, ClientCloseWindow.class);
register(0x07, ClientConfirmTransactionPacket.class); register(0x07, ClientClickWindowButtonPacket.class);
register(0x1C, ClientSteerVehiclePacket.class); register(0x1C, ClientSteerVehiclePacket.class);
register(0x2D, ClientUseItemPacket.class); register(0x2D, ClientUseItemPacket.class);
register(0x04, ClientStatusPacket.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.client.ClientPreplayPacket;
import fr.themode.minestom.net.packet.server.login.JoinGamePacket; import fr.themode.minestom.net.packet.server.login.JoinGamePacket;
import fr.themode.minestom.net.packet.server.login.LoginSuccessPacket; import fr.themode.minestom.net.packet.server.login.LoginSuccessPacket;
import fr.themode.minestom.net.packet.server.play.DeclareCommandsPacket;
import fr.themode.minestom.net.packet.server.play.PlayerInfoPacket; import fr.themode.minestom.net.packet.server.play.PlayerInfoPacket;
import fr.themode.minestom.net.packet.server.play.SpawnPositionPacket; import fr.themode.minestom.net.packet.server.play.SpawnPositionPacket;
import fr.themode.minestom.net.player.PlayerConnection; import fr.themode.minestom.net.player.PlayerConnection;
@ -76,7 +77,7 @@ public class LoginStartPacket implements ClientPreplayPacket {
connection.sendPacket(spawnPositionPacket); connection.sendPacket(spawnPositionPacket);
PlayerInfoPacket playerInfoPacket = new PlayerInfoPacket(PlayerInfoPacket.Action.ADD_PLAYER); 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)); PlayerInfoPacket.AddPlayer.Property prop = new PlayerInfoPacket.AddPlayer.Property("textures", property); //new PlayerInfoPacket.AddPlayer.Property("textures", properties.get(username));
addPlayer.properties.add(prop); addPlayer.properties.add(prop);
playerInfoPacket.playerInfos.add(addPlayer); playerInfoPacket.playerInfos.add(addPlayer);
@ -84,7 +85,7 @@ public class LoginStartPacket implements ClientPreplayPacket {
Main.getEntityManager().addWaitingPlayer(player); Main.getEntityManager().addWaitingPlayer(player);
/*DeclareCommandsPacket declareCommandsPacket = new DeclareCommandsPacket(); DeclareCommandsPacket declareCommandsPacket = new DeclareCommandsPacket();
DeclareCommandsPacket.Node argumentNode = new DeclareCommandsPacket.Node(); DeclareCommandsPacket.Node argumentNode = new DeclareCommandsPacket.Node();
argumentNode.flags = 0b1010; argumentNode.flags = 0b1010;
argumentNode.children = new int[0]; argumentNode.children = new int[0];
@ -102,7 +103,7 @@ public class LoginStartPacket implements ClientPreplayPacket {
declareCommandsPacket.rootIndex = 0; declareCommandsPacket.rootIndex = 0;
connection.sendPacket(declareCommandsPacket);*/ connection.sendPacket(declareCommandsPacket);
} }
@Override @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; 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.PacketReader;
import fr.themode.minestom.net.packet.client.ClientPlayPacket; import fr.themode.minestom.net.packet.client.ClientPlayPacket;
@ -10,6 +11,7 @@ public class ClientClickWindowPacket extends ClientPlayPacket {
public byte button; public byte button;
public short actionNumber; public short actionNumber;
public int mode; public int mode;
public ItemStack item;
// TODO clicked item // TODO clicked item
@Override @Override
@ -18,10 +20,10 @@ public class ClientClickWindowPacket extends ClientPlayPacket {
reader.readShort(value -> slot = value); reader.readShort(value -> slot = value);
reader.readByte(value -> button = value); reader.readByte(value -> button = value);
reader.readShort(value -> actionNumber = value); reader.readShort(value -> actionNumber = value);
reader.readVarInt(value -> { reader.readVarInt(value -> mode = value);
mode = value; reader.readSlot(itemStack -> {
item = itemStack;
callback.run(); 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" + private static final String JSON_EXAMPLE = "{\n" +
" \"version\": {\n" + " \"version\": {\n" +
" \"name\": \"1.14.4\",\n" + " \"name\": \"1.15.2\",\n" +
" \"protocol\": 498\n" + " \"protocol\": 578\n" +
" },\n" + " },\n" +
" \"players\": {\n" + " \"players\": {\n" +
" \"max\": 100,\n" + " \"max\": 100,\n" +

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -16,7 +16,7 @@ public class ChangeGameStatePacket implements ServerPacket {
@Override @Override
public int getId() { public int getId() {
return 0x1E; return 0x1F;
} }
public enum Reason { public enum Reason {
@ -30,7 +30,8 @@ public class ChangeGameStatePacket implements ServerPacket {
FADE_VALUE, FADE_VALUE,
FADE_TIME, FADE_TIME,
PLAY_PUFFERFISH_STING_SOUND, 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 @Override
public int getId() { public int getId() {
return 0x0E; return 0x0F;
} }
public enum Position { 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); writer.writeVarInt(mask);
// Heightmap // Heightmap
@ -84,6 +75,15 @@ public class ChunkDataPacket implements ServerPacket {
writer.writeBytes(data); 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.writeVarInt(blocks.getSize());
writer.writeBufferAndFree(blocks); writer.writeBufferAndFree(blocks);
@ -129,6 +129,6 @@ public class ChunkDataPacket implements ServerPacket {
@Override @Override
public int getId() { public int getId() {
return 0x21; return 0x22;
} }
} }

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -16,6 +16,6 @@ public class RemoveEntityEffectPacket implements ServerPacket {
@Override @Override
public int getId() { 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 class RespawnPacket implements ServerPacket {
public Dimension dimension; public Dimension dimension;
public long hashedSeed;
public GameMode gameMode; public GameMode gameMode;
public LevelType levelType; public LevelType levelType;
@Override @Override
public void write(PacketWriter writer) { public void write(PacketWriter writer) {
writer.writeByte((byte) gameMode.getId()); // Hardcore flag not included
writer.writeInt(dimension.getId()); writer.writeInt(dimension.getId());
writer.writeLong(hashedSeed);
writer.writeByte((byte) gameMode.getId()); // Hardcore flag not included
writer.writeSizedString(levelType.getType()); writer.writeSizedString(levelType.getType());
} }
@Override @Override
public int getId() { public int getId() {
return 0x3A; return 0x3B;
} }
} }

View File

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

View File

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

View File

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

View File

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

View File

@ -1,12 +1,10 @@
package fr.themode.minestom.net.packet.server.play; 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.PacketWriter;
import fr.themode.minestom.net.packet.server.ServerPacket; import fr.themode.minestom.net.packet.server.ServerPacket;
import fr.themode.minestom.utils.Position; import fr.themode.minestom.utils.Position;
import java.util.UUID; import java.util.UUID;
import java.util.function.Consumer;
public class SpawnMobPacket implements ServerPacket { public class SpawnMobPacket implements ServerPacket {
@ -16,7 +14,6 @@ public class SpawnMobPacket implements ServerPacket {
public Position position; public Position position;
public float headPitch; public float headPitch;
public short velocityX, velocityY, velocityZ; public short velocityX, velocityY, velocityZ;
public Consumer<Packet> consumer;
@Override @Override
public void write(PacketWriter writer) { public void write(PacketWriter writer) {
@ -32,10 +29,6 @@ public class SpawnMobPacket implements ServerPacket {
writer.writeShort(velocityX); writer.writeShort(velocityX);
writer.writeShort(velocityY); writer.writeShort(velocityY);
writer.writeShort(velocityZ); 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; 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.PacketWriter;
import fr.themode.minestom.net.packet.server.ServerPacket; import fr.themode.minestom.net.packet.server.ServerPacket;
import fr.themode.minestom.utils.Position; import fr.themode.minestom.utils.Position;
import java.util.UUID; import java.util.UUID;
import java.util.function.Consumer;
public class SpawnPlayerPacket implements ServerPacket { public class SpawnPlayerPacket implements ServerPacket {
public int entityId; public int entityId;
public UUID playerUuid; public UUID playerUuid;
public Position position; public Position position;
public Consumer<Packet> metadataConsumer;
@Override @Override
public void write(PacketWriter writer) { public void write(PacketWriter writer) {
@ -24,12 +21,6 @@ public class SpawnPlayerPacket implements ServerPacket {
writer.writeDouble(position.getZ()); writer.writeDouble(position.getZ());
writer.writeByte((byte) (position.getYaw() * 256f / 360f)); writer.writeByte((byte) (position.getYaw() * 256f / 360f));
writer.writeByte((byte) (position.getPitch() * 256f / 360f)); writer.writeByte((byte) (position.getPitch() * 256f / 360f));
if (metadataConsumer != null) {
writer.write(metadataConsumer);
} else {
writer.writeByte((byte) 0xff);
}
} }
@Override @Override

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -3,6 +3,7 @@ package fr.themode.minestom.timer;
public abstract class TaskRunnable { public abstract class TaskRunnable {
private int id; private int id;
private int callCount;
public abstract void run(); public abstract void run();
@ -10,7 +11,15 @@ public abstract class TaskRunnable {
return id; return id;
} }
public int getCallCount() {
return callCount;
}
protected void setId(int id) { protected void setId(int id) {
this.id = 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); PacketWriter packetWriter = new PacketWriter(packet);
serverPacket.write(packetWriter); serverPacket.write(packetWriter);
System.out.println("WRITE PACKET: " + id + " " + serverPacket.getClass().getSimpleName());
callback.accept(packet.prepend(p -> { callback.accept(packet.prepend(p -> {
Utils.writeVarInt(packet, packet.getSize()); 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.chat.Chat;
import fr.themode.minestom.item.ItemStack; import fr.themode.minestom.item.ItemStack;
import fr.themode.minestom.net.ConnectionUtils; 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.buffer.BufferWrapper;
import fr.themode.minestom.utils.consumer.StringConsumer; 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) { public static void writeBlocks(BufferWrapper buffer, short[] blocksId, int bitsPerEntry) {
short count = 0; short count = 0;
for (short id : blocksId) for (short id : blocksId)