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'
// 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
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
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'
@ -66,4 +64,8 @@ dependencies {
api 'net.kyori:text-serializer-legacy:3.0.3'
api 'net.kyori:text-serializer-gson: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.NoiseTestGenerator;
import net.minestom.server.MinecraftServer;
import net.minestom.server.attribute.Attribute;
import net.minestom.server.benchmark.BenchmarkManager;
import net.minestom.server.benchmark.ThreadResult;
import net.minestom.server.entity.*;
@ -39,6 +40,11 @@ import java.util.UUID;
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 netherTest;
@ -95,16 +101,15 @@ public class PlayerInit {
benchmarkMessage += "&e" + MathUtils.round(result.getCpuPercentage(), 2) + "% CPU ";
benchmarkMessage += "&c" + MathUtils.round(result.getUserPercentage(), 2) + "% USER ";
benchmarkMessage += "&d" + MathUtils.round(result.getBlockedPercentage(), 2) + "% BLOCKED ";
benchmarkMessage += "&a" + MathUtils.round(result.getWaitedPercentage(), 2) + "% WAITED ";
benchmarkMessage += "\n";
}
// if (benchmarkMessage.length() > 0)
// System.out.println(benchmarkMessage);
for (Player player : connectionManager.getOnlinePlayers()) {
player.sendHeaderFooter("RAM USAGE: " + ramUsage + " MB", benchmarkMessage, '&');
}
}
}, new UpdateOption(5, TimeUnit.TICK));
}, new UpdateOption(10, TimeUnit.TICK));
connectionManager.addPacketConsumer((player, packetController, packet) -> {
// Listen to all received packet
@ -137,10 +142,10 @@ public class PlayerInit {
return;
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()) {
event.setCustomBlockId((short) 3); // custom torch block
event.setCustomBlock((short) 3); // custom torch block
}
/*for (Player p : player.getInstance().getPlayers()) {
@ -150,6 +155,7 @@ public class PlayerInit {
ChickenCreature chickenCreature = new ChickenCreature(player.getPosition());
chickenCreature.setInstance(player.getInstance());
chickenCreature.setAttribute(Attribute.MOVEMENT_SPEED, 0.4f);
/*FakePlayer fakePlayer = new FakePlayer(UUID.randomUUID(), "test");
fakePlayer.addEventCallback(EntityDeathEvent.class, e -> {
@ -211,19 +217,24 @@ public class PlayerInit {
scoreboard.setTitle("test");*/
});
player.addEventCallback(PlayerSkinInitEvent.class, event -> {
event.setSkin(skin);
});
player.addEventCallback(PlayerSpawnEvent.class, event -> {
player.setGameMode(GameMode.CREATIVE);
player.teleport(new Position(0, 45, 0));
player.teleport(new Position(0, 41f, 0));
player.setGlowing(true);
ItemStack item = new ItemStack(Material.STONE_SWORD, (byte) 1);
item.setDisplayName("Item name");
item.getLore().add("a lore line");
item.addItemFlags(ItemFlag.HIDE_ATTRIBUTES);
item.setEnchantment(Enchantment.SHARPNESS, (short) 2);
item.addItemFlags(ItemFlag.HIDE_ENCHANTS);
item.setEnchantment(Enchantment.SHARPNESS, (short) 50);
player.getInventory().addItemStack(item);
inventory.addItemStack(item.clone());
player.openInventory(inventory);
player.getInventory().addItemStack(new ItemStack(Material.STONE, (byte) 100));
@ -256,7 +267,7 @@ public class PlayerInit {
});
player.addEventCallback(PlayerRespawnEvent.class, event -> {
event.setRespawnPosition(new Position(0f, 45f, 0f));
event.setRespawnPosition(new Position(0f, 41f, 0f));
});
player.addEventCallback(PlayerUseItemEvent.class, useEvent -> {
@ -301,7 +312,7 @@ public class PlayerInit {
public static ResponseDataConsumer getResponseDataConsumer() {
return (playerConnection, responseData) -> {
responseData.setMaxPlayer(100);
responseData.setMaxPlayer(0);
responseData.setOnline(MinecraftServer.getConnectionManager().getOnlinePlayers().size());
responseData.addPlayer("A name", 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.command.CommandProcessor;
import net.minestom.server.command.CommandSender;
import net.minestom.server.entity.Player;
import net.minestom.server.instance.Instance;
import net.minestom.server.world.Dimension;
@ -20,22 +21,27 @@ public class DimensionCommand implements CommandProcessor {
}
@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();
Dimension targetDimension = Dimension.NETHER;
if(instance.getDimension() == Dimension.NETHER) {
if (instance.getDimension() == Dimension.NETHER) {
targetDimension = Dimension.OVERWORLD;
}
Dimension finalTargetDimension = targetDimension;
Optional<Instance> targetInstance = MinecraftServer.getInstanceManager().getInstances().stream().filter(in -> in.getDimension() == finalTargetDimension).findFirst();
if(targetInstance.isPresent()) {
player.sendMessage("You were in "+instance.getDimension());
if (targetInstance.isPresent()) {
player.sendMessage("You were in " + instance.getDimension());
player.setInstance(targetInstance.get());
player.sendMessage("You are now in "+targetDimension);
player.sendMessage("You are now in " + targetDimension);
} else {
player.sendMessage("Could not find instance with dimension "+targetDimension);
player.sendMessage("Could not find instance with dimension " + targetDimension);
}
return true;

View File

@ -4,6 +4,7 @@ import fr.themode.command.Arguments;
import fr.themode.command.Command;
import fr.themode.command.arguments.Argument;
import fr.themode.command.arguments.ArgumentType;
import net.minestom.server.command.CommandSender;
import net.minestom.server.entity.GameMode;
import net.minestom.server.entity.Player;
@ -12,7 +13,7 @@ import java.util.Optional;
/**
* Command that make a player change gamemode
*/
public class GamemodeCommand extends Command<Player> {
public class GamemodeCommand extends Command<CommandSender> {
public GamemodeCommand() {
super("gamemode", "g", "gm");
@ -35,11 +36,13 @@ public class GamemodeCommand extends Command<Player> {
addSyntax(this::executeOnOther, player, mode);
}
private void usage(Player player, Arguments arguments) {
player.sendMessage("Usage: /gamemode [player] <gamemode>");
private void usage(CommandSender sender, Arguments arguments) {
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");
GameMode mode = GameMode.valueOf(gamemodeName.toUpperCase());
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);
}
private void executeOnOther(Player player, Arguments arguments) {
private void executeOnOther(CommandSender sender, Arguments arguments) {
Player player = (Player) sender;
String gamemodeName = arguments.getWord("mode");
String targetName = arguments.getWord("player");
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) {
player.sendMessage("'" + gamemode + "' is not a valid gamemode!");
private void gameModeCallback(CommandSender sender, String gamemode, int error) {
sender.sendMessage("'" + gamemode + "' is not a valid gamemode!");
}
private boolean isAllowed(Player player) {
return true; // TODO: permissions
private boolean isAllowed(CommandSender sender) {
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.ArgumentType;
import fr.themode.command.arguments.number.ArgumentNumber;
import net.minestom.server.command.CommandSender;
import net.minestom.server.entity.Player;
public class HealthCommand extends Command<Player> {
public class HealthCommand extends Command<CommandSender> {
public HealthCommand() {
super("health", "h", "healthbar");
@ -27,39 +28,39 @@ public class HealthCommand extends Command<Player> {
addSyntax(this::execute2, arg0, arg1);
}
private boolean condition(Player player) {
boolean hasPerm = true;
if (!hasPerm) {
player.sendMessage("You do not have permission !");
private boolean condition(CommandSender sender) {
if (!(sender instanceof Player)) {
sender.sendMessage("The command is only available for player");
return false;
}
return true;
}
private void defaultExecutor(Player player, Arguments args) {
player.sendMessage("Correct usage: health [set/add] [number]");
private void defaultExecutor(CommandSender sender, Arguments args) {
sender.sendMessage("Correct usage: health [set/add] [number]");
}
private void modeCallback(Player player, String value, int error) {
player.sendMessage("SYNTAX ERROR: '" + value + "' should be replaced by 'set' or 'add'");
private void modeCallback(CommandSender sender, String value, int error) {
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) {
case ArgumentNumber.NOT_NUMBER_ERROR:
player.sendMessage("SYNTAX ERROR: '" + value + "' isn't a number!");
sender.sendMessage("SYNTAX ERROR: '" + value + "' isn't a number!");
break;
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;
}
}
private void execute(Player player, Arguments args) {
player.sendMessage("/health " + args.getWord("mode") + " [Integer]");
private void execute(CommandSender sender, Arguments args) {
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");
int value = args.getInteger("value");

View File

@ -1,7 +1,15 @@
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.CommandSender;
import net.minestom.server.entity.Player;
import net.minestom.server.instance.Instance;
import java.util.Iterator;
public class SimpleCommand implements CommandProcessor {
@Override
@ -15,7 +23,11 @@ public class SimpleCommand implements CommandProcessor {
}
@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()) {
if (!(p instanceof FakePlayer))
@ -35,9 +47,33 @@ public class SimpleCommand implements CommandProcessor {
break;
}*/
System.gc();
player.sendMessage("Garbage collector called");
/*for (EntityCreature entityCreature : player.getInstance().getCreatures()) {
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;
}

View File

@ -1,19 +1,16 @@
package fr.themode.demo.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.type.EntityChicken;
import net.minestom.server.entity.vehicle.PlayerVehicleInformation;
import net.minestom.server.utils.Position;
import net.minestom.server.utils.Vector;
public class ChickenCreature extends EntityCreature {
public class ChickenCreature extends EntityChicken {
public ChickenCreature(Position defaultPosition) {
super(EntityType.CHICKEN, defaultPosition);
setBoundingBox(0.4f, 0.7f, 0.4f);
super(defaultPosition);
}
@Override
@ -22,8 +19,8 @@ public class ChickenCreature extends EntityCreature {
}
@Override
public void update() {
super.update();
public void update(long time) {
super.update(time);
float speed = 0.075f;
if (hasPassenger()) {
@ -80,10 +77,7 @@ public class ChickenCreature extends EntityCreature {
move(x, 0, z, updateView);
}
} 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;
}
@Override
public void update() {
}
@Override
public void spawn() {
}
@Override
public int getObjectData() {
return shooter.getEntityId() + 1;

View File

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

View File

@ -36,7 +36,6 @@ public class MinecraftServer {
public static final String THREAD_NAME_BENCHMARK = "Ms-Benchmark";
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 int THREAD_COUNT_PACKET_WRITER = 2;

View File

@ -1,5 +1,7 @@
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.Player;
import net.minestom.server.instance.InstanceManager;
@ -10,19 +12,27 @@ import net.minestom.server.utils.thread.MinestomThread;
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;
/**
* Should only be created in MinecraftServer
*/
protected UpdateManager() {
}
public void start() {
mainUpdate.execute(() -> {
ConnectionManager connectionManager = MinecraftServer.getConnectionManager();
EntityManager entityManager = MinecraftServer.getEntityManager();
InstanceManager instanceManager = MinecraftServer.getInstanceManager();
SchedulerManager schedulerManager = MinecraftServer.getSchedulerManager();
final ConnectionManager connectionManager = MinecraftServer.getConnectionManager();
final EntityManager entityManager = MinecraftServer.getEntityManager();
final InstanceManager instanceManager = MinecraftServer.getInstanceManager();
final SchedulerManager schedulerManager = MinecraftServer.getSchedulerManager();
final long tickDistance = MinecraftServer.TICK_MS * 1000000;
long currentTime;
@ -30,12 +40,17 @@ public class UpdateManager {
currentTime = System.nanoTime();
// Keep Alive Handling
final long time = System.currentTimeMillis();
final KeepAlivePacket keepAlivePacket = new KeepAlivePacket(time);
for (Player player : connectionManager.getOnlinePlayers()) {
long time = System.currentTimeMillis();
if (time - player.getLastKeepAlive() > 10000) {
final long lastKeepAlive = time - player.getLastKeepAlive();
if (lastKeepAlive > KEEP_ALIVE_DELAY && player.didAnswerKeepAlive()) {
player.refreshKeepAlive(time);
KeepAlivePacket keepAlivePacket = new KeepAlivePacket(time);
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 {
@ -37,4 +37,12 @@ public enum Attribute {
public float getMaxVanillaValue() {
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> lastUserTimeMap = new HashMap<>();
private Map<Long, Long> lastWaitedMap = new HashMap<>();
private Map<Long, Long> lastBlockedMap = new HashMap<>();
private Map<String, ThreadResult> resultMap = new ConcurrentHashMap<>();
@ -100,26 +101,30 @@ public class BenchmarkManager {
long lastCpuTime = lastCpuTimeMap.getOrDefault(id, 0L);
long lastUserTime = lastUserTimeMap.getOrDefault(id, 0L);
long lastWaitedTime = lastWaitedMap.getOrDefault(id, 0L);
long lastBlockedTime = lastBlockedMap.getOrDefault(id, 0L);
long blockedTime = threadInfo2.getBlockedTime();
//long waitedTime = threadInfo2.getWaitedTime();
long waitedTime = threadInfo2.getWaitedTime();
long cpuTime = threadMXBean.getThreadCpuTime(id);
long userTime = threadMXBean.getThreadUserTime(id);
lastCpuTimeMap.put(id, cpuTime);
lastUserTimeMap.put(id, userTime);
lastWaitedMap.put(id, waitedTime);
lastBlockedMap.put(id, blockedTime);
double totalCpuTime = (double) (cpuTime - lastCpuTime) / 1000000D;
double totalUserTime = (double) (userTime - lastUserTime) / 1000000D;
long totalBlocked = blockedTime - lastBlockedTime;
long totalWaited = waitedTime - lastWaitedTime;
double cpuPercentage = totalCpuTime / (double) time * 100L;
double userPercentage = totalUserTime / (double) time * 100L;
double waitedPercentage = totalWaited / (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);
}
}

View File

@ -2,11 +2,12 @@ package net.minestom.server.benchmark;
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.userPercentage = userPercentage;
this.waitedPercentage = waitedPercentage;
this.blockedPercentage = blockedPercentage;
}
@ -18,6 +19,10 @@ public class ThreadResult {
return userPercentage;
}
public double getWaitedPercentage() {
return waitedPercentage;
}
public double getBlockedPercentage() {
return blockedPercentage;
}

View File

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

View File

@ -21,12 +21,24 @@ public class BoundingBox {
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) {
return (getMinX() <= boundingBox.getMaxX() && getMaxX() >= boundingBox.getMinX()) &&
(getMinY() <= boundingBox.getMaxY() && getMaxY() >= boundingBox.getMinY()) &&
(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) {
final float x = blockPosition.getX();
@ -62,10 +74,22 @@ public class BoundingBox {
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) {
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) {
return new BoundingBox(entity, this.x - x, this.y - y, this.z - z);
}
@ -107,7 +131,7 @@ public class BoundingBox {
}
public Vector[] getBottomFace() {
return new Vector[] {
return new Vector[]{
new Vector(getMinX(), getMinY(), getMinZ()),
new Vector(getMaxX(), getMinY(), getMinZ()),
new Vector(getMaxX(), getMinY(), getMaxZ()),
@ -116,7 +140,7 @@ public class BoundingBox {
}
public Vector[] getTopFace() {
return new Vector[] {
return new Vector[]{
new Vector(getMinX(), getMaxY(), getMinZ()),
new Vector(getMaxX(), getMaxY(), getMinZ()),
new Vector(getMaxX(), getMaxY(), getMaxZ()),
@ -125,7 +149,7 @@ public class BoundingBox {
}
public Vector[] getLeftFace() {
return new Vector[] {
return new Vector[]{
new Vector(getMinX(), getMinY(), getMinZ()),
new Vector(getMinX(), getMaxY(), getMinZ()),
new Vector(getMinX(), getMaxY(), getMaxZ()),
@ -134,7 +158,7 @@ public class BoundingBox {
}
public Vector[] getRightFace() {
return new Vector[] {
return new Vector[]{
new Vector(getMaxX(), getMinY(), getMinZ()),
new Vector(getMaxX(), getMaxY(), getMinZ()),
new Vector(getMaxX(), getMaxY(), getMaxZ()),
@ -143,7 +167,7 @@ public class BoundingBox {
}
public Vector[] getFrontFace() {
return new Vector[] {
return new Vector[]{
new Vector(getMinX(), getMinY(), getMinZ()),
new Vector(getMaxX(), getMinY(), getMinZ()),
new Vector(getMaxX(), getMaxY(), getMinZ()),
@ -152,7 +176,7 @@ public class BoundingBox {
}
public Vector[] getBackFace() {
return new Vector[] {
return new Vector[]{
new Vector(getMinX(), getMinY(), getMaxZ()),
new Vector(getMaxX(), getMinY(), 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.validate.Check;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.*;
public class CommandManager {
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<>();
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);
}
@ -29,20 +43,24 @@ public class CommandManager {
this.commandProcessorMap.put(commandProcessor.getCommandName().toLowerCase(), commandProcessor);
}
public boolean execute(Player source, String command) {
Check.notNull(source, "Source cannot be null");
public boolean execute(CommandSender sender, String command) {
Check.notNull(sender, "Source cannot be null");
Check.notNull(command, "Command string cannot be null");
PlayerCommandEvent playerCommandEvent = new PlayerCommandEvent(source, command);
source.callEvent(PlayerCommandEvent.class, playerCommandEvent);
if (sender instanceof Player) {
Player player = (Player) sender;
if (playerCommandEvent.isCancelled())
return false;
PlayerCommandEvent playerCommandEvent = new PlayerCommandEvent(player, command);
player.callEvent(PlayerCommandEvent.class, playerCommandEvent);
command = playerCommandEvent.getCommand();
if (playerCommandEvent.isCancelled())
return false;
command = playerCommandEvent.getCommand();
}
try {
this.dispatcher.execute(source, command);
this.dispatcher.execute(sender, command);
return true;
} catch (NullPointerException e) {
String[] splitted = command.split(" ");
@ -53,7 +71,7 @@ public class CommandManager {
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;
}
public ConsoleSender getConsoleSender() {
return consoleSender;
}
public DeclareCommandsPacket createDeclareCommandsPacket(Player player) {
return buildPacket(player);
}
@ -74,7 +96,7 @@ public class CommandManager {
DeclareCommandsPacket declareCommandsPacket = new DeclareCommandsPacket();
List<String> commands = new ArrayList<>();
for (Command<Player> command : dispatcher.getCommands()) {
for (Command<CommandSender> command : dispatcher.getCommands()) {
CommandCondition<Player> commandCondition = command.getCondition();
if (commandCondition != null) {
// Do not show command if return false

View File

@ -8,7 +8,7 @@ public interface CommandProcessor {
String[] getAliases();
boolean process(Player player, String command, String[] args);
boolean process(CommandSender sender, String command, String[] args);
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() {
@Override
public <T> void set(String key, T value, Class<T> type) {}
public <T> void set(String key, T value, Class<T> type) {
}
@Override
public <T> T get(String key) {
@ -41,6 +42,8 @@ public class Data {
}
/**
* Get if the data has a key
*
* @param key
* @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
*/
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
*/
public boolean isEmpty() {
return data.isEmpty();
}
/**
* Clone this data
*
* @return a cloned data object
*/
public Data clone() {
Data data = new 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.item.ItemStack;
import net.minestom.server.utils.PrimitiveConversion;
import net.minestom.server.utils.validate.Check;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
public class DataManager {
public final class DataManager {
private Map<Class, DataType> dataTypeMap = new HashMap<>();
@ -42,6 +44,8 @@ public class DataManager {
registerType(String.class, new StringData());
registerType(String[].class, new StringArrayData());
registerType(UUID.class, new UuidType());
registerType(SerializableData.class, new SerializableDataData());
registerType(ItemStack.class, new ItemStackData());
@ -50,14 +54,27 @@ public class DataManager {
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) {
clazz = PrimitiveConversion.getObjectClass(clazz);
if (dataTypeMap.containsKey(clazz))
throw new UnsupportedOperationException("Type " + clazz.getName() + " has already been registed");
Check.stateCondition(dataTypeMap.containsKey(clazz),
"Type " + clazz.getName() + " has already been registered");
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) {
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.EntityVelocityEvent;
import net.minestom.server.event.handler.EventHandler;
import net.minestom.server.instance.Chunk;
import net.minestom.server.instance.Instance;
import net.minestom.server.instance.WorldBorder;
import net.minestom.server.instance.*;
import net.minestom.server.instance.block.CustomBlock;
import net.minestom.server.network.packet.PacketWriter;
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_ROTATION = 8;
protected static final byte METADATA_POSITION = 9;
protected static final byte METADATA_PARTICLE = 15;
protected static final byte METADATA_POSE = 18;
protected Instance instance;
protected Position position;
protected float lastX, lastY, lastZ;
protected float cacheX, cacheY, cacheZ; // Used to synchronize with #getPosition
protected float lastYaw, lastPitch;
protected float cacheYaw, cachePitch;
private int id;
private BoundingBox boundingBox;
@ -140,8 +141,10 @@ public abstract class Entity implements Viewable, EventHandler, DataContainer {
/**
* 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
@ -205,6 +208,39 @@ public abstract class Entity implements Viewable, EventHandler, DataContainer {
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
* 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) {
Check.notNull(player, "Viewer cannot be null");
boolean result = this.viewers.add(player);
if (!result)
return false;
player.viewableEntities.add(this);
return result;
}
@ -263,6 +301,11 @@ public abstract class Entity implements Viewable, EventHandler, DataContainer {
this.data = data;
}
/**
* Update the entity, called every tick
*
* @param time update time in milliseconds
*/
public void tick(long time) {
if (instance == null)
return;
@ -286,6 +329,21 @@ public abstract class Entity implements Viewable, EventHandler, DataContainer {
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)) {
this.lastUpdate = time;
@ -393,16 +451,16 @@ public abstract class Entity implements Viewable, EventHandler, DataContainer {
handleVoid();
// Call the abstract update method
update();
update(time);
ticks++;
callEvent(EntityTickEvent.class, tickEvent); // reuse tickEvent to avoid recreating it each tick
}
// Scheduled synchronization
if (time - lastSynchronizationTime >= synchronizationDelay) {
lastSynchronizationTime = time;
sendSynchronization();
}
// Scheduled synchronization
if (time - lastSynchronizationTime >= synchronizationDelay) {
lastSynchronizationTime = time;
sendSynchronization();
}
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() {
return ticks;
@ -438,6 +496,15 @@ public abstract class Entity implements Viewable, EventHandler, DataContainer {
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
public <E extends Event> List<EventCallback> getEventCallbacks(Class<E> eventClass) {
Check.notNull(eventClass, "Event class cannot be null");
@ -454,30 +521,73 @@ public abstract class Entity implements Viewable, EventHandler, DataContainer {
return id;
}
/**
* Return the entity type id, can convert using {@link EntityType#fromId(int)}
*
* @return the entity type id
*/
public int getEntityType() {
return entityType;
}
/**
* Get the entity UUID
*
* @return the entity UUID
*/
public UUID getUuid() {
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() {
return isActive;
}
/**
* Is used to check collision with coordinates or other blocks/entities
*
* @return the entity bounding box
*/
public BoundingBox getBoundingBox() {
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) {
this.boundingBox = new BoundingBox(this, x, y, z);
}
/**
* Get the entity current instance
*
* @return the entity instance
*/
public Instance getInstance() {
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) {
Check.notNull(instance, "instance cannot be null!");
Check.stateCondition(!MinecraftServer.getInstanceManager().getInstances().contains(instance),
@ -495,16 +605,22 @@ public abstract class Entity implements Viewable, EventHandler, DataContainer {
callEvent(EntitySpawnEvent.class, entitySpawnEvent);
}
/**
* Get the entity current velocity
*
* @return the entity current velocity
*/
public Vector getVelocity() {
return velocity;
}
public boolean hasVelocity() {
return velocity.getX() != 0 ||
velocity.getY() != 0 ||
velocity.getZ() != 0;
}
/**
* Change the entity velocity and calls {@link EntityVelocityEvent}.
* <p>
* The final velocity can be cancelled or modified by the event
*
* @param velocity the new entity velocity
*/
public void setVelocity(Vector velocity) {
EntityVelocityEvent entityVelocityEvent = new EntityVelocityEvent(this, velocity);
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) {
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) {
Check.notNull(entity, "Entity cannot be null");
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() {
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) {
Check.notNull(entity, "Passenger cannot be null");
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());
}
/**
* 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) {
Check.notNull(entity, "Passenger cannot be null");
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());
}
/**
* Get if the entity has any passenger
*
* @return true if the entity has any passenger, false otherwise
*/
public boolean hasPassenger() {
return !passengers.isEmpty();
}
/**
* Get the entity passengers
*
* @return an unmodifiable list containing all the entity passengers
*/
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
*/
public boolean isOnFire() {
@ -607,40 +771,79 @@ public abstract class Entity implements Viewable, EventHandler, DataContainer {
sendMetadataIndex(0);
}
/**
* Get if the entity is invisible or not
*
* @return true if the entity is invisible, false otherwise
*/
public boolean isInvisible() {
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) {
this.invisible = invisible;
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
*/
public boolean isGlowing() {
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() {
return customName;
}
/**
* Change the entity custom name
*
* @param customName the custom name of the entity, null to remove it
*/
public void setCustomName(String customName) {
this.customName = customName;
sendMetadataIndex(2);
}
/**
* Get the custom name visible metadata field
*
* @return true if the custom name is visible, false otherwise
*/
public boolean isCustomNameVisible() {
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) {
this.customNameVisible = customNameVisible;
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
*/
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
*/
public boolean hasNoGravity() {
@ -689,6 +896,9 @@ public abstract class Entity implements Viewable, EventHandler, DataContainer {
position.setX(x);
position.setY(y);
position.setZ(z);
this.cacheX = x;
this.cacheY = y;
this.cacheZ = z;
if (hasPassenger()) {
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) {
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) {
this.lastYaw = position.getYaw();
this.lastPitch = position.getPitch();
position.setYaw(yaw);
position.setPitch(pitch);
this.cacheYaw = yaw;
this.cachePitch = pitch;
}
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
*/
public Position getPosition() {
return position;
}
/**
* Get the entity eye height
*
* @return the entity eye height
*/
public float getEyeHeight() {
return eyeHeight;
}
/**
* Change the entity eye height
*
* @param eyeHeight the entity eye eight
*/
public void setEyeHeight(float eyeHeight) {
this.eyeHeight = eyeHeight;
}
/**
* Get if this entity is in the same chunk as the specified position
*
* @param position the checked position chunk
* @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;
}
/**
* 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) {
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
*/
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() {
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
}
public enum Pose {
private enum Pose {
STANDING,
FALL_FLYING,
SLEEPING,

View File

@ -1,8 +1,9 @@
package net.minestom.server.entity;
import net.minestom.server.attribute.Attribute;
import net.minestom.server.collision.CollisionUtils;
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.item.ItemStack;
import net.minestom.server.network.packet.server.play.*;
@ -48,24 +49,11 @@ public abstract class EntityCreature extends LivingEntity {
}
@Override
public void update() {
super.update();
public void update(long time) {
super.update(time);
// Path finding
if (blockPositions != null) {
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);
}
}
}
pathProgress();
}
/**
@ -94,9 +82,9 @@ public abstract class EntityCreature extends LivingEntity {
float yaw = (float) (radians * (180.0 / Math.PI)) - 90;
float pitch = position.getPitch(); // TODO
short deltaX = (short) ((newX * 32 - position.getX() * 32) * 128);
short deltaY = (short) ((newY * 32 - position.getY() * 32) * 128);
short deltaZ = (short) ((newZ * 32 - position.getZ() * 32) * 128);
final short deltaX = (short) ((newX * 32 - position.getX() * 32) * 128);
final short deltaY = (short) ((newY * 32 - position.getY() * 32) * 128);
final short deltaZ = (short) ((newZ * 32 - position.getZ() * 32) * 128);
if (updateView) {
EntityPositionAndRotationPacket entityPositionAndRotationPacket = new EntityPositionAndRotationPacket();
@ -119,11 +107,7 @@ public abstract class EntityCreature extends LivingEntity {
}
if (lastYaw != yaw) {
EntityHeadLookPacket entityHeadLookPacket = new EntityHeadLookPacket();
entityHeadLookPacket.entityId = getEntityId();
entityHeadLookPacket.yaw = yaw;
sendPacketToViewers(entityHeadLookPacket);
refreshView(yaw, pitch);
setView(yaw, pitch);
}
refreshPosition(newX, newY, newZ);
@ -145,6 +129,9 @@ public abstract class EntityCreature extends LivingEntity {
@Override
public boolean addViewer(Player player) {
boolean result = super.addViewer(player);
if (!result)
return false;
PlayerConnection playerConnection = player.getPlayerConnection();
EntityPacket entityPacket = new EntityPacket();
@ -163,7 +150,7 @@ public abstract class EntityCreature extends LivingEntity {
playerConnection.sendPacket(getMetadataPacket());
// Equipments synchronization
syncEquipments();
syncEquipments(playerConnection);
if (hasPassenger()) {
playerConnection.sendPacket(getPassengersPacket());
@ -238,9 +225,33 @@ public abstract class EntityCreature extends LivingEntity {
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) {
// FIXME magic value
Vector velocity = new Vector(0, height * 10, 0);
Vector velocity = new Vector(0, height * 5, 0);
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
*
* @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);
// FIXME: jump support
if (blockPosition.getY() > getPosition().getY())
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) {
itemStack = ItemStackUtils.notNull(itemStack);

View File

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

View File

@ -18,7 +18,7 @@ public class ExperienceOrb extends Entity {
}
@Override
public void update() {
public void update(long time) {
// 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.network.packet.PacketWriter;
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.UpdateOption;
import java.util.Set;
import java.util.function.Consumer;
/**
* Represent an item on the ground
*/
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 boolean pickable = true;
@ -26,12 +41,33 @@ public class ItemEntity extends ObjectEntity {
super(EntityType.ITEM, spawnPosition);
this.itemStack = itemStack;
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
public void update() {
if (isMergeable() && isPickable()) {
public void update(long time) {
if (isMergeable() && isPickable() &&
(mergeUpdateOption == null || !CooldownUtils.hasCooldown(time, lastMergeCheck, mergeUpdateOption))) {
this.lastMergeCheck = time;
Chunk chunk = instance.getChunkAt(getPosition());
Set<Entity> entities = instance.getChunkEntities(chunk);
for (Entity entity : entities) {
@ -49,30 +85,30 @@ public class ItemEntity extends ObjectEntity {
if (getDistance(itemEntity) > mergeRange)
continue;
synchronized (this) {
synchronized (itemEntity) {
ItemStack itemStackEntity = itemEntity.getItemStack();
// Use the class as a monitor to prevent deadlock
// Shouldn't happen too often to be an issue
synchronized (ItemEntity.class) {
final ItemStack itemStackEntity = itemEntity.getItemStack();
StackingRule stackingRule = itemStack.getStackingRule();
boolean canStack = stackingRule.canBeStacked(itemStack, itemStackEntity);
final StackingRule stackingRule = itemStack.getStackingRule();
final boolean canStack = stackingRule.canBeStacked(itemStack, itemStackEntity);
if (!canStack)
continue;
if (!canStack)
continue;
int totalAmount = stackingRule.getAmount(itemStack) + stackingRule.getAmount(itemStackEntity);
boolean canApply = stackingRule.canApply(itemStack, totalAmount);
final int totalAmount = stackingRule.getAmount(itemStack) + stackingRule.getAmount(itemStackEntity);
final boolean canApply = stackingRule.canApply(itemStack, totalAmount);
if (!canApply)
continue;
if (!canApply)
continue;
EntityItemMergeEvent entityItemMergeEvent = new EntityItemMergeEvent(this, itemEntity);
callCancellableEvent(EntityItemMergeEvent.class, entityItemMergeEvent, () -> {
ItemStack result = stackingRule.apply(itemStack.clone(), totalAmount);
setItemStack(result);
itemEntity.remove();
});
final ItemStack result = stackingRule.apply(itemStack.clone(), totalAmount);
}
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;
import net.minestom.server.attribute.Attribute;
import net.minestom.server.collision.BoundingBox;
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.EntityDeathEvent;
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.network.packet.PacketWriter;
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.SoundCategory;
import net.minestom.server.utils.Position;
@ -64,14 +65,14 @@ public abstract class LivingEntity extends Entity implements EquipmentHandler {
}
@Override
public void update() {
public void update(long time) {
if (isOnFire()) {
if (System.currentTimeMillis() > fireExtinguishTime) {
if (time > fireExtinguishTime) {
setOnFire(false);
} else {
if (System.currentTimeMillis() - lastFireDamageTime > fireDamagePeriod) {
if (time - lastFireDamageTime > fireDamagePeriod) {
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;
if (!itemEntity.isPickable())
continue;
BoundingBox itemBoundingBox = itemEntity.getBoundingBox();
if (livingBoundingBox.intersect(itemBoundingBox)) {
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() {
return arrowCount;
}
/**
* Change the amount of arrow stuck in the entity
*
* @param arrowCount the arrow count
*/
public void setArrowCount(int arrowCount) {
this.arrowCount = arrowCount;
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
*/
public boolean damage(DamageType type, float value) {
if (isDead())
return false;
if (isImmune(type)) {
return false;
}
@ -273,10 +287,20 @@ public abstract class LivingEntity extends Entity implements EquipmentHandler {
return false;
}
/**
* Get the entity health
*
* @return the entity health
*/
public float getHealth() {
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) {
health = Math.min(health, getMaxHealth());
@ -287,6 +311,11 @@ public abstract class LivingEntity extends Entity implements EquipmentHandler {
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() {
return getAttributeValue(Attribute.MAX_HEALTH);
}
@ -320,6 +349,15 @@ public abstract class LivingEntity extends Entity implements EquipmentHandler {
}
// 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() {
for (EntityEquipmentPacket.Slot slot : EntityEquipmentPacket.Slot.values()) {
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
*/
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
*/
public boolean canPickupItem() {
@ -373,6 +415,28 @@ public abstract class LivingEntity extends Entity implements EquipmentHandler {
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) {
this.isHandActive = isHandActive;
this.offHand = offHand;
@ -392,14 +456,14 @@ public abstract class LivingEntity extends Entity implements EquipmentHandler {
int length = Attribute.values().length;
EntityPropertiesPacket.Property[] properties = new EntityPropertiesPacket.Property[length];
for (int i = 0; i < length; i++) {
Attribute attribute = Attribute.values()[i];
EntityPropertiesPacket.Property property = new EntityPropertiesPacket.Property();
float maxValue = attribute.getMaxVanillaValue();
float value = getAttributeValue(attribute);
value = value > maxValue ? maxValue : value; // Bypass vanilla limit client-side if needed (by sending the max value allowed)
property.key = attribute.getKey();
Attribute attribute = Attribute.values()[i];
float value = getAttributeValue(attribute);
property.attribute = attribute;
property.value = value;
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() {
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;
}
}

View File

@ -19,7 +19,7 @@ public abstract class ObjectEntity extends Entity {
public abstract int getObjectData();
@Override
public void update() {
public void update(long time) {
}
@ -30,6 +30,10 @@ public abstract class ObjectEntity extends Entity {
@Override
public boolean addViewer(Player player) {
boolean result = super.addViewer(player);
if (!result)
return false;
PlayerConnection playerConnection = player.getPlayerConnection();
SpawnEntityPacket spawnEntityPacket = new SpawnEntityPacket();
@ -46,7 +50,7 @@ public abstract class ObjectEntity extends Entity {
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()));
}
public static DamageType fromPlayer(Player player) {
public static EntityDamage fromPlayer(Player player) {
return new EntityDamage(player);
}
public static EntityDamage fromEntity(Entity entity) {
return new EntityDamage(entity);
}
public Component buildDeathScreenMessage(Player killed) {
return buildChatMessage(killed);
}

View File

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

View File

@ -22,6 +22,8 @@ public class FakePlayer extends Player {
public FakePlayer(UUID uuid, String username, boolean addInCache) {
super(uuid, username, new FakePlayerConnection());
this.fakePlayerController = new FakePlayerController(this);
this.registered = addInCache;
if (registered) {
@ -39,13 +41,6 @@ public class FakePlayer extends Player {
this(uuid, username, false);
}
@Override
protected void playerConnectionInit() {
FakePlayerConnection playerConnection = (FakePlayerConnection) getPlayerConnection();
playerConnection.setFakePlayer(this);
this.fakePlayerController = new FakePlayerController(this);
}
public FakePlayerController getController() {
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.network.packet.PacketWriter;
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.Vector;
import net.minestom.server.utils.item.ItemStackUtils;
@ -63,7 +64,7 @@ public class EntityArmorStand extends ObjectEntity implements EquipmentHandler {
@Override
public boolean addViewer(Player player) {
boolean result = super.addViewer(player);
syncEquipments();
syncEquipments(player.getPlayerConnection());
return result;
}
@ -316,6 +317,15 @@ public class EntityArmorStand extends ObjectEntity implements EquipmentHandler {
}
// 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() {
for (EntityEquipmentPacket.Slot slot : EntityEquipmentPacket.Slot.values()) {
syncEquipment(slot);

View File

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

View File

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

View File

@ -22,16 +22,6 @@ public class EntityBoat extends ObjectEntity {
return 0;
}
@Override
public void update() {
}
@Override
public void spawn() {
}
@Override
public Consumer<PacketWriter> getMetadataConsumer() {
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 EntityChicken(Position 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 EntityCow(Position 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) {
super(EntityType.CREEPER, spawnPosition);
setBoundingBox(0.6f, 1.7f, 0.6f);
}
@Override

View File

@ -7,5 +7,6 @@ import net.minestom.server.utils.Position;
public class EntityEndermite extends EntityCreature {
public EntityEndermite(Position 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) {
super(EntityType.GHAST, spawnPosition);
setBoundingBox(4, 4, 4);
}
@Override

View File

@ -7,5 +7,6 @@ import net.minestom.server.utils.Position;
public class EntityGiant extends EntityCreature {
public EntityGiant(Position 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) {
super(EntityType.IRON_GOLEM, spawnPosition);
setBoundingBox(1.4f, 2.7f, 1.4f);
}
@Override

View File

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

View File

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

View File

@ -13,6 +13,7 @@ public class EntityPig extends EntityCreature {
public EntityPig(Position spawnPosition) {
super(EntityType.PIG, spawnPosition);
setBoundingBox(0.9f, 0.9f, 0.9f);
}
@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) {
super(EntityType.POLAR_BEAR, spawnPosition);
setBoundingBox(1.3f, 1.4f, 1.3f);
}
@Override

View File

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

View File

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

View File

@ -7,5 +7,6 @@ import net.minestom.server.utils.Position;
public class EntitySilverfish extends EntityCreature {
public EntitySilverfish(Position 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) {
this.size = size;
final float boxSize = 0.51000005f * size;
setBoundingBox(boxSize, boxSize, boxSize);
sendMetadataIndex(15);
}
}

View File

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

View File

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

View File

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

View File

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

View File

@ -4,10 +4,16 @@ public class CancellableEvent extends Event {
private boolean cancelled;
/**
* @return true if the event should be cancelled, false otherwise
*/
public boolean isCancelled() {
return cancelled;
}
/**
* @param cancel true if the event should be cancelled, false otherwise
*/
public void setCancelled(boolean 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.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 {
private Entity source;
@ -13,10 +17,16 @@ public class EntityAttackEvent extends Event {
this.target = target;
}
/**
* @return the source of the attack
*/
public Entity getSource() {
return source;
}
/**
* @return the target of the attack
*/
public Entity getTarget() {
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.event.CancellableEvent;
/**
* Called with {@link net.minestom.server.entity.LivingEntity#damage(DamageType, float)}
*/
public class EntityDamageEvent extends CancellableEvent {
private DamageType damageType;
@ -13,14 +16,23 @@ public class EntityDamageEvent extends CancellableEvent {
this.damage = damage;
}
/**
* @return the damage type
*/
public DamageType getDamageType() {
return damageType;
}
/**
* @return the damage amount
*/
public float getDamage() {
return damage;
}
/**
* @param damage the new damage amount
*/
public void setDamage(float damage) {
this.damage = damage;
}

View File

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

View File

@ -2,22 +2,61 @@ package net.minestom.server.event.entity;
import net.minestom.server.entity.ItemEntity;
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 {
private ItemEntity source;
private ItemEntity merged;
public EntityItemMergeEvent(ItemEntity source, ItemEntity merged) {
private ItemStack result;
public EntityItemMergeEvent(ItemEntity source, ItemEntity merged, ItemStack result) {
this.source = source;
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() {
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() {
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.instance.Instance;
/**
* Called when a new instance is set for an entity
*/
public class EntitySpawnEvent extends Event {
private Instance spawnInstance;
@ -11,6 +14,11 @@ public class EntitySpawnEvent extends Event {
this.spawnInstance = spawnInstance;
}
/**
* Get the entity new instance
*
* @return the instance
*/
public Instance getSpawnInstance() {
return spawnInstance;
}

View File

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

View File

@ -17,6 +17,15 @@ public interface EventHandler {
*/
<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 <E>

View File

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

View File

@ -1,24 +1,43 @@
package net.minestom.server.event.inventory;
import net.minestom.server.entity.Player;
import net.minestom.server.event.Event;
import net.minestom.server.inventory.Inventory;
public class InventoryCloseEvent extends Event {
private Player player;
private Inventory inventory;
private Inventory newInventory;
public InventoryCloseEvent(Inventory inventory) {
public InventoryCloseEvent(Player player, Inventory inventory) {
this.player = player;
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
*/
public Inventory getInventory() {
return inventory;
}
/**
* Get the new inventory to open
*
* @return the new inventory to open, null if there isn't any
*/
public Inventory getNewInventory() {
return newInventory;
}
@ -26,7 +45,7 @@ public class InventoryCloseEvent extends Event {
/**
* 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) {
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.event.CancellableEvent;
import net.minestom.server.inventory.Inventory;
import net.minestom.server.utils.validate.Check;
public class InventoryOpenEvent extends CancellableEvent {
@ -15,16 +14,32 @@ public class InventoryOpenEvent extends CancellableEvent {
this.inventory = inventory;
}
/**
* Get the player who opens the inventory
*
* @return the player who opens the inventory
*/
public Player getPlayer() {
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() {
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) {
Check.notNull(inventory, "Inventory cannot be null!");
this.inventory = inventory;
}
}

View File

@ -1,5 +1,6 @@
package net.minestom.server.event.inventory;
import net.minestom.server.entity.Player;
import net.minestom.server.event.CancellableEvent;
import net.minestom.server.inventory.Inventory;
import net.minestom.server.inventory.click.ClickType;
@ -8,13 +9,15 @@ import net.minestom.server.utils.item.ItemStackUtils;
public class InventoryPreClickEvent extends CancellableEvent {
private Player player;
private Inventory inventory;
private int slot;
private ClickType clickType;
private ItemStack clickedItem;
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.slot = slot;
this.clickType = clickType;
@ -22,6 +25,15 @@ public class InventoryPreClickEvent extends CancellableEvent {
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
*
@ -31,26 +43,56 @@ public class InventoryPreClickEvent extends CancellableEvent {
return inventory;
}
/**
* Get the clicked slot number
*
* @return the clicked slot number
*/
public int getSlot() {
return slot;
}
/**
* Get the click type
*
* @return the click type
*/
public ClickType getClickType() {
return clickType;
}
/**
* Get the item who have been clicked
*
* @return the clicked item
*/
public ItemStack getClickedItem() {
return clickedItem;
}
/**
* Change the clicked item
*
* @param clickedItem the clicked item
*/
public void setClickedItem(ItemStack clickedItem) {
this.clickedItem = ItemStackUtils.notNull(clickedItem);
}
/**
* Get the item who was in the player cursor
*
* @return the cursor item
*/
public ItemStack getCursorItem() {
return cursorItem;
}
/**
* Change the cursor item
*
* @param cursorItem the cursor item
*/
public void setCursorItem(ItemStack 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;
import net.minestom.server.event.CancellableEvent;
import net.minestom.server.instance.block.CustomBlock;
import net.minestom.server.utils.BlockPosition;
public class PlayerBlockBreakEvent extends CancellableEvent {
private BlockPosition blockPosition;
private short blockId;
private CustomBlock customBlock;
private short resultBlockId;
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.blockId = blockId;
this.customBlock = customBlock;
this.resultBlockId = resultBlockId;
this.resultCustomBlockId = resultCustomBlockId;
}
/**
* Get the block position
*
* @return the block position
*/
public BlockPosition getBlockPosition() {
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() {
return resultBlockId;
}
/**
* Change the visual block id result
*
* @param resultBlockId the result block id
*/
public void setResultBlockId(short 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() {
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) {
this.resultCustomBlockId = resultCustomBlockId;
}
public boolean isResultCustomBlock() {
return resultCustomBlockId != 0;
}
}

View File

@ -1,11 +1,19 @@
package net.minestom.server.event.player;
import net.minestom.server.MinecraftServer;
import net.minestom.server.entity.Player;
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;
/**
* Called when a player tries placing a block
*/
public class PlayerBlockPlaceEvent extends CancellableEvent {
private static final BlockManager BLOCK_MANAGER = MinecraftServer.getBlockManager();
private final Player player;
private short blockId;
private short customBlockId;
@ -23,38 +31,100 @@ public class PlayerBlockPlaceEvent extends CancellableEvent {
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() {
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() {
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() {
return player;
}
/**
* @return the position of the block to place
*/
public BlockPosition getBlockPosition() {
return blockPosition;
}
/**
* @return the hand with which the player is trying to place
*/
public Player.Hand getHand() {
return hand;
}
/**
* @param consumeBlock true if the block should be consumer (-1 amount), false otherwise
*/
public void consumeBlock(boolean consumeBlock) {
this.consumeBlock = consumeBlock;
}
/**
* @return true if the block will be consumed, false otherwise
*/
public boolean doesConsumeBlock() {
return consumeBlock;
}

View File

@ -8,6 +8,10 @@ import java.util.ArrayList;
import java.util.Collection;
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 {
private Player sender;
@ -21,26 +25,52 @@ public class PlayerChatEvent extends CancellableEvent {
this.message = message;
}
/**
* @param chatFormat the custom chat format
*/
public void setChatFormat(Function<PlayerChatEvent, TextComponent> chatFormat) {
this.chatFormat = chatFormat;
}
/**
* @return the sender of the message
*/
public Player getSender() {
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() {
return recipients;
}
/**
* @return the sender's message
*/
public String getMessage() {
return message;
}
/**
* Used to change the message
*
* @param message the new message
*/
public void setMessage(String 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() {
return chatFormat;
}

View File

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

View File

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

View File

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

View File

@ -1,6 +1,25 @@
package net.minestom.server.event.player;
import net.minestom.server.entity.Player;
import net.minestom.server.event.Event;
/**
* Called when a player disconnect
*/
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;
import net.minestom.server.entity.Player;
import net.minestom.server.event.Event;
import net.minestom.server.item.ItemStack;
/**
* Called when a player is finished eating
*/
public class PlayerEatEvent extends Event {
private Player player;
private ItemStack foodItem;
public PlayerEatEvent(ItemStack foodItem) {
public PlayerEatEvent(Player player, ItemStack foodItem) {
this.player = player;
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() {
return foodItem;
}

View File

@ -4,20 +4,44 @@ import net.minestom.server.entity.Entity;
import net.minestom.server.entity.Player;
import net.minestom.server.event.Event;
/**
* Called when a player interacts (right-click) with an entity
*/
public class PlayerInteractEvent extends Event {
private Player player;
private Entity entityTarget;
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.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() {
return entityTarget;
}
/**
* Get with which hand the player interacted with the entity
*
* @return the hand
*/
public Player.Hand getHand() {
return hand;
}

View File

@ -1,18 +1,49 @@
package net.minestom.server.event.player;
import net.minestom.server.entity.Player;
import net.minestom.server.event.Event;
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 {
private Player player;
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() {
return spawningInstance;
}
/**
* Change the spawning instance
*
* @param instance the new spawning instance
*/
public void setSpawningInstance(Instance instance) {
this.spawningInstance = instance;
}
}

View File

@ -1,16 +1,36 @@
package net.minestom.server.event.player;
import net.minestom.server.entity.Player;
import net.minestom.server.event.CancellableEvent;
import net.minestom.server.utils.Position;
/**
* Called when a player is modifying his position
*/
public class PlayerMoveEvent extends CancellableEvent {
private Player player;
private Position newPosition;
public PlayerMoveEvent(float x, float y, float z, float yaw, float pitch) {
this.newPosition = new Position(x, y, z, yaw, pitch);
public PlayerMoveEvent(Player player, Position newPosition) {
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() {
return newPosition;
}

View File

@ -1,25 +1,55 @@
package net.minestom.server.event.player;
import net.minestom.server.entity.Player;
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 {
private Player player;
private String identifier;
private byte[] message;
public PlayerPluginMessageEvent(String identifier, byte[] message) {
public PlayerPluginMessageEvent(Player player, String identifier, byte[] message) {
this.player = player;
this.identifier = identifier;
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() {
return identifier;
}
/**
* Get the message data as a byte array
*
* @return the message
*/
public byte[] getMessage() {
return message;
}
/**
* Get the message data as a String
*
* @return the message
*/
public String getMessageString() {
return new String(message);
}

View File

@ -21,18 +21,40 @@ public class PlayerPreEatEvent extends CancellableEvent {
this.eatingTime = eatingTime;
}
/**
* The player who is trying to eat
*
* @return the concerned player
*/
public Player getPlayer() {
return player;
}
/**
* The food item which will be eaten
*
* @return the food item
*/
public ItemStack getFoodItem() {
return foodItem;
}
/**
* Get the food eating time
* <p>
* This is by default {@link Player#getDefaultEatingTime()}
*
* @return the eating time
*/
public long getEatingTime() {
return eatingTime;
}
/**
* Change the food eating time
*
* @param eatingTime the new eating time
*/
public void setEatingTime(long 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;
import net.minestom.server.entity.Player;
import net.minestom.server.event.Event;
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 {
private Player player;
private Position respawnPosition;
public PlayerRespawnEvent(Position respawnPosition) {
public PlayerRespawnEvent(Player player, Position respawnPosition) {
this.player = player;
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() {
return respawnPosition;
}
/**
* Change the respawn position
*
* @param respawnPosition the new respawn position
*/
public void setRespawnPosition(Position 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.instance.Instance;
/**
* Called when a new instance is set for a player
*/
public class PlayerSpawnEvent extends EntitySpawnEvent {
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
* @return
*
* @return true if this is the first spawn, false otherwise
*/
public boolean isFirstSpawn() {
return firstSpawn;

View File

@ -1,24 +1,52 @@
package net.minestom.server.event.player;
import net.minestom.server.entity.Player;
import net.minestom.server.event.CancellableEvent;
import net.minestom.server.instance.block.CustomBlock;
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 {
private Player player;
private BlockPosition blockPosition;
private CustomBlock customBlock;
public PlayerStartDiggingEvent(BlockPosition blockPosition, CustomBlock customBlock) {
public PlayerStartDiggingEvent(Player player, BlockPosition blockPosition, CustomBlock customBlock) {
this.player = player;
this.blockPosition = blockPosition;
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() {
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;
}
}

View File

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

View File

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

View File

@ -1,30 +1,65 @@
package net.minestom.server.event.player;
import net.minestom.server.entity.Player;
import net.minestom.server.event.CancellableEvent;
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 {
private Player player;
private ItemStack mainHandItem;
private ItemStack offHandItem;
public PlayerSwapItemEvent(ItemStack mainHandItem, ItemStack offHandItem) {
public PlayerSwapItemEvent(Player player, ItemStack mainHandItem, ItemStack offHandItem) {
this.player = player;
this.mainHandItem = mainHandItem;
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() {
return mainHandItem;
}
/**
* Change the item which will be in the player main hand
*
* @param mainHandItem the main hand item
*/
public void setMainHandItem(ItemStack 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() {
return offHandItem;
}
/**
* Change the item which will be in the player off hand
*
* @param offHandItem the off hand item
*/
public void setOffHandItem(ItemStack 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.event.Event;
/**
* Called at each player tick
*/
public class PlayerTickEvent extends Event {
private Player player;
@ -11,6 +14,11 @@ public class PlayerTickEvent extends Event {
this.player = player;
}
/**
* Get the player
*
* @return the player
*/
public Player getPlayer() {
return player;
}

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