Conflicts:
	src/main/java/fr/themode/demo/PlayerInit.java
	src/main/java/fr/themode/demo/generator/NoiseTestGenerator.java
	src/main/java/net/minestom/server/utils/chunk/ChunkUtils.java
This commit is contained in:
Eoghanmc22 2020-08-20 12:22:40 -04:00
commit c16b716350
276 changed files with 3407 additions and 2761 deletions

3
.gitignore vendored
View File

@ -50,3 +50,6 @@ gradle-app.setting
# gradle/wrapper/gradle-wrapper.properties
/src/main/java/com/mcecraft/
# When running the demo we generate the extensions folder
extensions/

View File

@ -1,6 +1,6 @@
package fr.themode.demo;
import fr.themode.demo.entity.ChickenCreature;
import fr.themode.demo.blocks.StoneBlock;
import fr.themode.demo.generator.ChunkGeneratorDemo;
import fr.themode.demo.generator.NoiseTestGenerator;
import net.minestom.server.MinecraftServer;
@ -8,6 +8,7 @@ import net.minestom.server.benchmark.BenchmarkManager;
import net.minestom.server.benchmark.ThreadResult;
import net.minestom.server.chat.ChatColor;
import net.minestom.server.chat.ColoredText;
import net.minestom.server.data.Data;
import net.minestom.server.entity.*;
import net.minestom.server.entity.damage.DamageType;
import net.minestom.server.event.entity.EntityAttackEvent;
@ -20,6 +21,7 @@ import net.minestom.server.instance.Instance;
import net.minestom.server.instance.InstanceContainer;
import net.minestom.server.instance.WorldBorder;
import net.minestom.server.instance.block.Block;
import net.minestom.server.instance.block.CustomBlock;
import net.minestom.server.inventory.Inventory;
import net.minestom.server.inventory.InventoryType;
import net.minestom.server.item.ItemStack;
@ -28,6 +30,7 @@ import net.minestom.server.item.metadata.MapMeta;
import net.minestom.server.network.ConnectionManager;
import net.minestom.server.ping.ResponseDataConsumer;
import net.minestom.server.scoreboard.Sidebar;
import net.minestom.server.utils.BlockPosition;
import net.minestom.server.utils.MathUtils;
import net.minestom.server.utils.Position;
import net.minestom.server.utils.Vector;
@ -35,19 +38,16 @@ import net.minestom.server.utils.time.TimeUnit;
import net.minestom.server.world.DimensionType;
import java.util.Map;
import java.util.Random;
import java.util.UUID;
public class PlayerInit {
private static volatile InstanceContainer instanceContainer;
//private static volatile InstanceContainer netherTest;
private static Random r = new Random();
private static volatile Inventory inventory;
static {
//StorageFolder storageFolder = MinecraftServer.getStorageManager().getFolder("instance_data", new StorageOption().setCompression(true));
//StorageFolder storageFolder = MinecraftServer.getStorageManager().getFolder("instance_data", new StorageOptions().setCompression(true));
ChunkGeneratorDemo chunkGeneratorDemo = new ChunkGeneratorDemo();
NoiseTestGenerator noiseTestGenerator = new NoiseTestGenerator();
//instanceContainer = MinecraftServer.getInstanceManager().createInstanceContainer(storageFolder);
@ -156,10 +156,10 @@ public class PlayerInit {
p.teleport(player.getPosition());
}*/
for (int i = 0; i < 100; i++) {
/*for (int i = 0; i < 100; i++) {
ChickenCreature chickenCreature = new ChickenCreature(player.getPosition());
chickenCreature.setInstance(player.getInstance());
}
}*/
/*EntityZombie zombie = new EntityZombie(player.getPosition());
zombie.setAttribute(Attribute.MOVEMENT_SPEED, 0.25f);
@ -186,6 +186,17 @@ public class PlayerInit {
if (event.getHand() != Player.Hand.MAIN)
return;
final Instance instance = player.getInstance();
final BlockPosition blockPosition = event.getBlockPosition();
final CustomBlock customBlock = instance.getCustomBlock(blockPosition);
if (customBlock instanceof StoneBlock) {
final Data data = instance.getBlockData(blockPosition);
if (data != null) {
player.sendMessage("test: " + data.get("test"));
}
}
final short blockStateId = player.getInstance().getBlockStateId(event.getBlockPosition());
final Block block = Block.fromStateId(blockStateId);
player.sendMessage("You clicked at the block " + block);
@ -260,8 +271,8 @@ public class PlayerInit {
});
player.addEventCallback(PlayerSpawnEvent.class, event -> {
player.setGameMode(GameMode.CREATIVE);
player.teleport(new Position(r.nextInt(200)-100, 73, r.nextInt(200)-100));
player.setGameMode(GameMode.SURVIVAL);
player.teleport(new Position(0, 41f, 0));
//player.setHeldItemSlot((byte) 5);
@ -378,7 +389,7 @@ public class PlayerInit {
// Unload the chunk (save memory) if it has no remaining viewer
if (chunk.getViewers().isEmpty()) {
player.getInstance().unloadChunk(chunk);
//player.getInstance().unloadChunk(chunk);
}
});

View File

@ -20,8 +20,8 @@ public class BurningTorchBlock extends CustomBlock {
@Override
public void handleContact(Instance instance, BlockPosition position, Entity touching) {
System.out.println("touching "+touching);
if(touching instanceof LivingEntity) {
System.out.println("touching " + touching);
if (touching instanceof LivingEntity) {
((LivingEntity) touching).damage(DamageType.GRAVITY, 0.1f);
}
}
@ -45,9 +45,4 @@ public class BurningTorchBlock extends CustomBlock {
public short getCustomBlockId() {
return 3;
}
@Override
public int getBreakDelay(Player player, BlockPosition position) {
return -1;
}
}

View File

@ -7,6 +7,8 @@ import net.minestom.server.instance.block.Block;
import net.minestom.server.instance.block.CustomBlock;
import net.minestom.server.utils.BlockPosition;
import java.util.Set;
public class StoneBlock extends CustomBlock {
public StoneBlock() {
@ -39,8 +41,18 @@ public class StoneBlock extends CustomBlock {
}
@Override
public int getBreakDelay(Player player, BlockPosition position) {
return 750;
public int getBreakDelay(Player player, BlockPosition position, byte stage, Set<Player> breakers) {
return 5;
}
@Override
public boolean enableCustomBreakDelay() {
return true;
}
@Override
public boolean enableMultiPlayerBreaking() {
return true;
}
@Override

View File

@ -9,6 +9,8 @@ import net.minestom.server.utils.BlockPosition;
import net.minestom.server.utils.time.TimeUnit;
import net.minestom.server.utils.time.UpdateOption;
import java.util.Set;
public class UpdatableBlockDemo extends CustomBlock {
private static final UpdateOption UPDATE_OPTION = new UpdateOption(20, TimeUnit.TICK);
@ -43,8 +45,13 @@ public class UpdatableBlockDemo extends CustomBlock {
}
@Override
public int getBreakDelay(Player player, BlockPosition position) {
return 500;
public int getBreakDelay(Player player, BlockPosition position, byte stage, Set<Player> breakers) {
return 1;
}
@Override
public boolean enableCustomBreakDelay() {
return true;
}
@Override

View File

@ -67,6 +67,10 @@ public class SimpleCommand implements CommandProcessor {
NotificationCenter.send(notification, player);
NotificationCenter.send(notification, player);
System.gc();
//player.getInstance().saveChunksToStorageFolder(() -> System.out.println("end save"));
return true;
}

View File

@ -13,6 +13,8 @@ import net.minestom.server.data.DataType;
import net.minestom.server.data.SerializableData;
import net.minestom.server.entity.EntityManager;
import net.minestom.server.entity.EntityType;
import net.minestom.server.extensions.Extension;
import net.minestom.server.extensions.ExtensionManager;
import net.minestom.server.extras.mojangAuth.MojangCrypt;
import net.minestom.server.fluids.Fluid;
import net.minestom.server.gamedata.loottables.LootTableManager;
@ -33,7 +35,6 @@ import net.minestom.server.network.packet.server.play.PluginMessagePacket;
import net.minestom.server.network.packet.server.play.ServerDifficultyPacket;
import net.minestom.server.particle.Particle;
import net.minestom.server.ping.ResponseDataConsumer;
import net.minestom.server.plugins.PluginManager;
import net.minestom.server.potion.PotionType;
import net.minestom.server.recipe.RecipeManager;
import net.minestom.server.registry.ResourceGatherer;
@ -102,8 +103,6 @@ public class MinecraftServer {
//Rate Limiting
private static int rateLimit = 0;
// Networking
private static PacketProcessor packetProcessor;
private static PacketListenerManager packetListenerManager;
private static NettyServer nettyServer;
@ -123,7 +122,7 @@ public class MinecraftServer {
private static BiomeManager biomeManager;
private static AdvancementManager advancementManager;
private static PluginManager pluginManager;
private static ExtensionManager extensionManager;
private static UpdateManager updateManager;
private static MinecraftServer minecraftServer;
@ -161,7 +160,8 @@ public class MinecraftServer {
Fluid.values();
connectionManager = new ConnectionManager();
packetProcessor = new PacketProcessor();
// Networking
final PacketProcessor packetProcessor = new PacketProcessor();
packetListenerManager = new PacketListenerManager();
instanceManager = new InstanceManager();
@ -180,7 +180,7 @@ public class MinecraftServer {
updateManager = new UpdateManager();
pluginManager = PluginManager.getInstance();
extensionManager = new ExtensionManager();
lootTableManager = new LootTableManager();
tagManager = new TagManager();
@ -452,8 +452,14 @@ public class MinecraftServer {
updateManager.start();
nettyServer.start(address, port);
long t1 = -System.nanoTime();
pluginManager.loadPlugins();
LOGGER.info("Plugins loaded in " + (t1 + System.nanoTime()) / 1_000_000D + "ms");
extensionManager.loadExtensionJARs();
// Init extensions
// TODO: Extensions should handle depending on each other and have a load-order.
extensionManager.getExtensions().forEach(Extension::preInitialize);
extensionManager.getExtensions().forEach(Extension::initialize);
extensionManager.getExtensions().forEach(Extension::postInitialize);
LOGGER.info("Extensions loaded in " + (t1 + System.nanoTime()) / 1_000_000D + "ms");
LOGGER.info("Minestom server started successfully.");
}

View File

@ -13,6 +13,7 @@ import net.minestom.server.utils.thread.MinestomThread;
import net.minestom.server.utils.validate.Check;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;
import java.util.function.Consumer;
@ -61,7 +62,7 @@ public final class UpdateManager {
//Tick Callbacks
tickStartCallbacks.forEach(Runnable::run);
ArrayList<Future<?>> futures;
List<Future<?>> futures;
// Server tick (instance/chunk/entity)
// Synchronize with the update manager instance, like the signal for chunk load/unload

View File

@ -11,7 +11,7 @@ import java.util.Map;
*/
public class AdvancementManager {
private Map<String, AdvancementTab> advancementTabMap = new HashMap<>();
private final Map<String, AdvancementTab> advancementTabMap = new HashMap<>();
/**
* Create a new tab with a single advancement

View File

@ -16,14 +16,14 @@ import java.util.*;
*/
public class AdvancementTab implements Viewable {
private static Map<Player, Set<AdvancementTab>> playerTabMap = new HashMap<>();
private static final Map<Player, Set<AdvancementTab>> PLAYER_TAB_MAP = new HashMap<>();
private Set<Player> viewers = new HashSet<>();
private final Set<Player> viewers = new HashSet<>();
private AdvancementRoot root;
private final AdvancementRoot root;
// Advancement -> its parent
private Map<Advancement, Advancement> advancementMap = new HashMap<>();
private final Map<Advancement, Advancement> advancementMap = new HashMap<>();
// Packet cache, updated every time the tab changes
protected ByteBuf createBuffer;
@ -47,7 +47,7 @@ public class AdvancementTab implements Viewable {
* @return all the advancement tabs that the player sees
*/
public static Set<AdvancementTab> getTabs(Player player) {
return playerTabMap.getOrDefault(player, null);
return PLAYER_TAB_MAP.getOrDefault(player, null);
}
/**
@ -171,7 +171,7 @@ public class AdvancementTab implements Viewable {
* @param player the player
*/
private void addPlayer(Player player) {
Set<AdvancementTab> tabs = playerTabMap.computeIfAbsent(player, p -> new HashSet<>());
Set<AdvancementTab> tabs = PLAYER_TAB_MAP.computeIfAbsent(player, p -> new HashSet<>());
tabs.add(this);
}
@ -181,13 +181,13 @@ public class AdvancementTab implements Viewable {
* @param player the player
*/
private void removePlayer(Player player) {
if (!playerTabMap.containsKey(player)) {
if (!PLAYER_TAB_MAP.containsKey(player)) {
return;
}
Set<AdvancementTab> tabs = playerTabMap.get(player);
Set<AdvancementTab> tabs = PLAYER_TAB_MAP.get(player);
tabs.remove(this);
if (tabs.isEmpty()) {
playerTabMap.remove(player);
PLAYER_TAB_MAP.remove(player);
}
}

View File

@ -42,7 +42,6 @@ public class BenchmarkManager {
private boolean enabled = false;
private volatile boolean stop = false;
private Thread thread;
private long time;
@ -51,7 +50,7 @@ public class BenchmarkManager {
time = updateOption.getTimeUnit().toMilliseconds(updateOption.getValue());
this.thread = new Thread(null, () -> {
final Thread thread = new Thread(null, () -> {
while (!stop) {
refreshData();
@ -67,7 +66,7 @@ public class BenchmarkManager {
}, MinecraftServer.THREAD_NAME_BENCHMARK, 0L);
this.thread.start();
thread.start();
this.enabled = true;
}

View File

@ -61,7 +61,7 @@ public class ColoredText {
}
private static String toLegacy(String message, char colorChar) {
String result = "";
StringBuilder result = new StringBuilder();
for (int i = 0; i < message.length(); i++) {
final char c = message.charAt(i);
@ -71,19 +71,19 @@ public class ColoredText {
final char nextChar = message.charAt(i + 1);
final ChatColor color = ChatColor.fromLegacyColorCodes(nextChar);
if (color != ChatColor.NO_COLOR) {
String replacement = color.toString();
result += replacement;
final String replacement = color.toString();
result.append(replacement);
i++; // Increment to ignore the color code
} else {
result += c;
result.append(c);
}
}
} else {
result += c;
result.append(c);
}
}
return result;
return result.toString();
}
public ColoredText appendLegacy(String message, char colorChar) {

View File

@ -39,11 +39,11 @@ public class TranslatableText {
final String prefix = "{@";
final String suffix = "}";
String content = code;
StringBuilder content = new StringBuilder(code);
if (arguments != null && arguments.length > 0) {
for (String arg : arguments) {
content += "," + arg;
content.append("," + arg);
}
}

View File

@ -111,7 +111,7 @@ public class CollisionUtils {
// find the corner which moved the least
float smallestDisplacement = Float.POSITIVE_INFINITY;
for (int i = 0; i < corners.length; i++) {
float displacement = (float) corners[i].distance(cornersCopy[i]);
final float displacement = (float) corners[i].distance(cornersCopy[i]);
if (displacement < smallestDisplacement) {
smallestDisplacement = displacement;
}

View File

@ -104,37 +104,41 @@ public class CommandDispatcher {
// true if the arg is valid, false otherwise
boolean correct = false;
// the raw string representing the correct argument syntax
String argValue = "";
StringBuilder argValue = new StringBuilder();
if (useRemaining) {
for (int i = argIndex; i < args.length; i++) {
final String arg = args[i];
if (argValue.length() > 0)
argValue += " ";
argValue += arg;
argValue.append(" ");
argValue.append(arg);
}
correctionResult = argument.getCorrectionResult(argValue);
final String argValueString = argValue.toString();
correctionResult = argument.getCorrectionResult(argValueString);
if (correctionResult == Argument.SUCCESS) {
correct = true;
argsValues[argIndex] = argValue;
argsValues[argIndex] = argValueString;
}
} else {
for (int i = argIndex; i < args.length; i++) {
final String arg = args[i];
argValue += arg;
argValue.append(arg);
correctionResult = argument.getCorrectionResult(argValue);
final String argValueString = argValue.toString();
correctionResult = argument.getCorrectionResult(argValueString);
if (correctionResult == Argument.SUCCESS) {
correct = true;
argsValues[argIndex] = argValue;
argsValues[argIndex] = argValueString;
argIndex = i + 1;
break;
} else {
if (!argument.allowSpace())
break;
argValue += " ";
argValue.append(" ");
}
}
}
@ -145,7 +149,7 @@ public class CommandDispatcher {
syntaxCorrect = false;
CommandSuggestionHolder suggestionHolder = new CommandSuggestionHolder();
suggestionHolder.syntax = syntax;
suggestionHolder.argValue = argValue;
suggestionHolder.argValue = argValue.toString();
suggestionHolder.correctionResult = correctionResult;
suggestionHolder.argIndex = argCount;
syntaxesSuggestions.put(argCount, suggestionHolder);
@ -222,7 +226,7 @@ public class CommandDispatcher {
return result;
}
private class CommandSuggestionHolder {
private static class CommandSuggestionHolder {
private CommandSyntax syntax;
private String argValue;
private int correctionResult;
@ -230,7 +234,7 @@ public class CommandDispatcher {
}
private class CommandResult {
private static class CommandResult {
// Command
private Command command;

View File

@ -27,7 +27,7 @@ public class Data {
}
};
protected ConcurrentHashMap<String, Object> data = new ConcurrentHashMap();
protected final ConcurrentHashMap<String, Object> data = new ConcurrentHashMap<>();
/**
* Set a value to a specific key

View File

@ -79,7 +79,8 @@ public final class DataManager {
* @throws NullPointerException if none is found
*/
public <T> DataType<T> getDataType(Class<T> clazz) {
return dataTypeMap.get(PrimitiveConversion.getObjectClass(clazz));
clazz = PrimitiveConversion.getObjectClass(clazz);
return dataTypeMap.get(clazz);
}
}

View File

@ -1,24 +1,24 @@
package net.minestom.server.data;
import net.minestom.server.network.packet.PacketReader;
import net.minestom.server.network.packet.PacketWriter;
import net.minestom.server.utils.binary.BinaryReader;
import net.minestom.server.utils.binary.BinaryWriter;
public abstract class DataType<T> {
/**
* Encode the data type
*
* @param packetWriter the data writer
* @param value the value to encode
* @param writer the data writer
* @param value the value to encode
*/
public abstract void encode(PacketWriter packetWriter, T value);
public abstract void encode(BinaryWriter writer, T value);
/**
* Decode the data type
*
* @param packetReader the data reader
* @param reader the data reader
* @return the decoded value
*/
public abstract T decode(PacketReader packetReader);
public abstract T decode(BinaryReader reader);
}

View File

@ -1,13 +1,9 @@
package net.minestom.server.data;
import net.minestom.server.MinecraftServer;
import net.minestom.server.network.packet.PacketWriter;
import net.minestom.server.utils.PrimitiveConversion;
import net.minestom.server.utils.binary.BinaryWriter;
import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
public class SerializableData extends Data {
@ -52,36 +48,28 @@ public class SerializableData extends Data {
* to convert it back
*
* @return the array representation of this data object
* @throws IOException if an error occur when serializing the data
*/
public byte[] getSerializedData() throws IOException {
ByteArrayOutputStream output = new ByteArrayOutputStream();
DataOutputStream dos = new DataOutputStream(output);
public byte[] getSerializedData() {
BinaryWriter binaryWriter = new BinaryWriter();
for (Map.Entry<String, Object> entry : data.entrySet()) {
final String key = entry.getKey();
data.forEach((key, value) -> {
final Class type = dataType.get(key);
final Object value = entry.getValue();
final DataType dataType = DATA_MANAGER.getDataType(type);
final byte[] encodedType = PrimitiveConversion.getObjectClassString(type.getName()).getBytes(); // Data type (fix for primitives)
dos.writeShort(encodedType.length);
dos.write(encodedType);
// Write the data type
final String encodedType = PrimitiveConversion.getObjectClassString(type.getName()); // Data type (fix for primitives)
binaryWriter.writeSizedString(encodedType);
final byte[] encodedName = key.getBytes(); // Data name
dos.writeShort(encodedName.length);
dos.write(encodedName);
// Write the data key
binaryWriter.writeSizedString(key);
PacketWriter packetWriter = new PacketWriter();
dataType.encode(packetWriter, value); // Encode
final byte[] encodedValue = packetWriter.toByteArray(); // Retrieve bytes
dos.writeInt(encodedValue.length);
dos.write(encodedValue);
}
// Write the data (no length)
dataType.encode(binaryWriter, value);
});
dos.writeShort(0xff); // End of data object
binaryWriter.writeVarInt(0); // End of data object
return output.toByteArray();
return binaryWriter.toByteArray();
}
}

View File

@ -1,17 +1,17 @@
package net.minestom.server.data.type;
import net.minestom.server.data.DataType;
import net.minestom.server.network.packet.PacketReader;
import net.minestom.server.network.packet.PacketWriter;
import net.minestom.server.utils.binary.BinaryReader;
import net.minestom.server.utils.binary.BinaryWriter;
public class BooleanData extends DataType<Boolean> {
@Override
public void encode(PacketWriter packetWriter, Boolean value) {
packetWriter.writeBoolean(value);
public void encode(BinaryWriter writer, Boolean value) {
writer.writeBoolean(value);
}
@Override
public Boolean decode(PacketReader packetReader) {
return packetReader.readBoolean();
public Boolean decode(BinaryReader reader) {
return reader.readBoolean();
}
}

View File

@ -1,17 +1,17 @@
package net.minestom.server.data.type;
import net.minestom.server.data.DataType;
import net.minestom.server.network.packet.PacketReader;
import net.minestom.server.network.packet.PacketWriter;
import net.minestom.server.utils.binary.BinaryReader;
import net.minestom.server.utils.binary.BinaryWriter;
public class ByteData extends DataType<Byte> {
@Override
public void encode(PacketWriter packetWriter, Byte value) {
packetWriter.writeByte(value);
public void encode(BinaryWriter writer, Byte value) {
writer.writeByte(value);
}
@Override
public Byte decode(PacketReader packetReader) {
return packetReader.readByte();
public Byte decode(BinaryReader reader) {
return reader.readByte();
}
}

View File

@ -1,18 +1,18 @@
package net.minestom.server.data.type;
import net.minestom.server.data.DataType;
import net.minestom.server.network.packet.PacketReader;
import net.minestom.server.network.packet.PacketWriter;
import net.minestom.server.utils.binary.BinaryReader;
import net.minestom.server.utils.binary.BinaryWriter;
public class CharacterData extends DataType<Character> {
@Override
public void encode(PacketWriter packetWriter, Character value) {
packetWriter.writeChar(value);
public void encode(BinaryWriter writer, Character value) {
writer.writeChar(value);
}
@Override
public Character decode(PacketReader packetReader) {
return packetReader.readChar();
public Character decode(BinaryReader reader) {
return reader.readChar();
}
}

View File

@ -1,18 +1,18 @@
package net.minestom.server.data.type;
import net.minestom.server.data.DataType;
import net.minestom.server.network.packet.PacketReader;
import net.minestom.server.network.packet.PacketWriter;
import net.minestom.server.utils.binary.BinaryReader;
import net.minestom.server.utils.binary.BinaryWriter;
public class DoubleData extends DataType<Double> {
@Override
public void encode(PacketWriter packetWriter, Double value) {
packetWriter.writeDouble(value);
public void encode(BinaryWriter writer, Double value) {
writer.writeDouble(value);
}
@Override
public Double decode(PacketReader packetReader) {
return packetReader.readDouble();
public Double decode(BinaryReader reader) {
return reader.readDouble();
}
}

View File

@ -1,18 +1,18 @@
package net.minestom.server.data.type;
import net.minestom.server.data.DataType;
import net.minestom.server.network.packet.PacketReader;
import net.minestom.server.network.packet.PacketWriter;
import net.minestom.server.utils.binary.BinaryReader;
import net.minestom.server.utils.binary.BinaryWriter;
public class FloatData extends DataType<Float> {
@Override
public void encode(PacketWriter packetWriter, Float value) {
packetWriter.writeFloat(value);
public void encode(BinaryWriter writer, Float value) {
writer.writeFloat(value);
}
@Override
public Float decode(PacketReader packetReader) {
return packetReader.readFloat();
public Float decode(BinaryReader reader) {
return reader.readFloat();
}
}

View File

@ -1,18 +1,18 @@
package net.minestom.server.data.type;
import net.minestom.server.data.DataType;
import net.minestom.server.network.packet.PacketReader;
import net.minestom.server.network.packet.PacketWriter;
import net.minestom.server.utils.binary.BinaryReader;
import net.minestom.server.utils.binary.BinaryWriter;
public class IntegerData extends DataType<Integer> {
@Override
public void encode(PacketWriter packetWriter, Integer value) {
packetWriter.writeVarInt(value);
public void encode(BinaryWriter writer, Integer value) {
writer.writeVarInt(value);
}
@Override
public Integer decode(PacketReader packetReader) {
return packetReader.readVarInt();
public Integer decode(BinaryReader reader) {
return reader.readVarInt();
}
}

View File

@ -3,37 +3,37 @@ package net.minestom.server.data.type;
import net.minestom.server.data.DataType;
import net.minestom.server.inventory.Inventory;
import net.minestom.server.inventory.InventoryType;
import net.minestom.server.network.packet.PacketReader;
import net.minestom.server.network.packet.PacketWriter;
import net.minestom.server.utils.binary.BinaryReader;
import net.minestom.server.utils.binary.BinaryWriter;
public class InventoryData extends DataType<Inventory> {
@Override
public void encode(PacketWriter packetWriter, Inventory value) {
public void encode(BinaryWriter writer, Inventory value) {
final InventoryType inventoryType = value.getInventoryType();
final int size = inventoryType.getAdditionalSlot();
// Inventory title & type
packetWriter.writeSizedString(value.getTitle());
packetWriter.writeSizedString(inventoryType.name());
writer.writeSizedString(value.getTitle());
writer.writeSizedString(inventoryType.name());
// Write all item stacks
for (int i = 0; i < size; i++) {
packetWriter.writeItemStack(value.getItemStack(i));
writer.writeItemStack(value.getItemStack(i));
}
}
@Override
public Inventory decode(PacketReader packetReader) {
final String title = packetReader.readSizedString();
final InventoryType inventoryType = InventoryType.valueOf(packetReader.readSizedString());
public Inventory decode(BinaryReader reader) {
final String title = reader.readSizedString();
final InventoryType inventoryType = InventoryType.valueOf(reader.readSizedString());
final int size = inventoryType.getAdditionalSlot();
Inventory inventory = new Inventory(inventoryType, title);
// Read all item stacks
for (int i = 0; i < size; i++) {
inventory.setItemStack(i, packetReader.readSlot());
inventory.setItemStack(i, reader.readSlot());
}
return inventory;

View File

@ -2,17 +2,17 @@ package net.minestom.server.data.type;
import net.minestom.server.data.DataType;
import net.minestom.server.item.ItemStack;
import net.minestom.server.network.packet.PacketReader;
import net.minestom.server.network.packet.PacketWriter;
import net.minestom.server.utils.binary.BinaryReader;
import net.minestom.server.utils.binary.BinaryWriter;
public class ItemStackData extends DataType<ItemStack> {
@Override
public void encode(PacketWriter packetWriter, ItemStack value) {
packetWriter.writeItemStack(value);
public void encode(BinaryWriter writer, ItemStack value) {
writer.writeItemStack(value);
}
@Override
public ItemStack decode(PacketReader packetReader) {
return packetReader.readSlot();
public ItemStack decode(BinaryReader reader) {
return reader.readSlot();
}
}

View File

@ -1,17 +1,17 @@
package net.minestom.server.data.type;
import net.minestom.server.data.DataType;
import net.minestom.server.network.packet.PacketReader;
import net.minestom.server.network.packet.PacketWriter;
import net.minestom.server.utils.binary.BinaryReader;
import net.minestom.server.utils.binary.BinaryWriter;
public class LongData extends DataType<Long> {
@Override
public void encode(PacketWriter packetWriter, Long value) {
packetWriter.writeLong(value);
public void encode(BinaryWriter writer, Long value) {
writer.writeLong(value);
}
@Override
public Long decode(PacketReader packetReader) {
return packetReader.readLong();
public Long decode(BinaryReader reader) {
return reader.readLong();
}
}

View File

@ -2,27 +2,20 @@ package net.minestom.server.data.type;
import net.minestom.server.data.DataType;
import net.minestom.server.data.SerializableData;
import net.minestom.server.network.packet.PacketReader;
import net.minestom.server.network.packet.PacketWriter;
import net.minestom.server.reader.DataReader;
import java.io.IOException;
import net.minestom.server.utils.binary.BinaryReader;
import net.minestom.server.utils.binary.BinaryWriter;
// Pretty weird name huh?
public class SerializableDataData extends DataType<SerializableData> {
@Override
public void encode(PacketWriter packetWriter, SerializableData value) {
try {
packetWriter.writeBytes(value.getSerializedData());
} catch (IOException e) {
e.printStackTrace();
throw new IllegalArgumentException("error while writing the data");
}
public void encode(BinaryWriter writer, SerializableData value) {
writer.writeBytes(value.getSerializedData());
}
@Override
public SerializableData decode(PacketReader packetReader) {
return DataReader.readData(packetReader.getBuffer());
public SerializableData decode(BinaryReader reader) {
return DataReader.readData(reader);
}
}

View File

@ -1,18 +1,18 @@
package net.minestom.server.data.type;
import net.minestom.server.data.DataType;
import net.minestom.server.network.packet.PacketReader;
import net.minestom.server.network.packet.PacketWriter;
import net.minestom.server.utils.binary.BinaryReader;
import net.minestom.server.utils.binary.BinaryWriter;
public class ShortData extends DataType<Short> {
@Override
public void encode(PacketWriter packetWriter, Short value) {
packetWriter.writeShort(value);
public void encode(BinaryWriter writer, Short value) {
writer.writeShort(value);
}
@Override
public Short decode(PacketReader packetReader) {
return packetReader.readShort();
public Short decode(BinaryReader reader) {
return reader.readShort();
}
}

View File

@ -1,18 +1,18 @@
package net.minestom.server.data.type;
import net.minestom.server.data.DataType;
import net.minestom.server.network.packet.PacketReader;
import net.minestom.server.network.packet.PacketWriter;
import net.minestom.server.utils.binary.BinaryReader;
import net.minestom.server.utils.binary.BinaryWriter;
public class StringData extends DataType<String> {
@Override
public void encode(PacketWriter packetWriter, String value) {
packetWriter.writeSizedString(value);
public void encode(BinaryWriter writer, String value) {
writer.writeSizedString(value);
}
@Override
public String decode(PacketReader packetReader) {
return packetReader.readSizedString();
public String decode(BinaryReader reader) {
return reader.readSizedString();
}
}

View File

@ -1,19 +1,19 @@
package net.minestom.server.data.type;
import net.minestom.server.data.DataType;
import net.minestom.server.network.packet.PacketReader;
import net.minestom.server.network.packet.PacketWriter;
import net.minestom.server.utils.binary.BinaryReader;
import net.minestom.server.utils.binary.BinaryWriter;
import java.util.UUID;
public class UuidType extends DataType<UUID> {
@Override
public void encode(PacketWriter packetWriter, UUID value) {
packetWriter.writeUuid(value);
public void encode(BinaryWriter writer, UUID value) {
writer.writeUuid(value);
}
@Override
public UUID decode(PacketReader packetReader) {
return packetReader.readUuid();
public UUID decode(BinaryReader reader) {
return reader.readUuid();
}
}

View File

@ -1,24 +1,24 @@
package net.minestom.server.data.type.array;
import net.minestom.server.data.DataType;
import net.minestom.server.network.packet.PacketReader;
import net.minestom.server.network.packet.PacketWriter;
import net.minestom.server.utils.binary.BinaryReader;
import net.minestom.server.utils.binary.BinaryWriter;
public class BooleanArrayData extends DataType<boolean[]> {
@Override
public void encode(PacketWriter packetWriter, boolean[] value) {
packetWriter.writeVarInt(value.length);
public void encode(BinaryWriter writer, boolean[] value) {
writer.writeVarInt(value.length);
for (boolean val : value) {
packetWriter.writeBoolean(val);
writer.writeBoolean(val);
}
}
@Override
public boolean[] decode(PacketReader packetReader) {
boolean[] array = new boolean[packetReader.readVarInt()];
public boolean[] decode(BinaryReader reader) {
boolean[] array = new boolean[reader.readVarInt()];
for (int i = 0; i < array.length; i++) {
array[i] = packetReader.readBoolean();
array[i] = reader.readBoolean();
}
return array;
}

View File

@ -1,31 +1,31 @@
package net.minestom.server.data.type.array;
import net.minestom.server.data.DataType;
import net.minestom.server.network.packet.PacketReader;
import net.minestom.server.network.packet.PacketWriter;
import net.minestom.server.utils.binary.BinaryReader;
import net.minestom.server.utils.binary.BinaryWriter;
public class ByteArrayData extends DataType<byte[]> {
@Override
public void encode(PacketWriter packetWriter, byte[] value) {
encodeByteArray(packetWriter, value);
public void encode(BinaryWriter writer, byte[] value) {
encodeByteArray(writer, value);
}
@Override
public byte[] decode(PacketReader packetReader) {
return decodeByteArray(packetReader);
public byte[] decode(BinaryReader reader) {
return decodeByteArray(reader);
}
public static void encodeByteArray(PacketWriter packetWriter, byte[] value) {
packetWriter.writeVarInt(value.length);
public static void encodeByteArray(BinaryWriter binaryWriter, byte[] value) {
binaryWriter.writeVarInt(value.length);
for (byte val : value) {
packetWriter.writeByte(val);
binaryWriter.writeByte(val);
}
}
public static byte[] decodeByteArray(PacketReader packetReader) {
byte[] array = new byte[packetReader.readVarInt()];
public static byte[] decodeByteArray(BinaryReader binaryReader) {
byte[] array = new byte[binaryReader.readVarInt()];
for (int i = 0; i < array.length; i++) {
array[i] = packetReader.readByte();
array[i] = binaryReader.readByte();
}
return array;
}

View File

@ -1,23 +1,23 @@
package net.minestom.server.data.type.array;
import net.minestom.server.data.DataType;
import net.minestom.server.network.packet.PacketReader;
import net.minestom.server.network.packet.PacketWriter;
import net.minestom.server.utils.binary.BinaryReader;
import net.minestom.server.utils.binary.BinaryWriter;
public class CharacterArrayData extends DataType<char[]> {
@Override
public void encode(PacketWriter packetWriter, char[] value) {
packetWriter.writeVarInt(value.length);
public void encode(BinaryWriter writer, char[] value) {
writer.writeVarInt(value.length);
for (char val : value) {
packetWriter.writeChar(val);
writer.writeChar(val);
}
}
@Override
public char[] decode(PacketReader packetReader) {
char[] array = new char[packetReader.readVarInt()];
public char[] decode(BinaryReader reader) {
char[] array = new char[reader.readVarInt()];
for (int i = 0; i < array.length; i++) {
array[i] = packetReader.readChar();
array[i] = reader.readChar();
}
return array;
}

View File

@ -1,24 +1,24 @@
package net.minestom.server.data.type.array;
import net.minestom.server.data.DataType;
import net.minestom.server.network.packet.PacketReader;
import net.minestom.server.network.packet.PacketWriter;
import net.minestom.server.utils.binary.BinaryReader;
import net.minestom.server.utils.binary.BinaryWriter;
public class DoubleArrayData extends DataType<double[]> {
@Override
public void encode(PacketWriter packetWriter, double[] value) {
packetWriter.writeVarInt(value.length);
public void encode(BinaryWriter writer, double[] value) {
writer.writeVarInt(value.length);
for (double val : value) {
packetWriter.writeDouble(val);
writer.writeDouble(val);
}
}
@Override
public double[] decode(PacketReader packetReader) {
double[] array = new double[packetReader.readVarInt()];
public double[] decode(BinaryReader reader) {
double[] array = new double[reader.readVarInt()];
for (int i = 0; i < array.length; i++) {
array[i] = packetReader.readDouble();
array[i] = reader.readDouble();
}
return array;
}

View File

@ -1,24 +1,24 @@
package net.minestom.server.data.type.array;
import net.minestom.server.data.DataType;
import net.minestom.server.network.packet.PacketReader;
import net.minestom.server.network.packet.PacketWriter;
import net.minestom.server.utils.binary.BinaryReader;
import net.minestom.server.utils.binary.BinaryWriter;
public class FloatArrayData extends DataType<float[]> {
@Override
public void encode(PacketWriter packetWriter, float[] value) {
packetWriter.writeVarInt(value.length);
public void encode(BinaryWriter writer, float[] value) {
writer.writeVarInt(value.length);
for (float val : value) {
packetWriter.writeFloat(val);
writer.writeFloat(val);
}
}
@Override
public float[] decode(PacketReader packetReader) {
float[] array = new float[packetReader.readVarInt()];
public float[] decode(BinaryReader reader) {
float[] array = new float[reader.readVarInt()];
for (int i = 0; i < array.length; i++) {
array[i] = packetReader.readFloat();
array[i] = reader.readFloat();
}
return array;
}

View File

@ -1,24 +1,24 @@
package net.minestom.server.data.type.array;
import net.minestom.server.data.DataType;
import net.minestom.server.network.packet.PacketReader;
import net.minestom.server.network.packet.PacketWriter;
import net.minestom.server.utils.binary.BinaryReader;
import net.minestom.server.utils.binary.BinaryWriter;
public class IntegerArrayData extends DataType<int[]> {
@Override
public void encode(PacketWriter packetWriter, int[] value) {
packetWriter.writeVarInt(value.length);
public void encode(BinaryWriter writer, int[] value) {
writer.writeVarInt(value.length);
for (int val : value) {
packetWriter.writeInt(val);
writer.writeInt(val);
}
}
@Override
public int[] decode(PacketReader packetReader) {
int[] array = new int[packetReader.readVarInt()];
public int[] decode(BinaryReader reader) {
int[] array = new int[reader.readVarInt()];
for (int i = 0; i < array.length; i++) {
array[i] = packetReader.readInteger();
array[i] = reader.readInteger();
}
return array;
}

View File

@ -2,23 +2,23 @@ package net.minestom.server.data.type.array;
import net.minestom.server.data.DataType;
import net.minestom.server.item.ItemStack;
import net.minestom.server.network.packet.PacketReader;
import net.minestom.server.network.packet.PacketWriter;
import net.minestom.server.utils.binary.BinaryReader;
import net.minestom.server.utils.binary.BinaryWriter;
public class ItemStackArrayData extends DataType<ItemStack[]> {
@Override
public void encode(PacketWriter packetWriter, ItemStack[] value) {
packetWriter.writeVarInt(value.length);
public void encode(BinaryWriter writer, ItemStack[] value) {
writer.writeVarInt(value.length);
for (ItemStack itemStack : value) {
packetWriter.writeItemStack(itemStack);
writer.writeItemStack(itemStack);
}
}
@Override
public ItemStack[] decode(PacketReader packetReader) {
ItemStack[] items = new ItemStack[packetReader.readVarInt()];
public ItemStack[] decode(BinaryReader reader) {
ItemStack[] items = new ItemStack[reader.readVarInt()];
for (int i = 0; i < items.length; i++) {
items[i] = packetReader.readSlot();
items[i] = reader.readSlot();
}
return items;
}

View File

@ -1,24 +1,24 @@
package net.minestom.server.data.type.array;
import net.minestom.server.data.DataType;
import net.minestom.server.network.packet.PacketReader;
import net.minestom.server.network.packet.PacketWriter;
import net.minestom.server.utils.binary.BinaryReader;
import net.minestom.server.utils.binary.BinaryWriter;
public class LongArrayData extends DataType<long[]> {
@Override
public void encode(PacketWriter packetWriter, long[] value) {
packetWriter.writeVarInt(value.length);
public void encode(BinaryWriter writer, long[] value) {
writer.writeVarInt(value.length);
for (long val : value) {
packetWriter.writeLong(val);
writer.writeLong(val);
}
}
@Override
public long[] decode(PacketReader packetReader) {
long[] array = new long[packetReader.readVarInt()];
public long[] decode(BinaryReader reader) {
long[] array = new long[reader.readVarInt()];
for (int i = 0; i < array.length; i++) {
array[i] = packetReader.readLong();
array[i] = reader.readLong();
}
return array;
}

View File

@ -1,24 +1,24 @@
package net.minestom.server.data.type.array;
import net.minestom.server.data.DataType;
import net.minestom.server.network.packet.PacketReader;
import net.minestom.server.network.packet.PacketWriter;
import net.minestom.server.utils.binary.BinaryReader;
import net.minestom.server.utils.binary.BinaryWriter;
public class ShortArrayData extends DataType<short[]> {
@Override
public void encode(PacketWriter packetWriter, short[] value) {
packetWriter.writeVarInt(value.length);
public void encode(BinaryWriter writer, short[] value) {
writer.writeVarInt(value.length);
for (short val : value) {
packetWriter.writeShort(val);
writer.writeShort(val);
}
}
@Override
public short[] decode(PacketReader packetReader) {
short[] array = new short[packetReader.readVarInt()];
public short[] decode(BinaryReader reader) {
short[] array = new short[reader.readVarInt()];
for (int i = 0; i < array.length; i++) {
array[i] = packetReader.readShort();
array[i] = reader.readShort();
}
return array;
}

View File

@ -1,24 +1,24 @@
package net.minestom.server.data.type.array;
import net.minestom.server.data.DataType;
import net.minestom.server.network.packet.PacketReader;
import net.minestom.server.network.packet.PacketWriter;
import net.minestom.server.utils.binary.BinaryReader;
import net.minestom.server.utils.binary.BinaryWriter;
public class StringArrayData extends DataType<String[]> {
@Override
public void encode(PacketWriter packetWriter, String[] value) {
packetWriter.writeVarInt(value.length);
public void encode(BinaryWriter writer, String[] value) {
writer.writeVarInt(value.length);
for (String val : value) {
packetWriter.writeSizedString(val);
writer.writeSizedString(val);
}
}
@Override
public String[] decode(PacketReader packetReader) {
String[] array = new String[packetReader.readVarInt()];
public String[] decode(BinaryReader reader) {
String[] array = new String[reader.readVarInt()];
for (int i = 0; i < array.length; i++) {
array[i] = packetReader.readSizedString();
array[i] = reader.readSizedString();
}
return array;
}

View File

@ -19,12 +19,12 @@ import net.minestom.server.instance.Instance;
import net.minestom.server.instance.InstanceManager;
import net.minestom.server.instance.WorldBorder;
import net.minestom.server.instance.block.CustomBlock;
import net.minestom.server.network.packet.PacketWriter;
import net.minestom.server.network.packet.server.play.*;
import net.minestom.server.utils.ArrayUtils;
import net.minestom.server.utils.BlockPosition;
import net.minestom.server.utils.Position;
import net.minestom.server.utils.Vector;
import net.minestom.server.utils.binary.BinaryWriter;
import net.minestom.server.utils.chunk.ChunkUtils;
import net.minestom.server.utils.entity.EntityUtils;
import net.minestom.server.utils.player.PlayerUtils;
@ -1195,7 +1195,7 @@ public abstract class Entity implements Viewable, EventHandler, DataContainer {
*
* @return The consumer used to write {@link EntityMetaDataPacket} in {@link #getMetadataPacket()}
*/
public Consumer<PacketWriter> getMetadataConsumer() {
public Consumer<BinaryWriter> getMetadataConsumer() {
return packet -> {
fillMetadataIndex(packet, 0);
fillMetadataIndex(packet, 1);
@ -1209,7 +1209,7 @@ public abstract class Entity implements Viewable, EventHandler, DataContainer {
/**
* Send a {@link EntityMetaDataPacket} containing only the specified index
* The index is wrote using {@link #fillMetadataIndex(PacketWriter, int)}
* The index is wrote using {@link #fillMetadataIndex(BinaryWriter, int)}
*
* @param index the metadata index
*/
@ -1229,7 +1229,7 @@ public abstract class Entity implements Viewable, EventHandler, DataContainer {
* @param packet the packet writer
* @param index the index to fill/write
*/
protected void fillMetadataIndex(PacketWriter packet, int index) {
protected void fillMetadataIndex(BinaryWriter packet, int index) {
switch (index) {
case 0:
fillStateMetadata(packet);
@ -1255,7 +1255,7 @@ public abstract class Entity implements Viewable, EventHandler, DataContainer {
}
}
private void fillStateMetadata(PacketWriter packet) {
private void fillStateMetadata(BinaryWriter packet) {
packet.writeByte((byte) 0);
packet.writeByte(METADATA_BYTE);
byte index0 = 0;
@ -1278,13 +1278,13 @@ public abstract class Entity implements Viewable, EventHandler, DataContainer {
packet.writeByte(index0);
}
private void fillAirTickMetaData(PacketWriter packet) {
private void fillAirTickMetaData(BinaryWriter packet) {
packet.writeByte((byte) 1);
packet.writeByte(METADATA_VARINT);
packet.writeVarInt(air);
}
private void fillCustomNameMetaData(PacketWriter packet) {
private void fillCustomNameMetaData(BinaryWriter packet) {
boolean hasCustomName = customName != null;
packet.writeByte((byte) 2);
@ -1295,25 +1295,25 @@ public abstract class Entity implements Viewable, EventHandler, DataContainer {
}
}
private void fillCustomNameVisibleMetaData(PacketWriter packet) {
private void fillCustomNameVisibleMetaData(BinaryWriter packet) {
packet.writeByte((byte) 3);
packet.writeByte(METADATA_BOOLEAN);
packet.writeBoolean(customNameVisible);
}
private void fillSilentMetaData(PacketWriter packet) {
private void fillSilentMetaData(BinaryWriter packet) {
packet.writeByte((byte) 4);
packet.writeByte(METADATA_BOOLEAN);
packet.writeBoolean(silent);
}
private void fillNoGravityMetaData(PacketWriter packet) {
private void fillNoGravityMetaData(BinaryWriter packet) {
packet.writeByte((byte) 5);
packet.writeByte(METADATA_BOOLEAN);
packet.writeBoolean(noGravity);
}
private void fillPoseMetaData(PacketWriter packet) {
private void fillPoseMetaData(BinaryWriter packet) {
packet.writeByte((byte) 6);
packet.writeByte(METADATA_POSE);
packet.writeVarInt(pose.ordinal());

View File

@ -28,16 +28,15 @@ public final class EntityManager {
private void waitingPlayersTick() {
Player waitingPlayer;
while ((waitingPlayer = waitingPlayers.poll()) != null) {
final Player playerCache = waitingPlayer;
playerCache.init();
waitingPlayer.init();
PlayerLoginEvent loginEvent = new PlayerLoginEvent(playerCache);
playerCache.callEvent(PlayerLoginEvent.class, loginEvent);
PlayerLoginEvent loginEvent = new PlayerLoginEvent(waitingPlayer);
waitingPlayer.callEvent(PlayerLoginEvent.class, loginEvent);
final Instance spawningInstance = loginEvent.getSpawningInstance();
Check.notNull(spawningInstance, "You need to specify a spawning instance in the PlayerLoginEvent");
playerCache.setInstance(spawningInstance);
waitingPlayer.setInstance(spawningInstance);
}
}

View File

@ -4,8 +4,8 @@ import net.minestom.server.event.entity.EntityItemMergeEvent;
import net.minestom.server.instance.Chunk;
import net.minestom.server.item.ItemStack;
import net.minestom.server.item.StackingRule;
import net.minestom.server.network.packet.PacketWriter;
import net.minestom.server.utils.Position;
import net.minestom.server.utils.binary.BinaryWriter;
import net.minestom.server.utils.time.CooldownUtils;
import net.minestom.server.utils.time.TimeUnit;
import net.minestom.server.utils.time.UpdateOption;
@ -118,7 +118,7 @@ public class ItemEntity extends ObjectEntity {
}
@Override
public Consumer<PacketWriter> getMetadataConsumer() {
public Consumer<BinaryWriter> getMetadataConsumer() {
return packet -> {
super.getMetadataConsumer().accept(packet);
fillMetadataIndex(packet, 7);
@ -126,7 +126,7 @@ public class ItemEntity extends ObjectEntity {
}
@Override
protected void fillMetadataIndex(PacketWriter packet, int index) {
protected void fillMetadataIndex(BinaryWriter packet, int index) {
super.fillMetadataIndex(packet, index);
if (index == 7) {
packet.writeByte((byte) 7);

View File

@ -10,7 +10,6 @@ import net.minestom.server.event.item.PickupItemEvent;
import net.minestom.server.instance.Chunk;
import net.minestom.server.inventory.EquipmentHandler;
import net.minestom.server.item.ItemStack;
import net.minestom.server.network.packet.PacketWriter;
import net.minestom.server.network.packet.server.play.CollectItemPacket;
import net.minestom.server.network.packet.server.play.EntityAnimationPacket;
import net.minestom.server.network.packet.server.play.EntityPropertiesPacket;
@ -19,6 +18,7 @@ import net.minestom.server.scoreboard.Team;
import net.minestom.server.sound.Sound;
import net.minestom.server.sound.SoundCategory;
import net.minestom.server.utils.Position;
import net.minestom.server.utils.binary.BinaryWriter;
import net.minestom.server.utils.time.TimeUnit;
import java.util.Set;
@ -35,7 +35,7 @@ public abstract class LivingEntity extends Entity implements EquipmentHandler {
// Bounding box used for items' pickup (see LivingEntity#setBoundingBox)
protected BoundingBox expandedBoundingBox;
private float[] attributeValues = new float[Attribute.values().length];
private final float[] attributeValues = new float[Attribute.values().length];
private boolean isHandActive;
private boolean offHand;
@ -119,7 +119,7 @@ public abstract class LivingEntity extends Entity implements EquipmentHandler {
}
@Override
public Consumer<PacketWriter> getMetadataConsumer() {
public Consumer<BinaryWriter> getMetadataConsumer() {
return packet -> {
super.getMetadataConsumer().accept(packet);
fillMetadataIndex(packet, 7);
@ -129,7 +129,7 @@ public abstract class LivingEntity extends Entity implements EquipmentHandler {
}
@Override
protected void fillMetadataIndex(PacketWriter packet, int index) {
protected void fillMetadataIndex(BinaryWriter packet, int index) {
super.fillMetadataIndex(packet, index);
if (index == 7) {
packet.writeByte((byte) 7);

View File

@ -24,13 +24,13 @@ import net.minestom.server.inventory.Inventory;
import net.minestom.server.inventory.PlayerInventory;
import net.minestom.server.item.ItemStack;
import net.minestom.server.item.Material;
import net.minestom.server.network.packet.PacketWriter;
import net.minestom.server.network.packet.client.ClientPlayPacket;
import net.minestom.server.network.packet.server.ServerPacket;
import net.minestom.server.network.packet.server.login.JoinGamePacket;
import net.minestom.server.network.packet.server.play.*;
import net.minestom.server.network.player.PlayerConnection;
import net.minestom.server.permission.Permission;
import net.minestom.server.potion.PotionType;
import net.minestom.server.recipe.Recipe;
import net.minestom.server.recipe.RecipeManager;
import net.minestom.server.resourcepack.ResourcePack;
@ -43,6 +43,7 @@ import net.minestom.server.utils.ArrayUtils;
import net.minestom.server.utils.BlockPosition;
import net.minestom.server.utils.MathUtils;
import net.minestom.server.utils.Position;
import net.minestom.server.utils.binary.BinaryWriter;
import net.minestom.server.utils.chunk.ChunkUtils;
import net.minestom.server.utils.validate.Check;
import net.minestom.server.world.DimensionType;
@ -102,9 +103,10 @@ public class Player extends LivingEntity implements CommandSender {
// CustomBlock break delay
private CustomBlock targetCustomBlock;
private BlockPosition targetBlockPosition;
private long targetBlockTime;
private byte targetLastStage;
private int blockBreakTime;
private long targetBreakDelay; // The last break delay requested
private long targetBlockBreakCount; // Number of tick since the last stage change
private byte targetStage; // The current stage of the target block, only if multi player breaking is disabled
private final Set<Player> targetBreakers = new HashSet<>(1); // Only used if multi player breaking is disabled, contains only this player
private BelowNameTag belowNameTag;
@ -159,6 +161,9 @@ public class Player extends LivingEntity implements CommandSender {
this.levelType = LevelType.FLAT;
refreshPosition(0, 0, 0);
// Used to cache the breaker for single custom block breaking
this.targetBreakers.add(this);
// FakePlayer init its connection there
playerConnectionInit();
@ -300,17 +305,38 @@ public class Player extends LivingEntity implements CommandSender {
// Target block stage
if (targetCustomBlock != null) {
final byte animationCount = 10;
final long since = time - targetBlockTime;
byte stage = (byte) (since / (blockBreakTime / animationCount));
stage = MathUtils.setBetween(stage, (byte) -1, animationCount);
if (stage != targetLastStage) {
sendBlockBreakAnimation(targetBlockPosition, stage);
}
this.targetLastStage = stage;
if (stage > 9) {
instance.breakBlock(this, targetBlockPosition);
resetTargetBlock();
this.targetBlockBreakCount++;
final boolean processStage = targetBlockBreakCount >= targetBreakDelay;
if (processStage) {
// Should increment the target block stage
if (targetCustomBlock.enableMultiPlayerBreaking()) {
// Let the custom block object manages the breaking
final boolean canContinue = this.targetCustomBlock.processStage(instance, targetBlockPosition, this);
if (canContinue) {
final Set<Player> breakers = targetCustomBlock.getBreakers(instance, targetBlockPosition);
refreshBreakDelay(breakers);
} else {
resetTargetBlock();
}
} else {
// Let the player object manages the breaking
// The custom block doesn't support multi player breaking
if (targetStage + 1 >= CustomBlock.MAX_STAGE) {
// Break the block
instance.breakBlock(this, targetBlockPosition);
resetTargetBlock();
} else {
// Send the new block break animation packet and refresh data
final Chunk chunk = instance.getChunkAt(targetBlockPosition);
final int entityId = targetCustomBlock.getBreakEntityId(this);
final BlockBreakAnimationPacket blockBreakAnimationPacket = new BlockBreakAnimationPacket(entityId, targetBlockPosition, targetStage);
chunk.sendPacketToViewers(blockBreakAnimationPacket);
refreshBreakDelay(targetBreakers);
this.targetStage++;
}
}
}
}
@ -579,7 +605,7 @@ public class Player extends LivingEntity implements CommandSender {
}
@Override
public Consumer<PacketWriter> getMetadataConsumer() {
public Consumer<BinaryWriter> getMetadataConsumer() {
return packet -> {
super.getMetadataConsumer().accept(packet);
fillMetadataIndex(packet, 14);
@ -588,7 +614,7 @@ public class Player extends LivingEntity implements CommandSender {
}
@Override
protected void fillMetadataIndex(PacketWriter packet, int index) {
protected void fillMetadataIndex(BinaryWriter packet, int index) {
super.fillMetadataIndex(packet, index);
if (index == 14) {
packet.writeByte((byte) 14);
@ -622,7 +648,7 @@ public class Player extends LivingEntity implements CommandSender {
*/
public void sendPluginMessage(String channel, String message) {
// Write the data
PacketWriter writer = new PacketWriter();
BinaryWriter writer = new BinaryWriter();
writer.writeSizedString(message);
// Retrieve the data
final byte[] data = writer.toByteArray();
@ -630,24 +656,6 @@ public class Player extends LivingEntity implements CommandSender {
sendPluginMessage(channel, data);
}
/**
* Send a {@link BlockBreakAnimationPacket} packet to the player and his viewers
* Setting {@code destroyStage} to -1 resets the break animation
*
* @param blockPosition the position of the block
* @param destroyStage the destroy stage
* @throws IllegalArgumentException if {@code destroyStage} is not between -1 and 10
*/
public void sendBlockBreakAnimation(BlockPosition blockPosition, byte destroyStage) {
Check.argCondition(!MathUtils.isBetween(destroyStage, -1, 10),
"The destroy stage has to be between -1 and 10");
BlockBreakAnimationPacket breakAnimationPacket = new BlockBreakAnimationPacket();
breakAnimationPacket.entityId = getEntityId() + 1;
breakAnimationPacket.blockPosition = blockPosition;
breakAnimationPacket.destroyStage = destroyStage;
sendPacketToViewersAndSelf(breakAnimationPacket);
}
@Override
public void sendMessage(String message) {
sendMessage(ColoredText.of(message));
@ -1690,7 +1698,7 @@ public class Player extends LivingEntity implements CommandSender {
* Change the player ability "Creative Mode"
* <a href="https://wiki.vg/Protocol#Player_Abilities_.28clientbound.29">see</a>
* <p>
* WARNING: this has nothing to do with {@link CustomBlock#getBreakDelay(Player, BlockPosition)}
* WARNING: this has nothing to do with {@link CustomBlock#getBreakDelay(Player, BlockPosition, byte, Set)}
*
* @param instantBreak true to allow instant break
*/
@ -1858,8 +1866,8 @@ public class Player extends LivingEntity implements CommandSender {
if (isFood && !allowFood)
return null;
ItemUpdateStateEvent itemUpdateStateEvent = new ItemUpdateStateEvent(updatedItem,
isOffhand ? Hand.OFF : Hand.MAIN);
final Hand hand = isOffhand ? Hand.OFF : Hand.MAIN;
ItemUpdateStateEvent itemUpdateStateEvent = new ItemUpdateStateEvent(this, hand, updatedItem);
callEvent(ItemUpdateStateEvent.class, itemUpdateStateEvent);
return itemUpdateStateEvent;
@ -1870,13 +1878,33 @@ public class Player extends LivingEntity implements CommandSender {
*
* @param targetCustomBlock the custom block to dig
* @param targetBlockPosition the custom block position
* @param breakTime the time it will take to break the block in milliseconds
* @param breakers the breakers of the block, can be null if {@code this} is the only breaker
*/
public void setTargetBlock(CustomBlock targetCustomBlock, BlockPosition targetBlockPosition, int breakTime) {
public void setTargetBlock(CustomBlock targetCustomBlock, BlockPosition targetBlockPosition, Set<Player> breakers) {
this.targetCustomBlock = targetCustomBlock;
this.targetBlockPosition = targetBlockPosition;
this.targetBlockTime = targetBlockPosition == null ? 0 : System.currentTimeMillis();
this.blockBreakTime = breakTime;
refreshBreakDelay(breakers);
}
/**
* Refresh the break delay for the next block break stage
*
* @param breakers the list of breakers, can be null if {@code this} is the only breaker
*/
private void refreshBreakDelay(Set<Player> breakers) {
breakers = breakers == null ? targetBreakers : breakers;
// Refresh the last tick update
this.targetBlockBreakCount = 0;
// Get if multi player breaking is enabled
final boolean multiPlayerBreaking = targetCustomBlock.enableMultiPlayerBreaking();
// Get the stage from the custom block object if it is, otherwise use the local fieldl
final byte stage = multiPlayerBreaking ? targetCustomBlock.getBreakStage(instance, targetBlockPosition) : targetStage;
// Retrieve the break delay for the current stage
final int breakDelay = targetCustomBlock.getBreakDelay(this, targetBlockPosition, stage, breakers);
this.targetBreakDelay = breakDelay;
}
/**
@ -1884,17 +1912,19 @@ public class Player extends LivingEntity implements CommandSender {
* If the currently mined block (or if there isn't any) is not a CustomBlock, nothing append
*/
public void resetTargetBlock() {
if (targetBlockPosition != null) {
sendBlockBreakAnimation(targetBlockPosition, (byte) -1); // Clear the break animation
if (targetCustomBlock != null) {
targetCustomBlock.stopDigging(instance, targetBlockPosition, this);
this.targetCustomBlock = null;
this.targetBlockPosition = null;
this.targetBlockTime = 0;
this.targetBreakDelay = 0;
this.targetBlockBreakCount = 0;
this.targetStage = 0;
// Remove effect
RemoveEntityEffectPacket removeEntityEffectPacket = new RemoveEntityEffectPacket();
removeEntityEffectPacket.entityId = getEntityId();
removeEntityEffectPacket.effectId = 4;
getPlayerConnection().sendPacket(removeEntityEffectPacket);
removeEntityEffectPacket.effect = PotionType.AWKWARD;
playerConnection.sendPacket(removeEntityEffectPacket);
}
}
@ -1927,7 +1957,7 @@ public class Player extends LivingEntity implements CommandSender {
}
/**
* Get the packet to add the player from tab-list
* Get the packet to add the player from the tab-list
*
* @return a {@link PlayerInfoPacket} to add the player
*/
@ -1950,9 +1980,9 @@ public class Player extends LivingEntity implements CommandSender {
}
/**
* Get the packet to remove the player from tab-list
* Get the packet to remove the player from the tab-list
*
* @return a {@link PlayerInfoPacket} to add the player
* @return a {@link PlayerInfoPacket} to remove the player
*/
protected PlayerInfoPacket getRemovePlayerToList() {
PlayerInfoPacket playerInfoPacket = new PlayerInfoPacket(PlayerInfoPacket.Action.REMOVE_PLAYER);
@ -1968,7 +1998,7 @@ public class Player extends LivingEntity implements CommandSender {
* Send all the related packet to have the player sent to another with related data
* (create player, spawn position, velocity, metadata, equipments, passengers, team)
* <p>
* WARNING: this does not sync the player, please use {@link #addViewer(Player)}
* WARNING: this alone does not sync the player, please use {@link #addViewer(Player)}
*
* @param connection the connection to show the player to
*/

View File

@ -17,7 +17,7 @@ public class Hologram implements Viewable {
private static final float OFFSET_Y = -0.9875f;
private HologramEntity entity;
private final HologramEntity entity;
private Position position;
private ColoredText text;
@ -124,7 +124,7 @@ public class Hologram implements Viewable {
}
private class HologramEntity extends EntityArmorStand {
private static class HologramEntity extends EntityArmorStand {
public HologramEntity(Position spawnPosition) {
super(spawnPosition);

View File

@ -1,11 +1,36 @@
package net.minestom.server.entity.pathfinding;
import com.extollit.gaming.ai.path.model.IBlockDescription;
import it.unimi.dsi.fastutil.shorts.Short2ObjectMap;
import it.unimi.dsi.fastutil.shorts.Short2ObjectOpenHashMap;
import net.minestom.server.instance.block.Block;
public class PFBlockDescription implements IBlockDescription {
private Block block;
private static final Short2ObjectMap<PFBlockDescription> BLOCK_DESCRITION_MAP = new Short2ObjectOpenHashMap<>();
/**
* Get the {@link PFBlockDescription} linked to the block state id
* <p>
* Cache the result if it is not already
*
* @param blockStateId the block state id
* @return the {@link PFBlockDescription} linked to {@code blockStateId}
*/
public static PFBlockDescription getBlockDescription(short blockStateId) {
if (!BLOCK_DESCRITION_MAP.containsKey(blockStateId)) {
synchronized (BLOCK_DESCRITION_MAP) {
final Block block = Block.fromStateId(blockStateId);
final PFBlockDescription blockDescription = new PFBlockDescription(block);
BLOCK_DESCRITION_MAP.put(blockStateId, blockDescription);
return blockDescription;
}
}
return BLOCK_DESCRITION_MAP.get(blockStateId);
}
private final Block block;
public PFBlockDescription(Block block) {
this.block = block;

View File

@ -2,11 +2,36 @@ package net.minestom.server.entity.pathfinding;
import com.extollit.gaming.ai.path.model.IBlockObject;
import com.extollit.linalg.immutable.AxisAlignedBBox;
import it.unimi.dsi.fastutil.shorts.Short2ObjectMap;
import it.unimi.dsi.fastutil.shorts.Short2ObjectOpenHashMap;
import net.minestom.server.instance.block.Block;
public class PFBlockObject implements IBlockObject {
private Block block;
private static final Short2ObjectMap<PFBlockObject> BLOCK_OBJECT_MAP = new Short2ObjectOpenHashMap<>();
/**
* Get the {@link PFBlockObject} linked to the block state id
* <p>
* Cache the result if it is not already
*
* @param blockStateId the block state id
* @return the {@link PFBlockObject} linked to {@code blockStateId}
*/
public static PFBlockObject getBlockObject(short blockStateId) {
if (!BLOCK_OBJECT_MAP.containsKey(blockStateId)) {
synchronized (BLOCK_OBJECT_MAP) {
final Block block = Block.fromStateId(blockStateId);
final PFBlockObject blockObject = new PFBlockObject(block);
BLOCK_OBJECT_MAP.put(blockStateId, blockObject);
return blockObject;
}
}
return BLOCK_OBJECT_MAP.get(blockStateId);
}
private final Block block;
public PFBlockObject(Block block) {
this.block = block;

View File

@ -5,7 +5,6 @@ import com.extollit.gaming.ai.path.model.IBlockDescription;
import com.extollit.gaming.ai.path.model.IColumnarSpace;
import com.extollit.gaming.ai.path.model.IInstanceSpace;
import net.minestom.server.instance.Chunk;
import net.minestom.server.instance.block.Block;
public class PFColumnarSpace implements IColumnarSpace {
@ -22,8 +21,7 @@ public class PFColumnarSpace implements IColumnarSpace {
@Override
public IBlockDescription blockAt(int x, int y, int z) {
final short blockStateId = chunk.getBlockStateId(x, y, z);
final Block block = Block.fromStateId(blockStateId);
return new PFBlockDescription(block);
return PFBlockDescription.getBlockDescription(blockStateId);
}
@Override

View File

@ -5,7 +5,6 @@ import com.extollit.gaming.ai.path.model.IColumnarSpace;
import com.extollit.gaming.ai.path.model.IInstanceSpace;
import net.minestom.server.instance.Chunk;
import net.minestom.server.instance.Instance;
import net.minestom.server.instance.block.Block;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
@ -22,8 +21,7 @@ public class PFInstanceSpace implements IInstanceSpace {
@Override
public IBlockObject blockObjectAt(int x, int y, int z) {
final short blockStateId = instance.getBlockStateId(x, y, z);
final Block block = Block.fromStateId(blockStateId);
return new PFBlockObject(block);
return PFBlockObject.getBlockObject(blockStateId);
}
@Override
@ -33,14 +31,11 @@ public class PFInstanceSpace implements IInstanceSpace {
return null;
}
final PFColumnarSpace columnarSpace =
chunkSpaceMap.computeIfAbsent(chunk, c -> {
final PFColumnarSpace cs = new PFColumnarSpace(this, c);
c.setColumnarSpace(cs);
return cs;
});
return columnarSpace;
return chunkSpaceMap.computeIfAbsent(chunk, c -> {
final PFColumnarSpace cs = new PFColumnarSpace(this, c);
c.setColumnarSpace(cs);
return cs;
});
}
public Instance getInstance() {

View File

@ -3,8 +3,8 @@ package net.minestom.server.entity.type.ambient;
import net.minestom.server.entity.EntityCreature;
import net.minestom.server.entity.EntityType;
import net.minestom.server.entity.type.Animal;
import net.minestom.server.network.packet.PacketWriter;
import net.minestom.server.utils.Position;
import net.minestom.server.utils.binary.BinaryWriter;
import java.util.function.Consumer;
@ -18,7 +18,7 @@ public class EntityBat extends EntityCreature implements Animal {
}
@Override
public Consumer<PacketWriter> getMetadataConsumer() {
public Consumer<BinaryWriter> getMetadataConsumer() {
return packet -> {
super.getMetadataConsumer().accept(packet);
fillMetadataIndex(packet, 15);
@ -26,7 +26,7 @@ public class EntityBat extends EntityCreature implements Animal {
}
@Override
protected void fillMetadataIndex(PacketWriter packet, int index) {
protected void fillMetadataIndex(BinaryWriter packet, int index) {
super.fillMetadataIndex(packet, index);
if (index == 15) {
packet.writeByte((byte) 15);

View File

@ -3,8 +3,8 @@ package net.minestom.server.entity.type.animal;
import net.minestom.server.entity.EntityCreature;
import net.minestom.server.entity.EntityType;
import net.minestom.server.entity.type.Animal;
import net.minestom.server.network.packet.PacketWriter;
import net.minestom.server.utils.Position;
import net.minestom.server.utils.binary.BinaryWriter;
import java.util.function.Consumer;
@ -19,7 +19,7 @@ public class EntityMooshroom extends EntityCreature implements Animal {
}
@Override
public Consumer<PacketWriter> getMetadataConsumer() {
public Consumer<BinaryWriter> getMetadataConsumer() {
return packet -> {
super.getMetadataConsumer().accept(packet);
fillMetadataIndex(packet, 16);
@ -27,7 +27,7 @@ public class EntityMooshroom extends EntityCreature implements Animal {
}
@Override
protected void fillMetadataIndex(PacketWriter packet, int index) {
protected void fillMetadataIndex(BinaryWriter packet, int index) {
super.fillMetadataIndex(packet, index);
if (index == 16) {
packet.writeByte((byte) 16);

View File

@ -3,8 +3,8 @@ package net.minestom.server.entity.type.animal;
import net.minestom.server.entity.EntityCreature;
import net.minestom.server.entity.EntityType;
import net.minestom.server.entity.type.Animal;
import net.minestom.server.network.packet.PacketWriter;
import net.minestom.server.utils.Position;
import net.minestom.server.utils.binary.BinaryWriter;
import java.util.function.Consumer;
@ -18,7 +18,7 @@ public class EntityPig extends EntityCreature implements Animal {
}
@Override
public Consumer<PacketWriter> getMetadataConsumer() {
public Consumer<BinaryWriter> getMetadataConsumer() {
return packet -> {
super.getMetadataConsumer().accept(packet);
fillMetadataIndex(packet, 16);
@ -26,7 +26,7 @@ public class EntityPig extends EntityCreature implements Animal {
}
@Override
protected void fillMetadataIndex(PacketWriter packet, int index) {
protected void fillMetadataIndex(BinaryWriter packet, int index) {
super.fillMetadataIndex(packet, index);
if (index == 16) {
packet.writeByte((byte) 16);

View File

@ -3,8 +3,8 @@ package net.minestom.server.entity.type.animal;
import net.minestom.server.entity.EntityCreature;
import net.minestom.server.entity.EntityType;
import net.minestom.server.entity.type.Animal;
import net.minestom.server.network.packet.PacketWriter;
import net.minestom.server.utils.Position;
import net.minestom.server.utils.binary.BinaryWriter;
import java.util.function.Consumer;
@ -18,7 +18,7 @@ public class EntityPolarBear extends EntityCreature implements Animal {
}
@Override
public Consumer<PacketWriter> getMetadataConsumer() {
public Consumer<BinaryWriter> getMetadataConsumer() {
return packet -> {
super.getMetadataConsumer().accept(packet);
fillMetadataIndex(packet, 16);
@ -26,7 +26,7 @@ public class EntityPolarBear extends EntityCreature implements Animal {
}
@Override
protected void fillMetadataIndex(PacketWriter packet, int index) {
protected void fillMetadataIndex(BinaryWriter packet, int index) {
super.fillMetadataIndex(packet, index);
if (index == 16) {
packet.writeByte((byte) 16);

View File

@ -3,8 +3,8 @@ package net.minestom.server.entity.type.animal;
import net.minestom.server.entity.EntityCreature;
import net.minestom.server.entity.EntityType;
import net.minestom.server.entity.type.Animal;
import net.minestom.server.network.packet.PacketWriter;
import net.minestom.server.utils.Position;
import net.minestom.server.utils.binary.BinaryWriter;
import java.util.function.Consumer;
@ -18,7 +18,7 @@ public class EntityRabbit extends EntityCreature implements Animal {
}
@Override
public Consumer<PacketWriter> getMetadataConsumer() {
public Consumer<BinaryWriter> getMetadataConsumer() {
return packet -> {
super.getMetadataConsumer().accept(packet);
fillMetadataIndex(packet, 16);
@ -26,7 +26,7 @@ public class EntityRabbit extends EntityCreature implements Animal {
}
@Override
protected void fillMetadataIndex(PacketWriter packet, int index) {
protected void fillMetadataIndex(BinaryWriter packet, int index) {
super.fillMetadataIndex(packet, index);
if (index == 16) {
packet.writeByte((byte) 16);

View File

@ -6,10 +6,10 @@ import net.minestom.server.entity.Player;
import net.minestom.server.event.item.ArmorEquipEvent;
import net.minestom.server.inventory.EquipmentHandler;
import net.minestom.server.item.ItemStack;
import net.minestom.server.network.packet.PacketWriter;
import net.minestom.server.network.packet.server.play.EntityEquipmentPacket;
import net.minestom.server.utils.Position;
import net.minestom.server.utils.Vector;
import net.minestom.server.utils.binary.BinaryWriter;
import net.minestom.server.utils.item.ItemStackUtils;
import java.util.function.Consumer;
@ -73,7 +73,7 @@ public class EntityArmorStand extends ObjectEntity implements EquipmentHandler {
}
@Override
public Consumer<PacketWriter> getMetadataConsumer() {
public Consumer<BinaryWriter> getMetadataConsumer() {
return packet -> {
super.getMetadataConsumer().accept(packet);
fillMetadataIndex(packet, 14);
@ -87,7 +87,7 @@ public class EntityArmorStand extends ObjectEntity implements EquipmentHandler {
}
@Override
protected void fillMetadataIndex(PacketWriter packet, int index) {
protected void fillMetadataIndex(BinaryWriter packet, int index) {
super.fillMetadataIndex(packet, index);
if (index == 14) {
packet.writeByte((byte) 14);

View File

@ -3,9 +3,9 @@ package net.minestom.server.entity.type.decoration;
import net.minestom.server.entity.EntityType;
import net.minestom.server.entity.ObjectEntity;
import net.minestom.server.item.ItemStack;
import net.minestom.server.network.packet.PacketWriter;
import net.minestom.server.utils.Position;
import net.minestom.server.utils.Rotation;
import net.minestom.server.utils.binary.BinaryWriter;
import net.minestom.server.utils.item.ItemStackUtils;
import java.util.function.Consumer;
@ -27,7 +27,7 @@ public class EntityItemFrame extends ObjectEntity {
}
@Override
public Consumer<PacketWriter> getMetadataConsumer() {
public Consumer<BinaryWriter> getMetadataConsumer() {
return packet -> {
super.getMetadataConsumer().accept(packet);
fillMetadataIndex(packet, 7);
@ -36,7 +36,7 @@ public class EntityItemFrame extends ObjectEntity {
}
@Override
protected void fillMetadataIndex(PacketWriter packet, int index) {
protected void fillMetadataIndex(BinaryWriter packet, int index) {
super.fillMetadataIndex(packet, index);
if (index == 7) {
packet.writeByte((byte) 7);

View File

@ -3,8 +3,8 @@ package net.minestom.server.entity.type.monster;
import net.minestom.server.entity.EntityCreature;
import net.minestom.server.entity.EntityType;
import net.minestom.server.entity.type.Monster;
import net.minestom.server.network.packet.PacketWriter;
import net.minestom.server.utils.Position;
import net.minestom.server.utils.binary.BinaryWriter;
import java.util.function.Consumer;
@ -16,7 +16,7 @@ public class EntityBlaze extends EntityCreature implements Monster {
}
@Override
public Consumer<PacketWriter> getMetadataConsumer() {
public Consumer<BinaryWriter> getMetadataConsumer() {
return packet -> {
super.getMetadataConsumer().accept(packet);
fillMetadataIndex(packet, 15);
@ -24,7 +24,7 @@ public class EntityBlaze extends EntityCreature implements Monster {
}
@Override
protected void fillMetadataIndex(PacketWriter packet, int index) {
protected void fillMetadataIndex(BinaryWriter packet, int index) {
super.fillMetadataIndex(packet, index);
if (index == 15) {
packet.writeByte((byte) 15);

View File

@ -3,8 +3,8 @@ package net.minestom.server.entity.type.monster;
import net.minestom.server.entity.EntityCreature;
import net.minestom.server.entity.EntityType;
import net.minestom.server.entity.type.Monster;
import net.minestom.server.network.packet.PacketWriter;
import net.minestom.server.utils.Position;
import net.minestom.server.utils.binary.BinaryWriter;
import java.util.function.Consumer;
@ -20,7 +20,7 @@ public class EntityCreeper extends EntityCreature implements Monster {
}
@Override
public Consumer<PacketWriter> getMetadataConsumer() {
public Consumer<BinaryWriter> getMetadataConsumer() {
return packet -> {
super.getMetadataConsumer().accept(packet);
fillMetadataIndex(packet, 15);
@ -28,7 +28,7 @@ public class EntityCreeper extends EntityCreature implements Monster {
}
@Override
protected void fillMetadataIndex(PacketWriter packet, int index) {
protected void fillMetadataIndex(BinaryWriter packet, int index) {
super.fillMetadataIndex(packet, index);
if (index == 15) {
packet.writeByte((byte) 15);

View File

@ -3,8 +3,8 @@ package net.minestom.server.entity.type.monster;
import net.minestom.server.entity.EntityCreature;
import net.minestom.server.entity.EntityType;
import net.minestom.server.entity.type.Monster;
import net.minestom.server.network.packet.PacketWriter;
import net.minestom.server.utils.Position;
import net.minestom.server.utils.binary.BinaryWriter;
import java.util.function.Consumer;
@ -19,7 +19,7 @@ public class EntityGhast extends EntityCreature implements Monster {
}
@Override
public Consumer<PacketWriter> getMetadataConsumer() {
public Consumer<BinaryWriter> getMetadataConsumer() {
return packet -> {
super.getMetadataConsumer().accept(packet);
fillMetadataIndex(packet, 15);
@ -27,7 +27,7 @@ public class EntityGhast extends EntityCreature implements Monster {
}
@Override
protected void fillMetadataIndex(PacketWriter packet, int index) {
protected void fillMetadataIndex(BinaryWriter packet, int index) {
super.fillMetadataIndex(packet, index);
if (index == 15) {
packet.writeByte((byte) 15);

View File

@ -4,8 +4,8 @@ import net.minestom.server.entity.Entity;
import net.minestom.server.entity.EntityCreature;
import net.minestom.server.entity.EntityType;
import net.minestom.server.entity.type.Monster;
import net.minestom.server.network.packet.PacketWriter;
import net.minestom.server.utils.Position;
import net.minestom.server.utils.binary.BinaryWriter;
import java.util.function.Consumer;
@ -20,7 +20,7 @@ public class EntityGuardian extends EntityCreature implements Monster {
}
@Override
public Consumer<PacketWriter> getMetadataConsumer() {
public Consumer<BinaryWriter> getMetadataConsumer() {
return packet -> {
super.getMetadataConsumer().accept(packet);
fillMetadataIndex(packet, 15);
@ -29,7 +29,7 @@ public class EntityGuardian extends EntityCreature implements Monster {
}
@Override
protected void fillMetadataIndex(PacketWriter packet, int index) {
protected void fillMetadataIndex(BinaryWriter packet, int index) {
super.fillMetadataIndex(packet, index);
if (index == 15) {
packet.writeByte((byte) 15);

View File

@ -3,8 +3,8 @@ package net.minestom.server.entity.type.monster;
import net.minestom.server.entity.EntityCreature;
import net.minestom.server.entity.EntityType;
import net.minestom.server.entity.type.Monster;
import net.minestom.server.network.packet.PacketWriter;
import net.minestom.server.utils.Position;
import net.minestom.server.utils.binary.BinaryWriter;
import java.util.function.Consumer;
@ -18,7 +18,7 @@ public class EntityPhantom extends EntityCreature implements Monster {
}
@Override
public Consumer<PacketWriter> getMetadataConsumer() {
public Consumer<BinaryWriter> getMetadataConsumer() {
return packet -> {
super.getMetadataConsumer().accept(packet);
fillMetadataIndex(packet, 15);
@ -26,7 +26,7 @@ public class EntityPhantom extends EntityCreature implements Monster {
}
@Override
protected void fillMetadataIndex(PacketWriter packet, int index) {
protected void fillMetadataIndex(BinaryWriter packet, int index) {
super.fillMetadataIndex(packet, index);
if (index == 15) {
packet.writeByte((byte) 15);

View File

@ -3,8 +3,8 @@ package net.minestom.server.entity.type.monster;
import net.minestom.server.entity.EntityCreature;
import net.minestom.server.entity.EntityType;
import net.minestom.server.entity.type.Monster;
import net.minestom.server.network.packet.PacketWriter;
import net.minestom.server.utils.Position;
import net.minestom.server.utils.binary.BinaryWriter;
import java.util.function.Consumer;
@ -18,7 +18,7 @@ public class EntitySlime extends EntityCreature implements Monster {
}
@Override
public Consumer<PacketWriter> getMetadataConsumer() {
public Consumer<BinaryWriter> getMetadataConsumer() {
return packet -> {
super.getMetadataConsumer().accept(packet);
fillMetadataIndex(packet, 15);
@ -26,7 +26,7 @@ public class EntitySlime extends EntityCreature implements Monster {
}
@Override
protected void fillMetadataIndex(PacketWriter packet, int index) {
protected void fillMetadataIndex(BinaryWriter packet, int index) {
super.fillMetadataIndex(packet, index);
if (index == 15) {
packet.writeByte((byte) 15);

View File

@ -3,8 +3,8 @@ package net.minestom.server.entity.type.monster;
import net.minestom.server.entity.EntityCreature;
import net.minestom.server.entity.EntityType;
import net.minestom.server.entity.type.Monster;
import net.minestom.server.network.packet.PacketWriter;
import net.minestom.server.utils.Position;
import net.minestom.server.utils.binary.BinaryWriter;
import java.util.function.Consumer;
@ -19,7 +19,7 @@ public class EntitySpider extends EntityCreature implements Monster {
}
@Override
public Consumer<PacketWriter> getMetadataConsumer() {
public Consumer<BinaryWriter> getMetadataConsumer() {
return packet -> {
super.getMetadataConsumer().accept(packet);
fillMetadataIndex(packet, 15);
@ -27,7 +27,7 @@ public class EntitySpider extends EntityCreature implements Monster {
}
@Override
protected void fillMetadataIndex(PacketWriter packet, int index) {
protected void fillMetadataIndex(BinaryWriter packet, int index) {
super.fillMetadataIndex(packet, index);
if (index == 15) {
packet.writeByte((byte) 15);

View File

@ -3,8 +3,8 @@ package net.minestom.server.entity.type.monster;
import net.minestom.server.entity.EntityCreature;
import net.minestom.server.entity.EntityType;
import net.minestom.server.entity.type.Monster;
import net.minestom.server.network.packet.PacketWriter;
import net.minestom.server.utils.Position;
import net.minestom.server.utils.binary.BinaryWriter;
import java.util.function.Consumer;
@ -19,7 +19,7 @@ public class EntityWitch extends EntityCreature implements Monster {
}
@Override
public Consumer<PacketWriter> getMetadataConsumer() {
public Consumer<BinaryWriter> getMetadataConsumer() {
return packet -> {
super.getMetadataConsumer().accept(packet);
fillMetadataIndex(packet, 16);
@ -27,7 +27,7 @@ public class EntityWitch extends EntityCreature implements Monster {
}
@Override
protected void fillMetadataIndex(PacketWriter packet, int index) {
protected void fillMetadataIndex(BinaryWriter packet, int index) {
super.fillMetadataIndex(packet, index);
if (index == 16) {
packet.writeByte((byte) 16);

View File

@ -3,8 +3,8 @@ package net.minestom.server.entity.type.monster;
import net.minestom.server.entity.EntityCreature;
import net.minestom.server.entity.EntityType;
import net.minestom.server.entity.type.Monster;
import net.minestom.server.network.packet.PacketWriter;
import net.minestom.server.utils.Position;
import net.minestom.server.utils.binary.BinaryWriter;
import java.util.function.Consumer;
@ -19,7 +19,7 @@ public class EntityZombie extends EntityCreature implements Monster {
}
@Override
public Consumer<PacketWriter> getMetadataConsumer() {
public Consumer<BinaryWriter> getMetadataConsumer() {
return packet -> {
super.getMetadataConsumer().accept(packet);
fillMetadataIndex(packet, 15);
@ -28,7 +28,7 @@ public class EntityZombie extends EntityCreature implements Monster {
}
@Override
protected void fillMetadataIndex(PacketWriter packet, int index) {
protected void fillMetadataIndex(BinaryWriter packet, int index) {
super.fillMetadataIndex(packet, index);
if (index == 15) {
packet.writeByte((byte) 15);

View File

@ -3,8 +3,8 @@ package net.minestom.server.entity.type.monster;
import net.minestom.server.entity.EntityCreature;
import net.minestom.server.entity.EntityType;
import net.minestom.server.entity.type.Monster;
import net.minestom.server.network.packet.PacketWriter;
import net.minestom.server.utils.Position;
import net.minestom.server.utils.binary.BinaryWriter;
import java.util.function.Consumer;
@ -19,7 +19,7 @@ public class EntityZombifiedPiglin extends EntityCreature implements Monster {
}
@Override
public Consumer<PacketWriter> getMetadataConsumer() {
public Consumer<BinaryWriter> getMetadataConsumer() {
return packet -> {
super.getMetadataConsumer().accept(packet);
fillMetadataIndex(packet, 15);
@ -28,7 +28,7 @@ public class EntityZombifiedPiglin extends EntityCreature implements Monster {
}
@Override
protected void fillMetadataIndex(PacketWriter packet, int index) {
protected void fillMetadataIndex(BinaryWriter packet, int index) {
super.fillMetadataIndex(packet, index);
if (index == 15) {
packet.writeByte((byte) 15);

View File

@ -2,15 +2,15 @@ package net.minestom.server.entity.type.other;
import net.minestom.server.entity.EntityType;
import net.minestom.server.entity.ObjectEntity;
import net.minestom.server.network.packet.PacketWriter;
import net.minestom.server.particle.Particle;
import net.minestom.server.utils.Position;
import net.minestom.server.utils.binary.BinaryWriter;
import java.util.function.Consumer;
public class EntityAreaEffectCloud extends ObjectEntity {
public Consumer<PacketWriter> particleDataConsumer;
public Consumer<BinaryWriter> particleDataConsumer;
private float radius;
private int color;
private boolean ignoreRadius;
@ -27,7 +27,7 @@ public class EntityAreaEffectCloud extends ObjectEntity {
}
@Override
public Consumer<PacketWriter> getMetadataConsumer() {
public Consumer<BinaryWriter> getMetadataConsumer() {
return packet -> {
super.getMetadataConsumer().accept(packet);
fillMetadataIndex(packet, 7);
@ -38,7 +38,7 @@ public class EntityAreaEffectCloud extends ObjectEntity {
}
@Override
protected void fillMetadataIndex(PacketWriter packet, int index) {
protected void fillMetadataIndex(BinaryWriter packet, int index) {
super.fillMetadataIndex(packet, index);
if (index == 7) {
packet.writeByte((byte) 7);
@ -102,7 +102,7 @@ public class EntityAreaEffectCloud extends ObjectEntity {
sendMetadataIndex(10);
}
public Consumer<PacketWriter> getParticleDataConsumer() {
public Consumer<BinaryWriter> getParticleDataConsumer() {
return particleDataConsumer;
}
@ -112,7 +112,7 @@ public class EntityAreaEffectCloud extends ObjectEntity {
* @param particleDataConsumer the particle data consumer
* @see @see <a href="https://wiki.vg/Data_types#Particle">Particle data</a>
*/
public void setParticleDataConsumer(Consumer<PacketWriter> particleDataConsumer) {
public void setParticleDataConsumer(Consumer<BinaryWriter> particleDataConsumer) {
this.particleDataConsumer = particleDataConsumer;
}
}

View File

@ -3,8 +3,8 @@ package net.minestom.server.entity.type.other;
import net.minestom.server.entity.EntityCreature;
import net.minestom.server.entity.EntityType;
import net.minestom.server.entity.type.Constructable;
import net.minestom.server.network.packet.PacketWriter;
import net.minestom.server.utils.Position;
import net.minestom.server.utils.binary.BinaryWriter;
import java.util.function.Consumer;
@ -18,7 +18,7 @@ public class EntityIronGolem extends EntityCreature implements Constructable {
}
@Override
public Consumer<PacketWriter> getMetadataConsumer() {
public Consumer<BinaryWriter> getMetadataConsumer() {
return packet -> {
super.getMetadataConsumer().accept(packet);
fillMetadataIndex(packet, 15);
@ -26,7 +26,7 @@ public class EntityIronGolem extends EntityCreature implements Constructable {
}
@Override
protected void fillMetadataIndex(PacketWriter packet, int index) {
protected void fillMetadataIndex(BinaryWriter packet, int index) {
super.fillMetadataIndex(packet, index);
if (index == 15) {
packet.writeByte((byte) 15);

View File

@ -3,8 +3,8 @@ package net.minestom.server.entity.type.other;
import net.minestom.server.entity.EntityCreature;
import net.minestom.server.entity.EntityType;
import net.minestom.server.entity.type.Constructable;
import net.minestom.server.network.packet.PacketWriter;
import net.minestom.server.utils.Position;
import net.minestom.server.utils.binary.BinaryWriter;
import java.util.function.Consumer;
@ -18,7 +18,7 @@ public class EntitySnowman extends EntityCreature implements Constructable {
}
@Override
public Consumer<PacketWriter> getMetadataConsumer() {
public Consumer<BinaryWriter> getMetadataConsumer() {
return packet -> {
super.getMetadataConsumer().accept(packet);
fillMetadataIndex(packet, 15);
@ -26,7 +26,7 @@ public class EntitySnowman extends EntityCreature implements Constructable {
}
@Override
protected void fillMetadataIndex(PacketWriter packet, int index) {
protected void fillMetadataIndex(BinaryWriter packet, int index) {
super.fillMetadataIndex(packet, index);
if (index == 15) {
packet.writeByte((byte) 15);

View File

@ -5,8 +5,8 @@ import net.minestom.server.entity.ObjectEntity;
import net.minestom.server.entity.type.Projectile;
import net.minestom.server.item.ItemStack;
import net.minestom.server.item.Material;
import net.minestom.server.network.packet.PacketWriter;
import net.minestom.server.utils.Position;
import net.minestom.server.utils.binary.BinaryWriter;
import java.util.function.Consumer;
@ -19,7 +19,7 @@ public class EntityEyeOfEnder extends ObjectEntity implements Projectile {
}
@Override
public Consumer<PacketWriter> getMetadataConsumer() {
public Consumer<BinaryWriter> getMetadataConsumer() {
return packet -> {
super.getMetadataConsumer().accept(packet);
fillMetadataIndex(packet, 7);
@ -27,7 +27,7 @@ public class EntityEyeOfEnder extends ObjectEntity implements Projectile {
}
@Override
protected void fillMetadataIndex(PacketWriter packet, int index) {
protected void fillMetadataIndex(BinaryWriter packet, int index) {
super.fillMetadataIndex(packet, index);
if (index == 7) {
packet.writeByte((byte) 7);

View File

@ -4,8 +4,8 @@ import net.minestom.server.entity.EntityType;
import net.minestom.server.entity.ObjectEntity;
import net.minestom.server.entity.type.Projectile;
import net.minestom.server.item.ItemStack;
import net.minestom.server.network.packet.PacketWriter;
import net.minestom.server.utils.Position;
import net.minestom.server.utils.binary.BinaryWriter;
import java.util.function.Consumer;
@ -20,7 +20,7 @@ public class EntityPotion extends ObjectEntity implements Projectile {
}
@Override
public Consumer<PacketWriter> getMetadataConsumer() {
public Consumer<BinaryWriter> getMetadataConsumer() {
return packet -> {
super.getMetadataConsumer().accept(packet);
fillMetadataIndex(packet, 7);
@ -28,7 +28,7 @@ public class EntityPotion extends ObjectEntity implements Projectile {
}
@Override
protected void fillMetadataIndex(PacketWriter packet, int index) {
protected void fillMetadataIndex(BinaryWriter packet, int index) {
super.fillMetadataIndex(packet, index);
if (index == 7) {
packet.writeByte((byte) 7);

View File

@ -3,8 +3,8 @@ package net.minestom.server.entity.type.vehicle;
import net.minestom.server.entity.EntityType;
import net.minestom.server.entity.ObjectEntity;
import net.minestom.server.entity.type.Vehicle;
import net.minestom.server.network.packet.PacketWriter;
import net.minestom.server.utils.Position;
import net.minestom.server.utils.binary.BinaryWriter;
import net.minestom.server.utils.validate.Check;
import java.util.function.Consumer;
@ -27,7 +27,7 @@ public class EntityBoat extends ObjectEntity implements Vehicle {
}
@Override
public Consumer<PacketWriter> getMetadataConsumer() {
public Consumer<BinaryWriter> getMetadataConsumer() {
return packet -> {
super.getMetadataConsumer().accept(packet);
fillMetadataIndex(packet, 10);
@ -39,7 +39,7 @@ public class EntityBoat extends ObjectEntity implements Vehicle {
}
@Override
protected void fillMetadataIndex(PacketWriter packet, int index) {
protected void fillMetadataIndex(BinaryWriter packet, int index) {
super.fillMetadataIndex(packet, index);
if (index == 10) {
packet.writeByte((byte) 10);

View File

@ -23,6 +23,14 @@ public class PlayerVehicleInformation {
return unmount;
}
/**
* Refresh internal data
*
* @param sideways the new sideways value
* @param forward the new forward value
* @param jump the new jump value
* @param unmount the new unmount value
*/
public void refresh(float sideways, float forward, boolean jump, boolean unmount) {
this.sideways = sideways;
this.forward = forward;

View File

@ -43,7 +43,7 @@ public interface EventHandler {
* @param <E> the event type
*/
default <E extends Event> void callEvent(Class<E> eventClass, E event) {
List<EventCallback> eventCallbacks = getEventCallbacks(eventClass);
final List<EventCallback> eventCallbacks = getEventCallbacks(eventClass);
for (EventCallback<E> eventCallback : eventCallbacks) {
eventCallback.run(event);
}

View File

@ -8,8 +8,8 @@ import net.minestom.server.instance.Instance;
*/
public class InstanceChunkLoadEvent extends Event {
private Instance instance;
private int chunkX, chunkZ;
private final Instance instance;
private final int chunkX, chunkZ;
public InstanceChunkLoadEvent(Instance instance, int chunkX, int chunkZ) {
this.instance = instance;

View File

@ -8,8 +8,8 @@ import net.minestom.server.instance.Instance;
*/
public class InstanceChunkUnloadEvent extends Event {
private Instance instance;
private int chunkX, chunkZ;
private final Instance instance;
private final int chunkX, chunkZ;
public InstanceChunkUnloadEvent(Instance instance, int chunkX, int chunkZ) {
this.instance = instance;

View File

@ -8,14 +8,15 @@ import net.minestom.server.item.ItemStack;
public class InventoryClickEvent extends Event {
private Player player;
private Inventory inventory;
private int slot;
private ClickType clickType;
private ItemStack clickedItem;
private ItemStack cursorItem;
private final Player player;
private final Inventory inventory;
private final int slot;
private final ClickType clickType;
private final ItemStack clickedItem;
private final ItemStack cursorItem;
public InventoryClickEvent(Player player, Inventory inventory, int slot, ClickType clickType, ItemStack clicked, ItemStack cursor) {
this.player = player;
this.inventory = inventory;
this.slot = slot;
this.clickType = clickType;

View File

@ -6,8 +6,8 @@ import net.minestom.server.inventory.Inventory;
public class InventoryCloseEvent extends Event {
private Player player;
private Inventory inventory;
private final Player player;
private final Inventory inventory;
private Inventory newInventory;
public InventoryCloseEvent(Player player, Inventory inventory) {

View File

@ -6,7 +6,7 @@ import net.minestom.server.inventory.Inventory;
public class InventoryOpenEvent extends CancellableEvent {
private Player player;
private final Player player;
private Inventory inventory;
public InventoryOpenEvent(Player player, Inventory inventory) {

View File

@ -9,10 +9,10 @@ import net.minestom.server.utils.item.ItemStackUtils;
public class InventoryPreClickEvent extends CancellableEvent {
private Player player;
private Inventory inventory;
private int slot;
private ClickType clickType;
private final Player player;
private final Inventory inventory;
private final int slot;
private final ClickType clickType;
private ItemStack clickedItem;
private ItemStack cursorItem;

View File

@ -6,23 +6,29 @@ import net.minestom.server.item.ItemStack;
public class ItemUpdateStateEvent extends Event {
private ItemStack itemStack;
private Player.Hand hand;
private Player player;
private final Player.Hand hand;
private final ItemStack itemStack;
private boolean handAnimation;
public ItemUpdateStateEvent(ItemStack itemStack, Player.Hand hand) {
this.itemStack = itemStack;
public ItemUpdateStateEvent(Player player, Player.Hand hand, ItemStack itemStack) {
this.player = player;
this.hand = hand;
this.itemStack = itemStack;
}
public ItemStack getItemStack() {
return itemStack;
public Player getPlayer() {
return player;
}
public Player.Hand getHand() {
return hand;
}
public ItemStack getItemStack() {
return itemStack;
}
public void setHandAnimation(boolean handAnimation) {
this.handAnimation = handAnimation;
}

View File

@ -0,0 +1,41 @@
package net.minestom.server.extensions;
import com.google.gson.JsonObject;
import org.slf4j.Logger;
public abstract class Extension {
private JsonObject description;
private Logger logger;
protected Extension() {
}
public void preInitialize() {
}
public abstract void initialize();
public void postInitialize() {
}
public void preTerminate() {
}
public abstract void terminate();
public void postTerminate() {
}
public JsonObject getDescription() {
return description;
}
protected Logger getLogger() {
return logger;
}
}

View File

@ -0,0 +1,169 @@
package net.minestom.server.extensions;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import lombok.extern.slf4j.Slf4j;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.slf4j.LoggerFactory;
import java.io.File;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Slf4j
public class ExtensionManager {
private final Map<URL, URLClassLoader> extensionLoaders = new HashMap<>();
private final Map<String, Extension> extensions = new HashMap<>();
private final File extensionFolder = new File("extensions");
public ExtensionManager() {
}
public void loadExtensionJARs() {
if (!extensionFolder.exists()) {
if (!extensionFolder.mkdirs()) {
log.error("Could not find or create the extension folder, extensions will not be loaded!");
return;
}
}
for (File file : extensionFolder.listFiles()) {
if (file.isDirectory()) {
continue;
}
if (!file.getName().endsWith(".jar")) {
continue;
}
URLClassLoader loader;
try {
URL url = file.toURI().toURL();
loader = loadJar(url);
extensionLoaders.put(url, loader);
} catch (MalformedURLException e) {
log.error(String.format("Failed to get URL for file %s.", file.getPath()));
return;
}
InputStream extensionInputStream = loader.getResourceAsStream("extension.json");
if (extensionInputStream == null) {
log.error(String.format("Failed to find extension.json in the file '%s'.", file.getPath()));
return;
}
JsonObject extensionDescription = JsonParser.parseReader(new InputStreamReader(extensionInputStream)).getAsJsonObject();
String mainClass = extensionDescription.get("entrypoint").getAsString();
String extensionName = extensionDescription.get("name").getAsString();
if (extensions.containsKey(extensionName.toLowerCase())) {
log.error(String.format("An extension called '%s' has already been registered.", extensionName));
return;
}
Class<?> jarClass;
try {
jarClass = Class.forName(mainClass, true, loader);
} catch (ClassNotFoundException e) {
log.error(String.format("Could not find main class '%s' in extension '%s'.", mainClass, extensionName), e);
return;
}
Class<? extends Extension> extensionClass;
try {
extensionClass = jarClass.asSubclass(Extension.class);
} catch (ClassCastException e) {
log.error(String.format("Main class '%s' in '%s' does not extend the 'extension superclass'.", mainClass, extensionName), e);
return;
}
Constructor<? extends Extension> constructor;
try {
constructor = extensionClass.getDeclaredConstructor();
// Let's just make it accessible, plugin creators don't have to make this public.
constructor.setAccessible(true);
} catch (NoSuchMethodException e) {
log.error(String.format("Main class '%s' in '%s' does not define a no-args constructor.", mainClass, extensionName), e);
return;
}
Extension extension = null;
try {
// Is annotated with NotNull
extension = constructor.newInstance();
} catch (InstantiationException e) {
log.error(String.format("Main class '%s' in '%s' cannot be an abstract class.", mainClass, extensionName), e);
return;
} catch (IllegalAccessException ignored) {
// We made it accessible, should not occur
} catch (InvocationTargetException e) {
log.error(
String.format(
"While instantiating the main class '%s' in '%s' an exception was thrown.", mainClass, extensionName
), e.getTargetException()
);
return;
}
// Set description
try {
Field descriptionField = extensionClass.getSuperclass().getDeclaredField("description");
descriptionField.setAccessible(true);
descriptionField.set(extension, extensionDescription);
} catch (IllegalAccessException e) {
// We made it accessible, should not occur
} catch (NoSuchFieldException e) {
log.error(String.format("Main class '%s' in '%s' has no description field.", mainClass, extensionName), e);
return;
}
// Set Logger
try {
Field descriptionField = extensionClass.getSuperclass().getDeclaredField("logger");
descriptionField.setAccessible(true);
descriptionField.set(extension, LoggerFactory.getLogger(extensionClass));
} catch (IllegalAccessException e) {
// We made it accessible, should not occur
} catch (NoSuchFieldException e) {
log.error(String.format("Main class '%s' in '%s' has no logger field.", mainClass, extensionName), e);
}
extensions.put(extensionName.toLowerCase(), extension);
}
}
/**
* Loads a URL into the classpath.
*
* @param url {@link URL} (usually a JAR) that should be loaded.
*/
@NotNull
public URLClassLoader loadJar(@NotNull URL url) {
return URLClassLoader.newInstance(new URL[]{url}, ExtensionManager.class.getClassLoader());
}
@NotNull
public File getExtensionFolder() {
return extensionFolder;
}
@NotNull
public List<Extension> getExtensions() {
return new ArrayList<>(extensions.values());
}
@Nullable
public Extension getExtension(@NotNull String name) {
return extensions.get(name.toLowerCase());
}
@NotNull
public Map<URL, URLClassLoader> getExtensionLoaders() {
return new HashMap<>(extensionLoaders);
}
}

View File

@ -18,6 +18,7 @@ import net.minestom.server.network.packet.server.play.ChunkDataPacket;
import net.minestom.server.network.packet.server.play.UpdateLightPacket;
import net.minestom.server.network.player.PlayerConnection;
import net.minestom.server.utils.BlockPosition;
import net.minestom.server.utils.MathUtils;
import net.minestom.server.utils.chunk.ChunkUtils;
import net.minestom.server.utils.player.PlayerUtils;
import net.minestom.server.utils.time.CooldownUtils;
@ -25,10 +26,8 @@ import net.minestom.server.utils.time.UpdateOption;
import net.minestom.server.utils.validate.Check;
import net.minestom.server.world.biomes.Biome;
import java.io.IOException;
import java.util.*;
import java.util.concurrent.CopyOnWriteArraySet;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.Consumer;
// TODO light data & API
@ -41,15 +40,13 @@ public abstract class Chunk implements Viewable {
public static final int CHUNK_SIZE_Z = 16;
public static final int CHUNK_SECTION_SIZE = 16;
public static final int CHUNK_SECTION_COUNT = CHUNK_SIZE_Y / CHUNK_SECTION_SIZE;
public static final int BIOME_COUNT = 1024; // 4x4x4 blocks
protected Biome[] biomes;
protected int chunkX, chunkZ;
// blocks id based on coord, see Chunk#getBlockIndex
//public short[] blocksStateId = new short[CHUNK_SIZE_X * CHUNK_SIZE_Y * CHUNK_SIZE_Z];
//protected short[] customBlocksId = new short[CHUNK_SIZE_X * CHUNK_SIZE_Y * CHUNK_SIZE_Z];
// Used to get all blocks with data (no null)
// Key is still chunk coord
protected Int2ObjectMap<Data> blocksData = new Int2ObjectOpenHashMap<>(16 * 16); // Start with the size of a single row
@ -59,7 +56,7 @@ public abstract class Chunk implements Viewable {
// (block index)/(last update in ms)
protected Int2LongMap updatableBlocksLastUpdate = new Int2LongOpenHashMap();
protected AtomicBoolean packetUpdated = new AtomicBoolean(false);
protected volatile boolean packetUpdated;
// Block entities
protected Set<Integer> blockEntities = new CopyOnWriteArraySet<>();
@ -114,8 +111,10 @@ public abstract class Chunk implements Viewable {
public abstract CustomBlock getCustomBlock(int x, int y, int z);
protected CustomBlock getCustomBlock(int index) {
final int[] pos = ChunkUtils.indexToChunkPosition(index);
return getCustomBlock(pos[0], pos[1], pos[2]);
final int x = ChunkUtils.blockIndexToChunkPositionX(index);
final int y = ChunkUtils.blockIndexToChunkPositionY(index);
final int z = ChunkUtils.blockIndexToChunkPositionZ(index);
return getCustomBlock(x, y, z);
}
protected abstract void refreshBlockValue(int x, int y, int z, short blockStateId, short customId);
@ -142,7 +141,7 @@ public abstract class Chunk implements Viewable {
return;
// Block all chunk operation during the update
IntIterator iterator = new IntOpenHashSet(updatableBlocks).iterator();
final IntIterator iterator = new IntOpenHashSet(updatableBlocks).iterator();
while (iterator.hasNext()) {
final int index = iterator.nextInt();
final CustomBlock customBlock = getCustomBlock(index);
@ -156,12 +155,7 @@ public abstract class Chunk implements Viewable {
this.updatableBlocksLastUpdate.put(index, time); // Refresh last update time
final int[] blockPos = ChunkUtils.indexToPosition(index, chunkX, chunkZ);
final int x = blockPos[0];
final int y = blockPos[1];
final int z = blockPos[2];
final BlockPosition blockPosition = new BlockPosition(x, y, z);
final BlockPosition blockPosition = ChunkUtils.getBlockPosition(index, chunkX, chunkZ);
final Data data = getData(index);
customBlock.update(instance, blockPosition, data);
}
@ -184,7 +178,7 @@ public abstract class Chunk implements Viewable {
* <p>
* Use {@link #retrieveDataBuffer(Consumer)} to be sure to get the updated version
*
* @return the current cached data packet, can be null or outdated
* @return the last cached data packet, can be null or outdated
*/
public ByteBuf getFullDataPacket() {
return fullDataPacket;
@ -192,7 +186,7 @@ public abstract class Chunk implements Viewable {
public void setFullDataPacket(ByteBuf fullDataPacket) {
this.fullDataPacket = fullDataPacket;
this.packetUpdated.set(true);
this.packetUpdated = true;
}
protected boolean isBlockEntity(short blockStateId) {
@ -214,13 +208,13 @@ public abstract class Chunk implements Viewable {
}
/**
* Retrieve the updated data packet
* Retrieve (and save if needed) the updated data packet
*
* @param consumer the consumer called once the packet is sure to be up-to-date
*/
public void retrieveDataBuffer(Consumer<ByteBuf> consumer) {
final ByteBuf data = getFullDataPacket();
if (data == null || !packetUpdated.get()) {
if (data == null || !packetUpdated) {
PacketWriterUtils.writeCallbackPacket(getFreshFullDataPacket(), packet -> {
setFullDataPacket(packet);
consumer.accept(packet);
@ -234,9 +228,8 @@ public abstract class Chunk implements Viewable {
* Serialize the chunk
*
* @return the serialized chunk
* @throws IOException
*/
protected abstract byte[] getSerializedData() throws IOException;
protected abstract byte[] getSerializedData();
/**
* Get a {@link ChunkDataPacket} which should contain the full chunk
@ -279,7 +272,13 @@ public abstract class Chunk implements Viewable {
return "Chunk[" + chunkX + ":" + chunkZ + "]";
}
// UNSAFE
/**
* Send the chunk to {@code player} and add it to the player viewing chunks collection
* and send a {@link PlayerChunkLoadEvent}
*
* @param player the viewer to add
* @return true if the player has just been added to the viewer collection
*/
@Override
public boolean addViewer(Player player) {
final boolean result = this.viewers.add(player);
@ -294,7 +293,13 @@ public abstract class Chunk implements Viewable {
return result;
}
// UNSAFE
/**
* Remove the chunk to the player viewing chunks collection
* and send a {@link PlayerChunkUnloadEvent}
*
* @param player the viewer to remove
* @return true if the player has just been removed to the viewer collection
*/
@Override
public boolean removeViewer(Player player) {
final boolean result = this.viewers.remove(player);
@ -325,9 +330,7 @@ public abstract class Chunk implements Viewable {
final PlayerConnection playerConnection = player.getPlayerConnection();
retrieveDataBuffer(buf -> {
playerConnection.sendPacket(buf, true);
});
retrieveDataBuffer(buf -> playerConnection.sendPacket(buf, true));
// TODO do not hardcode
if (MinecraftServer.isFixLighting()) {
@ -372,15 +375,13 @@ public abstract class Chunk implements Viewable {
public void sendChunkUpdate() {
final Set<Player> chunkViewers = getViewers();
if (!chunkViewers.isEmpty()) {
retrieveDataBuffer(buf -> {
chunkViewers.forEach(player -> {
final PlayerConnection playerConnection = player.getPlayerConnection();
if (!PlayerUtils.isNettyClient(playerConnection))
return;
retrieveDataBuffer(buf -> chunkViewers.forEach(player -> {
final PlayerConnection playerConnection = player.getPlayerConnection();
if (!PlayerUtils.isNettyClient(playerConnection))
return;
playerConnection.sendPacket(buf, true);
});
});
playerConnection.sendPacket(buf, true);
}));
}
}
@ -394,14 +395,22 @@ public abstract class Chunk implements Viewable {
public void sendChunkSectionUpdate(int section, Player player) {
if (!PlayerUtils.isNettyClient(player))
return;
Check.argCondition(!MathUtils.isBetween(section, 0, CHUNK_SECTION_COUNT),
"The chunk section " + section + " does not exist");
PacketWriterUtils.writeAndSend(player, getChunkSectionUpdatePacket(section));
}
/**
* Get the {@link ChunkDataPacket} to update a single chunk section
*
* @param section the chunk section to update
* @return the {@link ChunkDataPacket} to update a single chunk sectionl
*/
protected ChunkDataPacket getChunkSectionUpdatePacket(int section) {
ChunkDataPacket chunkDataPacket = getFreshPartialDataPacket();
chunkDataPacket.fullChunk = false;
int[] sections = new int[16];
int[] sections = new int[CHUNK_SECTION_COUNT];
sections[section] = 1;
chunkDataPacket.sections = sections;
return chunkDataPacket;

View File

@ -5,22 +5,20 @@ import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
import net.minestom.server.data.Data;
import net.minestom.server.data.SerializableData;
import net.minestom.server.entity.pathfinding.PFBlockDescription;
import net.minestom.server.instance.block.Block;
import net.minestom.server.instance.block.CustomBlock;
import net.minestom.server.instance.block.UpdateConsumer;
import net.minestom.server.network.packet.server.play.ChunkDataPacket;
import net.minestom.server.utils.MathUtils;
import net.minestom.server.utils.binary.BinaryWriter;
import net.minestom.server.world.biomes.Biome;
import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.util.concurrent.CopyOnWriteArraySet;
public class DynamicChunk extends Chunk {
public short[] blocksStateId = new short[CHUNK_SIZE_X * CHUNK_SIZE_Y * CHUNK_SIZE_Z];
private short[] customBlocksId = new short[CHUNK_SIZE_X * CHUNK_SIZE_Y * CHUNK_SIZE_Z];
// blocks id based on coordinate, see Chunk#getBlockIndex
private final short[] blocksStateId = new short[CHUNK_SIZE_X * CHUNK_SIZE_Y * CHUNK_SIZE_Z];
private final short[] customBlocksId = new short[CHUNK_SIZE_X * CHUNK_SIZE_Y * CHUNK_SIZE_Z];
public DynamicChunk(Biome[] biomes, int chunkX, int chunkZ) {
super(biomes, chunkX, chunkZ);
@ -40,9 +38,18 @@ public class DynamicChunk extends Chunk {
@Override
protected void setBlock(int x, int y, int z, short blockStateId, short customId, Data data, UpdateConsumer updateConsumer) {
{
// Update pathfinder
if (columnarSpace != null) {
final ColumnarOcclusionFieldList columnarOcclusionFieldList = columnarSpace.occlusionFields();
final PFBlockDescription blockDescription = PFBlockDescription.getBlockDescription(blockStateId);
columnarOcclusionFieldList.onBlockChanged(x, y, z, blockDescription, 0);
}
}
final int index = getBlockIndex(x, y, z);
if (blockStateId != 0
|| (blockStateId == 0 && customId != 0 && updateConsumer != null)) { // Allow custom air block for update purpose, refused if no update consumer has been found
if (blockStateId != 0 || customId != 0 && updateConsumer != null) { // Allow custom air block for update purpose, refused if no update consumer has been found
this.blocksStateId[index] = blockStateId;
this.customBlocksId[index] = customId;
} else {
@ -57,7 +64,7 @@ public class DynamicChunk extends Chunk {
this.blockEntities.remove(index);
this.packetUpdated.set(false);
this.packetUpdated = false;
return;
}
@ -84,13 +91,7 @@ public class DynamicChunk extends Chunk {
this.blockEntities.remove(index);
}
this.packetUpdated.set(false);
if (columnarSpace != null) {
final ColumnarOcclusionFieldList columnarOcclusionFieldList = columnarSpace.occlusionFields();
final PFBlockDescription blockDescription = new PFBlockDescription(Block.fromStateId(blockStateId));
columnarOcclusionFieldList.onBlockChanged(x, y, z, blockDescription, 0);
}
this.packetUpdated = false;
}
@Override
@ -99,8 +100,7 @@ public class DynamicChunk extends Chunk {
if (!MathUtils.isBetween(index, 0, blocksStateId.length)) {
return 0; // TODO: custom invalid block
}
final short id = blocksStateId[index];
return id;
return blocksStateId[index];
}
@Override
@ -109,8 +109,7 @@ public class DynamicChunk extends Chunk {
if (!MathUtils.isBetween(index, 0, blocksStateId.length)) {
return 0; // TODO: custom invalid block
}
final short id = customBlocksId[index];
return id;
return customBlocksId[index];
}
@Override
@ -145,12 +144,13 @@ public class DynamicChunk extends Chunk {
}
@Override
protected byte[] getSerializedData() throws IOException {
ByteArrayOutputStream output = new ByteArrayOutputStream();
DataOutputStream dos = new DataOutputStream(output);
protected byte[] getSerializedData() {
BinaryWriter binaryWriter = new BinaryWriter();
// Write the biomes id
for (int i = 0; i < BIOME_COUNT; i++) {
dos.writeByte(biomes[i].getId());
final byte id = (byte) biomes[i].getId();
binaryWriter.writeByte(id);
}
for (byte x = 0; x < CHUNK_SIZE_X; x++) {
@ -161,34 +161,32 @@ public class DynamicChunk extends Chunk {
final short blockStateId = blocksStateId[index];
final short customBlockId = customBlocksId[index];
// No block at the position
if (blockStateId == 0 && customBlockId == 0)
continue;
final Data data = blocksData.get(index);
// Chunk coordinates
dos.writeInt(x);
dos.writeInt(y);
dos.writeInt(z);
binaryWriter.writeByte(x);
binaryWriter.writeShort(y);
binaryWriter.writeByte(z);
// Id
dos.writeShort(blockStateId);
dos.writeShort(customBlockId);
// Block ids
binaryWriter.writeShort(blockStateId);
binaryWriter.writeShort(customBlockId);
// Data
final boolean hasData = (data != null && (data instanceof SerializableData));
dos.writeBoolean(hasData);
final Data data = blocksData.get(index);
final boolean hasData = data instanceof SerializableData;
binaryWriter.writeBoolean(hasData);
if (hasData) {
final byte[] d = ((SerializableData) data).getSerializedData();
dos.writeInt(d.length);
dos.write(d);
final byte[] serializedData = ((SerializableData) data).getSerializedData();
binaryWriter.writeBytes(serializedData);
}
}
}
}
final byte[] result = output.toByteArray();
return result;
return binaryWriter.toByteArray();
}
@Override

View File

@ -48,9 +48,9 @@ public abstract class Instance implements BlockModifier, EventHandler, DataConta
private boolean registered;
private DimensionType dimensionType;
private final DimensionType dimensionType;
private WorldBorder worldBorder;
private final WorldBorder worldBorder;
// Tick since the creation of the instance
private long worldAge;
@ -61,24 +61,24 @@ public abstract class Instance implements BlockModifier, EventHandler, DataConta
private UpdateOption timeUpdate = new UpdateOption(1, TimeUnit.TICK);
private long lastTimeUpdate;
private Map<Class<? extends Event>, List<EventCallback>> eventCallbacks = new ConcurrentHashMap<>();
private final Map<Class<? extends Event>, List<EventCallback>> eventCallbacks = new ConcurrentHashMap<>();
// Entities present in this instance
protected Set<Player> players = new CopyOnWriteArraySet<>();
protected Set<EntityCreature> creatures = new CopyOnWriteArraySet<>();
protected Set<ObjectEntity> objectEntities = new CopyOnWriteArraySet<>();
protected Set<ExperienceOrb> experienceOrbs = new CopyOnWriteArraySet<>();
protected final Set<Player> players = new CopyOnWriteArraySet<>();
protected final Set<EntityCreature> creatures = new CopyOnWriteArraySet<>();
protected final Set<ObjectEntity> objectEntities = new CopyOnWriteArraySet<>();
protected final Set<ExperienceOrb> experienceOrbs = new CopyOnWriteArraySet<>();
// Entities per chunk
protected Map<Long, Set<Entity>> chunkEntities = new ConcurrentHashMap<>();
protected final Map<Long, Set<Entity>> chunkEntities = new ConcurrentHashMap<>();
protected UUID uniqueId;
protected List<Consumer<Instance>> nextTick = Collections.synchronizedList(new ArrayList<>());
protected final List<Consumer<Instance>> nextTick = Collections.synchronizedList(new ArrayList<>());
private Data data;
private ExplosionSupplier explosionSupplier;
// Pathfinder
private PFInstanceSpace instanceSpace = new PFInstanceSpace(this);
private final PFInstanceSpace instanceSpace = new PFInstanceSpace(this);
public Instance(UUID uniqueId, DimensionType dimensionType) {
this.uniqueId = uniqueId;
@ -754,13 +754,13 @@ public abstract class Instance implements BlockModifier, EventHandler, DataConta
*/
public void removeEntity(Entity entity) {
final Instance entityInstance = entity.getInstance();
if (entityInstance == null || entityInstance != this)
if (entityInstance != this)
return;
RemoveEntityFromInstanceEvent event = new RemoveEntityFromInstanceEvent(this, entity);
callCancellableEvent(RemoveEntityFromInstanceEvent.class, event, () -> {
// Remove this entity from players viewable list and send delete entities packet
entity.getViewers().forEach(p -> entity.removeViewer(p));
entity.getViewers().forEach(entity::removeViewer);
// Remove the entity from cache
final Chunk chunk = getChunkAt(entity.getPosition());
@ -832,8 +832,7 @@ public abstract class Instance implements BlockModifier, EventHandler, DataConta
}
private Set<Entity> getEntitiesInChunk(long index) {
final Set<Entity> entities = chunkEntities.computeIfAbsent(index, i -> new CopyOnWriteArraySet<>());
return entities;
return chunkEntities.computeIfAbsent(index, i -> new CopyOnWriteArraySet<>());
}
/**
@ -864,7 +863,7 @@ public abstract class Instance implements BlockModifier, EventHandler, DataConta
// time
this.worldAge++;
this.time += 1 * timeRate;
this.time += timeRate;
if (timeUpdate != null && !CooldownUtils.hasCooldown(time, lastTimeUpdate, timeUpdate)) {
PacketWriterUtils.writeAndSend(getPlayers(), getTimePacket());

View File

@ -54,8 +54,8 @@ public class InstanceContainer extends Instance {
private ChunkGenerator chunkGenerator;
// WARNING: need to be synchronized properly
private Long2ObjectMap<Chunk> chunks = new Long2ObjectOpenHashMap();
private Set<Chunk> scheduledChunksToRemove = new HashSet<>();
private final Long2ObjectMap<Chunk> chunks = new Long2ObjectOpenHashMap<>();
private final Set<Chunk> scheduledChunksToRemove = new HashSet<>();
private ReadWriteLock changingBlockLock = new ReentrantReadWriteLock();
private Map<BlockPosition, Block> currentlyChangingBlocks = new HashMap<>();
@ -116,8 +116,17 @@ public class InstanceContainer extends Instance {
setAlreadyChanged(blockPosition, blockStateId);
final int index = ChunkUtils.getBlockIndex(x, y, z);
// Call the destroy listener if previous block was a custom block
callBlockDestroy(chunk, index, blockPosition);
final CustomBlock previousBlock = chunk.getCustomBlock(index);
if (previousBlock != null) {
// Previous block was a custom block
// Call the destroy listener
callBlockDestroy(chunk, index, previousBlock, blockPosition);
// Remove digging information for the previous custom block
previousBlock.removeDiggingInformation(this, blockPosition);
}
// Change id based on neighbors
blockStateId = executeBlockPlacementRule(blockStateId, blockPosition);
@ -170,13 +179,10 @@ public class InstanceContainer extends Instance {
}
}
private void callBlockDestroy(Chunk chunk, int index, BlockPosition blockPosition) {
final CustomBlock previousBlock = chunk.getCustomBlock(index);
if (previousBlock != null) {
final Data previousData = chunk.getData(index);
previousBlock.onDestroy(this, blockPosition, previousData);
chunk.UNSAFE_removeCustomBlock(blockPosition.getX(), blockPosition.getY(), blockPosition.getZ());
}
private void callBlockDestroy(Chunk chunk, int index, CustomBlock previousBlock, BlockPosition blockPosition) {
final Data previousData = chunk.getData(index);
previousBlock.onDestroy(this, blockPosition, previousData);
chunk.UNSAFE_removeCustomBlock(blockPosition.getX(), blockPosition.getY(), blockPosition.getZ());
}
private void callBlockPlace(Chunk chunk, int index, BlockPosition blockPosition) {
@ -351,8 +357,9 @@ public class InstanceContainer extends Instance {
Check.notNull(getStorageFolder(), "You cannot save the instance if no StorageFolder has been defined");
this.storageFolder.set(UUID_KEY, getUniqueId(), UUID.class);
Data data = getData();
final Data data = getData();
if (data != null) {
// Save the instance data
Check.stateCondition(!(data instanceof SerializableData),
"Instance#getData needs to be a SerializableData in order to be saved");
this.storageFolder.set(DATA_KEY, (SerializableData) getData(), SerializableData.class);

View File

@ -5,13 +5,12 @@ import net.minestom.server.storage.StorageFolder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.util.function.Consumer;
public class MinestomBasicChunkLoader implements IChunkLoader {
private final static Logger LOGGER = LoggerFactory.getLogger(MinestomBasicChunkLoader.class);
private StorageFolder storageFolder;
private final StorageFolder storageFolder;
public MinestomBasicChunkLoader(StorageFolder storageFolder) {
this.storageFolder = storageFolder;
@ -24,21 +23,22 @@ public class MinestomBasicChunkLoader implements IChunkLoader {
LOGGER.warn("No folder to save chunk!");
return;
}
final int chunkX = chunk.getChunkX();
final int chunkZ = chunk.getChunkZ();
try {
final String key = getChunkKey(chunkX, chunkZ);
final byte[] data = chunk.getSerializedData();
if (data == null)
return;
storageFolder.set(key, data);
final String key = getChunkKey(chunkX, chunkZ);
final byte[] data = chunk.getSerializedData();
if (data == null) {
if (callback != null)
callback.run();
} catch (IOException e) {
e.printStackTrace();
return;
}
storageFolder.set(key, data);
if (callback != null)
callback.run();
}
@Override

View File

@ -19,7 +19,7 @@ import java.util.function.Consumer;
*/
public class SharedInstance extends Instance {
private InstanceContainer instanceContainer;
private final InstanceContainer instanceContainer;
public SharedInstance(UUID uniqueId, InstanceContainer instanceContainer) {
super(uniqueId, instanceContainer.getDimensionType());

View File

@ -70,8 +70,10 @@ public class StaticChunk extends Chunk {
fullDataPacket.chunkZ = chunkZ;
short[] blocksStateId = new short[CHUNK_SIZE_X * CHUNK_SIZE_Y * CHUNK_SIZE_Z];
for (int i = 0; i < blocksStateId.length; i++) {
final int[] pos = ChunkUtils.indexToPosition(i, 0, 0);
blocksStateId[i] = blockProvider.getBlockStateId(pos[0], pos[1], pos[2]);
final int x = ChunkUtils.blockIndexToChunkPositionX(i);
final int y = ChunkUtils.blockIndexToChunkPositionY(i);
final int z = ChunkUtils.blockIndexToChunkPositionZ(i);
blocksStateId[i] = blockProvider.getBlockStateId(x, y, z);
}
fullDataPacket.blocksStateId = blocksStateId;
fullDataPacket.customBlocksId = new short[0];

View File

@ -11,7 +11,7 @@ import net.minestom.server.utils.Position;
*/
public class WorldBorder {
private Instance instance;
private final Instance instance;
private float centerX, centerZ;

View File

@ -87,7 +87,7 @@ public class BlockBatch implements InstanceBatch {
}
}
private class BlockData {
private static class BlockData {
private int x, y, z;
private boolean hasCustomBlock;

View File

@ -18,8 +18,8 @@ import java.util.function.Consumer;
*/
public class ChunkBatch implements InstanceBatch {
private InstanceContainer instance;
private Chunk chunk;
private final InstanceContainer instance;
private final Chunk chunk;
// Give it the max capacity by default (avoid resizing)
private List<BlockData> dataList =
@ -109,7 +109,7 @@ public class ChunkBatch implements InstanceBatch {
}
}
private class BlockData {
private static class BlockData {
private int x, y, z;
private boolean hasCustomBlock;

View File

@ -1,16 +1,28 @@
package net.minestom.server.instance.block;
import it.unimi.dsi.fastutil.objects.Object2ByteMap;
import it.unimi.dsi.fastutil.objects.Object2ByteOpenHashMap;
import it.unimi.dsi.fastutil.objects.Object2IntMap;
import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap;
import net.minestom.server.data.Data;
import net.minestom.server.entity.Entity;
import net.minestom.server.entity.Player;
import net.minestom.server.gamedata.loottables.LootTable;
import net.minestom.server.gamedata.loottables.LootTableManager;
import net.minestom.server.instance.BlockModifier;
import net.minestom.server.instance.Chunk;
import net.minestom.server.instance.Instance;
import net.minestom.server.network.packet.server.play.BlockBreakAnimationPacket;
import net.minestom.server.utils.BlockPosition;
import net.minestom.server.utils.time.UpdateOption;
import net.minestom.server.utils.validate.Check;
import org.jglrxavpok.hephaistos.nbt.NBTCompound;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
/**
* Represent the handler of a custom block type.
* <p>
@ -20,10 +32,17 @@ import org.jglrxavpok.hephaistos.nbt.NBTCompound;
*/
public abstract class CustomBlock {
public static final byte MAX_STAGE = 10;
/**
* TODO
* - option to set the global as "global breaking" meaning that multiple players mining the same block will break it faster (accumulation)
* Instance -> break data
* Used to store block break stage data when {@link #enableMultiPlayerBreaking()} is enabled
*/
private final Map<Instance, InstanceBreakData> instanceBreakDataMap = new HashMap<>();
public int getBreakEntityId(Player firstBreaker) {
return firstBreaker.getEntityId() + 1;
}
private final short blockStateId;
private final String identifier;
@ -106,17 +125,45 @@ public abstract class CustomBlock {
public abstract short getCustomBlockId();
/**
* Called at digging start to check for custom breaking time
* Can be set to < 0 to be cancelled, in this case vanilla time will be used
* Called when the player requests the next stage break delay
*
* @param player the player who is trying to break the block
* @param position the block position
* @return the time in ms to break it
* @param stage the current break stage of the block (0-10)
* @param breakers the list containing all the players currently digging this block
* @return the time in tick to pass to the next state, 0 to instant break it.
* @see #enableCustomBreakDelay() to enable/disable it
*/
public abstract int getBreakDelay(Player player, BlockPosition position);
public int getBreakDelay(Player player, BlockPosition position, byte stage, Set<Player> breakers) {
return 0;
}
/**
* @return true if {@link #getUpdateOption()} is not null, false otherwise
* Used to enable the custom break delay from {@link #getBreakDelay(Player, BlockPosition, byte, Set)}
* Disabling it would result in having vanilla time
*
* @return true to enable custom break delay
*/
public boolean enableCustomBreakDelay() {
return false;
}
/**
* Get if this block breaking time can be reduced by having multiple players
* digging it
* <p>
* WARNING: this should be constant, do not change this value halfway
*
* @return true to enable the multi-player breaking feature
*/
public boolean enableMultiPlayerBreaking() {
return false;
}
/**
* Get if this {@link CustomBlock} requires any tick update
*
* @return true if {@link #getUpdateOption()} is not null and the value is positive
*/
public boolean hasUpdate() {
final UpdateOption updateOption = getUpdateOption();
@ -239,4 +286,189 @@ public abstract class CustomBlock {
public LootTable getLootTable(LootTableManager tableManager) {
return null;
}
// BLOCK BREAK METHODS
/**
* Called when a player start digging this custom block,
* process all necessary data if {@link #enableMultiPlayerBreaking()} is enabled
*
* @param instance the instance of the block
* @param blockPosition the position of the block
* @param player the player who started digging
*/
public void startDigging(Instance instance, BlockPosition blockPosition, Player player) {
// Stay null if multi player breaking is disabled
Set<Player> breakers = null;
if (enableMultiPlayerBreaking()) {
// Multi player breaking enabled, get the breakers and cache some values
InstanceBreakData instanceBreakData = instanceBreakDataMap.computeIfAbsent(instance, i -> new InstanceBreakData());
Map<BlockPosition, Set<Player>> breakersMap = instanceBreakData.breakersMap;
breakers = breakersMap.computeIfAbsent(blockPosition, pos -> new HashSet<>(1));
breakers.add(player);
Object2ByteMap<BlockPosition> breakStageMap = instanceBreakData.breakStageMap;
// Set the block stage to 0, use the previous one if any
if (!breakStageMap.containsKey(blockPosition)) {
breakStageMap.put(blockPosition, (byte) 0);
}
Object2IntMap<BlockPosition> breakIdMap = instanceBreakData.breakIdMap;
// Set the entity id used for the packet, otherwise use the previous one
if (!breakIdMap.containsKey(blockPosition)) {
breakIdMap.put(blockPosition, getBreakEntityId(player));
}
}
// Set the player target block
player.setTargetBlock(this, blockPosition, breakers);
}
/**
* Called when a player stop digging a block,
* does remove the block break animation if he was the only breaker
*
* @param instance the instance of the block
* @param blockPosition the position of the block
* @param player the player who stopped digging
*/
public void stopDigging(Instance instance, BlockPosition blockPosition, Player player) {
if (enableMultiPlayerBreaking()) {
// Remove cache data
if (instanceBreakDataMap.containsKey(instance)) {
InstanceBreakData instanceBreakData = instanceBreakDataMap.get(instance);
Set<Player> breakers = instanceBreakData.breakersMap.get(blockPosition);
if (breakers != null) {
breakers.remove(player);
if (breakers.isEmpty()) {
// No remaining breakers
// Get the entity id assigned to the block break
final int entityId = instanceBreakData.breakIdMap.getInt(blockPosition);
final Chunk chunk = instance.getChunkAt(blockPosition);
chunk.sendPacketToViewers(new BlockBreakAnimationPacket(entityId, blockPosition, (byte) -1));
// Clear cache
removeDiggingInformation(instance, blockPosition);
}
}
}
} else {
// Stop the breaking animation for the specific player id
final Chunk chunk = instance.getChunkAt(blockPosition);
final int entityId = getBreakEntityId(player);
chunk.sendPacketToViewers(new BlockBreakAnimationPacket(entityId, blockPosition, (byte) -1));
}
}
/**
* Process one stage on the block, break it if it excess {@link #MAX_STAGE},
* only if {@link #enableMultiPlayerBreaking()} is enabled
*
* @param instance the instance of the block
* @param blockPosition the position of the block
* @param player the player who processed one stage on the block
* @return true if the block can continue being digged
* @throws IllegalStateException if {@link #enableMultiPlayerBreaking()} is disabled
*/
public synchronized boolean processStage(Instance instance, BlockPosition blockPosition, Player player) {
Check.stateCondition(!enableMultiPlayerBreaking(),
"CustomBlock#processState requires having the multi player breaking feature enabled");
if (instanceBreakDataMap.containsKey(instance)) {
InstanceBreakData instanceBreakData = instanceBreakDataMap.get(instance);
Object2ByteMap<BlockPosition> breakStageMap = instanceBreakData.breakStageMap;
byte stage = breakStageMap.getByte(blockPosition);
if (stage + 1 >= MAX_STAGE) {
instance.breakBlock(player, blockPosition);
return false;
} else {
// Get the entity id assigned to the block break
final int entityId = instanceBreakData.breakIdMap.getInt(blockPosition);
// Send the block break animation
final Chunk chunk = instance.getChunkAt(blockPosition);
chunk.sendPacketToViewers(new BlockBreakAnimationPacket(entityId, blockPosition, stage));
// Refresh the stage
breakStageMap.put(blockPosition, ++stage);
return true;
}
}
return false;
}
public void removeDiggingInformation(Instance instance, BlockPosition blockPosition) {
if (!enableMultiPlayerBreaking()) {
return;
}
if (instanceBreakDataMap.containsKey(instance)) {
InstanceBreakData instanceBreakData = instanceBreakDataMap.get(instance);
// Remove the block position from all maps
instanceBreakData.clear(blockPosition);
}
}
/**
* Get all the breakers of a block, only if {@link #enableMultiPlayerBreaking()} is enabled
*
* @param instance the instance of the block
* @param blockPosition the position of the block
* @return the {@link Set} of breakers of a block
* @throws IllegalStateException if {@link #enableMultiPlayerBreaking()} is disabled
*/
public Set<Player> getBreakers(Instance instance, BlockPosition blockPosition) {
Check.stateCondition(!enableMultiPlayerBreaking(),
"CustomBlock#getBreakers requires having the multi player breaking feature enabled");
if (instanceBreakDataMap.containsKey(instance)) {
InstanceBreakData instanceBreakData = instanceBreakDataMap.get(instance);
return instanceBreakData.breakersMap.get(blockPosition);
}
return null;
}
/**
* Get the block break stage at a position, only work if {@link #enableMultiPlayerBreaking()} is enabled
*
* @param instance the instance of the custom block
* @param blockPosition the position of the custom block
* @return the break stage at the position. Can also be 0 when nonexistent
*/
public byte getBreakStage(Instance instance, BlockPosition blockPosition) {
Check.stateCondition(!enableMultiPlayerBreaking(),
"CustomBlock#getBreakStage requires having the multi player breaking feature enabled");
if (!instanceBreakDataMap.containsKey(instance))
return 0;
final InstanceBreakData instanceBreakData = instanceBreakDataMap.get(instance);
return instanceBreakData.breakStageMap.getByte(blockPosition);
}
/**
* Class used to store block break stage
* Only used if multi player breaking is enabled
*/
private class InstanceBreakData {
// Contains all the breakers of a block
private final Map<BlockPosition, Set<Player>> breakersMap = new HashMap<>();
// Contains the current break stage of a block
private final Object2ByteMap<BlockPosition> breakStageMap = new Object2ByteOpenHashMap<>();
// Contains the entity id used by the block break packet
private final Object2IntMap<BlockPosition> breakIdMap = new Object2IntOpenHashMap<>();
private void clear(BlockPosition blockPosition) {
this.breakersMap.remove(blockPosition);
this.breakStageMap.removeByte(blockPosition);
this.breakIdMap.removeInt(blockPosition);
}
}
}

View File

@ -27,25 +27,26 @@ import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.CopyOnWriteArraySet;
import java.util.concurrent.atomic.AtomicInteger;
public class Inventory implements InventoryModifier, InventoryClickHandler, Viewable {
private static volatile byte lastInventoryId;
private static AtomicInteger lastInventoryId = new AtomicInteger();
private byte id;
private final byte id;
private final InventoryType inventoryType;
private String title;
private int size;
private final int size;
private int offset;
private final int offset;
private ItemStack[] itemStacks;
private Set<Player> viewers = new CopyOnWriteArraySet<>();
private ConcurrentHashMap<Player, ItemStack> cursorPlayersItem = new ConcurrentHashMap<>();
private final ItemStack[] itemStacks;
private final Set<Player> viewers = new CopyOnWriteArraySet<>();
private final ConcurrentHashMap<Player, ItemStack> cursorPlayersItem = new ConcurrentHashMap<>();
private List<InventoryCondition> inventoryConditions = new CopyOnWriteArrayList<>();
private InventoryClickProcessor clickProcessor = new InventoryClickProcessor();
private final List<InventoryCondition> inventoryConditions = new CopyOnWriteArrayList<>();
private final InventoryClickProcessor clickProcessor = new InventoryClickProcessor();
// Cached windows packet
@ -64,8 +65,8 @@ public class Inventory implements InventoryModifier, InventoryClickHandler, View
}
private static byte generateId() {
byte newInventoryId = ++lastInventoryId;
if (newInventoryId < 0)
byte newInventoryId = (byte) lastInventoryId.incrementAndGet();
if (newInventoryId == Byte.MAX_VALUE)
newInventoryId = 1;
return newInventoryId;
}

View File

@ -33,7 +33,7 @@ public enum InventoryProperty {
BREWING_STAND_FUEL_TIME((short) 1);
private short property;
private final short property;
InventoryProperty(short property) {
this.property = property;

Some files were not shown because too many files have changed in this diff Show More