Merge remote-tracking branch 'origin/master' into block-types

This commit is contained in:
jglrxavpok 2020-06-21 22:07:38 +02:00
commit fcc0f5e035
173 changed files with 4762 additions and 940 deletions

View File

@ -35,17 +35,15 @@ dependencies {
testCompile group: 'junit', name: 'junit', version: '4.12' testCompile group: 'junit', name: 'junit', version: '4.12'
// https://mvnrepository.com/artifact/io.netty/netty-all // https://mvnrepository.com/artifact/io.netty/netty-all
api group: 'io.netty', name: 'netty-all', version: '4.1.48.Final' api group: 'io.netty', name: 'netty-all', version: '4.1.50.Final'
api 'com.github.jhg023:Pbbl:1.0.1' api 'com.github.jhg023:Pbbl:1.0.2'
// https://mvnrepository.com/artifact/it.unimi.dsi/fastutil // https://mvnrepository.com/artifact/it.unimi.dsi/fastutil
api group: 'it.unimi.dsi', name: 'fastutil', version: '8.3.0' api group: 'it.unimi.dsi', name: 'fastutil', version: '8.3.0'
api 'com.github.Querz:NBT:4.1'
// https://mvnrepository.com/artifact/com.google.code.gson/gson // https://mvnrepository.com/artifact/com.google.code.gson/gson
api group: 'com.google.code.gson', name: 'gson', version: '2.8.5' api group: 'com.google.code.gson', name: 'gson', version: '2.8.6'
api 'com.github.TheMode:CommandBuilder:f893cfbfe4' api 'com.github.TheMode:CommandBuilder:f893cfbfe4'
@ -66,4 +64,8 @@ dependencies {
api 'net.kyori:text-serializer-legacy:3.0.3' api 'net.kyori:text-serializer-legacy:3.0.3'
api 'net.kyori:text-serializer-gson:3.0.3' api 'net.kyori:text-serializer-gson:3.0.3'
api 'net.kyori:text-serializer-plain:3.0.3' api 'net.kyori:text-serializer-plain:3.0.3'
// Pathfinding
implementation 'com.github.MadMartian:hydrazine-path-finding:1.02'
} }

View File

@ -0,0 +1,71 @@
package fr.themode.demo;
import net.minestom.server.MinecraftServer;
import net.minestom.server.event.player.PlayerLoginEvent;
import net.minestom.server.event.player.PlayerSpawnEvent;
import net.minestom.server.instance.*;
import net.minestom.server.instance.batch.ChunkBatch;
import net.minestom.server.instance.block.Block;
import net.minestom.server.network.ConnectionManager;
import net.minestom.server.utils.Position;
import java.util.Arrays;
import java.util.List;
public class MainDemo {
public static void main(String[] args) {
// Initialization
MinecraftServer minecraftServer = MinecraftServer.init();
InstanceManager instanceManager = MinecraftServer.getInstanceManager();
// Create the instance
InstanceContainer instanceContainer = instanceManager.createInstanceContainer();
// Set the ChunkGenerator
instanceContainer.setChunkGenerator(new GeneratorDemo());
// Enable the auto chunk loading (when players come close)
instanceContainer.enableAutoChunkLoad(true);
// Add event listeners
ConnectionManager connectionManager = MinecraftServer.getConnectionManager();
connectionManager.addPlayerInitialization(player -> {
// Set the spawning instance
player.addEventCallback(PlayerLoginEvent.class, event -> {
event.setSpawningInstance(instanceContainer);
});
// Teleport the player at spawn
player.addEventCallback(PlayerSpawnEvent.class, event -> {
player.teleport(new Position(0, 45, 0));
});
});
// Start the server
minecraftServer.start("localhost", 55555);
}
private static class GeneratorDemo extends ChunkGenerator {
@Override
public void generateChunkData(ChunkBatch batch, int chunkX, int chunkZ) {
// Set chunk blocks
for (byte x = 0; x < Chunk.CHUNK_SIZE_X; x++)
for (byte z = 0; z < Chunk.CHUNK_SIZE_Z; z++) {
for (byte y = 0; y < 40; y++) {
batch.setBlock(x, y, z, Block.STONE);
}
}
}
@Override
public void fillBiomes(Biome[] biomes, int chunkX, int chunkZ) {
Arrays.fill(biomes, Biome.PLAINS);
}
@Override
public List<ChunkPopulator> getPopulators() {
return null;
}
}
}

View File

