diff --git a/build.gradle b/build.gradle index 479ff1206..2b5b7f986 100644 --- a/build.gradle +++ b/build.gradle @@ -1,5 +1,6 @@ plugins { id 'java' + id 'net.ltgt.apt' version '0.10' } group 'fr.themode.minestom' @@ -12,12 +13,26 @@ repositories { maven { url 'https://jitpack.io' } } +def lombokDependency = 'org.projectlombok:lombok:1.18.2' + + dependencies { testCompile group: 'junit', name: 'junit', version: '4.12' + + compileOnly lombokDependency + + apt lombokDependency + + // https://mvnrepository.com/artifact/com.github.jhg023/SimpleNet + compile group: 'com.github.jhg023', name: 'SimpleNet', version: '1.5.1' + // https://mvnrepository.com/artifact/it.unimi.dsi/fastutil + compile group: 'it.unimi.dsi', name: 'fastutil', version: '8.3.0' + compile 'com.github.Querz:NBT:4.1' implementation 'com.github.luben:zstd-jni:1.4.3-1' implementation 'com.esotericsoftware:reflectasm:1.11.9' implementation 'com.github.LynnOwens:starlite:9971b899f7' - //implementation 'com.github.jhg023:SimpleNet:1.5.0' - implementation 'com.github.jhg023:SimpleNet:97dbc4951e' + // https://mvnrepository.com/artifact/com.google.code.gson/gson + compile group: 'com.google.code.gson', name: 'gson', version: '2.8.5' + } diff --git a/src/main/java/fr/themode/minestom/Main.java b/src/main/java/fr/themode/minestom/Main.java index c883156e7..8b4ec0c00 100644 --- a/src/main/java/fr/themode/minestom/Main.java +++ b/src/main/java/fr/themode/minestom/Main.java @@ -4,8 +4,8 @@ import com.github.simplenet.Server; import fr.themode.minestom.data.DataManager; import fr.themode.minestom.entity.EntityManager; import fr.themode.minestom.entity.Player; -import fr.themode.minestom.instance.BlockManager; import fr.themode.minestom.instance.InstanceManager; +import fr.themode.minestom.instance.block.BlockManager; import fr.themode.minestom.instance.demo.StoneBlock; import fr.themode.minestom.listener.PacketListenerManager; import fr.themode.minestom.net.ConnectionManager; @@ -22,7 +22,6 @@ public class Main { // Thread number public static final int THREAD_COUNT_PACKET_WRITER = 2; public static final int THREAD_COUNT_IO = 2; - public static final int THREAD_COUNT_CHUNK_BATCH = 2; public static final int THREAD_COUNT_BLOCK_BATCH = 2; public static final int THREAD_COUNT_ENTITIES = 2; public static final int THREAD_COUNT_PLAYERS_ENTITIES = 2; @@ -64,7 +63,7 @@ public class Main { System.out.println("CONNECTION"); client.preDisconnect(() -> { - System.out.println("A Disconnection"); + System.out.println("DISCONNECTION"); PlayerConnection playerConnection = packetProcessor.getPlayerConnection(client); if (playerConnection != null) { playerConnection.refreshOnline(false); @@ -115,6 +114,11 @@ public class Main { // Entities update entityManager.update(); + // Blocks update + blockManager.update(); + + // TODO miscellaneous update (scoreboard) + // Sleep until next tick long sleepTime = (tickDistance - (System.nanoTime() - currentTime)) / 1000000; sleepTime = Math.max(1, sleepTime); diff --git a/src/main/java/fr/themode/minestom/chat/ChatColor.java b/src/main/java/fr/themode/minestom/chat/ChatColor.java new file mode 100644 index 000000000..2cacc1d42 --- /dev/null +++ b/src/main/java/fr/themode/minestom/chat/ChatColor.java @@ -0,0 +1,35 @@ +package fr.themode.minestom.chat; + +import fr.themode.minestom.utils.HexUtils; + +public enum ChatColor { + + BLACK((byte) 0), + DARK_BLUE((byte) 1), + DARK_GREEN((byte) 2), + DARK_AQUA((byte) 3), + DARK_RED((byte) 4), + DARK_PURPLE((byte) 5), + GOLD((byte) 6), + GRAY((byte) 7), + DARK_GRAY((byte) 8), + BLUE((byte) 9), + GREEN((byte) 0xa), + AQUA((byte) 0xb), + RED((byte) 0xc), + LIGHT_PURPLE((byte) 0xd), + YELLOW((byte) 0xe), + WHITE((byte) 0xf); + + + private byte id; + + ChatColor(byte id) { + this.id = id; + } + + @Override + public String toString() { + return Chat.COLOR_CHAR + String.valueOf(HexUtils.byteToHex(id)); + } +} diff --git a/src/main/java/fr/themode/minestom/entity/Entity.java b/src/main/java/fr/themode/minestom/entity/Entity.java index fc59ff63b..461ee7a37 100644 --- a/src/main/java/fr/themode/minestom/entity/Entity.java +++ b/src/main/java/fr/themode/minestom/entity/Entity.java @@ -204,21 +204,20 @@ public abstract class Entity implements Viewable, DataContainer { // Velocity if (velocityTime != 0) { + if (this instanceof Player) { + sendPacketToViewersAndSelf(getVelocityPacket()); + } else { + 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()); + } else if (this instanceof EntityCreature) { + teleport(getPosition()); + } + } if (time >= velocityTime) { sendSynchronization(); // Send synchronization after velocity ended resetVelocity(); - } else { - if (this instanceof Player) { - sendPacketToViewersAndSelf(getVelocityPacket()); - } else { - 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()); - } else if (this instanceof EntityCreature) { - teleport(getPosition()); - } - } } } diff --git a/src/main/java/fr/themode/minestom/entity/ItemEntity.java b/src/main/java/fr/themode/minestom/entity/ItemEntity.java index 5fb2dc378..dc0272172 100644 --- a/src/main/java/fr/themode/minestom/entity/ItemEntity.java +++ b/src/main/java/fr/themode/minestom/entity/ItemEntity.java @@ -18,7 +18,7 @@ public class ItemEntity extends ObjectEntity { super(34); this.itemStack = itemStack; setBoundingBox(0.25f, 0.25f, 0.25f); - setGravity(0.02f); + setGravity(0.025f); } @Override diff --git a/src/main/java/fr/themode/minestom/entity/LivingEntity.java b/src/main/java/fr/themode/minestom/entity/LivingEntity.java index c6b7610ff..71c385779 100644 --- a/src/main/java/fr/themode/minestom/entity/LivingEntity.java +++ b/src/main/java/fr/themode/minestom/entity/LivingEntity.java @@ -153,8 +153,12 @@ public abstract class LivingEntity extends Entity { for (int i = 0; i < length; i++) { Attribute attribute = Attribute.values()[i]; EntityPropertiesPacket.Property property = new EntityPropertiesPacket.Property(); + float maxValue = attribute.getMaxVanillaValue(); + float value = getAttributeValue(attribute); + value = value > maxValue ? maxValue : value; // Bypass vanilla limit client-side if needed (by sending the max value allowed) + property.key = attribute.getKey(); - property.value = getAttributeValue(attribute); + property.value = value; properties[i] = property; } diff --git a/src/main/java/fr/themode/minestom/entity/Player.java b/src/main/java/fr/themode/minestom/entity/Player.java index 1f2ae3a55..25d6c14f7 100644 --- a/src/main/java/fr/themode/minestom/entity/Player.java +++ b/src/main/java/fr/themode/minestom/entity/Player.java @@ -9,9 +9,9 @@ import fr.themode.minestom.collision.BoundingBox; import fr.themode.minestom.entity.property.Attribute; import fr.themode.minestom.event.*; import fr.themode.minestom.instance.Chunk; -import fr.themode.minestom.instance.CustomBlock; import fr.themode.minestom.instance.Instance; import fr.themode.minestom.instance.InstanceContainer; +import fr.themode.minestom.instance.block.CustomBlock; import fr.themode.minestom.instance.demo.ChunkGeneratorDemo; import fr.themode.minestom.inventory.Inventory; import fr.themode.minestom.inventory.PlayerInventory; @@ -20,7 +20,6 @@ import fr.themode.minestom.net.packet.client.ClientPlayPacket; import fr.themode.minestom.net.packet.server.ServerPacket; import fr.themode.minestom.net.packet.server.play.*; import fr.themode.minestom.net.player.PlayerConnection; -import fr.themode.minestom.scoreboard.Scoreboard; import fr.themode.minestom.utils.*; import fr.themode.minestom.world.Dimension; import fr.themode.minestom.world.LevelType; @@ -145,7 +144,7 @@ public class Player extends LivingEntity { }); setEventCallback(PlayerSpawnEvent.class, event -> { - setGameMode(GameMode.CREATIVE); + setGameMode(GameMode.SURVIVAL); teleport(new Position(0, 66, 0)); /*Random random = new Random(); @@ -183,14 +182,12 @@ public class Player extends LivingEntity { setAttribute(Attribute.MAX_HEALTH, 10); heal(); - setExp(0.9f); - - 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");*/ }); } diff --git a/src/main/java/fr/themode/minestom/entity/property/Attribute.java b/src/main/java/fr/themode/minestom/entity/property/Attribute.java index db121c309..299de52b7 100644 --- a/src/main/java/fr/themode/minestom/entity/property/Attribute.java +++ b/src/main/java/fr/themode/minestom/entity/property/Attribute.java @@ -2,22 +2,24 @@ package fr.themode.minestom.entity.property; public enum Attribute { - MAX_HEALTH("generic.maxHealth", 20), - FOLLOW_RANGE("generic.followRange", 32), - KNOCKBACK_RESISTANCE("generic.knockbackResistance", 0), - MOVEMENT_SPEED("generic.movementSpeed", 0.7f), - ATTACK_DAMAGE("generic.attackDamage", 2), - ATTACK_SPEED("generic.attackSpeed", 4), - FLYING_SPEED("generic.flyingSpeed", 0.4f), - HORSE_JUMP_STRENGTH("horse.jumpStrength", 0.7f), - ZOMBIE_SPAWN_REINFORCEMENTS("zombie.spawnReinforcements", 0); + MAX_HEALTH("generic.maxHealth", 20, 1024), + FOLLOW_RANGE("generic.followRange", 32, 2048), + KNOCKBACK_RESISTANCE("generic.knockbackResistance", 0, 1), + MOVEMENT_SPEED("generic.movementSpeed", 0.7f, 1024), + ATTACK_DAMAGE("generic.attackDamage", 2, 2048), + ATTACK_SPEED("generic.attackSpeed", 4, 1024), + FLYING_SPEED("generic.flyingSpeed", 0.4f, 1024), + HORSE_JUMP_STRENGTH("horse.jumpStrength", 0.7f, 2), + ZOMBIE_SPAWN_REINFORCEMENTS("zombie.spawnReinforcements", 0, 1); private String key; private float defaultValue; + private float maxVanillaValue; - Attribute(String key, float defaultValue) { + Attribute(String key, float defaultValue, float maxVanillaValue) { this.key = key; this.defaultValue = defaultValue; + this.maxVanillaValue = maxVanillaValue; } public String getKey() { @@ -27,4 +29,8 @@ public enum Attribute { public float getDefaultValue() { return defaultValue; } + + public float getMaxVanillaValue() { + return maxVanillaValue; + } } diff --git a/src/main/java/fr/themode/minestom/event/PlayerStartDiggingEvent.java b/src/main/java/fr/themode/minestom/event/PlayerStartDiggingEvent.java index 018dcbcf7..e52516c7b 100644 --- a/src/main/java/fr/themode/minestom/event/PlayerStartDiggingEvent.java +++ b/src/main/java/fr/themode/minestom/event/PlayerStartDiggingEvent.java @@ -1,6 +1,6 @@ package fr.themode.minestom.event; -import fr.themode.minestom.instance.CustomBlock; +import fr.themode.minestom.instance.block.CustomBlock; public class PlayerStartDiggingEvent extends CancellableEvent { diff --git a/src/main/java/fr/themode/minestom/instance/Chunk.java b/src/main/java/fr/themode/minestom/instance/Chunk.java index 7a88f083e..f7c396fbc 100644 --- a/src/main/java/fr/themode/minestom/instance/Chunk.java +++ b/src/main/java/fr/themode/minestom/instance/Chunk.java @@ -3,7 +3,9 @@ package fr.themode.minestom.instance; import com.github.simplenet.packet.Packet; import fr.themode.minestom.Main; import fr.themode.minestom.Viewable; +import fr.themode.minestom.data.Data; import fr.themode.minestom.entity.Player; +import fr.themode.minestom.instance.block.CustomBlock; import fr.themode.minestom.net.packet.server.play.ChunkDataPacket; import fr.themode.minestom.utils.PacketUtils; import fr.themode.minestom.utils.SerializerUtils; @@ -14,7 +16,9 @@ import java.io.IOException; import java.util.Collections; import java.util.Set; import java.util.concurrent.CopyOnWriteArraySet; +import java.util.function.Consumer; +// TODO air management to free memory public class Chunk implements Viewable { public static final int CHUNK_SIZE_X = 16; @@ -30,6 +34,8 @@ public class Chunk implements Viewable { // Block entities private Set blockEntities = new CopyOnWriteArraySet<>(); + // TODO blocks update + // Cache private Set viewers = new CopyOnWriteArraySet<>(); private Packet fullDataPacket; @@ -42,16 +48,16 @@ public class Chunk implements Viewable { this.chunkZ = chunkZ; } - protected void setBlock(byte x, byte y, byte z, short blockId) { + public void UNSAFE_setBlock(byte x, byte y, byte z, short blockId) { setBlock(x, y, z, blockId, (short) 0); } - protected void setCustomBlock(byte x, byte y, byte z, String blockId) { + public void UNSAFE_setCustomBlock(byte x, byte y, byte z, String blockId) { CustomBlock customBlock = Main.getBlockManager().getBlock(blockId); if (customBlock == null) throw new IllegalArgumentException("The block " + blockId + " does not exist or isn't registered"); - setBlock(x, y, z, customBlock.getType(), customBlock.getId()); + setCustomBlock(x, y, z, customBlock); } protected void setCustomBlock(byte x, byte y, byte z, short customBlockId) { @@ -59,7 +65,7 @@ public class Chunk implements Viewable { if (customBlock == null) throw new IllegalArgumentException("The custom block " + customBlockId + " does not exist or isn't registered"); - setBlock(x, y, z, customBlock.getType(), customBlockId); + setCustomBlock(x, y, z, customBlock); } private void setBlock(byte x, byte y, byte z, short blockType, short customId) { @@ -74,6 +80,14 @@ public class Chunk implements Viewable { this.packetUpdated = false; } + private void setCustomBlock(byte x, byte y, byte z, CustomBlock customBlock) { + if (customBlock.hasUpdate()) { + Consumer test = customBlock::update; + // TODO add update callback + } + setBlock(x, y, z, customBlock.getType(), customBlock.getId()); + } + public short getBlockId(byte x, byte y, byte z) { return this.blocksId[SerializerUtils.chunkCoordToIndex(x, y, z)]; } @@ -83,6 +97,17 @@ public class Chunk implements Viewable { return id != 0 ? Main.getBlockManager().getBlock(id) : null; } + public void updateBlocks() { + /** + * TODO blocks' update: + * - get all custom blocks + * - check if they have an update method + * - check if they should be updated + * - get custom block's data + * - call update method + */ + } + public Biome getBiome() { return biome; } @@ -110,6 +135,7 @@ public class Chunk implements Viewable { public void setFullDataPacket(Packet fullDataPacket) { this.fullDataPacket = fullDataPacket; + this.packetUpdated = true; } protected byte[] getSerializedData() throws IOException { @@ -153,10 +179,9 @@ public class Chunk implements Viewable { } // Write the packet in the current thread - protected void refreshDataPacket() { + public void refreshDataPacket() { PacketUtils.writePacket(getFreshFullDataPacket(), packet -> { - fullDataPacket = packet; - packetUpdated = true; + setFullDataPacket(packet); }); } diff --git a/src/main/java/fr/themode/minestom/instance/ChunkGenerator.java b/src/main/java/fr/themode/minestom/instance/ChunkGenerator.java index 212e5fee0..29bbae53b 100644 --- a/src/main/java/fr/themode/minestom/instance/ChunkGenerator.java +++ b/src/main/java/fr/themode/minestom/instance/ChunkGenerator.java @@ -1,5 +1,7 @@ package fr.themode.minestom.instance; +import fr.themode.minestom.instance.batch.ChunkBatch; + public abstract class ChunkGenerator { public abstract void generateChunkData(ChunkBatch batch, int chunkX, int chunkZ); diff --git a/src/main/java/fr/themode/minestom/instance/ChunkLoaderIO.java b/src/main/java/fr/themode/minestom/instance/ChunkLoaderIO.java index cf1272cf9..fcc1289ca 100644 --- a/src/main/java/fr/themode/minestom/instance/ChunkLoaderIO.java +++ b/src/main/java/fr/themode/minestom/instance/ChunkLoaderIO.java @@ -69,7 +69,7 @@ public class ChunkLoaderIO { if (isCustomBlock) { chunk.setCustomBlock(chunkPos[0], chunkPos[1], chunkPos[2], blockId); } else { - chunk.setBlock(chunkPos[0], chunkPos[1], chunkPos[2], blockId); + chunk.UNSAFE_setBlock(chunkPos[0], chunkPos[1], chunkPos[2], blockId); } } } catch (EOFException e) { diff --git a/src/main/java/fr/themode/minestom/instance/Instance.java b/src/main/java/fr/themode/minestom/instance/Instance.java index b57490358..e5bb944cd 100644 --- a/src/main/java/fr/themode/minestom/instance/Instance.java +++ b/src/main/java/fr/themode/minestom/instance/Instance.java @@ -3,6 +3,9 @@ package fr.themode.minestom.instance; import com.github.simplenet.packet.Packet; import fr.themode.minestom.Main; import fr.themode.minestom.entity.*; +import fr.themode.minestom.instance.batch.BlockBatch; +import fr.themode.minestom.instance.batch.ChunkBatch; +import fr.themode.minestom.instance.block.CustomBlock; import fr.themode.minestom.net.PacketWriterUtils; import fr.themode.minestom.net.packet.server.play.ChunkDataPacket; import fr.themode.minestom.utils.BlockPosition; diff --git a/src/main/java/fr/themode/minestom/instance/InstanceContainer.java b/src/main/java/fr/themode/minestom/instance/InstanceContainer.java index ebba125f6..5a736fa76 100644 --- a/src/main/java/fr/themode/minestom/instance/InstanceContainer.java +++ b/src/main/java/fr/themode/minestom/instance/InstanceContainer.java @@ -3,6 +3,8 @@ package fr.themode.minestom.instance; import com.github.simplenet.packet.Packet; import fr.themode.minestom.entity.Player; import fr.themode.minestom.event.PlayerBlockBreakEvent; +import fr.themode.minestom.instance.batch.BlockBatch; +import fr.themode.minestom.instance.batch.ChunkBatch; import fr.themode.minestom.net.PacketWriterUtils; import fr.themode.minestom.net.packet.server.play.BlockChangePacket; import fr.themode.minestom.net.packet.server.play.ParticlePacket; @@ -41,7 +43,7 @@ public class InstanceContainer extends Instance { byte chunkX = (byte) (x % 16); byte chunkY = (byte) y; byte chunkZ = (byte) (z % 16); - chunk.setBlock(chunkX, chunkY, chunkZ, blockId); + chunk.UNSAFE_setBlock(chunkX, chunkY, chunkZ, blockId); sendBlockChange(chunk, x, y, z, blockId); } } @@ -53,7 +55,7 @@ public class InstanceContainer extends Instance { byte chunkX = (byte) (x % 16); byte chunkY = (byte) y; byte chunkZ = (byte) (z % 16); - chunk.setCustomBlock(chunkX, chunkY, chunkZ, blockId); + chunk.UNSAFE_setCustomBlock(chunkX, chunkY, chunkZ, blockId); short id = chunk.getBlockId(chunkX, chunkY, chunkZ); sendBlockChange(chunk, x, y, z, id); } @@ -199,7 +201,6 @@ public class InstanceContainer extends Instance { if (data == null || !chunk.packetUpdated) { PacketWriterUtils.writeCallbackPacket(chunk.getFreshFullDataPacket(), buffer -> { chunk.setFullDataPacket(buffer); - chunk.packetUpdated = true; sendChunkUpdate(player, chunk); }); } else { diff --git a/src/main/java/fr/themode/minestom/instance/SharedInstance.java b/src/main/java/fr/themode/minestom/instance/SharedInstance.java index f147f25a3..3912d2c6a 100644 --- a/src/main/java/fr/themode/minestom/instance/SharedInstance.java +++ b/src/main/java/fr/themode/minestom/instance/SharedInstance.java @@ -1,6 +1,8 @@ package fr.themode.minestom.instance; import fr.themode.minestom.entity.Player; +import fr.themode.minestom.instance.batch.BlockBatch; +import fr.themode.minestom.instance.batch.ChunkBatch; import fr.themode.minestom.utils.BlockPosition; import java.io.File; diff --git a/src/main/java/fr/themode/minestom/instance/BlockBatch.java b/src/main/java/fr/themode/minestom/instance/batch/BlockBatch.java similarity index 82% rename from src/main/java/fr/themode/minestom/instance/BlockBatch.java rename to src/main/java/fr/themode/minestom/instance/batch/BlockBatch.java index 21ba03d9f..9c0898c95 100644 --- a/src/main/java/fr/themode/minestom/instance/BlockBatch.java +++ b/src/main/java/fr/themode/minestom/instance/batch/BlockBatch.java @@ -1,17 +1,15 @@ -package fr.themode.minestom.instance; +package fr.themode.minestom.instance.batch; -import fr.themode.minestom.Main; -import fr.themode.minestom.utils.thread.MinestomThread; +import fr.themode.minestom.instance.BlockModifier; +import fr.themode.minestom.instance.Chunk; +import fr.themode.minestom.instance.InstanceContainer; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.concurrent.ExecutorService; -public class BlockBatch implements BlockModifier { - - private static final ExecutorService batchesPool = new MinestomThread(Main.THREAD_COUNT_BLOCK_BATCH, "Ms-BlockBatchPool"); +public class BlockBatch implements IBatch, BlockModifier { private InstanceContainer instance; @@ -85,9 +83,9 @@ public class BlockBatch implements BlockModifier { public void apply(Chunk chunk) { if (blockIdentifier == null) { - chunk.setBlock((byte) x, (byte) y, (byte) z, blockId); + chunk.UNSAFE_setBlock((byte) x, (byte) y, (byte) z, blockId); } else { - chunk.setCustomBlock((byte) x, (byte) y, (byte) z, blockIdentifier); + chunk.UNSAFE_setCustomBlock((byte) x, (byte) y, (byte) z, blockIdentifier); } } diff --git a/src/main/java/fr/themode/minestom/instance/ChunkBatch.java b/src/main/java/fr/themode/minestom/instance/batch/ChunkBatch.java similarity index 81% rename from src/main/java/fr/themode/minestom/instance/ChunkBatch.java rename to src/main/java/fr/themode/minestom/instance/batch/ChunkBatch.java index 063a8dbaa..35f682fbe 100644 --- a/src/main/java/fr/themode/minestom/instance/ChunkBatch.java +++ b/src/main/java/fr/themode/minestom/instance/batch/ChunkBatch.java @@ -1,19 +1,18 @@ -package fr.themode.minestom.instance; +package fr.themode.minestom.instance.batch; -import fr.themode.minestom.Main; -import fr.themode.minestom.utils.thread.MinestomThread; +import fr.themode.minestom.instance.BlockModifier; +import fr.themode.minestom.instance.Chunk; +import fr.themode.minestom.instance.ChunkGenerator; +import fr.themode.minestom.instance.InstanceContainer; import java.util.ArrayList; import java.util.List; -import java.util.concurrent.ExecutorService; import java.util.function.Consumer; /** * Use chunk coordinate (0-16) instead of world's */ -public class ChunkBatch implements BlockModifier { - - private static final ExecutorService batchesPool = new MinestomThread(Main.THREAD_COUNT_CHUNK_BATCH, "Ms-ChunkBatchPool"); +public class ChunkBatch implements IBatch, BlockModifier { private InstanceContainer instance; private Chunk chunk; @@ -82,9 +81,9 @@ public class ChunkBatch implements BlockModifier { public void apply(Chunk chunk) { if (blockIdentifier == null) { - chunk.setBlock(x, y, z, blockId); + chunk.UNSAFE_setBlock(x, y, z, blockId); } else { - chunk.setCustomBlock(x, y, z, blockIdentifier); + chunk.UNSAFE_setCustomBlock(x, y, z, blockIdentifier); } } diff --git a/src/main/java/fr/themode/minestom/instance/batch/IBatch.java b/src/main/java/fr/themode/minestom/instance/batch/IBatch.java new file mode 100644 index 000000000..f28c6949b --- /dev/null +++ b/src/main/java/fr/themode/minestom/instance/batch/IBatch.java @@ -0,0 +1,12 @@ +package fr.themode.minestom.instance.batch; + +import fr.themode.minestom.Main; +import fr.themode.minestom.utils.thread.MinestomThread; + +import java.util.concurrent.ExecutorService; + +public interface IBatch { + + ExecutorService batchesPool = new MinestomThread(Main.THREAD_COUNT_BLOCK_BATCH, "Ms-BlockBatchPool"); + +} diff --git a/src/main/java/fr/themode/minestom/instance/BlockManager.java b/src/main/java/fr/themode/minestom/instance/block/BlockManager.java similarity index 57% rename from src/main/java/fr/themode/minestom/instance/BlockManager.java rename to src/main/java/fr/themode/minestom/instance/block/BlockManager.java index 632ef4143..53d1d4d43 100644 --- a/src/main/java/fr/themode/minestom/instance/BlockManager.java +++ b/src/main/java/fr/themode/minestom/instance/block/BlockManager.java @@ -1,4 +1,9 @@ -package fr.themode.minestom.instance; +package fr.themode.minestom.instance.block; + +import fr.themode.minestom.Main; +import fr.themode.minestom.instance.Chunk; +import fr.themode.minestom.instance.Instance; +import fr.themode.minestom.instance.InstanceManager; import java.util.HashMap; import java.util.Map; @@ -6,6 +11,8 @@ import java.util.function.Supplier; public class BlockManager { + private static InstanceManager instanceManager = Main.getInstanceManager(); + private Map blocksInternalId = new HashMap<>(); private Map blocksId = new HashMap<>(); @@ -17,6 +24,15 @@ public class BlockManager { this.blocksId.put(identifier, customBlock); } + public void update() { + for (Instance instance : instanceManager.getInstances()) { + // TODO only InstanceContainer? + for (Chunk chunk : instance.getChunks()) { + chunk.updateBlocks(); + } + } + } + public CustomBlock getBlock(String identifier) { return blocksId.get(identifier); } diff --git a/src/main/java/fr/themode/minestom/instance/CustomBlock.java b/src/main/java/fr/themode/minestom/instance/block/CustomBlock.java similarity index 66% rename from src/main/java/fr/themode/minestom/instance/CustomBlock.java rename to src/main/java/fr/themode/minestom/instance/block/CustomBlock.java index a2eef14c3..199a65208 100644 --- a/src/main/java/fr/themode/minestom/instance/CustomBlock.java +++ b/src/main/java/fr/themode/minestom/instance/block/CustomBlock.java @@ -1,5 +1,6 @@ -package fr.themode.minestom.instance; +package fr.themode.minestom.instance.block; +import fr.themode.minestom.data.Data; import fr.themode.minestom.entity.Player; import java.util.concurrent.atomic.AtomicInteger; @@ -18,6 +19,12 @@ public abstract class CustomBlock { this.id = (short) idCounter.incrementAndGet(); } + public void update(Data data) { + throw new UnsupportedOperationException("Update method not overriden"); + } + + public abstract UpdateOption getUpdateOption(); + public abstract short getType(); public abstract String getIdentifier(); @@ -27,6 +34,10 @@ public abstract class CustomBlock { */ public abstract int getBreakDelay(Player player); + public boolean hasUpdate() { + return getUpdateOption().getValue() > 0; + } + public short getId() { return id; } diff --git a/src/main/java/fr/themode/minestom/instance/block/UpdateOption.java b/src/main/java/fr/themode/minestom/instance/block/UpdateOption.java new file mode 100644 index 000000000..bd900c25b --- /dev/null +++ b/src/main/java/fr/themode/minestom/instance/block/UpdateOption.java @@ -0,0 +1,26 @@ +package fr.themode.minestom.instance.block; + +import fr.themode.minestom.timer.TimeUnit; + +public class UpdateOption { + + private int value; + private TimeUnit timeUnit; + + public UpdateOption(int value, TimeUnit timeUnit) { + this.value = value; + this.timeUnit = timeUnit; + } + + public UpdateOption() { + this(0, null); + } + + public int getValue() { + return value; + } + + public TimeUnit getTimeUnit() { + return timeUnit; + } +} diff --git a/src/main/java/fr/themode/minestom/instance/demo/ChunkGeneratorDemo.java b/src/main/java/fr/themode/minestom/instance/demo/ChunkGeneratorDemo.java index fcdd8c526..d13759699 100644 --- a/src/main/java/fr/themode/minestom/instance/demo/ChunkGeneratorDemo.java +++ b/src/main/java/fr/themode/minestom/instance/demo/ChunkGeneratorDemo.java @@ -1,8 +1,8 @@ package fr.themode.minestom.instance.demo; import fr.themode.minestom.instance.Biome; -import fr.themode.minestom.instance.ChunkBatch; import fr.themode.minestom.instance.ChunkGenerator; +import fr.themode.minestom.instance.batch.ChunkBatch; import java.util.Random; diff --git a/src/main/java/fr/themode/minestom/instance/demo/StoneBlock.java b/src/main/java/fr/themode/minestom/instance/demo/StoneBlock.java index 80cef0c35..20a5d49a8 100644 --- a/src/main/java/fr/themode/minestom/instance/demo/StoneBlock.java +++ b/src/main/java/fr/themode/minestom/instance/demo/StoneBlock.java @@ -1,10 +1,25 @@ package fr.themode.minestom.instance.demo; +import fr.themode.minestom.data.Data; import fr.themode.minestom.entity.Player; -import fr.themode.minestom.instance.CustomBlock; +import fr.themode.minestom.instance.block.CustomBlock; +import fr.themode.minestom.instance.block.UpdateOption; +import fr.themode.minestom.timer.TimeUnit; public class StoneBlock extends CustomBlock { + private static final UpdateOption UPDATE_OPTION = new UpdateOption(1, TimeUnit.TICK); + + @Override + public UpdateOption getUpdateOption() { + return UPDATE_OPTION; + } + + @Override + public void update(Data data) { + System.out.println("BLOCK HAS BEEN UPDATED"); + } + @Override public short getType() { return 1; diff --git a/src/main/java/fr/themode/minestom/listener/BlockPlacementListener.java b/src/main/java/fr/themode/minestom/listener/BlockPlacementListener.java index 282d9b88b..2998a4370 100644 --- a/src/main/java/fr/themode/minestom/listener/BlockPlacementListener.java +++ b/src/main/java/fr/themode/minestom/listener/BlockPlacementListener.java @@ -1,5 +1,6 @@ package fr.themode.minestom.listener; +import fr.themode.minestom.entity.GameMode; import fr.themode.minestom.entity.Player; import fr.themode.minestom.event.PlayerBlockPlaceEvent; import fr.themode.minestom.instance.Chunk; @@ -37,6 +38,8 @@ public class BlockPlacementListener { boolean intersectPlayer = player.getBoundingBox().intersect(blockPosition); // TODO check if collide with nearby players if (!intersectPlayer) { PlayerBlockPlaceEvent playerBlockPlaceEvent = new PlayerBlockPlaceEvent((short) 10, blockPosition, packet.hand); + playerBlockPlaceEvent.consumeBlock(player.getGameMode() != GameMode.CREATIVE); + player.callEvent(PlayerBlockPlaceEvent.class, playerBlockPlaceEvent); if (!playerBlockPlaceEvent.isCancelled()) { instance.setBlock(blockPosition, "custom_block"); // TODO set useItem's block instead diff --git a/src/main/java/fr/themode/minestom/listener/KeepAliveListener.java b/src/main/java/fr/themode/minestom/listener/KeepAliveListener.java index c4d0b757a..28879ef09 100644 --- a/src/main/java/fr/themode/minestom/listener/KeepAliveListener.java +++ b/src/main/java/fr/themode/minestom/listener/KeepAliveListener.java @@ -1,5 +1,6 @@ package fr.themode.minestom.listener; +import fr.themode.minestom.chat.ChatColor; import fr.themode.minestom.entity.Player; import fr.themode.minestom.net.packet.client.play.ClientKeepAlivePacket; @@ -7,7 +8,7 @@ public class KeepAliveListener { public static void listener(ClientKeepAlivePacket packet, Player player) { if (packet.id != player.getLastKeepAlive()) { - player.kick("Bad Keep Alive packet"); + player.kick(ChatColor.RED + "Bad Keep Alive packet"); } } diff --git a/src/main/java/fr/themode/minestom/listener/PlayerDiggingListener.java b/src/main/java/fr/themode/minestom/listener/PlayerDiggingListener.java index 4311c2255..e1c2152ce 100644 --- a/src/main/java/fr/themode/minestom/listener/PlayerDiggingListener.java +++ b/src/main/java/fr/themode/minestom/listener/PlayerDiggingListener.java @@ -5,8 +5,8 @@ import fr.themode.minestom.entity.ItemEntity; import fr.themode.minestom.entity.Player; import fr.themode.minestom.event.ItemDropEvent; import fr.themode.minestom.event.PlayerStartDiggingEvent; -import fr.themode.minestom.instance.CustomBlock; import fr.themode.minestom.instance.Instance; +import fr.themode.minestom.instance.block.CustomBlock; import fr.themode.minestom.inventory.PlayerInventory; import fr.themode.minestom.item.ItemStack; import fr.themode.minestom.net.packet.client.play.ClientPlayerDiggingPacket; diff --git a/src/main/java/fr/themode/minestom/timer/TimeUnit.java b/src/main/java/fr/themode/minestom/timer/TimeUnit.java new file mode 100644 index 000000000..c1b080f36 --- /dev/null +++ b/src/main/java/fr/themode/minestom/timer/TimeUnit.java @@ -0,0 +1,21 @@ +package fr.themode.minestom.timer; + +import fr.themode.minestom.Main; + +public enum TimeUnit { + + TICK, MILLISECOND, SECOND; + + public long toMilliseconds(int value) { + switch (this) { + case TICK: + return Main.TICK_MS * value; + case SECOND: + return value * 1000; + case MILLISECOND: + return value; + } + return -1; // Unexpected + } + +} diff --git a/src/main/java/fr/themode/minestom/utils/HexUtils.java b/src/main/java/fr/themode/minestom/utils/HexUtils.java new file mode 100644 index 000000000..90f524d22 --- /dev/null +++ b/src/main/java/fr/themode/minestom/utils/HexUtils.java @@ -0,0 +1,13 @@ +package fr.themode.minestom.utils; + +public class HexUtils { + + private static final char[] HEX_ARRAY = "0123456789ABCDEF".toCharArray(); + + public static char byteToHex(byte b) { + int v = b & 0xFF; + char hexChar = HEX_ARRAY[v >>> 4]; + return hexChar; + } + +}