Fixed a generation issue and refactored some code around WorldGenerators

- ChunkRequestDaemon now attempts to generate requested loaded non-ready
chunks upon discovery
- The server is now only specified once for WorldGenerator
- WorldLogic now actively checks the generation contract
This commit is contained in:
OLEGSHA 2021-04-02 21:51:52 +03:00
parent 2d3d250f92
commit 3c3f3816df
Signed by: OLEGSHA
GPG Key ID: E57A4B08D64AFF7A
8 changed files with 98 additions and 36 deletions

View File

@ -72,7 +72,7 @@ public class Server {
this.world = new WorldLogic( this.world = new WorldLogic(
world, world,
this, this,
w -> new TestPlanetGenerator("Test:PlanetGenerator", new Planet(4, 9.8f, 16f, 16f), w) new TestPlanetGenerator("Test:PlanetGenerator", this, new Planet(4, 9.8f, 16f, 16f))
); );
this.serverThread = new ServerThread(this); this.serverThread = new ServerThread(this);

View File

@ -41,6 +41,7 @@ public class ChunkRequestDaemon {
private final ChunkSet loaded; private final ChunkSet loaded;
private final ChunkSet requested = ChunkSets.newHashSet(); private final ChunkSet requested = ChunkSets.newHashSet();
private final ChunkSet toLoad = ChunkSets.newHashSet(); private final ChunkSet toLoad = ChunkSets.newHashSet();
private final ChunkSet toGenerate = ChunkSets.newHashSet();
private final ChunkSet toRequestUnload = ChunkSets.newHashSet(); private final ChunkSet toRequestUnload = ChunkSets.newHashSet();
private final Collection<Vec3i> buffer = new ArrayList<>(); private final Collection<Vec3i> buffer = new ArrayList<>();
@ -118,6 +119,9 @@ public class ChunkRequestDaemon {
toLoad.forEach(getChunkManager()::loadOrGenerateChunk); toLoad.forEach(getChunkManager()::loadOrGenerateChunk);
toLoad.clear(); toLoad.clear();
toGenerate.forEach(getChunkManager()::loadOrGenerateChunk);
toGenerate.clear();
unloadScheduledChunks(); unloadScheduledChunks();
} }
@ -161,10 +165,15 @@ public class ChunkRequestDaemon {
private void sendChunks(PlayerVision vision) { private void sendChunks(PlayerVision vision) {
vision.getRequestedChunks().forEachIn(getServer().getWorld(), chunk -> { vision.getRequestedChunks().forEachIn(getServer().getWorld(), chunk -> {
if (!chunk.isReady()) if (!chunk.isReady()) {
toGenerate.add(chunk);
return; return;
if (vision.isChunkVisible(chunk.getPosition())) }
if (vision.isChunkVisible(chunk.getPosition())) {
return; return;
}
buffer.add(chunk.getPosition()); buffer.add(chunk.getPosition());
}); });

View File

@ -21,9 +21,10 @@ package ru.windcorp.progressia.server.world;
import java.util.Collection; import java.util.Collection;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.function.Function;
import glm.Glm;
import glm.vec._3.i.Vec3i; import glm.vec._3.i.Vec3i;
import ru.windcorp.progressia.common.util.crash.CrashReports;
import ru.windcorp.progressia.common.world.ChunkData; import ru.windcorp.progressia.common.world.ChunkData;
import ru.windcorp.progressia.common.world.ChunkDataListeners; import ru.windcorp.progressia.common.world.ChunkDataListeners;
import ru.windcorp.progressia.common.world.WorldData; import ru.windcorp.progressia.common.world.WorldData;
@ -52,11 +53,11 @@ public class WorldLogic
private final Evaluation tickEntitiesTask = new TickEntitiesTask(); private final Evaluation tickEntitiesTask = new TickEntitiesTask();
public WorldLogic(WorldData data, Server server, Function<WorldLogic, WorldGenerator> worldGeneratorConstructor) { public WorldLogic(WorldData data, Server server, WorldGenerator generator) {
this.data = data; this.data = data;
this.server = server; this.server = server;
this.generator = worldGeneratorConstructor.apply(this); this.generator = generator;
data.setGravityModel(getGenerator().getGravityModel()); data.setGravityModel(getGenerator().getGravityModel());
data.addListener(new WorldDataListener() { data.addListener(new WorldDataListener() {
@ -106,7 +107,38 @@ public class WorldLogic
} }
public ChunkData generate(Vec3i chunkPos) { public ChunkData generate(Vec3i chunkPos) {
return getGenerator().generate(chunkPos, getData()); ChunkData chunk = getGenerator().generate(chunkPos);
if (!Glm.equals(chunkPos, chunk.getPosition())) {
throw CrashReports.report(null, "Generator %s has generated a chunk at (%d; %d; %d) when requested to generate a chunk at (%d; %d; %d)",
getGenerator(),
chunk.getX(), chunk.getY(), chunk.getZ(),
chunkPos.x, chunkPos.y, chunkPos.z
);
}
if (getData().getChunk(chunk.getPosition()) != chunk) {
if (isChunkLoaded(chunkPos)) {
throw CrashReports.report(null, "Generator %s has returned a chunk different to the chunk that is located at (%d; %d; %d)",
getGenerator(),
chunkPos.x, chunkPos.y, chunkPos.z
);
} else {
throw CrashReports.report(null, "Generator %s has returned a chunk that is not loaded when requested to generate a chunk at (%d; %d; %d)",
getGenerator(),
chunkPos.x, chunkPos.y, chunkPos.z
);
}
}
if (!getChunk(chunk).isReady()) {
throw CrashReports.report(null, "Generator %s has returned a chunk that is not ready when requested to generate a chunk at (%d; %d; %d)",
getGenerator(),
chunkPos.x, chunkPos.y, chunkPos.z
);
}
return chunk;
} }
public ChunkLogic getChunk(ChunkData chunkData) { public ChunkLogic getChunk(ChunkData chunkData) {

View File

@ -27,6 +27,9 @@ import ru.windcorp.progressia.common.world.ChunkData;
import ru.windcorp.progressia.common.world.DecodingException; import ru.windcorp.progressia.common.world.DecodingException;
import ru.windcorp.progressia.common.world.GravityModel; import ru.windcorp.progressia.common.world.GravityModel;
import ru.windcorp.progressia.common.world.GravityModelRegistry; import ru.windcorp.progressia.common.world.GravityModelRegistry;
import ru.windcorp.progressia.common.world.WorldData;
import ru.windcorp.progressia.server.Server;
import ru.windcorp.progressia.server.world.WorldLogic;
public abstract class AbstractWorldGenerator<H> extends WorldGenerator { public abstract class AbstractWorldGenerator<H> extends WorldGenerator {
@ -34,10 +37,13 @@ public abstract class AbstractWorldGenerator<H> extends WorldGenerator {
private final GravityModel gravityModel; private final GravityModel gravityModel;
public AbstractWorldGenerator(String id, Class<H> hintClass, String gravityModelId) { private final Server server;
public AbstractWorldGenerator(String id, Server server, Class<H> hintClass, String gravityModelId) {
super(id); super(id);
this.hintClass = Objects.requireNonNull(hintClass, "hintClass"); this.hintClass = Objects.requireNonNull(hintClass, "hintClass");
this.gravityModel = GravityModelRegistry.getInstance().create(Objects.requireNonNull(gravityModelId, "gravityModelId")); this.gravityModel = GravityModelRegistry.getInstance().create(Objects.requireNonNull(gravityModelId, "gravityModelId"));
this.server = server;
if (this.gravityModel == null) { if (this.gravityModel == null) {
throw new IllegalArgumentException("Gravity model with ID \"" + gravityModelId + "\" not found"); throw new IllegalArgumentException("Gravity model with ID \"" + gravityModelId + "\" not found");
@ -78,4 +84,19 @@ public abstract class AbstractWorldGenerator<H> extends WorldGenerator {
return gravityModel; return gravityModel;
} }
@Override
public Server getServer() {
return server;
}
@Override
public WorldLogic getWorldLogic() {
return server.getWorld();
}
@Override
public WorldData getWorldData() {
return server.getWorld().getData();
}
} }

View File

@ -29,6 +29,8 @@ import ru.windcorp.progressia.common.world.ChunkData;
import ru.windcorp.progressia.common.world.DecodingException; import ru.windcorp.progressia.common.world.DecodingException;
import ru.windcorp.progressia.common.world.GravityModel; import ru.windcorp.progressia.common.world.GravityModel;
import ru.windcorp.progressia.common.world.WorldData; import ru.windcorp.progressia.common.world.WorldData;
import ru.windcorp.progressia.server.Server;
import ru.windcorp.progressia.server.world.WorldLogic;
public abstract class WorldGenerator extends Namespaced { public abstract class WorldGenerator extends Namespaced {
@ -37,7 +39,7 @@ public abstract class WorldGenerator extends Namespaced {
// package-private constructor; extend AbstractWorldGeneration // package-private constructor; extend AbstractWorldGeneration
} }
public abstract ChunkData generate(Vec3i chunkPos, WorldData world); public abstract ChunkData generate(Vec3i chunkPos);
public abstract Object readGenerationHint(DataInputStream input) throws IOException, DecodingException; public abstract Object readGenerationHint(DataInputStream input) throws IOException, DecodingException;
@ -49,4 +51,8 @@ public abstract class WorldGenerator extends Namespaced {
public abstract Vec3 suggestSpawnLocation(); public abstract Vec3 suggestSpawnLocation();
public abstract Server getServer();
public abstract WorldLogic getWorldLogic();
public abstract WorldData getWorldData();
} }

View File

@ -37,18 +37,18 @@ import ru.windcorp.progressia.common.world.block.BlockDataRegistry;
import ru.windcorp.progressia.common.world.rels.AbsFace; import ru.windcorp.progressia.common.world.rels.AbsFace;
import ru.windcorp.progressia.common.world.tile.TileData; import ru.windcorp.progressia.common.world.tile.TileData;
import ru.windcorp.progressia.common.world.tile.TileDataRegistry; import ru.windcorp.progressia.common.world.tile.TileDataRegistry;
import ru.windcorp.progressia.server.world.WorldLogic; import ru.windcorp.progressia.server.Server;
import ru.windcorp.progressia.server.world.generation.AbstractWorldGenerator; import ru.windcorp.progressia.server.world.generation.AbstractWorldGenerator;
public class TestWorldGenerator extends AbstractWorldGenerator<Boolean> { public class TestWorldGenerator extends AbstractWorldGenerator<Boolean> {
private final TestTerrainGenerator terrainGen; private final TestTerrainGenerator terrainGen;
public TestWorldGenerator(WorldLogic world) { public TestWorldGenerator(Server server) {
super("Test:WorldGenerator", Boolean.class, "Test:TheGravityModel"); super("Test:WorldGenerator", server, Boolean.class, "Test:TheGravityModel");
this.terrainGen = new TestTerrainGenerator(this, world); this.terrainGen = new TestTerrainGenerator(this, server.getWorld());
world.getData().addListener(new WorldDataListener() { getWorldData().addListener(new WorldDataListener() {
@Override @Override
public void onChunkLoaded(WorldData world, ChunkData chunk) { public void onChunkLoaded(WorldData world, ChunkData chunk) {
findAndPopulate(chunk.getPosition(), world); findAndPopulate(chunk.getPosition(), world);
@ -77,9 +77,9 @@ public class TestWorldGenerator extends AbstractWorldGenerator<Boolean> {
} }
@Override @Override
public ChunkData generate(Vec3i chunkPos, WorldData world) { public ChunkData generate(Vec3i chunkPos) {
ChunkData chunk = generateUnpopulated(chunkPos, world); ChunkData chunk = generateUnpopulated(chunkPos, getWorldData());
world.addChunk(chunk); getWorldData().addChunk(chunk);
return chunk; return chunk;
} }

View File

@ -24,7 +24,6 @@ import ru.windcorp.progressia.common.util.FloatRangeMap;
import ru.windcorp.progressia.common.util.VectorUtil; import ru.windcorp.progressia.common.util.VectorUtil;
import ru.windcorp.progressia.common.world.ChunkData; import ru.windcorp.progressia.common.world.ChunkData;
import ru.windcorp.progressia.common.world.Coordinates; import ru.windcorp.progressia.common.world.Coordinates;
import ru.windcorp.progressia.common.world.WorldData;
import ru.windcorp.progressia.common.world.block.BlockData; import ru.windcorp.progressia.common.world.block.BlockData;
import ru.windcorp.progressia.common.world.block.BlockDataRegistry; import ru.windcorp.progressia.common.world.block.BlockDataRegistry;
import ru.windcorp.progressia.test.gen.TerrainLayer; import ru.windcorp.progressia.test.gen.TerrainLayer;
@ -61,8 +60,8 @@ class PlanetTerrainGenerator {
return parent; return parent;
} }
public ChunkData generateTerrain(Vec3i chunkPos, WorldData world) { public ChunkData generateTerrain(Vec3i chunkPos) {
ChunkData chunk = new ChunkData(chunkPos, world); ChunkData chunk = new ChunkData(chunkPos, getGenerator().getWorldData());
if (isOrdinaryChunk(chunkPos)) { if (isOrdinaryChunk(chunkPos)) {
generateOrdinaryTerrain(chunk); generateOrdinaryTerrain(chunk);

View File

@ -26,24 +26,19 @@ import glm.vec._3.i.Vec3i;
import ru.windcorp.progressia.common.util.VectorUtil; import ru.windcorp.progressia.common.util.VectorUtil;
import ru.windcorp.progressia.common.world.ChunkData; import ru.windcorp.progressia.common.world.ChunkData;
import ru.windcorp.progressia.common.world.DecodingException; import ru.windcorp.progressia.common.world.DecodingException;
import ru.windcorp.progressia.common.world.WorldData;
import ru.windcorp.progressia.server.Server; import ru.windcorp.progressia.server.Server;
import ru.windcorp.progressia.server.world.WorldLogic;
import ru.windcorp.progressia.server.world.generation.AbstractWorldGenerator; import ru.windcorp.progressia.server.world.generation.AbstractWorldGenerator;
public class TestPlanetGenerator extends AbstractWorldGenerator<Boolean> { public class TestPlanetGenerator extends AbstractWorldGenerator<Boolean> {
private final Server server;
private final Planet planet; private final Planet planet;
private final PlanetTerrainGenerator terrainGenerator; private final PlanetTerrainGenerator terrainGenerator;
private final PlanetFeatureGenerator featureGenerator; private final PlanetFeatureGenerator featureGenerator;
public TestPlanetGenerator(String id, Planet planet, WorldLogic world) { public TestPlanetGenerator(String id, Server server, Planet planet) {
super(id, Boolean.class, "Test:PlanetGravityModel"); super(id, server, Boolean.class, "Test:PlanetGravityModel");
this.server = world.getServer();
this.planet = planet; this.planet = planet;
TestPlanetGravityModel model = (TestPlanetGravityModel) this.getGravityModel(); TestPlanetGravityModel model = (TestPlanetGravityModel) this.getGravityModel();
@ -81,9 +76,9 @@ public class TestPlanetGenerator extends AbstractWorldGenerator<Boolean> {
} }
@Override @Override
public ChunkData generate(Vec3i chunkPos, WorldData world) { public ChunkData generate(Vec3i chunkPos) {
VectorUtil.iterateCuboidAround(chunkPos, 3, r -> conjureTerrain(r, world)); VectorUtil.iterateCuboidAround(chunkPos, 3, r -> conjureTerrain(r));
ChunkData chunk = world.getChunk(chunkPos); ChunkData chunk = getWorldData().getChunk(chunkPos);
if (!isChunkReady(chunk.getGenerationHint())) { if (!isChunkReady(chunk.getGenerationHint())) {
featureGenerator.generateFeatures(chunk); featureGenerator.generateFeatures(chunk);
@ -92,17 +87,17 @@ public class TestPlanetGenerator extends AbstractWorldGenerator<Boolean> {
return chunk; return chunk;
} }
private void conjureTerrain(Vec3i chunkPos, WorldData world) { private void conjureTerrain(Vec3i chunkPos) {
ChunkData chunk = world.getChunk(chunkPos); ChunkData chunk = getWorldData().getChunk(chunkPos);
if (chunk == null) { if (chunk == null) {
server.getLoadManager().getChunkManager().loadChunk(chunkPos); getServer().getLoadManager().getChunkManager().loadChunk(chunkPos);
chunk = world.getChunk(chunkPos); chunk = getWorldData().getChunk(chunkPos);
} }
if (chunk == null) { if (chunk == null) {
chunk = terrainGenerator.generateTerrain(chunkPos, world); chunk = terrainGenerator.generateTerrain(chunkPos);
world.addChunk(chunk); getWorldData().addChunk(chunk);
} }
} }