From d33b48578d7f41cee5e3e62769ce1f49f67ccc62 Mon Sep 17 00:00:00 2001 From: OLEGSHA Date: Tue, 17 Aug 2021 16:05:44 +0300 Subject: [PATCH] Added SurfaceContexts to replace SurfaceWorld+Request. WIP There is a problem with features when up != POS_Z --- .../ru/windcorp/progressia/server/Server.java | 54 ++++--- .../world/ticking/TickerCoordinator.java | 32 +++-- .../progressia/test/TestBushFeature.java | 26 ++-- .../progressia/test/TestGrassFeature.java | 20 +-- .../progressia/test/TestTreeFeature.java | 69 ++++----- .../gen/planet/PlanetFeatureGenerator.java | 13 +- .../test/gen/planet/TestPlanetGenerator.java | 2 +- .../test/gen/surface/SurfaceFeature.java | 60 +------- .../gen/surface/SurfaceFeatureGenerator.java | 26 +++- .../gen/surface/SurfaceTopLayerFeature.java | 50 ++++--- .../surface/context/SurfaceBlockContext.java | 87 +++++++++++ .../gen/surface/context/SurfaceContext.java | 136 ++++++++++++++++++ .../surface/context/SurfaceContextImpl.java | 114 +++++++++++++++ .../context/SurfaceContextImplLogic.java | 72 ++++++++++ .../surface/context/SurfaceTileContext.java | 54 +++++++ .../context/SurfaceTileStackContext.java | 64 +++++++++ .../surface/context/SurfaceWorldContext.java | 54 +++++++ 17 files changed, 757 insertions(+), 176 deletions(-) create mode 100644 src/main/java/ru/windcorp/progressia/test/gen/surface/context/SurfaceBlockContext.java create mode 100644 src/main/java/ru/windcorp/progressia/test/gen/surface/context/SurfaceContext.java create mode 100644 src/main/java/ru/windcorp/progressia/test/gen/surface/context/SurfaceContextImpl.java create mode 100644 src/main/java/ru/windcorp/progressia/test/gen/surface/context/SurfaceContextImplLogic.java create mode 100644 src/main/java/ru/windcorp/progressia/test/gen/surface/context/SurfaceTileContext.java create mode 100644 src/main/java/ru/windcorp/progressia/test/gen/surface/context/SurfaceTileStackContext.java create mode 100644 src/main/java/ru/windcorp/progressia/test/gen/surface/context/SurfaceWorldContext.java diff --git a/src/main/java/ru/windcorp/progressia/server/Server.java b/src/main/java/ru/windcorp/progressia/server/Server.java index 915c262..132b5bf 100644 --- a/src/main/java/ru/windcorp/progressia/server/Server.java +++ b/src/main/java/ru/windcorp/progressia/server/Server.java @@ -47,6 +47,7 @@ import ru.windcorp.progressia.server.world.context.impl.RotatingServerContext; import ru.windcorp.progressia.server.world.tasks.WorldAccessor; import ru.windcorp.progressia.server.world.ticking.Change; import ru.windcorp.progressia.server.world.ticking.Evaluation; +import ru.windcorp.progressia.server.world.ticking.TickerCoordinator; import ru.windcorp.progressia.test.gen.planet.Planet; import ru.windcorp.progressia.test.gen.planet.TestPlanetGenerator; @@ -232,13 +233,41 @@ public class Server { schedule(() -> task.accept(this)); } - public void requestChange(Change change) { + /** + * Delayed + */ + public void scheduleChange(Change change) { serverThread.getTicker().requestChange(change); } - - public void requestEvaluation(Evaluation evaluation) { + + /** + * Delayed + */ + public void scheduleEvaluation(Evaluation evaluation) { serverThread.getTicker().requestEvaluation(evaluation); } + + /** + * Immediate if possible, otherwise delayed + */ + public void requestChange(Change change) { + if (serverThread.getTicker().getPhase() == TickerCoordinator.TickPhase.SYNCHRONOUS) { + change.affect(this); + } else { + serverThread.getTicker().requestChange(change); + } + } + + /** + * Immediate if possible, otherwise delayed + */ + public void requestEvaluation(Evaluation evaluation) { + if (serverThread.getTicker().getPhase() == TickerCoordinator.TickPhase.SYNCHRONOUS) { + evaluation.evaluate(this); + } else { + serverThread.getTicker().requestEvaluation(evaluation); + } + } public void subscribe(Object object) { eventBus.register(object); @@ -279,20 +308,7 @@ public class Server { public long getUptimeTicks() { return this.serverThread.getTicker().getUptimeTicks(); } - -// /** -// * Returns the {@link WorldAccessor} object for this server. Use the -// * provided accessor to request common {@link Evaluation}s and -// * {@link Change}s. -// * -// * @return a {@link WorldAccessor} -// * @see #requestChange(Change) -// * @see #requestEvaluation(Evaluation) -// */ -// public WorldAccessor getWorldAccessor() { -// return worldAccessor; -// } - + public WorldAccessor getWorldAccessor___really_bad_dont_use() { return worldAccessor; } @@ -338,8 +354,8 @@ public class Server { } private void scheduleWorldTicks(Server server) { - server.getWorld().getChunks().forEach(chunk -> requestEvaluation(chunk.getTickTask())); - requestEvaluation(server.getWorld().getTickEntitiesTask()); + server.getWorld().getChunks().forEach(chunk -> scheduleEvaluation(chunk.getTickTask())); + scheduleEvaluation(server.getWorld().getTickEntitiesTask()); } /** diff --git a/src/main/java/ru/windcorp/progressia/server/world/ticking/TickerCoordinator.java b/src/main/java/ru/windcorp/progressia/server/world/ticking/TickerCoordinator.java index 25dc4db..08a0841 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/ticking/TickerCoordinator.java +++ b/src/main/java/ru/windcorp/progressia/server/world/ticking/TickerCoordinator.java @@ -23,8 +23,8 @@ import java.util.Collection; import java.util.ConcurrentModificationException; import java.util.HashSet; import java.util.Objects; -import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicReference; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -47,6 +47,12 @@ import ru.windcorp.progressia.server.Server; * @author javapony */ public class TickerCoordinator { + + public enum TickPhase { + SYNCHRONOUS, + EVALUATION, + CHANGE + } static final int INITIAL_QUEUE_SIZE = 1024; @@ -77,7 +83,7 @@ public class TickerCoordinator { private final AtomicInteger workingTickers = new AtomicInteger(); - private final AtomicBoolean canChange = new AtomicBoolean(true); + private final AtomicReference phase = new AtomicReference<>(TickPhase.SYNCHRONOUS); private boolean isTickStartSet = false; private long tickStart = -1; @@ -96,17 +102,14 @@ public class TickerCoordinator { } this.tickers = ImmutableList.copyOf(tickerCollection); - this.threads = Collections2.transform(this.tickers, Ticker::getThread); // Immutable - // because - // it - // is - // a - // view + + // Immutable because it is a view + this.threads = Collections2.transform(this.tickers, Ticker::getThread); server.getWorld().getData().addListener(ChunkDataListeners.createAdder(new ChunkDataListener() { @Override public void onChunkChanged(DefaultChunkData chunk) { - if (!canChange.get()) { + if (phase.get() == TickPhase.EVALUATION) { throw CrashReports.report(null, "A change has been detected during evaluation phase"); } } @@ -156,8 +159,14 @@ public class TickerCoordinator { public long getUptimeTicks() { return ticks; } + + public TickPhase getPhase() { + return phase.get(); + } private void onTickStart() { + phase.set(TickPhase.EVALUATION); + long now = System.currentTimeMillis(); if (isTickStartSet) { @@ -171,6 +180,7 @@ public class TickerCoordinator { private void onTickEnd() { ticks++; + phase.set(TickPhase.SYNCHRONOUS); } /* @@ -212,9 +222,9 @@ public class TickerCoordinator { } private synchronized void runOnePass() throws InterruptedException { - canChange.set(false); + phase.set(TickPhase.EVALUATION); runPassStage(pendingEvaluations, "EVALUATION"); - canChange.set(true); + phase.set(TickPhase.CHANGE); runPassStage(pendingChanges, "CHANGE"); } diff --git a/src/main/java/ru/windcorp/progressia/test/TestBushFeature.java b/src/main/java/ru/windcorp/progressia/test/TestBushFeature.java index 50a56aa..a7174f9 100644 --- a/src/main/java/ru/windcorp/progressia/test/TestBushFeature.java +++ b/src/main/java/ru/windcorp/progressia/test/TestBushFeature.java @@ -22,9 +22,9 @@ import ru.windcorp.progressia.common.util.VectorUtil; import ru.windcorp.progressia.common.world.block.BlockData; import ru.windcorp.progressia.common.world.block.BlockDataRegistry; import ru.windcorp.progressia.common.world.rels.RelFace; -import ru.windcorp.progressia.server.world.block.BlockLogicRegistry; import ru.windcorp.progressia.test.gen.surface.SurfaceTopLayerFeature; -import ru.windcorp.progressia.test.gen.surface.SurfaceWorld; +import ru.windcorp.progressia.test.gen.surface.context.SurfaceBlockContext; +import ru.windcorp.progressia.test.gen.surface.context.SurfaceWorldContext; public class TestBushFeature extends SurfaceTopLayerFeature { @@ -32,35 +32,35 @@ public class TestBushFeature extends SurfaceTopLayerFeature { super(id); } - private void tryToSetLeaves(SurfaceWorld world, Vec3i posSfc, BlockData leaves) { - if (world.getBlockSfc(posSfc).getId().equals("Test:Air")) { - world.setBlockSfc(posSfc, leaves, false); + private void tryToSetLeaves(SurfaceWorldContext context, Vec3i location, BlockData leaves) { + if (context.getBlock(location).getId().equals("Test:Air")) { + context.setBlock(location, leaves); } } @Override - protected void processTopBlock(SurfaceWorld world, Request request, Vec3i topBlock) { - if (request.getRandom().nextInt(10*10) > 0) return; + protected void processTopBlock(SurfaceBlockContext context) { + if (context.getRandom().nextInt(10*10) > 0) return; - Vec3i center = topBlock.add_(0, 0, 1); + Vec3i center = context.getLocation().add_(0, 0, 1); BlockData log = BlockDataRegistry.getInstance().get("Test:Log"); BlockData leaves = BlockDataRegistry.getInstance().get("Test:TemporaryLeaves"); - world.setBlockSfc(center, log, false); + context.setBlock(center, log); VectorUtil.iterateCuboidAround(center.x, center.y, center.z, 3, 3, 3, p -> { - tryToSetLeaves(world, p, leaves); + tryToSetLeaves(context, p, leaves); }); VectorUtil.iterateCuboidAround(center.x, center.y, center.z, 5, 5, 1, p -> { - tryToSetLeaves(world, p, leaves); + tryToSetLeaves(context, p, leaves); }); } @Override - protected boolean isSolid(SurfaceWorld world, Vec3i surfaceBlockInWorld) { - return BlockLogicRegistry.getInstance().get(world.getBlockSfc(surfaceBlockInWorld).getId()).isSolid(RelFace.UP); + protected boolean isSolid(SurfaceBlockContext context) { + return context.logic().getBlock().isSolid(RelFace.UP); } } diff --git a/src/main/java/ru/windcorp/progressia/test/TestGrassFeature.java b/src/main/java/ru/windcorp/progressia/test/TestGrassFeature.java index 3689998..cd18ebe 100644 --- a/src/main/java/ru/windcorp/progressia/test/TestGrassFeature.java +++ b/src/main/java/ru/windcorp/progressia/test/TestGrassFeature.java @@ -21,13 +21,11 @@ import java.util.Set; import com.google.common.collect.ImmutableSet; -import glm.vec._3.i.Vec3i; import ru.windcorp.progressia.common.world.rels.RelFace; import ru.windcorp.progressia.common.world.tile.TileData; import ru.windcorp.progressia.common.world.tile.TileDataRegistry; -import ru.windcorp.progressia.server.world.block.BlockLogicRegistry; import ru.windcorp.progressia.test.gen.surface.SurfaceTopLayerFeature; -import ru.windcorp.progressia.test.gen.surface.SurfaceWorld; +import ru.windcorp.progressia.test.gen.surface.context.SurfaceBlockContext; public class TestGrassFeature extends SurfaceTopLayerFeature { @@ -44,8 +42,8 @@ public class TestGrassFeature extends SurfaceTopLayerFeature { } @Override - protected void processTopBlock(SurfaceWorld world, Request request, Vec3i topBlock) { - if (!WHITELIST.contains(world.getBlockSfc(topBlock).getId())) { + protected void processTopBlock(SurfaceBlockContext context) { + if (!WHITELIST.contains(context.getBlock().getId())) { return; } @@ -54,15 +52,19 @@ public class TestGrassFeature extends SurfaceTopLayerFeature { for (RelFace face : RelFace.getFaces()) { if (face == RelFace.DOWN) continue; - if (BlockLogicRegistry.getInstance().get(world.getBlockSfc(topBlock.add_(face.getRelVector())).getId()).isTransparent()) { - world.getTilesSfc(topBlock, face).addFarthest(grass); + if (context.pushRelative(face).logic().getBlock().isTransparent()) { + context.pop(); + context.addTile(face, grass); + } else { + context.pop(); } + } } @Override - protected boolean isSolid(SurfaceWorld world, Vec3i surfaceBlockInWorld) { - return BlockLogicRegistry.getInstance().get(world.getBlockSfc(surfaceBlockInWorld).getId()).isSolid(RelFace.UP); + protected boolean isSolid(SurfaceBlockContext context) { + return context.logic().getBlock().isSolid(RelFace.UP); } } diff --git a/src/main/java/ru/windcorp/progressia/test/TestTreeFeature.java b/src/main/java/ru/windcorp/progressia/test/TestTreeFeature.java index 5ca923a..2e91dc9 100644 --- a/src/main/java/ru/windcorp/progressia/test/TestTreeFeature.java +++ b/src/main/java/ru/windcorp/progressia/test/TestTreeFeature.java @@ -24,25 +24,27 @@ import ru.windcorp.progressia.common.util.VectorUtil; import ru.windcorp.progressia.common.world.block.BlockData; import ru.windcorp.progressia.common.world.block.BlockDataRegistry; import ru.windcorp.progressia.common.world.rels.RelFace; -import ru.windcorp.progressia.server.world.block.BlockLogicRegistry; import ru.windcorp.progressia.test.gen.surface.SurfaceTopLayerFeature; -import ru.windcorp.progressia.test.gen.surface.SurfaceWorld; +import ru.windcorp.progressia.test.gen.surface.context.SurfaceBlockContext; +import ru.windcorp.progressia.test.gen.surface.context.SurfaceWorldContext; public class TestTreeFeature extends SurfaceTopLayerFeature { public TestTreeFeature(String id) { super(id); } - - private void tryToSetLeaves(SurfaceWorld world, Vec3i posSfc, BlockData leaves) { - if (world.getBlockSfc(posSfc).getId().equals("Test:Air")) { - world.setBlockSfc(posSfc, leaves, false); + + private void tryToSetLeaves(SurfaceWorldContext context, Vec3i location, BlockData leaves) { + if (context.getBlock(location).getId().equals("Test:Air")) { + context.setBlock(location, leaves); } } - + private void iterateSpheroid(Vec3i center, double horDiameter, double vertDiameter, Consumer action) { VectorUtil.iterateCuboidAround( - center.x, center.y, center.z, + center.x, + center.y, + center.z, (int) Math.ceil(horDiameter) / 2 * 2 + 5, (int) Math.ceil(horDiameter) / 2 * 2 + 5, (int) Math.ceil(vertDiameter) / 2 * 2 + 5, @@ -50,54 +52,55 @@ public class TestTreeFeature extends SurfaceTopLayerFeature { double sx = (pos.x - center.x) / horDiameter; double sy = (pos.y - center.y) / horDiameter; double sz = (pos.z - center.z) / vertDiameter; - - if (sx*sx + sy*sy + sz*sz <= 1) { + + if (sx * sx + sy * sy + sz * sz <= 1) { action.accept(pos); } } ); } - + @Override - protected void processTopBlock(SurfaceWorld world, Request request, Vec3i topBlock) { - if (request.getRandom().nextInt(20*20) > 0) return; - - Vec3i start = topBlock.add_(0, 0, 1); + protected void processTopBlock(SurfaceBlockContext context) { + if (context.getRandom().nextInt(20 * 20) > 0) + return; + + Vec3i start = context.getLocation().add_(0, 0, 1); BlockData log = BlockDataRegistry.getInstance().get("Test:Log"); BlockData leaves = BlockDataRegistry.getInstance().get("Test:TemporaryLeaves"); - + Vec3i center = start.add_(0); - - int height = request.getRandom().nextInt(3) + 5; + + int height = context.getRandom().nextInt(3) + 5; for (; center.z < start.z + height; ++center.z) { - world.setBlockSfc(center, log, false); + context.setBlock(center, log); } - + double branchHorDistance = 0; - + do { - double branchSize = 0.5 + 1 * request.getRandom().nextDouble(); - double branchHorAngle = 2 * Math.PI * request.getRandom().nextDouble(); - int branchVertOffset = -2 + request.getRandom().nextInt(3); - + double branchSize = 0.5 + 1 * context.getRandom().nextDouble(); + double branchHorAngle = 2 * Math.PI * context.getRandom().nextDouble(); + int branchVertOffset = -2 + context.getRandom().nextInt(3); + Vec3i branchCenter = center.add_( (int) (Math.sin(branchHorAngle) * branchHorDistance), (int) (Math.cos(branchHorAngle) * branchHorDistance), branchVertOffset ); - + iterateSpheroid(branchCenter, 1.75 * branchSize, 2.5 * branchSize, p -> { - tryToSetLeaves(world, p, leaves); + tryToSetLeaves(context, p, leaves); }); - - branchHorDistance = 1 + 2 * request.getRandom().nextDouble(); - } while (request.getRandom().nextInt(8) > 1); + + branchHorDistance = 1 + 2 * context.getRandom().nextDouble(); + } while (context.getRandom().nextInt(8) > 1); } - + @Override - protected boolean isSolid(SurfaceWorld world, Vec3i surfaceBlockInWorld) { - return BlockLogicRegistry.getInstance().get(world.getBlockSfc(surfaceBlockInWorld).getId()).isSolid(RelFace.UP); + protected boolean isSolid(SurfaceBlockContext context) { + return context.logic().getBlock().isSolid(RelFace.UP); } } diff --git a/src/main/java/ru/windcorp/progressia/test/gen/planet/PlanetFeatureGenerator.java b/src/main/java/ru/windcorp/progressia/test/gen/planet/PlanetFeatureGenerator.java index a33cb87..38ed248 100644 --- a/src/main/java/ru/windcorp/progressia/test/gen/planet/PlanetFeatureGenerator.java +++ b/src/main/java/ru/windcorp/progressia/test/gen/planet/PlanetFeatureGenerator.java @@ -25,6 +25,7 @@ import glm.vec._3.i.Vec3i; import ru.windcorp.progressia.common.util.VectorUtil; import ru.windcorp.progressia.common.world.DefaultChunkData; import ru.windcorp.progressia.common.world.rels.AbsFace; +import ru.windcorp.progressia.server.Server; import ru.windcorp.progressia.test.TestBushFeature; import ru.windcorp.progressia.test.TestGrassFeature; import ru.windcorp.progressia.test.TestTreeFeature; @@ -57,11 +58,11 @@ public class PlanetFeatureGenerator { return parent; } - public void generateFeatures(DefaultChunkData chunk) { + public void generateFeatures(Server server, DefaultChunkData chunk) { if (isOrdinaryChunk(chunk.getPosition())) { - generateOrdinaryFeatures(chunk); + generateOrdinaryFeatures(server, chunk); } else { - generateBorderFeatures(chunk); + generateBorderFeatures(server, chunk); } chunk.setGenerationHint(true); @@ -72,11 +73,11 @@ public class PlanetFeatureGenerator { return sorted.x != sorted.y; } - private void generateOrdinaryFeatures(DefaultChunkData chunk) { - surfaceGenerators.get(chunk.getUp()).generateFeatures(chunk); + private void generateOrdinaryFeatures(Server server, DefaultChunkData chunk) { + surfaceGenerators.get(chunk.getUp()).generateFeatures(server, chunk); } - private void generateBorderFeatures(DefaultChunkData chunk) { + private void generateBorderFeatures(Server server, DefaultChunkData chunk) { // Do nothing } 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 8b92470..f531282 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 @@ -81,7 +81,7 @@ public class TestPlanetGenerator extends AbstractWorldGenerator { DefaultChunkData chunk = getWorldData().getChunk(chunkPos); if (!isChunkReady(chunk.getGenerationHint())) { - featureGenerator.generateFeatures(chunk); + featureGenerator.generateFeatures(getServer(), chunk); } return chunk; diff --git a/src/main/java/ru/windcorp/progressia/test/gen/surface/SurfaceFeature.java b/src/main/java/ru/windcorp/progressia/test/gen/surface/SurfaceFeature.java index 0510d98..7bd1cc4 100644 --- a/src/main/java/ru/windcorp/progressia/test/gen/surface/SurfaceFeature.java +++ b/src/main/java/ru/windcorp/progressia/test/gen/surface/SurfaceFeature.java @@ -18,15 +18,13 @@ package ru.windcorp.progressia.test.gen.surface; import java.util.Random; -import java.util.function.Consumer; import glm.Glm; import glm.vec._3.i.Vec3i; -import ru.windcorp.progressia.common.util.VectorUtil; -import ru.windcorp.progressia.common.util.Vectors; import ru.windcorp.progressia.common.util.namespaces.Namespaced; import ru.windcorp.progressia.common.world.DefaultChunkData; import ru.windcorp.progressia.common.world.generic.GenericChunks; +import ru.windcorp.progressia.test.gen.surface.context.SurfaceWorldContext; public abstract class SurfaceFeature extends Namespaced { @@ -107,60 +105,6 @@ public abstract class SurfaceFeature extends Namespaced { super(id); } - public abstract void process(SurfaceWorld world, Request request); - - /* - * Utility methods - */ - - public boolean contains(Request request, Vec3i surfaceBlockInWorld) { - Vec3i bic = Vectors.grab3i(); - bic.set(surfaceBlockInWorld.x, surfaceBlockInWorld.y, surfaceBlockInWorld.z); - bic.sub(request.minSfc); - boolean result = GenericChunks.containsBiC(bic); - Vectors.release(bic); - return result; - } - - public void forEach(Request request, Consumer action) { - VectorUtil.iterateCuboid( - request.minSfc.x, - request.minSfc.y, - request.minSfc.z, - request.maxSfc.x + 1, - request.maxSfc.y + 1, - request.maxSfc.z + 1, - action - ); - } - - /** - * Provided vectors have z set to {@link #getMinZ()}. - */ - public void forEachOnFloor(Request request, Consumer action) { - forEachOnLayer(request, action, request.getMinZ()); - } - - /** - * Provided vectors have z set to {@link #getMaxZ()}. - */ - public void forEachOnCeiling(Request request, Consumer action) { - forEachOnLayer(request, action, request.getMaxZ()); - } - - /** - * Provided vectors have z set to layer. - */ - public void forEachOnLayer(Request request, Consumer action, int layer) { - VectorUtil.iterateCuboid( - request.minSfc.x, - request.minSfc.y, - layer, - request.maxSfc.x + 1, - request.maxSfc.y + 1, - layer + 1, - action - ); - } + public abstract void process(SurfaceWorldContext context); } diff --git a/src/main/java/ru/windcorp/progressia/test/gen/surface/SurfaceFeatureGenerator.java b/src/main/java/ru/windcorp/progressia/test/gen/surface/SurfaceFeatureGenerator.java index 54b582e..aafd0ea 100644 --- a/src/main/java/ru/windcorp/progressia/test/gen/surface/SurfaceFeatureGenerator.java +++ b/src/main/java/ru/windcorp/progressia/test/gen/surface/SurfaceFeatureGenerator.java @@ -21,8 +21,13 @@ import java.util.ArrayList; import java.util.Collection; import java.util.Random; +import glm.Glm; +import glm.vec._3.i.Vec3i; import ru.windcorp.progressia.common.util.CoordinatePacker; import ru.windcorp.progressia.common.world.DefaultChunkData; +import ru.windcorp.progressia.server.Server; +import ru.windcorp.progressia.server.world.context.ServerTileContext; +import ru.windcorp.progressia.test.gen.surface.context.SurfaceContextImpl; public class SurfaceFeatureGenerator { @@ -42,14 +47,27 @@ public class SurfaceFeatureGenerator { return surface; } - public void generateFeatures(DefaultChunkData chunk) { - SurfaceWorld world = new SurfaceWorld(surface, chunk.getWorld()); + public void generateFeatures(Server server, DefaultChunkData chunk) { Random random = new Random(CoordinatePacker.pack3IntsIntoLong(chunk.getPosition()) /* ^ seed*/); - SurfaceFeature.Request request = new SurfaceFeature.Request(world, chunk, random); + + SurfaceContextImpl context = new SurfaceContextImpl((ServerTileContext) server.createAbsoluteContext(), surface); + context.setRandom(random); + + Vec3i tmpA = new Vec3i(); + Vec3i tmpB = new Vec3i(); + + chunk.getMinBIW(tmpA); + chunk.getMaxBIW(tmpB); + + context.toContext(tmpA, tmpA); + context.toContext(tmpB, tmpB); + + Glm.min(tmpA, tmpB, context.getMin()); + Glm.max(tmpA, tmpB, context.getMax()); for (SurfaceFeature feature : features) { - feature.process(world, request); + feature.process(context); } chunk.setGenerationHint(true); diff --git a/src/main/java/ru/windcorp/progressia/test/gen/surface/SurfaceTopLayerFeature.java b/src/main/java/ru/windcorp/progressia/test/gen/surface/SurfaceTopLayerFeature.java index 5947950..4981dff 100644 --- a/src/main/java/ru/windcorp/progressia/test/gen/surface/SurfaceTopLayerFeature.java +++ b/src/main/java/ru/windcorp/progressia/test/gen/surface/SurfaceTopLayerFeature.java @@ -18,41 +18,47 @@ package ru.windcorp.progressia.test.gen.surface; import glm.vec._3.i.Vec3i; -import ru.windcorp.progressia.common.util.Vectors; +import ru.windcorp.progressia.test.gen.surface.context.SurfaceBlockContext; +import ru.windcorp.progressia.test.gen.surface.context.SurfaceWorldContext; public abstract class SurfaceTopLayerFeature extends SurfaceFeature { - + public SurfaceTopLayerFeature(String id) { super(id); } - protected abstract void processTopBlock(SurfaceWorld world, Request request, Vec3i topBlock); - - protected abstract boolean isSolid(SurfaceWorld world, Vec3i surfaceBlockInWorld); - + protected abstract void processTopBlock(SurfaceBlockContext context); + + protected abstract boolean isSolid(SurfaceBlockContext context); + @Override - public void process(SurfaceWorld world, Request request) { - Vec3i cursor = Vectors.grab3i(); - - forEachOnLayer(request, pos -> { - + public void process(SurfaceWorldContext context) { + Vec3i cursor = new Vec3i(); + + context.forEachOnFloor(pos -> { + cursor.set(pos.x, pos.y, pos.z); - - if (!isSolid(world, cursor)) { + + if (!isSolid(context.push(cursor))) { + context.pop(); return; } - - for (cursor.z += 1; cursor.z <= request.getMaxZ() + 1; ++cursor.z) { - if (!isSolid(world, cursor)) { - cursor.z -= 1; - processTopBlock(world, request, cursor); + context.pop(); + + for (cursor.z += 1; cursor.z <= context.getMaxZ() + 1; ++cursor.z) { + SurfaceBlockContext blockContext = context.push(cursor); + + if (!isSolid(blockContext)) { + processTopBlock(blockContext.pushRelative(0, 0, -1)); + context.pop(); + context.pop(); return; } + + context.pop(); } - - }, request.getMinZ()); - - Vectors.release(cursor); + + }); } } diff --git a/src/main/java/ru/windcorp/progressia/test/gen/surface/context/SurfaceBlockContext.java b/src/main/java/ru/windcorp/progressia/test/gen/surface/context/SurfaceBlockContext.java new file mode 100644 index 0000000..be3c285 --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/test/gen/surface/context/SurfaceBlockContext.java @@ -0,0 +1,87 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package ru.windcorp.progressia.test.gen.surface.context; + +import glm.vec._3.i.Vec3i; +import ru.windcorp.progressia.common.world.rels.RelFace; +import ru.windcorp.progressia.common.world.rels.RelRelation; +import ru.windcorp.progressia.server.world.context.ServerBlockContext; + +public interface SurfaceBlockContext extends ServerBlockContext, SurfaceWorldContext { + + public interface Logic extends ServerBlockContext.Logic, SurfaceWorldContext.Logic { + + @Override + SurfaceBlockContext data(); + + @Override + default SurfaceBlockContext.Logic pushRelative(int dx, int dy, int dz) { + return push(getLocation().add_(dx, dy, dz)); + } + + @Override + default SurfaceBlockContext.Logic pushRelative(Vec3i direction) { + return push(getLocation().add_(direction)); + } + + @Override + default SurfaceBlockContext.Logic pushRelative(RelRelation direction) { + return push(getLocation().add_(direction.getRelVector())); + } + + @Override + default SurfaceTileStackContext.Logic push(RelFace face) { + return push(getLocation(), face); + } + + @Override + default SurfaceTileContext.Logic push(RelFace face, int layer) { + return push(getLocation(), face, layer); + } + + } + + @Override + SurfaceBlockContext.Logic logic(); + + @Override + default SurfaceBlockContext pushRelative(int dx, int dy, int dz) { + return push(getLocation().add_(dx, dy, dz)); + } + + @Override + default SurfaceBlockContext pushRelative(Vec3i direction) { + return push(getLocation().add_(direction)); + } + + @Override + default SurfaceBlockContext pushRelative(RelRelation direction) { + return push(getLocation().add_(direction.getRelVector())); + } + + @Override + default SurfaceTileStackContext push(RelFace face) { + return push(getLocation(), face); + } + + @Override + default SurfaceTileContext push(RelFace face, int layer) { + return push(getLocation(), face, layer); + } + +} diff --git a/src/main/java/ru/windcorp/progressia/test/gen/surface/context/SurfaceContext.java b/src/main/java/ru/windcorp/progressia/test/gen/surface/context/SurfaceContext.java new file mode 100644 index 0000000..b0b1aca --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/test/gen/surface/context/SurfaceContext.java @@ -0,0 +1,136 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package ru.windcorp.progressia.test.gen.surface.context; + +import java.util.function.Consumer; + +import glm.vec._3.i.Vec3i; +import ru.windcorp.progressia.common.util.VectorUtil; +import ru.windcorp.progressia.test.gen.surface.Surface; + +public interface SurfaceContext { + + /** + * Returns the {@link Surface} object relevant to this context. + * + * @return the surface details + */ + Surface getSurface(); + + /** + * Returns lower bounds (inclusive) on the coordinates of the requested + * region. + * + * @return the coordinates of the minimum corner of the region that + * should be processed + */ + Vec3i getMin(); + + /** + * Returns upper bounds (inclusive) on the coordinates of the requested + * region. + * + * @return the coordinates of the maximum corner of the region that + * should be processed + */ + Vec3i getMax(); + + /* + * Convenience methods + */ + + default int getMinX() { + return getMin().x; + } + + default int getMinY() { + return getMin().y; + } + + default int getMinZ() { + return getMin().z; + } + + default int getMaxX() { + return getMax().x; + } + + default int getMaxY() { + return getMax().y; + } + + default int getMaxZ() { + return getMax().z; + } + + default boolean isRequested(int x, int y, int z) { + Vec3i min = getMin(); + Vec3i max = getMax(); + return (min.x <= x && x <= max.x) && (min.y <= y && y <= max.y) && (min.z <= z && z <= max.z); + } + + default boolean isRequested(Vec3i location) { + return isRequested(location.x, location.y, location.z); + } + + default void forEachRequested(Consumer action) { + Vec3i min = getMin(); + Vec3i max = getMax(); + VectorUtil.iterateCuboid( + min.x, + min.y, + min.z, + max.x + 1, + max.y + 1, + max.z + 1, + action + ); + } + + /** + * Provided vectors have z set to {@link #getMinZ()}. + */ + default void forEachOnFloor(Consumer action) { + forEachOnLayer(action, getMinZ()); + } + + /** + * Provided vectors have z set to {@link #getMaxZ()}. + */ + default void forEachOnCeiling(Consumer action) { + forEachOnLayer(action, getMaxZ()); + } + + /** + * Provided vectors have z set to layer. + */ + default void forEachOnLayer(Consumer action, int layer) { + Vec3i min = getMin(); + Vec3i max = getMax(); + VectorUtil.iterateCuboid( + min.x, + min.y, + layer, + max.x + 1, + max.y + 1, + layer + 1, + action + ); + } + +} diff --git a/src/main/java/ru/windcorp/progressia/test/gen/surface/context/SurfaceContextImpl.java b/src/main/java/ru/windcorp/progressia/test/gen/surface/context/SurfaceContextImpl.java new file mode 100644 index 0000000..307330e --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/test/gen/surface/context/SurfaceContextImpl.java @@ -0,0 +1,114 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package ru.windcorp.progressia.test.gen.surface.context; + +import java.util.Random; + +import glm.vec._3.i.Vec3i; +import ru.windcorp.progressia.common.world.rels.RelFace; +import ru.windcorp.progressia.server.world.context.ServerTileContext; +import ru.windcorp.progressia.server.world.context.impl.RotatingServerContext; +import ru.windcorp.progressia.test.gen.surface.Surface; + +public class SurfaceContextImpl extends RotatingServerContext implements SurfaceTileContext { + + final Surface surface; + final Vec3i min = new Vec3i(); + final Vec3i max = new Vec3i(); + private Random random; + + private final SurfaceContextImplLogic logic; + + public SurfaceContextImpl(ServerTileContext parent, Surface surface) { + super(parent, surface.getUp()); + this.logic = new SurfaceContextImplLogic(this); + + this.surface = surface; + } + + @Override + protected void transform(Vec3i userLocation, Vec3i output) { + output.set(userLocation.x, userLocation.y, userLocation.z); + output.z += surface.getSeaLevel(); + super.transform(output, output); + } + + @Override + protected void untransform(Vec3i parentLocation, Vec3i output) { + super.untransform(parentLocation, output); + output.z -= surface.getSeaLevel(); + } + + @Override + public Surface getSurface() { + return surface; + } + + /** + * {@inheritDoc} + * + * @implNote can rw + */ + @Override + public Vec3i getMin() { + return min; + } + + /** + * {@inheritDoc} + * + * @implNote can rw + */ + @Override + public Vec3i getMax() { + return max; + } + + @Override + public Random getRandom() { + return random; + } + + public void setRandom(Random random) { + this.random = random; + } + + @Override + public SurfaceContextImplLogic logic() { + return logic; + } + + @Override + public SurfaceTileContext push(Vec3i location) { + super.push(location); + return this; + } + + @Override + public SurfaceTileContext push(Vec3i location, RelFace face) { + super.push(location, face); + return this; + } + + @Override + public SurfaceTileContext push(Vec3i location, RelFace face, int layer) { + super.push(location, face, layer); + return this; + } + +} diff --git a/src/main/java/ru/windcorp/progressia/test/gen/surface/context/SurfaceContextImplLogic.java b/src/main/java/ru/windcorp/progressia/test/gen/surface/context/SurfaceContextImplLogic.java new file mode 100644 index 0000000..b8f45df --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/test/gen/surface/context/SurfaceContextImplLogic.java @@ -0,0 +1,72 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package ru.windcorp.progressia.test.gen.surface.context; + +import glm.vec._3.i.Vec3i; +import ru.windcorp.progressia.common.world.rels.RelFace; +import ru.windcorp.progressia.server.world.context.impl.DefaultServerContextLogic; +import ru.windcorp.progressia.test.gen.surface.Surface; + +public class SurfaceContextImplLogic extends DefaultServerContextLogic implements SurfaceTileContext.Logic { + + private final SurfaceContextImpl surfaceParent; + + public SurfaceContextImplLogic(SurfaceContextImpl surfaceParent) { + super(surfaceParent); + this.surfaceParent = surfaceParent; + } + + @Override + public Surface getSurface() { + return this.surfaceParent.surface; + } + + @Override + public Vec3i getMin() { + return this.surfaceParent.min; + } + + @Override + public Vec3i getMax() { + return this.surfaceParent.max; + } + + @Override + public SurfaceContextImpl data() { + return this.surfaceParent; + } + + @Override + public SurfaceTileContext.Logic push(Vec3i location) { + super.push(location); + return this; + } + + @Override + public SurfaceTileContext.Logic push(Vec3i location, RelFace face) { + super.push(location, face); + return this; + } + + @Override + public SurfaceTileContext.Logic push(Vec3i location, RelFace face, int layer) { + super.push(location, face, layer); + return this; + } + +} \ No newline at end of file diff --git a/src/main/java/ru/windcorp/progressia/test/gen/surface/context/SurfaceTileContext.java b/src/main/java/ru/windcorp/progressia/test/gen/surface/context/SurfaceTileContext.java new file mode 100644 index 0000000..13f2211 --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/test/gen/surface/context/SurfaceTileContext.java @@ -0,0 +1,54 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package ru.windcorp.progressia.test.gen.surface.context; + +import ru.windcorp.progressia.server.world.context.ServerTileContext; + +public interface SurfaceTileContext extends ServerTileContext, SurfaceTileStackContext { + + public interface Logic extends ServerTileContext.Logic, SurfaceTileStackContext.Logic { + + @Override + SurfaceTileContext data(); + + @Override + default SurfaceTileContext.Logic pushCloser() { + return push(getLocation(), getFace(), getLayer() - 1); + } + + @Override + default SurfaceTileContext.Logic pushFarther() { + return push(getLocation(), getFace(), getLayer() + 1); + } + + } + + @Override + SurfaceTileContext.Logic logic(); + + @Override + default SurfaceTileContext pushCloser() { + return push(getLocation(), getFace(), getLayer() - 1); + } + + @Override + default SurfaceTileContext pushFarther() { + return push(getLocation(), getFace(), getLayer() + 1); + } + +} diff --git a/src/main/java/ru/windcorp/progressia/test/gen/surface/context/SurfaceTileStackContext.java b/src/main/java/ru/windcorp/progressia/test/gen/surface/context/SurfaceTileStackContext.java new file mode 100644 index 0000000..54f65bc --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/test/gen/surface/context/SurfaceTileStackContext.java @@ -0,0 +1,64 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package ru.windcorp.progressia.test.gen.surface.context; + +import ru.windcorp.progressia.server.world.context.ServerTileStackContext; + +public interface SurfaceTileStackContext extends ServerTileStackContext, SurfaceBlockContext { + + public interface Logic extends ServerTileStackContext.Logic, SurfaceBlockContext.Logic { + + @Override + SurfaceTileStackContext data(); + + @Override + default SurfaceTileContext.Logic push(int layer) { + return push(getLocation(), getFace(), layer); + } + + @Override + default SurfaceTileStackContext.Logic pushCounter() { + return push(getFace().getCounter()); + } + + @Override + default SurfaceTileStackContext.Logic pushOpposite() { + return push(getLocation().add_(getFace().getRelVector()), getFace().getCounter()); + } + + } + + @Override + SurfaceTileStackContext.Logic logic(); + + @Override + default SurfaceTileContext push(int layer) { + return push(getLocation(), getFace(), layer); + } + + @Override + default SurfaceTileStackContext pushCounter() { + return push(getFace().getCounter()); + } + + @Override + default SurfaceTileStackContext pushOpposite() { + return push(getLocation().add_(getFace().getRelVector()), getFace().getCounter()); + } + +} diff --git a/src/main/java/ru/windcorp/progressia/test/gen/surface/context/SurfaceWorldContext.java b/src/main/java/ru/windcorp/progressia/test/gen/surface/context/SurfaceWorldContext.java new file mode 100644 index 0000000..76510cf --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/test/gen/surface/context/SurfaceWorldContext.java @@ -0,0 +1,54 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package ru.windcorp.progressia.test.gen.surface.context; + +import glm.vec._3.i.Vec3i; +import ru.windcorp.progressia.common.world.rels.RelFace; +import ru.windcorp.progressia.server.world.context.ServerWorldContext; + +public interface SurfaceWorldContext extends ServerWorldContext, SurfaceContext { + + public interface Logic extends ServerWorldContext.Logic, SurfaceContext { + + @Override + SurfaceWorldContext data(); + + @Override + SurfaceBlockContext.Logic push(Vec3i location); + + @Override + SurfaceTileStackContext.Logic push(Vec3i location, RelFace face); + + @Override + SurfaceTileContext.Logic push(Vec3i location, RelFace face, int layer); + + } + + @Override + SurfaceWorldContext.Logic logic(); + + @Override + SurfaceBlockContext push(Vec3i location); + + @Override + SurfaceTileStackContext push(Vec3i location, RelFace face); + + @Override + SurfaceTileContext push(Vec3i location, RelFace face, int layer); + +}