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(
world,
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);

View File

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

View File

@ -21,9 +21,10 @@ package ru.windcorp.progressia.server.world;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Function;
import glm.Glm;
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.ChunkDataListeners;
import ru.windcorp.progressia.common.world.WorldData;
@ -52,11 +53,11 @@ public class WorldLogic
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.server = server;
this.generator = worldGeneratorConstructor.apply(this);
this.generator = generator;
data.setGravityModel(getGenerator().getGravityModel());
data.addListener(new WorldDataListener() {
@ -106,7 +107,38 @@ public class WorldLogic
}
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) {

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.GravityModel;
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 {
@ -34,10 +37,13 @@ public abstract class AbstractWorldGenerator<H> extends WorldGenerator {
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);
this.hintClass = Objects.requireNonNull(hintClass, "hintClass");
this.gravityModel = GravityModelRegistry.getInstance().create(Objects.requireNonNull(gravityModelId, "gravityModelId"));
this.server = server;
if (this.gravityModel == null) {
throw new IllegalArgumentException("Gravity model with ID \"" + gravityModelId + "\" not found");
@ -78,4 +84,19 @@ public abstract class AbstractWorldGenerator<H> extends WorldGenerator {
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.GravityModel;
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 {
@ -37,7 +39,7 @@ public abstract class WorldGenerator extends Namespaced {
// 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;
@ -49,4 +51,8 @@ public abstract class WorldGenerator extends Namespaced {
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.tile.TileData;
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;
public class TestWorldGenerator extends AbstractWorldGenerator<Boolean> {
private final TestTerrainGenerator terrainGen;
public TestWorldGenerator(WorldLogic world) {
super("Test:WorldGenerator", Boolean.class, "Test:TheGravityModel");
this.terrainGen = new TestTerrainGenerator(this, world);
public TestWorldGenerator(Server server) {
super("Test:WorldGenerator", server, Boolean.class, "Test:TheGravityModel");
this.terrainGen = new TestTerrainGenerator(this, server.getWorld());
world.getData().addListener(new WorldDataListener() {
getWorldData().addListener(new WorldDataListener() {
@Override
public void onChunkLoaded(WorldData world, ChunkData chunk) {
findAndPopulate(chunk.getPosition(), world);
@ -77,9 +77,9 @@ public class TestWorldGenerator extends AbstractWorldGenerator<Boolean> {
}
@Override
public ChunkData generate(Vec3i chunkPos, WorldData world) {
ChunkData chunk = generateUnpopulated(chunkPos, world);
world.addChunk(chunk);
public ChunkData generate(Vec3i chunkPos) {
ChunkData chunk = generateUnpopulated(chunkPos, getWorldData());
getWorldData().addChunk(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.world.ChunkData;
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.BlockDataRegistry;
import ru.windcorp.progressia.test.gen.TerrainLayer;
@ -61,8 +60,8 @@ class PlanetTerrainGenerator {
return parent;
}
public ChunkData generateTerrain(Vec3i chunkPos, WorldData world) {
ChunkData chunk = new ChunkData(chunkPos, world);
public ChunkData generateTerrain(Vec3i chunkPos) {
ChunkData chunk = new ChunkData(chunkPos, getGenerator().getWorldData());
if (isOrdinaryChunk(chunkPos)) {
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.world.ChunkData;
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.world.WorldLogic;
import ru.windcorp.progressia.server.world.generation.AbstractWorldGenerator;
public class TestPlanetGenerator extends AbstractWorldGenerator<Boolean> {
private final Server server;
private final Planet planet;
private final PlanetTerrainGenerator terrainGenerator;
private final PlanetFeatureGenerator featureGenerator;
public TestPlanetGenerator(String id, Planet planet, WorldLogic world) {
super(id, Boolean.class, "Test:PlanetGravityModel");
public TestPlanetGenerator(String id, Server server, Planet planet) {
super(id, server, Boolean.class, "Test:PlanetGravityModel");
this.server = world.getServer();
this.planet = planet;
TestPlanetGravityModel model = (TestPlanetGravityModel) this.getGravityModel();
@ -81,9 +76,9 @@ public class TestPlanetGenerator extends AbstractWorldGenerator<Boolean> {
}
@Override
public ChunkData generate(Vec3i chunkPos, WorldData world) {
VectorUtil.iterateCuboidAround(chunkPos, 3, r -> conjureTerrain(r, world));
ChunkData chunk = world.getChunk(chunkPos);
public ChunkData generate(Vec3i chunkPos) {
VectorUtil.iterateCuboidAround(chunkPos, 3, r -> conjureTerrain(r));
ChunkData chunk = getWorldData().getChunk(chunkPos);
if (!isChunkReady(chunk.getGenerationHint())) {
featureGenerator.generateFeatures(chunk);
@ -92,17 +87,17 @@ public class TestPlanetGenerator extends AbstractWorldGenerator<Boolean> {
return chunk;
}
private void conjureTerrain(Vec3i chunkPos, WorldData world) {
ChunkData chunk = world.getChunk(chunkPos);
private void conjureTerrain(Vec3i chunkPos) {
ChunkData chunk = getWorldData().getChunk(chunkPos);
if (chunk == null) {
server.getLoadManager().getChunkManager().loadChunk(chunkPos);
chunk = world.getChunk(chunkPos);
getServer().getLoadManager().getChunkManager().loadChunk(chunkPos);
chunk = getWorldData().getChunk(chunkPos);
}
if (chunk == null) {
chunk = terrainGenerator.generateTerrain(chunkPos, world);
world.addChunk(chunk);
chunk = terrainGenerator.generateTerrain(chunkPos);
getWorldData().addChunk(chunk);
}
}