Moved chunk code to ChunkManager

This commit is contained in:
kuroppoi 2022-04-03 14:18:56 +02:00
parent 8b9c978d1b
commit 565301f528
2 changed files with 141 additions and 95 deletions

View file

@ -7,6 +7,12 @@ import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
@ -17,6 +23,7 @@ import org.msgpack.jackson.dataformat.MessagePackFactory;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.module.SimpleModule;
import brainwine.gameserver.entity.player.Player;
import brainwine.gameserver.serialization.BlockDeserializer;
import brainwine.gameserver.serialization.BlockSerializer;
import brainwine.gameserver.util.ZipUtils;
@ -29,6 +36,7 @@ public class ChunkManager {
.registerModule(new SimpleModule()
.addDeserializer(Block.class, BlockDeserializer.INSTANCE)
.addSerializer(BlockSerializer.INSTANCE));
private final Map<Integer, Chunk> chunks = new HashMap<>();
private final Zone zone;
private final File blocksFile;
private RandomAccessFile file;
@ -84,32 +92,35 @@ public class ChunkManager {
}
}
public Chunk loadChunk(int index) {
try {
if(file == null) {
file = new RandomAccessFile(blocksFile, "rw");
}
file.seek(dataOffset + index * allocSize);
byte[] bytes = new byte[file.readShort()];
file.read(bytes);
return mapper.readValue(ZipUtils.inflateBytes(bytes), Chunk.class);
} catch(Exception e) {
logger.error("Could not load chunk {} of zone {}", index, zone.getDocumentId(), e);
}
public void saveChunks() {
List<Chunk> inactiveChunks = new ArrayList<>();
return null;
}
public void saveModifiedChunks() {
for(Chunk chunk : zone.getChunks()) {
if(chunk.isModified()) {
saveChunk(chunk);
}
boolean active = false;
for(Player player : zone.getPlayers()) {
if(player.isChunkActive(chunk)) {
active = true;
break;
}
}
if(!active) {
inactiveChunks.add(chunk);
}
}
for(Chunk chunk : inactiveChunks) {
chunks.remove(getChunkIndex(chunk.getX(), chunk.getY()));
zone.onChunkUnloaded(chunk);
}
}
public void saveChunk(Chunk chunk) {
private void saveChunk(Chunk chunk) {
int index = zone.getChunkIndex(chunk.getX(), chunk.getY());
try {
@ -131,4 +142,68 @@ public class ChunkManager {
logger.error("Could not save chunk {} of zone {}", index, zone.getDocumentId(), e);
}
}
private Chunk loadChunk(int index) {
try {
if(file == null) {
file = new RandomAccessFile(blocksFile, "rw");
}
file.seek(dataOffset + index * allocSize);
byte[] bytes = new byte[file.readShort()];
file.read(bytes);
return mapper.readValue(ZipUtils.inflateBytes(bytes), Chunk.class);
} catch(Exception e) {
logger.error("Could not load chunk {} of zone {}", index, zone.getDocumentId(), e);
}
return null;
}
public void putChunk(int index, Chunk chunk) {
if(!chunks.containsKey(index) && isChunkIndexInBounds(index)) {
chunk.setModified(true);
chunks.put(index, chunk);
}
}
public boolean isChunkLoaded(int x, int y) {
return isChunkLoaded(getChunkIndex(x, y));
}
public boolean isChunkLoaded(int index) {
return chunks.containsKey(index);
}
public boolean isChunkIndexInBounds(int index) {
return index >= 0 && index < zone.getNumChunksWidth() * zone.getNumChunksHeight();
}
public int getChunkIndex(int x, int y) {
return y / zone.getChunkHeight() * zone.getNumChunksWidth() + x / zone.getChunkWidth();
}
public Chunk getChunk(int x, int y) {
return getChunk(getChunkIndex(x, y));
}
public Chunk getChunk(int index) {
if(!isChunkIndexInBounds(index)) {
return null;
}
Chunk chunk = chunks.get(index);
if(chunk == null) {
chunk = loadChunk(index);
chunks.put(index, chunk);
zone.onChunkLoaded(chunk);
}
return chunk;
}
public Collection<Chunk> getChunks() {
return Collections.unmodifiableCollection(chunks.values());
}
}

View file

@ -8,10 +8,8 @@ import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Queue;
import java.util.Random;
import java.util.Set;
@ -71,7 +69,6 @@ public class Zone {
private final Set<Integer> pendingSunlight = new HashSet<>();
private final Map<Integer, Entity> entities = new HashMap<>();
private final List<Player> players = new ArrayList<>();
private final Map<Integer, Chunk> chunks = new HashMap<>();
private final Map<String, Integer> dungeons = new HashMap<>();
private final Map<Integer, MetaBlock> metaBlocks = new HashMap<>();
private final Map<Integer, MetaBlock> globalMetaBlocks = new HashMap<>();
@ -144,11 +141,6 @@ public class Zone {
}
}
public void saveModifiedChunks() {
chunkManager.saveModifiedChunks();
removeInactiveChunks();
}
/**
* Sends a message to each player in this zone.
*
@ -678,75 +670,8 @@ public class Zone {
return x >= 0 && y >= 0 && x < width && y < height;
}
private void removeInactiveChunks() {
Iterator<Entry<Integer, Chunk>> iterator = chunks.entrySet().iterator();
while(iterator.hasNext()) {
Entry<Integer, Chunk> entry = iterator.next();
Chunk chunk = entry.getValue();
boolean active = false;
for(Player player : players) {
if(player.isChunkActive(chunk)) {
active = true;
break;
}
}
if(!active) {
iterator.remove();
}
}
}
public boolean isChunkIndexInBounds(int index) {
return index >= 0 && index < numChunksWidth * numChunksHeight;
}
public boolean isChunkLoaded(int x, int y) {
return isChunkLoaded(getChunkIndex(x, y));
}
public boolean isChunkLoaded(int index) {
return chunks.containsKey(index);
}
public void putChunk(int index, Chunk chunk) {
if(!chunks.containsKey(index) && isChunkIndexInBounds(index)) {
chunk.setModified(true);
chunks.put(index, chunk);
}
}
public int getChunkIndex(int x, int y) {
return y / chunkHeight * numChunksWidth + x / chunkWidth;
}
public Chunk getChunk(int x, int y) {
return getChunk(getChunkIndex(x, y));
}
public Chunk getChunk(int index) {
if(!isChunkIndexInBounds(index)) {
return null;
}
Chunk chunk = chunks.get(index);
if(chunk == null) {
chunk = chunkManager.loadChunk(index);
tryRecalculatePendingSunlight(chunk);
chunks.put(index, chunk);
}
return chunk;
}
public Collection<Chunk> getChunks() {
return chunks.values();
}
private void tryRecalculatePendingSunlight(Chunk chunk) {
protected void onChunkLoaded(Chunk chunk) {
// Update sunlight
if(!pendingSunlight.isEmpty()) {
int chunkX = chunk.getX();
@ -757,6 +682,52 @@ public class Zone {
}
}
}
// TODO more chunk related thingies, such as surface calculations,
// entity spawning and block indexing
}
protected void onChunkUnloaded(Chunk chunk) {
// TODO
}
public void saveChunks() {
chunkManager.saveChunks();
}
/**
* Should only be called by zone gen.
*/
public void putChunk(int index, Chunk chunk) {
chunkManager.putChunk(index, chunk);
}
public boolean isChunkLoaded(int x, int y) {
return chunkManager.isChunkLoaded(x, y);
}
public boolean isChunkLoaded(int index) {
return chunkManager.isChunkLoaded(index);
}
public boolean isChunkIndexInBounds(int index) {
return chunkManager.isChunkIndexInBounds(index);
}
public int getChunkIndex(int x, int y) {
return chunkManager.getChunkIndex(x, y);
}
public Chunk getChunk(int x, int y) {
return chunkManager.getChunk(x, y);
}
public Chunk getChunk(int index) {
return chunkManager.getChunk(index);
}
public Collection<Chunk> getChunks() {
return chunkManager.getChunks();
}
public void setSurface(int x, int surface) {