Lot of comments

This commit is contained in:
Felix Cravic 2020-05-27 20:30:13 +02:00
parent f5ddc66c43
commit 039e9aca4f
8 changed files with 257 additions and 35 deletions

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

@ -428,6 +428,10 @@ public class Player extends LivingEntity {
super.kill();
}
/**
* Respawn the player by sending a {@link RespawnPacket} to the player and teleporting him
* to {@link #getRespawnPoint()}. It also reset fire and his health
*/
public void respawn() {
if (!isDead())
return;
@ -594,7 +598,17 @@ public class Player extends LivingEntity {
}
}
/**
* Send a {@link BlockBreakAnimationPacket} packet to the player and his viewers
* Setting {@code destroyStage} to -1 reset the break animation
*
* @param blockPosition the position of the block
* @param destroyStage the destroy stage
* @throws IllegalArgumentException if {@code destroyStage} is not between -1 and 10
*/
public void sendBlockBreakAnimation(BlockPosition blockPosition, byte destroyStage) {
Check.argCondition(!MathUtils.isBetween(destroyStage, -1, 10),
"The destroy stage has to be between -1 and 10");
BlockBreakAnimationPacket breakAnimationPacket = new BlockBreakAnimationPacket();
breakAnimationPacket.entityId = getEntityId() + 1;
breakAnimationPacket.blockPosition = blockPosition;
@ -607,6 +621,12 @@ public class Player extends LivingEntity {
sendMessage(Chat.fromLegacyText(message));
}
/**
* Send a message to the player
*
* @param message the message to send
* @param colorChar the character used to represent the color
*/
public void sendMessage(String message, char colorChar) {
sendMessage(Chat.fromLegacyText(message, colorChar));
}
@ -749,15 +769,26 @@ public class Player extends LivingEntity {
sendUpdateHealthPacket();
}
/**
* @return the additional hearts of the player
*/
public float getAdditionalHearts() {
return additionalHearts;
}
/**
* Update the internal field and send the appropriate {@link EntityMetaDataPacket}
*
* @param additionalHearts the count of additional heartss
*/
public void setAdditionalHearts(float additionalHearts) {
this.additionalHearts = additionalHearts;
sendMetadataIndex(14);
}
/**
* @return the food of the player
*/
public int getFood() {
return food;
}

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

@ -63,49 +63,139 @@ public abstract class Instance implements BlockModifier, EventHandler, DataConta
this.worldBorder = new WorldBorder(this);
}
/**
* Used to change the id of the block in a specific position.
* <p>
* In case of a CustomBlock it does not remove it but only refresh its visual
*
* @param blockPosition the block position
* @param blockId the new block id
*/
public abstract void refreshBlockId(BlockPosition blockPosition, short blockId);
// Used to call BlockBreakEvent and sending particle packet if true
public abstract void breakBlock(Player player, BlockPosition blockPosition);
/**
* Does call {@link net.minestom.server.event.player.PlayerBlockBreakEvent}
* and send particle packets
*
* @param player the player who break the block
* @param blockPosition the position of the broken block
* @return true if the block has been broken, false if it has been cancelled
*/
public abstract boolean breakBlock(Player player, BlockPosition blockPosition);
// Force the generation of the chunk, even if no file and ChunkGenerator are defined
/**
* Force the generation of the chunk, even if no file and ChunkGenerator are defined
*
* @param chunkX the chunk X
* @param chunkZ the chunk Z
* @param callback consumer called after the chunk has been generated,
* the returned chunk will never be null
*/
public abstract void loadChunk(int chunkX, int chunkZ, Consumer<Chunk> callback);
// Load only if auto chunk load is enabled
/**
* Load the chunk if the chunk is already loaded or if
* {@link #hasEnabledAutoChunkLoad()} returns true
*
* @param chunkX the chunk X
* @param chunkZ the chunk Z
* @param callback consumer called after the chunk has tried to be loaded,
* contains a chunk if it is successful, null otherwise
*/
public abstract void loadOptionalChunk(int chunkX, int chunkZ, Consumer<Chunk> callback);
/**
* @param chunk the chunk to unload
*/
public abstract void unloadChunk(Chunk chunk);
/**
* @param chunkX the chunk X
* @param chunkZ the chunk Z
* @return the chunk at the specified position, null if not loaded
*/
public abstract Chunk getChunk(int chunkX, int chunkZ);
/**
* @param chunk the chunk to save
* @param callback called when the chunk is done saving
* @throws NullPointerException if {@link #getStorageFolder()} returns null
*/
public abstract void saveChunkToStorageFolder(Chunk chunk, Runnable callback);
/**
* @param callback called when the chunks are done saving
* @throws NullPointerException if {@link #getStorageFolder()} returns null
*/
public abstract void saveChunksToStorageFolder(Runnable callback);
/**
* @return a BlockBatch linked to the instance
*/
public abstract BlockBatch createBlockBatch();
/**
* @param chunk the chunk to modify
* @return a ChunkBatch linked to {@code chunk}
* @throws NullPointerException if {@code chunk} is null
*/
public abstract ChunkBatch createChunkBatch(Chunk chunk);
/**
* @return the chunk generator of the instance
*/
public abstract ChunkGenerator getChunkGenerator();
/**
* @param chunkGenerator the new chunk generator of the instance
*/
public abstract void setChunkGenerator(ChunkGenerator chunkGenerator);
/**
* @return an unmodifiable containing all the loaded chunks of the instance
*/
public abstract Collection<Chunk> getChunks();
/**
* @return the storage folder of the instance
*/
public abstract StorageFolder getStorageFolder();
/**
* @param storageFolder the new storage folder of the instance
*/
public abstract void setStorageFolder(StorageFolder storageFolder);
public abstract void sendChunkUpdate(Player player, Chunk chunk);
protected abstract void retrieveChunk(int chunkX, int chunkZ, Consumer<Chunk> callback);
public abstract void createChunk(int chunkX, int chunkZ, Consumer<Chunk> callback);
protected abstract void createChunk(int chunkX, int chunkZ, Consumer<Chunk> callback);
/**
* Send all chunks data to {@code player}
*
* @param player the player
*/
public abstract void sendChunks(Player player);
/**
* Send a specific chunk data to {@code player}
*
* @param player the player
* @param chunk the chunk
*/
public abstract void sendChunk(Player player, Chunk chunk);
/**
* When set to true, chunks will load with players moving closer
* Otherwise using {@link #loadChunk(int, int)} will be required to even spawn a player
*
* @param enable enable the auto chunk load
*/
public abstract void enableAutoChunkLoad(boolean enable);
/**
* @return true if auto chunk load is enabled, false otherwise
*/
public abstract boolean hasEnabledAutoChunkLoad();
/**
@ -118,6 +208,17 @@ public abstract class Instance implements BlockModifier, EventHandler, DataConta
public abstract boolean isInVoid(Position position);
//
/**
* Send a full {@link ChunkDataPacket} to {@code player}
*
* @param player the player to update the chunk to
* @param chunk the chunk to send
*/
public void sendChunkUpdate(Player player, Chunk chunk) {
player.getPlayerConnection().sendPacket(chunk.getFullDataPacket());
}
protected void sendChunkUpdate(Collection<Player> players, Chunk chunk) {
ByteBuf chunkData = chunk.getFullDataPacket();
players.forEach(player -> {
@ -150,32 +251,55 @@ public abstract class Instance implements BlockModifier, EventHandler, DataConta
//
/**
* @return the dimension of the instance
*/
public Dimension getDimension() {
return dimension;
}
/**
* @return the world border linked to the instance
*/
public WorldBorder getWorldBorder() {
return worldBorder;
}
/**
* @return an unmodifiable list containing all the players in the instance
*/
public Set<Player> getPlayers() {
return Collections.unmodifiableSet(players);
}
/**
* @return an unmodifiable list containing all the creatures in the instance
*/
public Set<EntityCreature> getCreatures() {
return Collections.unmodifiableSet(creatures);
}
/**
* @return an unmodifiable list containing all the object entities in the instance
*/
public Set<ObjectEntity> getObjectEntities() {
return Collections.unmodifiableSet(objectEntities);
}
/**
* @return an unmodifiable list containing all the experience orbs in the instance
*/
public Set<ExperienceOrb> getExperienceOrbs() {
return Collections.unmodifiableSet(experienceOrbs);
}
/**
* @param chunk the chunk to get the entities from
* @return an unmodifiable set containing all the entities in a chunk
*/
public Set<Entity> getChunkEntities(Chunk chunk) {
return Collections.unmodifiableSet(getEntitiesInChunk(ChunkUtils.getChunkIndex(chunk.getChunkX(), chunk.getChunkZ())));
long index = ChunkUtils.getChunkIndex(chunk.getChunkX(), chunk.getChunkZ());
return Collections.unmodifiableSet(getEntitiesInChunk(index));
}
public void refreshBlockId(int x, int y, int z, short blockId) {
@ -308,6 +432,14 @@ public abstract class Instance implements BlockModifier, EventHandler, DataConta
// UNSAFE METHODS (need most of time to be synchronized)
/**
* Used when called {@link Entity#setInstance(Instance)}, it is used to refresh viewable chunks
* and add viewers if {@code entity} is a Player
* <p>
* Warning: unsafe, you probably want to use {@link Entity#setInstance(Instance)} instead
*
* @param entity the entity to add
*/
public void addEntity(Entity entity) {
Instance lastInstance = entity.getInstance();
if (lastInstance != null && lastInstance != this) {
@ -343,6 +475,13 @@ public abstract class Instance implements BlockModifier, EventHandler, DataConta
});
}
/**
* Used when an entity is removed from the instance, it removes all of his viewers
* <p>
* Warning: unsafe, you probably want to set the entity to another instance
*
* @param entity the entity to remove
*/
public void removeEntity(Entity entity) {
Instance entityInstance = entity.getInstance();
if (entityInstance == null || entityInstance != this)
@ -360,6 +499,14 @@ public abstract class Instance implements BlockModifier, EventHandler, DataConta
});
}
/**
* Add the specified entity to the instance entities cache
* <p>
* Warning: this is done automatically the entity move out of his chunk
*
* @param entity the entity to add
* @param chunk the chunk where the entity will be added
*/
public void addEntityToChunk(Entity entity, Chunk chunk) {
Check.notNull(chunk,
"The chunk " + chunk + " is not loaded, you can make it automatic by using Instance#enableAutoChunkLoad(true)");
@ -382,6 +529,14 @@ public abstract class Instance implements BlockModifier, EventHandler, DataConta
}
}
/**
* Remove the specified entity to the instance entities cache
* <p>
* Warning: this is done automatically the entity move out of his chunk
*
* @param entity the entity to remove
* @param chunk the chunk where the entity will be removed
*/
public void removeEntityFromChunk(Entity entity, Chunk chunk) {
long chunkIndex = ChunkUtils.getChunkIndex(chunk.getChunkX(), chunk.getChunkZ());
synchronized (chunkEntities) {

View File

@ -24,6 +24,7 @@ import net.minestom.server.utils.chunk.ChunkUtils;
import net.minestom.server.utils.player.PlayerUtils;
import net.minestom.server.utils.time.TimeUnit;
import net.minestom.server.utils.time.UpdateOption;
import net.minestom.server.utils.validate.Check;
import net.minestom.server.world.Dimension;
import java.util.*;
@ -204,7 +205,7 @@ public class InstanceContainer extends Instance {
}
@Override
public void breakBlock(Player player, BlockPosition blockPosition) {
public boolean breakBlock(Player player, BlockPosition blockPosition) {
Chunk chunk = getChunkAt(blockPosition);
int x = blockPosition.getX();
@ -216,12 +217,13 @@ public class InstanceContainer extends Instance {
// The player probably have a wrong version of this chunk section, send it
if (blockId == 0) {
sendChunkSectionUpdate(chunk, ChunkUtils.getSectionAt(y), player);
return;
return false;
}
PlayerBlockBreakEvent blockBreakEvent = new PlayerBlockBreakEvent(blockPosition, (short) 0, (short) 0);
player.callEvent(PlayerBlockBreakEvent.class, blockBreakEvent);
if (!blockBreakEvent.isCancelled()) {
boolean result = !blockBreakEvent.isCancelled();
if (result) {
// Break or change the broken block based on event result
setSeparateBlocks(x, y, z, blockBreakEvent.getResultBlockId(), blockBreakEvent.getResultCustomBlockId());
@ -238,6 +240,7 @@ public class InstanceContainer extends Instance {
// Cancelled so we need to refresh player chunk section
sendChunkSectionUpdate(chunk, ChunkUtils.getSectionAt(blockPosition.getY()), player);
}
return result;
}
@Override
@ -298,14 +301,13 @@ public class InstanceContainer extends Instance {
@Override
public void saveChunkToStorageFolder(Chunk chunk, Runnable callback) {
Check.notNull(getStorageFolder(), "You cannot save the chunk if no StorageFolder has been defined");
CHUNK_LOADER_IO.saveChunk(chunk, getStorageFolder(), callback);
}
@Override
public void saveChunksToStorageFolder(Runnable callback) {
if (storageFolder == null)
throw new UnsupportedOperationException("You cannot save an instance without setting a folder.");
Check.notNull(getStorageFolder(), "You cannot save the instance if no StorageFolder has been defined");
Iterator<Chunk> chunks = getChunks().iterator();
while (chunks.hasNext()) {
Chunk chunk = chunks.next();
@ -321,14 +323,10 @@ public class InstanceContainer extends Instance {
@Override
public ChunkBatch createChunkBatch(Chunk chunk) {
Check.notNull(chunk, "The chunk of a ChunkBatch cannot be null");
return new ChunkBatch(this, chunk);
}
@Override
public void sendChunkUpdate(Player player, Chunk chunk) {
player.getPlayerConnection().sendPacket(chunk.getFullDataPacket());
}
@Override
protected void retrieveChunk(int chunkX, int chunkZ, Consumer<Chunk> callback) {
if (storageFolder != null) {
@ -345,7 +343,7 @@ public class InstanceContainer extends Instance {
}
@Override
public void createChunk(int chunkX, int chunkZ, Consumer<Chunk> callback) {
protected void createChunk(int chunkX, int chunkZ, Consumer<Chunk> callback) {
Biome[] biomes = new Biome[Chunk.BIOME_COUNT];
if (chunkGenerator == null) {
Arrays.fill(biomes, Biome.VOID);
@ -418,6 +416,12 @@ public class InstanceContainer extends Instance {
this.chunks.put(ChunkUtils.getChunkIndex(chunk.getChunkX(), chunk.getChunkZ()), chunk);
}
@Override
public ChunkGenerator getChunkGenerator() {
return chunkGenerator;
}
@Override
public void setChunkGenerator(ChunkGenerator chunkGenerator) {
this.chunkGenerator = chunkGenerator;
}

View File

@ -31,8 +31,8 @@ public class SharedInstance extends Instance {
}
@Override
public void breakBlock(Player player, BlockPosition blockPosition) {
instanceContainer.breakBlock(player, blockPosition);
public boolean breakBlock(Player player, BlockPosition blockPosition) {
return instanceContainer.breakBlock(player, blockPosition);
}
@Override
@ -80,6 +80,11 @@ public class SharedInstance extends Instance {
instanceContainer.setChunkGenerator(chunkGenerator);
}
@Override
public ChunkGenerator getChunkGenerator() {
return instanceContainer.getChunkGenerator();
}
@Override
public Collection<Chunk> getChunks() {
return instanceContainer.getChunks();
@ -95,11 +100,6 @@ public class SharedInstance extends Instance {
instanceContainer.setStorageFolder(storageFolder);
}
@Override
public void sendChunkUpdate(Player player, Chunk chunk) {
instanceContainer.sendChunkUpdate(player, chunk);
}
@Override
public void sendChunkSectionUpdate(Chunk chunk, int section, Player player) {
instanceContainer.sendChunkSectionUpdate(chunk, section, player);
@ -111,7 +111,7 @@ public class SharedInstance extends Instance {
}
@Override
public void createChunk(int chunkX, int chunkZ, Consumer<Chunk> callback) {
protected void createChunk(int chunkX, int chunkZ, Consumer<Chunk> callback) {
instanceContainer.createChunk(chunkX, chunkZ, callback);
}

View File

@ -30,6 +30,7 @@ public class PlayerDiggingListener {
if (instance == null)
return;
final short blockId = instance.getBlockId(blockPosition);
switch (status) {