Moved TestWorldDiskIO to a subpackage and introduced some abstractions

This commit is contained in:
OLEGSHA 2021-08-28 23:31:50 +03:00
parent 41a2909f7c
commit cd16334db8
Signed by: OLEGSHA
GPG Key ID: E57A4B08D64AFF7A
9 changed files with 204 additions and 50 deletions

View File

@ -46,6 +46,7 @@ import ru.windcorp.progressia.server.world.context.impl.DefaultServerContext;
import ru.windcorp.progressia.server.world.context.impl.ReportingServerContext;
import ru.windcorp.progressia.server.world.context.impl.RotatingServerContext;
import ru.windcorp.progressia.server.world.generation.WorldGenerator;
import ru.windcorp.progressia.server.world.io.WorldContainer;
import ru.windcorp.progressia.server.world.tasks.WorldAccessor;
import ru.windcorp.progressia.server.world.ticking.Change;
import ru.windcorp.progressia.server.world.ticking.Evaluation;
@ -78,11 +79,16 @@ public class Server {
private final TickingSettings tickingSettings = new TickingSettings();
public Server(DefaultWorldData world, Function<Server, WorldGenerator> generatorCreator) {
public Server(
DefaultWorldData world,
Function<Server, WorldGenerator> generatorCreator,
WorldContainer worldContainer
) {
this.world = new DefaultWorldLogic(
world,
this,
generatorCreator.apply(this),
worldContainer,
worldAccessor
);
this.serverThread = new ServerThread(this);
@ -349,6 +355,7 @@ public class Server {
public void shutdown(String message) {
LogManager.getLogger().warn("Server.shutdown() is not yet implemented");
serverThread.stop();
getWorld().getContainer().close();
}
private void scheduleWorldTicks(Server server) {

View File

@ -18,8 +18,14 @@
package ru.windcorp.progressia.server;
import java.nio.file.Paths;
import java.util.function.Function;
import ru.windcorp.progressia.common.world.DefaultWorldData;
import ru.windcorp.progressia.server.world.generation.WorldGenerator;
import ru.windcorp.progressia.server.world.io.WorldContainer;
import ru.windcorp.progressia.test.gen.TestGenerationConfig;
import ru.windcorp.progressia.test.region.RegionFormat;
public class ServerState {
@ -34,9 +40,14 @@ public class ServerState {
}
public static void startServer() {
Server server = new Server(new DefaultWorldData(), TestGenerationConfig.createGenerator());
Function<Server, WorldGenerator> generator = new TestGenerationConfig().getGenerator();
WorldContainer container = new RegionFormat("Test:Region").create(Paths.get("tmp_world"));
Server server = new Server(new DefaultWorldData(), generator, container);
setInstance(server);
server.start();
}
private ServerState() {

View File

@ -24,7 +24,7 @@ import ru.windcorp.progressia.common.world.PacketSendChunk;
import ru.windcorp.progressia.common.world.DefaultWorldData;
import ru.windcorp.progressia.server.Player;
import ru.windcorp.progressia.server.Server;
import ru.windcorp.progressia.test.TestWorldDiskIO;
import ru.windcorp.progressia.server.world.io.WorldContainer;
/**
* Chunk manager provides facilities to load, unload and generate chunks for a
@ -52,6 +52,10 @@ public class ChunkManager {
return getLoadManager().getServer();
}
public WorldContainer getContainer() {
return getServer().getWorld().getContainer();
}
/**
* Describes the result of an attempt to load a chunk.
*/
@ -115,7 +119,7 @@ public class ChunkManager {
DefaultWorldData world = getServer().getWorld().getData();
DefaultChunkData chunk = TestWorldDiskIO.tryToLoad(chunkPos, world, getServer());
DefaultChunkData chunk = getServer().getWorld().getContainer().load(chunkPos, world, getServer());
if (chunk != null) {
world.addChunk(chunk);
return LoadResult.LOADED_FROM_DISK;
@ -141,7 +145,7 @@ public class ChunkManager {
}
world.removeChunk(chunk);
TestWorldDiskIO.saveChunk(chunk, getServer());
getContainer().save(chunk, getServer().getWorld().getData(), getServer());
return true;
}

View File

@ -32,6 +32,7 @@ import ru.windcorp.progressia.common.world.WorldDataListener;
import ru.windcorp.progressia.common.world.entity.EntityData;
import ru.windcorp.progressia.server.Server;
import ru.windcorp.progressia.server.world.generation.WorldGenerator;
import ru.windcorp.progressia.server.world.io.WorldContainer;
import ru.windcorp.progressia.server.world.tasks.TickEntitiesTask;
import ru.windcorp.progressia.server.world.tasks.WorldAccessor;
import ru.windcorp.progressia.server.world.ticking.Evaluation;
@ -42,18 +43,21 @@ public class DefaultWorldLogic implements WorldLogic {
private final Server server;
private final WorldGenerator generator;
private final WorldContainer container;
private final Map<DefaultChunkData, DefaultChunkLogic> chunks = new HashMap<>();
private final Evaluation tickEntitiesTask = new TickEntitiesTask();
public DefaultWorldLogic(DefaultWorldData data, Server server, WorldGenerator generator, WorldAccessor accessor) {
public DefaultWorldLogic(DefaultWorldData data, Server server, WorldGenerator generator, WorldContainer container, WorldAccessor accessor) {
this.data = data;
this.server = server;
this.generator = generator;
data.setGravityModel(getGenerator().getGravityModel());
this.container = container;
data.addListener(new WorldDataListener() {
@Override
public void onChunkLoaded(DefaultWorldData world, DefaultChunkData chunk) {
@ -106,6 +110,10 @@ public class DefaultWorldLogic implements WorldLogic {
return generator;
}
public WorldContainer getContainer() {
return container;
}
public DefaultChunkData generate(Vec3i chunkPos) {
DefaultChunkData chunk = getGenerator().generate(chunkPos);

View File

@ -0,0 +1,37 @@
/*
* 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 <https://www.gnu.org/licenses/>.
*/
package ru.windcorp.progressia.server.world.io;
import java.nio.file.Path;
import glm.vec._3.i.Vec3i;
import ru.windcorp.progressia.common.world.DefaultChunkData;
import ru.windcorp.progressia.common.world.DefaultWorldData;
import ru.windcorp.progressia.server.Server;
public interface WorldContainer {
Path getPath();
DefaultChunkData load(Vec3i position, DefaultWorldData world, Server server);
void save(DefaultChunkData chunk, DefaultWorldData world, Server server);
void close();
}

View File

@ -0,0 +1,32 @@
/*
* 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 <https://www.gnu.org/licenses/>.
*/
package ru.windcorp.progressia.server.world.io;
import java.nio.file.Path;
import ru.windcorp.progressia.common.util.namespaces.Namespaced;
public abstract class WorldContainerFormat extends Namespaced {
public WorldContainerFormat(String id) {
super(id);
}
public abstract WorldContainer create(Path directory);
}

View File

@ -49,9 +49,18 @@ public class TestGenerationConfig {
private static final float CURVATURE = Units.get("100 m");
private static final float INNER_RADIUS = Units.get("200 m");
private static final Fields FIELDS = new Fields(SEED);
private final Fields fields = new Fields(SEED);
private final Function<Server, WorldGenerator> generator;
public static Function<Server, WorldGenerator> createGenerator() {
public TestGenerationConfig() {
this.generator = createGenerator();
}
public Function<Server, WorldGenerator> getGenerator() {
return generator;
}
private Function<Server, WorldGenerator> createGenerator() {
Planet planet = new Planet(
((int) PLANET_RADIUS) / Coordinates.CHUNK_SIZE,
@ -60,7 +69,7 @@ public class TestGenerationConfig {
INNER_RADIUS
);
TestHeightMap heightMap = new TestHeightMap(planet, planet.getRadius() / 4, FIELDS);
TestHeightMap heightMap = new TestHeightMap(planet, planet.getRadius() / 4, fields);
FloatRangeMap<TerrainLayer> layers = new ArrayFloatRangeMap<>();
registerTerrainLayers(layers);
@ -72,11 +81,11 @@ public class TestGenerationConfig {
}
private static void registerTerrainLayers(FloatRangeMap<TerrainLayer> layers) {
private void registerTerrainLayers(FloatRangeMap<TerrainLayer> layers) {
BlockData dirt = BlockDataRegistry.getInstance().get("Test:Dirt");
BlockData air = BlockDataRegistry.getInstance().get("Test:Air");
SurfaceFloatField cliffs = FIELDS.get("Test:Cliff");
SurfaceFloatField cliffs = fields.get("Test:Cliff");
WorleyProceduralNoise.Builder<TerrainLayer> builder = WorleyProceduralNoise.builder();
TestContent.ROCKS.getRocks().forEach(rock -> {
@ -88,9 +97,9 @@ public class TestGenerationConfig {
}
}, 1);
});
SurfaceFloatField rockDepthOffsets = FIELDS.register(
SurfaceFloatField rockDepthOffsets = fields.register(
"Test:RockDepthOffsets",
() -> tweak(FIELDS.primitive(), 40, 5)
() -> tweak(fields.primitive(), 40, 5)
);
RockLayer rockLayer = new RockLayer(builder.build(SEED), rockDepthOffsets);
@ -105,28 +114,28 @@ public class TestGenerationConfig {
layers.put(4, Float.POSITIVE_INFINITY, rockLayer);
}
private static void registerFeatures(List<SurfaceFeature> features) {
private void registerFeatures(List<SurfaceFeature> features) {
SurfaceFloatField forestiness = FIELDS.register(
SurfaceFloatField forestiness = fields.register(
"Test:Forest",
() -> squash(scale(FIELDS.primitive(), 200), 5)
() -> squash(scale(fields.primitive(), 200), 5)
);
SurfaceFloatField grassiness = FIELDS.register(
SurfaceFloatField grassiness = fields.register(
"Test:Grass",
f -> multiply(
tweak(octaves(FIELDS.primitive(), 2, 2), 40, 0.5, 1.2),
squash(tweak(FIELDS.get("Test:Forest", f), 1, -1, 1), 10),
anti(squash(FIELDS.get("Test:Cliff", f), 10))
tweak(octaves(fields.primitive(), 2, 2), 40, 0.5, 1.2),
squash(tweak(fields.get("Test:Forest", f), 1, -1, 1), 10),
anti(squash(fields.get("Test:Cliff", f), 10))
)
);
Function<String, SurfaceFloatField> floweriness = flowerName -> FIELDS.register(
Function<String, SurfaceFloatField> floweriness = flowerName -> fields.register(
"Test:Flower" + flowerName,
f -> multiply(
selectPositive(squash(scale(octaves(FIELDS.primitive(), 2, 3), 100), 2), 1, 0.5),
tweak(FIELDS.get("Test:Forest", f), 1, -1, 1.1),
anti(squash(FIELDS.get("Test:Cliff", f), 10))
selectPositive(squash(scale(octaves(fields.primitive(), 2, 3), 100), 2), 1, 0.5),
tweak(fields.get("Test:Forest", f), 1, -1, 1.1),
anti(squash(fields.get("Test:Cliff", f), 10))
)
);

View File

@ -0,0 +1,36 @@
/*
* 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 <https://www.gnu.org/licenses/>.
*/
package ru.windcorp.progressia.test.region;
import java.nio.file.Path;
import ru.windcorp.progressia.server.world.io.WorldContainer;
import ru.windcorp.progressia.server.world.io.WorldContainerFormat;
public class RegionFormat extends WorldContainerFormat {
public RegionFormat(String id) {
super(id);
}
@Override
public WorldContainer create(Path directory) {
return new TestWorldDiskIO(directory);
}
}

View File

@ -16,7 +16,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package ru.windcorp.progressia.test;
package ru.windcorp.progressia.test.region;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
@ -52,12 +52,13 @@ import ru.windcorp.progressia.common.world.DecodingException;
import ru.windcorp.progressia.common.world.DefaultWorldData;
import ru.windcorp.progressia.common.world.io.ChunkIO;
import ru.windcorp.progressia.server.Server;
import ru.windcorp.progressia.server.world.io.WorldContainer;
public class TestWorldDiskIO {
public class TestWorldDiskIO implements WorldContainer {
private static final boolean resetCorrupted = true;
public static class RandomFileMapped {
public class RandomFileMapped {
public RandomAccessFile file;
public HashMap<HashableVec3i, Integer> offsets;
public HashMap<HashableVec3i, Integer> lengths;
@ -121,11 +122,11 @@ public class TestWorldDiskIO {
}
}
private static Path SAVE_DIR = Paths.get("tmp_world");
private Path SAVE_DIR = Paths.get("tmp_world");
private static final String formatFile = "world.format";
private static final Logger LOG = LogManager.getLogger("TestWorldDiskIO");
private static HashMap<HashableVec3i, RandomFileMapped> inOutMap;
private HashMap<HashableVec3i, RandomFileMapped> inOutMap;
private static final boolean ENABLE = false;
private static int maxSize = 1048576;
@ -134,11 +135,11 @@ public class TestWorldDiskIO {
private static final int bestFormat = 65536;
// private Map<Vec3i,Vec3i> regions = new HashMap<Vec3i,Vec3i>();
private static Vec3i regionSize;
private static int chunksPerRegion;
private Vec3i regionSize;
private int chunksPerRegion;
private static int currentFormat = -1;
private static String extension = ".null";
private int currentFormat = -1;
private String extension = ".null";
private static int natFromInt(int loc) {
if (loc < 0)
@ -155,7 +156,7 @@ public class TestWorldDiskIO {
* }
*/
private static Vec3i getRegion(Vec3i chunkLoc) {
private Vec3i getRegion(Vec3i chunkLoc) {
int x = chunkLoc.x;
if (x<0)
{
@ -197,15 +198,11 @@ public class TestWorldDiskIO {
return ((a % m) + m) % m;
}
private static Vec3i getRegionLoc(Vec3i chunkLoc) {
private Vec3i getRegionLoc(Vec3i chunkLoc) {
return new Vec3i(mod(chunkLoc.x, regionSize.x), mod(chunkLoc.y, regionSize.y), mod(chunkLoc.z, regionSize.z));
}
public static void initRegions() {
initRegions(null);
}
public static void initRegions(Path worldPath) {
public TestWorldDiskIO(Path worldPath) {
if (worldPath != null) {
SAVE_DIR = worldPath;
}
@ -224,7 +221,7 @@ public class TestWorldDiskIO {
return sectorsUsed;
}*/
private static void setRegionSize(int format) {
private void setRegionSize(int format) {
inOutMap = new HashMap<HashableVec3i, RandomFileMapped>();
switch (format) {
case 65536:
@ -243,7 +240,7 @@ public class TestWorldDiskIO {
}
}
public static boolean confirmHeaderHealth(RandomAccessFile input, HashMap<HashableVec3i, Integer> offsets, HashMap<HashableVec3i, Integer> length) throws IOException
public boolean confirmHeaderHealth(RandomAccessFile input, HashMap<HashableVec3i, Integer> offsets, HashMap<HashableVec3i, Integer> length) throws IOException
{
Set<Integer> used = new HashSet<Integer>();
input.seek(0);
@ -282,7 +279,8 @@ public class TestWorldDiskIO {
return true;
}
public static void saveChunk(DefaultChunkData chunk, Server server) {
@Override
public void save(DefaultChunkData chunk, DefaultWorldData world, Server server) {
if (!ENABLE)
return;
@ -472,7 +470,7 @@ public class TestWorldDiskIO {
}
}
private static RandomFileMapped makeNew(Path path, Object hashObj) {
private RandomFileMapped makeNew(Path path, Object hashObj) {
try
{
RandomAccessFile raf = new RandomAccessFile(path.toFile(), "rw");
@ -490,12 +488,13 @@ public class TestWorldDiskIO {
return null;
}
private static void writeGenerationHint(DefaultChunkData chunk, DataOutputStream output, Server server)
private void writeGenerationHint(DefaultChunkData chunk, DataOutputStream output, Server server)
throws IOException {
server.getWorld().getGenerator().writeGenerationHint(output, chunk.getGenerationHint());
}
public static DefaultChunkData tryToLoad(Vec3i chunkPos, DefaultWorldData world, Server server) {
@Override
public DefaultChunkData load(Vec3i chunkPos, DefaultWorldData world, Server server) {
if (!ENABLE)
return null;
@ -650,7 +649,7 @@ public class TestWorldDiskIO {
return null;
}
private static DefaultChunkData loadRegion(Path path, Vec3i chunkPos, DefaultWorldData world, Server server)
private DefaultChunkData loadRegion(Path path, Vec3i chunkPos, DefaultWorldData world, Server server)
throws IOException,
DecodingException {
int offset = 0;
@ -724,7 +723,7 @@ public class TestWorldDiskIO {
return null;
}
private static DefaultChunkData loadRegionX(Path path, Vec3i chunkPos, DefaultWorldData world, Server server)
private DefaultChunkData loadRegionX(Path path, Vec3i chunkPos, DefaultWorldData world, Server server)
throws IOException,
DecodingException {
int offset = 0;
@ -810,4 +809,15 @@ public class TestWorldDiskIO {
chunk.setGenerationHint(server.getWorld().getGenerator().readGenerationHint(input));
}
@Override
public Path getPath() {
return SAVE_DIR;
}
@Override
public void close() {
// TODO Auto-generated method stub
}
}