diff --git a/src/main/java/ru/windcorp/progressia/common/world/GravityModel.java b/src/main/java/ru/windcorp/progressia/common/world/GravityModel.java index 14f61e9..917d45f 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/GravityModel.java +++ b/src/main/java/ru/windcorp/progressia/common/world/GravityModel.java @@ -17,6 +17,9 @@ */ package ru.windcorp.progressia.common.world; +import java.io.DataInput; +import java.io.DataOutput; +import java.io.IOException; import java.util.Objects; import glm.vec._3.Vec3; @@ -165,5 +168,63 @@ public abstract class GravityModel extends Namespaced { * specified chunk. Never {@code null}. */ protected abstract AbsFace doGetDiscreteUp(Vec3i chunkPos); + + /** + * Parses the settings from the provided {@link DataInput} and configures this object appropriately. This method will not necessarily exhaust the input. + * @param input a stream to read the settings from + * @throws IOException if an I/O error occurs + * @throws DecodingException if the settings could not be parsed from input + */ + public void readSettings(DataInput input) throws IOException, DecodingException { + Objects.requireNonNull(input, "input"); + + try { + doReadSettings(input); + } catch (IOException | DecodingException e) { + throw e; + } catch (Exception e) { + throw CrashReports.report( + e, + "%s failed to read its settings", + this + ); + } + } + + /** + * Encodes the settings of this model into the provided {@link DataOutput}. + * @param output a stream to write the settings into + * @throws IOException if an I/O error occurs + */ + public void writeSettings(DataOutput output) throws IOException { + Objects.requireNonNull(output, "output"); + + try { + doWriteSettings(output); + } catch (IOException e) { + throw e; + } catch (Exception e) { + throw CrashReports.report( + e, + "%s failed to write its settings", + this + ); + } + } + + /** + * Parses the settings from the provided {@link DataInput} and configures this object appropriately. This method will not necessarily exhaust the input. + * @param input a stream to read the settings from + * @throws IOException if an I/O error occurs + * @throws DecodingException if the settings could not be parsed from input + */ + protected abstract void doReadSettings(DataInput input) throws IOException, DecodingException; + + /** + * Encodes the settings of this model into the provided {@link DataOutput}. + * @param output a stream to write the settings into + * @throws IOException if an I/O error occurs + */ + protected abstract void doWriteSettings(DataOutput output) throws IOException; } diff --git a/src/main/java/ru/windcorp/progressia/common/world/GravityModelRegistry.java b/src/main/java/ru/windcorp/progressia/common/world/GravityModelRegistry.java index b48cd0c..776e04f 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/GravityModelRegistry.java +++ b/src/main/java/ru/windcorp/progressia/common/world/GravityModelRegistry.java @@ -17,9 +17,9 @@ */ package ru.windcorp.progressia.common.world; -import ru.windcorp.progressia.common.util.namespaces.NamespacedInstanceRegistry; +import ru.windcorp.progressia.common.util.namespaces.NamespacedFactoryRegistry; -public class GravityModelRegistry extends NamespacedInstanceRegistry { +public class GravityModelRegistry extends NamespacedFactoryRegistry { public static final GravityModelRegistry INSTANCE = new GravityModelRegistry(); diff --git a/src/main/java/ru/windcorp/progressia/common/world/PacketSetGravityModel.java b/src/main/java/ru/windcorp/progressia/common/world/PacketSetGravityModel.java index 7e7f95e..2fd30a6 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/PacketSetGravityModel.java +++ b/src/main/java/ru/windcorp/progressia/common/world/PacketSetGravityModel.java @@ -21,9 +21,13 @@ import java.io.DataInput; import java.io.DataOutput; import java.io.IOException; +import ru.windcorp.progressia.common.util.DataBuffer; +import ru.windcorp.progressia.common.util.crash.CrashReports; + public class PacketSetGravityModel extends PacketAffectWorld { private String gravityModelId; + private final DataBuffer settings = new DataBuffer(); public PacketSetGravityModel() { this("Core:SetGravityModel"); @@ -35,22 +39,38 @@ public class PacketSetGravityModel extends PacketAffectWorld { public void set(GravityModel model) { this.gravityModelId = model.getId(); + + try { + model.writeSettings(settings.getWriter()); + } catch (IOException e) { + throw CrashReports.report(e, "%s has errored when writing its settings", model); + } } @Override public void read(DataInput input) throws IOException, DecodingException { gravityModelId = input.readUTF(); + settings.fill(input, input.readInt()); } @Override public void write(DataOutput output) throws IOException { output.writeUTF(gravityModelId); + output.writeInt(settings.getSize()); + settings.flush(output); } @Override public void apply(WorldData world) { - GravityModel model = GravityModelRegistry.getInstance().get(gravityModelId); + GravityModel model = GravityModelRegistry.getInstance().create(gravityModelId); world.setGravityModel(model); + try { + model.readSettings(settings.getReader()); + } catch (IOException e) { + throw CrashReports.report(e, "%s has errored when reading its settings", model); + } catch (DecodingException e) { + throw CrashReports.report(e, "%s has failed to parse its settings", model); + } } } diff --git a/src/main/java/ru/windcorp/progressia/server/Server.java b/src/main/java/ru/windcorp/progressia/server/Server.java index ceafa47..8ca9383 100644 --- a/src/main/java/ru/windcorp/progressia/server/Server.java +++ b/src/main/java/ru/windcorp/progressia/server/Server.java @@ -61,7 +61,7 @@ public class Server { private final TickingSettings tickingSettings = new TickingSettings(); public Server(WorldData world) { - this.world = new WorldLogic(world, this, w -> new TestPlanetGenerator("Test:PlanetGenerator", new Planet(4, 16f, 9.8f, 16f), w)); + this.world = new WorldLogic(world, this, w -> new TestPlanetGenerator("Test:PlanetGenerator", new Planet(4, 9.8f, 16f, 16f), w)); this.serverThread = new ServerThread(this); this.clientManager = new ClientManager(this); 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 74583ff..6856887 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 @@ -37,7 +37,7 @@ public abstract class AbstractWorldGenerator extends WorldGenerator { public AbstractWorldGenerator(String id, Class hintClass, String gravityModelId) { super(id); this.hintClass = Objects.requireNonNull(hintClass, "hintClass"); - this.gravityModel = GravityModelRegistry.getInstance().get(Objects.requireNonNull(gravityModelId, "gravityModelId")); + this.gravityModel = GravityModelRegistry.getInstance().create(Objects.requireNonNull(gravityModelId, "gravityModelId")); if (this.gravityModel == null) { throw new IllegalArgumentException("Gravity model with ID \"" + gravityModelId + "\" not found"); diff --git a/src/main/java/ru/windcorp/progressia/test/TestContent.java b/src/main/java/ru/windcorp/progressia/test/TestContent.java index dd72aa8..e65ae68 100644 --- a/src/main/java/ru/windcorp/progressia/test/TestContent.java +++ b/src/main/java/ru/windcorp/progressia/test/TestContent.java @@ -422,8 +422,8 @@ public class TestContent { private static void registerMisc() { ChunkIO.registerCodec(new TestChunkCodec()); ChunkRenderOptimizerRegistry.getInstance().register("Core:SurfaceOptimizer", ChunkRenderOptimizerSurface::new); - GravityModelRegistry.getInstance().register(new TestGravityModel()); - GravityModelRegistry.getInstance().register(new TestPlanetGravityModel()); + GravityModelRegistry.getInstance().register("Test:TheGravityModel", TestGravityModel::new); + GravityModelRegistry.getInstance().register("Test:PlanetGravityModel", TestPlanetGravityModel::new); } } diff --git a/src/main/java/ru/windcorp/progressia/test/gen/TestGravityModel.java b/src/main/java/ru/windcorp/progressia/test/gen/TestGravityModel.java index 02bb12e..a2a8a8d 100644 --- a/src/main/java/ru/windcorp/progressia/test/gen/TestGravityModel.java +++ b/src/main/java/ru/windcorp/progressia/test/gen/TestGravityModel.java @@ -17,15 +17,20 @@ */ package ru.windcorp.progressia.test.gen; +import java.io.DataInput; +import java.io.DataOutput; +import java.io.IOException; + import glm.vec._3.Vec3; import glm.vec._3.i.Vec3i; +import ru.windcorp.progressia.common.world.DecodingException; import ru.windcorp.progressia.common.world.GravityModel; import ru.windcorp.progressia.common.world.rels.AbsFace; public class TestGravityModel extends GravityModel { - public TestGravityModel() { - super("Test:TheGravityModel"); + public TestGravityModel(String id) { + super(id); } @Override @@ -39,4 +44,14 @@ public class TestGravityModel extends GravityModel { return rounded == null ? AbsFace.POS_Z : rounded; } + @Override + protected void doReadSettings(DataInput input) throws IOException, DecodingException { + // Do nothing + } + + @Override + protected void doWriteSettings(DataOutput output) throws IOException { + // Do nothing + } + } diff --git a/src/main/java/ru/windcorp/progressia/test/gen/planet/Planet.java b/src/main/java/ru/windcorp/progressia/test/gen/planet/Planet.java index 795c85f..38b9d94 100644 --- a/src/main/java/ru/windcorp/progressia/test/gen/planet/Planet.java +++ b/src/main/java/ru/windcorp/progressia/test/gen/planet/Planet.java @@ -23,20 +23,20 @@ public class Planet { private final int radiusInChunks; - private final float curvature; - private final float surfaceGravitationalAcceleration; - private final float innerGravityRadius; + private final TestPlanetGravityModel.Settings gravityModelSettings; public Planet( int radiusInChunks, - float curvature, float surfaceGravitationalAcceleration, + float curvature, float innerGravityRadius ) { this.radiusInChunks = radiusInChunks; - this.curvature = curvature; - this.surfaceGravitationalAcceleration = surfaceGravitationalAcceleration; - this.innerGravityRadius = innerGravityRadius; + this.gravityModelSettings = new TestPlanetGravityModel.Settings( + surfaceGravitationalAcceleration, + curvature, + innerGravityRadius + ); } /** @@ -62,21 +62,28 @@ public class Planet { * @return the curvature */ public float getCurvature() { - return curvature; + return gravityModelSettings.curvature; } /** * @return the innerGravityRadius */ public float getInnerGravityRadius() { - return innerGravityRadius; + return gravityModelSettings.innerRadius; } /** * @return the surfaceGravitationalAcceleration */ public float getSurfaceGravitationalAcceleration() { - return surfaceGravitationalAcceleration; + return gravityModelSettings.surfaceGravitationalAcceleration; + } + + /** + * @return the gravityModelSettings + */ + public TestPlanetGravityModel.Settings getGravityModelSettings() { + return gravityModelSettings; } } 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 b21d985..3012715 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 @@ -37,8 +37,12 @@ public class TestPlanetGenerator extends AbstractWorldGenerator { public TestPlanetGenerator(String id, Planet planet, WorldLogic world) { super(id, Boolean.class, "Test:PlanetGravityModel"); + this.planet = planet; + TestPlanetGravityModel model = (TestPlanetGravityModel) this.getGravityModel(); + model.configure(planet.getGravityModelSettings()); + this.terrainGenerator = new PlanetTerrainGenerator(this); this.scatterGenerator = new PlanetScatterGenerator(this); } diff --git a/src/main/java/ru/windcorp/progressia/test/gen/planet/TestPlanetGravityModel.java b/src/main/java/ru/windcorp/progressia/test/gen/planet/TestPlanetGravityModel.java index 309e0de..cb5fc34 100644 --- a/src/main/java/ru/windcorp/progressia/test/gen/planet/TestPlanetGravityModel.java +++ b/src/main/java/ru/windcorp/progressia/test/gen/planet/TestPlanetGravityModel.java @@ -19,36 +19,86 @@ package ru.windcorp.progressia.test.gen.planet; import glm.vec._3.Vec3; import glm.vec._3.i.Vec3i; -import ru.windcorp.progressia.common.Units; 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.rels.AbsFace; import static java.lang.Math.*; +import java.io.DataInput; +import java.io.DataOutput; +import java.io.IOException; + public class TestPlanetGravityModel extends GravityModel { - private static final float GRAVITATIONAL_ACCELERATION = Units.get("9.8 m/s^2"); - private static final float ROUNDNESS = Units.get("16 m"); - private static final float INNER_RADIUS = Units.get("16 m"); + public static class Settings { + public float surfaceGravitationalAcceleration; + public float curvature; + public float innerRadius; + + public Settings() {} + + public Settings(float surfaceGravitationalAcceleration, float curvature, float innerRadius) { + this.surfaceGravitationalAcceleration = surfaceGravitationalAcceleration; + this.curvature = curvature; + this.innerRadius = innerRadius; + } + + public void copyFrom(Settings copyFrom) { + this.surfaceGravitationalAcceleration = copyFrom.surfaceGravitationalAcceleration; + this.curvature = copyFrom.curvature; + this.innerRadius = copyFrom.innerRadius; + } + + public void read(DataInput input) throws IOException, DecodingException { + surfaceGravitationalAcceleration = input.readFloat(); + curvature = input.readFloat(); + innerRadius = input.readFloat(); + } + + public void write(DataOutput output) throws IOException { + output.writeFloat(surfaceGravitationalAcceleration); + output.writeFloat(curvature); + output.writeFloat(innerRadius); + } + } - public TestPlanetGravityModel() { - this("Test:PlanetGravityModel"); + private Settings settings = new Settings(); + + public TestPlanetGravityModel(String id) { + super(id); } - protected TestPlanetGravityModel(String id) { - super(id); + public float getSurfaceGravitationalAcceleration() { + return settings.surfaceGravitationalAcceleration; + } + + public float getCurvature() { + return settings.curvature; + } + + public float getInnerRadius() { + return settings.innerRadius; + } + + public void configure(Settings settings) { + this.settings = settings; } @Override protected void doGetGravity(Vec3 pos, Vec3 output) { + float r = getInnerRadius(); + float c = getCurvature(); + float g = getSurfaceGravitationalAcceleration(); + // Change to a CS where (0;0;0) is the center of the center chunk float px = pos.x - ChunkData.CHUNK_RADIUS + 0.5f; float py = pos.y - ChunkData.CHUNK_RADIUS + 0.5f; float pz = pos.z - ChunkData.CHUNK_RADIUS + 0.5f; // Assume weightlessness when too close to center - if ((px*px + py*py + pz*pz) < INNER_RADIUS*INNER_RADIUS) { + if ((px*px + py*py + pz*pz) < r*r) { output.set(0, 0, 0); return; } @@ -81,24 +131,26 @@ public class TestPlanetGravityModel extends GravityModel { } } - output.x = maxAbs - ax < ROUNDNESS ? (px > 0 ? +1 : -1) : 0; - output.y = maxAbs - ay < ROUNDNESS ? (py > 0 ? +1 : -1) : 0; - output.z = maxAbs - az < ROUNDNESS ? (pz > 0 ? +1 : -1) : 0; + output.x = maxAbs - ax < c ? (px > 0 ? +1 : -1) : 0; + output.y = maxAbs - ay < c ? (py > 0 ? +1 : -1) : 0; + output.z = maxAbs - az < c ? (pz > 0 ? +1 : -1) : 0; - if (maxAbs - midAbs < ROUNDNESS) { + if (maxAbs - midAbs < c) { output.normalize(); computeEdgeGravity(output.x, output.y, output.z, px, py, pz, output); } else { - assert output.dot(output) == 1 : "maxAbs - midAbs = " + maxAbs + " - " + midAbs + " > " + ROUNDNESS + " yet l*l != 1"; + assert output.dot(output) == 1 : "maxAbs - midAbs = " + maxAbs + " - " + midAbs + " > " + c + " yet l*l != 1"; } - output.mul(-GRAVITATIONAL_ACCELERATION); + output.mul(-g); } private void computeEdgeGravity(float lx, float ly, float lz, float rx, float ry, float rz, Vec3 output) { // da math is gud, no worry // - Javapony + float r = getInnerRadius(); + if (lx == 0) rx = 0; if (ly == 0) ry = 0; if (lz == 0) rz = 0; @@ -107,10 +159,10 @@ public class TestPlanetGravityModel extends GravityModel { float rSquared = rx*rx + ry*ry + rz*rz; float distanceAlongEdge = scalarProduct - (float) sqrt( - scalarProduct*scalarProduct - rSquared + ROUNDNESS*ROUNDNESS + scalarProduct*scalarProduct - rSquared + r*r ); - output.set(lx, ly, lz).mul(-distanceAlongEdge).add(rx, ry, rz).div(ROUNDNESS); + output.set(lx, ly, lz).mul(-distanceAlongEdge).add(rx, ry, rz).div(r); final float f = (float) sqrt(3.0/2); @@ -128,5 +180,15 @@ public class TestPlanetGravityModel extends GravityModel { AbsFace rounded = AbsFace.roundToFace(chunkPos.x, chunkPos.y, chunkPos.z); return rounded == null ? AbsFace.POS_Z : rounded; } + + @Override + protected void doReadSettings(DataInput input) throws IOException, DecodingException { + this.settings.read(input); + } + + @Override + protected void doWriteSettings(DataOutput output) throws IOException { + this.settings.write(output); + } } diff --git a/src/main/java/ru/windcorp/progressia/test/gen/surface/SurfaceCachingFloatField.java b/src/main/java/ru/windcorp/progressia/test/gen/surface/SurfaceCachingFloatField.java new file mode 100644 index 0000000..01a98f0 --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/test/gen/surface/SurfaceCachingFloatField.java @@ -0,0 +1,77 @@ +/* + * 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; + +import ru.windcorp.progressia.common.util.namespaces.Namespaced; +import ru.windcorp.progressia.common.world.rels.AbsFace; + +/** + * A scalar field defined on a plane. For each pair of {@code float}s (north; west) a single {@code float} is defined by this object. + */ +public abstract class SurfaceCachingFloatField extends Namespaced implements SurfaceFloatField { + + private final int levels; + + private SurfaceFieldRegistry registry = null; + private int index; + + public SurfaceCachingFloatField(String id, int levels) { + super(id); + this.levels = levels; + } + + int getIndex() { + if (getRegistry() == null) { + throw new IllegalStateException("No registry assigned to field " + this); + } + return index; + } + + void setIndex(int index) { + if (getRegistry() == null) { + throw new IllegalStateException("No registry assigned to field " + this); + } + this.index = index; + } + + SurfaceFieldRegistry getRegistry() { + return registry; + } + + void setRegistry(SurfaceFieldRegistry registry) { + this.registry = registry; + } + + public int getLevels() { + return levels; + } + + protected abstract float computeDetailAt(AbsFace surface, int level, float north, float west); + + @Override + public float get(AbsFace surface, float north, float west) { + float result = 0; + + for (int level = 0; level < getLevels(); ++level) { + result += computeDetailAt(surface, level, north, west); + } + + return result; + } + +} diff --git a/src/main/java/ru/windcorp/progressia/test/gen/surface/SurfaceFieldRegistry.java b/src/main/java/ru/windcorp/progressia/test/gen/surface/SurfaceFieldRegistry.java new file mode 100644 index 0000000..f1decd4 --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/test/gen/surface/SurfaceFieldRegistry.java @@ -0,0 +1,29 @@ +/* + * 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; + +public class SurfaceFieldRegistry { + + private int nextIndex = 0; + + public void register(SurfaceCachingFloatField field) { + field.setIndex(nextIndex); + nextIndex++; + } + +} diff --git a/src/main/java/ru/windcorp/progressia/test/gen/surface/SurfaceNodeStorage.java b/src/main/java/ru/windcorp/progressia/test/gen/surface/SurfaceNodeStorage.java new file mode 100644 index 0000000..ad1ec39 --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/test/gen/surface/SurfaceNodeStorage.java @@ -0,0 +1,57 @@ +/* + * 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; + +import java.io.DataInput; +import java.io.DataOutput; +import java.io.IOException; + +import gnu.trove.map.TLongObjectMap; +import gnu.trove.map.hash.TLongObjectHashMap; +import ru.windcorp.progressia.common.util.CoordinatePacker; +import ru.windcorp.progressia.common.world.DecodingException; + +public class SurfaceNodeStorage { + + public static class Node { +// private float[] floats; + } + + private final TLongObjectMap map = new TLongObjectHashMap<>(); + + public Node getNode(int north, int west) { + return map.get(CoordinatePacker.pack2IntsIntoLong(north, west)); + } + + public boolean hasNode(int north, int west) { + return map.containsKey(CoordinatePacker.pack2IntsIntoLong(north, west)); + } + + public void put(int north, int west, Node node) { + map.put(CoordinatePacker.pack2IntsIntoLong(north, west), node); + } + + public void read(DataInput input) throws IOException, DecodingException { + System.err.println("PlaneNodeMap.read did nothing because nobody implemented it yet"); + } + + public void write(DataOutput output) throws IOException { + System.err.println("PlaneNodeMap.write did nothing because nobody implemented it yet"); + } + +}