More comments + cleanup

This commit is contained in:
Felix Cravic 2020-07-22 17:39:48 +02:00
parent 7c6f919120
commit df6c9e4953
14 changed files with 162 additions and 74 deletions

View File

@ -57,9 +57,9 @@ public class BoundingBox {
float minZ = z; float minZ = z;
float maxZ = z + offsetZ; float maxZ = z + offsetZ;
boolean checkX = getMinX() < maxX && getMaxX() > minX; final boolean checkX = getMinX() < maxX && getMaxX() > minX;
boolean checkY = getMinY() < maxY && getMaxY() > minY; final boolean checkY = getMinY() < maxY && getMaxY() > minY;
boolean checkZ = getMinZ() < maxZ && getMaxZ() > minZ; final boolean checkZ = getMinZ() < maxZ && getMaxZ() > minZ;
return checkX && checkY && checkZ; return checkX && checkY && checkZ;
} }
@ -75,6 +75,8 @@ public class BoundingBox {
} }
/** /**
* Create a new bounding box linked to the same entity with expanded size
*
* @param x the X offset * @param x the X offset
* @param y the Y offset * @param y the Y offset
* @param z the Z offset * @param z the Z offset
@ -85,6 +87,8 @@ public class BoundingBox {
} }
/** /**
* Create a new bounding box linked to the same entity with contracted size
*
* @param x the X offset * @param x the X offset
* @param y the Y offset * @param y the Y offset
* @param z the Z offset * @param z the Z offset

View File

@ -29,14 +29,38 @@ public class Data {
protected ConcurrentHashMap<String, Object> data = new ConcurrentHashMap(); protected ConcurrentHashMap<String, Object> data = new ConcurrentHashMap();
/**
* Set a value to a specific key
*
* @param key the key
* @param value the value object
* @param type the value type
* @param <T> the value generic
*/
public <T> void set(String key, T value, Class<T> type) { public <T> void set(String key, T value, Class<T> type) {
this.data.put(key, value); this.data.put(key, value);
} }
/**
* Retrieve a value based on its key
*
* @param key the key
* @param <T> the value type
* @return the data associated with the key
* @throws NullPointerException if the key is not found
*/
public <T> T get(String key) { public <T> T get(String key) {
return (T) data.get(key); return (T) data.get(key);
} }
/**
* Retrieve a value based on its key, give a default value if not found
*
* @param key the key
* @param defaultValue the value to return if the key is not found
* @param <T> the value type
* @return {@link #get(String)} if found, {@code defaultValue} otherwise
*/
public <T> T getOrDefault(String key, T defaultValue) { public <T> T getOrDefault(String key, T defaultValue) {
return (T) data.getOrDefault(key, defaultValue); return (T) data.getOrDefault(key, defaultValue);
} }

View File