@ -4,6 +4,7 @@ import fr.themode.demo.entity.ChickenCreature;
import fr.themode.demo.generator.ChunkGeneratorDemo; import fr.themode.demo.generator.ChunkGeneratorDemo;
import fr.themode.demo.generator.NoiseTestGenerator; import fr.themode.demo.generator.NoiseTestGenerator;
import net.minestom.server.MinecraftServer; import net.minestom.server.MinecraftServer;
import net.minestom.server.attribute.Attribute;
import net.minestom.server.benchmark.BenchmarkManager; import net.minestom.server.benchmark.BenchmarkManager;
import net.minestom.server.benchmark.ThreadResult; import net.minestom.server.benchmark.ThreadResult;
import net.minestom.server.entity.*; import net.minestom.server.entity.*;
@ -39,6 +40,11 @@ import java.util.UUID;
public class PlayerInit { public class PlayerInit {
private static String textures = "ewogICJ0aW1lc3RhbXAiIDogMTU5MDg1NTI3NjIwNCwKICAicHJvZmlsZUlkIiA6ICI0NTY2ZTY5ZmM5MDc0OGVlOGQ3MWQ3YmE1YWEwMGQyMCIsCiAgInByb2ZpbGVOYW1lIiA6ICJUaGlua29mZGVhdGgiLAogICJzaWduYXR1cmVSZXF1aXJlZCIgOiB0cnVlLAogICJ0ZXh0dXJlcyIgOiB7CiAgICAiU0tJTiIgOiB7CiAgICAgICJ1cmwiIDogImh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNzRkMWUwOGIwYmI3ZTlmNTkwYWYyNzc1ODEyNWJiZWQxNzc4YWM2Y2VmNzI5YWVkZmNiOTYxM2U5OTExYWU3NSIKICAgIH0sCiAgICAiQ0FQRSIgOiB7CiAgICAgICJ1cmwiIDogImh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYjBjYzA4ODQwNzAwNDQ3MzIyZDk1M2EwMmI5NjVmMWQ2NWExM2E2MDNiZjY0YjE3YzgwM2MyMTQ0NmZlMTYzNSIKICAgIH0KICB9Cn0=";
private static String signature = "rCVVwVpLF9ovy+Hm4cOXOLSPOMjNo5WoBfHo9K2OcTUPqcZJ1P/1k4lAnQkChD/Ri11iJ84PejWJzDkHMXM8196Wh+jf12d2GJVhca9/SRLms0cFJjdZZjs72+82AdX0OtO3+qzwKRHzHoEYb+ZVZLfgx37ZKKo4DD3IKmaSnwEjOVJ4BOhnsXLmcNW37kdZUmv2/hlg7ZuWZaayWPhadCYEMnkpVtDIpnpzAeV9EcRfg/ysQoynO2v6WEW0RtnfFEczMN6vXtfiuC8UqyA2SK9aiLnBgpGaehDfFIq/0dpo2uFilVDS/Il6uQ1JSwq7yNT5lNF+i1AlH9SGf1VVy5mT9ShmkVmRxCXX5cSNLXZD0acsNNJb/GAuDHuXpE32GsfgKxWAXMHLw0GnbADbFDfdl5nQyQTDS7FRfUjsFpF8a8Z83muFXaty2WLFy1zxy2JEkI/q+ltLaEG6mQbWI2zhOS7ARvK0OmPz4lDYVInfrwL93AIdMUg2Re817hsapkN6Dm1ND+iirvayR90gqQ9C9J0dMMBlSyTSoKBQeLsi8qETS+7LuhvletPTDFolnTIvP8hj2bWLmQ7LfXJ2arJCUw86YEavVYuF0gYrBuKcEYTC4DA0kO4yLj63gwEgOj9dEigCgyqUcenzmZBffSZ365/QF0cGrG7HC7HmF0w=";
private static PlayerSkin skin = new PlayerSkin(textures, signature);
private static volatile InstanceContainer instanceContainer; private static volatile InstanceContainer instanceContainer;
private static volatile InstanceContainer netherTest; private static volatile InstanceContainer netherTest;
@ -95,16 +101,15 @@ public class PlayerInit {
benchmarkMessage += "&e" + MathUtils.round(result.getCpuPercentage(), 2) + "% CPU "; benchmarkMessage += "&e" + MathUtils.round(result.getCpuPercentage(), 2) + "% CPU ";
benchmarkMessage += "&c" + MathUtils.round(result.getUserPercentage(), 2) + "% USER "; benchmarkMessage += "&c" + MathUtils.round(result.getUserPercentage(), 2) + "% USER ";
benchmarkMessage += "&d" + MathUtils.round(result.getBlockedPercentage(), 2) + "% BLOCKED "; benchmarkMessage += "&d" + MathUtils.round(result.getBlockedPercentage(), 2) + "% BLOCKED ";
benchmarkMessage += "&a" + MathUtils.round(result.getWaitedPercentage(), 2) + "% WAITED ";
benchmarkMessage += "\n"; benchmarkMessage += "\n";
} }
// if (benchmarkMessage.length() > 0)
// System.out.println(benchmarkMessage);
for (Player player : connectionManager.getOnlinePlayers()) { for (Player player : connectionManager.getOnlinePlayers()) {
player.sendHeaderFooter("RAM USAGE: " + ramUsage + " MB", benchmarkMessage, '&'); player.sendHeaderFooter("RAM USAGE: " + ramUsage + " MB", benchmarkMessage, '&');
} }
} }
}, new UpdateOption(5, TimeUnit.TICK)); }, new UpdateOption(10, TimeUnit.TICK));
connectionManager.addPacketConsumer((player, packetController, packet) -> { connectionManager.addPacketConsumer((player, packetController, packet) -> {
// Listen to all received packet // Listen to all received packet
@ -137,10 +142,10 @@ public class PlayerInit {
return; return;
if (event.getBlockId() == Block.STONE.getBlockId()) { if (event.getBlockId() == Block.STONE.getBlockId()) {
event.setCustomBlockId((short) 2); // custom stone block event.setCustomBlock((short) 2); // custom stone block
} }
if (event.getBlockId() == Block.TORCH.getBlockId()) { if (event.getBlockId() == Block.TORCH.getBlockId()) {
event.setCustomBlockId((short) 3); // custom torch block event.setCustomBlock((short) 3); // custom torch block
} }
/*for (Player p : player.getInstance().getPlayers()) { /*for (Player p : player.getInstance().getPlayers()) {
@ -150,6 +155,7 @@ public class PlayerInit {
ChickenCreature chickenCreature = new ChickenCreature(player.getPosition()); ChickenCreature chickenCreature = new ChickenCreature(player.getPosition());
chickenCreature.setInstance(player.getInstance()); chickenCreature.setInstance(player.getInstance());
chickenCreature.setAttribute(Attribute.MOVEMENT_SPEED, 0.4f);
/*FakePlayer fakePlayer = new FakePlayer(UUID.randomUUID(), "test"); /*FakePlayer fakePlayer = new FakePlayer(UUID.randomUUID(), "test");
fakePlayer.addEventCallback(EntityDeathEvent.class, e -> { fakePlayer.addEventCallback(EntityDeathEvent.class, e -> {
@ -211,19 +217,24 @@ public class PlayerInit {
scoreboard.setTitle("test");*/ scoreboard.setTitle("test");*/
}); });
player.addEventCallback(PlayerSkinInitEvent.class, event -> {
event.setSkin(skin);
});
player.addEventCallback(PlayerSpawnEvent.class, event -> { player.addEventCallback(PlayerSpawnEvent.class, event -> {
player.setGameMode(GameMode.CREATIVE); player.setGameMode(GameMode.CREATIVE);
player.teleport(new Position(0, 45, 0)); player.teleport(new Position(0, 41f, 0));
player.setGlowing(true); player.setGlowing(true);
ItemStack item = new ItemStack(Material.STONE_SWORD, (byte) 1); ItemStack item = new ItemStack(Material.STONE_SWORD, (byte) 1);
item.setDisplayName("Item name"); item.setDisplayName("Item name");
item.getLore().add("a lore line"); item.getLore().add("a lore line");
item.addItemFlags(ItemFlag.HIDE_ATTRIBUTES); item.addItemFlags(ItemFlag.HIDE_ENCHANTS);
item.setEnchantment(Enchantment.SHARPNESS, (short) 2); item.setEnchantment(Enchantment.SHARPNESS, (short) 50);
player.getInventory().addItemStack(item); player.getInventory().addItemStack(item);
inventory.addItemStack(item.clone());
player.openInventory(inventory); player.openInventory(inventory);
player.getInventory().addItemStack(new ItemStack(Material.STONE, (byte) 100)); player.getInventory().addItemStack(new ItemStack(Material.STONE, (byte) 100));
@ -256,7 +267,7 @@ public class PlayerInit {
}); });
player.addEventCallback(PlayerRespawnEvent.class, event -> { player.addEventCallback(PlayerRespawnEvent.class, event -> {
event.setRespawnPosition(new Position(0f, 45f, 0f)); event.setRespawnPosition(new Position(0f, 41f, 0f));
}); });
player.addEventCallback(PlayerUseItemEvent.class, useEvent -> { player.addEventCallback(PlayerUseItemEvent.class, useEvent -> {
@ -301,7 +312,7 @@ public class PlayerInit {
public static ResponseDataConsumer getResponseDataConsumer() { public static ResponseDataConsumer getResponseDataConsumer() {
return (playerConnection, responseData) -> { return (playerConnection, responseData) -> {
responseData.setMaxPlayer(100); responseData.setMaxPlayer(0);
responseData.setOnline(MinecraftServer.getConnectionManager().getOnlinePlayers().size()); responseData.setOnline(MinecraftServer.getConnectionManager().getOnlinePlayers().size());
responseData.addPlayer("A name", UUID.randomUUID()); responseData.addPlayer("A name", UUID.randomUUID());
responseData.addPlayer("Could be some message", UUID.randomUUID()); responseData.addPlayer("Could be some message", UUID.randomUUID());

View File

@ -2,6 +2,7 @@ package fr.themode.demo.commands;
import net.minestom.server.MinecraftServer; import net.minestom.server.MinecraftServer;
import net.minestom.server.command.CommandProcessor; import net.minestom.server.command.CommandProcessor;
import net.minestom.server.command.CommandSender;
import net.minestom.server.entity.Player; import net.minestom.server.entity.Player;
import net.minestom.server.instance.Instance; import net.minestom.server.instance.Instance;
import net.minestom.server.world.Dimension; import net.minestom.server.world.Dimension;
@ -20,22 +21,27 @@ public class DimensionCommand implements CommandProcessor {
} }
@Override @Override
public boolean process(Player player, String command, String[] args) { public boolean process(CommandSender sender, String command, String[] args) {
if (!(sender instanceof Player))
return false;
Player player = (Player) sender;
Instance instance = player.getInstance(); Instance instance = player.getInstance();
Dimension targetDimension = Dimension.NETHER; Dimension targetDimension = Dimension.NETHER;
if(instance.getDimension() == Dimension.NETHER) { if (instance.getDimension() == Dimension.NETHER) {
targetDimension = Dimension.OVERWORLD; targetDimension = Dimension.OVERWORLD;
} }
Dimension finalTargetDimension = targetDimension; Dimension finalTargetDimension = targetDimension;
Optional<Instance> targetInstance = MinecraftServer.getInstanceManager().getInstances().stream().filter(in -> in.getDimension() == finalTargetDimension).findFirst(); Optional<Instance> targetInstance = MinecraftServer.getInstanceManager().getInstances().stream().filter(in -> in.getDimension() == finalTargetDimension).findFirst();
if(targetInstance.isPresent()) { if (targetInstance.isPresent()) {
player.sendMessage("You were in "+instance.getDimension()); player.sendMessage("You were in " + instance.getDimension());
player.setInstance(targetInstance.get()); player.setInstance(targetInstance.get());
player.sendMessage("You are now in "+targetDimension); player.sendMessage("You are now in " + targetDimension);
} else { } else {
player.sendMessage("Could not find instance with dimension "+targetDimension); player.sendMessage("Could not find instance with dimension " + targetDimension);
} }
return true; return true;

View File

@ -4,6 +4,7 @@ import fr.themode.command.Arguments;
import fr.themode.command.Command; import fr.themode.command.Command;
import fr.themode.command.arguments.Argument; import fr.themode.command.arguments.Argument;
import fr.themode.command.arguments.ArgumentType; import fr.themode.command.arguments.ArgumentType;
import net.minestom.server.command.CommandSender;
import net.minestom.server.entity.GameMode; import net.minestom.server.entity.GameMode;
import net.minestom.server.entity.Player; import net.minestom.server.entity.Player;
@ -12,7 +13,7 @@ import java.util.Optional;
/** /**
* Command that make a player change gamemode * Command that make a player change gamemode
*/ */
public class GamemodeCommand extends Command<Player> { public class GamemodeCommand extends Command<CommandSender> {
public GamemodeCommand() { public GamemodeCommand() {
super("gamemode", "g", "gm"); super("gamemode", "g", "gm");
@ -35,11 +36,13 @@ public class GamemodeCommand extends Command<Player> {
addSyntax(this::executeOnOther, player, mode); addSyntax(this::executeOnOther, player, mode);
} }
private void usage(Player player, Arguments arguments) { private void usage(CommandSender sender, Arguments arguments) {
player.sendMessage("Usage: /gamemode [player] <gamemode>"); sender.sendMessage("Usage: /gamemode [player] <gamemode>");
} }
private void executeOnSelf(Player player, Arguments arguments) { private void executeOnSelf(CommandSender sender, Arguments arguments) {
Player player = (Player) sender;
String gamemodeName = arguments.getWord("mode"); String gamemodeName = arguments.getWord("mode");
GameMode mode = GameMode.valueOf(gamemodeName.toUpperCase()); GameMode mode = GameMode.valueOf(gamemodeName.toUpperCase());
assert mode != null; // mode is not supposed to be null, because gamemodeName will be valid assert mode != null; // mode is not supposed to be null, because gamemodeName will be valid
@ -47,7 +50,9 @@ public class GamemodeCommand extends Command<Player> {
player.sendMessage("You are now playing in " + gamemodeName); player.sendMessage("You are now playing in " + gamemodeName);
} }
private void executeOnOther(Player player, Arguments arguments) { private void executeOnOther(CommandSender sender, Arguments arguments) {
Player player = (Player) sender;
String gamemodeName = arguments.getWord("mode"); String gamemodeName = arguments.getWord("mode");
String targetName = arguments.getWord("player"); String targetName = arguments.getWord("player");
GameMode mode = GameMode.valueOf(gamemodeName.toUpperCase()); GameMode mode = GameMode.valueOf(gamemodeName.toUpperCase());
@ -61,11 +66,15 @@ public class GamemodeCommand extends Command<Player> {
} }
} }
private void gameModeCallback(Player player, String gamemode, int error) { private void gameModeCallback(CommandSender sender, String gamemode, int error) {
player.sendMessage("'" + gamemode + "' is not a valid gamemode!"); sender.sendMessage("'" + gamemode + "' is not a valid gamemode!");
} }
private boolean isAllowed(Player player) { private boolean isAllowed(CommandSender sender) {
return true; // TODO: permissions if (!(sender instanceof Player)) {
sender.sendMessage("The command is only available for player");
return false;
}
return true;
} }
} }

View File

@ -5,9 +5,10 @@ import fr.themode.command.Command;
import fr.themode.command.arguments.Argument; import fr.themode.command.arguments.Argument;
import fr.themode.command.arguments.ArgumentType; import fr.themode.command.arguments.ArgumentType;
import fr.themode.command.arguments.number.ArgumentNumber; import fr.themode.command.arguments.number.ArgumentNumber;
import net.minestom.server.command.CommandSender;
import net.minestom.server.entity.Player; import net.minestom.server.entity.Player;
public class HealthCommand extends Command<Player> { public class HealthCommand extends Command<CommandSender> {
public HealthCommand() { public HealthCommand() {
super("health", "h", "healthbar"); super("health", "h", "healthbar");
@ -27,39 +28,39 @@ public class HealthCommand extends Command<Player> {
addSyntax(this::execute2, arg0, arg1); addSyntax(this::execute2, arg0, arg1);
} }
private boolean condition(Player player) { private boolean condition(CommandSender sender) {
boolean hasPerm = true; if (!(sender instanceof Player)) {
if (!hasPerm) { sender.sendMessage("The command is only available for player");
player.sendMessage("You do not have permission !");
return false; return false;
} }
return true; return true;
} }
private void defaultExecutor(Player player, Arguments args) { private void defaultExecutor(CommandSender sender, Arguments args) {
player.sendMessage("Correct usage: health [set/add] [number]"); sender.sendMessage("Correct usage: health [set/add] [number]");
} }
private void modeCallback(Player player, String value, int error) { private void modeCallback(CommandSender sender, String value, int error) {
player.sendMessage("SYNTAX ERROR: '" + value + "' should be replaced by 'set' or 'add'"); sender.sendMessage("SYNTAX ERROR: '" + value + "' should be replaced by 'set' or 'add'");
} }
private void valueCallback(Player player, String value, int error) { private void valueCallback(CommandSender sender, String value, int error) {
switch (error) { switch (error) {
case ArgumentNumber.NOT_NUMBER_ERROR: case ArgumentNumber.NOT_NUMBER_ERROR:
player.sendMessage("SYNTAX ERROR: '" + value + "' isn't a number!"); sender.sendMessage("SYNTAX ERROR: '" + value + "' isn't a number!");
break; break;
case ArgumentNumber.RANGE_ERROR: case ArgumentNumber.RANGE_ERROR:
player.sendMessage("SYNTAX ERROR: " + value + " is not between 0 and 100"); sender.sendMessage("SYNTAX ERROR: " + value + " is not between 0 and 100");
break; break;
} }
} }
private void execute(Player player, Arguments args) { private void execute(CommandSender sender, Arguments args) {
player.sendMessage("/health " + args.getWord("mode") + " [Integer]"); sender.sendMessage("/health " + args.getWord("mode") + " [Integer]");
} }
private void execute2(Player player, Arguments args) { private void execute2(CommandSender sender, Arguments args) {
Player player = (Player) sender;
String mode = args.getWord("mode"); String mode = args.getWord("mode");
int value = args.getInteger("value"); int value = args.getInteger("value");

View File

@ -1,7 +1,15 @@
package fr.themode.demo.commands; package fr.themode.demo.commands;
import com.extollit.gaming.ai.path.HydrazinePathFinder;
import com.extollit.gaming.ai.path.model.PathObject;
import com.extollit.linalg.immutable.Vec3i;
import fr.themode.demo.entity.ChickenCreature;
import net.minestom.server.command.CommandProcessor; import net.minestom.server.command.CommandProcessor;
import net.minestom.server.command.CommandSender;
import net.minestom.server.entity.Player; import net.minestom.server.entity.Player;
import net.minestom.server.instance.Instance;
import java.util.Iterator;
public class SimpleCommand implements CommandProcessor { public class SimpleCommand implements CommandProcessor {
@Override @Override
@ -15,7 +23,11 @@ public class SimpleCommand implements CommandProcessor {
} }
@Override @Override
public boolean process(Player player, String command, String[] args) { public boolean process(CommandSender sender, String command, String[] args) {
if (!(sender instanceof Player))
return false;
Player player = (Player) sender;
/*for (Player p : MinecraftServer.getConnectionManager().getOnlinePlayers()) { /*for (Player p : MinecraftServer.getConnectionManager().getOnlinePlayers()) {
if (!(p instanceof FakePlayer)) if (!(p instanceof FakePlayer))
@ -35,9 +47,33 @@ public class SimpleCommand implements CommandProcessor {
break; break;
}*/ }*/
System.gc(); /*for (EntityCreature entityCreature : player.getInstance().getCreatures()) {
player.sendMessage("Garbage collector called"); entityCreature.setPathTo(player.getPosition().clone());
//entityCreature.jump(1);
}
System.gc();
player.sendMessage("Garbage collector called");*/
Instance instance = player.getInstance();
ChickenCreature chickenCreature = new ChickenCreature(player.getPosition());
chickenCreature.setInstance(instance);
/*
PFPathingEntity pathingEntity = new PFPathingEntity(chickenCreature);
PFInstanceSpace instanceSpace = new PFInstanceSpace(instance);
final HydrazinePathFinder pathFinder = new HydrazinePathFinder(pathingEntity, instanceSpace);
final PathObject path = pathFinder.initiatePathTo(-10, 42, -10);
for (Iterator<Vec3i> it = path.iterator(); it.hasNext(); ) {
Vec3i ite = it.next();
System.out.println("test: " + ite);
}
*/
return true; return true;
} }

View File

@ -1,19 +1,16 @@
package fr.themode.demo.entity; package fr.themode.demo.entity;
import net.minestom.server.entity.Entity; import net.minestom.server.entity.Entity;
import net.minestom.server.entity.EntityCreature;
import net.minestom.server.entity.EntityType;
import net.minestom.server.entity.Player; import net.minestom.server.entity.Player;
import net.minestom.server.entity.type.EntityChicken;
import net.minestom.server.entity.vehicle.PlayerVehicleInformation; import net.minestom.server.entity.vehicle.PlayerVehicleInformation;
import net.minestom.server.utils.Position; import net.minestom.server.utils.Position;
import net.minestom.server.utils.Vector; import net.minestom.server.utils.Vector;
public class ChickenCreature extends EntityCreature { public class ChickenCreature extends EntityChicken {
public ChickenCreature(Position defaultPosition) { public ChickenCreature(Position defaultPosition) {
super(EntityType.CHICKEN, defaultPosition); super(defaultPosition);
setBoundingBox(0.4f, 0.7f, 0.4f);
} }
@Override @Override
@ -22,8 +19,8 @@ public class ChickenCreature extends EntityCreature {
} }
@Override @Override
public void update() { public void update(long time) {
super.update(); super.update(time);
float speed = 0.075f; float speed = 0.075f;
if (hasPassenger()) { if (hasPassenger()) {
@ -80,10 +77,7 @@ public class ChickenCreature extends EntityCreature {
move(x, 0, z, updateView); move(x, 0, z, updateView);
} }
} else { } else {
//move(0.5f * speed, 0, 0.5f * speed, true); //move(-0.5f * speed, 0, 0.5f * speed, true);
} }
//Player player = MinecraftServer.getConnectionManager().getPlayer("TheMode911");
//moveTo(player.getPosition().clone());
} }
} }

View File

@ -14,16 +14,6 @@ public class TestArrow extends ObjectEntity {
this.shooter = shooter; this.shooter = shooter;
} }
@Override
public void update() {
}
@Override
public void spawn() {
}
@Override @Override
public int getObjectData() { public int getObjectData() {
return shooter.getEntityId() + 1; return shooter.getEntityId() + 1;

View File

@ -9,22 +9,15 @@ import net.minestom.server.instance.block.Block;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.Random;
public class ChunkGeneratorDemo extends ChunkGenerator { public class ChunkGeneratorDemo extends ChunkGenerator {
private final Random random = new Random();
@Override @Override
public void generateChunkData(ChunkBatch batch, int chunkX, int chunkZ) { public void generateChunkData(ChunkBatch batch, int chunkX, int chunkZ) {
for (byte x = 0; x < Chunk.CHUNK_SIZE_X; x++) for (byte x = 0; x < Chunk.CHUNK_SIZE_X; x++)
for (byte z = 0; z < Chunk.CHUNK_SIZE_Z; z++) { for (byte z = 0; z < Chunk.CHUNK_SIZE_Z; z++) {
for (byte y = 0; y < 65; y++) { for (byte y = 0; y < 40; y++) {
if (random.nextInt(100) > 10) { batch.setBlock(x, y, z, Block.STONE);
batch.setCustomBlock(x, y, z, "custom_block");
} else {
batch.setBlock(x, y, z, Block.DIAMOND_BLOCK);
}
} }
} }
} }

View File

@ -36,7 +36,6 @@ public class MinecraftServer {
public static final String THREAD_NAME_BENCHMARK = "Ms-Benchmark"; public static final String THREAD_NAME_BENCHMARK = "Ms-Benchmark";
public static final String THREAD_NAME_MAIN_UPDATE = "Ms-MainUpdate"; public static final String THREAD_NAME_MAIN_UPDATE = "Ms-MainUpdate";
public static final int THREAD_COUNT_MAIN_UPDATE = 1; // Keep it to 1
public static final String THREAD_NAME_PACKET_WRITER = "Ms-PacketWriterPool"; public static final String THREAD_NAME_PACKET_WRITER = "Ms-PacketWriterPool";
public static final int THREAD_COUNT_PACKET_WRITER = 2; public static final int THREAD_COUNT_PACKET_WRITER = 2;

View File

@ -1,5 +1,7 @@
package net.minestom.server; package net.minestom.server;
import net.kyori.text.TextComponent;
import net.kyori.text.format.TextColor;
import net.minestom.server.entity.EntityManager; import net.minestom.server.entity.EntityManager;
import net.minestom.server.entity.Player; import net.minestom.server.entity.Player;
import net.minestom.server.instance.InstanceManager; import net.minestom.server.instance.InstanceManager;
@ -10,19 +12,27 @@ import net.minestom.server.utils.thread.MinestomThread;
import java.util.concurrent.ExecutorService; import java.util.concurrent.ExecutorService;
public class UpdateManager { public final class UpdateManager {
private ExecutorService mainUpdate = new MinestomThread(MinecraftServer.THREAD_COUNT_MAIN_UPDATE, MinecraftServer.THREAD_NAME_MAIN_UPDATE); private static final long KEEP_ALIVE_DELAY = 10_000;
private static final long KEEP_ALIVE_KICK = 30_000;
private ExecutorService mainUpdate = new MinestomThread(1, MinecraftServer.THREAD_NAME_MAIN_UPDATE);
private boolean stopRequested; private boolean stopRequested;
/**
* Should only be created in MinecraftServer
*/
protected UpdateManager() {
}
public void start() { public void start() {
mainUpdate.execute(() -> { mainUpdate.execute(() -> {
ConnectionManager connectionManager = MinecraftServer.getConnectionManager(); final ConnectionManager connectionManager = MinecraftServer.getConnectionManager();
EntityManager entityManager = MinecraftServer.getEntityManager(); final EntityManager entityManager = MinecraftServer.getEntityManager();
InstanceManager instanceManager = MinecraftServer.getInstanceManager(); final InstanceManager instanceManager = MinecraftServer.getInstanceManager();
SchedulerManager schedulerManager = MinecraftServer.getSchedulerManager(); final SchedulerManager schedulerManager = MinecraftServer.getSchedulerManager();
final long tickDistance = MinecraftServer.TICK_MS * 1000000; final long tickDistance = MinecraftServer.TICK_MS * 1000000;
long currentTime; long currentTime;
@ -30,12 +40,17 @@ public class UpdateManager {
currentTime = System.nanoTime(); currentTime = System.nanoTime();
// Keep Alive Handling // Keep Alive Handling
final long time = System.currentTimeMillis();
final KeepAlivePacket keepAlivePacket = new KeepAlivePacket(time);
for (Player player : connectionManager.getOnlinePlayers()) { for (Player player : connectionManager.getOnlinePlayers()) {
long time = System.currentTimeMillis(); final long lastKeepAlive = time - player.getLastKeepAlive();
if (time - player.getLastKeepAlive() > 10000) { if (lastKeepAlive > KEEP_ALIVE_DELAY && player.didAnswerKeepAlive()) {
player.refreshKeepAlive(time); player.refreshKeepAlive(time);
KeepAlivePacket keepAlivePacket = new KeepAlivePacket(time);
player.getPlayerConnection().sendPacket(keepAlivePacket); player.getPlayerConnection().sendPacket(keepAlivePacket);
} else if (lastKeepAlive >= KEEP_ALIVE_KICK) {
TextComponent textComponent = TextComponent.of("Timeout")
.color(TextColor.RED);
player.kick(textComponent);
} }
} }

View File

@ -1,4 +1,4 @@
package net.minestom.server.entity.property; package net.minestom.server.attribute;
public enum Attribute { public enum Attribute {
@ -37,4 +37,12 @@ public enum Attribute {
public float getMaxVanillaValue() { public float getMaxVanillaValue() {
return maxVanillaValue; return maxVanillaValue;
} }
public static Attribute fromKey(String key) {
for (Attribute attribute : values()) {
if (attribute.getKey().equals(key))
return attribute;
}
return null;
}
} }

View File

@ -0,0 +1,26 @@
package net.minestom.server.attribute;
public enum AttributeOperation {
ADDITION(0),
MULTIPLY_BASE(1),
MULTIPLY_TOTAL(2);
private static final AttributeOperation[] VALUES = new AttributeOperation[]{ADDITION, MULTIPLY_BASE, MULTIPLY_TOTAL};
private final int id;
AttributeOperation(int id) {
this.id = id;
}
public static AttributeOperation byId(int id) {
if (id >= 0 && id < VALUES.length) {
return VALUES[id];
} else {
throw new IllegalArgumentException("No operation with value " + id);
}
}
public int getId() {
return this.id;
}
}

View File

@ -26,6 +26,7 @@ public class BenchmarkManager {
private Map<Long, Long> lastCpuTimeMap = new HashMap<>(); private Map<Long, Long> lastCpuTimeMap = new HashMap<>();
private Map<Long, Long> lastUserTimeMap = new HashMap<>(); private Map<Long, Long> lastUserTimeMap = new HashMap<>();
private Map<Long, Long> lastWaitedMap = new HashMap<>();
private Map<Long, Long> lastBlockedMap = new HashMap<>(); private Map<Long, Long> lastBlockedMap = new HashMap<>();
private Map<String, ThreadResult> resultMap = new ConcurrentHashMap<>(); private Map<String, ThreadResult> resultMap = new ConcurrentHashMap<>();
@ -100,26 +101,30 @@ public class BenchmarkManager {
long lastCpuTime = lastCpuTimeMap.getOrDefault(id, 0L); long lastCpuTime = lastCpuTimeMap.getOrDefault(id, 0L);
long lastUserTime = lastUserTimeMap.getOrDefault(id, 0L); long lastUserTime = lastUserTimeMap.getOrDefault(id, 0L);
long lastWaitedTime = lastWaitedMap.getOrDefault(id, 0L);
long lastBlockedTime = lastBlockedMap.getOrDefault(id, 0L); long lastBlockedTime = lastBlockedMap.getOrDefault(id, 0L);
long blockedTime = threadInfo2.getBlockedTime(); long blockedTime = threadInfo2.getBlockedTime();
//long waitedTime = threadInfo2.getWaitedTime(); long waitedTime = threadInfo2.getWaitedTime();
long cpuTime = threadMXBean.getThreadCpuTime(id); long cpuTime = threadMXBean.getThreadCpuTime(id);
long userTime = threadMXBean.getThreadUserTime(id); long userTime = threadMXBean.getThreadUserTime(id);
lastCpuTimeMap.put(id, cpuTime); lastCpuTimeMap.put(id, cpuTime);
lastUserTimeMap.put(id, userTime); lastUserTimeMap.put(id, userTime);
lastWaitedMap.put(id, waitedTime);
lastBlockedMap.put(id, blockedTime); lastBlockedMap.put(id, blockedTime);
double totalCpuTime = (double) (cpuTime - lastCpuTime) / 1000000D; double totalCpuTime = (double) (cpuTime - lastCpuTime) / 1000000D;
double totalUserTime = (double) (userTime - lastUserTime) / 1000000D; double totalUserTime = (double) (userTime - lastUserTime) / 1000000D;
long totalBlocked = blockedTime - lastBlockedTime; long totalBlocked = blockedTime - lastBlockedTime;
long totalWaited = waitedTime - lastWaitedTime;
double cpuPercentage = totalCpuTime / (double) time * 100L; double cpuPercentage = totalCpuTime / (double) time * 100L;
double userPercentage = totalUserTime / (double) time * 100L; double userPercentage = totalUserTime / (double) time * 100L;
double waitedPercentage = totalWaited / (double) time * 100L;
double blockedPercentage = totalBlocked / (double) time * 100L; double blockedPercentage = totalBlocked / (double) time * 100L;
ThreadResult threadResult = new ThreadResult(cpuPercentage, userPercentage, blockedPercentage); ThreadResult threadResult = new ThreadResult(cpuPercentage, userPercentage, waitedPercentage, blockedPercentage);
resultMap.put(name, threadResult); resultMap.put(name, threadResult);
} }
} }

View File

@ -2,11 +2,12 @@ package net.minestom.server.benchmark;
public class ThreadResult { public class ThreadResult {
private double cpuPercentage, userPercentage, blockedPercentage; private double cpuPercentage, userPercentage, waitedPercentage, blockedPercentage;
protected ThreadResult(double cpuPercentage, double userPercentage, double blockedPercentage) { protected ThreadResult(double cpuPercentage, double userPercentage, double waitedPercentage, double blockedPercentage) {
this.cpuPercentage = cpuPercentage; this.cpuPercentage = cpuPercentage;
this.userPercentage = userPercentage; this.userPercentage = userPercentage;
this.waitedPercentage = waitedPercentage;
this.blockedPercentage = blockedPercentage; this.blockedPercentage = blockedPercentage;
} }
@ -18,6 +19,10 @@ public class ThreadResult {
return userPercentage; return userPercentage;
} }
public double getWaitedPercentage() {
return waitedPercentage;
}
public double getBlockedPercentage() { public double getBlockedPercentage() {
return blockedPercentage; return blockedPercentage;
} }

View File

@ -4,12 +4,17 @@ import net.minestom.server.Viewable;
import net.minestom.server.chat.Chat; import net.minestom.server.chat.Chat;
import net.minestom.server.entity.Player; import net.minestom.server.entity.Player;
import net.minestom.server.network.packet.server.play.BossBarPacket; import net.minestom.server.network.packet.server.play.BossBarPacket;
import net.minestom.server.utils.MathUtils;
import net.minestom.server.utils.validate.Check;
import java.util.Collections; import java.util.Collections;
import java.util.Set; import java.util.Set;
import java.util.UUID; import java.util.UUID;
import java.util.concurrent.CopyOnWriteArraySet; import java.util.concurrent.CopyOnWriteArraySet;
/**
* Represent a bossbar which can be showed to any player {@link #addViewer(Player)}
*/
public class BossBar implements Viewable { public class BossBar implements Viewable {
private UUID uuid = UUID.randomUUID(); private UUID uuid = UUID.randomUUID();
@ -48,41 +53,87 @@ public class BossBar implements Viewable {
return Collections.unmodifiableSet(viewers); return Collections.unmodifiableSet(viewers);
} }
/**
* Get the bossbar title
*
* @return the current title of the bossbar
*/
public String getTitle() { public String getTitle() {
return title; return title;
} }
/**
* Change the bossbar title
*
* @param title the new title of the bossbar
*/
public void setTitle(String title) { public void setTitle(String title) {
this.title = title; this.title = title;
} }
/**
* Get the bossbar progress
*
* @return the current progress of the bossbar
*/
public float getProgress() { public float getProgress() {
return progress; return progress;
} }
/**
* Change the bossbar progress
*
* @param progress the new progress bar percentage
* @throws IllegalArgumentException if {@code progress} is not between 0 and 1
*/
public void setProgress(float progress) { public void setProgress(float progress) {
Check.argCondition(!MathUtils.isBetween(progress, 0, 1),
"BossBar progress percentage should be between 0 and 1");
this.progress = progress; this.progress = progress;
updateProgress(); updateProgress();
} }
/**
* Get the bossbar color
*
* @return the current bossbar color
*/
public BarColor getColor() { public BarColor getColor() {
return color; return color;
} }
/**
* Change the bossbar color
*
* @param color the new color of the bossbar
*/
public void setColor(BarColor color) { public void setColor(BarColor color) {
this.color = color; this.color = color;
updateStyle(); updateStyle();
} }
/**
* Get the bossbar division
*
* @return the current bossbar division
*/
public BarDivision getDivision() { public BarDivision getDivision() {
return division; return division;
} }
/**
* Change the bossbar division
*
* @param division the new bossbar division count
*/
public void setDivision(BarDivision division) { public void setDivision(BarDivision division) {
this.division = division; this.division = division;
updateStyle(); updateStyle();
} }
/**
* Delete the boss bar and remove all of its viewers
*/
public void delete() { public void delete() {
BossBarPacket bossBarPacket = new BossBarPacket(); BossBarPacket bossBarPacket = new BossBarPacket();
bossBarPacket.uuid = uuid; bossBarPacket.uuid = uuid;

View File

@ -21,12 +21,24 @@ public class BoundingBox {
this.z = z; this.z = z;
} }
/**
* Used to know if two BoundingBox intersect with each other
*
* @param boundingBox the bounding box to check
* @return true if the two BoundingBox intersect with each other, false otherwise
*/
public boolean intersect(BoundingBox boundingBox) { public boolean intersect(BoundingBox boundingBox) {
return (getMinX() <= boundingBox.getMaxX() && getMaxX() >= boundingBox.getMinX()) && return (getMinX() <= boundingBox.getMaxX() && getMaxX() >= boundingBox.getMinX()) &&
(getMinY() <= boundingBox.getMaxY() && getMaxY() >= boundingBox.getMinY()) && (getMinY() <= boundingBox.getMaxY() && getMaxY() >= boundingBox.getMinY()) &&
(getMinZ() <= boundingBox.getMaxZ() && getMaxZ() >= boundingBox.getMinZ()); (getMinZ() <= boundingBox.getMaxZ() && getMaxZ() >= boundingBox.getMinZ());
} }
/**
* Used to know if the bounding box intersects with a block (can be air)
*
* @param blockPosition the position to check
* @return true if the bounding box intersects with the position, false otherwise
*/
public boolean intersect(BlockPosition blockPosition) { public boolean intersect(BlockPosition blockPosition) {
final float x = blockPosition.getX(); final float x = blockPosition.getX();
@ -62,10 +74,22 @@ public class BoundingBox {
return intersect(position.getX(), position.getY(), position.getZ()); return intersect(position.getX(), position.getY(), position.getZ());
} }
/**
* @param x the X offset
* @param y the Y offset
* @param z the Z offset
* @return a new bounding box expanded
*/
public BoundingBox expand(float x, float y, float z) { public BoundingBox expand(float x, float y, float z) {
return new BoundingBox(entity, this.x + x, this.y + y, this.z + z); return new BoundingBox(entity, this.x + x, this.y + y, this.z + z);
} }
/**
* @param x the X offset
* @param y the Y offset
* @param z the Z offset
* @return a new bounding box contracted
*/
public BoundingBox contract(float x, float y, float z) { public BoundingBox contract(float x, float y, float z) {
return new BoundingBox(entity, this.x - x, this.y - y, this.z - z); return new BoundingBox(entity, this.x - x, this.y - y, this.z - z);
} }
@ -107,7 +131,7 @@ public class BoundingBox {
} }
public Vector[] getBottomFace() { public Vector[] getBottomFace() {
return new Vector[] { return new Vector[]{
new Vector(getMinX(), getMinY(), getMinZ()), new Vector(getMinX(), getMinY(), getMinZ()),
new Vector(getMaxX(), getMinY(), getMinZ()), new Vector(getMaxX(), getMinY(), getMinZ()),
new Vector(getMaxX(), getMinY(), getMaxZ()), new Vector(getMaxX(), getMinY(), getMaxZ()),
@ -116,7 +140,7 @@ public class BoundingBox {
} }
public Vector[] getTopFace() { public Vector[] getTopFace() {
return new Vector[] { return new Vector[]{
new Vector(getMinX(), getMaxY(), getMinZ()), new Vector(getMinX(), getMaxY(), getMinZ()),
new Vector(getMaxX(), getMaxY(), getMinZ()), new Vector(getMaxX(), getMaxY(), getMinZ()),
new Vector(getMaxX(), getMaxY(), getMaxZ()), new Vector(getMaxX(), getMaxY(), getMaxZ()),
@ -125,7 +149,7 @@ public class BoundingBox {
} }
public Vector[] getLeftFace() { public Vector[] getLeftFace() {
return new Vector[] { return new Vector[]{
new Vector(getMinX(), getMinY(), getMinZ()), new Vector(getMinX(), getMinY(), getMinZ()),
new Vector(getMinX(), getMaxY(), getMinZ()), new Vector(getMinX(), getMaxY(), getMinZ()),
new Vector(getMinX(), getMaxY(), getMaxZ()), new Vector(getMinX(), getMaxY(), getMaxZ()),
@ -134,7 +158,7 @@ public class BoundingBox {
} }
public Vector[] getRightFace() { public Vector[] getRightFace() {
return new Vector[] { return new Vector[]{
new Vector(getMaxX(), getMinY(), getMinZ()), new Vector(getMaxX(), getMinY(), getMinZ()),
new Vector(getMaxX(), getMaxY(), getMinZ()), new Vector(getMaxX(), getMaxY(), getMinZ()),
new Vector(getMaxX(), getMaxY(), getMaxZ()), new Vector(getMaxX(), getMaxY(), getMaxZ()),
@ -143,7 +167,7 @@ public class BoundingBox {
} }
public Vector[] getFrontFace() { public Vector[] getFrontFace() {
return new Vector[] { return new Vector[]{
new Vector(getMinX(), getMinY(), getMinZ()), new Vector(getMinX(), getMinY(), getMinZ()),
new Vector(getMaxX(), getMinY(), getMinZ()), new Vector(getMaxX(), getMinY(), getMinZ()),
new Vector(getMaxX(), getMaxY(), getMinZ()), new Vector(getMaxX(), getMaxY(), getMinZ()),
@ -152,7 +176,7 @@ public class BoundingBox {
} }
public Vector[] getBackFace() { public Vector[] getBackFace() {
return new Vector[] { return new Vector[]{
new Vector(getMinX(), getMinY(), getMaxZ()), new Vector(getMinX(), getMinY(), getMaxZ()),
new Vector(getMaxX(), getMinY(), getMaxZ()), new Vector(getMaxX(), getMinY(), getMaxZ()),
new Vector(getMaxX(), getMaxY(), getMaxZ()), new Vector(getMaxX(), getMaxY(), getMaxZ()),

View File

@ -9,19 +9,33 @@ import net.minestom.server.network.packet.server.play.DeclareCommandsPacket;
import net.minestom.server.utils.ArrayUtils; import net.minestom.server.utils.ArrayUtils;
import net.minestom.server.utils.validate.Check; import net.minestom.server.utils.validate.Check;
import java.util.ArrayList; import java.util.*;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class CommandManager { public class CommandManager {
private String commandPrefix = "/"; private String commandPrefix = "/";
private CommandDispatcher<Player> dispatcher = new CommandDispatcher<>(); private ConsoleSender consoleSender = new ConsoleSender();
private CommandDispatcher<CommandSender> dispatcher = new CommandDispatcher<>();
private Map<String, CommandProcessor> commandProcessorMap = new HashMap<>(); private Map<String, CommandProcessor> commandProcessorMap = new HashMap<>();
public void register(Command<Player> command) { public CommandManager() {
// Setup console thread
new Thread(() -> {
Scanner scanner = new Scanner(System.in);
while (true) {
String command = scanner.nextLine();
if (!command.startsWith(commandPrefix))
continue;
command = command.replaceFirst(commandPrefix, "");
execute(consoleSender, command);
}
}, "ConsoleCommand-Thread").start();
}
public void register(Command<CommandSender> command) {
this.dispatcher.register(command); this.dispatcher.register(command);
} }
@ -29,20 +43,24 @@ public class CommandManager {
this.commandProcessorMap.put(commandProcessor.getCommandName().toLowerCase(), commandProcessor); this.commandProcessorMap.put(commandProcessor.getCommandName().toLowerCase(), commandProcessor);
} }
public boolean execute(Player source, String command) { public boolean execute(CommandSender sender, String command) {
Check.notNull(source, "Source cannot be null"); Check.notNull(sender, "Source cannot be null");
Check.notNull(command, "Command string cannot be null"); Check.notNull(command, "Command string cannot be null");
PlayerCommandEvent playerCommandEvent = new PlayerCommandEvent(source, command); if (sender instanceof Player) {
source.callEvent(PlayerCommandEvent.class, playerCommandEvent); Player player = (Player) sender;
if (playerCommandEvent.isCancelled()) PlayerCommandEvent playerCommandEvent = new PlayerCommandEvent(player, command);
return false; player.callEvent(PlayerCommandEvent.class, playerCommandEvent);
command = playerCommandEvent.getCommand(); if (playerCommandEvent.isCancelled())
return false;
command = playerCommandEvent.getCommand();
}
try { try {
this.dispatcher.execute(source, command); this.dispatcher.execute(sender, command);
return true; return true;
} catch (NullPointerException e) { } catch (NullPointerException e) {
String[] splitted = command.split(" "); String[] splitted = command.split(" ");
@ -53,7 +71,7 @@ public class CommandManager {
String[] args = command.substring(command.indexOf(" ") + 1).split(" "); String[] args = command.substring(command.indexOf(" ") + 1).split(" ");
return commandProcessor.process(source, commandName, args); return commandProcessor.process(sender, commandName, args);
} }
} }
@ -66,6 +84,10 @@ public class CommandManager {
this.commandPrefix = commandPrefix; this.commandPrefix = commandPrefix;
} }
public ConsoleSender getConsoleSender() {
return consoleSender;
}
public DeclareCommandsPacket createDeclareCommandsPacket(Player player) { public DeclareCommandsPacket createDeclareCommandsPacket(Player player) {
return buildPacket(player); return buildPacket(player);
} }
@ -74,7 +96,7 @@ public class CommandManager {
DeclareCommandsPacket declareCommandsPacket = new DeclareCommandsPacket(); DeclareCommandsPacket declareCommandsPacket = new DeclareCommandsPacket();
List<String> commands = new ArrayList<>(); List<String> commands = new ArrayList<>();
for (Command<Player> command : dispatcher.getCommands()) { for (Command<CommandSender> command : dispatcher.getCommands()) {
CommandCondition<Player> commandCondition = command.getCondition(); CommandCondition<Player> commandCondition = command.getCondition();
if (commandCondition != null) { if (commandCondition != null) {
// Do not show command if return false // Do not show command if return false

View File

@ -8,7 +8,7 @@ public interface CommandProcessor {
String[] getAliases(); String[] getAliases();
boolean process(Player player, String command, String[] args); boolean process(CommandSender sender, String command, String[] args);
boolean hasAccess(Player player); boolean hasAccess(Player player);
} }

View File

@ -0,0 +1,13 @@
package net.minestom.server.command;
public interface CommandSender {
void sendMessage(String message);
default void sendMessage(String[] messages) {
for (String message : messages) {
sendMessage(message);
}
}
}

View File

@ -0,0 +1,8 @@
package net.minestom.server.command;
public class ConsoleSender implements CommandSender {
@Override
public void sendMessage(String message) {
System.out.println(message);
}
}

View File

@ -8,7 +8,8 @@ public class Data {
public static final Data EMPTY = new Data() { public static final Data EMPTY = new Data() {
@Override @Override
public <T> void set(String key, T value, Class<T> type) {} public <T> void set(String key, T value, Class<T> type) {
}
@Override @Override
public <T> T get(String key) { public <T> T get(String key) {
@ -41,6 +42,8 @@ public class Data {
} }
/** /**
* Get if the data has a key
*
* @param key * @param key
* @return true if the data contains the key, false otherwise * @return true if the data contains the key, false otherwise
*/ */
@ -49,6 +52,8 @@ public class Data {
} }
/** /**
* Get the list of data keys
*
* @return an unmodifiable set containing all keys * @return an unmodifiable set containing all keys
*/ */
public Set<String> getKeys() { public Set<String> getKeys() {
@ -56,12 +61,19 @@ public class Data {
} }
/** /**
* Get if the data is empty or not
*
* @return true if the data does not contain anything, false otherwise * @return true if the data does not contain anything, false otherwise
*/ */
public boolean isEmpty() { public boolean isEmpty() {
return data.isEmpty(); return data.isEmpty();
} }
/**
* Clone this data
*
* @return a cloned data object
*/
public Data clone() { public Data clone() {
Data data = new Data(); Data data = new Data();
data.data = new ConcurrentHashMap<>(this.data); data.data = new ConcurrentHashMap<>(this.data);

View File

@ -6,11 +6,13 @@ import net.minestom.server.data.type.array.*;
import net.minestom.server.inventory.Inventory; import net.minestom.server.inventory.Inventory;
import net.minestom.server.item.ItemStack; import net.minestom.server.item.ItemStack;
import net.minestom.server.utils.PrimitiveConversion; import net.minestom.server.utils.PrimitiveConversion;
import net.minestom.server.utils.validate.Check;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.UUID;
public class DataManager { public final class DataManager {
private Map<Class, DataType> dataTypeMap = new HashMap<>(); private Map<Class, DataType> dataTypeMap = new HashMap<>();
@ -42,6 +44,8 @@ public class DataManager {
registerType(String.class, new StringData()); registerType(String.class, new StringData());
registerType(String[].class, new StringArrayData()); registerType(String[].class, new StringArrayData());
registerType(UUID.class, new UuidType());
registerType(SerializableData.class, new SerializableDataData()); registerType(SerializableData.class, new SerializableDataData());
registerType(ItemStack.class, new ItemStackData()); registerType(ItemStack.class, new ItemStackData());
@ -50,14 +54,27 @@ public class DataManager {
registerType(Inventory.class, new InventoryData()); registerType(Inventory.class, new InventoryData());
} }
/**
* Register a new data type
*
* @param clazz the data class
* @param dataType the data type associated
* @param <T> the data type
*/
public <T> void registerType(Class<T> clazz, DataType<T> dataType) { public <T> void registerType(Class<T> clazz, DataType<T> dataType) {
clazz = PrimitiveConversion.getObjectClass(clazz); clazz = PrimitiveConversion.getObjectClass(clazz);
if (dataTypeMap.containsKey(clazz)) Check.stateCondition(dataTypeMap.containsKey(clazz),
throw new UnsupportedOperationException("Type " + clazz.getName() + " has already been registed"); "Type " + clazz.getName() + " has already been registered");
this.dataTypeMap.put(clazz, dataType); this.dataTypeMap.put(clazz, dataType);
} }
/**
* @param clazz the data class
* @param <T> the data type
* @return the {@link DataType} associated to the class
* @throws NullPointerException if none is found
*/
public <T> DataType<T> getDataType(Class<T> clazz) { public <T> DataType<T> getDataType(Class<T> clazz) {
return dataTypeMap.get(PrimitiveConversion.getObjectClass(clazz)); return dataTypeMap.get(PrimitiveConversion.getObjectClass(clazz));
} }

View File

@ -0,0 +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 java.util.UUID;
public class UuidType extends DataType<UUID> {
@Override
public void encode(PacketWriter packetWriter, UUID value) {
packetWriter.writeUuid(value);
}
@Override
public UUID decode(PacketReader packetReader) {
return packetReader.readUuid();
}
}

View File

@ -14,9 +14,7 @@ import net.minestom.server.event.entity.EntitySpawnEvent;
import net.minestom.server.event.entity.EntityTickEvent; import net.minestom.server.event.entity.EntityTickEvent;
import net.minestom.server.event.entity.EntityVelocityEvent; import net.minestom.server.event.entity.EntityVelocityEvent;
import net.minestom.server.event.handler.EventHandler; import net.minestom.server.event.handler.EventHandler;
import net.minestom.server.instance.Chunk; import net.minestom.server.instance.*;
import net.minestom.server.instance.Instance;
import net.minestom.server.instance.WorldBorder;
import net.minestom.server.instance.block.CustomBlock; import net.minestom.server.instance.block.CustomBlock;
import net.minestom.server.network.packet.PacketWriter; import net.minestom.server.network.packet.PacketWriter;
import net.minestom.server.network.packet.server.play.*; import net.minestom.server.network.packet.server.play.*;
@ -50,12 +48,15 @@ public abstract class Entity implements Viewable, EventHandler, DataContainer {
protected static final byte METADATA_BOOLEAN = 7; protected static final byte METADATA_BOOLEAN = 7;
protected static final byte METADATA_ROTATION = 8; protected static final byte METADATA_ROTATION = 8;
protected static final byte METADATA_POSITION = 9; protected static final byte METADATA_POSITION = 9;
protected static final byte METADATA_PARTICLE = 15;
protected static final byte METADATA_POSE = 18; protected static final byte METADATA_POSE = 18;
protected Instance instance; protected Instance instance;
protected Position position; protected Position position;
protected float lastX, lastY, lastZ; protected float lastX, lastY, lastZ;
protected float cacheX, cacheY, cacheZ; // Used to synchronize with #getPosition
protected float lastYaw, lastPitch; protected float lastYaw, lastPitch;
protected float cacheYaw, cachePitch;
private int id; private int id;
private BoundingBox boundingBox; private BoundingBox boundingBox;
@ -140,8 +141,10 @@ public abstract class Entity implements Viewable, EventHandler, DataContainer {
/** /**
* Called each tick * Called each tick
*
* @param time the time of update in milliseconds
*/ */
public abstract void update(); public abstract void update(long time);
/** /**
* Called when a new instance is set * Called when a new instance is set
@ -205,6 +208,39 @@ public abstract class Entity implements Viewable, EventHandler, DataContainer {
teleport(position, null); teleport(position, null);
} }
/**
* Change the view of the entity
*
* @param yaw the new yaw
* @param pitch the new pitch
*/
public void setView(float yaw, float pitch) {
refreshView(yaw, pitch);
EntityRotationPacket entityRotationPacket = new EntityRotationPacket();
entityRotationPacket.entityId = getEntityId();
entityRotationPacket.yaw = yaw;
entityRotationPacket.pitch = pitch;
entityRotationPacket.onGround = onGround;
EntityHeadLookPacket entityHeadLookPacket = new EntityHeadLookPacket();
entityHeadLookPacket.entityId = getEntityId();
entityHeadLookPacket.yaw = yaw;
sendPacketToViewersAndSelf(entityHeadLookPacket);
sendPacketToViewersAndSelf(entityRotationPacket);
}
/**
* Change the view of the entity
* Only the yaw and pitch is used
*
* @param position the new view
*/
public void setView(Position position) {
setView(position.getYaw(), position.getPitch());
}
/** /**
* When set to true, the entity will automatically get new viewers when they come too close * When set to true, the entity will automatically get new viewers when they come too close
* This can be use to complete control over which player can see it, without having to deal with * This can be use to complete control over which player can see it, without having to deal with
@ -231,6 +267,8 @@ public abstract class Entity implements Viewable, EventHandler, DataContainer {
public boolean addViewer(Player player) { public boolean addViewer(Player player) {
Check.notNull(player, "Viewer cannot be null"); Check.notNull(player, "Viewer cannot be null");
boolean result = this.viewers.add(player); boolean result = this.viewers.add(player);
if (!result)
return false;
player.viewableEntities.add(this); player.viewableEntities.add(this);
return result; return result;
} }
@ -263,6 +301,11 @@ public abstract class Entity implements Viewable, EventHandler, DataContainer {
this.data = data; this.data = data;
} }
/**
* Update the entity, called every tick
*
* @param time update time in milliseconds
*/
public void tick(long time) { public void tick(long time) {
if (instance == null) if (instance == null)
return; return;
@ -286,6 +329,21 @@ public abstract class Entity implements Viewable, EventHandler, DataContainer {
return; return;
} }
// Synchronization with updated fields in #getPosition()
{
// X/Y/Z axis
if (cacheX != position.getX() ||
cacheY != position.getY() ||
cacheZ != position.getZ()) {
teleport(position);
}
// Yaw/Pitch
if (cacheYaw != position.getYaw() ||
cachePitch != position.getPitch()) {
setView(position);
}
}
if (shouldUpdate(time)) { if (shouldUpdate(time)) {
this.lastUpdate = time; this.lastUpdate = time;
@ -393,16 +451,16 @@ public abstract class Entity implements Viewable, EventHandler, DataContainer {
handleVoid(); handleVoid();
// Call the abstract update method // Call the abstract update method
update(); update(time);
ticks++; ticks++;
callEvent(EntityTickEvent.class, tickEvent); // reuse tickEvent to avoid recreating it each tick callEvent(EntityTickEvent.class, tickEvent); // reuse tickEvent to avoid recreating it each tick
}
// Scheduled synchronization // Scheduled synchronization
if (time - lastSynchronizationTime >= synchronizationDelay) { if (time - lastSynchronizationTime >= synchronizationDelay) {
lastSynchronizationTime = time; lastSynchronizationTime = time;
sendSynchronization(); sendSynchronization();
}
} }
if (shouldRemove()) { if (shouldRemove()) {
@ -411,9 +469,9 @@ public abstract class Entity implements Viewable, EventHandler, DataContainer {
} }
/** /**
* Returns the number of ticks this entity has been active for * Get the number of ticks this entity has been active for
* *
* @return * @return the number of ticks this entity has been active for
*/ */
public long getAliveTicks() { public long getAliveTicks() {
return ticks; return ticks;
@ -438,6 +496,15 @@ public abstract class Entity implements Viewable, EventHandler, DataContainer {
this.eventCallbacks.put(eventClass, callbacks); this.eventCallbacks.put(eventClass, callbacks);
} }
@Override
public <E extends Event> void removeEventCallback(Class<E> eventClass, EventCallback<E> eventCallback) {
Check.notNull(eventClass, "Event class cannot be null");
Check.notNull(eventCallback, "Event callback cannot be null");
List<EventCallback> callbacks = getEventCallbacks(eventClass);
callbacks.remove(eventCallback);
this.eventCallbacks.put(eventClass, callbacks);
}
@Override @Override
public <E extends Event> List<EventCallback> getEventCallbacks(Class<E> eventClass) { public <E extends Event> List<EventCallback> getEventCallbacks(Class<E> eventClass) {
Check.notNull(eventClass, "Event class cannot be null"); Check.notNull(eventClass, "Event class cannot be null");
@ -454,30 +521,73 @@ public abstract class Entity implements Viewable, EventHandler, DataContainer {
return id; return id;
} }
/**
* Return the entity type id, can convert using {@link EntityType#fromId(int)}
*
* @return the entity type id
*/
public int getEntityType() { public int getEntityType() {
return entityType; return entityType;
} }
/**
* Get the entity UUID
*
* @return the entity UUID
*/
public UUID getUuid() { public UUID getUuid() {
return uuid; return uuid;
} }
/**
* Return false just after instantiation, set to true after calling {@link #setInstance(Instance)}
*
* @return true if the entity has been linked to an instance, false otherwise
*/
public boolean isActive() { public boolean isActive() {
return isActive; return isActive;
} }
/**
* Is used to check collision with coordinates or other blocks/entities
*
* @return the entity bounding box
*/
public BoundingBox getBoundingBox() { public BoundingBox getBoundingBox() {
return boundingBox; return boundingBox;
} }
/**
* Change the internal entity bounding box
* <p>
* WARNING: this does not change the entity hit-box which is client-side
*
* @param x the bounding box X size
* @param y the bounding box Y size
* @param z the bounding box Z size
*/
public void setBoundingBox(float x, float y, float z) { public void setBoundingBox(float x, float y, float z) {
this.boundingBox = new BoundingBox(this, x, y, z); this.boundingBox = new BoundingBox(this, x, y, z);
} }
/**
* Get the entity current instance
*
* @return the entity instance
*/
public Instance getInstance() { public Instance getInstance() {
return instance; return instance;
} }
/**
* Change the entity instance
*
* @param instance the new instance of the entity
* @throws NullPointerException if {@code instance} is null
* @throws IllegalStateException if {@code instance} has not been registered in
* {@link InstanceManager#createInstanceContainer()} or
* {@link InstanceManager#createSharedInstance(InstanceContainer)}
*/
public void setInstance(Instance instance) { public void setInstance(Instance instance) {
Check.notNull(instance, "instance cannot be null!"); Check.notNull(instance, "instance cannot be null!");
Check.stateCondition(!MinecraftServer.getInstanceManager().getInstances().contains(instance), Check.stateCondition(!MinecraftServer.getInstanceManager().getInstances().contains(instance),
@ -495,16 +605,22 @@ public abstract class Entity implements Viewable, EventHandler, DataContainer {
callEvent(EntitySpawnEvent.class, entitySpawnEvent); callEvent(EntitySpawnEvent.class, entitySpawnEvent);
} }
/**
* Get the entity current velocity
*
* @return the entity current velocity
*/
public Vector getVelocity() { public Vector getVelocity() {
return velocity; return velocity;
} }
public boolean hasVelocity() { /**
return velocity.getX() != 0 || * Change the entity velocity and calls {@link EntityVelocityEvent}.
velocity.getY() != 0 || * <p>
velocity.getZ() != 0; * The final velocity can be cancelled or modified by the event
} *
* @param velocity the new entity velocity
*/
public void setVelocity(Vector velocity) { public void setVelocity(Vector velocity) {
EntityVelocityEvent entityVelocityEvent = new EntityVelocityEvent(this, velocity); EntityVelocityEvent entityVelocityEvent = new EntityVelocityEvent(this, velocity);
callCancellableEvent(EntityVelocityEvent.class, entityVelocityEvent, () -> { callCancellableEvent(EntityVelocityEvent.class, entityVelocityEvent, () -> {
@ -513,19 +629,51 @@ public abstract class Entity implements Viewable, EventHandler, DataContainer {
}); });
} }
/**
* @return true if velocity is not set to 0
*/
public boolean hasVelocity() {
return velocity.getX() != 0 ||
velocity.getY() != 0 ||
velocity.getZ() != 0;
}
/**
* Change the gravity of the entity
*
* @param gravityDragPerTick
*/
public void setGravity(float gravityDragPerTick) { public void setGravity(float gravityDragPerTick) {
this.gravityDragPerTick = gravityDragPerTick; this.gravityDragPerTick = gravityDragPerTick;
} }
/**
* Get the distance between two entities
*
* @param entity the entity to get the distance from
* @return the distance between this and {@code entity}
*/
public float getDistance(Entity entity) { public float getDistance(Entity entity) {
Check.notNull(entity, "Entity cannot be null"); Check.notNull(entity, "Entity cannot be null");
return getPosition().getDistance(entity.getPosition()); return getPosition().getDistance(entity.getPosition());
} }
/**
* Get the entity vehicle or null
*
* @return the entity vehicle, or null if there is not any
*/
public Entity getVehicle() { public Entity getVehicle() {
return vehicle; return vehicle;
} }
/**
* Add a new passenger to this entity
*
* @param entity the new passenger
* @throws NullPointerException if {@code entity} is null
* @throws IllegalStateException if {@link #getInstance()} returns null
*/
public void addPassenger(Entity entity) { public void addPassenger(Entity entity) {
Check.notNull(entity, "Passenger cannot be null"); Check.notNull(entity, "Passenger cannot be null");
Check.stateCondition(instance == null, "You need to set an instance using Entity#setInstance"); Check.stateCondition(instance == null, "You need to set an instance using Entity#setInstance");
@ -540,6 +688,13 @@ public abstract class Entity implements Viewable, EventHandler, DataContainer {
sendPacketToViewersAndSelf(getPassengersPacket()); sendPacketToViewersAndSelf(getPassengersPacket());
} }
/**
* Remove a passenger to this entity
*
* @param entity the passenger to remove
* @throws NullPointerException if {@code entity} is null
* @throws IllegalStateException if {@link #getInstance()} returns null
*/
public void removePassenger(Entity entity) { public void removePassenger(Entity entity) {
Check.notNull(entity, "Passenger cannot be null"); Check.notNull(entity, "Passenger cannot be null");
Check.stateCondition(instance == null, "You need to set an instance using Entity#setInstance"); Check.stateCondition(instance == null, "You need to set an instance using Entity#setInstance");
@ -550,11 +705,18 @@ public abstract class Entity implements Viewable, EventHandler, DataContainer {
sendPacketToViewersAndSelf(getPassengersPacket()); sendPacketToViewersAndSelf(getPassengersPacket());
} }
/**
* Get if the entity has any passenger
*
* @return true if the entity has any passenger, false otherwise
*/
public boolean hasPassenger() { public boolean hasPassenger() {
return !passengers.isEmpty(); return !passengers.isEmpty();
} }
/** /**
* Get the entity passengers
*
* @return an unmodifiable list containing all the entity passengers * @return an unmodifiable list containing all the entity passengers
*/ */
public Set<Entity> getPassengers() { public Set<Entity> getPassengers() {
@ -588,6 +750,8 @@ public abstract class Entity implements Viewable, EventHandler, DataContainer {
} }
/** /**
* Get if the entity is on fire
*
* @return true if the entity is in fire, false otherwise * @return true if the entity is in fire, false otherwise
*/ */
public boolean isOnFire() { public boolean isOnFire() {
@ -607,40 +771,79 @@ public abstract class Entity implements Viewable, EventHandler, DataContainer {
sendMetadataIndex(0); sendMetadataIndex(0);
} }
/**
* Get if the entity is invisible or not
*
* @return true if the entity is invisible, false otherwise
*/
public boolean isInvisible() { public boolean isInvisible() {
return invisible; return invisible;
} }
/**
* Change the internal invisible value and send a {@link EntityMetaDataPacket}
* to make visible or invisible the entity to its viewers
*
* @param invisible true to set the entity invisible, false otherwise
*/
public void setInvisible(boolean invisible) { public void setInvisible(boolean invisible) {
this.invisible = invisible; this.invisible = invisible;
sendMetadataIndex(0); sendMetadataIndex(0);
} }
public void setGlowing(boolean glowing) {
this.glowing = glowing;
sendMetadataIndex(0);
}
/** /**
* Get if the entity is glowing or not
*
* @return true if the entity is glowing, false otherwise * @return true if the entity is glowing, false otherwise
*/ */
public boolean isGlowing() { public boolean isGlowing() {
return glowing; return glowing;
} }
/**
* Set or remove the entity glowing effect
*
* @param glowing true to make the entity glows, false otherwise
*/
public void setGlowing(boolean glowing) {
this.glowing = glowing;
sendMetadataIndex(0);
}
/**
* Get the entity custom name
*
* @return the custom name of the entity, null if there is not
*/
public String getCustomName() { public String getCustomName() {
return customName; return customName;
} }
/**
* Change the entity custom name
*
* @param customName the custom name of the entity, null to remove it
*/
public void setCustomName(String customName) { public void setCustomName(String customName) {
this.customName = customName; this.customName = customName;
sendMetadataIndex(2); sendMetadataIndex(2);
} }
/**
* Get the custom name visible metadata field
*
* @return true if the custom name is visible, false otherwise
*/
public boolean isCustomNameVisible() { public boolean isCustomNameVisible() {
return customNameVisible; return customNameVisible;
} }
/**
* Change the internal custom name visible field and send a {@link EntityMetaDataPacket}
* to update the entity state to its viewers
*
* @param customNameVisible true to make the custom name visible, false otherwise
*/
public void setCustomNameVisible(boolean customNameVisible) { public void setCustomNameVisible(boolean customNameVisible) {
this.customNameVisible = customNameVisible; this.customNameVisible = customNameVisible;
sendMetadataIndex(3); sendMetadataIndex(3);
@ -656,6 +859,8 @@ public abstract class Entity implements Viewable, EventHandler, DataContainer {
} }
/** /**
* Change the noGravity metadata field and change the gravity behaviour accordingly
*
* @param noGravity should the entity ignore gravity * @param noGravity should the entity ignore gravity
*/ */
public void setNoGravity(boolean noGravity) { public void setNoGravity(boolean noGravity) {
@ -664,6 +869,8 @@ public abstract class Entity implements Viewable, EventHandler, DataContainer {
} }
/** /**
* Get the noGravity metadata field
*
* @return true if the entity ignore gravity, false otherwise * @return true if the entity ignore gravity, false otherwise
*/ */
public boolean hasNoGravity() { public boolean hasNoGravity() {
@ -689,6 +896,9 @@ public abstract class Entity implements Viewable, EventHandler, DataContainer {
position.setX(x); position.setX(x);
position.setY(y); position.setY(y);
position.setZ(z); position.setZ(z);
this.cacheX = x;
this.cacheY = y;
this.cacheZ = z;
if (hasPassenger()) { if (hasPassenger()) {
for (Entity passenger : getPassengers()) { for (Entity passenger : getPassengers()) {
@ -710,6 +920,10 @@ public abstract class Entity implements Viewable, EventHandler, DataContainer {
} }
} }
/**
* @param position the new position
* @see #refreshPosition(float, float, float)
*/
public void refreshPosition(Position position) { public void refreshPosition(Position position) {
refreshPosition(position.getX(), position.getY(), position.getZ()); refreshPosition(position.getX(), position.getY(), position.getZ());
} }
@ -765,11 +979,21 @@ public abstract class Entity implements Viewable, EventHandler, DataContainer {
} }
} }
/**
* Update the entity view internally
* <p>
* Warning: you probably want to use {@link #setView(float, float)}
*
* @param yaw the yaw
* @param pitch the pitch
*/
public void refreshView(float yaw, float pitch) { public void refreshView(float yaw, float pitch) {
this.lastYaw = position.getYaw(); this.lastYaw = position.getYaw();
this.lastPitch = position.getPitch(); this.lastPitch = position.getPitch();
position.setYaw(yaw); position.setYaw(yaw);
position.setPitch(pitch); position.setPitch(pitch);
this.cacheYaw = yaw;
this.cachePitch = pitch;
} }
public void refreshSneaking(boolean sneaking) { public void refreshSneaking(boolean sneaking) {
@ -785,21 +1009,35 @@ public abstract class Entity implements Viewable, EventHandler, DataContainer {
} }
/** /**
* Get the entity position
*
* @return the current position of the entity * @return the current position of the entity
*/ */
public Position getPosition() { public Position getPosition() {
return position; return position;
} }
/**
* Get the entity eye height
*
* @return the entity eye height
*/
public float getEyeHeight() { public float getEyeHeight() {
return eyeHeight; return eyeHeight;
} }
/**
* Change the entity eye height
*
* @param eyeHeight the entity eye eight
*/
public void setEyeHeight(float eyeHeight) { public void setEyeHeight(float eyeHeight) {
this.eyeHeight = eyeHeight; this.eyeHeight = eyeHeight;
} }
/** /**
* Get if this entity is in the same chunk as the specified position
*
* @param position the checked position chunk * @param position the checked position chunk
* @return true if the entity is in the same chunk as {@code position} * @return true if the entity is in the same chunk as {@code position}
*/ */
@ -815,6 +1053,12 @@ public abstract class Entity implements Viewable, EventHandler, DataContainer {
return chunkX1 == chunkX2 && chunkZ1 == chunkZ2; return chunkX1 == chunkX2 && chunkZ1 == chunkZ2;
} }
/**
* Get if the entity is in the same chunk as another
*
* @param entity the entity to check
* @return true if both entities are in the same chunk, false otherwise
*/
public boolean sameChunk(Entity entity) { public boolean sameChunk(Entity entity) {
return sameChunk(entity.getPosition()); return sameChunk(entity.getPosition());
} }
@ -847,6 +1091,8 @@ public abstract class Entity implements Viewable, EventHandler, DataContainer {
} }
/** /**
* Get if the entity removal is scheduled
*
* @return true if {@link #scheduleRemove(long, TimeUnit)} has been called, false otherwise * @return true if {@link #scheduleRemove(long, TimeUnit)} has been called, false otherwise
*/ */
public boolean isRemoveScheduled() { public boolean isRemoveScheduled() {
@ -1015,7 +1261,7 @@ public abstract class Entity implements Viewable, EventHandler, DataContainer {
} }
/** /**
* Ask for a synchronization (position) to happen during next entity update * Ask for a synchronization (position) to happen during next entity tick
*/ */
public void askSynchronization() { public void askSynchronization() {
this.lastSynchronizationTime = 0; this.lastSynchronizationTime = 0;
@ -1025,7 +1271,7 @@ public abstract class Entity implements Viewable, EventHandler, DataContainer {
return (float) (time - lastUpdate) >= MinecraftServer.TICK_MS * 0.9f; // Margin of error return (float) (time - lastUpdate) >= MinecraftServer.TICK_MS * 0.9f; // Margin of error
} }
public enum Pose { private enum Pose {
STANDING, STANDING,
FALL_FLYING, FALL_FLYING,
SLEEPING, SLEEPING,

View File

@ -1,8 +1,9 @@
package net.minestom.server.entity; package net.minestom.server.entity;
import net.minestom.server.attribute.Attribute;
import net.minestom.server.collision.CollisionUtils; import net.minestom.server.collision.CollisionUtils;
import net.minestom.server.entity.pathfinding.EntityPathFinder; import net.minestom.server.entity.pathfinding.EntityPathFinder;
import net.minestom.server.entity.property.Attribute; import net.minestom.server.event.entity.EntityAttackEvent;
import net.minestom.server.event.item.ArmorEquipEvent; import net.minestom.server.event.item.ArmorEquipEvent;
import net.minestom.server.item.ItemStack; import net.minestom.server.item.ItemStack;
import net.minestom.server.network.packet.server.play.*; import net.minestom.server.network.packet.server.play.*;
@ -48,24 +49,11 @@ public abstract class EntityCreature extends LivingEntity {
} }
@Override @Override
public void update() { public void update(long time) {
super.update(); super.update(time);
// Path finding // Path finding
if (blockPositions != null) { pathProgress();
if (targetPosition != null) {
float distance = getPosition().getDistance(targetPosition);
//System.out.println("test: "+distance);
if (distance < 0.7f) {
setNextPathPosition();
//System.out.println("END TARGET");
} else {
moveTowards(targetPosition, getAttributeValue(Attribute.MOVEMENT_SPEED));
//System.out.println("MOVE TOWARD " + targetPosition);
}
}
}
} }
/** /**
@ -94,9 +82,9 @@ public abstract class EntityCreature extends LivingEntity {
float yaw = (float) (radians * (180.0 / Math.PI)) - 90; float yaw = (float) (radians * (180.0 / Math.PI)) - 90;
float pitch = position.getPitch(); // TODO float pitch = position.getPitch(); // TODO
short deltaX = (short) ((newX * 32 - position.getX() * 32) * 128); final short deltaX = (short) ((newX * 32 - position.getX() * 32) * 128);
short deltaY = (short) ((newY * 32 - position.getY() * 32) * 128); final short deltaY = (short) ((newY * 32 - position.getY() * 32) * 128);
short deltaZ = (short) ((newZ * 32 - position.getZ() * 32) * 128); final short deltaZ = (short) ((newZ * 32 - position.getZ() * 32) * 128);
if (updateView) { if (updateView) {
EntityPositionAndRotationPacket entityPositionAndRotationPacket = new EntityPositionAndRotationPacket(); EntityPositionAndRotationPacket entityPositionAndRotationPacket = new EntityPositionAndRotationPacket();
@ -119,11 +107,7 @@ public abstract class EntityCreature extends LivingEntity {
} }
if (lastYaw != yaw) { if (lastYaw != yaw) {
EntityHeadLookPacket entityHeadLookPacket = new EntityHeadLookPacket(); setView(yaw, pitch);
entityHeadLookPacket.entityId = getEntityId();
entityHeadLookPacket.yaw = yaw;
sendPacketToViewers(entityHeadLookPacket);
refreshView(yaw, pitch);
} }
refreshPosition(newX, newY, newZ); refreshPosition(newX, newY, newZ);
@ -145,6 +129,9 @@ public abstract class EntityCreature extends LivingEntity {
@Override @Override
public boolean addViewer(Player player) { public boolean addViewer(Player player) {
boolean result = super.addViewer(player); boolean result = super.addViewer(player);
if (!result)
return false;
PlayerConnection playerConnection = player.getPlayerConnection(); PlayerConnection playerConnection = player.getPlayerConnection();
EntityPacket entityPacket = new EntityPacket(); EntityPacket entityPacket = new EntityPacket();
@ -163,7 +150,7 @@ public abstract class EntityCreature extends LivingEntity {
playerConnection.sendPacket(getMetadataPacket()); playerConnection.sendPacket(getMetadataPacket());
// Equipments synchronization // Equipments synchronization
syncEquipments(); syncEquipments(playerConnection);
if (hasPassenger()) { if (hasPassenger()) {
playerConnection.sendPacket(getPassengersPacket()); playerConnection.sendPacket(getPassengersPacket());
@ -238,9 +225,33 @@ public abstract class EntityCreature extends LivingEntity {
syncEquipment(EntityEquipmentPacket.Slot.BOOTS); syncEquipment(EntityEquipmentPacket.Slot.BOOTS);
} }
/**
* Call a {@link EntityAttackEvent} with this entity as the source and {@code target} as the target.
*
* @param target the entity target
* @param swingHand true to swing the entity main hand, false otherwise
*/
public void attack(Entity target, boolean swingHand) {
if (swingHand)
swingMainHand();
EntityAttackEvent attackEvent = new EntityAttackEvent(this, target);
callEvent(EntityAttackEvent.class, attackEvent);
}
/**
* Call a {@link EntityAttackEvent} with this entity as the source and {@code target} as the target.
* <p>
* This does not trigger the hand animation
*
* @param target the entity target
*/
public void attack(Entity target) {
attack(target, false);
}
public void jump(float height) { public void jump(float height) {
// FIXME magic value // FIXME magic value
Vector velocity = new Vector(0, height * 10, 0); Vector velocity = new Vector(0, height * 5, 0);
setVelocity(velocity); setVelocity(velocity);
} }
@ -271,7 +282,7 @@ public abstract class EntityCreature extends LivingEntity {
} }
/** /**
* Used to move the entity toward {@code direction} in the axis X and Z * Used to move the entity toward {@code direction} in the X and Z axis
* Gravity is still applied but the entity will not attempt to jump * Gravity is still applied but the entity will not attempt to jump
* *
* @param direction the targeted position * @param direction the targeted position
@ -294,11 +305,27 @@ public abstract class EntityCreature extends LivingEntity {
} }
this.targetPosition = blockPosition.toPosition();//.add(0.5f, 0, 0.5f); this.targetPosition = blockPosition.toPosition();//.add(0.5f, 0, 0.5f);
// FIXME: jump support
if (blockPosition.getY() > getPosition().getY()) if (blockPosition.getY() > getPosition().getY())
jump(1); jump(1);
} }
private void pathProgress() {
if (blockPositions != null) {
if (targetPosition != null) {
float distance = getPosition().getDistance(targetPosition);
//System.out.println("test: "+distance);
if (distance < 1f) {
setNextPathPosition();
pathProgress();
//System.out.println("END TARGET");
} else {
moveTowards(targetPosition, getAttributeValue(Attribute.MOVEMENT_SPEED));
//System.out.println("MOVE TOWARD " + targetPosition);
}
}
}
}
private ItemStack getEquipmentItem(ItemStack itemStack, ArmorEquipEvent.ArmorSlot armorSlot) { private ItemStack getEquipmentItem(ItemStack itemStack, ArmorEquipEvent.ArmorSlot armorSlot) {
itemStack = ItemStackUtils.notNull(itemStack); itemStack = ItemStackUtils.notNull(itemStack);

View File

@ -12,7 +12,7 @@ import java.util.Set;
import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.ExecutorService; import java.util.concurrent.ExecutorService;
public class EntityManager { public final class EntityManager {
private static InstanceManager instanceManager = MinecraftServer.getInstanceManager(); private static InstanceManager instanceManager = MinecraftServer.getInstanceManager();
@ -24,6 +24,9 @@ public class EntityManager {
private ConcurrentLinkedQueue<Player> waitingPlayers = new ConcurrentLinkedQueue<>(); private ConcurrentLinkedQueue<Player> waitingPlayers = new ConcurrentLinkedQueue<>();
/**
* Execute a whole entity server tick
*/
public void update() { public void update() {
final long time = System.currentTimeMillis(); final long time = System.currentTimeMillis();
@ -164,7 +167,7 @@ public class EntityManager {
playersPool.execute(() -> { playersPool.execute(() -> {
playerCache.init(); playerCache.init();
PlayerLoginEvent loginEvent = new PlayerLoginEvent(); PlayerLoginEvent loginEvent = new PlayerLoginEvent(playerCache);
playerCache.callEvent(PlayerLoginEvent.class, loginEvent); playerCache.callEvent(PlayerLoginEvent.class, loginEvent);
Instance spawningInstance = loginEvent.getSpawningInstance(); Instance spawningInstance = loginEvent.getSpawningInstance();
@ -179,10 +182,16 @@ public class EntityManager {
this.waitingPlayers.add(player); this.waitingPlayers.add(player);
} }
/**
* @return the current entity update type
*/
public UpdateType getUpdateType() { public UpdateType getUpdateType() {
return updateType; return updateType;
} }
/**
* @param updateType the new entity update type
*/
public void setUpdateType(UpdateType updateType) { public void setUpdateType(UpdateType updateType) {
this.updateType = updateType; this.updateType = updateType;
} }

View File

@ -18,7 +18,7 @@ public class ExperienceOrb extends Entity {
} }
@Override @Override
public void update() { public void update(long time) {
// TODO slide toward nearest player // TODO slide toward nearest player
} }

View File

@ -6,13 +6,28 @@ import net.minestom.server.item.ItemStack;
import net.minestom.server.item.StackingRule; import net.minestom.server.item.StackingRule;
import net.minestom.server.network.packet.PacketWriter; import net.minestom.server.network.packet.PacketWriter;
import net.minestom.server.utils.Position; import net.minestom.server.utils.Position;
import net.minestom.server.utils.time.CooldownUtils;
import net.minestom.server.utils.time.TimeUnit; import net.minestom.server.utils.time.TimeUnit;
import net.minestom.server.utils.time.UpdateOption;
import java.util.Set; import java.util.Set;
import java.util.function.Consumer; import java.util.function.Consumer;
/**
* Represent an item on the ground
*/
public class ItemEntity extends ObjectEntity { public class ItemEntity extends ObjectEntity {
/**
* Used to slow down the merge check delay
*/
private static UpdateOption mergeUpdateOption = new UpdateOption(10, TimeUnit.TICK);
/**
* The last time that this item has checked his neighbors for merge
*/
private long lastMergeCheck;
private ItemStack itemStack; private ItemStack itemStack;
private boolean pickable = true; private boolean pickable = true;
@ -26,12 +41,33 @@ public class ItemEntity extends ObjectEntity {
super(EntityType.ITEM, spawnPosition); super(EntityType.ITEM, spawnPosition);
this.itemStack = itemStack; this.itemStack = itemStack;
setBoundingBox(0.25f, 0.25f, 0.25f); setBoundingBox(0.25f, 0.25f, 0.25f);
setGravity(0.025f); }
/**
* Get the update option for the merging feature
*
* @return the merge update option
*/
public static UpdateOption getMergeUpdateOption() {
return mergeUpdateOption;
}
/**
* Change the merge update option.
* Can be set to null to entirely remove the delay
*
* @param mergeUpdateOption the new merge update option
*/
public static void setMergeUpdateOption(UpdateOption mergeUpdateOption) {
ItemEntity.mergeUpdateOption = mergeUpdateOption;
} }
@Override @Override
public void update() { public void update(long time) {
if (isMergeable() && isPickable()) { if (isMergeable() && isPickable() &&
(mergeUpdateOption == null || !CooldownUtils.hasCooldown(time, lastMergeCheck, mergeUpdateOption))) {
this.lastMergeCheck = time;
Chunk chunk = instance.getChunkAt(getPosition()); Chunk chunk = instance.getChunkAt(getPosition());
Set<Entity> entities = instance.getChunkEntities(chunk); Set<Entity> entities = instance.getChunkEntities(chunk);
for (Entity entity : entities) { for (Entity entity : entities) {
@ -49,30 +85,30 @@ public class ItemEntity extends ObjectEntity {
if (getDistance(itemEntity) > mergeRange) if (getDistance(itemEntity) > mergeRange)
continue; continue;
synchronized (this) { // Use the class as a monitor to prevent deadlock
synchronized (itemEntity) { // Shouldn't happen too often to be an issue
ItemStack itemStackEntity = itemEntity.getItemStack(); synchronized (ItemEntity.class) {
final ItemStack itemStackEntity = itemEntity.getItemStack();
StackingRule stackingRule = itemStack.getStackingRule(); final StackingRule stackingRule = itemStack.getStackingRule();
boolean canStack = stackingRule.canBeStacked(itemStack, itemStackEntity); final boolean canStack = stackingRule.canBeStacked(itemStack, itemStackEntity);
if (!canStack) if (!canStack)
continue; continue;
int totalAmount = stackingRule.getAmount(itemStack) + stackingRule.getAmount(itemStackEntity); final int totalAmount = stackingRule.getAmount(itemStack) + stackingRule.getAmount(itemStackEntity);
boolean canApply = stackingRule.canApply(itemStack, totalAmount); final boolean canApply = stackingRule.canApply(itemStack, totalAmount);
if (!canApply) if (!canApply)
continue; continue;
EntityItemMergeEvent entityItemMergeEvent = new EntityItemMergeEvent(this, itemEntity); final ItemStack result = stackingRule.apply(itemStack.clone(), totalAmount);
callCancellableEvent(EntityItemMergeEvent.class, entityItemMergeEvent, () -> {
ItemStack result = stackingRule.apply(itemStack.clone(), totalAmount);
setItemStack(result);
itemEntity.remove();
});
} EntityItemMergeEvent entityItemMergeEvent = new EntityItemMergeEvent(this, itemEntity, result);
callCancellableEvent(EntityItemMergeEvent.class, entityItemMergeEvent, () -> {
setItemStack(entityItemMergeEvent.getResult());
itemEntity.remove();
});
} }
} }

View File

@ -1,8 +1,8 @@
package net.minestom.server.entity; package net.minestom.server.entity;
import net.minestom.server.attribute.Attribute;
import net.minestom.server.collision.BoundingBox; import net.minestom.server.collision.BoundingBox;
import net.minestom.server.entity.damage.DamageType; import net.minestom.server.entity.damage.DamageType;
import net.minestom.server.entity.property.Attribute;
import net.minestom.server.event.entity.EntityDamageEvent; import net.minestom.server.event.entity.EntityDamageEvent;
import net.minestom.server.event.entity.EntityDeathEvent; import net.minestom.server.event.entity.EntityDeathEvent;
import net.minestom.server.event.entity.EntityFireEvent; import net.minestom.server.event.entity.EntityFireEvent;
@ -12,6 +12,7 @@ import net.minestom.server.inventory.EquipmentHandler;
import net.minestom.server.item.ItemStack; import net.minestom.server.item.ItemStack;
import net.minestom.server.network.packet.PacketWriter; import net.minestom.server.network.packet.PacketWriter;
import net.minestom.server.network.packet.server.play.*; import net.minestom.server.network.packet.server.play.*;
import net.minestom.server.network.player.PlayerConnection;
import net.minestom.server.sound.Sound; import net.minestom.server.sound.Sound;
import net.minestom.server.sound.SoundCategory; import net.minestom.server.sound.SoundCategory;
import net.minestom.server.utils.Position; import net.minestom.server.utils.Position;
@ -64,14 +65,14 @@ public abstract class LivingEntity extends Entity implements EquipmentHandler {
} }
@Override @Override
public void update() { public void update(long time) {
if (isOnFire()) { if (isOnFire()) {
if (System.currentTimeMillis() > fireExtinguishTime) { if (time > fireExtinguishTime) {
setOnFire(false); setOnFire(false);
} else { } else {
if (System.currentTimeMillis() - lastFireDamageTime > fireDamagePeriod) { if (time - lastFireDamageTime > fireDamagePeriod) {
damage(DamageType.ON_FIRE, 1.0f); damage(DamageType.ON_FIRE, 1.0f);
lastFireDamageTime = System.currentTimeMillis(); lastFireDamageTime = time;
} }
} }
} }
@ -91,6 +92,7 @@ public abstract class LivingEntity extends Entity implements EquipmentHandler {
ItemEntity itemEntity = (ItemEntity) entity; ItemEntity itemEntity = (ItemEntity) entity;
if (!itemEntity.isPickable()) if (!itemEntity.isPickable())
continue; continue;
BoundingBox itemBoundingBox = itemEntity.getBoundingBox(); BoundingBox itemBoundingBox = itemEntity.getBoundingBox();
if (livingBoundingBox.intersect(itemBoundingBox)) { if (livingBoundingBox.intersect(itemBoundingBox)) {
synchronized (itemEntity) { synchronized (itemEntity) {
@ -149,10 +151,20 @@ public abstract class LivingEntity extends Entity implements EquipmentHandler {
} }
} }
/**
* Get the amount of arrows in the entity
*
* @return the arrow count
*/
public int getArrowCount() { public int getArrowCount() {
return arrowCount; return arrowCount;
} }
/**
* Change the amount of arrow stuck in the entity
*
* @param arrowCount the arrow count
*/
public void setArrowCount(int arrowCount) { public void setArrowCount(int arrowCount) {
this.arrowCount = arrowCount; this.arrowCount = arrowCount;
sendMetadataIndex(11); sendMetadataIndex(11);
@ -214,6 +226,8 @@ public abstract class LivingEntity extends Entity implements EquipmentHandler {
* @return true if damage has been applied, false if it didn't * @return true if damage has been applied, false if it didn't
*/ */
public boolean damage(DamageType type, float value) { public boolean damage(DamageType type, float value) {
if (isDead())
return false;
if (isImmune(type)) { if (isImmune(type)) {
return false; return false;
} }
@ -273,10 +287,20 @@ public abstract class LivingEntity extends Entity implements EquipmentHandler {
return false; return false;
} }
/**
* Get the entity health
*
* @return the entity health
*/
public float getHealth() { public float getHealth() {
return health; return health;
} }
/**
* Change the entity health, kill it if {@code health} is <= 0 and is not dead yet
*
* @param health the new entity health
*/
public void setHealth(float health) { public void setHealth(float health) {
health = Math.min(health, getMaxHealth()); health = Math.min(health, getMaxHealth());
@ -287,6 +311,11 @@ public abstract class LivingEntity extends Entity implements EquipmentHandler {
sendMetadataIndex(8); // Health metadata index sendMetadataIndex(8); // Health metadata index
} }
/**
* Get the entity max health from {@link #getAttributeValue(Attribute)} {@link Attribute#MAX_HEALTH}
*
* @return the entity max health
*/
public float getMaxHealth() { public float getMaxHealth() {
return getAttributeValue(Attribute.MAX_HEALTH); return getAttributeValue(Attribute.MAX_HEALTH);
} }
@ -320,6 +349,15 @@ public abstract class LivingEntity extends Entity implements EquipmentHandler {
} }
// Equipments // Equipments
public void syncEquipments(PlayerConnection connection) {
for (EntityEquipmentPacket.Slot slot : EntityEquipmentPacket.Slot.values()) {
EntityEquipmentPacket entityEquipmentPacket = getEquipmentPacket(slot);
if (entityEquipmentPacket == null)
return;
connection.sendPacket(entityEquipmentPacket);
}
}
public void syncEquipments() { public void syncEquipments() {
for (EntityEquipmentPacket.Slot slot : EntityEquipmentPacket.Slot.values()) { for (EntityEquipmentPacket.Slot slot : EntityEquipmentPacket.Slot.values()) {
syncEquipment(slot); syncEquipment(slot);
@ -345,6 +383,8 @@ public abstract class LivingEntity extends Entity implements EquipmentHandler {
} }
/** /**
* Get if the entity is dead or not
*
* @return true if the entity is dead, false otherwise * @return true if the entity is dead, false otherwise
*/ */
public boolean isDead() { public boolean isDead() {
@ -352,6 +392,8 @@ public abstract class LivingEntity extends Entity implements EquipmentHandler {
} }
/** /**
* Get if the entity is able to pickup items
*
* @return true if the entity is able to pickup items * @return true if the entity is able to pickup items
*/ */
public boolean canPickupItem() { public boolean canPickupItem() {
@ -373,6 +415,28 @@ public abstract class LivingEntity extends Entity implements EquipmentHandler {
this.expandedBoundingBox = getBoundingBox().expand(1, 0.5f, 1); this.expandedBoundingBox = getBoundingBox().expand(1, 0.5f, 1);
} }
/**
* Send a {@link EntityAnimationPacket} to swing the main hand
* (can be used for attack animation)
*/
public void swingMainHand() {
EntityAnimationPacket animationPacket = new EntityAnimationPacket();
animationPacket.entityId = getEntityId();
animationPacket.animation = EntityAnimationPacket.Animation.SWING_MAIN_ARM;
sendPacketToViewers(animationPacket);
}
/**
* Send a {@link EntityAnimationPacket} to swing the off hand
* (can be used for attack animation)
*/
public void swingOffHand() {
EntityAnimationPacket animationPacket = new EntityAnimationPacket();
animationPacket.entityId = getEntityId();
animationPacket.animation = EntityAnimationPacket.Animation.SWING_OFF_HAND;
sendPacketToViewers(animationPacket);
}
public void refreshActiveHand(boolean isHandActive, boolean offHand, boolean riptideSpinAttack) { public void refreshActiveHand(boolean isHandActive, boolean offHand, boolean riptideSpinAttack) {
this.isHandActive = isHandActive; this.isHandActive = isHandActive;
this.offHand = offHand; this.offHand = offHand;
@ -392,14 +456,14 @@ public abstract class LivingEntity extends Entity implements EquipmentHandler {
int length = Attribute.values().length; int length = Attribute.values().length;
EntityPropertiesPacket.Property[] properties = new EntityPropertiesPacket.Property[length]; EntityPropertiesPacket.Property[] properties = new EntityPropertiesPacket.Property[length];
for (int i = 0; i < length; i++) { for (int i = 0; i < length; i++) {
Attribute attribute = Attribute.values()[i];
EntityPropertiesPacket.Property property = new EntityPropertiesPacket.Property(); EntityPropertiesPacket.Property property = new EntityPropertiesPacket.Property();
float maxValue = attribute.getMaxVanillaValue();
float value = getAttributeValue(attribute);
value = value > maxValue ? maxValue : value; // Bypass vanilla limit client-side if needed (by sending the max value allowed)
property.key = attribute.getKey(); Attribute attribute = Attribute.values()[i];
float value = getAttributeValue(attribute);
property.attribute = attribute;
property.value = value; property.value = value;
properties[i] = property; properties[i] = property;
} }
@ -421,11 +485,23 @@ public abstract class LivingEntity extends Entity implements EquipmentHandler {
} }
} }
/**
* Get the time in ms between two fire damage applications
*
* @return the time in ms
*/
public long getFireDamagePeriod() { public long getFireDamagePeriod() {
return fireDamagePeriod; return fireDamagePeriod;
} }
public void setFireDamagePeriod(long fireDamagePeriod) { /**
* Change the delay between two fire damage applications
*
* @param fireDamagePeriod the delay
* @param timeUnit the time unit
*/
public void setFireDamagePeriod(long fireDamagePeriod, TimeUnit timeUnit) {
fireDamagePeriod = timeUnit.toMilliseconds(fireDamagePeriod);
this.fireDamagePeriod = fireDamagePeriod; this.fireDamagePeriod = fireDamagePeriod;
} }
} }

View File

@ -19,7 +19,7 @@ public abstract class ObjectEntity extends Entity {
public abstract int getObjectData(); public abstract int getObjectData();
@Override @Override
public void update() { public void update(long time) {
} }
@ -30,6 +30,10 @@ public abstract class ObjectEntity extends Entity {
@Override @Override
public boolean addViewer(Player player) { public boolean addViewer(Player player) {
boolean result = super.addViewer(player);
if (!result)
return false;
PlayerConnection playerConnection = player.getPlayerConnection(); PlayerConnection playerConnection = player.getPlayerConnection();
SpawnEntityPacket spawnEntityPacket = new SpawnEntityPacket(); SpawnEntityPacket spawnEntityPacket = new SpawnEntityPacket();
@ -46,7 +50,7 @@ public abstract class ObjectEntity extends Entity {
playerConnection.sendPacket(getPassengersPacket()); playerConnection.sendPacket(getPassengersPacket());
} }
return super.addViewer(player); // Add player to viewers list return result;
} }
} }

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,94 @@
package net.minestom.server.entity;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import net.minestom.server.utils.url.URLUtils;
import java.io.IOException;
import java.util.Iterator;
/**
* Contains all the data required to store a skin
*/
public class PlayerSkin {
private String textures;
private String signature;
public PlayerSkin(String textures, String signature) {
this.textures = textures;
this.signature = signature;
}
/**
* Get the skin textures value
*
* @return the textures value
*/
public String getTextures() {
return textures;
}
/**
* Get the skin signature
*
* @return the skin signature
*/
public String getSignature() {
return signature;
}
/**
* Get a skin from a Mojang UUID
*
* @param uuid Mojang UUID
* @return a player skin based on the UUID
*/
public static PlayerSkin fromUuid(String uuid) {
final String url = "https://sessionserver.mojang.com/session/minecraft/profile/" + uuid + "?unsigned=false";
try {
final String response = URLUtils.getText(url);
JsonObject jsonObject = (new JsonParser()).parse(response).getAsJsonObject();
JsonArray propertiesArray = jsonObject.get("properties").getAsJsonArray();
Iterator<JsonElement> iterator = propertiesArray.iterator();
while (iterator.hasNext()) {
JsonObject propertyObject = iterator.next().getAsJsonObject();
final String name = propertyObject.get("name").getAsString();
if (!name.equals("textures"))
continue;
final String textureValue = propertyObject.get("value").getAsString();
final String signatureValue = propertyObject.get("signature").getAsString();
return new PlayerSkin(textureValue, signatureValue);
}
return null;
} catch (IOException e) {
e.printStackTrace();
return null;
}
}
/**
* Get a skin from a Minecraft username
*
* @param username the Minecraft username
* @return a skin based on a Minecraft username
*/
public static PlayerSkin fromUsername(String username) {
final String url = "https://api.mojang.com/users/profiles/minecraft/" + username;
try {
final String response = URLUtils.getText(url);
JsonObject jsonObject = (new JsonParser()).parse(response).getAsJsonObject();
final String uuid = jsonObject.get("id").getAsString();
return fromUuid(uuid);
} catch (IOException e) {
e.printStackTrace();
return null;
}
}
}

View File

@ -39,10 +39,14 @@ public class DamageType {
return TranslatableComponent.of("death." + identifier, TextComponent.of(killed.getUsername())); return TranslatableComponent.of("death." + identifier, TextComponent.of(killed.getUsername()));
} }
public static DamageType fromPlayer(Player player) { public static EntityDamage fromPlayer(Player player) {
return new EntityDamage(player); return new EntityDamage(player);
} }
public static EntityDamage fromEntity(Entity entity) {
return new EntityDamage(entity);
}
public Component buildDeathScreenMessage(Player killed) { public Component buildDeathScreenMessage(Player killed) {
return buildChatMessage(killed); return buildChatMessage(killed);
} }

View File

@ -14,6 +14,9 @@ public class EntityDamage extends DamageType {
this.source = source; this.source = source;
} }
/**
* @return the source of the damage
*/
public Entity getSource() { public Entity getSource() {
return source; return source;
} }

View File

@ -22,6 +22,8 @@ public class FakePlayer extends Player {
public FakePlayer(UUID uuid, String username, boolean addInCache) { public FakePlayer(UUID uuid, String username, boolean addInCache) {
super(uuid, username, new FakePlayerConnection()); super(uuid, username, new FakePlayerConnection());
this.fakePlayerController = new FakePlayerController(this);
this.registered = addInCache; this.registered = addInCache;
if (registered) { if (registered) {
@ -39,13 +41,6 @@ public class FakePlayer extends Player {
this(uuid, username, false); this(uuid, username, false);
} }
@Override
protected void playerConnectionInit() {
FakePlayerConnection playerConnection = (FakePlayerConnection) getPlayerConnection();
playerConnection.setFakePlayer(this);
this.fakePlayerController = new FakePlayerController(this);
}
public FakePlayerController getController() { public FakePlayerController getController() {
return fakePlayerController; return fakePlayerController;
} }

View File

@ -0,0 +1,118 @@
package net.minestom.server.entity.type;
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 java.util.function.Consumer;
public class EntityAreaEffectCloud extends ObjectEntity {
public Consumer<PacketWriter> particleDataConsumer;
private float radius;
private int color;
private boolean ignoreRadius;
private Particle particle;
public EntityAreaEffectCloud(Position spawnPosition) {
super(EntityType.AREA_EFFECT_CLOUD, spawnPosition);
setRadius(0.5f);
setColor(0);
setIgnoreRadius(false);
setParticle(Particle.EFFECT);
setParticleDataConsumer(packetWriter -> {
});
}
@Override
public Consumer<PacketWriter> getMetadataConsumer() {
return packet -> {
super.getMetadataConsumer().accept(packet);
fillMetadataIndex(packet, 7);
fillMetadataIndex(packet, 8);
fillMetadataIndex(packet, 9);
fillMetadataIndex(packet, 10);
};
}
@Override
protected void fillMetadataIndex(PacketWriter packet, int index) {
super.fillMetadataIndex(packet, index);
if (index == 7) {
packet.writeByte((byte) 7);
packet.writeByte(METADATA_FLOAT);
packet.writeFloat(radius);
} else if (index == 8) {
packet.writeByte((byte) 8);
packet.writeByte(METADATA_VARINT);
packet.writeVarInt(color);
} else if (index == 9) {
packet.writeByte((byte) 9);
packet.writeByte(METADATA_BOOLEAN);
packet.writeBoolean(ignoreRadius);
} else if (index == 10) {
packet.writeByte((byte) 10);
packet.writeByte(METADATA_PARTICLE);
packet.writeVarInt(particle.getId());
particleDataConsumer.accept(packet);
}
}
@Override
public int getObjectData() {
return 0;
}
public float getRadius() {
return radius;
}
public void setRadius(float radius) {
this.radius = radius;
setBoundingBox(2 * radius, 0.5f, 2 * radius);
sendMetadataIndex(7);
}
public int getColor() {
return color;
}
public void setColor(int color) {
this.color = color;
sendMetadataIndex(8);
}
public boolean isIgnoreRadius() {
return ignoreRadius;
}
public void setIgnoreRadius(boolean ignoreRadius) {
this.ignoreRadius = ignoreRadius;
sendMetadataIndex(9);
}
public Particle getParticle() {
return particle;
}
public void setParticle(Particle particle) {
this.particle = particle;
sendMetadataIndex(10);
}
public Consumer<PacketWriter> getParticleDataConsumer() {
return particleDataConsumer;
}
/**
* Used to add data to the particle
*
* @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) {
this.particleDataConsumer = particleDataConsumer;
}
}

View File

@ -8,6 +8,7 @@ import net.minestom.server.inventory.EquipmentHandler;
import net.minestom.server.item.ItemStack; import net.minestom.server.item.ItemStack;
import net.minestom.server.network.packet.PacketWriter; import net.minestom.server.network.packet.PacketWriter;
import net.minestom.server.network.packet.server.play.EntityEquipmentPacket; import net.minestom.server.network.packet.server.play.EntityEquipmentPacket;
import net.minestom.server.network.player.PlayerConnection;
import net.minestom.server.utils.Position; import net.minestom.server.utils.Position;
import net.minestom.server.utils.Vector; import net.minestom.server.utils.Vector;
import net.minestom.server.utils.item.ItemStackUtils; import net.minestom.server.utils.item.ItemStackUtils;
@ -63,7 +64,7 @@ public class EntityArmorStand extends ObjectEntity implements EquipmentHandler {
@Override @Override
public boolean addViewer(Player player) { public boolean addViewer(Player player) {
boolean result = super.addViewer(player); boolean result = super.addViewer(player);
syncEquipments(); syncEquipments(player.getPlayerConnection());
return result; return result;
} }
@ -316,6 +317,15 @@ public class EntityArmorStand extends ObjectEntity implements EquipmentHandler {
} }
// Equipments // Equipments
public void syncEquipments(PlayerConnection connection) {
for (EntityEquipmentPacket.Slot slot : EntityEquipmentPacket.Slot.values()) {
EntityEquipmentPacket entityEquipmentPacket = getEquipmentPacket(slot);
if (entityEquipmentPacket == null)
return;
connection.sendPacket(entityEquipmentPacket);
}
}
public void syncEquipments() { public void syncEquipments() {
for (EntityEquipmentPacket.Slot slot : EntityEquipmentPacket.Slot.values()) { for (EntityEquipmentPacket.Slot slot : EntityEquipmentPacket.Slot.values()) {
syncEquipment(slot); syncEquipment(slot);

View File

@ -13,6 +13,7 @@ public class EntityBat extends EntityCreature {
public EntityBat(Position spawnPosition) { public EntityBat(Position spawnPosition) {
super(EntityType.BAT, spawnPosition); super(EntityType.BAT, spawnPosition);
setBoundingBox(0.5f, 0.9f, 0.5f);
} }
@Override @Override

View File

@ -11,6 +11,7 @@ public class EntityBlaze extends EntityCreature {
public EntityBlaze(Position spawnPosition) { public EntityBlaze(Position spawnPosition) {
super(EntityType.BLAZE, spawnPosition); super(EntityType.BLAZE, spawnPosition);
setBoundingBox(0.6f, 1.8f, 0.6f);
} }
@Override @Override

View File

@ -22,16 +22,6 @@ public class EntityBoat extends ObjectEntity {
return 0; return 0;
} }
@Override
public void update() {
}
@Override
public void spawn() {
}
@Override @Override
public Consumer<PacketWriter> getMetadataConsumer() { public Consumer<PacketWriter> getMetadataConsumer() {
return packet -> { return packet -> {

View File

@ -0,0 +1,12 @@
package net.minestom.server.entity.type;
import net.minestom.server.entity.EntityCreature;
import net.minestom.server.entity.EntityType;
import net.minestom.server.utils.Position;
public class EntityCaveSpider extends EntityCreature {
public EntityCaveSpider(Position spawnPosition) {
super(EntityType.CAVE_SPIDER, spawnPosition);
setBoundingBox(0.7f, 0.5f, 0.7f);
}
}

View File

@ -7,5 +7,6 @@ import net.minestom.server.utils.Position;
public class EntityChicken extends EntityCreature { public class EntityChicken extends EntityCreature {
public EntityChicken(Position spawnPosition) { public EntityChicken(Position spawnPosition) {
super(EntityType.CHICKEN, spawnPosition); super(EntityType.CHICKEN, spawnPosition);
setBoundingBox(0.4f, 0.7f, 0.4f);
} }
} }

View File

@ -7,5 +7,6 @@ import net.minestom.server.utils.Position;
public class EntityCow extends EntityCreature { public class EntityCow extends EntityCreature {
public EntityCow(Position spawnPosition) { public EntityCow(Position spawnPosition) {
super(EntityType.COW, spawnPosition); super(EntityType.COW, spawnPosition);
setBoundingBox(0.9f, 1.4f, 0.9f);
} }
} }

View File

@ -15,6 +15,7 @@ public class EntityCreeper extends EntityCreature {
public EntityCreeper(Position spawnPosition) { public EntityCreeper(Position spawnPosition) {
super(EntityType.CREEPER, spawnPosition); super(EntityType.CREEPER, spawnPosition);
setBoundingBox(0.6f, 1.7f, 0.6f);
} }
@Override @Override

View File

@ -7,5 +7,6 @@ import net.minestom.server.utils.Position;
public class EntityEndermite extends EntityCreature { public class EntityEndermite extends EntityCreature {
public EntityEndermite(Position spawnPosition) { public EntityEndermite(Position spawnPosition) {
super(EntityType.ENDERMITE, spawnPosition); super(EntityType.ENDERMITE, spawnPosition);
setBoundingBox(0.4f, 0.3f, 0.4f);
} }
} }

View File

@ -13,6 +13,7 @@ public class EntityGhast extends EntityCreature {
public EntityGhast(Position spawnPosition) { public EntityGhast(Position spawnPosition) {
super(EntityType.GHAST, spawnPosition); super(EntityType.GHAST, spawnPosition);
setBoundingBox(4, 4, 4);
} }
@Override @Override

View File

@ -7,5 +7,6 @@ import net.minestom.server.utils.Position;
public class EntityGiant extends EntityCreature { public class EntityGiant extends EntityCreature {
public EntityGiant(Position spawnPosition) { public EntityGiant(Position spawnPosition) {
super(EntityType.GIANT, spawnPosition); super(EntityType.GIANT, spawnPosition);
setBoundingBox(3.6f, 10.8f, 3.6f);
} }
} }

View File

@ -0,0 +1,59 @@
package net.minestom.server.entity.type;
import net.minestom.server.entity.Entity;
import net.minestom.server.entity.EntityCreature;
import net.minestom.server.entity.EntityType;
import net.minestom.server.network.packet.PacketWriter;
import net.minestom.server.utils.Position;
import java.util.function.Consumer;
public class EntityGuardian extends EntityCreature {
private boolean retractingSpikes;
private Entity target;
public EntityGuardian(Position spawnPosition) {
super(EntityType.GUARDIAN, spawnPosition);
setBoundingBox(0.85f, 0.85f, 0.85f);
}
@Override
public Consumer<PacketWriter> getMetadataConsumer() {
return packet -> {
super.getMetadataConsumer().accept(packet);
fillMetadataIndex(packet, 15);
fillMetadataIndex(packet, 16);
};
}
@Override
protected void fillMetadataIndex(PacketWriter packet, int index) {
super.fillMetadataIndex(packet, index);
if (index == 15) {
packet.writeByte((byte) 15);
packet.writeByte(METADATA_BOOLEAN);
packet.writeBoolean(retractingSpikes);
} else if (index == 16) {
packet.writeByte((byte) 16);
packet.writeByte(METADATA_VARINT);
packet.writeVarInt(target == null ? 0 : target.getEntityId());
}
}
public boolean isRetractingSpikes() {
return retractingSpikes;
}
public void setRetractingSpikes(boolean retractingSpikes) {
this.retractingSpikes = retractingSpikes;
}
public Entity getTarget() {
return target;
}
public void setTarget(Entity target) {
this.target = target;
}
}

View File

@ -13,6 +13,7 @@ public class EntityIronGolem extends EntityCreature {
public EntityIronGolem(Position spawnPosition) { public EntityIronGolem(Position spawnPosition) {
super(EntityType.IRON_GOLEM, spawnPosition); super(EntityType.IRON_GOLEM, spawnPosition);
setBoundingBox(1.4f, 2.7f, 1.4f);
} }
@Override @Override

View File

@ -13,6 +13,7 @@ public class EntityMooshroom extends EntityCreature {
public EntityMooshroom(Position spawnPosition) { public EntityMooshroom(Position spawnPosition) {
super(EntityType.MOOSHROOM, spawnPosition); super(EntityType.MOOSHROOM, spawnPosition);
setBoundingBox(0.9f, 1.4f, 0.9f);
setMooshroomType(MooshroomType.RED); setMooshroomType(MooshroomType.RED);
} }

View File

@ -13,6 +13,7 @@ public class EntityPhantom extends EntityCreature {
public EntityPhantom(Position spawnPosition) { public EntityPhantom(Position spawnPosition) {
super(EntityType.PHANTOM, spawnPosition); super(EntityType.PHANTOM, spawnPosition);
setBoundingBox(0.9f, 0.5f, 0.9f); // TODO change based on size
} }
@Override @Override

View File

@ -13,6 +13,7 @@ public class EntityPig extends EntityCreature {
public EntityPig(Position spawnPosition) { public EntityPig(Position spawnPosition) {
super(EntityType.PIG, spawnPosition); super(EntityType.PIG, spawnPosition);
setBoundingBox(0.9f, 0.9f, 0.9f);
} }
@Override @Override

View File

@ -0,0 +1,61 @@
package net.minestom.server.entity.type;
import net.minestom.server.entity.EntityCreature;
import net.minestom.server.entity.EntityType;
import net.minestom.server.network.packet.PacketWriter;
import net.minestom.server.utils.Position;
import java.util.function.Consumer;
public class EntityPigZombie extends EntityCreature {
private boolean baby;
private boolean becomingDrowned;
public EntityPigZombie(Position spawnPosition) {
super(EntityType.ZOMBIE_PIGMAN, spawnPosition);
setBoundingBox(0.6f, 1.95f, 0.6f);
}
@Override
public Consumer<PacketWriter> getMetadataConsumer() {
return packet -> {
super.getMetadataConsumer().accept(packet);
fillMetadataIndex(packet, 15);
fillMetadataIndex(packet, 17);
};
}
@Override
protected void fillMetadataIndex(PacketWriter packet, int index) {
super.fillMetadataIndex(packet, index);
if (index == 15) {
packet.writeByte((byte) 15);
packet.writeByte(METADATA_BOOLEAN);
packet.writeBoolean(baby);
} else if (index == 17) {
packet.writeByte((byte) 17);
packet.writeByte(METADATA_BOOLEAN);
packet.writeBoolean(becomingDrowned);
}
}
public boolean isBaby() {
return baby;
}
public void setBaby(boolean baby) {
this.baby = baby;
sendMetadataIndex(15);
}
public boolean isBecomingDrowned() {
return becomingDrowned;
}
public void setBecomingDrowned(boolean becomingDrowned) {
this.becomingDrowned = becomingDrowned;
sendMetadataIndex(17);
}
}

View File

@ -13,6 +13,7 @@ public class EntityPolarBear extends EntityCreature {
public EntityPolarBear(Position spawnPosition) { public EntityPolarBear(Position spawnPosition) {
super(EntityType.POLAR_BEAR, spawnPosition); super(EntityType.POLAR_BEAR, spawnPosition);
setBoundingBox(1.3f, 1.4f, 1.3f);
} }
@Override @Override

View File

@ -14,6 +14,7 @@ public class EntityPotion extends ObjectEntity {
public EntityPotion(Position spawnPosition, ItemStack potion) { public EntityPotion(Position spawnPosition, ItemStack potion) {
super(EntityType.POTION, spawnPosition); super(EntityType.POTION, spawnPosition);
setBoundingBox(0.25f, 0.25f, 0.25f);
setPotion(potion); setPotion(potion);
} }

View File

@ -13,6 +13,7 @@ public class EntityRabbit extends EntityCreature {
public EntityRabbit(Position spawnPosition) { public EntityRabbit(Position spawnPosition) {
super(EntityType.RABBIT, spawnPosition); super(EntityType.RABBIT, spawnPosition);
setBoundingBox(0.4f, 0.5f, 0.4f);
} }
@Override @Override

View File

@ -7,5 +7,6 @@ import net.minestom.server.utils.Position;
public class EntitySilverfish extends EntityCreature { public class EntitySilverfish extends EntityCreature {
public EntitySilverfish(Position spawnPosition) { public EntitySilverfish(Position spawnPosition) {
super(EntityType.SILVERFISH, spawnPosition); super(EntityType.SILVERFISH, spawnPosition);
setBoundingBox(0.4f, 0.3f, 0.4f);
} }
} }

View File

@ -40,6 +40,8 @@ public class EntitySlime extends EntityCreature {
public void setSize(int size) { public void setSize(int size) {
this.size = size; this.size = size;
final float boxSize = 0.51000005f * size;
setBoundingBox(boxSize, boxSize, boxSize);
sendMetadataIndex(15); sendMetadataIndex(15);
} }
} }

View File

@ -13,6 +13,7 @@ public class EntitySnowman extends EntityCreature {
public EntitySnowman(Position spawnPosition) { public EntitySnowman(Position spawnPosition) {
super(EntityType.SNOW_GOLEM, spawnPosition); super(EntityType.SNOW_GOLEM, spawnPosition);
setBoundingBox(0.7f, 1.9f, 0.7f);
} }
@Override @Override

View File

@ -13,6 +13,7 @@ public class EntitySpider extends EntityCreature {
public EntitySpider(Position spawnPosition) { public EntitySpider(Position spawnPosition) {
super(EntityType.SPIDER, spawnPosition); super(EntityType.SPIDER, spawnPosition);
setBoundingBox(1.4f, 0.9f, 1.4f);
} }
@Override @Override

View File

@ -13,6 +13,7 @@ public class EntityWitch extends EntityCreature {
public EntityWitch(Position spawnPosition) { public EntityWitch(Position spawnPosition) {
super(EntityType.WITCH, spawnPosition); super(EntityType.WITCH, spawnPosition);
setBoundingBox(0.6f, 1.95f, 0.6f);
} }
@Override @Override

View File

@ -14,6 +14,7 @@ public class EntityZombie extends EntityCreature {
public EntityZombie(Position spawnPosition) { public EntityZombie(Position spawnPosition) {
super(EntityType.ZOMBIE, spawnPosition); super(EntityType.ZOMBIE, spawnPosition);
setBoundingBox(0.6f, 1.95f, 0.6f);
} }
@Override @Override

View File

@ -4,10 +4,16 @@ public class CancellableEvent extends Event {
private boolean cancelled; private boolean cancelled;
/**
* @return true if the event should be cancelled, false otherwise
*/
public boolean isCancelled() { public boolean isCancelled() {
return cancelled; return cancelled;
} }
/**
* @param cancel true if the event should be cancelled, false otherwise
*/
public void setCancelled(boolean cancel) { public void setCancelled(boolean cancel) {
this.cancelled = cancel; this.cancelled = cancel;
} }

View File

@ -3,6 +3,10 @@ package net.minestom.server.event.entity;
import net.minestom.server.entity.Entity; import net.minestom.server.entity.Entity;
import net.minestom.server.event.Event; import net.minestom.server.event.Event;
/**
* Called when a player does a left click on an entity or with
* {@link net.minestom.server.entity.EntityCreature#attack(Entity)}
*/
public class EntityAttackEvent extends Event { public class EntityAttackEvent extends Event {
private Entity source; private Entity source;
@ -13,10 +17,16 @@ public class EntityAttackEvent extends Event {
this.target = target; this.target = target;
} }
/**
* @return the source of the attack
*/
public Entity getSource() { public Entity getSource() {
return source; return source;
} }
/**
* @return the target of the attack
*/
public Entity getTarget() { public Entity getTarget() {
return target; return target;
} }

View File

@ -3,6 +3,9 @@ package net.minestom.server.event.entity;
import net.minestom.server.entity.damage.DamageType; import net.minestom.server.entity.damage.DamageType;
import net.minestom.server.event.CancellableEvent; import net.minestom.server.event.CancellableEvent;
/**
* Called with {@link net.minestom.server.entity.LivingEntity#damage(DamageType, float)}
*/
public class EntityDamageEvent extends CancellableEvent { public class EntityDamageEvent extends CancellableEvent {
private DamageType damageType; private DamageType damageType;
@ -13,14 +16,23 @@ public class EntityDamageEvent extends CancellableEvent {
this.damage = damage; this.damage = damage;
} }
/**
* @return the damage type
*/
public DamageType getDamageType() { public DamageType getDamageType() {
return damageType; return damageType;
} }
/**
* @return the damage amount
*/
public float getDamage() { public float getDamage() {
return damage; return damage;
} }
/**
* @param damage the new damage amount
*/
public void setDamage(float damage) { public void setDamage(float damage) {
this.damage = damage; this.damage = damage;
} }

View File

@ -12,6 +12,9 @@ public class EntityDeathEvent extends Event {
this.entity = entity; this.entity = entity;
} }
/**
* @return the entity that died
*/
public Entity getEntity() { public Entity getEntity() {
return entity; return entity;
} }

View File

@ -2,22 +2,61 @@ package net.minestom.server.event.entity;
import net.minestom.server.entity.ItemEntity; import net.minestom.server.entity.ItemEntity;
import net.minestom.server.event.CancellableEvent; import net.minestom.server.event.CancellableEvent;
import net.minestom.server.item.ItemStack;
/**
* Called when two {@link ItemEntity} are merging their ItemStack together to form a sole entity
*/
public class EntityItemMergeEvent extends CancellableEvent { public class EntityItemMergeEvent extends CancellableEvent {
private ItemEntity source; private ItemEntity source;
private ItemEntity merged; private ItemEntity merged;
public EntityItemMergeEvent(ItemEntity source, ItemEntity merged) { private ItemStack result;
public EntityItemMergeEvent(ItemEntity source, ItemEntity merged, ItemStack result) {
this.source = source; this.source = source;
this.merged = merged; this.merged = merged;
this.result = result;
} }
/**
* Get the entity who is receiving {@link #getMerged()} ItemStack
* <p>
* This can be used to get the final ItemEntity position
*
* @return the source ItemEntity
*/
public ItemEntity getSource() { public ItemEntity getSource() {
return source; return source;
} }
/**
* Get the entity who will be merged
* <p>
* This entity will be removed after the event
*
* @return the merged ItemEntity
*/
public ItemEntity getMerged() { public ItemEntity getMerged() {
return merged; return merged;
} }
/**
* Get the final item stack on the ground
*
* @return the item stack
*/
public ItemStack getResult() {
return result;
}
/**
* Change the item stack which will appear on the ground
*
* @param result the new item stack
*/
public void setResult(ItemStack result) {
this.result = result;
}
} }

View File

@ -3,6 +3,9 @@ package net.minestom.server.event.entity;
import net.minestom.server.event.Event; import net.minestom.server.event.Event;
import net.minestom.server.instance.Instance; import net.minestom.server.instance.Instance;
/**
* Called when a new instance is set for an entity
*/
public class EntitySpawnEvent extends Event { public class EntitySpawnEvent extends Event {
private Instance spawnInstance; private Instance spawnInstance;
@ -11,6 +14,11 @@ public class EntitySpawnEvent extends Event {
this.spawnInstance = spawnInstance; this.spawnInstance = spawnInstance;
} }
/**
* Get the entity new instance
*
* @return the instance
*/
public Instance getSpawnInstance() { public Instance getSpawnInstance() {
return spawnInstance; return spawnInstance;
} }

View File

@ -14,14 +14,23 @@ public class EntityVelocityEvent extends CancellableEvent {
this.velocity = velocity; this.velocity = velocity;
} }
/**
* @return the entity who the velocity is applied to
*/
public Entity getEntity() { public Entity getEntity() {
return entity; return entity;
} }
/**
* @return the velocity which will be applied
*/
public Vector getVelocity() { public Vector getVelocity() {
return velocity; return velocity;
} }
/**
* @param velocity the new velocity to applies
*/
public void setVelocity(Vector velocity) { public void setVelocity(Vector velocity) {
this.velocity = velocity; this.velocity = velocity;
} }

View File

@ -17,6 +17,15 @@ public interface EventHandler {
*/ */
<E extends Event> void addEventCallback(Class<E> eventClass, EventCallback<E> eventCallback); <E extends Event> void addEventCallback(Class<E> eventClass, EventCallback<E> eventCallback);
/**
* Remove an event callback
*
* @param eventClass the event class
* @param eventCallback the event callback
* @param <E> the event type
*/
<E extends Event> void removeEventCallback(Class<E> eventClass, EventCallback<E> eventCallback);
/** /**
* @param eventClass * @param eventClass
* @param <E> * @param <E>

View File

@ -1,5 +1,6 @@
package net.minestom.server.event.inventory; package net.minestom.server.event.inventory;
import net.minestom.server.entity.Player;
import net.minestom.server.event.Event; import net.minestom.server.event.Event;
import net.minestom.server.inventory.Inventory; import net.minestom.server.inventory.Inventory;
import net.minestom.server.inventory.click.ClickType; import net.minestom.server.inventory.click.ClickType;
@ -7,13 +8,14 @@ import net.minestom.server.item.ItemStack;
public class InventoryClickEvent extends Event { public class InventoryClickEvent extends Event {
private Player player;
private Inventory inventory; private Inventory inventory;
private int slot; private int slot;
private ClickType clickType; private ClickType clickType;
private ItemStack clickedItem; private ItemStack clickedItem;
private ItemStack cursorItem; private ItemStack cursorItem;
public InventoryClickEvent(Inventory inventory, int slot, ClickType clickType, ItemStack clicked, ItemStack cursor) { public InventoryClickEvent(Player player, Inventory inventory, int slot, ClickType clickType, ItemStack clicked, ItemStack cursor) {
this.inventory = inventory; this.inventory = inventory;
this.slot = slot; this.slot = slot;
this.clickType = clickType; this.clickType = clickType;
@ -21,6 +23,15 @@ public class InventoryClickEvent extends Event {
this.cursorItem = cursor; this.cursorItem = cursor;
} }
/**
* Get the player who clicked in the inventory
*
* @return the player who clicked in the inventory
*/
public Player getPlayer() {
return player;
}
/** /**
* Can be null if the clicked inventory is the player one * Can be null if the clicked inventory is the player one
* *
@ -30,18 +41,38 @@ public class InventoryClickEvent extends Event {
return inventory; return inventory;
} }
/**
* Get the clicked slot number
*
* @return the clicked slot number
*/
public int getSlot() { public int getSlot() {
return slot; return slot;
} }
/**
* Get the click type
*
* @return the click type
*/
public ClickType getClickType() { public ClickType getClickType() {
return clickType; return clickType;
} }
/**
* Get the clicked item
*
* @return the clicked item
*/
public ItemStack getClickedItem() { public ItemStack getClickedItem() {
return clickedItem; return clickedItem;
} }
/**
* Get the item in the player cursor
*
* @return the cursor item
*/
public ItemStack getCursorItem() { public ItemStack getCursorItem() {
return cursorItem; return cursorItem;
} }

View File

@ -1,24 +1,43 @@
package net.minestom.server.event.inventory; package net.minestom.server.event.inventory;
import net.minestom.server.entity.Player;
import net.minestom.server.event.Event; import net.minestom.server.event.Event;
import net.minestom.server.inventory.Inventory; import net.minestom.server.inventory.Inventory;
public class InventoryCloseEvent extends Event { public class InventoryCloseEvent extends Event {
private Player player;
private Inventory inventory; private Inventory inventory;
private Inventory newInventory; private Inventory newInventory;
public InventoryCloseEvent(Inventory inventory) { public InventoryCloseEvent(Player player, Inventory inventory) {
this.player = player;
this.inventory = inventory; this.inventory = inventory;
} }
/** /**
* Get the player who closed the inventory
*
* @return the player who closed the inventory
*/
public Player getPlayer() {
return player;
}
/**
* Get the closed inventory
*
* @return the closed inventory, null if this is the player inventory * @return the closed inventory, null if this is the player inventory
*/ */
public Inventory getInventory() { public Inventory getInventory() {
return inventory; return inventory;
} }
/**
* Get the new inventory to open
*
* @return the new inventory to open, null if there isn't any
*/
public Inventory getNewInventory() { public Inventory getNewInventory() {
return newInventory; return newInventory;
} }
@ -26,7 +45,7 @@ public class InventoryCloseEvent extends Event {
/** /**
* Can be used to open a new inventory after closing the previous one * Can be used to open a new inventory after closing the previous one
* *
* @param newInventory the inventory to open, can be null * @param newInventory the inventory to open, null to do not open any
*/ */
public void setNewInventory(Inventory newInventory) { public void setNewInventory(Inventory newInventory) {
this.newInventory = newInventory; this.newInventory = newInventory;

View File

@ -3,7 +3,6 @@ package net.minestom.server.event.inventory;
import net.minestom.server.entity.Player; import net.minestom.server.entity.Player;
import net.minestom.server.event.CancellableEvent; import net.minestom.server.event.CancellableEvent;
import net.minestom.server.inventory.Inventory; import net.minestom.server.inventory.Inventory;
import net.minestom.server.utils.validate.Check;
public class InventoryOpenEvent extends CancellableEvent { public class InventoryOpenEvent extends CancellableEvent {
@ -15,16 +14,32 @@ public class InventoryOpenEvent extends CancellableEvent {
this.inventory = inventory; this.inventory = inventory;
} }
/**
* Get the player who opens the inventory
*
* @return the player who opens the inventory
*/
public Player getPlayer() { public Player getPlayer() {
return player; return player;
} }
/**
* Get the inventory to open, this could have been change by the {@link #setInventory(Inventory)}
*
* @return the inventory to open
*/
public Inventory getInventory() { public Inventory getInventory() {
return inventory; return inventory;
} }
/**
* Change the inventory to open.
* to do not open any inventory see {@link #setCancelled(boolean)}
*
* @param inventory the inventory to open
* @throws NullPointerException if {@code inventory} is null
*/
public void setInventory(Inventory inventory) { public void setInventory(Inventory inventory) {
Check.notNull(inventory, "Inventory cannot be null!");
this.inventory = inventory; this.inventory = inventory;
} }
} }

View File

@ -1,5 +1,6 @@
package net.minestom.server.event.inventory; package net.minestom.server.event.inventory;
import net.minestom.server.entity.Player;
import net.minestom.server.event.CancellableEvent; import net.minestom.server.event.CancellableEvent;
import net.minestom.server.inventory.Inventory; import net.minestom.server.inventory.Inventory;
import net.minestom.server.inventory.click.ClickType; import net.minestom.server.inventory.click.ClickType;
@ -8,13 +9,15 @@ import net.minestom.server.utils.item.ItemStackUtils;
public class InventoryPreClickEvent extends CancellableEvent { public class InventoryPreClickEvent extends CancellableEvent {
private Player player;
private Inventory inventory; private Inventory inventory;
private int slot; private int slot;
private ClickType clickType; private ClickType clickType;
private ItemStack clickedItem; private ItemStack clickedItem;
private ItemStack cursorItem; private ItemStack cursorItem;
public InventoryPreClickEvent(Inventory inventory, int slot, ClickType clickType, ItemStack clicked, ItemStack cursor) { public InventoryPreClickEvent(Player player, Inventory inventory, int slot, ClickType clickType, ItemStack clicked, ItemStack cursor) {
this.player = player;
this.inventory = inventory; this.inventory = inventory;
this.slot = slot; this.slot = slot;
this.clickType = clickType; this.clickType = clickType;
@ -22,6 +25,15 @@ public class InventoryPreClickEvent extends CancellableEvent {
this.cursorItem = cursor; this.cursorItem = cursor;
} }
/**
* Get the player who is trying to click on the inventory
*
* @return the player who clicked
*/
public Player getPlayer() {
return player;
}
/** /**
* Can be null if the clicked inventory is the player one * Can be null if the clicked inventory is the player one
* *
@ -31,26 +43,56 @@ public class InventoryPreClickEvent extends CancellableEvent {
return inventory; return inventory;
} }
/**
* Get the clicked slot number
*
* @return the clicked slot number
*/
public int getSlot() { public int getSlot() {
return slot; return slot;
} }
/**
* Get the click type
*
* @return the click type
*/
public ClickType getClickType() { public ClickType getClickType() {
return clickType; return clickType;
} }
/**
* Get the item who have been clicked
*
* @return the clicked item
*/
public ItemStack getClickedItem() { public ItemStack getClickedItem() {
return clickedItem; return clickedItem;
} }
/**
* Change the clicked item
*
* @param clickedItem the clicked item
*/
public void setClickedItem(ItemStack clickedItem) { public void setClickedItem(ItemStack clickedItem) {
this.clickedItem = ItemStackUtils.notNull(clickedItem); this.clickedItem = ItemStackUtils.notNull(clickedItem);
} }
/**
* Get the item who was in the player cursor
*
* @return the cursor item
*/
public ItemStack getCursorItem() { public ItemStack getCursorItem() {
return cursorItem; return cursorItem;
} }
/**
* Change the cursor item
*
* @param cursorItem the cursor item
*/
public void setCursorItem(ItemStack cursorItem) { public void setCursorItem(ItemStack cursorItem) {
this.cursorItem = ItemStackUtils.notNull(cursorItem); this.cursorItem = ItemStackUtils.notNull(cursorItem);
} }

View File

@ -0,0 +1,47 @@
package net.minestom.server.event.player;
import net.minestom.server.entity.Player;
import net.minestom.server.event.CancellableEvent;
import net.minestom.server.item.ItemStack;
import net.minestom.server.utils.item.ItemStackUtils;
/**
* Called as a result of {@link net.minestom.server.inventory.PlayerInventory#addItemStack(ItemStack)}
*/
public class PlayerAddItemStackEvent extends CancellableEvent {
private Player player;
private ItemStack itemStack;
public PlayerAddItemStackEvent(Player player, ItemStack itemStack) {
this.player = player;
this.itemStack = itemStack;
}
/**
* Get the player who has an item stack added to his inventory
*
* @return the player
*/
public Player getPlayer() {
return player;
}
/**
* Get the item stack which will be added
*
* @return the item stack
*/
public ItemStack getItemStack() {
return itemStack;
}
/**
* Change the item stack which will be added
*
* @param itemStack the new item stack
*/
public void setItemStack(ItemStack itemStack) {
this.itemStack = ItemStackUtils.notNull(itemStack);
}
}

View File

@ -1,42 +1,97 @@
package net.minestom.server.event.player; package net.minestom.server.event.player;
import net.minestom.server.event.CancellableEvent; import net.minestom.server.event.CancellableEvent;
import net.minestom.server.instance.block.CustomBlock;
import net.minestom.server.utils.BlockPosition; import net.minestom.server.utils.BlockPosition;
public class PlayerBlockBreakEvent extends CancellableEvent { public class PlayerBlockBreakEvent extends CancellableEvent {
private BlockPosition blockPosition; private BlockPosition blockPosition;
private short blockId;
private CustomBlock customBlock;
private short resultBlockId; private short resultBlockId;
private short resultCustomBlockId; private short resultCustomBlockId;
public PlayerBlockBreakEvent(BlockPosition blockPosition, short resultBlockId, short resultCustomBlockId) { public PlayerBlockBreakEvent(BlockPosition blockPosition,
short blockId, CustomBlock customBlock,
short resultBlockId, short resultCustomBlockId) {
this.blockPosition = blockPosition; this.blockPosition = blockPosition;
this.blockId = blockId;
this.customBlock = customBlock;
this.resultBlockId = resultBlockId; this.resultBlockId = resultBlockId;
this.resultCustomBlockId = resultCustomBlockId; this.resultCustomBlockId = resultCustomBlockId;
} }
/**
* Get the block position
*
* @return the block position
*/
public BlockPosition getBlockPosition() { public BlockPosition getBlockPosition() {
return blockPosition; return blockPosition;
} }
/**
* Get the broken block visual id
*
* @return the block id
*/
public short getBlockId() {
return blockId;
}
/**
* Get the broken custom block
*
* @return the custom block,
* null if not any
*/
public CustomBlock getCustomBlock() {
return customBlock;
}
/**
* Get the visual block id result, which will be placed after the event
*
* @return the block id that will be set at {@link #getBlockPosition()}
* set to 0 to remove
*/
public short getResultBlockId() { public short getResultBlockId() {
return resultBlockId; return resultBlockId;
} }
/**
* Change the visual block id result
*
* @param resultBlockId the result block id
*/
public void setResultBlockId(short resultBlockId) { public void setResultBlockId(short resultBlockId) {
this.resultBlockId = resultBlockId; this.resultBlockId = resultBlockId;
} }
/**
* Get the custom block id result, which will be placed after the event
* <p>
* Warning: the visual block will not be changed, be sure to call {@link #setResultBlockId(short)}
* if you want the visual to be the same as {@link CustomBlock#getBlockId()}
*
* @return the custom block id that will be set at {@link #getBlockPosition()}
* set to 0 to remove
*/
public short getResultCustomBlockId() { public short getResultCustomBlockId() {
return resultCustomBlockId; return resultCustomBlockId;
} }
/**
* Change the custom block id result, which will be placed after the event
*
* @param resultCustomBlockId the custom block id result
*/
public void setResultCustomBlockId(short resultCustomBlockId) { public void setResultCustomBlockId(short resultCustomBlockId) {
this.resultCustomBlockId = resultCustomBlockId; this.resultCustomBlockId = resultCustomBlockId;
} }
public boolean isResultCustomBlock() {
return resultCustomBlockId != 0;
}
} }

View File

@ -1,11 +1,19 @@
package net.minestom.server.event.player; package net.minestom.server.event.player;
import net.minestom.server.MinecraftServer;
import net.minestom.server.entity.Player; import net.minestom.server.entity.Player;
import net.minestom.server.event.CancellableEvent; import net.minestom.server.event.CancellableEvent;
import net.minestom.server.instance.block.BlockManager;
import net.minestom.server.instance.block.CustomBlock;
import net.minestom.server.utils.BlockPosition; import net.minestom.server.utils.BlockPosition;
/**
* Called when a player tries placing a block
*/
public class PlayerBlockPlaceEvent extends CancellableEvent { public class PlayerBlockPlaceEvent extends CancellableEvent {
private static final BlockManager BLOCK_MANAGER = MinecraftServer.getBlockManager();
private final Player player; private final Player player;
private short blockId; private short blockId;
private short customBlockId; private short customBlockId;
@ -23,38 +31,100 @@ public class PlayerBlockPlaceEvent extends CancellableEvent {
this.consumeBlock = true; this.consumeBlock = true;
} }
public void setCustomBlockId(short customBlockId) { /**
this.customBlockId = customBlockId; * Set both the blockId and customBlockId
*
* @param customBlock the custom block to place
*/
public void setCustomBlock(CustomBlock customBlock) {
setBlockId(customBlock.getBlockId());
setCustomBlockId(customBlock.getCustomBlockId());
} }
/**
* Set both the blockId and customBlockId
*
* @param customBlockId the custom block id to place
*/
public void setCustomBlock(short customBlockId) {
CustomBlock customBlock = BLOCK_MANAGER.getCustomBlock(customBlockId);
setCustomBlock(customBlock);
}
/**
* Set both the blockId and customBlockId
*
* @param customBlockId the custom block id to place
*/
public void setCustomBlock(String customBlockId) {
CustomBlock customBlock = BLOCK_MANAGER.getCustomBlock(customBlockId);
setCustomBlock(customBlock);
}
/**
* @return the custom block id to place
*/
public short getCustomBlockId() { public short getCustomBlockId() {
return customBlockId; return customBlockId;
} }
public void setBlockId(short blockId) { /**
this.blockId = blockId; * Set the custom block id to place
* <p>
* WARNING: this does not change the visual block id, see {@link #setBlockId(short)}
* or {@link #setCustomBlock(short)}
*
* @param customBlockId
*/
public void setCustomBlockId(short customBlockId) {
this.customBlockId = customBlockId;
} }
/**
* @return the visual block id to place
*/
public short getBlockId() { public short getBlockId() {
return blockId; return blockId;
} }
/**
* @param blockId the visual block id to place
*/
public void setBlockId(short blockId) {
this.blockId = blockId;
}
/**
* @return the player who is placing the block
*/
public Player getPlayer() { public Player getPlayer() {
return player; return player;
} }
/**
* @return the position of the block to place
*/
public BlockPosition getBlockPosition() { public BlockPosition getBlockPosition() {
return blockPosition; return blockPosition;
} }
/**
* @return the hand with which the player is trying to place
*/
public Player.Hand getHand() { public Player.Hand getHand() {
return hand; return hand;
} }
/**
* @param consumeBlock true if the block should be consumer (-1 amount), false otherwise
*/
public void consumeBlock(boolean consumeBlock) { public void consumeBlock(boolean consumeBlock) {
this.consumeBlock = consumeBlock; this.consumeBlock = consumeBlock;
} }
/**
* @return true if the block will be consumed, false otherwise
*/
public boolean doesConsumeBlock() { public boolean doesConsumeBlock() {
return consumeBlock; return consumeBlock;
} }

View File

@ -8,6 +8,10 @@ import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.function.Function; import java.util.function.Function;
/**
* Called every time a player write and send something in the chat.
* The event can be cancelled to do not send anything, and the format can be changed
*/
public class PlayerChatEvent extends CancellableEvent { public class PlayerChatEvent extends CancellableEvent {
private Player sender; private Player sender;
@ -21,26 +25,52 @@ public class PlayerChatEvent extends CancellableEvent {
this.message = message; this.message = message;
} }
/**
* @param chatFormat the custom chat format
*/
public void setChatFormat(Function<PlayerChatEvent, TextComponent> chatFormat) { public void setChatFormat(Function<PlayerChatEvent, TextComponent> chatFormat) {
this.chatFormat = chatFormat; this.chatFormat = chatFormat;
} }
/**
* @return the sender of the message
*/
public Player getSender() { public Player getSender() {
return sender; return sender;
} }
/**
* This is all the players who will receive the message
* It can be modified to add or remove recipient
*
* @return a modifiable list of message targets
*/
public Collection<Player> getRecipients() { public Collection<Player> getRecipients() {
return recipients; return recipients;
} }
/**
* @return the sender's message
*/
public String getMessage() { public String getMessage() {
return message; return message;
} }
/**
* Used to change the message
*
* @param message the new message
*/
public void setMessage(String message) { public void setMessage(String message) {
this.message = message; this.message = message;
} }
/**
* Used to retrieve the chat format for this message.
* If null, the default format will be used
*
* @return the chat format which will be used
*/
public Function<PlayerChatEvent, TextComponent> getChatFormatFunction() { public Function<PlayerChatEvent, TextComponent> getChatFormatFunction() {
return chatFormat; return chatFormat;
} }

View File

@ -3,6 +3,9 @@ package net.minestom.server.event.player;
import net.minestom.server.entity.Player; import net.minestom.server.entity.Player;
import net.minestom.server.event.Event; import net.minestom.server.event.Event;
/**
* Called when a player receive a new chunk data
*/
public class PlayerChunkLoadEvent extends Event { public class PlayerChunkLoadEvent extends Event {
private Player player; private Player player;
@ -14,14 +17,29 @@ public class PlayerChunkLoadEvent extends Event {
this.chunkZ = chunkZ; this.chunkZ = chunkZ;
} }
/**
* Get the player
*
* @return the player
*/
public Player getPlayer() { public Player getPlayer() {
return player; return player;
} }
/**
* Get the chunk X
*
* @return the chunk X
*/
public int getChunkX() { public int getChunkX() {
return chunkX; return chunkX;
} }
/**
* Get the chunk Z
*
* @return the chunk Z
*/
public int getChunkZ() { public int getChunkZ() {
return chunkZ; return chunkZ;
} }

View File

@ -18,14 +18,29 @@ public class PlayerChunkUnloadEvent extends Event {
this.chunkZ = chunkZ; this.chunkZ = chunkZ;
} }
/**
* Get the player
*
* @return the player
*/
public Player getPlayer() { public Player getPlayer() {
return player; return player;
} }
/**
* Get the chunk X
*
* @return the chunk X
*/
public int getChunkX() { public int getChunkX() {
return chunkX; return chunkX;
} }
/**
* Get the chunk Z
*
* @return the chunk Z
*/
public int getChunkZ() { public int getChunkZ() {
return chunkZ; return chunkZ;
} }

View File

@ -3,6 +3,9 @@ package net.minestom.server.event.player;
import net.minestom.server.entity.Player; import net.minestom.server.entity.Player;
import net.minestom.server.event.CancellableEvent; import net.minestom.server.event.CancellableEvent;
/**
* Called every time a player send a message starting by '/'
*/
public class PlayerCommandEvent extends CancellableEvent { public class PlayerCommandEvent extends CancellableEvent {
private Player player; private Player player;
@ -13,14 +16,25 @@ public class PlayerCommandEvent extends CancellableEvent {
this.command = command; this.command = command;
} }
/**
* @return the player who want to execute the command
*/
public Player getPlayer() { public Player getPlayer() {
return player; return player;
} }
/**
* @return the command that the player wants to execute
*/
public String getCommand() { public String getCommand() {
return command; return command;
} }
/**
* Change the command to execute
*
* @param command the new command
*/
public void setCommand(String command) { public void setCommand(String command) {
this.command = command; this.command = command;
} }

View File

@ -1,6 +1,25 @@
package net.minestom.server.event.player; package net.minestom.server.event.player;
import net.minestom.server.entity.Player;
import net.minestom.server.event.Event; import net.minestom.server.event.Event;
/**
* Called when a player disconnect
*/
public class PlayerDisconnectEvent extends Event { public class PlayerDisconnectEvent extends Event {
private Player player;
public PlayerDisconnectEvent(Player player) {
this.player = player;
}
/**
* Get the player who is disconnecting
*
* @return the player
*/
public Player getPlayer() {
return player;
}
} }

View File

@ -1,16 +1,36 @@
package net.minestom.server.event.player; package net.minestom.server.event.player;
import net.minestom.server.entity.Player;
import net.minestom.server.event.Event; import net.minestom.server.event.Event;
import net.minestom.server.item.ItemStack; import net.minestom.server.item.ItemStack;
/**
* Called when a player is finished eating
*/
public class PlayerEatEvent extends Event { public class PlayerEatEvent extends Event {
private Player player;
private ItemStack foodItem; private ItemStack foodItem;
public PlayerEatEvent(ItemStack foodItem) { public PlayerEatEvent(Player player, ItemStack foodItem) {
this.player = player;
this.foodItem = foodItem; this.foodItem = foodItem;
} }
/**
* Get the player who is finished eating
*
* @return the concerned player
*/
public Player getPlayer() {
return player;
}
/**
* Get the food item that has been eaten
*
* @return the food item
*/
public ItemStack getFoodItem() { public ItemStack getFoodItem() {
return foodItem; return foodItem;
} }

View File

@ -4,20 +4,44 @@ import net.minestom.server.entity.Entity;
import net.minestom.server.entity.Player; import net.minestom.server.entity.Player;
import net.minestom.server.event.Event; import net.minestom.server.event.Event;
/**
* Called when a player interacts (right-click) with an entity
*/
public class PlayerInteractEvent extends Event { public class PlayerInteractEvent extends Event {
private Player player;
private Entity entityTarget; private Entity entityTarget;
private Player.Hand hand; private Player.Hand hand;
public PlayerInteractEvent(Entity entityTarget, Player.Hand hand) { public PlayerInteractEvent(Player player, Entity entityTarget, Player.Hand hand) {
this.player = player;
this.entityTarget = entityTarget; this.entityTarget = entityTarget;
this.hand = hand; this.hand = hand;
} }
/**
* Get the player who is interacting
*
* @return the player
*/
public Player getPlayer() {
return player;
}
/**
* Get the entity with who {@link #getPlayer()} is interacting
*
* @return the entity
*/
public Entity getTarget() { public Entity getTarget() {
return entityTarget; return entityTarget;
} }
/**
* Get with which hand the player interacted with the entity
*
* @return the hand
*/
public Player.Hand getHand() { public Player.Hand getHand() {
return hand; return hand;
} }

View File

@ -1,18 +1,49 @@
package net.minestom.server.event.player; package net.minestom.server.event.player;
import net.minestom.server.entity.Player;
import net.minestom.server.event.Event; import net.minestom.server.event.Event;
import net.minestom.server.instance.Instance; import net.minestom.server.instance.Instance;
/**
* Called at player login, used to define his spawn instance
* <p>
* WARNING: defining the spawning instance is MANDATORY
*/
public class PlayerLoginEvent extends Event { public class PlayerLoginEvent extends Event {
private Player player;
private Instance spawningInstance; private Instance spawningInstance;
public PlayerLoginEvent(Player player) {
this.player = player;
}
/**
* Get the player who is logging
*
* @return the player who is logging
*/
public Player getPlayer() {
return player;
}
/**
* Get the spawning instance of the player
* <p>
* WARNING: this must NOT be null, otherwise the player cannot spawn
*
* @return the spawning instance
*/
public Instance getSpawningInstance() { public Instance getSpawningInstance() {
return spawningInstance; return spawningInstance;
} }
/**
* Change the spawning instance
*
* @param instance the new spawning instance
*/
public void setSpawningInstance(Instance instance) { public void setSpawningInstance(Instance instance) {
this.spawningInstance = instance; this.spawningInstance = instance;
} }
} }

View File

@ -1,16 +1,36 @@
package net.minestom.server.event.player; package net.minestom.server.event.player;
import net.minestom.server.entity.Player;
import net.minestom.server.event.CancellableEvent; import net.minestom.server.event.CancellableEvent;
import net.minestom.server.utils.Position; import net.minestom.server.utils.Position;
/**
* Called when a player is modifying his position
*/
public class PlayerMoveEvent extends CancellableEvent { public class PlayerMoveEvent extends CancellableEvent {
private Player player;
private Position newPosition; private Position newPosition;
public PlayerMoveEvent(float x, float y, float z, float yaw, float pitch) { public PlayerMoveEvent(Player player, Position newPosition) {
this.newPosition = new Position(x, y, z, yaw, pitch); this.player = player;
this.newPosition = newPosition;
} }
/**
* Get the player who is moving
*
* @return the player
*/
public Player getPlayer() {
return player;
}
/**
* Get the target position
*
* @return the new position
*/
public Position getNewPosition() { public Position getNewPosition() {
return newPosition; return newPosition;
} }

View File

@ -1,25 +1,55 @@
package net.minestom.server.event.player; package net.minestom.server.event.player;
import net.minestom.server.entity.Player;
import net.minestom.server.event.Event; import net.minestom.server.event.Event;
/**
* Called when a player send {@link net.minestom.server.network.packet.client.play.ClientPluginMessagePacket}
*/
public class PlayerPluginMessageEvent extends Event { public class PlayerPluginMessageEvent extends Event {
private Player player;
private String identifier; private String identifier;
private byte[] message; private byte[] message;
public PlayerPluginMessageEvent(String identifier, byte[] message) { public PlayerPluginMessageEvent(Player player, String identifier, byte[] message) {
this.player = player;
this.identifier = identifier; this.identifier = identifier;
this.message = message; this.message = message;
} }
/**
* Get the player who sent the message
*
* @return the player
*/
public Player getPlayer() {
return player;
}
/**
* Get the message identifier
*
* @return the identifier
*/
public String getIdentifier() { public String getIdentifier() {
return identifier; return identifier;
} }
/**
* Get the message data as a byte array
*
* @return the message
*/
public byte[] getMessage() { public byte[] getMessage() {
return message; return message;
} }
/**
* Get the message data as a String
*
* @return the message
*/
public String getMessageString() { public String getMessageString() {
return new String(message); return new String(message);
} }

View File

@ -21,18 +21,40 @@ public class PlayerPreEatEvent extends CancellableEvent {
this.eatingTime = eatingTime; this.eatingTime = eatingTime;
} }
/**
* The player who is trying to eat
*
* @return the concerned player
*/
public Player getPlayer() { public Player getPlayer() {
return player; return player;
} }
/**
* The food item which will be eaten
*
* @return the food item
*/
public ItemStack getFoodItem() { public ItemStack getFoodItem() {
return foodItem; return foodItem;
} }
/**
* Get the food eating time
* <p>
* This is by default {@link Player#getDefaultEatingTime()}
*
* @return the eating time
*/
public long getEatingTime() { public long getEatingTime() {
return eatingTime; return eatingTime;
} }
/**
* Change the food eating time
*
* @param eatingTime the new eating time
*/
public void setEatingTime(long eatingTime) { public void setEatingTime(long eatingTime) {
this.eatingTime = eatingTime; this.eatingTime = eatingTime;
} }

View File

@ -0,0 +1,37 @@
package net.minestom.server.event.player;
import net.minestom.server.entity.Player;
import net.minestom.server.event.Event;
import net.minestom.server.resourcepack.ResourcePackStatus;
/**
* Called when a player warns the server of a resource pack status
*/
public class PlayerResourcePackStatusEvent extends Event {
private Player player;
private ResourcePackStatus status;
public PlayerResourcePackStatusEvent(Player player, ResourcePackStatus status) {
this.player = player;
this.status = status;
}
/**
* Get the player who send a resource pack status
*
* @return the player
*/
public Player getPlayer() {
return player;
}
/**
* Get the resource pack status
*
* @return the resource pack status
*/
public ResourcePackStatus getStatus() {
return status;
}
}

View File

@ -1,20 +1,46 @@
package net.minestom.server.event.player; package net.minestom.server.event.player;
import net.minestom.server.entity.Player;
import net.minestom.server.event.Event; import net.minestom.server.event.Event;
import net.minestom.server.utils.Position; import net.minestom.server.utils.Position;
/**
* Called when {@link Player#respawn()} is executed (for custom respawn or as a result of
* {@link net.minestom.server.network.packet.client.play.ClientStatusPacket}
*/
public class PlayerRespawnEvent extends Event { public class PlayerRespawnEvent extends Event {
private Player player;
private Position respawnPosition; private Position respawnPosition;
public PlayerRespawnEvent(Position respawnPosition) { public PlayerRespawnEvent(Player player, Position respawnPosition) {
this.player = player;
this.respawnPosition = respawnPosition; this.respawnPosition = respawnPosition;
} }
/**
* Get the player who is respawning
*
* @return the player
*/
public Player getPlayer() {
return player;
}
/**
* Get the respawn position
*
* @return the respawn position
*/
public Position getRespawnPosition() { public Position getRespawnPosition() {
return respawnPosition; return respawnPosition;
} }
/**
* Change the respawn position
*
* @param respawnPosition the new respawn position
*/
public void setRespawnPosition(Position respawnPosition) { public void setRespawnPosition(Position respawnPosition) {
this.respawnPosition = respawnPosition; this.respawnPosition = respawnPosition;
} }

View File

@ -0,0 +1,69 @@
package net.minestom.server.event.player;
import net.minestom.server.entity.Player;
import net.minestom.server.event.CancellableEvent;
import net.minestom.server.item.ItemStack;
import net.minestom.server.utils.item.ItemStackUtils;
/**
* Called as a result of {@link net.minestom.server.inventory.PlayerInventory#setItemStack(int, ItemStack)}
* and player click in his inventory
*/
public class PlayerSetItemStackEvent extends CancellableEvent {
private Player player;
private int slot;
private ItemStack itemStack;
public PlayerSetItemStackEvent(Player player, int slot, ItemStack itemStack) {
this.player = player;
this.slot = slot;
this.itemStack = itemStack;
}
/**
* Get the player who has an item stack set to his inventory
*
* @return the player
*/
public Player getPlayer() {
return player;
}
/**
* Get the slot where the item will be set
*
* @return the slot
*/
public int getSlot() {
return slot;
}
/**
* Change the slot where the item will be set
*
* @param slot the new slot
*/
public void setSlot(int slot) {
this.slot = slot;
}
/**
* Get the item stack which will be set
*
* @return the item stack
*/
public ItemStack getItemStack() {
return itemStack;
}
/**
* Change the item stack which will be set
*
* @param itemStack the new item stack
*/
public void setItemStack(ItemStack itemStack) {
this.itemStack = ItemStackUtils.notNull(itemStack);
}
}

View File

@ -0,0 +1,45 @@
package net.minestom.server.event.player;
import net.minestom.server.entity.Player;
import net.minestom.server.entity.PlayerSkin;
import net.minestom.server.event.Event;
/**
* Called at the player connection to initialize his skin
*/
public class PlayerSkinInitEvent extends Event {
private Player player;
private PlayerSkin skin;
public PlayerSkinInitEvent(Player player) {
this.player = player;
}
/**
* Get the player whose the skin is getting initialized
*
* @return
*/
public Player getPlayer() {
return player;
}
/**
* Get the spawning skin of the player
*
* @return the player skin, or null if not any
*/
public PlayerSkin getSkin() {
return skin;
}
/**
* Set the spawning skin of the player
*
* @param skin the new player skin
*/
public void setSkin(PlayerSkin skin) {
this.skin = skin;
}
}

View File

@ -3,6 +3,9 @@ package net.minestom.server.event.player;
import net.minestom.server.event.entity.EntitySpawnEvent; import net.minestom.server.event.entity.EntitySpawnEvent;
import net.minestom.server.instance.Instance; import net.minestom.server.instance.Instance;
/**
* Called when a new instance is set for a player
*/
public class PlayerSpawnEvent extends EntitySpawnEvent { public class PlayerSpawnEvent extends EntitySpawnEvent {
private final boolean firstSpawn; private final boolean firstSpawn;
@ -13,7 +16,8 @@ public class PlayerSpawnEvent extends EntitySpawnEvent {
/** /**
* 'true' if the player is spawning for the first time. 'false' if this spawn event was triggered by a dimension teleport * 'true' if the player is spawning for the first time. 'false' if this spawn event was triggered by a dimension teleport
* @return *
* @return true if this is the first spawn, false otherwise
*/ */
public boolean isFirstSpawn() { public boolean isFirstSpawn() {
return firstSpawn; return firstSpawn;

View File

@ -1,24 +1,52 @@
package net.minestom.server.event.player; package net.minestom.server.event.player;
import net.minestom.server.entity.Player;
import net.minestom.server.event.CancellableEvent; import net.minestom.server.event.CancellableEvent;
import net.minestom.server.instance.block.CustomBlock; import net.minestom.server.instance.block.CustomBlock;
import net.minestom.server.utils.BlockPosition; import net.minestom.server.utils.BlockPosition;
/**
* Called when a player start digging a {@link CustomBlock},
* can be used to forbid the player from mining a block
* <p>
* WARNING: this is not called for non-custom block
*/
public class PlayerStartDiggingEvent extends CancellableEvent { public class PlayerStartDiggingEvent extends CancellableEvent {
private Player player;
private BlockPosition blockPosition; private BlockPosition blockPosition;
private CustomBlock customBlock; private CustomBlock customBlock;
public PlayerStartDiggingEvent(BlockPosition blockPosition, CustomBlock customBlock) { public PlayerStartDiggingEvent(Player player, BlockPosition blockPosition, CustomBlock customBlock) {
this.player = player;
this.blockPosition = blockPosition; this.blockPosition = blockPosition;
this.customBlock = customBlock; this.customBlock = customBlock;
} }
/**
* Get the player who started digging the block
*
* @return the player
*/
public Player getPlayer() {
return player;
}
/**
* Get the block position
*
* @return the block position
*/
public BlockPosition getBlockPosition() { public BlockPosition getBlockPosition() {
return blockPosition; return blockPosition;
} }
public CustomBlock getBlock() { /**
* Get the custom block object that the player is trying to dig
*
* @return the custom block
*/
public CustomBlock getCustomBlock() {
return customBlock; return customBlock;
} }
} }

View File

@ -3,6 +3,9 @@ package net.minestom.server.event.player;
import net.minestom.server.entity.Player; import net.minestom.server.entity.Player;
import net.minestom.server.event.Event; import net.minestom.server.event.Event;
/**
* Called when a player start flying
*/
public class PlayerStartFlyingEvent extends Event { public class PlayerStartFlyingEvent extends Event {
private Player player; private Player player;
@ -11,6 +14,11 @@ public class PlayerStartFlyingEvent extends Event {
this.player = player; this.player = player;
} }
/**
* Get the player who started flying
*
* @return the player
*/
public Player getPlayer() { public Player getPlayer() {
return player; return player;
} }

View File

@ -3,6 +3,9 @@ package net.minestom.server.event.player;
import net.minestom.server.entity.Player; import net.minestom.server.entity.Player;
import net.minestom.server.event.Event; import net.minestom.server.event.Event;
/**
* Called when a player stop flying
*/
public class PlayerStopFlyingEvent extends Event { public class PlayerStopFlyingEvent extends Event {
private Player player; private Player player;
@ -11,6 +14,11 @@ public class PlayerStopFlyingEvent extends Event {
this.player = player; this.player = player;
} }
/**
* Get the player who stopped flying
*
* @return the player
*/
public Player getPlayer() { public Player getPlayer() {
return player; return player;
} }

View File

@ -1,30 +1,65 @@
package net.minestom.server.event.player; package net.minestom.server.event.player;
import net.minestom.server.entity.Player;
import net.minestom.server.event.CancellableEvent; import net.minestom.server.event.CancellableEvent;
import net.minestom.server.item.ItemStack; import net.minestom.server.item.ItemStack;
/**
* Called when a player is trying to swap his main and off hand item
*/
public class PlayerSwapItemEvent extends CancellableEvent { public class PlayerSwapItemEvent extends CancellableEvent {
private Player player;
private ItemStack mainHandItem; private ItemStack mainHandItem;
private ItemStack offHandItem; private ItemStack offHandItem;
public PlayerSwapItemEvent(ItemStack mainHandItem, ItemStack offHandItem) { public PlayerSwapItemEvent(Player player, ItemStack mainHandItem, ItemStack offHandItem) {
this.player = player;
this.mainHandItem = mainHandItem; this.mainHandItem = mainHandItem;
this.offHandItem = offHandItem; this.offHandItem = offHandItem;
} }
/**
* Get the player who is trying to swap his hands item
*
* @return the player
*/
public Player getPlayer() {
return player;
}
/**
* Get the item which will be in player main hand after the event
*
* @return the item in main hand
*/
public ItemStack getMainHandItem() { public ItemStack getMainHandItem() {
return mainHandItem; return mainHandItem;
} }
/**
* Change the item which will be in the player main hand
*
* @param mainHandItem the main hand item
*/
public void setMainHandItem(ItemStack mainHandItem) { public void setMainHandItem(ItemStack mainHandItem) {
this.mainHandItem = mainHandItem; this.mainHandItem = mainHandItem;
} }
/**
* Get the item which will be in player off hand after the event
*
* @return the item in off hand
*/
public ItemStack getOffHandItem() { public ItemStack getOffHandItem() {
return offHandItem; return offHandItem;
} }
/**
* Change the item which will be in the player off hand
*
* @param offHandItem the off hand item
*/
public void setOffHandItem(ItemStack offHandItem) { public void setOffHandItem(ItemStack offHandItem) {
this.offHandItem = offHandItem; this.offHandItem = offHandItem;
} }

View File

@ -3,6 +3,9 @@ package net.minestom.server.event.player;
import net.minestom.server.entity.Player; import net.minestom.server.entity.Player;
import net.minestom.server.event.Event; import net.minestom.server.event.Event;
/**
* Called at each player tick
*/
public class PlayerTickEvent extends Event { public class PlayerTickEvent extends Event {
private Player player; private Player player;
@ -11,6 +14,11 @@ public class PlayerTickEvent extends Event {
this.player = player; this.player = player;
} }
/**
* Get the player
*
* @return the player
*/
public Player getPlayer() { public Player getPlayer() {
return player; return player;
} }

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