Minestom/src/main/java/fr/themode/minestom/instance/Instance.java

233 lines
8.1 KiB
Java
Raw Normal View History

2019-08-11 07:42:56 +02:00
package fr.themode.minestom.instance;
2019-08-23 15:37:38 +02:00
import fr.adamaq01.ozao.net.Buffer;
2019-08-27 05:23:25 +02:00
import fr.themode.minestom.Main;
2019-08-31 07:54:53 +02:00
import fr.themode.minestom.entity.*;
2019-08-21 16:50:52 +02:00
import fr.themode.minestom.utils.BlockPosition;
2019-08-25 20:03:43 +02:00
import fr.themode.minestom.utils.ChunkUtils;
import fr.themode.minestom.utils.Position;
2019-08-11 07:42:56 +02:00
import java.io.File;
2019-08-24 21:41:43 +02:00
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArraySet;
import java.util.function.Consumer;
2019-08-11 07:42:56 +02:00
2019-08-24 21:41:43 +02:00
public abstract class Instance implements BlockModifier {
2019-08-11 07:42:56 +02:00
2019-08-24 21:41:43 +02:00
protected static final ChunkLoaderIO CHUNK_LOADER_IO = new ChunkLoaderIO();
// Entities present in this instance
protected Set<Player> players = new CopyOnWriteArraySet<>();
2019-08-31 07:54:53 +02:00
protected Set<EntityCreature> creatures = new CopyOnWriteArraySet<>();
protected Set<ObjectEntity> objectEntities = new CopyOnWriteArraySet<>();
protected Set<ExperienceOrb> experienceOrbs = new CopyOnWriteArraySet<>();
2019-08-24 21:41:43 +02:00
// Entities per chunk
protected Map<Long, Set<Entity>> chunkEntities = new ConcurrentHashMap<>();
private UUID uniqueId;
2019-08-24 21:41:43 +02:00
protected Instance(UUID uniqueId) {
this.uniqueId = uniqueId;
}
2019-08-18 23:52:11 +02:00
2019-08-25 20:03:43 +02:00
public abstract void breakBlock(Player player, BlockPosition blockPosition);
2019-08-11 07:42:56 +02:00
2019-08-24 21:41:43 +02:00
public abstract void loadChunk(int chunkX, int chunkZ, Consumer<Chunk> callback);
2019-08-20 22:40:57 +02:00
2019-08-25 20:03:43 +02:00
// Load only if auto chunk load is enabled
public abstract void loadOptionalChunk(int chunkX, int chunkZ, Consumer<Chunk> callback);
2019-08-24 21:41:43 +02:00
public abstract Chunk getChunk(int chunkX, int chunkZ);
2019-08-20 22:40:57 +02:00
2019-08-24 21:41:43 +02:00
public abstract void saveToFolder(Runnable callback);
2019-08-24 21:41:43 +02:00
public abstract BlockBatch createBlockBatch();
2019-08-24 21:41:43 +02:00
public abstract ChunkBatch createChunkBatch(Chunk chunk);
2019-08-24 21:41:43 +02:00
public abstract void setChunkGenerator(ChunkGenerator chunkGenerator);
2019-08-19 17:04:19 +02:00
2019-08-24 21:41:43 +02:00
public abstract Collection<Chunk> getChunks();
2019-08-18 23:52:11 +02:00
2019-08-24 21:41:43 +02:00
public abstract File getFolder();
2019-08-20 22:40:57 +02:00
2019-08-24 21:41:43 +02:00
public abstract void setFolder(File folder);
2019-08-18 23:52:11 +02:00
2019-08-24 21:41:43 +02:00
public abstract void sendChunkUpdate(Player player, Chunk chunk);
2019-08-12 13:27:24 +02:00
2019-09-01 06:18:41 +02:00
public abstract void sendChunkSectionUpdate(Chunk chunk, int section, Player player);
2019-08-25 20:03:43 +02:00
protected abstract void retrieveChunk(int chunkX, int chunkZ, Consumer<Chunk> callback);
2019-08-11 07:42:56 +02:00
2019-08-24 21:41:43 +02:00
public abstract void createChunk(int chunkX, int chunkZ, Consumer<Chunk> callback);
2019-08-11 07:42:56 +02:00
2019-08-24 21:41:43 +02:00
public abstract void sendChunks(Player player);
2019-08-21 16:50:52 +02:00
2019-08-25 20:03:43 +02:00
public abstract void sendChunk(Player player, Chunk chunk);
public abstract void enableAutoChunkLoad(boolean enable);
public abstract boolean hasEnabledAutoChunkLoad();
2019-08-24 20:34:01 +02:00
//
2019-08-24 21:41:43 +02:00
protected void sendChunkUpdate(Collection<Player> players, Chunk chunk) {
2019-08-24 20:34:01 +02:00
Buffer chunkData = chunk.getFullDataPacket();
2019-08-24 21:41:43 +02:00
chunkData.getData().retain(players.size()).markReaderIndex();
2019-08-24 20:34:01 +02:00
players.forEach(player -> {
player.getPlayerConnection().sendUnencodedPacket(chunkData);
chunkData.getData().resetReaderIndex();
});
2019-08-11 07:42:56 +02:00
}
2019-08-24 20:34:01 +02:00
//
2019-08-22 14:52:32 +02:00
2019-08-31 07:54:53 +02:00
public Set<Player> getPlayers() {
return Collections.unmodifiableSet(players);
2019-08-24 21:41:43 +02:00
}
public Set<EntityCreature> getCreatures() {
return Collections.unmodifiableSet(creatures);
}
2019-08-31 07:54:53 +02:00
public Set<ObjectEntity> getObjectEntities() {
return Collections.unmodifiableSet(objectEntities);
}
public Set<ExperienceOrb> getExperienceOrbs() {
return Collections.unmodifiableSet(experienceOrbs);
2019-08-24 21:41:43 +02:00
}
public Set<Entity> getChunkEntities(Chunk chunk) {
2019-08-25 20:03:43 +02:00
return Collections.unmodifiableSet(getEntitiesInChunk(ChunkUtils.getChunkIndex(chunk.getChunkX(), chunk.getChunkZ())));
2019-08-19 17:04:19 +02:00
}
2019-08-24 21:41:43 +02:00
public void loadChunk(int chunkX, int chunkZ) {
2019-08-24 20:34:01 +02:00
loadChunk(chunkX, chunkZ, null);
2019-08-11 07:42:56 +02:00
}
2019-08-24 21:41:43 +02:00
public void loadChunk(Position position, Consumer<Chunk> callback) {
2019-08-24 20:34:01 +02:00
int chunkX = Math.floorDiv((int) position.getX(), 16);
int chunkZ = Math.floorDiv((int) position.getY(), 16);
loadChunk(chunkX, chunkZ, callback);
2019-08-11 07:42:56 +02:00
}
2019-08-24 21:41:43 +02:00
public short getBlockId(int x, int y, int z) {
2019-08-24 20:34:01 +02:00
Chunk chunk = getChunkAt(x, z);
return chunk.getBlockId((byte) (x % 16), (byte) y, (byte) (z % 16));
2019-08-11 07:42:56 +02:00
}
2019-08-24 21:41:43 +02:00
public short getBlockId(BlockPosition blockPosition) {
2019-08-24 20:34:01 +02:00
return getBlockId(blockPosition.getX(), blockPosition.getY(), blockPosition.getZ());
}
2019-08-24 21:41:43 +02:00
public CustomBlock getCustomBlock(int x, int y, int z) {
2019-08-24 20:34:01 +02:00
Chunk chunk = getChunkAt(x, z);
return chunk.getCustomBlock((byte) (x % 16), (byte) y, (byte) (z % 16));
}
2019-08-24 21:41:43 +02:00
public Chunk getChunkAt(double x, double z) {
2019-08-24 20:34:01 +02:00
int chunkX = Math.floorDiv((int) x, 16);
int chunkZ = Math.floorDiv((int) z, 16);
return getChunk(chunkX, chunkZ);
}
2019-08-24 21:41:43 +02:00
public boolean isChunkLoaded(int chunkX, int chunkZ) {
2019-08-24 20:34:01 +02:00
return getChunk(chunkX, chunkZ) != null;
}
2019-08-24 21:41:43 +02:00
public Chunk getChunkAt(BlockPosition blockPosition) {
2019-08-24 20:34:01 +02:00
return getChunkAt(blockPosition.getX(), blockPosition.getZ());
}
2019-08-24 21:41:43 +02:00
public Chunk getChunkAt(Position position) {
2019-08-24 20:34:01 +02:00
return getChunkAt(position.getX(), position.getZ());
2019-08-11 07:42:56 +02:00
}
2019-08-12 08:30:59 +02:00
2019-08-24 21:41:43 +02:00
public void saveToFolder() {
2019-08-24 20:34:01 +02:00
saveToFolder(null);
2019-08-19 17:04:19 +02:00
}
2019-08-24 21:41:43 +02:00
public UUID getUniqueId() {
return uniqueId;
}
// UNSAFE METHODS (need most of time to be synchronized)
2019-08-19 17:04:19 +02:00
2019-08-24 21:41:43 +02:00
public void addEntity(Entity entity) {
Instance lastInstance = entity.getInstance();
if (lastInstance != null && lastInstance != this) {
2019-08-25 20:03:43 +02:00
lastInstance.removeEntity(entity); // If entity is in another instance, remove it from there and add it to this
2019-08-24 21:41:43 +02:00
}
2019-08-27 20:49:11 +02:00
long[] visibleChunksEntity = ChunkUtils.getChunksInRange(entity.getPosition(), Main.ENTITY_VIEW_DISTANCE);
boolean isPlayer = entity instanceof Player;
if (isPlayer) {
sendChunks((Player) entity);
}
// Send all visible entities
for (long chunkIndex : visibleChunksEntity) {
getEntitiesInChunk(chunkIndex).forEach(ent -> {
if (isPlayer)
ent.addViewer((Player) entity);
if (ent instanceof Player) {
entity.addViewer((Player) ent);
}
});
2019-08-24 21:41:43 +02:00
}
Chunk chunk = getChunkAt(entity.getPosition());
addEntityToChunk(entity, chunk);
}
public void removeEntity(Entity entity) {
Instance entityInstance = entity.getInstance();
if (entityInstance == null || entityInstance != this)
return;
2019-08-25 20:03:43 +02:00
entity.getViewers().forEach(p -> entity.removeViewer(p)); // Remove this entity from players viewable list and send delete entities packet
2019-08-24 21:41:43 +02:00
Chunk chunk = getChunkAt(entity.getPosition());
removeEntityFromChunk(entity, chunk);
}
public void addEntityToChunk(Entity entity, Chunk chunk) {
2019-08-25 20:03:43 +02:00
long chunkIndex = ChunkUtils.getChunkIndex(chunk.getChunkX(), chunk.getChunkZ());
2019-08-24 21:41:43 +02:00
Set<Entity> entities = getEntitiesInChunk(chunkIndex);
entities.add(entity);
this.chunkEntities.put(chunkIndex, entities);
if (entity instanceof Player) {
this.players.add((Player) entity);
} else if (entity instanceof EntityCreature) {
this.creatures.add((EntityCreature) entity);
} else if (entity instanceof ObjectEntity) {
this.objectEntities.add((ObjectEntity) entity);
2019-08-31 07:54:53 +02:00
} else if (entity instanceof ExperienceOrb) {
this.experienceOrbs.add((ExperienceOrb) entity);
2019-08-24 21:41:43 +02:00
}
}
public void removeEntityFromChunk(Entity entity, Chunk chunk) {
2019-08-25 20:03:43 +02:00
long chunkIndex = ChunkUtils.getChunkIndex(chunk.getChunkX(), chunk.getChunkZ());
2019-08-24 21:41:43 +02:00
Set<Entity> entities = getEntitiesInChunk(chunkIndex);
entities.remove(entity);
2019-08-25 20:03:43 +02:00
if (entities.isEmpty()) {
this.chunkEntities.remove(chunkIndex);
} else {
this.chunkEntities.put(chunkIndex, entities);
}
2019-08-24 21:41:43 +02:00
if (entity instanceof Player) {
this.players.remove(entity);
} else if (entity instanceof EntityCreature) {
this.creatures.remove(entity);
} else if (entity instanceof ObjectEntity) {
this.objectEntities.remove(entity);
2019-08-31 07:54:53 +02:00
} else if (entity instanceof ExperienceOrb) {
this.experienceOrbs.remove((ExperienceOrb) entity);
2019-08-24 21:41:43 +02:00
}
}
private Set<Entity> getEntitiesInChunk(long index) {
return chunkEntities.getOrDefault(index, new CopyOnWriteArraySet<>());
}
2019-08-11 07:42:56 +02:00
}