General optimization

This commit is contained in:
TheMode 2019-09-14 18:00:18 +02:00
parent ce83ea05a3
commit e8aa4bfe9e
28 changed files with 280 additions and 72 deletions

View File

@ -1,5 +1,6 @@
plugins { plugins {
id 'java' id 'java'
id 'net.ltgt.apt' version '0.10'
} }
group 'fr.themode.minestom' group 'fr.themode.minestom'
@ -12,12 +13,26 @@ repositories {
maven { url 'https://jitpack.io' } maven { url 'https://jitpack.io' }
} }
def lombokDependency = 'org.projectlombok:lombok:1.18.2'
dependencies { dependencies {
testCompile group: 'junit', name: 'junit', version: '4.12' 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' compile 'com.github.Querz:NBT:4.1'
implementation 'com.github.luben:zstd-jni:1.4.3-1' implementation 'com.github.luben:zstd-jni:1.4.3-1'
implementation 'com.esotericsoftware:reflectasm:1.11.9' implementation 'com.esotericsoftware:reflectasm:1.11.9'
implementation 'com.github.LynnOwens:starlite:9971b899f7' implementation 'com.github.LynnOwens:starlite:9971b899f7'
//implementation 'com.github.jhg023:SimpleNet:1.5.0' // https://mvnrepository.com/artifact/com.google.code.gson/gson
implementation 'com.github.jhg023:SimpleNet:97dbc4951e' compile group: 'com.google.code.gson', name: 'gson', version: '2.8.5'
} }

View File

@ -4,8 +4,8 @@ import com.github.simplenet.Server;
import fr.themode.minestom.data.DataManager; import fr.themode.minestom.data.DataManager;
import fr.themode.minestom.entity.EntityManager; import fr.themode.minestom.entity.EntityManager;
import fr.themode.minestom.entity.Player; import fr.themode.minestom.entity.Player;
import fr.themode.minestom.instance.BlockManager;
import fr.themode.minestom.instance.InstanceManager; import fr.themode.minestom.instance.InstanceManager;
import fr.themode.minestom.instance.block.BlockManager;
import fr.themode.minestom.instance.demo.StoneBlock; import fr.themode.minestom.instance.demo.StoneBlock;
import fr.themode.minestom.listener.PacketListenerManager; import fr.themode.minestom.listener.PacketListenerManager;
import fr.themode.minestom.net.ConnectionManager; import fr.themode.minestom.net.ConnectionManager;
@ -22,7 +22,6 @@ public class Main {
// Thread number // Thread number
public static final int THREAD_COUNT_PACKET_WRITER = 2; public static final int THREAD_COUNT_PACKET_WRITER = 2;
public static final int THREAD_COUNT_IO = 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_BLOCK_BATCH = 2;
public static final int THREAD_COUNT_ENTITIES = 2; public static final int THREAD_COUNT_ENTITIES = 2;
public static final int THREAD_COUNT_PLAYERS_ENTITIES = 2; public static final int THREAD_COUNT_PLAYERS_ENTITIES = 2;
@ -64,7 +63,7 @@ public class Main {
System.out.println("CONNECTION"); System.out.println("CONNECTION");
client.preDisconnect(() -> { client.preDisconnect(() -> {
System.out.println("A Disconnection"); System.out.println("DISCONNECTION");
PlayerConnection playerConnection = packetProcessor.getPlayerConnection(client); PlayerConnection playerConnection = packetProcessor.getPlayerConnection(client);
if (playerConnection != null) { if (playerConnection != null) {
playerConnection.refreshOnline(false); playerConnection.refreshOnline(false);
@ -115,6 +114,11 @@ public class Main {
// Entities update // Entities update
entityManager.update(); entityManager.update();
// Blocks update
blockManager.update();
// TODO miscellaneous update (scoreboard)
// Sleep until next tick // Sleep until next tick
long sleepTime = (tickDistance - (System.nanoTime() - currentTime)) / 1000000; long sleepTime = (tickDistance - (System.nanoTime() - currentTime)) / 1000000;
sleepTime = Math.max(1, sleepTime); sleepTime = Math.max(1, sleepTime);

View File

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

View File

@ -204,21 +204,20 @@ public abstract class Entity implements Viewable, DataContainer {
// Velocity // Velocity
if (velocityTime != 0) { 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) { if (time >= velocityTime) {
sendSynchronization(); // Send synchronization after velocity ended sendSynchronization(); // Send synchronization after velocity ended
resetVelocity(); 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());
}
}
} }
} }

View File

@ -18,7 +18,7 @@ public class ItemEntity extends ObjectEntity {
super(34); super(34);
this.itemStack = itemStack; this.itemStack = itemStack;
setBoundingBox(0.25f, 0.25f, 0.25f); setBoundingBox(0.25f, 0.25f, 0.25f);
setGravity(0.02f); setGravity(0.025f);
} }
@Override @Override

View File

@ -153,8 +153,12 @@ public abstract class LivingEntity extends Entity {
for (int i = 0; i < length; i++) { for (int i = 0; i < length; i++) {
Attribute attribute = Attribute.values()[i]; Attribute attribute = Attribute.values()[i];
EntityPropertiesPacket.Property property = new EntityPropertiesPacket.Property(); 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.key = attribute.getKey();
property.value = getAttributeValue(attribute); property.value = value;
properties[i] = property; properties[i] = property;
} }

View File

@ -9,9 +9,9 @@ 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.*;
import fr.themode.minestom.instance.Chunk; import fr.themode.minestom.instance.Chunk;
import fr.themode.minestom.instance.CustomBlock;
import fr.themode.minestom.instance.Instance; import fr.themode.minestom.instance.Instance;
import fr.themode.minestom.instance.InstanceContainer; import fr.themode.minestom.instance.InstanceContainer;
import fr.themode.minestom.instance.block.CustomBlock;
import fr.themode.minestom.instance.demo.ChunkGeneratorDemo; import fr.themode.minestom.instance.demo.ChunkGeneratorDemo;
import fr.themode.minestom.inventory.Inventory; import fr.themode.minestom.inventory.Inventory;
import fr.themode.minestom.inventory.PlayerInventory; 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.ServerPacket;
import fr.themode.minestom.net.packet.server.play.*; 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.Scoreboard;
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;
@ -145,7 +144,7 @@ public class Player extends LivingEntity {
}); });
setEventCallback(PlayerSpawnEvent.class, event -> { setEventCallback(PlayerSpawnEvent.class, event -> {
setGameMode(GameMode.CREATIVE); setGameMode(GameMode.SURVIVAL);
teleport(new Position(0, 66, 0)); teleport(new Position(0, 66, 0));
/*Random random = new Random(); /*Random random = new Random();
@ -183,14 +182,12 @@ public class Player extends LivingEntity {
setAttribute(Attribute.MAX_HEALTH, 10); setAttribute(Attribute.MAX_HEALTH, 10);
heal(); heal();
setExp(0.9f); /*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");*/
}); });
} }

