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 {
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'
}

View File

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

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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<Integer> blockEntities = new CopyOnWriteArraySet<>();
// TODO blocks update
// Cache
private Set<Player> 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<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) {
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);
});
}

View File

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

View File

@ -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) {

View File

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

View File

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

View File

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

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

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

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.Map;
@ -6,6 +11,8 @@ import java.util.function.Supplier;
public class BlockManager {
private static InstanceManager instanceManager = Main.getInstanceManager();
private Map<Short, CustomBlock> blocksInternalId = new HashMap<>();
private Map<String, CustomBlock> 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);
}

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

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

View File

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

View File

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

View File

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

View File

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

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