Added a lot of comments

This commit is contained in:
Felix Cravic 2020-05-15 18:03:28 +02:00
parent ee90f82969
commit b97b75f13c
11 changed files with 178 additions and 38 deletions

View File

@ -177,6 +177,13 @@ public class PlayerInit {
player.sendMessage("CLICK PLAYER INVENTORY"); player.sendMessage("CLICK PLAYER INVENTORY");
System.out.println("slot player: " + slot); System.out.println("slot player: " + slot);
}); });
/*Sidebar scoreboard = new Sidebar("Scoreboard Title");
for (int i = 0; i < 15; i++) {
scoreboard.createLine(new Sidebar.ScoreboardLine("id" + i, "Hey guys " + i, i));
}
scoreboard.addViewer(player);
scoreboard.updateLineContent("id3", "I HAVE BEEN UPDATED");*/
}); });
player.addEventCallback(PlayerSpawnEvent.class, event -> { player.addEventCallback(PlayerSpawnEvent.class, event -> {
@ -212,19 +219,16 @@ public class PlayerInit {
setAttribute(Attribute.MAX_HEALTH, 10); setAttribute(Attribute.MAX_HEALTH, 10);
heal(); heal();
Sidebar scoreboard = new Sidebar("Scoreboard Title");
for (int i = 0; i < 15; i++) {
scoreboard.createLine(new Sidebar.ScoreboardLine("id" + i, "Hey guys " + i, i));
}
scoreboard.addViewer(this);
scoreboard.updateLineContent("id3", "I HAVE BEEN UPDATED");
BelowNameScoreboard belowNameScoreboard = new BelowNameScoreboard(); BelowNameScoreboard belowNameScoreboard = new BelowNameScoreboard();
setBelowNameScoreboard(belowNameScoreboard); setBelowNameScoreboard(belowNameScoreboard);
belowNameScoreboard.updateScore(this, 50);*/ belowNameScoreboard.updateScore(this, 50);*/
}); });
player.addEventCallback(PlayerRespawnEvent.class, event -> {
event.setRespawnPosition(new Position(0f, 70f, 0f));
});
player.addEventCallback(PlayerUseItemEvent.class, useEvent -> { player.addEventCallback(PlayerUseItemEvent.class, useEvent -> {
player.sendMessage("Using item in air: " + useEvent.getItemStack().getMaterial()); player.sendMessage("Using item in air: " + useEvent.getItemStack().getMaterial());
}); });

View File

@ -8,6 +8,7 @@ import net.minestom.server.data.Data;
import net.minestom.server.data.DataContainer; import net.minestom.server.data.DataContainer;
import net.minestom.server.event.Event; import net.minestom.server.event.Event;
import net.minestom.server.event.EventCallback; import net.minestom.server.event.EventCallback;
import net.minestom.server.event.entity.EntityDeathEvent;
import net.minestom.server.event.entity.EntitySpawnEvent; import net.minestom.server.event.entity.EntitySpawnEvent;
import net.minestom.server.event.entity.EntityTickEvent; import net.minestom.server.event.entity.EntityTickEvent;
import net.minestom.server.event.entity.EntityVelocityEvent; import net.minestom.server.event.entity.EntityVelocityEvent;
@ -20,6 +21,7 @@ import net.minestom.server.network.packet.server.play.*;
import net.minestom.server.network.player.PlayerConnection; import net.minestom.server.network.player.PlayerConnection;
import net.minestom.server.utils.Vector; import net.minestom.server.utils.Vector;
import net.minestom.server.utils.*; import net.minestom.server.utils.*;
import net.minestom.server.utils.time.TimeUnit;
import java.util.*; import java.util.*;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
@ -114,18 +116,26 @@ public abstract class Entity implements Viewable, EventHandler, DataContainer {
this(entityType, new Position()); this(entityType, new Position());
} }
/**
* @param id the entity unique id ({@link #getEntityId()})
* @return the entity having the specified id, null if not found
*/
public static Entity getEntity(int id) { public static Entity getEntity(int id) {
return entityById.get(id); return entityById.getOrDefault(id, null);
} }
private static int generateId() { private static int generateId() {
return lastEntityId.incrementAndGet(); return lastEntityId.incrementAndGet();
} }
/**
* Called each tick
*/
public abstract void update(); public abstract void update();
// Called when a new instance is set /**
* Called when a new instance is set
*/
public abstract void spawn(); public abstract void spawn();
public boolean isOnGround() { public boolean isOnGround() {
@ -375,6 +385,12 @@ public abstract class Entity implements Viewable, EventHandler, DataContainer {
return eventCallbacks.getOrDefault(eventClass, new CopyOnWriteArrayList<>()); return eventCallbacks.getOrDefault(eventClass, new CopyOnWriteArrayList<>());
} }
/**
* Each entity has an unique id which will change after a restart
* All entities can be retrieved by calling {@link Entity#getEntity(int)}
*
* @return the unique entity id
*/
public int getEntityId() { public int getEntityId() {
return id; return id;
} }
@ -619,10 +635,17 @@ public abstract class Entity implements Viewable, EventHandler, DataContainer {
sendMetadataIndex(0); sendMetadataIndex(0);
} }
/**
* @return the current position of the entity
*/
public Position getPosition() { public Position getPosition() {
return position; return position;
} }
/**
* @param position the checked position chunk
* @return true if the entity is in the same chunk as {@code position}
*/
public boolean sameChunk(Position position) { public boolean sameChunk(Position position) {
Position pos = getPosition(); Position pos = getPosition();
int chunkX1 = ChunkUtils.getChunkCoordinate((int) Math.floor(pos.getX())); int chunkX1 = ChunkUtils.getChunkCoordinate((int) Math.floor(pos.getX()));
@ -638,6 +661,10 @@ public abstract class Entity implements Viewable, EventHandler, DataContainer {
return sameChunk(entity.getPosition()); return sameChunk(entity.getPosition());
} }
/**
* Remove the entity from the server immediately
* WARNING: this do not trigger the {@link EntityDeathEvent} event
*/
public void remove() { public void remove() {
this.shouldRemove = true; this.shouldRemove = true;
entityById.remove(id); entityById.remove(id);
@ -645,7 +672,15 @@ public abstract class Entity implements Viewable, EventHandler, DataContainer {
instance.removeEntity(this); instance.removeEntity(this);
} }
public void scheduleRemove(long delay) { /**
* Trigger {@link #remove()} after the specified time
*
* @param delay
* @param timeUnit to determine the delay unit
*/
public void scheduleRemove(long delay, TimeUnit timeUnit) {
delay = timeUnit.toMilliseconds(delay);
if (delay == 0) { // Cancel the scheduled remove if (delay == 0) { // Cancel the scheduled remove
this.scheduledRemoveTime = 0; this.scheduledRemoveTime = 0;
return; return;
@ -653,6 +688,9 @@ public abstract class Entity implements Viewable, EventHandler, DataContainer {
this.scheduledRemoveTime = System.currentTimeMillis() + delay; this.scheduledRemoveTime = System.currentTimeMillis() + delay;
} }
/**
* @return true if {@link #scheduleRemove(long, TimeUnit)} has been called, false otherwise
*/
public boolean isRemoveScheduled() { public boolean isRemoveScheduled() {
return scheduledRemoveTime != 0; return scheduledRemoveTime != 0;
} }
@ -667,6 +705,11 @@ public abstract class Entity implements Viewable, EventHandler, DataContainer {
return velocityPacket; return velocityPacket;
} }
/**
* Used to sync entities together, and sent when adding viewers
*
* @return The {@link EntityMetaDataPacket} related to this entity
*/
public EntityMetaDataPacket getMetadataPacket() { public EntityMetaDataPacket getMetadataPacket() {
EntityMetaDataPacket metaDataPacket = new EntityMetaDataPacket(); EntityMetaDataPacket metaDataPacket = new EntityMetaDataPacket();
metaDataPacket.entityId = getEntityId(); metaDataPacket.entityId = getEntityId();
@ -674,6 +717,11 @@ public abstract class Entity implements Viewable, EventHandler, DataContainer {
return metaDataPacket; return metaDataPacket;
} }
/**
* Should be override when wanting to add a new metadata index
*
* @return The consumer used to write {@link EntityMetaDataPacket} in {@link #getMetadataPacket()}
*/
public Consumer<PacketWriter> getMetadataConsumer() { public Consumer<PacketWriter> getMetadataConsumer() {
return packet -> { return packet -> {
fillMetadataIndex(packet, 0); fillMetadataIndex(packet, 0);
@ -683,6 +731,12 @@ public abstract class Entity implements Viewable, EventHandler, DataContainer {
}; };
} }
/**
* Send a {@link EntityMetaDataPacket} containing only the specified index
* The index is wrote using {@link #fillMetadataIndex(PacketWriter, int)}
*
* @param index
*/
protected void sendMetadataIndex(int index) { protected void sendMetadataIndex(int index) {
EntityMetaDataPacket metaDataPacket = new EntityMetaDataPacket(); EntityMetaDataPacket metaDataPacket = new EntityMetaDataPacket();
metaDataPacket.entityId = getEntityId(); metaDataPacket.entityId = getEntityId();
@ -693,6 +747,14 @@ public abstract class Entity implements Viewable, EventHandler, DataContainer {
sendPacketToViewersAndSelf(metaDataPacket); sendPacketToViewersAndSelf(metaDataPacket);
} }
/**
* Used to fill/write a specific metadata index
* The proper use to add a new metadata index is to override this and add your case
* Then you can also override {@link #getMetadataConsumer()} and fill your newly added index
*
* @param packet the packet writer
* @param index the index to fill/write
*/
protected void fillMetadataIndex(PacketWriter packet, int index) { protected void fillMetadataIndex(PacketWriter packet, int index) {
switch (index) { switch (index) {
case 0: case 0:

View File

@ -11,6 +11,7 @@ import net.minestom.server.utils.BlockPosition;
import net.minestom.server.utils.ChunkUtils; import net.minestom.server.utils.ChunkUtils;
import net.minestom.server.utils.Position; import net.minestom.server.utils.Position;
import net.minestom.server.utils.Vector; import net.minestom.server.utils.Vector;
import net.minestom.server.utils.time.TimeUnit;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.function.Consumer; import java.util.function.Consumer;
@ -119,7 +120,7 @@ public abstract class EntityCreature extends LivingEntity {
super.kill(); super.kill();
// Needed for proper death animation (wait for it to finish before destroying the entity) // Needed for proper death animation (wait for it to finish before destroying the entity)
scheduleRemove(1000); scheduleRemove(1000, TimeUnit.MILLISECOND);
} }
@Override @Override

View File

@ -142,6 +142,9 @@ public abstract class LivingEntity extends Entity implements EquipmentHandler {
syncEquipments(); syncEquipments();
} }
/**
* Kill the entity, trigger the {@link EntityDeathEvent} event
*/
public void kill() { public void kill() {
refreshIsDead(true); // So the entity isn't killed over and over again refreshIsDead(true); // So the entity isn't killed over and over again
triggerStatus((byte) 3); // Start death animation status triggerStatus((byte) 3); // Start death animation status

View File

@ -31,10 +31,7 @@ import net.minestom.server.scoreboard.Team;
import net.minestom.server.sound.Sound; import net.minestom.server.sound.Sound;
import net.minestom.server.sound.SoundCategory; import net.minestom.server.sound.SoundCategory;
import net.minestom.server.stat.PlayerStatistic; import net.minestom.server.stat.PlayerStatistic;
import net.minestom.server.utils.ArrayUtils; import net.minestom.server.utils.*;
import net.minestom.server.utils.BlockPosition;
import net.minestom.server.utils.ChunkUtils;
import net.minestom.server.utils.Position;
import net.minestom.server.world.Dimension; import net.minestom.server.world.Dimension;
import net.minestom.server.world.LevelType; import net.minestom.server.world.LevelType;
@ -71,6 +68,8 @@ public class Player extends LivingEntity {
private short heldSlot; private short heldSlot;
private Inventory openInventory; private Inventory openInventory;
private Position respawnPoint;
private int food; private int food;
private float foodSaturation; private float foodSaturation;
private long startEatingTime; private long startEatingTime;
@ -120,6 +119,8 @@ public class Player extends LivingEntity {
setBoundingBox(0.69f, 1.8f, 0.69f); setBoundingBox(0.69f, 1.8f, 0.69f);
setRespawnPoint(new Position(0, 0, 0));
// Some client update // Some client update
getPlayerConnection().sendPacket(getPropertiesPacket()); // Send default properties getPlayerConnection().sendPacket(getPropertiesPacket()); // Send default properties
refreshHealth(); refreshHealth();
@ -618,9 +619,23 @@ public class Player extends LivingEntity {
return !itemDropEvent.isCancelled(); return !itemDropEvent.isCancelled();
} }
/**
* Used to retrieve the default spawn point
* can be altered by the {@link PlayerRespawnEvent#setRespawnPosition(Position)}
*
* @return the default respawn point
*/
public Position getRespawnPoint() { public Position getRespawnPoint() {
// TODO: Custom return respawnPoint;
return new Position(0f, 70f, 0f); }
/**
* Change the default spawn point
*
* @param respawnPoint
*/
public void setRespawnPoint(Position respawnPoint) {
this.respawnPoint = respawnPoint;
} }
public void respawn() { public void respawn() {
@ -671,7 +686,7 @@ public class Player extends LivingEntity {
} }
public void setExp(float exp) { public void setExp(float exp) {
if (exp < 0 || exp > 1) if (!MathUtils.isBetween(exp, 0, 1))
throw new IllegalArgumentException("Exp should be between 0 and 1"); throw new IllegalArgumentException("Exp should be between 0 and 1");
this.exp = exp; this.exp = exp;
sendExperienceUpdatePacket(); sendExperienceUpdatePacket();
@ -884,7 +899,7 @@ public class Player extends LivingEntity {
} }
/** /**
* Open the specified Inventory * Open the specified Inventory, close the previous inventory if existing
* *
* @param inventory the inventory to open * @param inventory the inventory to open
* @return true if the inventory has been opened/sent to the player, false otherwise (cancelled by event) * @return true if the inventory has been opened/sent to the player, false otherwise (cancelled by event)
@ -916,6 +931,10 @@ public class Player extends LivingEntity {
return !inventoryOpenEvent.isCancelled(); return !inventoryOpenEvent.isCancelled();
} }
/**
* Close the current inventory if there is any
* It closes the player inventory if {@link #getOpenInventory()} returns null
*/
public void closeInventory() { public void closeInventory() {
Inventory openInventory = getOpenInventory(); Inventory openInventory = getOpenInventory();
CloseWindowPacket closeWindowPacket = new CloseWindowPacket(); CloseWindowPacket closeWindowPacket = new CloseWindowPacket();
@ -956,7 +975,7 @@ public class Player extends LivingEntity {
} }
public void setPermissionLevel(int permissionLevel) { public void setPermissionLevel(int permissionLevel) {
if (permissionLevel < 0 || permissionLevel > 4) if (!MathUtils.isBetween(permissionLevel, 0, 4))
throw new IllegalArgumentException("permissionLevel has to be between 0 and 4"); throw new IllegalArgumentException("permissionLevel has to be between 0 and 4");
this.permissionLevel = permissionLevel; this.permissionLevel = permissionLevel;
@ -1032,6 +1051,12 @@ public class Player extends LivingEntity {
refreshAbilities(); refreshAbilities();
} }
/**
* This is the map used to send the statistic packet
* It is possible to add/remove/change statistic value directly into it
*
* @return the modifiable statistic map
*/
public Map<PlayerStatistic, Integer> getStatisticValueMap() { public Map<PlayerStatistic, Integer> getStatisticValueMap() {
return statisticValueMap; return statisticValueMap;
} }
@ -1052,6 +1077,13 @@ public class Player extends LivingEntity {
playerConnection.sendPacket(playerAbilitiesPacket); playerConnection.sendPacket(playerAbilitiesPacket);
} }
/**
* All packets in the queue are executed in the {@link #update()} method
* It is used internally to add all received packet from the client
* Could be used to "simulate" a received packet, but to use at your own risk
*
* @param packet the packet to add in the queue
*/
public void addPacketToQueue(ClientPlayPacket packet) { public void addPacketToQueue(ClientPlayPacket packet) {
this.packets.add(packet); this.packets.add(packet);
} }

View File

@ -8,10 +8,29 @@ import java.util.List;
public interface EventHandler { public interface EventHandler {
/**
* Add a new event callback for the specified type {@code eventClass}
*
* @param eventClass the event class
* @param eventCallback the event callback
* @param <E> the event type
*/
<E extends Event> void addEventCallback(Class<E> eventClass, EventCallback<E> eventCallback); <E extends Event> void addEventCallback(Class<E> eventClass, EventCallback<E> eventCallback);
/**
* @param eventClass
* @param <E>
* @return all event callbacks for the specified type {@code eventClass}
*/
<E extends Event> List<EventCallback> getEventCallbacks(Class<E> eventClass); <E extends Event> List<EventCallback> getEventCallbacks(Class<E> eventClass);
/**
* Call the specified event type using the Event object parameter
*
* @param eventClass the event class
* @param event the event object
* @param <E> the event type
*/
default <E extends Event> void callEvent(Class<E> eventClass, E event) { default <E extends Event> void callEvent(Class<E> eventClass, E event) {
List<EventCallback> eventCallbacks = getEventCallbacks(eventClass); List<EventCallback> eventCallbacks = getEventCallbacks(eventClass);
for (EventCallback<E> eventCallback : eventCallbacks) { for (EventCallback<E> eventCallback : eventCallbacks) {
@ -19,6 +38,14 @@ public interface EventHandler {
} }
} }
/**
* Same as {@link #callEvent(Class, Event)} but add a Runnable which is called if the event is not cancelled
*
* @param eventClass the event class
* @param event the event object
* @param runnable the callback called when the event is not cancelled
* @param <E> the event type
*/
default <E extends CancellableEvent> void callCancellableEvent(Class<E> eventClass, E event, Runnable runnable) { default <E extends CancellableEvent> void callCancellableEvent(Class<E> eventClass, E event, Runnable runnable) {
callEvent(eventClass, event); callEvent(eventClass, event);
if (!event.isCancelled()) { if (!event.isCancelled()) {

View File

@ -259,13 +259,17 @@ public class InstanceContainer extends Instance {
public void loadOptionalChunk(int chunkX, int chunkZ, Consumer<Chunk> callback) { public void loadOptionalChunk(int chunkX, int chunkZ, Consumer<Chunk> callback) {
Chunk chunk = getChunk(chunkX, chunkZ); Chunk chunk = getChunk(chunkX, chunkZ);
if (chunk != null) { if (chunk != null) {
// Chunk already loaded
if (callback != null) if (callback != null)
callback.accept(chunk); callback.accept(chunk);
} else { } else {
if (hasEnabledAutoChunkLoad()) { if (hasEnabledAutoChunkLoad()) {
// Load chunk from StorageFolder or with ChunkGenerator
retrieveChunk(chunkX, chunkZ, callback); retrieveChunk(chunkX, chunkZ, callback);
} else { } else {
callback.accept(null); // Chunk not loaded, return null
if (callback != null)
callback.accept(null);
} }
} }
} }

View File

@ -15,7 +15,6 @@ import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.CopyOnWriteArraySet; import java.util.concurrent.CopyOnWriteArraySet;
import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicInteger;
// TODO update tick
public class Sidebar implements Viewable { public class Sidebar implements Viewable {
private static final AtomicInteger counter = new AtomicInteger(); private static final AtomicInteger counter = new AtomicInteger();
@ -73,20 +72,18 @@ public class Sidebar implements Viewable {
} }
public void updateLineContent(String id, String content) { public void updateLineContent(String id, String content) {
for (ScoreboardLine line : lines) { ScoreboardLine scoreboardLine = getLine(id);
if (line.id.equals(id)) { if (scoreboardLine != null) {
line.refreshContent(content); scoreboardLine.refreshContent(content);
sendPacketToViewers(line.sidebarTeam.updatePrefix(content)); sendPacketToViewers(scoreboardLine.sidebarTeam.updatePrefix(content));
}
} }
} }
public void updateLineScore(String id, int score) { public void updateLineScore(String id, int score) {
for (ScoreboardLine line : lines) { ScoreboardLine scoreboardLine = getLine(id);
if (line.id.equals(id)) { if (scoreboardLine != null) {
line.line = score; scoreboardLine.line = score;
sendPacketToViewers(line.getLineScoreUpdatePacket(objectiveName, score)); sendPacketToViewers(scoreboardLine.getLineScoreUpdatePacket(objectiveName, score));
}
} }
} }

View File

@ -8,7 +8,9 @@ public class ChunkUtils {
public static boolean isChunkUnloaded(Instance instance, float x, float z) { public static boolean isChunkUnloaded(Instance instance, float x, float z) {
int chunkX = getChunkCoordinate((int) x); int chunkX = getChunkCoordinate((int) x);
int chunkZ = getChunkCoordinate((int) z); int chunkZ = getChunkCoordinate((int) z);
return instance.getChunk(chunkX, chunkZ) == null;
Chunk chunk = instance.getChunk(chunkX, chunkZ);
return chunk == null || !chunk.isLoaded();
} }
public static int getChunkCoordinate(int xz) { public static int getChunkCoordinate(int xz) {

View File

@ -30,13 +30,21 @@ public class MathUtils {
public static Direction getHorizontalDirection(float yawInDegrees) { public static Direction getHorizontalDirection(float yawInDegrees) {
// +45f gives a 90° angle for the direction (-1° and 1° are towards the same direction) // +45f gives a 90° angle for the direction (-1° and 1° are towards the same direction)
int directionIndex = (int) Math.floor(((yawInDegrees+45f) / 90f)); int directionIndex = (int) Math.floor(((yawInDegrees + 45f) / 90f));
if(directionIndex < 0) { if (directionIndex < 0) {
directionIndex = (-directionIndex) % Direction.HORIZONTAL.length; directionIndex = (-directionIndex) % Direction.HORIZONTAL.length;
directionIndex = Direction.HORIZONTAL.length-directionIndex; directionIndex = Direction.HORIZONTAL.length - directionIndex;
} }
directionIndex %= Direction.HORIZONTAL.length; directionIndex %= Direction.HORIZONTAL.length;
return Direction.HORIZONTAL[directionIndex]; return Direction.HORIZONTAL[directionIndex];
} }
public static boolean isBetween(int number, int min, int max) {
return number >= min && number <= max;
}
public static boolean isBetween(float number, float min, float max) {
return number >= min && number <= max;
}
} }

View File

@ -6,7 +6,7 @@ public enum TimeUnit {
TICK, MILLISECOND; TICK, MILLISECOND;
public long toMilliseconds(int value) { public long toMilliseconds(long value) {
switch (this) { switch (this) {
case TICK: case TICK:
return MinecraftServer.TICK_MS * value; return MinecraftServer.TICK_MS * value;