From 3c3f3816df85b4dc214b1c871f1d30e7a65aeceb Mon Sep 17 00:00:00 2001 From: OLEGSHA Date: Fri, 2 Apr 2021 21:51:52 +0300 Subject: [PATCH] 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 --- .../ru/windcorp/progressia/server/Server.java | 2 +- .../management/load/ChunkRequestDaemon.java | 13 +++++- .../progressia/server/world/WorldLogic.java | 40 +++++++++++++++++-- .../generation/AbstractWorldGenerator.java | 23 ++++++++++- .../world/generation/WorldGenerator.java | 8 +++- .../test/gen/TestWorldGenerator.java | 16 ++++---- .../gen/planet/PlanetTerrainGenerator.java | 5 +-- .../test/gen/planet/TestPlanetGenerator.java | 27 +++++-------- 8 files changed, 98 insertions(+), 36 deletions(-) diff --git a/src/main/java/ru/windcorp/progressia/server/Server.java b/src/main/java/ru/windcorp/progressia/server/Server.java index d4d1883..63435a1 100644 --- a/src/main/java/ru/windcorp/progressia/server/Server.java +++ b/src/main/java/ru/windcorp/progressia/server/Server.java @@ -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); diff --git a/src/main/java/ru/windcorp/progressia/server/management/load/ChunkRequestDaemon.java b/src/main/java/ru/windcorp/progressia/server/management/load/ChunkRequestDaemon.java index 502f68f..f720c7f 100644 --- a/src/main/java/ru/windcorp/progressia/server/management/load/ChunkRequestDaemon.java +++ b/src/main/java/ru/windcorp/progressia/server/management/load/ChunkRequestDaemon.java @@ -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 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()); }); diff --git a/src/main/java/ru/windcorp/progressia/server/world/WorldLogic.java b/src/main/java/ru/windcorp/progressia/server/world/WorldLogic.java index 5931e34..4111646 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/WorldLogic.java +++ b/src/main/java/ru/windcorp/progressia/server/world/WorldLogic.java @@ -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 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) { diff --git a/src/main/java/ru/windcorp/progressia/server/world/generation/AbstractWorldGenerator.java b/src/main/java/ru/windcorp/progressia/server/world/generation/AbstractWorldGenerator.java index 6856887..e765d85 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/generation/AbstractWorldGenerator.java +++ b/src/main/java/ru/windcorp/progressia/server/world/generation/AbstractWorldGenerator.java @@ -27,17 +27,23 @@ 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 extends WorldGenerator { private final Class hintClass; private final GravityModel gravityModel; + + private final Server server; - public AbstractWorldGenerator(String id, Class hintClass, String gravityModelId) { + public AbstractWorldGenerator(String id, Server server, Class 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"); @@ -77,5 +83,20 @@ public abstract class AbstractWorldGenerator extends WorldGenerator { public GravityModel getGravityModel() { return gravityModel; } + + @Override + public Server getServer() { + return server; + } + + @Override + public WorldLogic getWorldLogic() { + return server.getWorld(); + } + + @Override + public WorldData getWorldData() { + return server.getWorld().getData(); + } } diff --git a/src/main/java/ru/windcorp/progressia/server/world/generation/WorldGenerator.java b/src/main/java/ru/windcorp/progressia/server/world/generation/WorldGenerator.java index f31cbc4..f05674d 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/generation/WorldGenerator.java +++ b/src/main/java/ru/windcorp/progressia/server/world/generation/WorldGenerator.java @@ -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; @@ -48,5 +50,9 @@ public abstract class WorldGenerator extends Namespaced { public abstract GravityModel getGravityModel(); public abstract Vec3 suggestSpawnLocation(); + + public abstract Server getServer(); + public abstract WorldLogic getWorldLogic(); + public abstract WorldData getWorldData(); } diff --git a/src/main/java/ru/windcorp/progressia/test/gen/TestWorldGenerator.java b/src/main/java/ru/windcorp/progressia/test/gen/TestWorldGenerator.java index 8e0195a..e8c8641 100644 --- a/src/main/java/ru/windcorp/progressia/test/gen/TestWorldGenerator.java +++ b/src/main/java/ru/windcorp/progressia/test/gen/TestWorldGenerator.java @@ -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 { 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 { } @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; } diff --git a/src/main/java/ru/windcorp/progressia/test/gen/planet/PlanetTerrainGenerator.java b/src/main/java/ru/windcorp/progressia/test/gen/planet/PlanetTerrainGenerator.java index 5948b92..bd144a9 100644 --- a/src/main/java/ru/windcorp/progressia/test/gen/planet/PlanetTerrainGenerator.java +++ b/src/main/java/ru/windcorp/progressia/test/gen/planet/PlanetTerrainGenerator.java @@ -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); diff --git a/src/main/java/ru/windcorp/progressia/test/gen/planet/TestPlanetGenerator.java b/src/main/java/ru/windcorp/progressia/test/gen/planet/TestPlanetGenerator.java index 7206edc..82f0f55 100644 --- a/src/main/java/ru/windcorp/progressia/test/gen/planet/TestPlanetGenerator.java +++ b/src/main/java/ru/windcorp/progressia/test/gen/planet/TestPlanetGenerator.java @@ -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 { - 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 { } @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 { 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); } }