@ -16,6 +16,17 @@ public class SerializableData extends Data {
private ConcurrentHashMap<String, Class> dataType = new ConcurrentHashMap<>(); private ConcurrentHashMap<String, Class> dataType = new ConcurrentHashMap<>();
/**
* Set a value to a specific key
* <p>
* WARNING: the type needs to be registered in {@link DataManager}
*
* @param key the key
* @param value the value object
* @param type the value type
* @param <T> the value generic
* @throws UnsupportedOperationException if {@code type} is not registered in {@link DataManager}
*/
@Override @Override
public <T> void set(String key, T value, Class<T> type) { public <T> void set(String key, T value, Class<T> type) {
if (DATA_MANAGER.getDataType(type) == null) { if (DATA_MANAGER.getDataType(type) == null) {
@ -34,6 +45,15 @@ public class SerializableData extends Data {
return data; return data;
} }
/**
* Serialize the data into an array of bytes
* <p>
* Use {@link net.minestom.server.reader.DataReader#readData(byte[])}
* to convert it back
*
* @return the array representation of this data object
* @throws IOException if an error occur when serializing the data
*/
public byte[] getSerializedData() throws IOException { public byte[] getSerializedData() throws IOException {
ByteArrayOutputStream output = new ByteArrayOutputStream(); ByteArrayOutputStream output = new ByteArrayOutputStream();
DataOutputStream dos = new DataOutputStream(output); DataOutputStream dos = new DataOutputStream(output);

View File

@ -929,10 +929,10 @@ public abstract class Entity implements Viewable, EventHandler, DataContainer {
} }
} }
Instance instance = getInstance(); final Instance instance = getInstance();
if (instance != null) { if (instance != null) {
Chunk lastChunk = instance.getChunkAt(lastX, lastZ); final Chunk lastChunk = instance.getChunkAt(lastX, lastZ);
Chunk newChunk = instance.getChunkAt(x, z); final Chunk newChunk = instance.getChunkAt(x, z);
if (lastChunk != null && newChunk != null && lastChunk != newChunk) { if (lastChunk != null && newChunk != null && lastChunk != newChunk) {
synchronized (instance) { synchronized (instance) {
instance.removeEntityFromChunk(this, lastChunk); instance.removeEntityFromChunk(this, lastChunk);
@ -952,24 +952,24 @@ public abstract class Entity implements Viewable, EventHandler, DataContainer {
} }
private void updateView(Chunk lastChunk, Chunk newChunk) { private void updateView(Chunk lastChunk, Chunk newChunk) {
boolean isPlayer = this instanceof Player; final boolean isPlayer = this instanceof Player;
if (isPlayer) if (isPlayer)
((Player) this).onChunkChange(lastChunk, newChunk); // Refresh loaded chunk ((Player) this).onChunkChange(lastChunk, newChunk); // Refresh loaded chunk
// Refresh entity viewable list // Refresh entity viewable list
long[] lastVisibleChunksEntity = ChunkUtils.getChunksInRange(new Position(16 * lastChunk.getChunkX(), 0, 16 * lastChunk.getChunkZ()), MinecraftServer.ENTITY_VIEW_DISTANCE); final long[] lastVisibleChunksEntity = ChunkUtils.getChunksInRange(new Position(16 * lastChunk.getChunkX(), 0, 16 * lastChunk.getChunkZ()), MinecraftServer.ENTITY_VIEW_DISTANCE);
long[] updatedVisibleChunksEntity = ChunkUtils.getChunksInRange(new Position(16 * newChunk.getChunkX(), 0, 16 * newChunk.getChunkZ()), MinecraftServer.ENTITY_VIEW_DISTANCE); final long[] updatedVisibleChunksEntity = ChunkUtils.getChunksInRange(new Position(16 * newChunk.getChunkX(), 0, 16 * newChunk.getChunkZ()), MinecraftServer.ENTITY_VIEW_DISTANCE);
int[] oldChunksEntity = ArrayUtils.getDifferencesBetweenArray(lastVisibleChunksEntity, updatedVisibleChunksEntity); final int[] oldChunksEntity = ArrayUtils.getDifferencesBetweenArray(lastVisibleChunksEntity, updatedVisibleChunksEntity);
for (int index : oldChunksEntity) { for (int index : oldChunksEntity) {
int[] chunkPos = ChunkUtils.getChunkCoord(lastVisibleChunksEntity[index]); final int[] chunkPos = ChunkUtils.getChunkCoord(lastVisibleChunksEntity[index]);
Chunk chunk = instance.getChunk(chunkPos[0], chunkPos[1]); final Chunk chunk = instance.getChunk(chunkPos[0], chunkPos[1]);
if (chunk == null) if (chunk == null)
continue; continue;
instance.getChunkEntities(chunk).forEach(ent -> { instance.getChunkEntities(chunk).forEach(ent -> {
if (ent instanceof Player) { if (ent instanceof Player) {
Player player = (Player) ent; final Player player = (Player) ent;
if (isAutoViewable()) if (isAutoViewable())
removeViewer(player); removeViewer(player);
if (isPlayer) { if (isPlayer) {
@ -981,10 +981,10 @@ public abstract class Entity implements Viewable, EventHandler, DataContainer {
}); });
} }
int[] newChunksEntity = ArrayUtils.getDifferencesBetweenArray(updatedVisibleChunksEntity, lastVisibleChunksEntity); final int[] newChunksEntity = ArrayUtils.getDifferencesBetweenArray(updatedVisibleChunksEntity, lastVisibleChunksEntity);
for (int index : newChunksEntity) { for (int index : newChunksEntity) {
int[] chunkPos = ChunkUtils.getChunkCoord(updatedVisibleChunksEntity[index]); final int[] chunkPos = ChunkUtils.getChunkCoord(updatedVisibleChunksEntity[index]);
Chunk chunk = instance.getChunk(chunkPos[0], chunkPos[1]); final Chunk chunk = instance.getChunk(chunkPos[0], chunkPos[1]);
if (chunk == null) if (chunk == null)
continue; continue;
instance.getChunkEntities(chunk).forEach(ent -> { instance.getChunkEntities(chunk).forEach(ent -> {
@ -1066,12 +1066,12 @@ public abstract class Entity implements Viewable, EventHandler, DataContainer {
*/ */
public boolean sameChunk(Position position) { public boolean sameChunk(Position position) {
Check.notNull(position, "Position cannot be null"); Check.notNull(position, "Position cannot be null");
Position pos = getPosition(); final Position pos = getPosition();
int chunkX1 = ChunkUtils.getChunkCoordinate((int) Math.floor(pos.getX())); final int chunkX1 = ChunkUtils.getChunkCoordinate((int) Math.floor(pos.getX()));
int chunkZ1 = ChunkUtils.getChunkCoordinate((int) Math.floor(pos.getZ())); final int chunkZ1 = ChunkUtils.getChunkCoordinate((int) Math.floor(pos.getZ()));
int chunkX2 = ChunkUtils.getChunkCoordinate((int) Math.floor(position.getX())); final int chunkX2 = ChunkUtils.getChunkCoordinate((int) Math.floor(position.getX()));
int chunkZ2 = ChunkUtils.getChunkCoordinate((int) Math.floor(position.getZ())); final int chunkZ2 = ChunkUtils.getChunkCoordinate((int) Math.floor(position.getZ()));
return chunkX1 == chunkX2 && chunkZ1 == chunkZ2; return chunkX1 == chunkX2 && chunkZ1 == chunkZ2;
} }

View File

@ -63,24 +63,24 @@ public abstract class EntityCreature extends LivingEntity {
* @param updateView should the entity move its head toward the position? * @param updateView should the entity move its head toward the position?
*/ */
public void move(float x, float y, float z, boolean updateView) { public void move(float x, float y, float z, boolean updateView) {
Position position = getPosition(); final Position position = getPosition();
Position newPosition = new Position(); Position newPosition = new Position();
// Calculate collisions boxes // Calculate collisions boxes
onGround = CollisionUtils.handlePhysics(this, new Vector(x, y, z), newPosition, new Vector()); onGround = CollisionUtils.handlePhysics(this, new Vector(x, y, z), newPosition, new Vector());
// Refresh target position // Refresh target position
float newX = newPosition.getX(); final float newX = newPosition.getX();
float newY = newPosition.getY(); final float newY = newPosition.getY();
float newZ = newPosition.getZ(); final float newZ = newPosition.getZ();
// Creatures cannot move in unload chunk // Creatures cannot move in unload chunk
if (ChunkUtils.isChunkUnloaded(getInstance(), newX, newZ)) if (ChunkUtils.isChunkUnloaded(getInstance(), newX, newZ))
return; return;
float lastYaw = position.getYaw(); final float lastYaw = position.getYaw();
float radians = (float) Math.atan2(newZ - position.getZ(), newX - position.getX()); final float radians = (float) Math.atan2(newZ - position.getZ(), newX - position.getX());
float yaw = (float) (radians * (180.0 / Math.PI)) - 90; final float yaw = (float) (radians * (180.0 / Math.PI)) - 90;
float pitch = position.getPitch(); // TODO final float pitch = position.getPitch(); // TODO
final short deltaX = (short) ((newX * 32 - position.getX() * 32) * 128); final short deltaX = (short) ((newX * 32 - position.getX() * 32) * 128);
final short deltaY = (short) ((newY * 32 - position.getY() * 32) * 128); final short deltaY = (short) ((newY * 32 - position.getY() * 32) * 128);
@ -289,14 +289,14 @@ public abstract class EntityCreature extends LivingEntity {
* @param speed define how far the entity will move * @param speed define how far the entity will move
*/ */
public void moveTowards(Position direction, float speed) { public void moveTowards(Position direction, float speed) {
float radians = (float) Math.atan2(direction.getZ() - position.getZ(), direction.getX() - position.getX()); final float radians = (float) Math.atan2(direction.getZ() - position.getZ(), direction.getX() - position.getX());
float speedX = (float) (Math.cos(radians) * speed); final float speedX = (float) (Math.cos(radians) * speed);
float speedZ = (float) (Math.sin(radians) * speed); final float speedZ = (float) (Math.sin(radians) * speed);
move(speedX, 0, speedZ, true); move(speedX, 0, speedZ, true);
} }
private void setNextPathPosition() { private void setNextPathPosition() {
BlockPosition blockPosition = blockPositions.pollFirst(); final BlockPosition blockPosition = blockPositions.pollFirst();
if (blockPosition == null) { if (blockPosition == null) {
this.blockPositions = null; this.blockPositions = null;
@ -312,7 +312,7 @@ public abstract class EntityCreature extends LivingEntity {
private void pathProgress() { private void pathProgress() {
if (blockPositions != null) { if (blockPositions != null) {
if (targetPosition != null) { if (targetPosition != null) {
float distance = getPosition().getDistance(targetPosition); final float distance = getPosition().getDistance(targetPosition);
//System.out.println("test: "+distance); //System.out.println("test: "+distance);
if (distance < 1f) { if (distance < 1f) {
setNextPathPosition(); setNextPathPosition();

View File

@ -33,7 +33,7 @@ public final class EntityManager {
PlayerLoginEvent loginEvent = new PlayerLoginEvent(playerCache); PlayerLoginEvent loginEvent = new PlayerLoginEvent(playerCache);
playerCache.callEvent(PlayerLoginEvent.class, loginEvent); playerCache.callEvent(PlayerLoginEvent.class, loginEvent);
Instance spawningInstance = loginEvent.getSpawningInstance(); final Instance spawningInstance = loginEvent.getSpawningInstance();
Check.notNull(spawningInstance, "You need to specify a spawning instance in the PlayerLoginEvent"); Check.notNull(spawningInstance, "You need to specify a spawning instance in the PlayerLoginEvent");
@ -68,8 +68,8 @@ public final class EntityManager {
// Add him to the list and change his username/uuid if changed // Add him to the list and change his username/uuid if changed
this.waitingPlayers.add(player); this.waitingPlayers.add(player);
String username = playerPreLoginEvent.getUsername(); final String username = playerPreLoginEvent.getUsername();
UUID uuid = playerPreLoginEvent.getPlayerUuid(); final UUID uuid = playerPreLoginEvent.getPlayerUuid();
player.setUsername(username); player.setUsername(username);
player.setUuid(uuid); player.setUuid(uuid);

View File

@ -68,8 +68,8 @@ public class ItemEntity extends ObjectEntity {
(mergeUpdateOption == null || !CooldownUtils.hasCooldown(time, lastMergeCheck, mergeUpdateOption))) { (mergeUpdateOption == null || !CooldownUtils.hasCooldown(time, lastMergeCheck, mergeUpdateOption))) {
this.lastMergeCheck = time; this.lastMergeCheck = time;
Chunk chunk = instance.getChunkAt(getPosition()); final Chunk chunk = instance.getChunkAt(getPosition());
Set<Entity> entities = instance.getChunkEntities(chunk); final Set<Entity> entities = instance.getChunkEntities(chunk);
for (Entity entity : entities) { for (Entity entity : entities) {
if (entity instanceof ItemEntity) { if (entity instanceof ItemEntity) {

View File

@ -453,7 +453,7 @@ public abstract class LivingEntity extends Entity implements EquipmentHandler {
EntityPropertiesPacket propertiesPacket = new EntityPropertiesPacket(); EntityPropertiesPacket propertiesPacket = new EntityPropertiesPacket();
propertiesPacket.entityId = getEntityId(); propertiesPacket.entityId = getEntityId();
int length = Attribute.values().length; final int length = Attribute.values().length;
EntityPropertiesPacket.Property[] properties = new EntityPropertiesPacket.Property[length]; EntityPropertiesPacket.Property[] properties = new EntityPropertiesPacket.Property[length];
for (int i = 0; i < length; i++) { for (int i = 0; i < length; i++) {
EntityPropertiesPacket.Property property = new EntityPropertiesPacket.Property(); EntityPropertiesPacket.Property property = new EntityPropertiesPacket.Property();

View File

@ -30,7 +30,7 @@ public abstract class ObjectEntity extends Entity {
@Override @Override
public boolean addViewer(Player player) { public boolean addViewer(Player player) {
boolean result = super.addViewer(player); final boolean result = super.addViewer(player);
if (!result) if (!result)
return false; return false;

View File

@ -270,7 +270,7 @@ public class Player extends LivingEntity implements CommandSender {
return false; return false;
// Compute final heart based on health and additional hearts // Compute final heart based on health and additional hearts
boolean result = super.damage(type, value); final boolean result = super.damage(type, value);
if (result) { if (result) {
lastDamageSource = type; lastDamageSource = type;
} }
@ -301,7 +301,7 @@ public class Player extends LivingEntity implements CommandSender {
// Target block stage // Target block stage
if (targetCustomBlock != null) { if (targetCustomBlock != null) {
final byte animationCount = 10; final byte animationCount = 10;
long since = time - targetBlockTime; final long since = time - targetBlockTime;
byte stage = (byte) (since / (blockBreakTime / animationCount)); byte stage = (byte) (since / (blockBreakTime / animationCount));
stage = MathUtils.setBetween(stage, (byte) -1, animationCount); stage = MathUtils.setBetween(stage, (byte) -1, animationCount);
if (stage != targetLastStage) { if (stage != targetLastStage) {
@ -315,12 +315,12 @@ public class Player extends LivingEntity implements CommandSender {
} }
// Experience orb pickup // Experience orb pickup
Chunk chunk = instance.getChunkAt(getPosition()); // TODO check surrounding chunks final Chunk chunk = instance.getChunkAt(getPosition()); // TODO check surrounding chunks
Set<Entity> entities = instance.getChunkEntities(chunk); final Set<Entity> entities = instance.getChunkEntities(chunk);
for (Entity entity : entities) { for (Entity entity : entities) {
if (entity instanceof ExperienceOrb) { if (entity instanceof ExperienceOrb) {
ExperienceOrb experienceOrb = (ExperienceOrb) entity; final ExperienceOrb experienceOrb = (ExperienceOrb) entity;
BoundingBox itemBoundingBox = experienceOrb.getBoundingBox(); final BoundingBox itemBoundingBox = experienceOrb.getBoundingBox();
if (expandedBoundingBox.intersect(itemBoundingBox)) { if (expandedBoundingBox.intersect(itemBoundingBox)) {
synchronized (experienceOrb) { synchronized (experienceOrb) {
if (experienceOrb.shouldRemove() || experienceOrb.isRemoveScheduled()) if (experienceOrb.shouldRemove() || experienceOrb.isRemoveScheduled())
@ -344,11 +344,11 @@ public class Player extends LivingEntity implements CommandSender {
ItemUpdateStateEvent itemUpdateStateEvent = callItemUpdateStateEvent(true); ItemUpdateStateEvent itemUpdateStateEvent = callItemUpdateStateEvent(true);
// Refresh hand // Refresh hand
boolean isOffHand = itemUpdateStateEvent.getHand() == Player.Hand.OFF; final boolean isOffHand = itemUpdateStateEvent.getHand() == Player.Hand.OFF;
refreshActiveHand(false, isOffHand, false); refreshActiveHand(false, isOffHand, false);
ItemStack foodItem = itemUpdateStateEvent.getItemStack(); final ItemStack foodItem = itemUpdateStateEvent.getItemStack();
boolean isFood = foodItem.getMaterial().isFood(); final boolean isFood = foodItem.getMaterial().isFood();
if (isFood) { if (isFood) {
PlayerEatEvent playerEatEvent = new PlayerEatEvent(this, foodItem); PlayerEatEvent playerEatEvent = new PlayerEatEvent(this, foodItem);
@ -508,7 +508,7 @@ public class Player extends LivingEntity implements CommandSender {
if (player == this) if (player == this)
return false; return false;
boolean result = super.addViewer(player); final boolean result = super.addViewer(player);
if (!result) if (!result)
return false; return false;
@ -537,7 +537,7 @@ public class Player extends LivingEntity implements CommandSender {
Check.notNull(instance, "instance cannot be null!"); Check.notNull(instance, "instance cannot be null!");
Check.argCondition(this.instance == instance, "Instance should be different than the current one"); Check.argCondition(this.instance == instance, "Instance should be different than the current one");
boolean firstSpawn = this.instance == null; // TODO: Handle player reconnections, must be false in that case too final boolean firstSpawn = this.instance == null; // TODO: Handle player reconnections, must be false in that case too
for (Chunk viewableChunk : viewableChunks) { for (Chunk viewableChunk : viewableChunks) {
viewableChunk.removeViewer(this); viewableChunk.removeViewer(this);
} }
@ -549,14 +549,14 @@ public class Player extends LivingEntity implements CommandSender {
sendDimension(instanceDimensionType); sendDimension(instanceDimensionType);
} }
long[] visibleChunks = ChunkUtils.getChunksInRange(position, getChunkRange()); final long[] visibleChunks = ChunkUtils.getChunksInRange(position, getChunkRange());
int length = visibleChunks.length; final int length = visibleChunks.length;
AtomicInteger counter = new AtomicInteger(0); AtomicInteger counter = new AtomicInteger(0);
for (int i = 0; i < length; i++) { for (int i = 0; i < length; i++) {
int[] chunkPos = ChunkUtils.getChunkCoord(visibleChunks[i]); final int[] chunkPos = ChunkUtils.getChunkCoord(visibleChunks[i]);
int chunkX = chunkPos[0]; final int chunkX = chunkPos[0];
int chunkZ = chunkPos[1]; final int chunkZ = chunkPos[1];
Consumer<Chunk> callback = (chunk) -> { Consumer<Chunk> callback = (chunk) -> {
if (chunk != null) { if (chunk != null) {
viewableChunks.add(chunk); viewableChunks.add(chunk);
@ -564,7 +564,7 @@ public class Player extends LivingEntity implements CommandSender {
instance.sendChunk(this, chunk); instance.sendChunk(this, chunk);
updateViewPosition(chunk); updateViewPosition(chunk);
} }
boolean isLast = counter.get() == length - 1; final boolean isLast = counter.get() == length - 1;
if (isLast) { if (isLast) {
// This is the last chunk to be loaded , spawn player // This is the last chunk to be loaded , spawn player
super.setInstance(instance); super.setInstance(instance);
@ -606,7 +606,7 @@ public class Player extends LivingEntity implements CommandSender {
/** /**
* Send a {@link BlockBreakAnimationPacket} packet to the player and his viewers * Send a {@link BlockBreakAnimationPacket} packet to the player and his viewers
* Setting {@code destroyStage} to -1 reset the break animation * Setting {@code destroyStage} to -1 resets the break animation
* *
* @param blockPosition the position of the block * @param blockPosition the position of the block
* @param destroyStage the destroy stage * @param destroyStage the destroy stage
@ -899,6 +899,8 @@ public class Player extends LivingEntity implements CommandSender {
/** /**
* Change the player skin * Change the player skin
* <p>
* This does remove the player for all viewers to spawn it again with the correct new skin
* *
* @param skin the player skin, null to reset it to his {@link #getUuid()} default skin * @param skin the player skin, null to reset it to his {@link #getUuid()} default skin
*/ */
@ -908,8 +910,8 @@ public class Player extends LivingEntity implements CommandSender {
DestroyEntitiesPacket destroyEntitiesPacket = new DestroyEntitiesPacket(); DestroyEntitiesPacket destroyEntitiesPacket = new DestroyEntitiesPacket();
destroyEntitiesPacket.entityIds = new int[]{getEntityId()}; destroyEntitiesPacket.entityIds = new int[]{getEntityId()};
PlayerInfoPacket removePlayerPacket = getRemovePlayerToList(); final PlayerInfoPacket removePlayerPacket = getRemovePlayerToList();
PlayerInfoPacket addPlayerPacket = getAddPlayerToList(); final PlayerInfoPacket addPlayerPacket = getAddPlayerToList();
RespawnPacket respawnPacket = new RespawnPacket(); RespawnPacket respawnPacket = new RespawnPacket();
respawnPacket.dimensionType = getDimensionType(); respawnPacket.dimensionType = getDimensionType();
@ -1007,7 +1009,6 @@ public class Player extends LivingEntity implements CommandSender {
public void setResourcePack(ResourcePack resourcePack) { public void setResourcePack(ResourcePack resourcePack) {
Check.notNull(resourcePack, "The resource pack cannot be null"); Check.notNull(resourcePack, "The resource pack cannot be null");
final String url = resourcePack.getUrl(); final String url = resourcePack.getUrl();
Check.notNull(url, "The resource pack url cannot be null");
final String hash = resourcePack.getHash(); final String hash = resourcePack.getHash();
ResourcePackSendPacket resourcePackSendPacket = new ResourcePackSendPacket(); ResourcePackSendPacket resourcePackSendPacket = new ResourcePackSendPacket();
@ -1157,15 +1158,24 @@ public class Player extends LivingEntity implements CommandSender {
playerConnection.sendPacket(setExperiencePacket); playerConnection.sendPacket(setExperiencePacket);
} }
/**
* Called when the player changes chunk (move from one to another)
* <p>
* It does remove and add the player from the chunks viewers list when removed or added
* It also calls the events {@link PlayerChunkUnloadEvent} and {@link PlayerChunkLoadEvent}
*
* @param lastChunk the last player chunk
* @param newChunk the current/new player chunk
*/
protected void onChunkChange(Chunk lastChunk, Chunk newChunk) { protected void onChunkChange(Chunk lastChunk, Chunk newChunk) {
long[] lastVisibleChunks = ChunkUtils.getChunksInRange(new Position(16 * lastChunk.getChunkX(), 0, 16 * lastChunk.getChunkZ()), MinecraftServer.CHUNK_VIEW_DISTANCE); final long[] lastVisibleChunks = ChunkUtils.getChunksInRange(new Position(16 * lastChunk.getChunkX(), 0, 16 * lastChunk.getChunkZ()), MinecraftServer.CHUNK_VIEW_DISTANCE);
long[] updatedVisibleChunks = ChunkUtils.getChunksInRange(new Position(16 * newChunk.getChunkX(), 0, 16 * newChunk.getChunkZ()), MinecraftServer.CHUNK_VIEW_DISTANCE); final long[] updatedVisibleChunks = ChunkUtils.getChunksInRange(new Position(16 * newChunk.getChunkX(), 0, 16 * newChunk.getChunkZ()), MinecraftServer.CHUNK_VIEW_DISTANCE);
int[] oldChunks = ArrayUtils.getDifferencesBetweenArray(lastVisibleChunks, updatedVisibleChunks); final int[] oldChunks = ArrayUtils.getDifferencesBetweenArray(lastVisibleChunks, updatedVisibleChunks);
int[] newChunks = ArrayUtils.getDifferencesBetweenArray(updatedVisibleChunks, lastVisibleChunks); final int[] newChunks = ArrayUtils.getDifferencesBetweenArray(updatedVisibleChunks, lastVisibleChunks);
// Unload old chunks // Unload old chunks
for (int index : oldChunks) { for (int index : oldChunks) {
int[] chunkPos = ChunkUtils.getChunkCoord(lastVisibleChunks[index]); final int[] chunkPos = ChunkUtils.getChunkCoord(lastVisibleChunks[index]);
UnloadChunkPacket unloadChunkPacket = new UnloadChunkPacket(); UnloadChunkPacket unloadChunkPacket = new UnloadChunkPacket();
unloadChunkPacket.chunkX = chunkPos[0]; unloadChunkPacket.chunkX = chunkPos[0];
unloadChunkPacket.chunkZ = chunkPos[1]; unloadChunkPacket.chunkZ = chunkPos[1];
@ -1180,8 +1190,8 @@ public class Player extends LivingEntity implements CommandSender {
// Load new chunks // Load new chunks
for (int i = 0; i < newChunks.length; i++) { for (int i = 0; i < newChunks.length; i++) {
int index = newChunks[i]; final int index = newChunks[i];
int[] chunkPos = ChunkUtils.getChunkCoord(updatedVisibleChunks[index]); final int[] chunkPos = ChunkUtils.getChunkCoord(updatedVisibleChunks[index]);
instance.loadOptionalChunk(chunkPos[0], chunkPos[1], chunk -> { instance.loadOptionalChunk(chunkPos[0], chunkPos[1], chunk -> {
if (chunk == null) { if (chunk == null) {
// Cannot load chunk (auto load is not enabled) // Cannot load chunk (auto load is not enabled)
@ -1567,7 +1577,8 @@ public class Player extends LivingEntity implements CommandSender {
this.permissionLevel = permissionLevel; this.permissionLevel = permissionLevel;
// Magic values: https://wiki.vg/Entity_statuses#Player // Magic values: https://wiki.vg/Entity_statuses#Player
byte permissionLevelStatus = (byte) (24 + permissionLevel); // TODO remove magic values
final byte permissionLevelStatus = (byte) (24 + permissionLevel);
triggerStatus(permissionLevelStatus); triggerStatus(permissionLevelStatus);
} }
@ -1580,7 +1591,8 @@ public class Player extends LivingEntity implements CommandSender {
this.reducedDebugScreenInformation = reduced; this.reducedDebugScreenInformation = reduced;
// Magic values: https://wiki.vg/Entity_statuses#Player // Magic values: https://wiki.vg/Entity_statuses#Player
byte debugScreenStatus = (byte) (reduced ? 22 : 23); // TODO remove magic values
final byte debugScreenStatus = (byte) (reduced ? 22 : 23);
triggerStatus(debugScreenStatus); triggerStatus(debugScreenStatus);
} }

View File

@ -14,8 +14,8 @@ import java.util.Iterator;
*/ */
public class PlayerSkin { public class PlayerSkin {
private String textures; private final String textures;
private String signature; private final String signature;
public PlayerSkin(String textures, String signature) { public PlayerSkin(String textures, String signature) {
this.textures = textures; this.textures = textures;

View File

@ -351,7 +351,7 @@ public abstract class Instance implements BlockModifier, EventHandler, DataConta
if (chunk == null) if (chunk == null)
return new HashSet<>(); return new HashSet<>();
long index = ChunkUtils.getChunkIndex(chunk.getChunkX(), chunk.getChunkZ()); final long index = ChunkUtils.getChunkIndex(chunk.getChunkX(), chunk.getChunkZ());
return Collections.unmodifiableSet(getEntitiesInChunk(index)); return Collections.unmodifiableSet(getEntitiesInChunk(index));
} }

View File

@ -1,15 +1,29 @@
package net.minestom.server.reader; package net.minestom.server.reader;
import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import net.minestom.server.MinecraftServer; import net.minestom.server.MinecraftServer;
import net.minestom.server.data.DataManager; import net.minestom.server.data.DataManager;
import net.minestom.server.data.SerializableData; import net.minestom.server.data.SerializableData;
import net.minestom.server.network.packet.PacketReader; import net.minestom.server.network.packet.PacketReader;
/**
* Class used to convert an array of bytes to a {@link SerializableData}
* <p>
* WARNING: the {@link DataManager} needs to have all the required types as the {@link SerializableData} has
*/
public class DataReader { public class DataReader {
private static final DataManager DATA_MANAGER = MinecraftServer.getDataManager(); private static final DataManager DATA_MANAGER = MinecraftServer.getDataManager();
/**
* Convert a buffer into a {@link SerializableData}
* <p>
* WARNING: the {@link DataManager} needs to have all the required types as the {@link SerializableData} has
*
* @param buffer the data
* @return a {@link SerializableData} based on the data input
*/
public static SerializableData readData(ByteBuf buffer) { public static SerializableData readData(ByteBuf buffer) {
SerializableData data = new SerializableData(); SerializableData data = new SerializableData();
try { try {
@ -50,4 +64,15 @@ public class DataReader {
return data; return data;
} }
/**
* Convert a bytes array to a {@link SerializableData}
*
* @param data the data
* @return a {@link SerializableData} based on the data input
* @see #readData(ByteBuf)
*/
public static SerializableData readData(byte[] data) {
return readData(Unpooled.wrappedBuffer(data));
}
} }

View File

@ -1,5 +1,7 @@
package net.minestom.server.resourcepack; package net.minestom.server.resourcepack;
import net.minestom.server.utils.validate.Check;
/** /**
* Represent a resource pack which can be send to a player * Represent a resource pack which can be send to a player
*/ */
@ -9,6 +11,7 @@ public class ResourcePack {
private String hash; private String hash;
public ResourcePack(String url, String hash) { public ResourcePack(String url, String hash) {
Check.notNull(url, "The resource pack url cannot be null");
this.url = url; this.url = url;
// Optional, set to empty if null // Optional, set to empty if null
this.hash = hash == null ? "" : hash; this.hash = hash == null ? "" : hash;