View File

@ -2,22 +2,24 @@ package fr.themode.minestom.entity.property;
public enum Attribute { public enum Attribute {
MAX_HEALTH("generic.maxHealth", 20), MAX_HEALTH("generic.maxHealth", 20, 1024),
FOLLOW_RANGE("generic.followRange", 32), FOLLOW_RANGE("generic.followRange", 32, 2048),
KNOCKBACK_RESISTANCE("generic.knockbackResistance", 0), KNOCKBACK_RESISTANCE("generic.knockbackResistance", 0, 1),
MOVEMENT_SPEED("generic.movementSpeed", 0.7f), MOVEMENT_SPEED("generic.movementSpeed", 0.7f, 1024),
ATTACK_DAMAGE("generic.attackDamage", 2), ATTACK_DAMAGE("generic.attackDamage", 2, 2048),
ATTACK_SPEED("generic.attackSpeed", 4), ATTACK_SPEED("generic.attackSpeed", 4, 1024),
FLYING_SPEED("generic.flyingSpeed", 0.4f), FLYING_SPEED("generic.flyingSpeed", 0.4f, 1024),
HORSE_JUMP_STRENGTH("horse.jumpStrength", 0.7f), HORSE_JUMP_STRENGTH("horse.jumpStrength", 0.7f, 2),
ZOMBIE_SPAWN_REINFORCEMENTS("zombie.spawnReinforcements", 0); ZOMBIE_SPAWN_REINFORCEMENTS("zombie.spawnReinforcements", 0, 1);
private String key; private String key;
private float defaultValue; private float defaultValue;
private float maxVanillaValue;
Attribute(String key, float defaultValue) { Attribute(String key, float defaultValue, float maxVanillaValue) {
this.key = key; this.key = key;
this.defaultValue = defaultValue; this.defaultValue = defaultValue;
this.maxVanillaValue = maxVanillaValue;
} }
public String getKey() { public String getKey() {
@ -27,4 +29,8 @@ public enum Attribute {
public float getDefaultValue() { public float getDefaultValue() {
return defaultValue; return defaultValue;
} }
public float getMaxVanillaValue() {
return maxVanillaValue;
}
} }

View File

@ -1,6 +1,6 @@
package fr.themode.minestom.event; package fr.themode.minestom.event;
import fr.themode.minestom.instance.CustomBlock; import fr.themode.minestom.instance.block.CustomBlock;
public class PlayerStartDiggingEvent extends CancellableEvent { public class PlayerStartDiggingEvent extends CancellableEvent {

View File

@ -3,7 +3,9 @@ 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.Viewable; import fr.themode.minestom.Viewable;
import fr.themode.minestom.data.Data;
import fr.themode.minestom.entity.Player; 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.net.packet.server.play.ChunkDataPacket;
import fr.themode.minestom.utils.PacketUtils; import fr.themode.minestom.utils.PacketUtils;
import fr.themode.minestom.utils.SerializerUtils; import fr.themode.minestom.utils.SerializerUtils;
@ -14,7 +16,9 @@ import java.io.IOException;
import java.util.Collections; import java.util.Collections;
import java.util.Set; import java.util.Set;
import java.util.concurrent.CopyOnWriteArraySet; import java.util.concurrent.CopyOnWriteArraySet;
import java.util.function.Consumer;
// TODO air management to free memory
public class Chunk implements Viewable { public class Chunk implements Viewable {
public static final int CHUNK_SIZE_X = 16; public static final int CHUNK_SIZE_X = 16;
@ -30,6 +34,8 @@ public class Chunk implements Viewable {
// Block entities // Block entities
private Set<Integer> blockEntities = new CopyOnWriteArraySet<>(); private Set<Integer> blockEntities = new CopyOnWriteArraySet<>();
// TODO blocks update
// Cache // Cache
private Set<Player> viewers = new CopyOnWriteArraySet<>(); private Set<Player> viewers = new CopyOnWriteArraySet<>();
private Packet fullDataPacket; private Packet fullDataPacket;
@ -42,16 +48,16 @@ public class Chunk implements Viewable {
this.chunkZ = chunkZ; 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); 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); CustomBlock customBlock = Main.getBlockManager().getBlock(blockId);
if (customBlock == null) if (customBlock == null)
throw new IllegalArgumentException("The block " + blockId + " does not exist or isn't registered"); 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) { protected void setCustomBlock(byte x, byte y, byte z, short customBlockId) {
@ -59,7 +65,7 @@ public class Chunk implements Viewable {
if (customBlock == null) if (customBlock == null)
throw new IllegalArgumentException("The custom block " + customBlockId + " does not exist or isn't registered"); 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) { 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; this.packetUpdated = false;
} }
private void setCustomBlock(byte x, byte y, byte z, CustomBlock customBlock) {
if (customBlock.hasUpdate()) {
Consumer<Data> test = customBlock::update;
// TODO add update callback
}
setBlock(x, y, z, customBlock.getType(), customBlock.getId());
}
public short getBlockId(byte x, byte y, byte z) { public short getBlockId(byte x, byte y, byte z) {
return this.blocksId[SerializerUtils.chunkCoordToIndex(x, y, 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; 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() { public Biome getBiome() {
return biome; return biome;
} }
@ -110,6 +135,7 @@ public class Chunk implements Viewable {
public void setFullDataPacket(Packet fullDataPacket) { public void setFullDataPacket(Packet fullDataPacket) {
this.fullDataPacket = fullDataPacket; this.fullDataPacket = fullDataPacket;
this.packetUpdated = true;
} }
protected byte[] getSerializedData() throws IOException { protected byte[] getSerializedData() throws IOException {
@ -153,10 +179,9 @@ public class Chunk implements Viewable {
} }
// Write the packet in the current thread // Write the packet in the current thread
protected void refreshDataPacket() { public void refreshDataPacket() {
PacketUtils.writePacket(getFreshFullDataPacket(), packet -> { PacketUtils.writePacket(getFreshFullDataPacket(), packet -> {
fullDataPacket = packet; setFullDataPacket(packet);
packetUpdated = true;
}); });
} }

View File

@ -1,5 +1,7 @@
package fr.themode.minestom.instance; package fr.themode.minestom.instance;
import fr.themode.minestom.instance.batch.ChunkBatch;
public abstract class ChunkGenerator { public abstract class ChunkGenerator {
public abstract void generateChunkData(ChunkBatch batch, int chunkX, int chunkZ); public abstract void generateChunkData(ChunkBatch batch, int chunkX, int chunkZ);

View File

@ -69,7 +69,7 @@ public class ChunkLoaderIO {
if (isCustomBlock) { if (isCustomBlock) {
chunk.setCustomBlock(chunkPos[0], chunkPos[1], chunkPos[2], blockId); chunk.setCustomBlock(chunkPos[0], chunkPos[1], chunkPos[2], blockId);
} else { } else {
chunk.setBlock(chunkPos[0], chunkPos[1], chunkPos[2], blockId); chunk.UNSAFE_setBlock(chunkPos[0], chunkPos[1], chunkPos[2], blockId);
} }
} }
} catch (EOFException e) { } catch (EOFException e) {

View File

@ -3,6 +3,9 @@ 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.entity.*; 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.PacketWriterUtils;
import fr.themode.minestom.net.packet.server.play.ChunkDataPacket; import fr.themode.minestom.net.packet.server.play.ChunkDataPacket;
import fr.themode.minestom.utils.BlockPosition; import fr.themode.minestom.utils.BlockPosition;

View File

@ -3,6 +3,8 @@ package fr.themode.minestom.instance;
import com.github.simplenet.packet.Packet; import com.github.simplenet.packet.Packet;
import fr.themode.minestom.entity.Player; import fr.themode.minestom.entity.Player;
import fr.themode.minestom.event.PlayerBlockBreakEvent; 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.PacketWriterUtils;
import fr.themode.minestom.net.packet.server.play.BlockChangePacket; import fr.themode.minestom.net.packet.server.play.BlockChangePacket;
import fr.themode.minestom.net.packet.server.play.ParticlePacket; import fr.themode.minestom.net.packet.server.play.ParticlePacket;
@ -41,7 +43,7 @@ public class InstanceContainer extends Instance {
byte chunkX = (byte) (x % 16); byte chunkX = (byte) (x % 16);
byte chunkY = (byte) y; byte chunkY = (byte) y;
byte chunkZ = (byte) (z % 16); byte chunkZ = (byte) (z % 16);
chunk.setBlock(chunkX, chunkY, chunkZ, blockId); chunk.UNSAFE_setBlock(chunkX, chunkY, chunkZ, blockId);
sendBlockChange(chunk, x, y, z, blockId); sendBlockChange(chunk, x, y, z, blockId);
} }
} }
@ -53,7 +55,7 @@ public class InstanceContainer extends Instance {
byte chunkX = (byte) (x % 16); byte chunkX = (byte) (x % 16);
byte chunkY = (byte) y; byte chunkY = (byte) y;
byte chunkZ = (byte) (z % 16); 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); short id = chunk.getBlockId(chunkX, chunkY, chunkZ);
sendBlockChange(chunk, x, y, z, id); sendBlockChange(chunk, x, y, z, id);
} }
@ -199,7 +201,6 @@ public class InstanceContainer extends Instance {
if (data == null || !chunk.packetUpdated) { if (data == null || !chunk.packetUpdated) {
PacketWriterUtils.writeCallbackPacket(chunk.getFreshFullDataPacket(), buffer -> { PacketWriterUtils.writeCallbackPacket(chunk.getFreshFullDataPacket(), buffer -> {
chunk.setFullDataPacket(buffer); chunk.setFullDataPacket(buffer);
chunk.packetUpdated = true;
sendChunkUpdate(player, chunk); sendChunkUpdate(player, chunk);
}); });
} else { } else {

View File

@ -1,6 +1,8 @@
package fr.themode.minestom.instance; package fr.themode.minestom.instance;
import fr.themode.minestom.entity.Player; 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 fr.themode.minestom.utils.BlockPosition;
import java.io.File; import java.io.File;

View File

@ -1,17 +1,15 @@
package fr.themode.minestom.instance; package fr.themode.minestom.instance.batch;
import fr.themode.minestom.Main; import fr.themode.minestom.instance.BlockModifier;
import fr.themode.minestom.utils.thread.MinestomThread; import fr.themode.minestom.instance.Chunk;
import fr.themode.minestom.instance.InstanceContainer;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.concurrent.ExecutorService;
public class BlockBatch implements BlockModifier { public class BlockBatch implements IBatch, BlockModifier {
private static final ExecutorService batchesPool = new MinestomThread(Main.THREAD_COUNT_BLOCK_BATCH, "Ms-BlockBatchPool");
private InstanceContainer instance; private InstanceContainer instance;
@ -85,9 +83,9 @@ public class BlockBatch implements BlockModifier {
public void apply(Chunk chunk) { public void apply(Chunk chunk) {
if (blockIdentifier == null) { if (blockIdentifier == null) {
chunk.setBlock((byte) x, (byte) y, (byte) z, blockId); chunk.UNSAFE_setBlock((byte) x, (byte) y, (byte) z, blockId);
} else { } else {
chunk.setCustomBlock((byte) x, (byte) y, (byte) z, blockIdentifier); chunk.UNSAFE_setCustomBlock((byte) x, (byte) y, (byte) z, blockIdentifier);
} }
} }

View File

@ -1,19 +1,18 @@
package fr.themode.minestom.instance; package fr.themode.minestom.instance.batch;
import fr.themode.minestom.Main; import fr.themode.minestom.instance.BlockModifier;
import fr.themode.minestom.utils.thread.MinestomThread; 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.ArrayList;
import java.util.List; import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.function.Consumer; import java.util.function.Consumer;
/** /**
* Use chunk coordinate (0-16) instead of world's * Use chunk coordinate (0-16) instead of world's
*/ */
public class ChunkBatch implements BlockModifier { public class ChunkBatch implements IBatch, BlockModifier {
private static final ExecutorService batchesPool = new MinestomThread(Main.THREAD_COUNT_CHUNK_BATCH, "Ms-ChunkBatchPool");
private InstanceContainer instance; private InstanceContainer instance;
private Chunk chunk; private Chunk chunk;
@ -82,9 +81,9 @@ public class ChunkBatch implements BlockModifier {
public void apply(Chunk chunk) { public void apply(Chunk chunk) {
if (blockIdentifier == null) { if (blockIdentifier == null) {
chunk.setBlock(x, y, z, blockId); chunk.UNSAFE_setBlock(x, y, z, blockId);
} else { } else {
chunk.setCustomBlock(x, y, z, blockIdentifier); chunk.UNSAFE_setCustomBlock(x, y, z, blockIdentifier);
} }
} }

View File

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

View File

@ -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.HashMap;
import java.util.Map; import java.util.Map;
@ -6,6 +11,8 @@ import java.util.function.Supplier;
public class BlockManager { public class BlockManager {
private static InstanceManager instanceManager = Main.getInstanceManager();
private Map<Short, CustomBlock> blocksInternalId = new HashMap<>(); private Map<Short, CustomBlock> blocksInternalId = new HashMap<>();
private Map<String, CustomBlock> blocksId = new HashMap<>(); private Map<String, CustomBlock> blocksId = new HashMap<>();
@ -17,6 +24,15 @@ public class BlockManager {
this.blocksId.put(identifier, customBlock); 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) { public CustomBlock getBlock(String identifier) {
return blocksId.get(identifier); return blocksId.get(identifier);
} }

View File

@ -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 fr.themode.minestom.entity.Player;
import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicInteger;
@ -18,6 +19,12 @@ public abstract class CustomBlock {
this.id = (short) idCounter.incrementAndGet(); 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 short getType();
public abstract String getIdentifier(); public abstract String getIdentifier();
@ -27,6 +34,10 @@ public abstract class CustomBlock {
*/ */
public abstract int getBreakDelay(Player player); public abstract int getBreakDelay(Player player);
public boolean hasUpdate() {
return getUpdateOption().getValue() > 0;
}
public short getId() { public short getId() {
return id; return id;
} }

View File

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

View File

@ -1,8 +1,8 @@
package fr.themode.minestom.instance.demo; package fr.themode.minestom.instance.demo;
import fr.themode.minestom.instance.Biome; import fr.themode.minestom.instance.Biome;
import fr.themode.minestom.instance.ChunkBatch;
import fr.themode.minestom.instance.ChunkGenerator; import fr.themode.minestom.instance.ChunkGenerator;
import fr.themode.minestom.instance.batch.ChunkBatch;
import java.util.Random; import java.util.Random;

View File

@ -1,10 +1,25 @@
package fr.themode.minestom.instance.demo; package fr.themode.minestom.instance.demo;
import fr.themode.minestom.data.Data;
import fr.themode.minestom.entity.Player; 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 { 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 @Override
public short getType() { public short getType() {
return 1; return 1;

View File

@ -1,5 +1,6 @@
package fr.themode.minestom.listener; package fr.themode.minestom.listener;
import fr.themode.minestom.entity.GameMode;
import fr.themode.minestom.entity.Player; import fr.themode.minestom.entity.Player;
import fr.themode.minestom.event.PlayerBlockPlaceEvent; import fr.themode.minestom.event.PlayerBlockPlaceEvent;
import fr.themode.minestom.instance.Chunk; 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 boolean intersectPlayer = player.getBoundingBox().intersect(blockPosition); // TODO check if collide with nearby players
if (!intersectPlayer) { if (!intersectPlayer) {
PlayerBlockPlaceEvent playerBlockPlaceEvent = new PlayerBlockPlaceEvent((short) 10, blockPosition, packet.hand); PlayerBlockPlaceEvent playerBlockPlaceEvent = new PlayerBlockPlaceEvent((short) 10, blockPosition, packet.hand);
playerBlockPlaceEvent.consumeBlock(player.getGameMode() != GameMode.CREATIVE);
player.callEvent(PlayerBlockPlaceEvent.class, playerBlockPlaceEvent); player.callEvent(PlayerBlockPlaceEvent.class, playerBlockPlaceEvent);
if (!playerBlockPlaceEvent.isCancelled()) { if (!playerBlockPlaceEvent.isCancelled()) {
instance.setBlock(blockPosition, "custom_block"); // TODO set useItem's block instead instance.setBlock(blockPosition, "custom_block"); // TODO set useItem's block instead

View File

@ -1,5 +1,6 @@
package fr.themode.minestom.listener; package fr.themode.minestom.listener;
import fr.themode.minestom.chat.ChatColor;
import fr.themode.minestom.entity.Player; import fr.themode.minestom.entity.Player;
import fr.themode.minestom.net.packet.client.play.ClientKeepAlivePacket; import fr.themode.minestom.net.packet.client.play.ClientKeepAlivePacket;
@ -7,7 +8,7 @@ public class KeepAliveListener {
public static void listener(ClientKeepAlivePacket packet, Player player) { public static void listener(ClientKeepAlivePacket packet, Player player) {
if (packet.id != player.getLastKeepAlive()) { if (packet.id != player.getLastKeepAlive()) {
player.kick("Bad Keep Alive packet"); player.kick(ChatColor.RED + "Bad Keep Alive packet");
} }
} }

View File

@ -5,8 +5,8 @@ import fr.themode.minestom.entity.ItemEntity;
import fr.themode.minestom.entity.Player; import fr.themode.minestom.entity.Player;
import fr.themode.minestom.event.ItemDropEvent; import fr.themode.minestom.event.ItemDropEvent;
import fr.themode.minestom.event.PlayerStartDiggingEvent; import fr.themode.minestom.event.PlayerStartDiggingEvent;
import fr.themode.minestom.instance.CustomBlock;
import fr.themode.minestom.instance.Instance; import fr.themode.minestom.instance.Instance;
import fr.themode.minestom.instance.block.CustomBlock;
import fr.themode.minestom.inventory.PlayerInventory; import fr.themode.minestom.inventory.PlayerInventory;
import fr.themode.minestom.item.ItemStack; import fr.themode.minestom.item.ItemStack;
import fr.themode.minestom.net.packet.client.play.ClientPlayerDiggingPacket; import fr.themode.minestom.net.packet.client.play.ClientPlayerDiggingPacket;

View File

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

View File

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