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:
parent
2d3d250f92
commit
3c3f3816df
@ -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);
|
||||||
|
|
||||||
|
@ -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());
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -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) {
|
||||||
|
@ -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();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -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();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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);
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user