From 8c5493f78e973fd3dc6227abc123d767c7baa953 Mon Sep 17 00:00:00 2001 From: OLEGSHA Date: Mon, 25 Jan 2021 21:35:46 +0300 Subject: [PATCH 01/55] Added GravityModels, removed gravity switch - Added GravityModel - can specify gravity varying by location and time - Added GravityModelRegistry - Stored in WorldData - Removed Minecraft gravity mode --- .../client/graphics/world/LayerWorld.java | 13 +++--- .../progressia/common/world/GravityModel.java | 41 +++++++++++++++++++ .../common/world/GravityModelRegistry.java | 30 ++++++++++++++ .../progressia/common/world/WorldData.java | 16 ++++++++ .../progressia/test/LayerTestGUI.java | 11 ----- .../windcorp/progressia/test/TestContent.java | 3 ++ .../progressia/test/TestPlayerControls.java | 18 +------- .../progressia/test/gen/TestGravityModel.java | 34 +++++++++++++++ .../resources/assets/languages/en-US.lang | 1 - .../resources/assets/languages/ru-RU.lang | 1 - 10 files changed, 133 insertions(+), 35 deletions(-) create mode 100644 src/main/java/ru/windcorp/progressia/common/world/GravityModel.java create mode 100644 src/main/java/ru/windcorp/progressia/common/world/GravityModelRegistry.java create mode 100644 src/main/java/ru/windcorp/progressia/test/gen/TestGravityModel.java diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/world/LayerWorld.java b/src/main/java/ru/windcorp/progressia/client/graphics/world/LayerWorld.java index 317dfa2..d8ac99a 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/world/LayerWorld.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/world/LayerWorld.java @@ -41,6 +41,7 @@ import ru.windcorp.progressia.common.Units; import ru.windcorp.progressia.common.collision.Collideable; import ru.windcorp.progressia.common.collision.colliders.Collider; import ru.windcorp.progressia.common.util.FloatMathUtil; +import ru.windcorp.progressia.common.util.Vectors; import ru.windcorp.progressia.common.world.entity.EntityData; import ru.windcorp.progressia.test.CollisionModelRenderer; import ru.windcorp.progressia.test.TestPlayerControls; @@ -197,16 +198,18 @@ public class LayerWorld extends Layer { entity.getVelocity().mul((float) Math.exp(-FRICTION_COEFF / entity.getCollisionMass() * tickLength)); } - private static final float MC_g = Units.get("32 m/s^2"); - private static final float IRL_g = Units.get("9.8 m/s^2"); - private void tmp_applyGravity(EntityData entity, float tickLength) { if (ClientState.getInstance().getLocalPlayer().getEntity() == entity && tmp_testControls.isFlying()) { return; } - final float gravitationalAcceleration = tmp_testControls.useMinecraftGravity() ? MC_g : IRL_g; - entity.getVelocity().add(0, 0, -gravitationalAcceleration * tickLength); + Vec3 gravitationalAcceleration = Vectors.grab3(); + ClientState.getInstance().getWorld().getData().getGravityModel().getGravity(gravitationalAcceleration); + + gravitationalAcceleration.mul(tickLength); + entity.getVelocity().add(gravitationalAcceleration); + + Vectors.release(gravitationalAcceleration); } @Override diff --git a/src/main/java/ru/windcorp/progressia/common/world/GravityModel.java b/src/main/java/ru/windcorp/progressia/common/world/GravityModel.java new file mode 100644 index 0000000..ce21649 --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/common/world/GravityModel.java @@ -0,0 +1,41 @@ +/* + * 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.common.world; + +import glm.vec._3.Vec3; +import ru.windcorp.progressia.common.util.namespaces.Namespaced; + +public abstract class GravityModel extends Namespaced { + + public GravityModel(String id) { + super(id); + } + + public Vec3 getGravity(Vec3 output) { + if (output == null) { + output = new Vec3(); + } + + doGetGravity(output); + + return output; + } + + protected abstract void doGetGravity(Vec3 output); + +} diff --git a/src/main/java/ru/windcorp/progressia/common/world/GravityModelRegistry.java b/src/main/java/ru/windcorp/progressia/common/world/GravityModelRegistry.java new file mode 100644 index 0000000..b48cd0c --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/common/world/GravityModelRegistry.java @@ -0,0 +1,30 @@ +/* + * 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.common.world; + +import ru.windcorp.progressia.common.util.namespaces.NamespacedInstanceRegistry; + +public class GravityModelRegistry extends NamespacedInstanceRegistry { + + public static final GravityModelRegistry INSTANCE = new GravityModelRegistry(); + + public static GravityModelRegistry getInstance() { + return INSTANCE; + } + +} diff --git a/src/main/java/ru/windcorp/progressia/common/world/WorldData.java b/src/main/java/ru/windcorp/progressia/common/world/WorldData.java index 85c6188..6806c1b 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/WorldData.java +++ b/src/main/java/ru/windcorp/progressia/common/world/WorldData.java @@ -51,6 +51,8 @@ public class WorldData private final TLongObjectMap entitiesById = TCollections.synchronizedMap(new TLongObjectHashMap<>()); private final Collection entities = Collections.unmodifiableCollection(entitiesById.valueCollection()); + + private GravityModel gravityModel = GravityModelRegistry.getInstance().get("Test:TheGravityModel"); private float time = 0; @@ -200,6 +202,20 @@ public class WorldData return null; return block.getCollisionModel(); } + + /** + * @return the gravity model + */ + public GravityModel getGravityModel() { + return gravityModel; + } + + /** + * @param gravityModel the gravity model to set + */ + public void setGravityModel(GravityModel gravityModel) { + this.gravityModel = gravityModel; + } public Collection getListeners() { return listeners; diff --git a/src/main/java/ru/windcorp/progressia/test/LayerTestGUI.java b/src/main/java/ru/windcorp/progressia/test/LayerTestGUI.java index 30cca35..fa50625 100755 --- a/src/main/java/ru/windcorp/progressia/test/LayerTestGUI.java +++ b/src/main/java/ru/windcorp/progressia/test/LayerTestGUI.java @@ -91,17 +91,6 @@ public class LayerTestGUI extends GUILayer { ) ); - panel.addChild( - new Label( - "GravityModeDisplay", - font, - tmp_dynFormat( - "LayerTestGUI.GravityModeDisplay", - () -> tpc.useMinecraftGravity() ? "Minecraft" : "Realistic" - ) - ) - ); - panel.addChild( new Label( "LanguageDisplay", diff --git a/src/main/java/ru/windcorp/progressia/test/TestContent.java b/src/main/java/ru/windcorp/progressia/test/TestContent.java index 9fabd96..fe647f2 100644 --- a/src/main/java/ru/windcorp/progressia/test/TestContent.java +++ b/src/main/java/ru/windcorp/progressia/test/TestContent.java @@ -47,6 +47,7 @@ import ru.windcorp.progressia.common.collision.AABB; import ru.windcorp.progressia.common.collision.CollisionModel; import ru.windcorp.progressia.common.comms.controls.*; import ru.windcorp.progressia.common.state.StatefulObjectRegistry.Factory; +import ru.windcorp.progressia.common.world.GravityModelRegistry; import ru.windcorp.progressia.common.world.block.*; import ru.windcorp.progressia.common.world.entity.*; import ru.windcorp.progressia.common.world.io.ChunkIO; @@ -56,6 +57,7 @@ import ru.windcorp.progressia.server.comms.controls.*; import ru.windcorp.progressia.server.world.block.*; import ru.windcorp.progressia.server.world.entity.*; import ru.windcorp.progressia.server.world.tile.*; +import ru.windcorp.progressia.test.gen.TestGravityModel; public class TestContent { @@ -423,6 +425,7 @@ public class TestContent { private static void registerMisc() { ChunkIO.registerCodec(new TestChunkCodec()); ChunkRenderOptimizerRegistry.getInstance().register("Core:SurfaceOptimizer", ChunkRenderOptimizerSurface::new); + GravityModelRegistry.getInstance().register(new TestGravityModel()); } } diff --git a/src/main/java/ru/windcorp/progressia/test/TestPlayerControls.java b/src/main/java/ru/windcorp/progressia/test/TestPlayerControls.java index 710cbc1..0a0d3d3 100644 --- a/src/main/java/ru/windcorp/progressia/test/TestPlayerControls.java +++ b/src/main/java/ru/windcorp/progressia/test/TestPlayerControls.java @@ -83,7 +83,6 @@ public class TestPlayerControls { private double lastSprintPress = Double.NEGATIVE_INFINITY; private boolean captureMouse = true; - private boolean useMinecraftGravity = false; private int selectedBlock = 0; private int selectedTile = 0; @@ -199,12 +198,6 @@ public class TestPlayerControls { handleCameraMode(); break; - case GLFW.GLFW_KEY_G: - if (!event.isPress()) - return false; - handleGravitySwitch(); - break; - case GLFW.GLFW_KEY_L: if (!event.isPress()) return false; @@ -269,7 +262,7 @@ public class TestPlayerControls { return; } - getEntity().getVelocity().add(0, 0, JUMP_VELOCITY * (useMinecraftGravity ? 2 : 1)); + getEntity().getVelocity().add(0, 0, JUMP_VELOCITY); } private void handleShift(int multiplier) { @@ -313,11 +306,6 @@ public class TestPlayerControls { } } - private void handleGravitySwitch() { - useMinecraftGravity = !useMinecraftGravity; - updateGUI(); - } - private void handleLanguageSwitch() { Localizer localizer = Localizer.getInstance(); if (localizer.getLanguage().equals("ru-RU")) { @@ -427,10 +415,6 @@ public class TestPlayerControls { return captureMouse; } - public boolean useMinecraftGravity() { - return useMinecraftGravity; - } - public BlockData getSelectedBlock() { return TestContent.PLACEABLE_BLOCKS.get(selectedBlock); } diff --git a/src/main/java/ru/windcorp/progressia/test/gen/TestGravityModel.java b/src/main/java/ru/windcorp/progressia/test/gen/TestGravityModel.java new file mode 100644 index 0000000..0b666ce --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/test/gen/TestGravityModel.java @@ -0,0 +1,34 @@ +/* + * 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; + +import glm.vec._3.Vec3; +import ru.windcorp.progressia.common.world.GravityModel; + +public class TestGravityModel extends GravityModel { + + public TestGravityModel() { + super("Test:TheGravityModel"); + } + + @Override + protected void doGetGravity(Vec3 output) { + output.set(0, 0, -9.8); + } + +} diff --git a/src/main/resources/assets/languages/en-US.lang b/src/main/resources/assets/languages/en-US.lang index a47e216..62e2e6e 100644 --- a/src/main/resources/assets/languages/en-US.lang +++ b/src/main/resources/assets/languages/en-US.lang @@ -8,7 +8,6 @@ LayerTestGUI.IsFlyingDisplay = Flying: %5s (Space bar x2) LayerTestGUI.IsSprintingDisplay = Sprinting: %5s (W x2) LayerTestGUI.IsMouseCapturedDisplay = Mouse captured: %5s (Esc) LayerTestGUI.CameraModeDisplay = Camera mode: %5d (F5) -LayerTestGUI.GravityModeDisplay = Gravity: %9s (G) LayerTestGUI.LanguageDisplay = Language: %5s (L) LayerTestGUI.FPSDisplay = FPS: LayerTestGUI.TPSDisplay = TPS: diff --git a/src/main/resources/assets/languages/ru-RU.lang b/src/main/resources/assets/languages/ru-RU.lang index 180b25a..081a630 100644 --- a/src/main/resources/assets/languages/ru-RU.lang +++ b/src/main/resources/assets/languages/ru-RU.lang @@ -8,7 +8,6 @@ LayerTestGUI.IsFlyingDisplay = Полёт: %5s (Пробел x2) LayerTestGUI.IsSprintingDisplay = Бег: %5s (W x2) LayerTestGUI.IsMouseCapturedDisplay = Захват мыши: %5s (Esc) LayerTestGUI.CameraModeDisplay = Камера: %5d (F5) -LayerTestGUI.GravityModeDisplay = Гравитация: %9s (G) LayerTestGUI.LanguageDisplay = Язык: %5s (L) LayerTestGUI.FPSDisplay = FPS: LayerTestGUI.TPSDisplay = TPS: From 553837f2077e01f9dd914cf68777c31db5d5afcd Mon Sep 17 00:00:00 2001 From: OLEGSHA Date: Mon, 25 Jan 2021 22:06:34 +0300 Subject: [PATCH 02/55] GravityModels now take position into account - Also documented GravityModel --- .../client/graphics/world/LayerWorld.java | 2 +- .../progressia/common/world/GravityModel.java | 48 +++++++++++++++++-- .../progressia/test/gen/TestGravityModel.java | 2 +- 3 files changed, 47 insertions(+), 5 deletions(-) diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/world/LayerWorld.java b/src/main/java/ru/windcorp/progressia/client/graphics/world/LayerWorld.java index d8ac99a..a8de633 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/world/LayerWorld.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/world/LayerWorld.java @@ -204,7 +204,7 @@ public class LayerWorld extends Layer { } Vec3 gravitationalAcceleration = Vectors.grab3(); - ClientState.getInstance().getWorld().getData().getGravityModel().getGravity(gravitationalAcceleration); + ClientState.getInstance().getWorld().getData().getGravityModel().getGravity(entity.getPosition(), gravitationalAcceleration); gravitationalAcceleration.mul(tickLength); entity.getVelocity().add(gravitationalAcceleration); 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 ce21649..f17c9b6 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/GravityModel.java +++ b/src/main/java/ru/windcorp/progressia/common/world/GravityModel.java @@ -17,25 +17,67 @@ */ package ru.windcorp.progressia.common.world; +import java.util.Objects; + import glm.vec._3.Vec3; +import ru.windcorp.progressia.common.util.crash.CrashReports; import ru.windcorp.progressia.common.util.namespaces.Namespaced; +/** + * Gravity model specifies the gravitational acceleration field. A gravity model may be queried for the vector of gravitational acceleration that should affect an object. This vector is, generally speaking, a function of space: gravity in two different locations may vary. Gravity may also be a zero vector. + * + * @author javapony + */ public abstract class GravityModel extends Namespaced { public GravityModel(String id) { super(id); } - public Vec3 getGravity(Vec3 output) { + /** + * Computes the vector of gravitational acceleration at the provided location. + * + * @param pos the position to compute gravity at + * @param output a {@link Vec3} where the result is stored. May be {@code null}. + * + * @return the vector of gravitational acceleration. The returned object will match {@code output} parameter is it is non-null. + */ + public Vec3 getGravity(Vec3 pos, Vec3 output) { + Objects.requireNonNull(pos, "pos"); + if (output == null) { output = new Vec3(); } - doGetGravity(output); + try { + doGetGravity(pos, output); + } catch (Exception e) { + throw CrashReports.report(e, "%s failed to compute gravity at (%d; %d; %d)", this, pos.x, pos.y, pos.z); + } return output; } - protected abstract void doGetGravity(Vec3 output); + /** + * Computes the up direction at the provided location. Up vector is defined as the normalized gravitational acceleration vector or {@code (0; 0; 0)} if there is no gravity. + * + * @param pos the position to compute up vector at + * @param output a {@link Vec3} where the result is stored. May be {@code null}. + * + * @return the up vector. The returned object will match {@code output} parameter is it is non-null. + */ + public Vec3 getUp(Vec3 pos, Vec3 output) { + output = getGravity(pos, output); + if (output.any()) output.normalize(); + return output; + } + + /** + * Computes the gravitational acceleration vector at the provided location. Actual computation of gravity is delegated to this method by the other methods in this class. + * + * @param pos the position to compute gravity at + * @param output a {@link Vec3} where the result must be stored. Never {@code null}. + */ + protected abstract void doGetGravity(Vec3 pos, Vec3 output); } 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 0b666ce..ebcf715 100644 --- a/src/main/java/ru/windcorp/progressia/test/gen/TestGravityModel.java +++ b/src/main/java/ru/windcorp/progressia/test/gen/TestGravityModel.java @@ -27,7 +27,7 @@ public class TestGravityModel extends GravityModel { } @Override - protected void doGetGravity(Vec3 output) { + protected void doGetGravity(Vec3 pos, Vec3 output) { output.set(0, 0, -9.8); } From f9717be412376662070ef3f72e7cee7bc767deab Mon Sep 17 00:00:00 2001 From: OLEGSHA Date: Fri, 29 Jan 2021 23:19:22 +0300 Subject: [PATCH 03/55] Switched to using looking-at vectors instead of Euler angles Also fixed camera jittering and added some vector functions --- .../client/graphics/world/Camera.java | 79 +++---- .../client/graphics/world/EntityAnchor.java | 24 +- .../client/graphics/world/Selection.java | 5 +- .../client/world/entity/EntityRenderable.java | 60 ++++- .../client/world/entity/HumanoidModel.java | 1 + .../client/world/entity/NPedModel.java | 206 ++++++++++++------ .../client/world/entity/QuadripedModel.java | 1 + .../progressia/common/util/VectorUtil.java | 74 ++++++- .../progressia/common/world/BlockRay.java | 12 +- .../common/world/entity/EntityData.java | 129 ++++++++--- .../progressia/server/PlayerManager.java | 11 +- .../windcorp/progressia/test/LayerTestUI.java | 29 +-- .../test/TestEntityRenderStatie.java | 2 +- .../progressia/test/TestPlayerControls.java | 92 +++++--- 14 files changed, 517 insertions(+), 208 deletions(-) diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/world/Camera.java b/src/main/java/ru/windcorp/progressia/client/graphics/world/Camera.java index 46b551c..9c30a49 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/world/Camera.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/world/Camera.java @@ -29,6 +29,9 @@ import glm.mat._4.Mat4; import glm.vec._3.Vec3; import ru.windcorp.progressia.client.graphics.backend.GraphicsInterface; import ru.windcorp.progressia.client.graphics.world.Camera.Anchor.Mode; +import ru.windcorp.progressia.client.world.entity.NPedModel; +import ru.windcorp.progressia.common.util.Matrices; +import ru.windcorp.progressia.common.util.Vectors; public class Camera { @@ -60,13 +63,13 @@ public class Camera { } } - void getCameraPosition(Vec3 output); + Vec3 getCameraPosition(Vec3 output); - void getCameraVelocity(Vec3 output); + Vec3 getCameraVelocity(Vec3 output); - float getCameraYaw(); - - float getCameraPitch(); + Vec3 getLookingAt(Vec3 output); + + Vec3 getUpVector(Vec3 output); Collection getCameraModes(); @@ -84,14 +87,11 @@ public class Camera { */ private final Vec3 lastAnchorPosition = new Vec3(); - private float lastAnchorYaw; - private float lastAnchorPitch; + private final Vec3 lastAnchorLookingAt = new Vec3(); + private final Vec3 lastAnchorUpVector = new Vec3(); private final Mat4 lastCameraMatrix = new Mat4(); - private final Vec3 lastAnchorLookingAt = new Vec3(); - private final Vec3 lastAnchorUp = new Vec3(); - { invalidateCache(); } @@ -108,6 +108,9 @@ public class Camera { */ public void apply(WorldRenderHelper helper) { + if (NPedModel.flag) { +// System.out.println("Camera.apply()"); + } applyPerspective(helper); rotateCoordinateSystem(helper); @@ -149,26 +152,34 @@ public class Camera { } private void applyDirection(WorldRenderHelper helper) { - float pitch = anchor.getCameraPitch(); - float yaw = anchor.getCameraYaw(); + anchor.getLookingAt(lastAnchorLookingAt); + anchor.getUpVector(lastAnchorUpVector); - helper.pushViewTransform() - .rotateY(-pitch) - .rotateZ(-yaw); + lookAt(helper.pushViewTransform()); + } - this.lastAnchorYaw = yaw; - this.lastAnchorPitch = pitch; - - this.lastAnchorLookingAt.set( - cos(pitch) * cos(yaw), - cos(pitch) * sin(yaw), - sin(pitch) - ); - this.lastAnchorUp.set( - cos(pitch + PI_F / 2) * cos(yaw), - cos(pitch + PI_F / 2) * sin(yaw), - sin(pitch + PI_F / 2) + private void lookAt(Mat4 result) { + Vec3 f = this.lastAnchorLookingAt; + Vec3 s = Vectors.grab3(); + Vec3 u = Vectors.grab3(); + + f.cross(this.lastAnchorUpVector, s); + s.normalize(); + + s.cross(f, u); + + Mat4 workspace = Matrices.grab4(); + workspace.set( + +f.x, -s.x, +u.x, 0, + +f.y, -s.y, +u.y, 0, + +f.z, -s.z, +u.z, 0, + 0, 0, 0, 1 ); + result.mul(workspace); + Matrices.release(workspace); + + Vectors.release(s); + Vectors.release(u); } private void applyPosition(WorldRenderHelper helper) { @@ -247,8 +258,6 @@ public class Camera { private void invalidateCache() { this.lastAnchorPosition.set(Float.NaN); - this.lastAnchorYaw = Float.NaN; - this.lastAnchorPitch = Float.NaN; this.lastCameraMatrix.set( Float.NaN, @@ -270,7 +279,7 @@ public class Camera { ); this.lastAnchorLookingAt.set(Float.NaN); - this.lastAnchorUp.set(Float.NaN); + this.lastAnchorUpVector.set(Float.NaN); } public Anchor.Mode getMode() { @@ -289,14 +298,6 @@ public class Camera { return currentModeIndex; } - public float getLastAnchorYaw() { - return lastAnchorYaw; - } - - public float getLastAnchorPitch() { - return lastAnchorPitch; - } - public Vec3 getLastAnchorPosition() { return lastAnchorPosition; } @@ -310,7 +311,7 @@ public class Camera { } public Vec3 getLastAnchorUp() { - return lastAnchorUp; + return lastAnchorUpVector; } } diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/world/EntityAnchor.java b/src/main/java/ru/windcorp/progressia/client/graphics/world/EntityAnchor.java index d11ea92..cb578d9 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/world/EntityAnchor.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/world/EntityAnchor.java @@ -59,24 +59,32 @@ public class EntityAnchor implements Anchor { } @Override - public void getCameraPosition(Vec3 output) { + public Vec3 getCameraPosition(Vec3 output) { + if (output == null) output = new Vec3(); model.getViewPoint(output); - output.add(entity.getPosition()); + output.add(model.getPosition()); + return output; } @Override - public void getCameraVelocity(Vec3 output) { + public Vec3 getCameraVelocity(Vec3 output) { + if (output == null) output = new Vec3(); output.set(entity.getVelocity()); + return output; } @Override - public float getCameraYaw() { - return entity.getYaw(); + public Vec3 getLookingAt(Vec3 output) { + if (output == null) output = new Vec3(); + model.getLookingAt(output); + return output; } - + @Override - public float getCameraPitch() { - return entity.getPitch(); + public Vec3 getUpVector(Vec3 output) { + if (output == null) output = new Vec3(); + model.getUpVector(output); + return output; } @Override diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/world/Selection.java b/src/main/java/ru/windcorp/progressia/client/graphics/world/Selection.java index cd4ba29..e6cd57d 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/world/Selection.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/world/Selection.java @@ -38,10 +38,9 @@ public class Selection { private BlockRay ray = new BlockRay(); public void update(WorldRender world, EntityData player) { - Vec3 direction = new Vec3(); Vec3 start = new Vec3(); - - player.getLookingAtVector(direction); + Vec3 direction = player.getLookingAt(); + world.getEntityRenderable(player).getViewPoint(start); start.add(player.getPosition()); diff --git a/src/main/java/ru/windcorp/progressia/client/world/entity/EntityRenderable.java b/src/main/java/ru/windcorp/progressia/client/world/entity/EntityRenderable.java index eecaa16..24ea147 100644 --- a/src/main/java/ru/windcorp/progressia/client/world/entity/EntityRenderable.java +++ b/src/main/java/ru/windcorp/progressia/client/world/entity/EntityRenderable.java @@ -15,22 +15,49 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.client.world.entity; import glm.vec._3.Vec3; +import ru.windcorp.progressia.client.graphics.backend.GraphicsInterface; import ru.windcorp.progressia.client.graphics.model.Renderable; +import ru.windcorp.progressia.client.graphics.model.ShapeRenderHelper; import ru.windcorp.progressia.common.world.entity.EntityData; import ru.windcorp.progressia.common.world.generic.GenericEntity; public abstract class EntityRenderable implements Renderable, GenericEntity { private final EntityData data; + + private long stateComputedForFrame = -1; public EntityRenderable(EntityData data) { this.data = data; } + /** + * Updates the state of this model. This method is invoked exactly once per + * renderable per frame before this entity is queried for the first time. + */ + protected void update() { + // Do nothing + } + + private void updateIfNecessary() { + if (stateComputedForFrame != GraphicsInterface.getFramesRendered()) { + update(); + stateComputedForFrame = GraphicsInterface.getFramesRendered(); + } + } + + @Override + public final void render(ShapeRenderHelper renderer) { + updateIfNecessary(); + doRender(renderer); + } + + protected abstract void doRender(ShapeRenderHelper renderer); + public EntityData getData() { return data; } @@ -45,7 +72,36 @@ public abstract class EntityRenderable implements Renderable, GenericEntity { return getData().getId(); } - public void getViewPoint(Vec3 output) { + public final Vec3 getLookingAt(Vec3 output) { + if (output == null) output = new Vec3(); + updateIfNecessary(); + doGetLookingAt(output); + return output; + } + + protected void doGetLookingAt(Vec3 output) { + output.set(getData().getLookingAt()); + } + + public final Vec3 getUpVector(Vec3 output) { + if (output == null) output = new Vec3(); + updateIfNecessary(); + doGetUpVector(output); + return output; + } + + protected void doGetUpVector(Vec3 output) { + output.set(getData().getUpVector()); + } + + public final Vec3 getViewPoint(Vec3 output) { + if (output == null) output = new Vec3(); + updateIfNecessary(); + doGetViewPoint(output); + return output; + } + + protected void doGetViewPoint(Vec3 output) { output.set(0, 0, 0); } diff --git a/src/main/java/ru/windcorp/progressia/client/world/entity/HumanoidModel.java b/src/main/java/ru/windcorp/progressia/client/world/entity/HumanoidModel.java index 1609bfc..c33356f 100644 --- a/src/main/java/ru/windcorp/progressia/client/world/entity/HumanoidModel.java +++ b/src/main/java/ru/windcorp/progressia/client/world/entity/HumanoidModel.java @@ -43,6 +43,7 @@ public class HumanoidModel extends NPedModel { @Override protected void applyTransform(Mat4 mat, NPedModel model) { + super.applyTransform(mat, model); float phase = model.getWalkingFrequency() * model.getWalkingParameter() + animationOffset; float value = sin(phase); float amplitude = getSwingAmplitude((HumanoidModel) model) * model.getVelocityParameter(); diff --git a/src/main/java/ru/windcorp/progressia/client/world/entity/NPedModel.java b/src/main/java/ru/windcorp/progressia/client/world/entity/NPedModel.java index ead6565..ecefd06 100644 --- a/src/main/java/ru/windcorp/progressia/client/world/entity/NPedModel.java +++ b/src/main/java/ru/windcorp/progressia/client/world/entity/NPedModel.java @@ -18,11 +18,8 @@ package ru.windcorp.progressia.client.world.entity; -import static java.lang.Math.atan2; -import static java.lang.Math.min; import static java.lang.Math.pow; import static java.lang.Math.toRadians; -import static ru.windcorp.progressia.common.util.FloatMathUtil.normalizeAngle; import glm.Glm; import glm.mat._4.Mat4; @@ -32,6 +29,9 @@ import ru.windcorp.progressia.client.graphics.backend.GraphicsInterface; import ru.windcorp.progressia.client.graphics.model.Renderable; import ru.windcorp.progressia.client.graphics.model.ShapeRenderHelper; import ru.windcorp.progressia.common.Units; +import ru.windcorp.progressia.common.util.FloatMathUtil; +import ru.windcorp.progressia.common.util.VectorUtil; +import ru.windcorp.progressia.common.util.Vectors; import ru.windcorp.progressia.common.world.entity.EntityData; public abstract class NPedModel extends EntityRenderable { @@ -51,29 +51,30 @@ public abstract class NPedModel extends EntityRenderable { ShapeRenderHelper renderer, NPedModel model ) { - renderer.pushTransform().translate(translation); applyTransform(renderer.pushTransform(), model); renderable.render(renderer); renderer.popTransform(); - renderer.popTransform(); } - protected abstract void applyTransform(Mat4 mat, NPedModel model); + protected void applyTransform(Mat4 mat, NPedModel model) { + mat.translate(getTranslation()); + } public Vec3 getTranslation() { return translation; } + + public Mat4 getTransform(Mat4 output, NPedModel model) { + if (output == null) output = new Mat4().identity(); + applyTransform(output, model); + return output; + } } public static class Body extends BodyPart { public Body(Renderable renderable) { super(renderable, null); } - - @Override - protected void applyTransform(Mat4 mat, NPedModel model) { - // Do nothing - } } public static class Head extends BodyPart { @@ -97,7 +98,8 @@ public abstract class NPedModel extends EntityRenderable { @Override protected void applyTransform(Mat4 mat, NPedModel model) { - mat.rotateZ(model.getHeadYaw()).rotateY(model.getHeadPitch()); + super.applyTransform(mat, model); + mat.rotateZ(-model.getHeadYaw()).rotateY(-model.getHeadPitch()); } public Vec3 getViewPoint() { @@ -105,6 +107,8 @@ public abstract class NPedModel extends EntityRenderable { } } + public static boolean flag; + protected final Body body; protected final Head head; @@ -128,7 +132,9 @@ public abstract class NPedModel extends EntityRenderable { private float walkingFrequency; - private float bodyYaw = Float.NaN; + private final Vec3 bodyLookingAt = new Vec3().set(0); + private final Mat4 bodyTransform = new Mat4(); + private float headYaw; private float headPitch; @@ -138,68 +144,122 @@ public abstract class NPedModel extends EntityRenderable { this.head = head; this.scale = scale; - evaluateAngles(); + computeRotations(); } @Override - public void render(ShapeRenderHelper renderer) { - renderer.pushTransform().scale(scale).rotateZ(bodyYaw); + protected void doRender(ShapeRenderHelper renderer) { + renderer.pushTransform().scale(scale).mul(bodyTransform); renderBodyParts(renderer); renderer.popTransform(); - - accountForVelocity(); - evaluateAngles(); } protected void renderBodyParts(ShapeRenderHelper renderer) { body.render(renderer, this); head.render(renderer, this); } - - private void evaluateAngles() { - float globalYaw = normalizeAngle(getData().getYaw()); - - if (Float.isNaN(bodyYaw)) { - bodyYaw = globalYaw; - headYaw = 0; - } else { - headYaw = normalizeAngle(globalYaw - bodyYaw); - - if (headYaw > +head.maxYaw) { - bodyYaw += headYaw - +head.maxYaw; - headYaw = +head.maxYaw; - } else if (headYaw < -head.maxYaw) { - bodyYaw += headYaw - -head.maxYaw; - headYaw = -head.maxYaw; - } - } - - bodyYaw = normalizeAngle(bodyYaw); - - headPitch = Glm.clamp( - getData().getPitch(), - -head.maxPitch, - head.maxPitch - ); + + @Override + protected void update() { + advanceTime(); + computeRotations(); } - private void accountForVelocity() { - Vec3 horizontal = new Vec3(getData().getVelocity()); - horizontal.z = 0; + private void computeRotations() { + if (!bodyLookingAt.any()) { + getData().getForwardVector(bodyLookingAt); + headYaw = 0; + } else { + ensureBodyLookingAtIsPerpendicularToUpVector(); + computeDesiredHeadYaw(); + clampHeadYawAndChangeBodyLookingAt(); + } + + recomputeBodyTransform(); + + setHeadPitch(); + } + + private void ensureBodyLookingAtIsPerpendicularToUpVector() { + Vec3 up = getData().getUpVector(); + if (up.dot(bodyLookingAt) > 1 - 1e-4) return; + + Vec3 tmp = Vectors.grab3(); + + tmp.set(up).mul(-up.dot(bodyLookingAt)).add(bodyLookingAt); + + float tmpLength = tmp.length(); + if (tmpLength > 1e-4) { + bodyLookingAt.set(tmp).div(tmpLength); + } else { + // bodyLookingAt is suddenly parallel to up vector -- PANIC! ENTERING RESCUE MODE! + getData().getForwardVector(bodyLookingAt); + } + + Vectors.release(tmp); + } + + private void computeDesiredHeadYaw() { + Vec3 newDirection = getData().getForwardVector(null); + Vec3 oldDirection = bodyLookingAt; + Vec3 up = getData().getUpVector(); + + headYaw = (float) VectorUtil.getAngle(oldDirection, newDirection, up); + } + + private void clampHeadYawAndChangeBodyLookingAt() { + float bodyYawChange = 0; + + if (headYaw > +head.maxYaw) { + bodyYawChange = headYaw - +head.maxYaw; + headYaw = +head.maxYaw; + } else if (headYaw < -head.maxYaw) { + bodyYawChange = headYaw - -head.maxYaw; + headYaw = -head.maxYaw; + } + + if (bodyYawChange != 0) { + VectorUtil.rotate(bodyLookingAt, getData().getUpVector(), bodyYawChange); + } + } + + private void recomputeBodyTransform() { + Vec3 u = getData().getUpVector(); + Vec3 f = bodyLookingAt; + Vec3 s = Vectors.grab3(); + + s.set(u).cross(f); + + bodyTransform.identity().set( + +f.x, -s.x, +u.x, 0, + +f.y, -s.y, +u.y, 0, + +f.z, -s.z, +u.z, 0, + 0, 0, 0, 1 + ); + + Vectors.release(s); + } + + private void setHeadPitch() { + headPitch = Glm.clamp((float) getData().getPitch(), -head.maxPitch, +head.maxPitch); + } + + private void advanceTime() { + Vec3 horizontal = getData().getUpVector() + .mul_(-getData().getUpVector().dot(getData().getVelocity())) + .add(getData().getVelocity()); velocity = horizontal.length(); - evaluateVelocityCoeff(); + computeVelocityParameter(); // TODO switch to world time walkingParameter += velocity * GraphicsInterface.getFrameLength() * 1000; - - bodyYaw += velocityParameter * normalizeAngle( - (float) (atan2(horizontal.y, horizontal.x) - bodyYaw) - ) * min(1, GraphicsInterface.getFrameLength() * 10); + + rotateBodyWithMovement(horizontal); } - private void evaluateVelocityCoeff() { + private void computeVelocityParameter() { if (velocity > maxEffectiveVelocity) { velocityParameter = 1; } else { @@ -207,17 +267,39 @@ public abstract class NPedModel extends EntityRenderable { } } + private void rotateBodyWithMovement(Vec3 target) { + if (velocityParameter == 0 || !target.any() || Glm.equals(target, bodyLookingAt)) { + return; + } + + Vec3 axis = getData().getUpVector(); + + float yawDifference = FloatMathUtil.normalizeAngle( + (float) VectorUtil.getAngle( + bodyLookingAt, + target.normalize_(), + axis + ) + ); + + float bodyYawChange = + velocityParameter * + yawDifference * + (float) Math.expm1(GraphicsInterface.getFrameLength() * 10); + + VectorUtil.rotate(bodyLookingAt, axis, bodyYawChange); + } + @Override - public void getViewPoint(Vec3 output) { + protected void doGetViewPoint(Vec3 output) { Mat4 m = new Mat4(); Vec4 v = new Vec4(); m.identity() .scale(scale) - .rotateZ(bodyYaw) - .translate(head.getTranslation()) - .rotateZ(headYaw) - .rotateY(headPitch); + .mul(bodyTransform); + + head.getTransform(m, this); v.set(head.getViewPoint(), 1); m.mul(v); @@ -232,9 +314,9 @@ public abstract class NPedModel extends EntityRenderable { public Head getHead() { return head; } - - public float getBodyYaw() { - return bodyYaw; + + public Vec3 getBodyLookingAt() { + return bodyLookingAt; } public float getHeadYaw() { diff --git a/src/main/java/ru/windcorp/progressia/client/world/entity/QuadripedModel.java b/src/main/java/ru/windcorp/progressia/client/world/entity/QuadripedModel.java index 8755b08..db6dbf4 100644 --- a/src/main/java/ru/windcorp/progressia/client/world/entity/QuadripedModel.java +++ b/src/main/java/ru/windcorp/progressia/client/world/entity/QuadripedModel.java @@ -44,6 +44,7 @@ public class QuadripedModel extends NPedModel { @Override protected void applyTransform(Mat4 mat, NPedModel model) { + super.applyTransform(mat, model); float phase = model.getWalkingFrequency() * model.getWalkingParameter() + animationOffset; float value = sin(phase); float amplitude = ((QuadripedModel) model).getWalkingSwing() * model.getVelocityParameter(); diff --git a/src/main/java/ru/windcorp/progressia/common/util/VectorUtil.java b/src/main/java/ru/windcorp/progressia/common/util/VectorUtil.java index 00ede3e..1de0848 100644 --- a/src/main/java/ru/windcorp/progressia/common/util/VectorUtil.java +++ b/src/main/java/ru/windcorp/progressia/common/util/VectorUtil.java @@ -20,6 +20,8 @@ package ru.windcorp.progressia.common.util; import java.util.function.Consumer; +import glm.Glm; +import glm.mat._3.Mat3; import glm.mat._4.Mat4; import glm.vec._2.Vec2; import glm.vec._2.d.Vec2d; @@ -135,12 +137,72 @@ public class VectorUtil { } public static void applyMat4(Vec3 inOut, Mat4 mat) { - Vec4 vec4 = Vectors.grab4(); - vec4.set(inOut, 1f); - - mat.mul(vec4); - - inOut.set(vec4.x, vec4.y, vec4.z); + applyMat4(inOut, mat, inOut); + } + + public static void rotate(Vec3 in, Vec3 axis, float angle, Vec3 out) { + Mat3 mat = Matrices.grab3(); + + mat.identity().rotate(angle, axis); + mat.mul(in, out); + + Matrices.release(mat); + } + + public static void rotate(Vec3 inOut, Vec3 axis, float angle) { + rotate(inOut, axis, angle, inOut); + } + + public static double getAngle(Vec3 from, Vec3 to, Vec3 normal) { + Vec3 left = Vectors.grab3(); + + left.set(normal).cross(from); + double sign = Math.signum(left.dot(to)); + + double result = (float) Math.acos(Glm.clamp(from.dot(to), -1, +1)) * sign; + + Vectors.release(left); + return result; + } + + public static Vec3 projectOnSurface(Vec3 in, Vec3 normal, Vec3 out) { + if (in == out) { + return projectOnSurface(in, normal); + } + + if (out == null) { + out = new Vec3(); + } + + out.set(normal).mul(-normal.dot(in)).add(in); + + return out; + } + + public static Vec3 projectOnSurface(Vec3 inOut, Vec3 normal) { + Vec3 buffer = Vectors.grab3(); + + projectOnSurface(inOut, normal, buffer); + inOut.set(buffer); + + Vectors.release(buffer); + + return inOut; + } + + public static Vec3 projectOnVector(Vec3 in, Vec3 vector, Vec3 out) { + if (out == null) { + out = new Vec3(); + } + + float dot = vector.dot(in); + out.set(vector).mul(dot); + + return out; + } + + public static Vec3 projectOnVector(Vec3 inOut, Vec3 vector) { + return projectOnVector(inOut, vector); } public static Vec3 linearCombination( diff --git a/src/main/java/ru/windcorp/progressia/common/world/BlockRay.java b/src/main/java/ru/windcorp/progressia/common/world/BlockRay.java index 4d5f1f9..743d238 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/BlockRay.java +++ b/src/main/java/ru/windcorp/progressia/common/world/BlockRay.java @@ -39,9 +39,17 @@ public class BlockRay { private boolean isValid = false; public void start(Vec3 position, Vec3 direction) { - if (!direction.any()) { + if (direction.x == 0 && direction.y == 0 && direction.z == 0) { throw new IllegalArgumentException("Direction is a zero vector"); } + + if (Float.isNaN(direction.x) || Float.isNaN(direction.y) || Float.isNaN(direction.z)) { + throw new IllegalArgumentException("Direction contains NaN: " + direction); + } + + if (Float.isNaN(position.x) || Float.isNaN(position.y) || Float.isNaN(position.z)) { + throw new IllegalArgumentException("Position contains NaN: " + position); + } isValid = true; this.position.set(position).sub(0.5f); // Make sure lattice points are @@ -75,6 +83,8 @@ public class BlockRay { tMin = tz; axis = Axis.Z; } + + assert tMin > 0 : "tMin is not positive (" + tMin + ")"; // block.(axis) += signum(direction.(axis)) VectorUtil.set(block, axis, VectorUtil.get(block, axis) + (int) signum(VectorUtil.get(direction, axis))); diff --git a/src/main/java/ru/windcorp/progressia/common/world/entity/EntityData.java b/src/main/java/ru/windcorp/progressia/common/world/entity/EntityData.java index 7b3325c..2dcdf3e 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/entity/EntityData.java +++ b/src/main/java/ru/windcorp/progressia/common/world/entity/EntityData.java @@ -15,14 +15,13 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.common.world.entity; import java.io.DataInput; import java.io.DataOutput; import java.io.IOException; -import glm.vec._2.Vec2; import glm.vec._3.Vec3; import ru.windcorp.jputil.chars.StringUtil; import ru.windcorp.progressia.common.collision.Collideable; @@ -36,7 +35,8 @@ public class EntityData extends StatefulObject implements Collideable, GenericEn private final Vec3 position = new Vec3(); private final Vec3 velocity = new Vec3(); - private final Vec2 direction = new Vec2(); + private final Vec3 lookingAt = new Vec3(1, 0, 0); + private final Vec3 upVector = new Vec3(0, 0, 1); /** * The unique {@code long} value guaranteed to never be assigned to an @@ -79,22 +79,6 @@ public class EntityData extends StatefulObject implements Collideable, GenericEn this.velocity.set(velocity); } - public Vec2 getDirection() { - return direction; - } - - public void setDirection(Vec2 direction) { - this.direction.set(direction.x, direction.y); - } - - public float getYaw() { - return getDirection().x; - } - - public float getPitch() { - return getDirection().y; - } - public long getEntityId() { return entityId; } @@ -152,16 +136,90 @@ public class EntityData extends StatefulObject implements Collideable, GenericEn getVelocity().add(velocityChange); } - public Vec3 getLookingAtVector(Vec3 output) { - output.set( - Math.cos(getPitch()) * Math.cos(getYaw()), - Math.cos(getPitch()) * Math.sin(getYaw()), - -Math.sin(getPitch()) - ); + public Vec3 getLookingAt() { + return lookingAt; + } + public void setLookingAt(Vec3 lookingAt) { + float lengthSq = lookingAt.x * lookingAt.x + lookingAt.y * lookingAt.y + lookingAt.z * lookingAt.z; + if (lengthSq == 1) { + this.lookingAt.set(lookingAt); + } else if (lengthSq == 0) { + throw new IllegalArgumentException("lookingAt is zero-length"); + } else { + float length = (float) Math.sqrt(lengthSq); + this.lookingAt.set( + lookingAt.x / length, + lookingAt.y / length, + lookingAt.z / length + ); + } + } + + public Vec3 getUpVector() { + return upVector; + } + + /** + * Sets this entity's up vector without updating looking at-vector. + * + * @param upVector the Vec3 to copy up vector from + * @see #changeUpVector(Vec3) + */ + public void setUpVector(Vec3 upVector) { + float lengthSq = upVector.x * upVector.x + upVector.y * upVector.y + upVector.z * upVector.z; + if (lengthSq == 1) { + this.upVector.set(upVector); + } else if (lengthSq == 0) { + throw new IllegalArgumentException("upVector is zero-length"); + } else { + float length = (float) Math.sqrt(lengthSq); + this.upVector.set( + upVector.x / length, + upVector.y / length, + upVector.z / length + ); + } + } + + /** + * Computes the forward vector of this entity. An entity's forward vector is + * defined as a normalized projection of the looking at-vector onto the + * plane perpendicular to up vector, or {@code (NaN; NaN; NaN)} if looking + * at-vector is parallel to the up vector. + * + * @param output a {@link Vec3} where the result is stored. May be + * {@code null}. + * @return the computed forward vector or {@code (NaN; NaN; NaN)} + */ + public Vec3 getForwardVector(Vec3 output) { + if (output == null) + output = new Vec3(); + output.set(getUpVector()).mul(-getUpVector().dot(getLookingAt())).add(getLookingAt()).normalize(); return output; } + public double getPitch() { + return -Math.acos(getLookingAt().dot(getUpVector())) + Math.PI / 2; + } + + /** + * Updates this entity's up vector and alters looking at-vector to match the + * rotation of the up vector. + *

+ * This method assumes that the up vector has changed due to rotation around + * some axis. The axis and the angle are computed, after which the same + * rotation is applied to the looking at-vector. + * + * @param newUpVector the Vec3 to copy up vector from. May be equal to + * current up vector + * @see #setLookingAt(Vec3) + */ + public void changeUpVector(Vec3 newUpVector) { + // TODO + this.upVector.set(newUpVector); + } + @Override public String toString() { return new StringBuilder(super.toString()) @@ -189,8 +247,13 @@ public class EntityData extends StatefulObject implements Collideable, GenericEn output.writeFloat(getVelocity().y); output.writeFloat(getVelocity().z); - output.writeFloat(getDirection().x); - output.writeFloat(getDirection().y); + output.writeFloat(getLookingAt().x); + output.writeFloat(getLookingAt().y); + output.writeFloat(getLookingAt().z); + + output.writeFloat(getUpVector().x); + output.writeFloat(getUpVector().y); + output.writeFloat(getUpVector().z); super.write(output, context); } @@ -209,14 +272,22 @@ public class EntityData extends StatefulObject implements Collideable, GenericEn input.readFloat() ); - Vec2 direction = new Vec2( + Vec3 lookingAt = new Vec3( + input.readFloat(), + input.readFloat(), + input.readFloat() + ); + + Vec3 upVector = new Vec3( + input.readFloat(), input.readFloat(), input.readFloat() ); setPosition(position); setVelocity(velocity); - setDirection(direction); + setLookingAt(lookingAt); + setUpVector(upVector); super.read(input, context); } diff --git a/src/main/java/ru/windcorp/progressia/server/PlayerManager.java b/src/main/java/ru/windcorp/progressia/server/PlayerManager.java index 38d0f32..8e34b49 100644 --- a/src/main/java/ru/windcorp/progressia/server/PlayerManager.java +++ b/src/main/java/ru/windcorp/progressia/server/PlayerManager.java @@ -22,7 +22,7 @@ import java.util.ArrayList; import java.util.Collection; import java.util.Collections; -import glm.vec._2.Vec2; +import glm.vec._3.Vec3; import ru.windcorp.progressia.common.util.crash.CrashReports; import ru.windcorp.progressia.common.world.entity.EntityData; import ru.windcorp.progressia.common.world.entity.EntityDataRegistry; @@ -61,12 +61,9 @@ public class PlayerManager { player.setEntityId(TestContent.PLAYER_ENTITY_ID); player.setPosition(TestContent.SPAWN); - player.setDirection( - new Vec2( - Math.toRadians(40), - Math.toRadians(10) - ) - ); + + player.setUpVector(new Vec3(0, 0, 1)); + player.setLookingAt(new Vec3(2, 1, 0)); getServer().getWorld().getData().addEntity(player); diff --git a/src/main/java/ru/windcorp/progressia/test/LayerTestUI.java b/src/main/java/ru/windcorp/progressia/test/LayerTestUI.java index c93a055..7962ca1 100755 --- a/src/main/java/ru/windcorp/progressia/test/LayerTestUI.java +++ b/src/main/java/ru/windcorp/progressia/test/LayerTestUI.java @@ -24,7 +24,6 @@ import com.google.common.eventbus.Subscribe; import glm.mat._4.Mat4; import glm.vec._4.Vec4; -import ru.windcorp.progressia.client.ClientState; import ru.windcorp.progressia.client.graphics.Colors; import ru.windcorp.progressia.client.graphics.backend.GraphicsInterface; import ru.windcorp.progressia.client.graphics.flat.AssembledFlatLayer; @@ -34,7 +33,6 @@ import ru.windcorp.progressia.client.graphics.input.bus.Input; import ru.windcorp.progressia.client.graphics.model.LambdaModel; import ru.windcorp.progressia.client.graphics.texture.SimpleTextures; import ru.windcorp.progressia.client.graphics.texture.Texture; -import ru.windcorp.progressia.client.graphics.world.Camera; public class LayerTestUI extends AssembledFlatLayer { @@ -46,9 +44,12 @@ public class LayerTestUI extends AssembledFlatLayer { private boolean flag = false; - private static final int WIDTH = 80; - private static final int HEIGHT = 80; + private static final int SCALE = 4; + private static final int TEX_SIZE = 16 * SCALE; + private static final int TEX_SHADOW = SCALE / 2; private static final int BORDER = 5; + private static final int HEIGHT = TEX_SIZE + 4 * BORDER; + private static final int WIDTH = HEIGHT; @Override protected void assemble(RenderTarget target) { @@ -64,25 +65,22 @@ public class LayerTestUI extends AssembledFlatLayer { target.fill(x, y, WIDTH, HEIGHT, borderColor); target.fill(x + BORDER, y + BORDER, WIDTH - 2 * BORDER, HEIGHT - 2 * BORDER, boxColor); - final int texShadow = 2; - final int texSize = HEIGHT - 4 * BORDER; - target.pushTransform(new Mat4().identity().translate(x + 2 * BORDER, y + 2 * BORDER, 0)); final Texture compassBg = SimpleTextures.get("compass_icon"); final Texture compassFg = SimpleTextures.get("compass_icon_arrow"); - target.drawTexture(texShadow, -texShadow, texSize, texSize, Colors.BLACK, compassBg); - target.drawTexture(0, 0, texSize, texSize, compassBg); + target.drawTexture(TEX_SHADOW, -TEX_SHADOW, TEX_SIZE, TEX_SIZE, Colors.BLACK, compassBg); + target.drawTexture(0, 0, TEX_SIZE, TEX_SIZE, compassBg); target.addCustomRenderer( new LambdaModel( LambdaModel.lambdaBuilder() .addDynamicPart( - target.createRectagle(0, 0, texSize, texSize, Colors.WHITE, compassFg), - mat -> mat.translate(texSize / 2, texSize / 2, 0) + target.createRectagle(0, 0, TEX_SIZE, TEX_SIZE, Colors.WHITE, compassFg), + mat -> mat.translate(TEX_SIZE / 2, TEX_SIZE / 2, 0) .rotateZ(getCompassRotation()) - .translate(-texSize / 2, -texSize / 2, 0) + .translate(-TEX_SIZE / 2, -TEX_SIZE / 2, 0) ) ) ); @@ -92,12 +90,7 @@ public class LayerTestUI extends AssembledFlatLayer { } private double getCompassRotation() { - Camera.Anchor anchor = ClientState.getInstance().getCamera().getAnchor(); - - if (anchor == null) - return 0; - - return -anchor.getCameraYaw(); + return 0; } private void drawCross(RenderTarget target) { diff --git a/src/main/java/ru/windcorp/progressia/test/TestEntityRenderStatie.java b/src/main/java/ru/windcorp/progressia/test/TestEntityRenderStatie.java index 47990fd..fa595e7 100644 --- a/src/main/java/ru/windcorp/progressia/test/TestEntityRenderStatie.java +++ b/src/main/java/ru/windcorp/progressia/test/TestEntityRenderStatie.java @@ -44,7 +44,7 @@ public class TestEntityRenderStatie extends EntityRender { public EntityRenderable createRenderable(EntityData entity) { return new EntityRenderable(entity) { @Override - public void render(ShapeRenderHelper renderer) { + public void doRender(ShapeRenderHelper renderer) { renderer.pushTransform().scale( ((TestEntityDataStatie) entity).getSize() / 24.0f ); diff --git a/src/main/java/ru/windcorp/progressia/test/TestPlayerControls.java b/src/main/java/ru/windcorp/progressia/test/TestPlayerControls.java index 0a0d3d3..1254399 100644 --- a/src/main/java/ru/windcorp/progressia/test/TestPlayerControls.java +++ b/src/main/java/ru/windcorp/progressia/test/TestPlayerControls.java @@ -20,7 +20,7 @@ package ru.windcorp.progressia.test; import glm.Glm; import glm.mat._3.Mat3; -import glm.vec._2.Vec2; +import glm.mat._4.Mat4; import glm.vec._3.Vec3; import org.lwjgl.glfw.GLFW; import ru.windcorp.progressia.client.ClientState; @@ -36,7 +36,9 @@ import ru.windcorp.progressia.client.graphics.input.bus.Input; import ru.windcorp.progressia.client.graphics.world.LocalPlayer; import ru.windcorp.progressia.client.localization.Localizer; import ru.windcorp.progressia.common.Units; -import ru.windcorp.progressia.common.util.FloatMathUtil; +import ru.windcorp.progressia.common.util.Matrices; +import ru.windcorp.progressia.common.util.VectorUtil; +import ru.windcorp.progressia.common.util.Vectors; import ru.windcorp.progressia.common.world.block.BlockData; import ru.windcorp.progressia.common.world.entity.EntityData; import ru.windcorp.progressia.common.world.tile.TileData; @@ -108,17 +110,17 @@ public class TestPlayerControls { authority = WALKING_CONTROL_AUTHORITY; } - Mat3 angMat = new Mat3().identity().rotateZ(player.getYaw()); - Vec3 desiredVelocity = new Vec3(movementForward, -movementRight, 0); - - if (movementForward != 0 && movementRight != 0) + Mat3 movementTransform = getMovementTransform(player, null); + Vec3 desiredVelocity = new Vec3(movementForward, movementRight, 0); + if (movementForward != 0 && movementRight != 0) { desiredVelocity.normalize(); - angMat.mul_(desiredVelocity); // bug in jglm, .mul() and mul_() are - // swapped + } desiredVelocity.z = movementUp; + movementTransform.mul_(desiredVelocity); // bug in jglm, .mul() and mul_() are + // swapped desiredVelocity.mul(speed); - Vec3 change = new Vec3() + Vec3 newVelocity = new Vec3() .set(desiredVelocity) .sub(player.getVelocity()) .mul((float) Math.exp(-authority * GraphicsInterface.getFrameLength())) @@ -126,10 +128,12 @@ public class TestPlayerControls { .add(desiredVelocity); if (!isFlying) { - change.z = player.getVelocity().z; + Vec3 up = player.getUpVector(); + Vec3 wantedVertical = VectorUtil.projectOnVector(player.getVelocity(), up, null); + VectorUtil.projectOnSurface(newVelocity, up).add(wantedVertical); } - player.getVelocity().set(change); + player.getVelocity().set(newVelocity); // THIS IS TERRIBLE TEST EntityData serverEntity = ServerState.getInstance().getWorld().getData() @@ -140,6 +144,22 @@ public class TestPlayerControls { } + private Mat3 getMovementTransform(EntityData player, Mat3 mat) { + if (mat == null) { + mat = new Mat3(); + } + + Vec3 f = player.getForwardVector(null); + Vec3 u = player.getUpVector(); + Vec3 s = u.cross_(f); + + return mat.set( + +f.x, -s.x, +u.x, + +f.y, -s.y, +u.y, + +f.z, -s.z, +u.z + ); + } + public void handleInput(Input input) { InputEvent event = input.getEvent(); @@ -318,36 +338,44 @@ public class TestPlayerControls { } private void onMouseMoved(CursorMoveEvent event) { - if (!captureMouse) + if (!captureMouse) { return; + } if (ClientState.getInstance() == null || !ClientState.getInstance().isReady()) { return; } - final float yawScale = -0.002f; - final float pitchScale = yawScale; + final double yawScale = -0.002f; + final double pitchScale = -yawScale; + final double pitchExtremum = Math.PI/2 * 0.95f; + + double yawChange = event.getChangeX() * yawScale; + double pitchChange = event.getChangeY() * pitchScale; EntityData player = getEntity(); + + double startPitch = player.getPitch(); + double endPitch = startPitch + pitchChange; + endPitch = Glm.clamp(endPitch, -pitchExtremum, +pitchExtremum); + pitchChange = endPitch - startPitch; + + Mat4 mat = Matrices.grab4(); + Vec3 lookingAt = Vectors.grab3(); + Vec3 rightVector = Vectors.grab3(); - normalizeAngles( - player.getDirection().add( - (float) (event.getChangeX() * yawScale), - (float) (event.getChangeY() * pitchScale) - ) - ); - } - - private void normalizeAngles(Vec2 dir) { - // Normalize yaw - dir.x = FloatMathUtil.normalizeAngle(dir.x); - - // Clamp pitch - dir.y = Glm.clamp( - dir.y, - -FloatMathUtil.PI_F / 2, - +FloatMathUtil.PI_F / 2 - ); + rightVector.set(player.getLookingAt()).cross(player.getUpVector()).normalize(); + + mat.identity() + .rotate((float) yawChange, player.getUpVector()) + .rotate((float) pitchChange, rightVector); + + VectorUtil.applyMat4(player.getLookingAt(), mat, lookingAt); + player.setLookingAt(lookingAt); + + Vectors.release(rightVector); + Vectors.release(lookingAt); + Matrices.release(mat); } private void onWheelScroll(WheelScrollEvent event) { From b1666fa4b9a5d3be01bd229c7af31887c5ca2fc8 Mon Sep 17 00:00:00 2001 From: OLEGSHA Date: Sun, 31 Jan 2021 23:34:24 +0300 Subject: [PATCH 04/55] Fixed a bunch of issues with gravity and implemented gravity changes Also added DebugGraphics and made VectorUtil comply with the general Vec contract --- .../client/graphics/world/LayerWorld.java | 10 +- .../client/world/entity/NPedModel.java | 7 +- .../progressia/common/util/VectorUtil.java | 32 +++++-- .../progressia/common/world/GravityModel.java | 55 +++++++---- .../common/world/entity/EntityData.java | 79 ++++++++++++++- .../progressia/test/DebugGraphics.java | 95 +++++++++++++++++++ .../progressia/test/TestPlayerControls.java | 16 +++- .../progressia/test/gen/TestGravityModel.java | 9 +- 8 files changed, 263 insertions(+), 40 deletions(-) create mode 100644 src/main/java/ru/windcorp/progressia/test/DebugGraphics.java diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/world/LayerWorld.java b/src/main/java/ru/windcorp/progressia/client/graphics/world/LayerWorld.java index a8de633..c58b806 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/world/LayerWorld.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/world/LayerWorld.java @@ -42,6 +42,7 @@ import ru.windcorp.progressia.common.collision.Collideable; import ru.windcorp.progressia.common.collision.colliders.Collider; import ru.windcorp.progressia.common.util.FloatMathUtil; import ru.windcorp.progressia.common.util.Vectors; +import ru.windcorp.progressia.common.world.GravityModel; import ru.windcorp.progressia.common.world.entity.EntityData; import ru.windcorp.progressia.test.CollisionModelRenderer; import ru.windcorp.progressia.test.TestPlayerControls; @@ -199,12 +200,19 @@ public class LayerWorld extends Layer { } private void tmp_applyGravity(EntityData entity, float tickLength) { + GravityModel gm = ClientState.getInstance().getWorld().getData().getGravityModel(); + + Vec3 upVector = Vectors.grab3(); + gm.getUp(entity.getPosition(), upVector); + entity.changeUpVector(upVector); + Vectors.release(upVector); + if (ClientState.getInstance().getLocalPlayer().getEntity() == entity && tmp_testControls.isFlying()) { return; } Vec3 gravitationalAcceleration = Vectors.grab3(); - ClientState.getInstance().getWorld().getData().getGravityModel().getGravity(entity.getPosition(), gravitationalAcceleration); + gm.getGravity(entity.getPosition(), gravitationalAcceleration); gravitationalAcceleration.mul(tickLength); entity.getVelocity().add(gravitationalAcceleration); diff --git a/src/main/java/ru/windcorp/progressia/client/world/entity/NPedModel.java b/src/main/java/ru/windcorp/progressia/client/world/entity/NPedModel.java index ecefd06..12a078e 100644 --- a/src/main/java/ru/windcorp/progressia/client/world/entity/NPedModel.java +++ b/src/main/java/ru/windcorp/progressia/client/world/entity/NPedModel.java @@ -231,9 +231,9 @@ public abstract class NPedModel extends EntityRenderable { s.set(u).cross(f); bodyTransform.identity().set( - +f.x, -s.x, +u.x, 0, - +f.y, -s.y, +u.y, 0, - +f.z, -s.z, +u.z, 0, + +f.x, +f.y, +f.z, 0, + -s.x, -s.y, -s.z, 0, + +u.x, +u.y, +u.z, 0, 0, 0, 0, 1 ); @@ -253,7 +253,6 @@ public abstract class NPedModel extends EntityRenderable { computeVelocityParameter(); - // TODO switch to world time walkingParameter += velocity * GraphicsInterface.getFrameLength() * 1000; rotateBodyWithMovement(horizontal); diff --git a/src/main/java/ru/windcorp/progressia/common/util/VectorUtil.java b/src/main/java/ru/windcorp/progressia/common/util/VectorUtil.java index 1de0848..1d86fce 100644 --- a/src/main/java/ru/windcorp/progressia/common/util/VectorUtil.java +++ b/src/main/java/ru/windcorp/progressia/common/util/VectorUtil.java @@ -126,7 +126,11 @@ public class VectorUtil { iterateCuboidAround(center.x, center.y, center.z, diameter, action); } - public static void applyMat4(Vec3 in, Mat4 mat, Vec3 out) { + public static Vec3 applyMat4(Vec3 in, Mat4 mat, Vec3 out) { + if (out == null) { + out = new Vec3(); + } + Vec4 vec4 = Vectors.grab4(); vec4.set(in, 1f); @@ -134,23 +138,31 @@ public class VectorUtil { out.set(vec4.x, vec4.y, vec4.z); Vectors.release(vec4); + + return out; } - public static void applyMat4(Vec3 inOut, Mat4 mat) { - applyMat4(inOut, mat, inOut); + public static Vec3 applyMat4(Vec3 inOut, Mat4 mat) { + return applyMat4(inOut, mat, inOut); } - public static void rotate(Vec3 in, Vec3 axis, float angle, Vec3 out) { + public static Vec3 rotate(Vec3 in, Vec3 axis, float angle, Vec3 out) { + if (out == null) { + out = new Vec3(); + } + Mat3 mat = Matrices.grab3(); mat.identity().rotate(angle, axis); mat.mul(in, out); Matrices.release(mat); + + return out; } - public static void rotate(Vec3 inOut, Vec3 axis, float angle) { - rotate(inOut, axis, angle, inOut); + public static Vec3 rotate(Vec3 inOut, Vec3 axis, float angle) { + return rotate(inOut, axis, angle, inOut); } public static double getAngle(Vec3 from, Vec3 to, Vec3 normal) { @@ -212,6 +224,10 @@ public class VectorUtil { float kb, Vec3 output ) { + if (output == null) { + output = new Vec3(); + } + output.set( va.x * ka + vb.x * kb, va.y * ka + vb.y * kb, @@ -229,6 +245,10 @@ public class VectorUtil { float kc, Vec3 output ) { + if (output == null) { + output = new Vec3(); + } + output.set( va.x * ka + vb.x * kb + vc.x * kc, va.y * ka + vb.y * kb + vc.y * kc, 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 f17c9b6..eecfc3b 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/GravityModel.java +++ b/src/main/java/ru/windcorp/progressia/common/world/GravityModel.java @@ -24,59 +24,72 @@ import ru.windcorp.progressia.common.util.crash.CrashReports; import ru.windcorp.progressia.common.util.namespaces.Namespaced; /** - * Gravity model specifies the gravitational acceleration field. A gravity model may be queried for the vector of gravitational acceleration that should affect an object. This vector is, generally speaking, a function of space: gravity in two different locations may vary. Gravity may also be a zero vector. + * Gravity model specifies the gravitational acceleration field. A gravity model + * may be queried for the vector of gravitational acceleration that should + * affect an object. This vector is, generally speaking, a function of space: + * gravity in two different locations may vary. Gravity may also be a zero + * vector. * * @author javapony */ public abstract class GravityModel extends Namespaced { - + public GravityModel(String id) { super(id); } /** - * Computes the vector of gravitational acceleration at the provided location. + * Computes the vector of gravitational acceleration at the provided + * location. * - * @param pos the position to compute gravity at - * @param output a {@link Vec3} where the result is stored. May be {@code null}. - * - * @return the vector of gravitational acceleration. The returned object will match {@code output} parameter is it is non-null. + * @param pos the position to compute gravity at + * @param output a {@link Vec3} where the result is stored. May be + * {@code null}. + * @return the vector of gravitational acceleration. The returned object + * will match {@code output} parameter is it is non-null. */ public Vec3 getGravity(Vec3 pos, Vec3 output) { Objects.requireNonNull(pos, "pos"); - + if (output == null) { output = new Vec3(); } - + try { doGetGravity(pos, output); } catch (Exception e) { throw CrashReports.report(e, "%s failed to compute gravity at (%d; %d; %d)", this, pos.x, pos.y, pos.z); } - + return output; } - + /** - * Computes the up direction at the provided location. Up vector is defined as the normalized gravitational acceleration vector or {@code (0; 0; 0)} if there is no gravity. + * Computes the up direction at the provided location. Up vector is defined + * as the additive inverse of the normalized gravitational acceleration + * vector or {@code (0; 0; 0)} if there is no gravity. * - * @param pos the position to compute up vector at - * @param output a {@link Vec3} where the result is stored. May be {@code null}. - * - * @return the up vector. The returned object will match {@code output} parameter is it is non-null. + * @param pos the position to compute up vector at + * @param output a {@link Vec3} where the result is stored. May be + * {@code null}. + * @return the up vector. The returned object will match {@code output} + * parameter is it is non-null. */ public Vec3 getUp(Vec3 pos, Vec3 output) { output = getGravity(pos, output); - if (output.any()) output.normalize(); + if (output.any()) + output.normalize().negate(); return output; } - + /** - * Computes the gravitational acceleration vector at the provided location. Actual computation of gravity is delegated to this method by the other methods in this class. + * Computes the gravitational acceleration vector at the provided location. + * Actual computation of gravity is delegated to this method by the other + * methods in this class. * - * @param pos the position to compute gravity at - * @param output a {@link Vec3} where the result must be stored. Never {@code null}. + * @param pos the position to compute gravity at + * @param output a {@link Vec3} where the result must be stored. Never + * {@code null}. */ protected abstract void doGetGravity(Vec3 pos, Vec3 output); diff --git a/src/main/java/ru/windcorp/progressia/common/world/entity/EntityData.java b/src/main/java/ru/windcorp/progressia/common/world/entity/EntityData.java index 2dcdf3e..344439a 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/entity/EntityData.java +++ b/src/main/java/ru/windcorp/progressia/common/world/entity/EntityData.java @@ -21,13 +21,16 @@ package ru.windcorp.progressia.common.world.entity; import java.io.DataInput; import java.io.DataOutput; import java.io.IOException; +import java.util.Objects; +import glm.mat._3.Mat3; import glm.vec._3.Vec3; import ru.windcorp.jputil.chars.StringUtil; import ru.windcorp.progressia.common.collision.Collideable; import ru.windcorp.progressia.common.collision.CollisionModel; import ru.windcorp.progressia.common.state.IOContext; import ru.windcorp.progressia.common.state.StatefulObject; +import ru.windcorp.progressia.common.util.Matrices; import ru.windcorp.progressia.common.world.generic.GenericEntity; public class EntityData extends StatefulObject implements Collideable, GenericEntity { @@ -146,6 +149,8 @@ public class EntityData extends StatefulObject implements Collideable, GenericEn this.lookingAt.set(lookingAt); } else if (lengthSq == 0) { throw new IllegalArgumentException("lookingAt is zero-length"); + } else if (!Float.isFinite(lengthSq)) { + throw new IllegalArgumentException("lookingAt is not finite: " + lookingAt); } else { float length = (float) Math.sqrt(lengthSq); this.lookingAt.set( @@ -172,6 +177,8 @@ public class EntityData extends StatefulObject implements Collideable, GenericEn this.upVector.set(upVector); } else if (lengthSq == 0) { throw new IllegalArgumentException("upVector is zero-length"); + } else if (!Float.isFinite(lengthSq)) { + throw new IllegalArgumentException("upVector is not finite: " + upVector); } else { float length = (float) Math.sqrt(lengthSq); this.upVector.set( @@ -216,8 +223,76 @@ public class EntityData extends StatefulObject implements Collideable, GenericEn * @see #setLookingAt(Vec3) */ public void changeUpVector(Vec3 newUpVector) { - // TODO - this.upVector.set(newUpVector); + Objects.requireNonNull(newUpVector, "newUpVector"); + + Vec3 u0 = upVector; + Vec3 u1 = newUpVector; + + if (u1.x == 0 && u1.y == 0 && u1.z == 0) { + // Entering weightlessness, not changing anything + return; + } + + if (u0.x == u1.x && u0.y == u1.y && u0.z == u1.z) { + // Nothing changed + return; + } + + if (u0.x == -u1.x && u0.y == -u1.y && u0.z == -u1.z) { + // Welp, don't do anything stupid then + upVector.set(newUpVector); + return; + } + + float u1LengthSq = u1.x*u1.x + u1.y*u1.y + u1.z*u1.z; + float u1Length = 1; + + if (!Float.isFinite(u1LengthSq)) { + throw new IllegalArgumentException("newUpVector is not finite: " + newUpVector); + } else if (u1LengthSq != 1) { + u1Length = (float) Math.sqrt(u1LengthSq); + } + + // u0 and u1 are now both definitely two different usable vectors + + if (rotateLookingAtToMatchUpVectorRotation(u0, u1, u1Length, lookingAt)) { + return; + } + + upVector.set(newUpVector).div(u1Length); + } + + private static boolean rotateLookingAtToMatchUpVectorRotation(Vec3 u0, Vec3 u1, float u1Length, Vec3 lookingAt) { + // Determine rotation parameters + Vec3 axis = u0.cross_(u1); + float cos = u0.dot(u1) / u1Length; + float sin = axis.length() / u1Length; + + if (sin == 0) { + return true; + } + + axis.div(sin * u1Length); // normalize axis + + float x = axis.x; + float y = axis.y; + float z = axis.z; + + Mat3 matrix = Matrices.grab3(); + + // Don't format. @formatter:off + matrix.set( + cos + (1 - cos)*x*x, (1 - cos)*x*y - sin*z, (1 - cos)*x*z + sin*y, + (1 - cos)*y*x + sin*z, cos + (1 - cos)*y*y, (1 - cos)*y*z - sin*x, + (1 - cos)*z*x - sin*y, (1 - cos)*z*y + sin*x, cos + (1 - cos)*z*z + ); + // @formatter:on + + matrix.mul_(lookingAt); // bug in jglm, .mul() and .mul_() are swapped + + Matrices.release(matrix); + + return false; } @Override diff --git a/src/main/java/ru/windcorp/progressia/test/DebugGraphics.java b/src/main/java/ru/windcorp/progressia/test/DebugGraphics.java new file mode 100644 index 0000000..859132f --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/test/DebugGraphics.java @@ -0,0 +1,95 @@ +/* + * 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; + +import glm.mat._4.Mat4; +import glm.vec._3.Vec3; +import glm.vec._4.Vec4; +import ru.windcorp.progressia.client.graphics.Colors; +import ru.windcorp.progressia.client.graphics.model.Renderable; +import ru.windcorp.progressia.client.graphics.model.ShapeRenderHelper; +import ru.windcorp.progressia.client.graphics.model.Shapes; +import ru.windcorp.progressia.client.graphics.model.StaticModel; +import ru.windcorp.progressia.client.graphics.texture.Texture; +import ru.windcorp.progressia.client.graphics.world.WorldRenderProgram; +import ru.windcorp.progressia.common.util.Vectors; + +public class DebugGraphics { + + private static final float TAIL_THICKNESS = 0.03f; + private static final float HEAD_SIZE = 0.1f; + + private static final Renderable THE_VECTOR = StaticModel.builder().addPart( + new Shapes.PppBuilder(WorldRenderProgram.getDefault(), (Texture) null) + .setSize(1.0f, TAIL_THICKNESS, TAIL_THICKNESS) + .setOrigin(0, -TAIL_THICKNESS / 2, -TAIL_THICKNESS / 2) + .create() + ).addPart( + new Shapes.PppBuilder(WorldRenderProgram.getDefault(), (Texture) null) + .setSize(HEAD_SIZE, HEAD_SIZE, HEAD_SIZE) + .setOrigin((1 - HEAD_SIZE / 2), -HEAD_SIZE / 2, -HEAD_SIZE / 2) + .create() + ).build(); + + public static void drawVector(Vec3 vector, Vec4 color, Vec3 origin, float scale, ShapeRenderHelper renderer) { + float length = vector.length(); + if (length == 0) return; + + if (scale == 0) scale = 1 / length; + + Mat4 mat = renderer.pushTransform(); + + mat.translate(origin); + + Vec3 somePerpendicular = new Vec3(); + + if (Math.abs(vector.z) > (1 - 1e-4f) * length) { + somePerpendicular.set(1, 0, 0); + } else { + somePerpendicular.set(0, 0, 1); + } + + Vec3 f = vector; + Vec3 s = somePerpendicular.cross_(f).normalize(); + Vec3 u = somePerpendicular.set(f).cross(s).normalize(); + + // @formatter:off + mat.mul(new Mat4( + +f.x * scale, +f.y * scale, +f.z * scale, 0, + -s.x, -s.y, -s.z, 0, + +u.x, +u.y, +u.z, 0, + 0, 0, 0, 1 + )); + // @formatter:on + + renderer.pushColorMultiplier().mul(color); + THE_VECTOR.render(renderer); + renderer.popColorMultiplier(); + + renderer.popTransform(); + } + + public static void drawVector(Vec3 vector, ShapeRenderHelper renderer) { + drawVector(vector, Colors.GRAY_A, Vectors.ZERO_3, 1, renderer); + } + + public static void drawDirection(Vec3 vector, ShapeRenderHelper renderer) { + drawVector(vector, Colors.GRAY_A, Vectors.ZERO_3, 0, renderer); + } + +} diff --git a/src/main/java/ru/windcorp/progressia/test/TestPlayerControls.java b/src/main/java/ru/windcorp/progressia/test/TestPlayerControls.java index 1254399..541d909 100644 --- a/src/main/java/ru/windcorp/progressia/test/TestPlayerControls.java +++ b/src/main/java/ru/windcorp/progressia/test/TestPlayerControls.java @@ -116,7 +116,7 @@ public class TestPlayerControls { desiredVelocity.normalize(); } desiredVelocity.z = movementUp; - movementTransform.mul_(desiredVelocity); // bug in jglm, .mul() and mul_() are + movementTransform.mul_(desiredVelocity); // bug in jglm, .mul() and .mul_() are // swapped desiredVelocity.mul(speed); @@ -154,9 +154,9 @@ public class TestPlayerControls { Vec3 s = u.cross_(f); return mat.set( - +f.x, -s.x, +u.x, - +f.y, -s.y, +u.y, - +f.z, -s.z, +u.z + +f.x, +f.y, +f.z, + -s.x, -s.y, -s.z, + +u.x, +u.y, +u.z ); } @@ -282,7 +282,13 @@ public class TestPlayerControls { return; } - getEntity().getVelocity().add(0, 0, JUMP_VELOCITY); + Vec3 up = getEntity().getUpVector(); + + getEntity().getVelocity().add( + up.x * JUMP_VELOCITY, + up.y * JUMP_VELOCITY, + up.z * JUMP_VELOCITY + ); } private void handleShift(int multiplier) { 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 ebcf715..39e889e 100644 --- a/src/main/java/ru/windcorp/progressia/test/gen/TestGravityModel.java +++ b/src/main/java/ru/windcorp/progressia/test/gen/TestGravityModel.java @@ -28,7 +28,14 @@ public class TestGravityModel extends GravityModel { @Override protected void doGetGravity(Vec3 pos, Vec3 output) { - output.set(0, 0, -9.8); + output.set(pos); + + if (output.length() < 10) { + output.set(0); + return; + } + + output.normalize().mul(-9.8f); } } From 848178b3437d6fcac260987d97e0976edc869b22 Mon Sep 17 00:00:00 2001 From: OLEGSHA Date: Mon, 1 Feb 2021 17:25:07 +0300 Subject: [PATCH 05/55] Renamed BlockFace and BlockRelation to AbsFace and AbsRelation - Renamed BlockFace to AbsFace - Renamed BlockRelation to AbsRelation - Renamed AbsFace constants using the following scheme: POS_X, NEG_Y, etc. --- .../graphics/model/BlockFaceVectors.java | 72 ++++++++--------- .../client/graphics/model/Faces.java | 4 +- .../client/graphics/model/Shapes.java | 16 ++-- .../graphics/texture/ComplexTexture.java | 8 +- .../client/graphics/world/Selection.java | 6 +- .../progressia/client/world/ChunkRender.java | 8 +- .../client/world/ChunkRenderModel.java | 10 +-- .../client/world/ChunkUpdateListener.java | 6 +- .../world/block/BlockRenderOpaqueCube.java | 28 +++---- .../world/block/BlockRenderTexturedCube.java | 42 +++++----- .../block/BlockRenderTransparentCube.java | 28 +++---- .../world/cro/ChunkRenderOptimizer.java | 6 +- .../cro/ChunkRenderOptimizerSurface.java | 34 ++++---- .../client/world/tile/TileRender.java | 6 +- .../client/world/tile/TileRenderGrass.java | 10 +-- .../client/world/tile/TileRenderNone.java | 4 +- .../world/tile/TileRenderOpaqueSurface.java | 4 +- .../client/world/tile/TileRenderSurface.java | 12 +-- .../tile/TileRenderTransparentSurface.java | 4 +- .../progressia/common/collision/AABBoid.java | 4 +- .../common/collision/TranslatedAABB.java | 4 +- .../collision/colliders/AABBoidCollider.java | 4 +- .../progressia/common/world/BlockRay.java | 14 ++-- .../progressia/common/world/ChunkData.java | 46 +++++------ .../common/world/ChunkDataListener.java | 4 +- .../block/{BlockFace.java => AbsFace.java} | 81 ++++++++++--------- .../{BlockRelation.java => AbsRelation.java} | 6 +- .../common/world/generic/GenericChunk.java | 8 +- .../world/generic/GenericTileStack.java | 4 +- .../common/world/generic/GenericWorld.java | 10 +-- .../common/world/tile/PacketAddTile.java | 4 +- .../common/world/tile/PacketAffectTile.java | 10 +-- .../common/world/tile/PacketRemoveTile.java | 4 +- .../progressia/server/world/ChunkLogic.java | 8 +- .../server/world/TickAndUpdateUtil.java | 10 +-- .../server/world/TickContextMutable.java | 16 ++-- .../server/world/UpdateTriggerer.java | 4 +- .../server/world/block/BlockLogic.java | 6 +- .../server/world/block/BlockTickContext.java | 12 +-- .../world/tasks/BlockTriggeredUpdate.java | 4 +- .../server/world/tasks/TickChunk.java | 6 +- .../world/tasks/TileTriggeredUpdate.java | 6 +- .../server/world/tasks/WorldAccessor.java | 10 +-- .../server/world/tile/TSTickContext.java | 4 +- .../server/world/tile/TileLogic.java | 4 +- .../progressia/test/ControlPlaceTileData.java | 8 +- .../progressia/test/TestBlockLogicAir.java | 4 +- .../progressia/test/TestBlockLogicGlass.java | 4 +- .../progressia/test/TestChunkCodec.java | 4 +- .../windcorp/progressia/test/TestContent.java | 2 +- .../test/TestEntityRenderJavapony.java | 12 +-- .../progressia/test/TestTileLogicGrass.java | 10 +-- .../test/gen/TestWorldGenerator.java | 18 ++--- 53 files changed, 333 insertions(+), 330 deletions(-) rename src/main/java/ru/windcorp/progressia/common/world/block/{BlockFace.java => AbsFace.java} (58%) rename src/main/java/ru/windcorp/progressia/common/world/block/{BlockRelation.java => AbsRelation.java} (95%) diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/model/BlockFaceVectors.java b/src/main/java/ru/windcorp/progressia/client/graphics/model/BlockFaceVectors.java index 3b929c0..0b07363 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/model/BlockFaceVectors.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/model/BlockFaceVectors.java @@ -18,23 +18,23 @@ package ru.windcorp.progressia.client.graphics.model; -import static ru.windcorp.progressia.common.world.block.BlockFace.*; +import static ru.windcorp.progressia.common.world.block.AbsFace.*; import com.google.common.collect.ImmutableMap; import glm.vec._3.Vec3; -import ru.windcorp.progressia.common.world.block.BlockFace; +import ru.windcorp.progressia.common.world.block.AbsFace; class BlockFaceVectors { private static BlockFaceVectors createInner(BlockFaceVectors outer) { - ImmutableMap.Builder originBuilder = ImmutableMap.builder(); + ImmutableMap.Builder originBuilder = ImmutableMap.builder(); - ImmutableMap.Builder widthBuilder = ImmutableMap.builder(); + ImmutableMap.Builder widthBuilder = ImmutableMap.builder(); - ImmutableMap.Builder heightBuilder = ImmutableMap.builder(); + ImmutableMap.Builder heightBuilder = ImmutableMap.builder(); - for (BlockFace face : getFaces()) { + for (AbsFace face : getFaces()) { Vec3 width = outer.getWidth(face); Vec3 height = outer.getHeight(face); @@ -59,36 +59,36 @@ class BlockFaceVectors { static { OUTER = new BlockFaceVectors( - ImmutableMap.builder() + ImmutableMap.builder() - .put(TOP, new Vec3(-0.5f, +0.5f, +0.5f)) - .put(BOTTOM, new Vec3(-0.5f, -0.5f, -0.5f)) - .put(NORTH, new Vec3(+0.5f, -0.5f, -0.5f)) - .put(SOUTH, new Vec3(-0.5f, +0.5f, -0.5f)) - .put(WEST, new Vec3(+0.5f, +0.5f, -0.5f)) - .put(EAST, new Vec3(-0.5f, -0.5f, -0.5f)) + .put(POS_Z, new Vec3(-0.5f, +0.5f, +0.5f)) + .put(NEG_Z, new Vec3(-0.5f, -0.5f, -0.5f)) + .put(POS_X, new Vec3(+0.5f, -0.5f, -0.5f)) + .put(NEG_X, new Vec3(-0.5f, +0.5f, -0.5f)) + .put(POS_Y, new Vec3(+0.5f, +0.5f, -0.5f)) + .put(NEG_Y, new Vec3(-0.5f, -0.5f, -0.5f)) .build(), - ImmutableMap.builder() + ImmutableMap.builder() - .put(TOP, new Vec3(0, -1, 0)) - .put(BOTTOM, new Vec3(0, +1, 0)) - .put(NORTH, new Vec3(0, +1, 0)) - .put(SOUTH, new Vec3(0, -1, 0)) - .put(WEST, new Vec3(-1, 0, 0)) - .put(EAST, new Vec3(+1, 0, 0)) + .put(POS_Z, new Vec3(0, -1, 0)) + .put(NEG_Z, new Vec3(0, +1, 0)) + .put(POS_X, new Vec3(0, +1, 0)) + .put(NEG_X, new Vec3(0, -1, 0)) + .put(POS_Y, new Vec3(-1, 0, 0)) + .put(NEG_Y, new Vec3(+1, 0, 0)) .build(), - ImmutableMap.builder() + ImmutableMap.builder() - .put(TOP, new Vec3(+1, 0, 0)) - .put(BOTTOM, new Vec3(+1, 0, 0)) - .put(NORTH, new Vec3(0, 0, +1)) - .put(SOUTH, new Vec3(0, 0, +1)) - .put(WEST, new Vec3(0, 0, +1)) - .put(EAST, new Vec3(0, 0, +1)) + .put(POS_Z, new Vec3(+1, 0, 0)) + .put(NEG_Z, new Vec3(+1, 0, 0)) + .put(POS_X, new Vec3(0, 0, +1)) + .put(NEG_X, new Vec3(0, 0, +1)) + .put(POS_Y, new Vec3(0, 0, +1)) + .put(NEG_Y, new Vec3(0, 0, +1)) .build() ); @@ -100,29 +100,29 @@ class BlockFaceVectors { return inner ? INNER : OUTER; } - private final ImmutableMap origins; - private final ImmutableMap widths; - private final ImmutableMap heights; + private final ImmutableMap origins; + private final ImmutableMap widths; + private final ImmutableMap heights; public BlockFaceVectors( - ImmutableMap origins, - ImmutableMap widths, - ImmutableMap heights + ImmutableMap origins, + ImmutableMap widths, + ImmutableMap heights ) { this.origins = origins; this.widths = widths; this.heights = heights; } - public Vec3 getOrigin(BlockFace face) { + public Vec3 getOrigin(AbsFace face) { return origins.get(face); } - public Vec3 getWidth(BlockFace face) { + public Vec3 getWidth(AbsFace face) { return widths.get(face); } - public Vec3 getHeight(BlockFace face) { + public Vec3 getHeight(AbsFace face) { return heights.get(face); } } diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/model/Faces.java b/src/main/java/ru/windcorp/progressia/client/graphics/model/Faces.java index d1e9c07..ff0f08f 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/model/Faces.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/model/Faces.java @@ -25,7 +25,7 @@ import glm.vec._3.Vec3; import glm.vec._4.Vec4; import ru.windcorp.progressia.client.graphics.model.ShapeRenderProgram.VertexBuilder; import ru.windcorp.progressia.client.graphics.texture.Texture; -import ru.windcorp.progressia.common.world.block.BlockFace; +import ru.windcorp.progressia.common.world.block.AbsFace; public class Faces { @@ -94,7 +94,7 @@ public class Faces { Texture texture, Vec4 colorMultiplier, Vec3 blockCenter, - BlockFace face, + AbsFace face, boolean inner ) { BlockFaceVectors vectors = BlockFaceVectors.get(inner); diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/model/Shapes.java b/src/main/java/ru/windcorp/progressia/client/graphics/model/Shapes.java index 7ddd5d6..8e30d14 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/model/Shapes.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/model/Shapes.java @@ -24,7 +24,7 @@ import glm.vec._3.Vec3; import glm.vec._4.Vec4; import ru.windcorp.progressia.client.graphics.backend.Usage; import ru.windcorp.progressia.client.graphics.texture.Texture; -import ru.windcorp.progressia.common.world.block.BlockFace; +import ru.windcorp.progressia.common.world.block.AbsFace; public class Shapes { @@ -165,16 +165,16 @@ public class Shapes { public PppBuilder( ShapeRenderProgram program, - Map textureMap + Map textureMap ) { this( program, - textureMap.get(BlockFace.TOP), - textureMap.get(BlockFace.BOTTOM), - textureMap.get(BlockFace.NORTH), - textureMap.get(BlockFace.SOUTH), - textureMap.get(BlockFace.EAST), - textureMap.get(BlockFace.WEST) + textureMap.get(AbsFace.POS_Z), + textureMap.get(AbsFace.NEG_Z), + textureMap.get(AbsFace.POS_X), + textureMap.get(AbsFace.NEG_X), + textureMap.get(AbsFace.NEG_Y), + textureMap.get(AbsFace.POS_Y) ); } diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/texture/ComplexTexture.java b/src/main/java/ru/windcorp/progressia/client/graphics/texture/ComplexTexture.java index a4f2881..40fefbd 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/texture/ComplexTexture.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/texture/ComplexTexture.java @@ -21,7 +21,7 @@ package ru.windcorp.progressia.client.graphics.texture; import java.util.Map; import glm.vec._2.Vec2; -import ru.windcorp.progressia.common.world.block.BlockFace; +import ru.windcorp.progressia.common.world.block.AbsFace; public class ComplexTexture { @@ -54,14 +54,14 @@ public class ComplexTexture { ); } - public Map getCuboidTextures( + public Map getCuboidTextures( int x, int y, int width, int height, int depth ) { - return BlockFace.mapToFaces( + return AbsFace.mapToFaces( get( x + depth + width, y + height + depth, @@ -86,7 +86,7 @@ public class ComplexTexture { ); } - public Map getCuboidTextures( + public Map getCuboidTextures( int x, int y, int size diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/world/Selection.java b/src/main/java/ru/windcorp/progressia/client/graphics/world/Selection.java index e6cd57d..b4dc7dc 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/world/Selection.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/world/Selection.java @@ -23,13 +23,13 @@ import glm.vec._3.Vec3; import glm.vec._3.i.Vec3i; import ru.windcorp.progressia.client.world.WorldRender; import ru.windcorp.progressia.common.world.BlockRay; -import ru.windcorp.progressia.common.world.block.BlockFace; +import ru.windcorp.progressia.common.world.block.AbsFace; import ru.windcorp.progressia.common.world.entity.EntityData; public class Selection { private final Vec3i block = new Vec3i(); - private BlockFace surface = null; + private AbsFace surface = null; private final Vec2 pointOnSurface = new Vec2(0.5f, 0.5f); private final Vec3 point = new Vec3(); @@ -70,7 +70,7 @@ public class Selection { return exists ? point : null; } - public BlockFace getSurface() { + public AbsFace getSurface() { return exists ? surface : null; } diff --git a/src/main/java/ru/windcorp/progressia/client/world/ChunkRender.java b/src/main/java/ru/windcorp/progressia/client/world/ChunkRender.java index 21f6098..b746843 100644 --- a/src/main/java/ru/windcorp/progressia/client/world/ChunkRender.java +++ b/src/main/java/ru/windcorp/progressia/client/world/ChunkRender.java @@ -30,7 +30,7 @@ import ru.windcorp.progressia.client.world.tile.TileRender; import ru.windcorp.progressia.client.world.tile.TileRenderRegistry; import ru.windcorp.progressia.client.world.tile.TileRenderStack; import ru.windcorp.progressia.common.world.ChunkData; -import ru.windcorp.progressia.common.world.block.BlockFace; +import ru.windcorp.progressia.common.world.block.AbsFace; import ru.windcorp.progressia.common.world.generic.GenericChunk; import ru.windcorp.progressia.common.world.tile.TileDataStack; @@ -64,12 +64,12 @@ public class ChunkRender } @Override - public TileRenderStack getTiles(Vec3i blockInChunk, BlockFace face) { + public TileRenderStack getTiles(Vec3i blockInChunk, AbsFace face) { return getTileStackWrapper(getData().getTiles(blockInChunk, face)); } @Override - public boolean hasTiles(Vec3i blockInChunk, BlockFace face) { + public boolean hasTiles(Vec3i blockInChunk, AbsFace face) { return getData().hasTiles(blockInChunk, face); } @@ -119,7 +119,7 @@ public class ChunkRender } @Override - public BlockFace getFace() { + public AbsFace getFace() { return parent.getFace(); } diff --git a/src/main/java/ru/windcorp/progressia/client/world/ChunkRenderModel.java b/src/main/java/ru/windcorp/progressia/client/world/ChunkRenderModel.java index 9653abe..2b4ead7 100644 --- a/src/main/java/ru/windcorp/progressia/client/world/ChunkRenderModel.java +++ b/src/main/java/ru/windcorp/progressia/client/world/ChunkRenderModel.java @@ -36,7 +36,7 @@ import ru.windcorp.progressia.client.world.tile.TileRender; import ru.windcorp.progressia.client.world.tile.TileRenderNone; import ru.windcorp.progressia.client.world.tile.TileRenderStack; import ru.windcorp.progressia.common.world.ChunkData; -import ru.windcorp.progressia.common.world.block.BlockFace; +import ru.windcorp.progressia.common.world.block.AbsFace; public class ChunkRenderModel implements Renderable { @@ -99,7 +99,7 @@ public class ChunkRenderModel implements Renderable { private void processBlockAndTiles(Vec3i blockInChunk, Builder sink) { processBlock(blockInChunk, sink); - for (BlockFace face : BlockFace.getFaces()) { + for (AbsFace face : AbsFace.getFaces()) { processTileStack(blockInChunk, face, sink); } } @@ -127,7 +127,7 @@ public class ChunkRenderModel implements Renderable { } } - private void processTileStack(Vec3i blockInChunk, BlockFace face, Builder sink) { + private void processTileStack(Vec3i blockInChunk, AbsFace face, Builder sink) { TileRenderStack trs = chunk.getTilesOrNull(blockInChunk, face); if (trs == null || trs.isEmpty()) { @@ -137,7 +137,7 @@ public class ChunkRenderModel implements Renderable { trs.forEach(tile -> processTile(tile, blockInChunk, face, sink)); } - private void processTile(TileRender tile, Vec3i blockInChunk, BlockFace face, Builder sink) { + private void processTile(TileRender tile, Vec3i blockInChunk, AbsFace face, Builder sink) { if (tile instanceof TileRenderNone) { return; } @@ -152,7 +152,7 @@ public class ChunkRenderModel implements Renderable { processTileWithCROs(tile, blockInChunk, face); } - private void processTileWithCROs(TileRender tile, Vec3i blockInChunk, BlockFace face) { + private void processTileWithCROs(TileRender tile, Vec3i blockInChunk, AbsFace face) { for (ChunkRenderOptimizer optimizer : optimizers) { optimizer.addTile(tile, blockInChunk, face); } diff --git a/src/main/java/ru/windcorp/progressia/client/world/ChunkUpdateListener.java b/src/main/java/ru/windcorp/progressia/client/world/ChunkUpdateListener.java index 32a950f..9b873ee 100644 --- a/src/main/java/ru/windcorp/progressia/client/world/ChunkUpdateListener.java +++ b/src/main/java/ru/windcorp/progressia/client/world/ChunkUpdateListener.java @@ -22,7 +22,7 @@ import glm.vec._3.i.Vec3i; import ru.windcorp.progressia.common.world.ChunkData; import ru.windcorp.progressia.common.world.ChunkDataListener; import ru.windcorp.progressia.common.world.block.BlockData; -import ru.windcorp.progressia.common.world.block.BlockFace; +import ru.windcorp.progressia.common.world.block.AbsFace; import ru.windcorp.progressia.common.world.tile.TileData; class ChunkUpdateListener implements ChunkDataListener { @@ -41,7 +41,7 @@ class ChunkUpdateListener implements ChunkDataListener { @Override public void onChunkLoaded(ChunkData chunk) { Vec3i cursor = new Vec3i(); - for (BlockFace face : BlockFace.getFaces()) { + for (AbsFace face : AbsFace.getFaces()) { cursor.set(chunk.getX(), chunk.getY(), chunk.getZ()); cursor.add(face.getVector()); world.markChunkForUpdate(cursor); @@ -57,7 +57,7 @@ class ChunkUpdateListener implements ChunkDataListener { public void onChunkTilesChanged( ChunkData chunk, Vec3i blockInChunk, - BlockFace face, + AbsFace face, TileData tile, boolean wasAdded ) { diff --git a/src/main/java/ru/windcorp/progressia/client/world/block/BlockRenderOpaqueCube.java b/src/main/java/ru/windcorp/progressia/client/world/block/BlockRenderOpaqueCube.java index e4d8723..7913fa8 100644 --- a/src/main/java/ru/windcorp/progressia/client/world/block/BlockRenderOpaqueCube.java +++ b/src/main/java/ru/windcorp/progressia/client/world/block/BlockRenderOpaqueCube.java @@ -19,27 +19,27 @@ package ru.windcorp.progressia.client.world.block; import ru.windcorp.progressia.client.graphics.texture.Texture; -import ru.windcorp.progressia.common.world.block.BlockFace; +import ru.windcorp.progressia.common.world.block.AbsFace; public class BlockRenderOpaqueCube extends BlockRenderTexturedCube { public BlockRenderOpaqueCube( String id, - Texture topTexture, - Texture bottomTexture, - Texture northTexture, - Texture southTexture, - Texture eastTexture, - Texture westTexture + Texture posZTexture, + Texture negZTexture, + Texture posXTexture, + Texture negXTexture, + Texture negYTexture, + Texture posYTexture ) { super( id, - topTexture, - bottomTexture, - northTexture, - southTexture, - eastTexture, - westTexture + posZTexture, + negZTexture, + posXTexture, + negXTexture, + negYTexture, + posYTexture ); } @@ -56,7 +56,7 @@ public class BlockRenderOpaqueCube extends BlockRenderTexturedCube { } @Override - public boolean isOpaque(BlockFace face) { + public boolean isOpaque(AbsFace face) { return true; } diff --git a/src/main/java/ru/windcorp/progressia/client/world/block/BlockRenderTexturedCube.java b/src/main/java/ru/windcorp/progressia/client/world/block/BlockRenderTexturedCube.java index 1042a46..b1b41d5 100644 --- a/src/main/java/ru/windcorp/progressia/client/world/block/BlockRenderTexturedCube.java +++ b/src/main/java/ru/windcorp/progressia/client/world/block/BlockRenderTexturedCube.java @@ -18,7 +18,7 @@ package ru.windcorp.progressia.client.world.block; -import static ru.windcorp.progressia.common.world.block.BlockFace.*; +import static ru.windcorp.progressia.common.world.block.AbsFace.*; import java.util.HashMap; import java.util.Map; @@ -38,44 +38,44 @@ import ru.windcorp.progressia.client.graphics.world.WorldRenderProgram; import ru.windcorp.progressia.client.world.cro.ChunkRenderOptimizerSurface.BlockOptimizedSurface; import ru.windcorp.progressia.common.util.Vectors; import ru.windcorp.progressia.common.world.ChunkData; -import ru.windcorp.progressia.common.world.block.BlockFace; +import ru.windcorp.progressia.common.world.block.AbsFace; public abstract class BlockRenderTexturedCube extends BlockRender implements BlockOptimizedSurface { - private final Map textures = new HashMap<>(); + private final Map textures = new HashMap<>(); public BlockRenderTexturedCube( String id, - Texture topTexture, - Texture bottomTexture, - Texture northTexture, - Texture southTexture, - Texture eastTexture, - Texture westTexture + Texture posZTexture, + Texture negZTexture, + Texture posXTexture, + Texture negXTexture, + Texture negYTexture, + Texture posYTexture ) { super(id); - textures.put(TOP, topTexture); - textures.put(BOTTOM, bottomTexture); - textures.put(NORTH, northTexture); - textures.put(SOUTH, southTexture); - textures.put(EAST, eastTexture); - textures.put(WEST, westTexture); + textures.put(POS_Z, posZTexture); + textures.put(NEG_Z, negZTexture); + textures.put(POS_X, posXTexture); + textures.put(NEG_X, negXTexture); + textures.put(NEG_Y, negYTexture); + textures.put(POS_Y, posYTexture); } - public Texture getTexture(BlockFace blockFace) { + public Texture getTexture(AbsFace blockFace) { return textures.get(blockFace); } - public Vec4 getColorMultiplier(BlockFace blockFace) { + public Vec4 getColorMultiplier(AbsFace blockFace) { return Colors.WHITE; } @Override public final void getFaces( - ChunkData chunk, Vec3i blockInChunk, BlockFace blockFace, + ChunkData chunk, Vec3i blockInChunk, AbsFace blockFace, boolean inner, Consumer output, Vec3 offset @@ -84,7 +84,7 @@ public abstract class BlockRenderTexturedCube } private Face createFace( - ChunkData chunk, Vec3i blockInChunk, BlockFace blockFace, + ChunkData chunk, Vec3i blockInChunk, AbsFace blockFace, boolean inner, Vec3 offset ) { @@ -105,12 +105,12 @@ public abstract class BlockRenderTexturedCube Face[] faces = new Face[BLOCK_FACE_COUNT + (opaque ? BLOCK_FACE_COUNT : 0)]; for (int i = 0; i < BLOCK_FACE_COUNT; ++i) { - faces[i] = createFace(chunk, blockInChunk, BlockFace.getFaces().get(i), false, Vectors.ZERO_3); + faces[i] = createFace(chunk, blockInChunk, AbsFace.getFaces().get(i), false, Vectors.ZERO_3); } if (!opaque) { for (int i = 0; i < BLOCK_FACE_COUNT; ++i) { - faces[i + BLOCK_FACE_COUNT] = createFace(chunk, blockInChunk, BlockFace.getFaces().get(i), true, Vectors.ZERO_3); + faces[i + BLOCK_FACE_COUNT] = createFace(chunk, blockInChunk, AbsFace.getFaces().get(i), true, Vectors.ZERO_3); } } diff --git a/src/main/java/ru/windcorp/progressia/client/world/block/BlockRenderTransparentCube.java b/src/main/java/ru/windcorp/progressia/client/world/block/BlockRenderTransparentCube.java index 7f3df03..424e4f0 100644 --- a/src/main/java/ru/windcorp/progressia/client/world/block/BlockRenderTransparentCube.java +++ b/src/main/java/ru/windcorp/progressia/client/world/block/BlockRenderTransparentCube.java @@ -19,27 +19,27 @@ package ru.windcorp.progressia.client.world.block; import ru.windcorp.progressia.client.graphics.texture.Texture; -import ru.windcorp.progressia.common.world.block.BlockFace; +import ru.windcorp.progressia.common.world.block.AbsFace; public class BlockRenderTransparentCube extends BlockRenderTexturedCube { public BlockRenderTransparentCube( String id, - Texture topTexture, - Texture bottomTexture, - Texture northTexture, - Texture southTexture, - Texture eastTexture, - Texture westTexture + Texture posZTexture, + Texture negZTexture, + Texture posXTexture, + Texture negXTexture, + Texture negYTexture, + Texture posYTexture ) { super( id, - topTexture, - bottomTexture, - northTexture, - southTexture, - eastTexture, - westTexture + posZTexture, + negZTexture, + posXTexture, + negXTexture, + negYTexture, + posYTexture ); } @@ -56,7 +56,7 @@ public class BlockRenderTransparentCube extends BlockRenderTexturedCube { } @Override - public boolean isOpaque(BlockFace face) { + public boolean isOpaque(AbsFace face) { return false; } diff --git a/src/main/java/ru/windcorp/progressia/client/world/cro/ChunkRenderOptimizer.java b/src/main/java/ru/windcorp/progressia/client/world/cro/ChunkRenderOptimizer.java index b684c6a..a42aa6f 100644 --- a/src/main/java/ru/windcorp/progressia/client/world/cro/ChunkRenderOptimizer.java +++ b/src/main/java/ru/windcorp/progressia/client/world/cro/ChunkRenderOptimizer.java @@ -24,7 +24,7 @@ import ru.windcorp.progressia.client.world.ChunkRender; import ru.windcorp.progressia.client.world.block.BlockRender; import ru.windcorp.progressia.client.world.tile.TileRender; import ru.windcorp.progressia.common.util.namespaces.Namespaced; -import ru.windcorp.progressia.common.world.block.BlockFace; +import ru.windcorp.progressia.common.world.block.AbsFace; /** * Chunk render optimizer (CRO) is an object that produces optimized models for @@ -44,7 +44,7 @@ import ru.windcorp.progressia.common.world.block.BlockFace; * instance. *

  • {@link #startRender()} is invoked. The CRO must reset its state.
  • *
  • {@link #addBlock(BlockRender, Vec3i)} and - * {@link #addTile(TileRender, Vec3i, BlockFace)} are invoked for each block and + * {@link #addTile(TileRender, Vec3i, AbsFace)} are invoked for each block and * tile that this CRO should optimize. {@code addTile} specifies tiles in order * of ascension within a tile stack.
  • *
  • {@link #endRender()} is invoked. The CRO may perform any pending @@ -116,7 +116,7 @@ public abstract class ChunkRenderOptimizer extends Namespaced { * @param blockInChunk the position of the block that the tile belongs to * @param blockFace the face that the tile belongs to */ - public abstract void addTile(TileRender tile, Vec3i blockInChunk, BlockFace blockFace); + public abstract void addTile(TileRender tile, Vec3i blockInChunk, AbsFace blockFace); /** * Requests that the CRO assembles and outputs its model. This method may diff --git a/src/main/java/ru/windcorp/progressia/client/world/cro/ChunkRenderOptimizerSurface.java b/src/main/java/ru/windcorp/progressia/client/world/cro/ChunkRenderOptimizerSurface.java index 488938e..fc0bd5c 100644 --- a/src/main/java/ru/windcorp/progressia/client/world/cro/ChunkRenderOptimizerSurface.java +++ b/src/main/java/ru/windcorp/progressia/client/world/cro/ChunkRenderOptimizerSurface.java @@ -19,7 +19,7 @@ package ru.windcorp.progressia.client.world.cro; import static ru.windcorp.progressia.common.world.ChunkData.BLOCKS_PER_CHUNK; -import static ru.windcorp.progressia.common.world.block.BlockFace.BLOCK_FACE_COUNT; +import static ru.windcorp.progressia.common.world.block.AbsFace.BLOCK_FACE_COUNT; import static ru.windcorp.progressia.common.world.generic.GenericTileStack.TILES_PER_FACE; import java.util.ArrayList; @@ -38,7 +38,7 @@ import ru.windcorp.progressia.client.world.block.BlockRender; import ru.windcorp.progressia.client.world.tile.TileRender; import ru.windcorp.progressia.common.util.Vectors; import ru.windcorp.progressia.common.world.ChunkData; -import ru.windcorp.progressia.common.world.block.BlockFace; +import ru.windcorp.progressia.common.world.block.AbsFace; public class ChunkRenderOptimizerSurface extends ChunkRenderOptimizer { @@ -69,7 +69,7 @@ public class ChunkRenderOptimizerSurface extends ChunkRenderOptimizer { void getFaces( ChunkData chunk, Vec3i blockInChunk, - BlockFace blockFace, + AbsFace blockFace, boolean inner, Consumer output, Vec3 offset /* kostyl 156% */ @@ -77,14 +77,14 @@ public class ChunkRenderOptimizerSurface extends ChunkRenderOptimizer { /** * Returns the opacity of the surface identified by the provided - * {@link BlockFace}. + * {@link AbsFace}. * Opaque surfaces prevent surfaces behind them from being included in * chunk models. * * @param blockFace the face to query * @return {@code true} iff the surface is opaque. */ - boolean isOpaque(BlockFace blockFace); + boolean isOpaque(AbsFace blockFace); } /** @@ -168,7 +168,7 @@ public class ChunkRenderOptimizerSurface extends ChunkRenderOptimizer { } @Override - public void addTile(TileRender tile, Vec3i pos, BlockFace face) { + public void addTile(TileRender tile, Vec3i pos, AbsFace face) { if (!(tile instanceof TileOptimizedSurface)) return; @@ -180,7 +180,7 @@ public class ChunkRenderOptimizerSurface extends ChunkRenderOptimizer { getBlock(pos).block = block; } - private void addTile(Vec3i pos, BlockFace face, TileOptimizedSurface tile) { + private void addTile(Vec3i pos, AbsFace face, TileOptimizedSurface tile) { FaceInfo faceInfo = getFace(pos, face); int index = faceInfo.tileCount; @@ -201,7 +201,7 @@ public class ChunkRenderOptimizerSurface extends ChunkRenderOptimizer { return data[cursor.x][cursor.y][cursor.z]; } - protected FaceInfo getFace(Vec3i cursor, BlockFace face) { + protected FaceInfo getFace(Vec3i cursor, AbsFace face) { return getBlock(cursor).faces[face.getId()]; } @@ -238,12 +238,12 @@ public class ChunkRenderOptimizerSurface extends ChunkRenderOptimizer { Vec3i blockInChunk, Consumer output ) { - for (BlockFace blockFace : BlockFace.getFaces()) { + for (AbsFace blockFace : AbsFace.getFaces()) { processOuterFace(blockInChunk, blockFace, output); } } - private void processOuterFace(Vec3i blockInChunk, BlockFace blockFace, Consumer output) { + private void processOuterFace(Vec3i blockInChunk, AbsFace blockFace, Consumer output) { if (!shouldRenderOuterFace(blockInChunk, blockFace)) return; @@ -274,12 +274,12 @@ public class ChunkRenderOptimizerSurface extends ChunkRenderOptimizer { Vec3i blockInChunk, Consumer output ) { - for (BlockFace blockFace : BlockFace.getFaces()) { + for (AbsFace blockFace : AbsFace.getFaces()) { processInnerFace(blockInChunk, blockFace, output); } } - private void processInnerFace(Vec3i blockInChunk, BlockFace blockFace, Consumer output) { + private void processInnerFace(Vec3i blockInChunk, AbsFace blockFace, Consumer output) { if (!shouldRenderInnerFace(blockInChunk, blockFace)) return; @@ -306,7 +306,7 @@ public class ChunkRenderOptimizerSurface extends ChunkRenderOptimizer { } } - private boolean shouldRenderOuterFace(Vec3i blockInChunk, BlockFace face) { + private boolean shouldRenderOuterFace(Vec3i blockInChunk, AbsFace face) { blockInChunk.add(face.getVector()); try { return shouldRenderWhenFacing(blockInChunk, face); @@ -315,11 +315,11 @@ public class ChunkRenderOptimizerSurface extends ChunkRenderOptimizer { } } - private boolean shouldRenderInnerFace(Vec3i blockInChunk, BlockFace face) { + private boolean shouldRenderInnerFace(Vec3i blockInChunk, AbsFace face) { return shouldRenderWhenFacing(blockInChunk, face); } - private boolean shouldRenderWhenFacing(Vec3i blockInChunk, BlockFace face) { + private boolean shouldRenderWhenFacing(Vec3i blockInChunk, AbsFace face) { if (chunk.containsBiC(blockInChunk)) { return shouldRenderWhenFacingLocal(blockInChunk, face); } else { @@ -327,7 +327,7 @@ public class ChunkRenderOptimizerSurface extends ChunkRenderOptimizer { } } - private boolean shouldRenderWhenFacingLocal(Vec3i blockInChunk, BlockFace face) { + private boolean shouldRenderWhenFacingLocal(Vec3i blockInChunk, AbsFace face) { BlockOptimizedSurface block = getBlock(blockInChunk).block; if (block == null) { @@ -340,7 +340,7 @@ public class ChunkRenderOptimizerSurface extends ChunkRenderOptimizer { return true; } - private boolean shouldRenderWhenFacingNeighbor(Vec3i blockInLocalChunk, BlockFace face) { + private boolean shouldRenderWhenFacingNeighbor(Vec3i blockInLocalChunk, AbsFace face) { Vec3i blockInChunk = Vectors.grab3i().set(blockInLocalChunk.x, blockInLocalChunk.y, blockInLocalChunk.z); Vec3i chunkPos = Vectors.grab3i().set(chunk.getX(), chunk.getY(), chunk.getZ()); diff --git a/src/main/java/ru/windcorp/progressia/client/world/tile/TileRender.java b/src/main/java/ru/windcorp/progressia/client/world/tile/TileRender.java index 4f82d86..4cef07e 100644 --- a/src/main/java/ru/windcorp/progressia/client/world/tile/TileRender.java +++ b/src/main/java/ru/windcorp/progressia/client/world/tile/TileRender.java @@ -24,7 +24,7 @@ import ru.windcorp.progressia.client.graphics.model.Renderable; import ru.windcorp.progressia.client.world.cro.ChunkRenderOptimizer; import ru.windcorp.progressia.common.util.namespaces.Namespaced; import ru.windcorp.progressia.common.world.ChunkData; -import ru.windcorp.progressia.common.world.block.BlockFace; +import ru.windcorp.progressia.common.world.block.AbsFace; import ru.windcorp.progressia.common.world.generic.GenericTile; public class TileRender extends Namespaced implements GenericTile { @@ -33,13 +33,13 @@ public class TileRender extends Namespaced implements GenericTile { super(id); } - public void render(ShapeRenderHelper renderer, BlockFace face) { + public void render(ShapeRenderHelper renderer, AbsFace face) { throw new UnsupportedOperationException( "TileRender.render() not implemented in " + this ); } - public Renderable createRenderable(ChunkData chunk, Vec3i blockInChunk, BlockFace face) { + public Renderable createRenderable(ChunkData chunk, Vec3i blockInChunk, AbsFace face) { return null; } diff --git a/src/main/java/ru/windcorp/progressia/client/world/tile/TileRenderGrass.java b/src/main/java/ru/windcorp/progressia/client/world/tile/TileRenderGrass.java index c73647b..86ed0dc 100644 --- a/src/main/java/ru/windcorp/progressia/client/world/tile/TileRenderGrass.java +++ b/src/main/java/ru/windcorp/progressia/client/world/tile/TileRenderGrass.java @@ -19,7 +19,7 @@ package ru.windcorp.progressia.client.world.tile; import ru.windcorp.progressia.client.graphics.texture.Texture; -import ru.windcorp.progressia.common.world.block.BlockFace; +import ru.windcorp.progressia.common.world.block.AbsFace; public class TileRenderGrass extends TileRenderSurface { @@ -37,13 +37,13 @@ public class TileRenderGrass extends TileRenderSurface { } @Override - public Texture getTexture(BlockFace face) { - return (face == BlockFace.TOP) ? topTexture : sideTexture; + public Texture getTexture(AbsFace face) { + return (face == AbsFace.POS_Z) ? topTexture : sideTexture; } @Override - public boolean isOpaque(BlockFace face) { - return face == BlockFace.TOP; + public boolean isOpaque(AbsFace face) { + return face == AbsFace.POS_Z; } } diff --git a/src/main/java/ru/windcorp/progressia/client/world/tile/TileRenderNone.java b/src/main/java/ru/windcorp/progressia/client/world/tile/TileRenderNone.java index 8e2a6e4..3b3c345 100644 --- a/src/main/java/ru/windcorp/progressia/client/world/tile/TileRenderNone.java +++ b/src/main/java/ru/windcorp/progressia/client/world/tile/TileRenderNone.java @@ -21,7 +21,7 @@ import glm.vec._3.i.Vec3i; import ru.windcorp.progressia.client.graphics.model.EmptyModel; import ru.windcorp.progressia.client.graphics.model.Renderable; import ru.windcorp.progressia.common.world.ChunkData; -import ru.windcorp.progressia.common.world.block.BlockFace; +import ru.windcorp.progressia.common.world.block.AbsFace; public class TileRenderNone extends TileRender { @@ -30,7 +30,7 @@ public class TileRenderNone extends TileRender { } @Override - public Renderable createRenderable(ChunkData chunk, Vec3i blockInChunk, BlockFace face) { + public Renderable createRenderable(ChunkData chunk, Vec3i blockInChunk, AbsFace face) { return EmptyModel.getInstance(); } diff --git a/src/main/java/ru/windcorp/progressia/client/world/tile/TileRenderOpaqueSurface.java b/src/main/java/ru/windcorp/progressia/client/world/tile/TileRenderOpaqueSurface.java index e4990e8..62bf758 100644 --- a/src/main/java/ru/windcorp/progressia/client/world/tile/TileRenderOpaqueSurface.java +++ b/src/main/java/ru/windcorp/progressia/client/world/tile/TileRenderOpaqueSurface.java @@ -19,7 +19,7 @@ package ru.windcorp.progressia.client.world.tile; import ru.windcorp.progressia.client.graphics.texture.Texture; -import ru.windcorp.progressia.common.world.block.BlockFace; +import ru.windcorp.progressia.common.world.block.AbsFace; public class TileRenderOpaqueSurface extends TileRenderSurface { @@ -28,7 +28,7 @@ public class TileRenderOpaqueSurface extends TileRenderSurface { } @Override - public boolean isOpaque(BlockFace face) { + public boolean isOpaque(AbsFace face) { return true; } diff --git a/src/main/java/ru/windcorp/progressia/client/world/tile/TileRenderSurface.java b/src/main/java/ru/windcorp/progressia/client/world/tile/TileRenderSurface.java index eebcb07..76d8fbb 100644 --- a/src/main/java/ru/windcorp/progressia/client/world/tile/TileRenderSurface.java +++ b/src/main/java/ru/windcorp/progressia/client/world/tile/TileRenderSurface.java @@ -34,7 +34,7 @@ import ru.windcorp.progressia.client.graphics.world.WorldRenderProgram; import ru.windcorp.progressia.client.world.cro.ChunkRenderOptimizerSurface.TileOptimizedSurface; import ru.windcorp.progressia.common.util.Vectors; import ru.windcorp.progressia.common.world.ChunkData; -import ru.windcorp.progressia.common.world.block.BlockFace; +import ru.windcorp.progressia.common.world.block.AbsFace; public abstract class TileRenderSurface extends TileRender implements TileOptimizedSurface { @@ -49,17 +49,17 @@ public abstract class TileRenderSurface extends TileRender implements TileOptimi this(id, null); } - public Texture getTexture(BlockFace blockFace) { + public Texture getTexture(AbsFace blockFace) { return texture; } - public Vec4 getColorMultiplier(BlockFace blockFace) { + public Vec4 getColorMultiplier(AbsFace blockFace) { return Colors.WHITE; } @Override public final void getFaces( - ChunkData chunk, Vec3i blockInChunk, BlockFace blockFace, + ChunkData chunk, Vec3i blockInChunk, AbsFace blockFace, boolean inner, Consumer output, Vec3 offset @@ -68,7 +68,7 @@ public abstract class TileRenderSurface extends TileRender implements TileOptimi } private Face createFace( - ChunkData chunk, Vec3i blockInChunk, BlockFace blockFace, + ChunkData chunk, Vec3i blockInChunk, AbsFace blockFace, boolean inner, Vec3 offset ) { @@ -83,7 +83,7 @@ public abstract class TileRenderSurface extends TileRender implements TileOptimi } @Override - public Renderable createRenderable(ChunkData chunk, Vec3i blockInChunk, BlockFace blockFace) { + public Renderable createRenderable(ChunkData chunk, Vec3i blockInChunk, AbsFace blockFace) { return new Shape( Usage.STATIC, WorldRenderProgram.getDefault(), diff --git a/src/main/java/ru/windcorp/progressia/client/world/tile/TileRenderTransparentSurface.java b/src/main/java/ru/windcorp/progressia/client/world/tile/TileRenderTransparentSurface.java index b35986e..29a99ac 100644 --- a/src/main/java/ru/windcorp/progressia/client/world/tile/TileRenderTransparentSurface.java +++ b/src/main/java/ru/windcorp/progressia/client/world/tile/TileRenderTransparentSurface.java @@ -19,7 +19,7 @@ package ru.windcorp.progressia.client.world.tile; import ru.windcorp.progressia.client.graphics.texture.Texture; -import ru.windcorp.progressia.common.world.block.BlockFace; +import ru.windcorp.progressia.common.world.block.AbsFace; public class TileRenderTransparentSurface extends TileRenderSurface { @@ -28,7 +28,7 @@ public class TileRenderTransparentSurface extends TileRenderSurface { } @Override - public boolean isOpaque(BlockFace face) { + public boolean isOpaque(AbsFace face) { return false; } diff --git a/src/main/java/ru/windcorp/progressia/common/collision/AABBoid.java b/src/main/java/ru/windcorp/progressia/common/collision/AABBoid.java index ab2cd80..c22d4b6 100644 --- a/src/main/java/ru/windcorp/progressia/common/collision/AABBoid.java +++ b/src/main/java/ru/windcorp/progressia/common/collision/AABBoid.java @@ -19,7 +19,7 @@ package ru.windcorp.progressia.common.collision; import glm.vec._3.Vec3; -import ru.windcorp.progressia.common.world.block.BlockFace; +import ru.windcorp.progressia.common.world.block.AbsFace; public interface AABBoid extends CollisionModel { @@ -27,7 +27,7 @@ public interface AABBoid extends CollisionModel { void getSize(Vec3 output); - default Wall getWall(BlockFace face) { + default Wall getWall(AbsFace face) { return getWall(face.getId()); } diff --git a/src/main/java/ru/windcorp/progressia/common/collision/TranslatedAABB.java b/src/main/java/ru/windcorp/progressia/common/collision/TranslatedAABB.java index 4c33ad2..4568f75 100644 --- a/src/main/java/ru/windcorp/progressia/common/collision/TranslatedAABB.java +++ b/src/main/java/ru/windcorp/progressia/common/collision/TranslatedAABB.java @@ -20,7 +20,7 @@ package ru.windcorp.progressia.common.collision; import glm.vec._3.Vec3; import ru.windcorp.progressia.common.util.Vectors; -import ru.windcorp.progressia.common.world.block.BlockFace; +import ru.windcorp.progressia.common.world.block.AbsFace; public class TranslatedAABB implements AABBoid { @@ -51,7 +51,7 @@ public class TranslatedAABB implements AABBoid { private AABBoid parent; private final Vec3 translation = new Vec3(); - private final TranslatedAABBWall[] walls = new TranslatedAABBWall[BlockFace.BLOCK_FACE_COUNT]; + private final TranslatedAABBWall[] walls = new TranslatedAABBWall[AbsFace.BLOCK_FACE_COUNT]; { for (int id = 0; id < walls.length; ++id) { diff --git a/src/main/java/ru/windcorp/progressia/common/collision/colliders/AABBoidCollider.java b/src/main/java/ru/windcorp/progressia/common/collision/colliders/AABBoidCollider.java index 5fab3d8..28802b2 100644 --- a/src/main/java/ru/windcorp/progressia/common/collision/colliders/AABBoidCollider.java +++ b/src/main/java/ru/windcorp/progressia/common/collision/colliders/AABBoidCollider.java @@ -25,7 +25,7 @@ import ru.windcorp.progressia.common.collision.colliders.Collider.ColliderWorksp import ru.windcorp.progressia.common.collision.colliders.Collider.Collision; import ru.windcorp.progressia.common.util.Matrices; import ru.windcorp.progressia.common.util.Vectors; -import ru.windcorp.progressia.common.world.block.BlockFace; +import ru.windcorp.progressia.common.world.block.AbsFace; class AABBoidCollider { @@ -50,7 +50,7 @@ class AABBoidCollider { computeCollisionVelocity(collisionVelocity, obstacleBody, colliderBody); // For every wall of collision space - for (int i = 0; i < BlockFace.BLOCK_FACE_COUNT; ++i) { + for (int i = 0; i < AbsFace.BLOCK_FACE_COUNT; ++i) { Wall wall = originCollisionSpace.getWall(i); Collision collision = computeWallCollision( diff --git a/src/main/java/ru/windcorp/progressia/common/world/BlockRay.java b/src/main/java/ru/windcorp/progressia/common/world/BlockRay.java index 743d238..6dc4750 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/BlockRay.java +++ b/src/main/java/ru/windcorp/progressia/common/world/BlockRay.java @@ -22,7 +22,7 @@ import glm.vec._3.Vec3; import glm.vec._3.i.Vec3i; import ru.windcorp.progressia.common.util.VectorUtil; import ru.windcorp.progressia.common.util.VectorUtil.Axis; -import ru.windcorp.progressia.common.world.block.BlockFace; +import ru.windcorp.progressia.common.world.block.AbsFace; import static java.lang.Math.*; @@ -34,7 +34,7 @@ public class BlockRay { private float distance; private final Vec3i block = new Vec3i(); - private BlockFace currentFace = null; + private AbsFace currentFace = null; private boolean isValid = false; @@ -120,18 +120,18 @@ public class BlockRay { return (edge - c) / dir; } - private BlockFace computeCurrentFace(Axis axis, int sign) { + private AbsFace computeCurrentFace(Axis axis, int sign) { if (sign == 0) throw new IllegalStateException("sign is zero"); switch (axis) { case X: - return sign > 0 ? BlockFace.SOUTH : BlockFace.NORTH; + return sign > 0 ? AbsFace.NEG_X : AbsFace.POS_X; case Y: - return sign > 0 ? BlockFace.EAST : BlockFace.WEST; + return sign > 0 ? AbsFace.NEG_Y : AbsFace.POS_Y; default: case Z: - return sign > 0 ? BlockFace.BOTTOM : BlockFace.TOP; + return sign > 0 ? AbsFace.NEG_Z : AbsFace.POS_Z; } } @@ -147,7 +147,7 @@ public class BlockRay { return output; } - public BlockFace getCurrentFace() { + public AbsFace getCurrentFace() { return currentFace; } diff --git a/src/main/java/ru/windcorp/progressia/common/world/ChunkData.java b/src/main/java/ru/windcorp/progressia/common/world/ChunkData.java index 252429c..4857479 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/ChunkData.java +++ b/src/main/java/ru/windcorp/progressia/common/world/ChunkData.java @@ -18,7 +18,7 @@ package ru.windcorp.progressia.common.world; -import static ru.windcorp.progressia.common.world.block.BlockFace.*; +import static ru.windcorp.progressia.common.world.block.AbsFace.*; import java.util.ArrayList; import java.util.Arrays; @@ -31,7 +31,7 @@ import java.util.function.Consumer; import glm.vec._3.i.Vec3i; import ru.windcorp.progressia.common.util.VectorUtil; import ru.windcorp.progressia.common.world.block.BlockData; -import ru.windcorp.progressia.common.world.block.BlockFace; +import ru.windcorp.progressia.common.world.block.AbsFace; import ru.windcorp.progressia.common.world.generic.GenericChunk; import ru.windcorp.progressia.common.world.tile.TileData; import ru.windcorp.progressia.common.world.tile.TileDataStack; @@ -83,31 +83,31 @@ public class ChunkData } @Override - public TileDataStack getTilesOrNull(Vec3i blockInChunk, BlockFace face) { + public TileDataStack getTilesOrNull(Vec3i blockInChunk, AbsFace face) { return tiles[getTileIndex(blockInChunk, face)]; } /** * Internal use only. Modify a list returned by - * {@link #getTiles(Vec3i, BlockFace)} or - * {@link #getTilesOrNull(Vec3i, BlockFace)} + * {@link #getTiles(Vec3i, AbsFace)} or + * {@link #getTilesOrNull(Vec3i, AbsFace)} * to change tiles. */ protected void setTiles( Vec3i blockInChunk, - BlockFace face, + AbsFace face, TileDataStack tiles ) { this.tiles[getTileIndex(blockInChunk, face)] = tiles; } @Override - public boolean hasTiles(Vec3i blockInChunk, BlockFace face) { + public boolean hasTiles(Vec3i blockInChunk, AbsFace face) { return getTilesOrNull(blockInChunk, face) != null; } @Override - public TileDataStack getTiles(Vec3i blockInChunk, BlockFace face) { + public TileDataStack getTiles(Vec3i blockInChunk, AbsFace face) { int index = getTileIndex(blockInChunk, face); if (tiles[index] == null) { @@ -117,15 +117,15 @@ public class ChunkData return tiles[index]; } - private void createTileStack(Vec3i blockInChunk, BlockFace face) { + private void createTileStack(Vec3i blockInChunk, AbsFace face) { Vec3i independentBlockInChunk = conjureIndependentBlockInChunkVec3i(blockInChunk); TileDataStackImpl stack = new TileDataStackImpl(independentBlockInChunk, face); setTiles(blockInChunk, face, stack); } private Vec3i conjureIndependentBlockInChunkVec3i(Vec3i blockInChunk) { - for (int i = 0; i < BlockFace.BLOCK_FACE_COUNT; ++i) { - TileDataStack stack = getTilesOrNull(blockInChunk, BlockFace.getFaces().get(i)); + for (int i = 0; i < AbsFace.BLOCK_FACE_COUNT; ++i) { + TileDataStack stack = getTilesOrNull(blockInChunk, AbsFace.getFaces().get(i)); if (stack instanceof TileDataStackImpl) { return ((TileDataStackImpl) stack).blockInChunk; } @@ -142,7 +142,7 @@ public class ChunkData posInChunk.x; } - private static int getTileIndex(Vec3i posInChunk, BlockFace face) { + private static int getTileIndex(Vec3i posInChunk, AbsFace face) { return getBlockIndex(posInChunk) * BLOCK_FACE_COUNT + face.getId(); } @@ -162,14 +162,14 @@ public class ChunkData posInChunk.z >= 0 && posInChunk.z < BLOCKS_PER_CHUNK; } - public boolean isBorder(Vec3i blockInChunk, BlockFace face) { + public boolean isBorder(Vec3i blockInChunk, AbsFace face) { final int min = 0, max = BLOCKS_PER_CHUNK - 1; - return (blockInChunk.x == min && face == SOUTH) || - (blockInChunk.x == max && face == NORTH) || - (blockInChunk.y == min && face == EAST) || - (blockInChunk.y == max && face == WEST) || - (blockInChunk.z == min && face == BOTTOM) || - (blockInChunk.z == max && face == TOP); + return (blockInChunk.x == min && face == NEG_X) || + (blockInChunk.x == max && face == POS_X) || + (blockInChunk.y == min && face == NEG_Y) || + (blockInChunk.y == max && face == POS_Y) || + (blockInChunk.z == min && face == NEG_Z) || + (blockInChunk.z == max && face == POS_Z); } public void forEachBlock(Consumer action) { @@ -186,7 +186,7 @@ public class ChunkData public void forEachTileStack(Consumer action) { forEachBlock(blockInChunk -> { - for (BlockFace face : BlockFace.getFaces()) { + for (AbsFace face : AbsFace.getFaces()) { TileDataStack stack = getTilesOrNull(blockInChunk, face); if (stack == null) continue; @@ -309,9 +309,9 @@ public class ChunkData * Potentially shared */ private final Vec3i blockInChunk; - private final BlockFace face; + private final AbsFace face; - public TileDataStackImpl(Vec3i blockInChunk, BlockFace face) { + public TileDataStackImpl(Vec3i blockInChunk, AbsFace face) { this.blockInChunk = blockInChunk; this.face = face; } @@ -325,7 +325,7 @@ public class ChunkData } @Override - public BlockFace getFace() { + public AbsFace getFace() { return face; } diff --git a/src/main/java/ru/windcorp/progressia/common/world/ChunkDataListener.java b/src/main/java/ru/windcorp/progressia/common/world/ChunkDataListener.java index 72008c4..3913468 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/ChunkDataListener.java +++ b/src/main/java/ru/windcorp/progressia/common/world/ChunkDataListener.java @@ -20,7 +20,7 @@ package ru.windcorp.progressia.common.world; import glm.vec._3.i.Vec3i; import ru.windcorp.progressia.common.world.block.BlockData; -import ru.windcorp.progressia.common.world.block.BlockFace; +import ru.windcorp.progressia.common.world.block.AbsFace; import ru.windcorp.progressia.common.world.tile.TileData; public interface ChunkDataListener { @@ -55,7 +55,7 @@ public interface ChunkDataListener { default void onChunkTilesChanged( ChunkData chunk, Vec3i blockInChunk, - BlockFace face, + AbsFace face, TileData tile, boolean wasAdded ) { diff --git a/src/main/java/ru/windcorp/progressia/common/world/block/BlockFace.java b/src/main/java/ru/windcorp/progressia/common/world/block/AbsFace.java similarity index 58% rename from src/main/java/ru/windcorp/progressia/common/world/block/BlockFace.java rename to src/main/java/ru/windcorp/progressia/common/world/block/AbsFace.java index 9023500..06747d6 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/block/BlockFace.java +++ b/src/main/java/ru/windcorp/progressia/common/world/block/AbsFace.java @@ -23,65 +23,68 @@ import com.google.common.collect.ImmutableMap; import glm.vec._3.i.Vec3i; -public final class BlockFace extends BlockRelation { +public final class AbsFace extends AbsRelation { - public static final BlockFace TOP = new BlockFace(0, 0, +1, true, "TOP"), - BOTTOM = new BlockFace(0, 0, -1, false, "BOTTOM"), - NORTH = new BlockFace(+1, 0, 0, true, "NORTH"), - SOUTH = new BlockFace(-1, 0, 0, false, "SOUTH"), - WEST = new BlockFace(0, +1, 0, false, "WEST"), - EAST = new BlockFace(0, -1, 0, true, "EAST"); + // @formatter:off + public static final AbsFace + POS_Z = new AbsFace( 0, 0, +1, true, "POS_Z"), + NEG_Z = new AbsFace( 0, 0, -1, false, "NEG_Z"), + POS_X = new AbsFace(+1, 0, 0, true, "POS_X"), + NEG_X = new AbsFace(-1, 0, 0, false, "NEG_X"), + POS_Y = new AbsFace( 0, +1, 0, false, "POS_Y"), + NEG_Y = new AbsFace( 0, -1, 0, true, "NEG_Y"); + // @formatter:on - private static final ImmutableList ALL_FACES = ImmutableList.of(TOP, BOTTOM, NORTH, SOUTH, WEST, EAST); + private static final ImmutableList ALL_FACES = ImmutableList.of(POS_Z, NEG_Z, POS_X, NEG_X, POS_Y, NEG_Y); static { - link(TOP, BOTTOM); - link(NORTH, SOUTH); - link(WEST, EAST); + link(POS_Z, NEG_Z); + link(POS_X, NEG_X); + link(POS_Y, NEG_Y); } - private static final ImmutableList PRIMARY_FACES = ALL_FACES.stream().filter(BlockFace::isPrimary) + private static final ImmutableList PRIMARY_FACES = ALL_FACES.stream().filter(AbsFace::isPrimary) .collect(ImmutableList.toImmutableList()); - private static final ImmutableList SECONDARY_FACES = ALL_FACES.stream().filter(BlockFace::isSecondary) + private static final ImmutableList SECONDARY_FACES = ALL_FACES.stream().filter(AbsFace::isSecondary) .collect(ImmutableList.toImmutableList()); public static final int BLOCK_FACE_COUNT = ALL_FACES.size(); public static final int PRIMARY_BLOCK_FACE_COUNT = PRIMARY_FACES.size(); public static final int SECONDARY_BLOCK_FACE_COUNT = SECONDARY_FACES.size(); - public static ImmutableList getFaces() { + public static ImmutableList getFaces() { return ALL_FACES; } - public static ImmutableList getPrimaryFaces() { + public static ImmutableList getPrimaryFaces() { return PRIMARY_FACES; } - public static ImmutableList getSecondaryFaces() { + public static ImmutableList getSecondaryFaces() { return SECONDARY_FACES; } - private static void link(BlockFace a, BlockFace b) { + private static void link(AbsFace a, AbsFace b) { a.counterFace = b; b.counterFace = a; } - public static ImmutableMap mapToFaces( - E top, - E bottom, - E north, - E south, - E east, - E west + public static ImmutableMap mapToFaces( + E posZ, + E negZ, + E posX, + E negX, + E negY, + E posY ) { - return ImmutableMap.builderWithExpectedSize(6) - .put(TOP, top) - .put(BOTTOM, bottom) - .put(NORTH, north) - .put(SOUTH, south) - .put(EAST, east) - .put(WEST, west) + return ImmutableMap.builderWithExpectedSize(6) + .put(POS_Z, posZ) + .put(NEG_Z, negZ) + .put(POS_X, posX) + .put(NEG_X, negX) + .put(NEG_Y, negY) + .put(POS_Y, posY) .build(); } @@ -89,10 +92,10 @@ public final class BlockFace extends BlockRelation { private final int id; private final String name; - private BlockFace counterFace; + private AbsFace counterFace; private final boolean isPrimary; - private BlockFace(int x, int y, int z, boolean isPrimary, String name) { + private AbsFace(int x, int y, int z, boolean isPrimary, String name) { super(x, y, z); this.id = nextId++; this.isPrimary = isPrimary; @@ -107,14 +110,14 @@ public final class BlockFace extends BlockRelation { return isPrimary; } - public BlockFace getPrimary() { + public AbsFace getPrimary() { if (isPrimary) return this; else return counterFace; } - public BlockFace getPrimaryAndMoveCursor(Vec3i cursor) { + public AbsFace getPrimaryAndMoveCursor(Vec3i cursor) { if (isPrimary) return this; @@ -126,14 +129,14 @@ public final class BlockFace extends BlockRelation { return !isPrimary; } - public BlockFace getSecondary() { + public AbsFace getSecondary() { if (isPrimary) return counterFace; else return this; } - public BlockFace getSecondaryAndMoveCursor(Vec3i cursor) { + public AbsFace getSecondaryAndMoveCursor(Vec3i cursor) { if (!isPrimary) return this; @@ -141,11 +144,11 @@ public final class BlockFace extends BlockRelation { return counterFace; } - public BlockFace getCounter() { + public AbsFace getCounter() { return counterFace; } - public BlockFace getCounterAndMoveCursor(Vec3i cursor) { + public AbsFace getCounterAndMoveCursor(Vec3i cursor) { cursor.add(getVector()); return counterFace; } diff --git a/src/main/java/ru/windcorp/progressia/common/world/block/BlockRelation.java b/src/main/java/ru/windcorp/progressia/common/world/block/AbsRelation.java similarity index 95% rename from src/main/java/ru/windcorp/progressia/common/world/block/BlockRelation.java rename to src/main/java/ru/windcorp/progressia/common/world/block/AbsRelation.java index 659a5fa..a14b4f0 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/block/BlockRelation.java +++ b/src/main/java/ru/windcorp/progressia/common/world/block/AbsRelation.java @@ -24,19 +24,19 @@ import static java.lang.Math.max; import glm.vec._3.Vec3; import glm.vec._3.i.Vec3i; -public class BlockRelation { +public class AbsRelation { private final Vec3i vector = new Vec3i(); private final Vec3 floatVector = new Vec3(); private final Vec3 normalized = new Vec3(); - public BlockRelation(int x, int y, int z) { + public AbsRelation(int x, int y, int z) { vector.set(x, y, z); floatVector.set(x, y, z); normalized.set(x, y, z).normalize(); } - public BlockRelation(Vec3i vector) { + public AbsRelation(Vec3i vector) { this(vector.x, vector.y, vector.z); } diff --git a/src/main/java/ru/windcorp/progressia/common/world/generic/GenericChunk.java b/src/main/java/ru/windcorp/progressia/common/world/generic/GenericChunk.java index 656304f..c2e9611 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/generic/GenericChunk.java +++ b/src/main/java/ru/windcorp/progressia/common/world/generic/GenericChunk.java @@ -24,7 +24,7 @@ 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.world.Coordinates; -import ru.windcorp.progressia.common.world.block.BlockFace; +import ru.windcorp.progressia.common.world.block.AbsFace; public interface GenericChunk, B extends GenericBlock, T extends GenericTile, TS extends GenericTileStack> { @@ -34,9 +34,9 @@ public interface GenericChunk, B exten B getBlock(Vec3i blockInChunk); - TS getTiles(Vec3i blockInChunk, BlockFace face); + TS getTiles(Vec3i blockInChunk, AbsFace face); - boolean hasTiles(Vec3i blockInChunk, BlockFace face); + boolean hasTiles(Vec3i blockInChunk, AbsFace face); default int getX() { return getPosition().x; @@ -182,7 +182,7 @@ public interface GenericChunk, B exten ); } - default TS getTilesOrNull(Vec3i blockInChunk, BlockFace face) { + default TS getTilesOrNull(Vec3i blockInChunk, AbsFace face) { if (hasTiles(blockInChunk, face)) { return getTiles(blockInChunk, face); } diff --git a/src/main/java/ru/windcorp/progressia/common/world/generic/GenericTileStack.java b/src/main/java/ru/windcorp/progressia/common/world/generic/GenericTileStack.java index 31a5158..5b6ea89 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/generic/GenericTileStack.java +++ b/src/main/java/ru/windcorp/progressia/common/world/generic/GenericTileStack.java @@ -25,7 +25,7 @@ import java.util.function.Consumer; import glm.vec._3.i.Vec3i; import ru.windcorp.progressia.common.world.Coordinates; -import ru.windcorp.progressia.common.world.block.BlockFace; +import ru.windcorp.progressia.common.world.block.AbsFace; public abstract class GenericTileStack, T extends GenericTile, C extends GenericChunk> extends AbstractList @@ -41,7 +41,7 @@ public abstract class GenericTileStack public abstract C getChunk(); - public abstract BlockFace getFace(); + public abstract AbsFace getFace(); public Vec3i getBlockInWorld(Vec3i output) { // This is safe diff --git a/src/main/java/ru/windcorp/progressia/common/world/generic/GenericWorld.java b/src/main/java/ru/windcorp/progressia/common/world/generic/GenericWorld.java index 943067e..af5ebb9 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/generic/GenericWorld.java +++ b/src/main/java/ru/windcorp/progressia/common/world/generic/GenericWorld.java @@ -26,7 +26,7 @@ import glm.vec._3.Vec3; import glm.vec._3.i.Vec3i; import ru.windcorp.progressia.common.util.Vectors; import ru.windcorp.progressia.common.world.Coordinates; -import ru.windcorp.progressia.common.world.block.BlockFace; +import ru.windcorp.progressia.common.world.block.AbsFace; public interface GenericWorld, C extends GenericChunk, E extends GenericEntity> { @@ -63,7 +63,7 @@ public interface GenericWorld { TileLogic tile = context.getTile(); @@ -106,7 +106,7 @@ public class TickAndUpdateUtil { } } - public static void updateTile(WorldLogic world, Vec3i blockInWorld, BlockFace face, int layer) { + public static void updateTile(WorldLogic world, Vec3i blockInWorld, AbsFace face, int layer) { TileLogic tile = world.getTile(blockInWorld, face, layer); if (!(tile instanceof UpdateableTile)) return; @@ -116,7 +116,7 @@ public class TickAndUpdateUtil { updateTile((UpdateableTile) tile, tickContext); } - public static void updateTiles(WorldLogic world, Vec3i blockInWorld, BlockFace face) { + public static void updateTiles(WorldLogic world, Vec3i blockInWorld, AbsFace face) { TickContextMutable.start().withWorld(world).withBlock(blockInWorld).withFace(face).build() .forEachTile(context -> { TileLogic tile = context.getTile(); diff --git a/src/main/java/ru/windcorp/progressia/server/world/TickContextMutable.java b/src/main/java/ru/windcorp/progressia/server/world/TickContextMutable.java index 68185d9..86e75bb 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/TickContextMutable.java +++ b/src/main/java/ru/windcorp/progressia/server/world/TickContextMutable.java @@ -25,7 +25,7 @@ import java.util.function.Function; import glm.vec._3.i.Vec3i; import ru.windcorp.progressia.common.world.ChunkData; import ru.windcorp.progressia.common.world.Coordinates; -import ru.windcorp.progressia.common.world.block.BlockFace; +import ru.windcorp.progressia.common.world.block.AbsFace; import ru.windcorp.progressia.common.world.generic.GenericTileStack; import ru.windcorp.progressia.common.world.tile.TileDataStack; import ru.windcorp.progressia.common.world.tile.TileReference; @@ -126,7 +126,7 @@ public abstract class TickContextMutable implements BlockTickContext, TSTickCont } public static interface Block extends Builder { - Builder.TileStack withFace(BlockFace face); + Builder.TileStack withFace(AbsFace face); } public static interface TileStack extends Builder { @@ -148,7 +148,7 @@ public abstract class TickContextMutable implements BlockTickContext, TSTickCont protected Server server; protected final Vec3i chunk = new Vec3i(); protected final Vec3i blockInWorld = new Vec3i(); - protected BlockFace face; + protected AbsFace face; protected int layer; protected Role role = Role.NONE; @@ -188,7 +188,7 @@ public abstract class TickContextMutable implements BlockTickContext, TSTickCont } @Override - public BlockFace getFace() { + public AbsFace getFace() { checkContextState(Role.TILE_STACK); return this.face; } @@ -277,7 +277,7 @@ public abstract class TickContextMutable implements BlockTickContext, TSTickCont } @Override - public TileStack withFace(BlockFace face) { + public TileStack withFace(AbsFace face) { Objects.requireNonNull(face, "face"); checkBuilderState(Role.BLOCK); @@ -339,12 +339,12 @@ public abstract class TickContextMutable implements BlockTickContext, TSTickCont @Override public void forEachFace(Consumer action) { checkContextState(Role.BLOCK); - BlockFace previousFace = this.face; + AbsFace previousFace = this.face; Role previousRole = this.role; this.role = Role.TILE_STACK; - for (int i = 0; i < BlockFace.BLOCK_FACE_COUNT; ++i) { - this.face = BlockFace.getFaces().get(i); + for (int i = 0; i < AbsFace.BLOCK_FACE_COUNT; ++i) { + this.face = AbsFace.getFaces().get(i); action.accept(this); } diff --git a/src/main/java/ru/windcorp/progressia/server/world/UpdateTriggerer.java b/src/main/java/ru/windcorp/progressia/server/world/UpdateTriggerer.java index 511170e..6d8bf22 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/UpdateTriggerer.java +++ b/src/main/java/ru/windcorp/progressia/server/world/UpdateTriggerer.java @@ -23,7 +23,7 @@ import ru.windcorp.progressia.common.world.ChunkData; import ru.windcorp.progressia.common.world.ChunkDataListener; import ru.windcorp.progressia.common.world.Coordinates; import ru.windcorp.progressia.common.world.block.BlockData; -import ru.windcorp.progressia.common.world.block.BlockFace; +import ru.windcorp.progressia.common.world.block.AbsFace; import ru.windcorp.progressia.common.world.tile.TileData; import ru.windcorp.progressia.server.Server; @@ -49,7 +49,7 @@ public class UpdateTriggerer implements ChunkDataListener { public void onChunkTilesChanged( ChunkData chunk, Vec3i blockInChunk, - BlockFace face, + AbsFace face, TileData tile, boolean wasAdded ) { diff --git a/src/main/java/ru/windcorp/progressia/server/world/block/BlockLogic.java b/src/main/java/ru/windcorp/progressia/server/world/block/BlockLogic.java index 794259f..5522813 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/block/BlockLogic.java +++ b/src/main/java/ru/windcorp/progressia/server/world/block/BlockLogic.java @@ -19,7 +19,7 @@ package ru.windcorp.progressia.server.world.block; import ru.windcorp.progressia.common.util.namespaces.Namespaced; -import ru.windcorp.progressia.common.world.block.BlockFace; +import ru.windcorp.progressia.common.world.block.AbsFace; import ru.windcorp.progressia.common.world.generic.GenericBlock; public class BlockLogic extends Namespaced implements GenericBlock { @@ -28,11 +28,11 @@ public class BlockLogic extends Namespaced implements GenericBlock { super(id); } - public boolean isSolid(BlockTickContext context, BlockFace face) { + public boolean isSolid(BlockTickContext context, AbsFace face) { return isSolid(face); } - public boolean isSolid(BlockFace face) { + public boolean isSolid(AbsFace face) { return true; } diff --git a/src/main/java/ru/windcorp/progressia/server/world/block/BlockTickContext.java b/src/main/java/ru/windcorp/progressia/server/world/block/BlockTickContext.java index a305b9a..3f3dbc2 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/block/BlockTickContext.java +++ b/src/main/java/ru/windcorp/progressia/server/world/block/BlockTickContext.java @@ -25,8 +25,8 @@ import java.util.function.Function; import glm.vec._3.i.Vec3i; import ru.windcorp.progressia.common.world.Coordinates; import ru.windcorp.progressia.common.world.block.BlockData; -import ru.windcorp.progressia.common.world.block.BlockFace; -import ru.windcorp.progressia.common.world.block.BlockRelation; +import ru.windcorp.progressia.common.world.block.AbsFace; +import ru.windcorp.progressia.common.world.block.AbsRelation; import ru.windcorp.progressia.server.world.ChunkTickContext; import ru.windcorp.progressia.server.world.TickContextMutable; import ru.windcorp.progressia.server.world.tile.TSTickContext; @@ -56,7 +56,7 @@ public interface BlockTickContext extends ChunkTickContext { Objects.requireNonNull(action, "action"); TickContextMutable context = TickContextMutable.uninitialized(); - for (BlockFace face : BlockFace.getFaces()) { + for (AbsFace face : AbsFace.getFaces()) { context.rebuild().withServer(getServer()).withBlock(getBlockInWorld()).withFace(face).build(); action.accept(context); } @@ -67,7 +67,7 @@ public interface BlockTickContext extends ChunkTickContext { return TickContextMutable.copyWorld(this).withBlock(getBlockInWorld().add_(direction)).build(); } - default BlockTickContext getNeighbor(BlockRelation relation) { + default BlockTickContext getNeighbor(AbsRelation relation) { Objects.requireNonNull(relation, "relation"); return getNeighbor(relation.getVector()); } @@ -78,7 +78,7 @@ public interface BlockTickContext extends ChunkTickContext { return action.apply(getNeighbor(direction)); } - default R evalNeighbor(BlockRelation relation, Function action) { + default R evalNeighbor(AbsRelation relation, Function action) { Objects.requireNonNull(action, "action"); Objects.requireNonNull(relation, "relation"); return evalNeighbor(relation.getVector(), action); @@ -93,7 +93,7 @@ public interface BlockTickContext extends ChunkTickContext { }); } - default void forNeighbor(BlockRelation relation, Consumer action) { + default void forNeighbor(AbsRelation relation, Consumer action) { Objects.requireNonNull(action, "action"); Objects.requireNonNull(relation, "relation"); forNeighbor(relation.getVector(), action); diff --git a/src/main/java/ru/windcorp/progressia/server/world/tasks/BlockTriggeredUpdate.java b/src/main/java/ru/windcorp/progressia/server/world/tasks/BlockTriggeredUpdate.java index 331a5c4..369492e 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/tasks/BlockTriggeredUpdate.java +++ b/src/main/java/ru/windcorp/progressia/server/world/tasks/BlockTriggeredUpdate.java @@ -22,7 +22,7 @@ import java.util.function.Consumer; import glm.vec._3.i.Vec3i; import ru.windcorp.progressia.common.world.Coordinates; -import ru.windcorp.progressia.common.world.block.BlockFace; +import ru.windcorp.progressia.common.world.block.AbsFace; import ru.windcorp.progressia.server.Server; import ru.windcorp.progressia.server.world.TickAndUpdateUtil; import ru.windcorp.progressia.server.world.WorldLogic; @@ -41,7 +41,7 @@ class BlockTriggeredUpdate extends CachedEvaluation { WorldLogic world = server.getWorld(); - for (BlockFace face : BlockFace.getFaces()) { + for (AbsFace face : AbsFace.getFaces()) { TickAndUpdateUtil.updateTiles(world, cursor, face); cursor.add(face.getVector()); TickAndUpdateUtil.updateBlock(world, cursor); diff --git a/src/main/java/ru/windcorp/progressia/server/world/tasks/TickChunk.java b/src/main/java/ru/windcorp/progressia/server/world/tasks/TickChunk.java index c0895e1..07fab12 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/tasks/TickChunk.java +++ b/src/main/java/ru/windcorp/progressia/server/world/tasks/TickChunk.java @@ -28,7 +28,7 @@ import com.google.common.collect.ImmutableList; import glm.vec._3.i.Vec3i; import ru.windcorp.progressia.common.util.FloatMathUtil; import ru.windcorp.progressia.common.world.ChunkData; -import ru.windcorp.progressia.common.world.block.BlockFace; +import ru.windcorp.progressia.common.world.block.AbsFace; import ru.windcorp.progressia.common.world.tile.TileDataStack; import ru.windcorp.progressia.server.Server; import ru.windcorp.progressia.server.world.ChunkLogic; @@ -54,7 +54,7 @@ public class TickChunk extends Evaluation { List> randomTickMethods = new ArrayList<>(); randomTickMethods.add(this::tickRandomBlock); - for (BlockFace face : BlockFace.getFaces()) { + for (AbsFace face : AbsFace.getFaces()) { randomTickMethods.add(s -> this.tickRandomTile(s, face)); } @@ -151,7 +151,7 @@ public class TickChunk extends Evaluation { tickable.tick(context); } - private void tickRandomTile(Server server, BlockFace face) { + private void tickRandomTile(Server server, AbsFace face) { Random random = server.getAdHocRandom(); Vec3i blockInChunk = new Vec3i( diff --git a/src/main/java/ru/windcorp/progressia/server/world/tasks/TileTriggeredUpdate.java b/src/main/java/ru/windcorp/progressia/server/world/tasks/TileTriggeredUpdate.java index 76fc414..b69ca2b 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/tasks/TileTriggeredUpdate.java +++ b/src/main/java/ru/windcorp/progressia/server/world/tasks/TileTriggeredUpdate.java @@ -22,7 +22,7 @@ import java.util.function.Consumer; import glm.vec._3.i.Vec3i; import ru.windcorp.progressia.common.world.Coordinates; -import ru.windcorp.progressia.common.world.block.BlockFace; +import ru.windcorp.progressia.common.world.block.AbsFace; import ru.windcorp.progressia.server.Server; import ru.windcorp.progressia.server.world.TickAndUpdateUtil; import ru.windcorp.progressia.server.world.WorldLogic; @@ -30,7 +30,7 @@ import ru.windcorp.progressia.server.world.WorldLogic; class TileTriggeredUpdate extends CachedEvaluation { private final Vec3i blockInWorld = new Vec3i(); - private BlockFace face = null; + private AbsFace face = null; public TileTriggeredUpdate(Consumer disposer) { super(disposer); @@ -53,7 +53,7 @@ class TileTriggeredUpdate extends CachedEvaluation { // complement } - public void init(Vec3i blockInWorld, BlockFace face) { + public void init(Vec3i blockInWorld, AbsFace face) { this.blockInWorld.set(blockInWorld.x, blockInWorld.y, blockInWorld.z); this.face = face; } diff --git a/src/main/java/ru/windcorp/progressia/server/world/tasks/WorldAccessor.java b/src/main/java/ru/windcorp/progressia/server/world/tasks/WorldAccessor.java index 2c83ccd..0b34bcf 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/tasks/WorldAccessor.java +++ b/src/main/java/ru/windcorp/progressia/server/world/tasks/WorldAccessor.java @@ -24,7 +24,7 @@ import glm.vec._3.i.Vec3i; import ru.windcorp.progressia.common.util.MultiLOC; import ru.windcorp.progressia.common.world.block.BlockData; import ru.windcorp.progressia.common.world.block.BlockDataRegistry; -import ru.windcorp.progressia.common.world.block.BlockFace; +import ru.windcorp.progressia.common.world.block.AbsFace; import ru.windcorp.progressia.common.world.entity.EntityData; import ru.windcorp.progressia.common.world.tile.TileData; import ru.windcorp.progressia.common.world.tile.TileDataRegistry; @@ -64,17 +64,17 @@ public class WorldAccessor { setBlock(blockInWorld, BlockDataRegistry.getInstance().get(id)); } - public void addTile(Vec3i blockInWorld, BlockFace face, TileData tile) { + public void addTile(Vec3i blockInWorld, AbsFace face, TileData tile) { AddTile change = cache.grab(AddTile.class); change.getPacket().set(tile, blockInWorld, face); server.requestChange(change); } - public void addTile(Vec3i blockInWorld, BlockFace face, String id) { + public void addTile(Vec3i blockInWorld, AbsFace face, String id) { addTile(blockInWorld, face, TileDataRegistry.getInstance().get(id)); } - public void removeTile(Vec3i blockInWorld, BlockFace face, int tag) { + public void removeTile(Vec3i blockInWorld, AbsFace face, int tag) { RemoveTile change = cache.grab(RemoveTile.class); change.getPacket().set(blockInWorld, face, tag); server.requestChange(change); @@ -112,7 +112,7 @@ public class WorldAccessor { * @param face */ // TODO rename to something meaningful - public void triggerUpdates(Vec3i blockInWorld, BlockFace face) { + public void triggerUpdates(Vec3i blockInWorld, AbsFace face) { TileTriggeredUpdate evaluation = cache.grab(TileTriggeredUpdate.class); evaluation.init(blockInWorld, face); server.requestEvaluation(evaluation); diff --git a/src/main/java/ru/windcorp/progressia/server/world/tile/TSTickContext.java b/src/main/java/ru/windcorp/progressia/server/world/tile/TSTickContext.java index 399f7b8..0110469 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/tile/TSTickContext.java +++ b/src/main/java/ru/windcorp/progressia/server/world/tile/TSTickContext.java @@ -23,7 +23,7 @@ import java.util.function.Consumer; import java.util.function.Function; import ru.windcorp.progressia.common.world.ChunkData; -import ru.windcorp.progressia.common.world.block.BlockFace; +import ru.windcorp.progressia.common.world.block.AbsFace; import ru.windcorp.progressia.common.world.tile.TileDataStack; import ru.windcorp.progressia.server.world.ChunkLogic; import ru.windcorp.progressia.server.world.TickContextMutable; @@ -35,7 +35,7 @@ public interface TSTickContext extends BlockTickContext { * Specifications */ - BlockFace getFace(); + AbsFace getFace(); /* * Getters diff --git a/src/main/java/ru/windcorp/progressia/server/world/tile/TileLogic.java b/src/main/java/ru/windcorp/progressia/server/world/tile/TileLogic.java index 4a97ead..f10283b 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/tile/TileLogic.java +++ b/src/main/java/ru/windcorp/progressia/server/world/tile/TileLogic.java @@ -19,7 +19,7 @@ package ru.windcorp.progressia.server.world.tile; import ru.windcorp.progressia.common.util.namespaces.Namespaced; -import ru.windcorp.progressia.common.world.block.BlockFace; +import ru.windcorp.progressia.common.world.block.AbsFace; import ru.windcorp.progressia.common.world.generic.GenericTile; public class TileLogic extends Namespaced implements GenericTile { @@ -32,7 +32,7 @@ public class TileLogic extends Namespaced implements GenericTile { return canOccupyFace(context.getFace()); } - public boolean canOccupyFace(BlockFace face) { + public boolean canOccupyFace(AbsFace face) { return true; } diff --git a/src/main/java/ru/windcorp/progressia/test/ControlPlaceTileData.java b/src/main/java/ru/windcorp/progressia/test/ControlPlaceTileData.java index 5a37b6f..6df061c 100644 --- a/src/main/java/ru/windcorp/progressia/test/ControlPlaceTileData.java +++ b/src/main/java/ru/windcorp/progressia/test/ControlPlaceTileData.java @@ -20,14 +20,14 @@ package ru.windcorp.progressia.test; import glm.vec._3.i.Vec3i; import ru.windcorp.progressia.common.comms.controls.ControlData; -import ru.windcorp.progressia.common.world.block.BlockFace; +import ru.windcorp.progressia.common.world.block.AbsFace; import ru.windcorp.progressia.common.world.tile.TileData; public class ControlPlaceTileData extends ControlData { private TileData tile; private final Vec3i blockInWorld = new Vec3i(); - private BlockFace face; + private AbsFace face; public ControlPlaceTileData(String id) { super(id); @@ -41,11 +41,11 @@ public class ControlPlaceTileData extends ControlData { return blockInWorld; } - public BlockFace getFace() { + public AbsFace getFace() { return face; } - public void set(TileData block, Vec3i blockInWorld, BlockFace face) { + public void set(TileData block, Vec3i blockInWorld, AbsFace face) { this.tile = block; this.blockInWorld.set(blockInWorld.x, blockInWorld.y, blockInWorld.z); this.face = face; diff --git a/src/main/java/ru/windcorp/progressia/test/TestBlockLogicAir.java b/src/main/java/ru/windcorp/progressia/test/TestBlockLogicAir.java index e378dbf..a31f521 100644 --- a/src/main/java/ru/windcorp/progressia/test/TestBlockLogicAir.java +++ b/src/main/java/ru/windcorp/progressia/test/TestBlockLogicAir.java @@ -18,7 +18,7 @@ package ru.windcorp.progressia.test; -import ru.windcorp.progressia.common.world.block.BlockFace; +import ru.windcorp.progressia.common.world.block.AbsFace; import ru.windcorp.progressia.server.world.block.BlockLogic; public class TestBlockLogicAir extends BlockLogic { @@ -28,7 +28,7 @@ public class TestBlockLogicAir extends BlockLogic { } @Override - public boolean isSolid(BlockFace face) { + public boolean isSolid(AbsFace face) { return false; } diff --git a/src/main/java/ru/windcorp/progressia/test/TestBlockLogicGlass.java b/src/main/java/ru/windcorp/progressia/test/TestBlockLogicGlass.java index eca9e5c..f0386d6 100644 --- a/src/main/java/ru/windcorp/progressia/test/TestBlockLogicGlass.java +++ b/src/main/java/ru/windcorp/progressia/test/TestBlockLogicGlass.java @@ -18,7 +18,7 @@ package ru.windcorp.progressia.test; -import ru.windcorp.progressia.common.world.block.BlockFace; +import ru.windcorp.progressia.common.world.block.AbsFace; import ru.windcorp.progressia.server.world.block.BlockLogic; public class TestBlockLogicGlass extends BlockLogic { @@ -28,7 +28,7 @@ public class TestBlockLogicGlass extends BlockLogic { } @Override - public boolean isSolid(BlockFace face) { + public boolean isSolid(AbsFace face) { return false; } diff --git a/src/main/java/ru/windcorp/progressia/test/TestChunkCodec.java b/src/main/java/ru/windcorp/progressia/test/TestChunkCodec.java index a4f891b..82c14f7 100644 --- a/src/main/java/ru/windcorp/progressia/test/TestChunkCodec.java +++ b/src/main/java/ru/windcorp/progressia/test/TestChunkCodec.java @@ -38,7 +38,7 @@ import ru.windcorp.progressia.common.world.DecodingException; import ru.windcorp.progressia.common.world.WorldData; import ru.windcorp.progressia.common.world.block.BlockData; import ru.windcorp.progressia.common.world.block.BlockDataRegistry; -import ru.windcorp.progressia.common.world.block.BlockFace; +import ru.windcorp.progressia.common.world.block.AbsFace; import ru.windcorp.progressia.common.world.io.ChunkCodec; import ru.windcorp.progressia.common.world.tile.TileData; import ru.windcorp.progressia.common.world.tile.TileDataRegistry; @@ -138,7 +138,7 @@ public class TestChunkCodec extends ChunkCodec { break; bic.set(xOrEndMarker, input.readByte() & 0xFF, input.readByte() & 0xFF); - BlockFace face = BlockFace.getFaces().get(input.readByte() & 0xFF); + AbsFace face = AbsFace.getFaces().get(input.readByte() & 0xFF); int tiles = input.readByte() & 0xFF; diff --git a/src/main/java/ru/windcorp/progressia/test/TestContent.java b/src/main/java/ru/windcorp/progressia/test/TestContent.java index fe647f2..2f7d461 100644 --- a/src/main/java/ru/windcorp/progressia/test/TestContent.java +++ b/src/main/java/ru/windcorp/progressia/test/TestContent.java @@ -413,7 +413,7 @@ public class TestContent { ControlPlaceTileData controlData = ((ControlPlaceTileData) packet.getControl()); TileData tile = controlData.getTile(); Vec3i blockInWorld = controlData.getBlockInWorld(); - BlockFace face = controlData.getFace(); + AbsFace face = controlData.getFace(); if (server.getWorld().getData().getChunkByBlock(blockInWorld) == null) return; diff --git a/src/main/java/ru/windcorp/progressia/test/TestEntityRenderJavapony.java b/src/main/java/ru/windcorp/progressia/test/TestEntityRenderJavapony.java index aefa1c6..0b6c7a2 100644 --- a/src/main/java/ru/windcorp/progressia/test/TestEntityRenderJavapony.java +++ b/src/main/java/ru/windcorp/progressia/test/TestEntityRenderJavapony.java @@ -39,7 +39,7 @@ import ru.windcorp.progressia.client.world.entity.EntityRender; import ru.windcorp.progressia.client.world.entity.EntityRenderRegistry; import ru.windcorp.progressia.client.world.entity.EntityRenderable; import ru.windcorp.progressia.client.world.entity.QuadripedModel; -import ru.windcorp.progressia.common.world.block.BlockFace; +import ru.windcorp.progressia.common.world.block.AbsFace; import ru.windcorp.progressia.common.world.entity.EntityData; public class TestEntityRenderJavapony extends EntityRender { @@ -78,7 +78,7 @@ public class TestEntityRenderJavapony extends EntityRender { b.addStaticPart( new PppBuilder( WorldRenderProgram.getDefault(), - BlockFace.mapToFaces( + AbsFace.mapToFaces( tailStartTexture, tailStartTexture, tailStartTexture, @@ -97,7 +97,7 @@ public class TestEntityRenderJavapony extends EntityRender { b.addStaticPart( new PppBuilder( WorldRenderProgram.getDefault(), - BlockFace.mapToFaces( + AbsFace.mapToFaces( neckTexture, neckTexture, neckTexture, @@ -360,7 +360,7 @@ public class TestEntityRenderJavapony extends EntityRender { b.addPart( new PppBuilder( program, - BlockFace.mapToFaces( + AbsFace.mapToFaces( texture.get(32, 64, 0, 0), texture.get(32, 64, 0, 0), texture.get(32 + 8, 64, 16, 8), @@ -375,7 +375,7 @@ public class TestEntityRenderJavapony extends EntityRender { b.addPart( new PppBuilder( program, - BlockFace.mapToFaces( + AbsFace.mapToFaces( texture.get(32, 64, 0, 0), texture.get(32, 64, 0, 0), texture.get(32 + 12, 64 + 8, 8, 4), @@ -416,7 +416,7 @@ public class TestEntityRenderJavapony extends EntityRender { b.addPart( new PppBuilder( program, - BlockFace.mapToFaces( + AbsFace.mapToFaces( texture.get(128, 96, 16, 16), texture.get(128, 96, 16, 16), texture.get(128, 96, 16, 32), diff --git a/src/main/java/ru/windcorp/progressia/test/TestTileLogicGrass.java b/src/main/java/ru/windcorp/progressia/test/TestTileLogicGrass.java index 06afc77..9c96d16 100644 --- a/src/main/java/ru/windcorp/progressia/test/TestTileLogicGrass.java +++ b/src/main/java/ru/windcorp/progressia/test/TestTileLogicGrass.java @@ -18,7 +18,7 @@ package ru.windcorp.progressia.test; -import ru.windcorp.progressia.common.world.block.BlockFace; +import ru.windcorp.progressia.common.world.block.AbsFace; import ru.windcorp.progressia.server.world.block.BlockLogic; import ru.windcorp.progressia.server.world.block.BlockTickContext; import ru.windcorp.progressia.server.world.ticking.TickingPolicy; @@ -34,12 +34,12 @@ public class TestTileLogicGrass extends HangingTileLogic implements TickableTile @Override public boolean canOccupyFace(TileTickContext context) { - return context.getFace() != BlockFace.BOTTOM && super.canOccupyFace(context); + return context.getFace() != AbsFace.NEG_Z && super.canOccupyFace(context); } @Override - public boolean canOccupyFace(BlockFace face) { - return face != BlockFace.BOTTOM; + public boolean canOccupyFace(AbsFace face) { + return face != AbsFace.NEG_Z; } @Override @@ -64,7 +64,7 @@ public class TestTileLogicGrass extends HangingTileLogic implements TickableTile } private boolean isBlockAboveTransparent(BlockTickContext context) { - return context.evalNeighbor(BlockFace.TOP, bctxt -> { + return context.evalNeighbor(AbsFace.POS_Z, bctxt -> { BlockLogic block = bctxt.getBlock(); if (block == null) return true; diff --git a/src/main/java/ru/windcorp/progressia/test/gen/TestWorldGenerator.java b/src/main/java/ru/windcorp/progressia/test/gen/TestWorldGenerator.java index 1b35ffc..e206ebb 100644 --- a/src/main/java/ru/windcorp/progressia/test/gen/TestWorldGenerator.java +++ b/src/main/java/ru/windcorp/progressia/test/gen/TestWorldGenerator.java @@ -33,7 +33,7 @@ import ru.windcorp.progressia.common.world.WorldData; import ru.windcorp.progressia.common.world.WorldDataListener; import ru.windcorp.progressia.common.world.block.BlockData; import ru.windcorp.progressia.common.world.block.BlockDataRegistry; -import ru.windcorp.progressia.common.world.block.BlockFace; +import ru.windcorp.progressia.common.world.block.AbsFace; import ru.windcorp.progressia.common.world.tile.TileData; import ru.windcorp.progressia.common.world.tile.TileDataRegistry; import ru.windcorp.progressia.server.world.WorldLogic; @@ -238,9 +238,9 @@ public class TestWorldGenerator extends AbstractWorldGenerator { BlockData air = BlockDataRegistry.getInstance().get("Test:Air"); TileData grass = TileDataRegistry.getInstance().get("Test:Grass"); - world.getTiles(biw, BlockFace.TOP).add(grass); + world.getTiles(biw, AbsFace.POS_Z).add(grass); - for (BlockFace face : BlockFace.getFaces()) { + for (AbsFace face : AbsFace.getFaces()) { if (face.getVector().z != 0) continue; biw.add(face.getVector()); @@ -257,25 +257,25 @@ public class TestWorldGenerator extends AbstractWorldGenerator { private void addDecor(ChunkData chunk, Vec3i biw, WorldData world, Random random, boolean isDirt) { if (isDirt) { if (random.nextInt(8) == 0) { - world.getTiles(biw, BlockFace.TOP).addFarthest( + world.getTiles(biw, AbsFace.POS_Z).addFarthest( TileDataRegistry.getInstance().get("Test:Sand") ); } if (random.nextInt(8) == 0) { - world.getTiles(biw, BlockFace.TOP).addFarthest( + world.getTiles(biw, AbsFace.POS_Z).addFarthest( TileDataRegistry.getInstance().get("Test:Stones") ); } if (random.nextInt(8) == 0) { - world.getTiles(biw, BlockFace.TOP).addFarthest( + world.getTiles(biw, AbsFace.POS_Z).addFarthest( TileDataRegistry.getInstance().get("Test:YellowFlowers") ); } } else { if (random.nextInt(2) == 0) { - world.getTiles(biw, BlockFace.TOP).addFarthest( + world.getTiles(biw, AbsFace.POS_Z).addFarthest( TileDataRegistry.getInstance().get("Test:Stones") ); } @@ -300,8 +300,8 @@ public class TestWorldGenerator extends AbstractWorldGenerator { double halfChance = computeSnowHalfChance(height, grad); double opaqueChance = computeSnowOpaqueChance(height, grad); - for (BlockFace face : BlockFace.getFaces()) { - if (face == BlockFace.BOTTOM) + for (AbsFace face : AbsFace.getFaces()) { + if (face == AbsFace.NEG_Z) continue; if (face.getVector().z == 0) { From acef9d32df56214915ac10a83931c6269ba27d7e Mon Sep 17 00:00:00 2001 From: OLEGSHA Date: Mon, 1 Feb 2021 19:14:49 +0300 Subject: [PATCH 06/55] Changed packages for relations, renamed Face to ShapePart - Added BlockRelation as an abstract superclass to existing relations - Must be given an absolute "up" direction before use - Moved AbsFace, AbsRelation and BlockRelation to .world.rels - Renamed Face to ShapePart to reduce confusion with AbsFace --- .../client/graphics/flat/RenderTarget.java | 18 +-- .../client/graphics/font/SpriteTypeface.java | 14 +- .../graphics/model/BlockFaceVectors.java | 4 +- .../client/graphics/model/Shape.java | 124 +++++++++--------- .../model/{Face.java => ShapePart.java} | 12 +- .../{FaceGroup.java => ShapePartGroup.java} | 6 +- .../model/{Faces.java => ShapeParts.java} | 12 +- .../graphics/model/ShapeRenderProgram.java | 8 +- .../client/graphics/model/Shapes.java | 14 +- .../graphics/texture/ComplexTexture.java | 2 +- .../client/graphics/world/Selection.java | 2 +- .../graphics/world/WorldRenderProgram.java | 10 +- .../progressia/client/world/ChunkRender.java | 2 +- .../client/world/ChunkRenderModel.java | 2 +- .../client/world/ChunkUpdateListener.java | 2 +- .../world/block/BlockRenderOpaqueCube.java | 2 +- .../world/block/BlockRenderTexturedCube.java | 18 +-- .../block/BlockRenderTransparentCube.java | 2 +- .../world/cro/ChunkRenderOptimizer.java | 2 +- .../cro/ChunkRenderOptimizerSurface.java | 40 +++--- .../client/world/tile/TileRender.java | 2 +- .../client/world/tile/TileRenderGrass.java | 2 +- .../client/world/tile/TileRenderNone.java | 2 +- .../world/tile/TileRenderOpaqueSurface.java | 2 +- .../client/world/tile/TileRenderSurface.java | 14 +- .../tile/TileRenderTransparentSurface.java | 2 +- .../progressia/common/collision/AABBoid.java | 2 +- .../common/collision/TranslatedAABB.java | 2 +- .../collision/colliders/AABBoidCollider.java | 2 +- .../progressia/common/world/BlockRay.java | 2 +- .../progressia/common/world/ChunkData.java | 4 +- .../common/world/ChunkDataListener.java | 2 +- .../common/world/generic/GenericChunk.java | 2 +- .../world/generic/GenericTileStack.java | 2 +- .../common/world/generic/GenericWorld.java | 2 +- .../common/world/{block => rels}/AbsFace.java | 2 +- .../common/world/rels/AbsRelation.java | 76 +++++++++++ .../BlockRelation.java} | 43 +++--- .../common/world/tile/PacketAddTile.java | 2 +- .../common/world/tile/PacketAffectTile.java | 2 +- .../common/world/tile/PacketRemoveTile.java | 2 +- .../progressia/server/world/ChunkLogic.java | 2 +- .../server/world/TickAndUpdateUtil.java | 2 +- .../server/world/TickContextMutable.java | 2 +- .../server/world/UpdateTriggerer.java | 2 +- .../server/world/block/BlockLogic.java | 2 +- .../server/world/block/BlockTickContext.java | 4 +- .../world/tasks/BlockTriggeredUpdate.java | 2 +- .../server/world/tasks/TickChunk.java | 2 +- .../world/tasks/TileTriggeredUpdate.java | 2 +- .../server/world/tasks/WorldAccessor.java | 2 +- .../server/world/tile/TSTickContext.java | 2 +- .../server/world/tile/TileLogic.java | 2 +- .../progressia/test/ControlPlaceTileData.java | 2 +- .../progressia/test/TestBlockLogicAir.java | 2 +- .../progressia/test/TestBlockLogicGlass.java | 2 +- .../progressia/test/TestChunkCodec.java | 2 +- .../windcorp/progressia/test/TestContent.java | 1 + .../test/TestEntityRenderJavapony.java | 38 +++--- .../progressia/test/TestTileLogicGrass.java | 2 +- .../test/gen/TestWorldGenerator.java | 2 +- 61 files changed, 305 insertions(+), 239 deletions(-) rename src/main/java/ru/windcorp/progressia/client/graphics/model/{Face.java => ShapePart.java} (95%) rename src/main/java/ru/windcorp/progressia/client/graphics/model/{FaceGroup.java => ShapePartGroup.java} (93%) rename src/main/java/ru/windcorp/progressia/client/graphics/model/{Faces.java => ShapeParts.java} (91%) rename src/main/java/ru/windcorp/progressia/common/world/{block => rels}/AbsFace.java (98%) create mode 100644 src/main/java/ru/windcorp/progressia/common/world/rels/AbsRelation.java rename src/main/java/ru/windcorp/progressia/common/world/{block/AbsRelation.java => rels/BlockRelation.java} (76%) diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/flat/RenderTarget.java b/src/main/java/ru/windcorp/progressia/client/graphics/flat/RenderTarget.java index 1fea54e..0501897 100755 --- a/src/main/java/ru/windcorp/progressia/client/graphics/flat/RenderTarget.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/flat/RenderTarget.java @@ -29,8 +29,8 @@ import glm.vec._3.Vec3; import glm.vec._4.Vec4; import ru.windcorp.progressia.client.graphics.Colors; import ru.windcorp.progressia.client.graphics.backend.Usage; -import ru.windcorp.progressia.client.graphics.model.Face; -import ru.windcorp.progressia.client.graphics.model.Faces; +import ru.windcorp.progressia.client.graphics.model.ShapePart; +import ru.windcorp.progressia.client.graphics.model.ShapeParts; import ru.windcorp.progressia.client.graphics.model.Shape; import ru.windcorp.progressia.client.graphics.model.Renderable; import ru.windcorp.progressia.client.graphics.texture.Texture; @@ -84,7 +84,7 @@ public class RenderTarget { private final Deque maskStack = new LinkedList<>(); private final Deque transformStack = new LinkedList<>(); - private final List currentClipFaces = new ArrayList<>(); + private final List currentClipFaces = new ArrayList<>(); private int depth = 0; @@ -94,8 +94,8 @@ public class RenderTarget { protected void assembleCurrentClipFromFaces() { if (!currentClipFaces.isEmpty()) { - Face[] faces = currentClipFaces.toArray( - new Face[currentClipFaces.size()] + ShapePart[] faces = currentClipFaces.toArray( + new ShapePart[currentClipFaces.size()] ); currentClipFaces.clear(); @@ -198,7 +198,7 @@ public class RenderTarget { ); } - protected void addFaceToCurrentClip(Face face) { + protected void addFaceToCurrentClip(ShapePart face) { currentClipFaces.add(face); } @@ -270,7 +270,7 @@ public class RenderTarget { fill(Colors.toVector(color)); } - public Face createRectagleFace( + public ShapePart createRectagleFace( int x, int y, int width, @@ -280,7 +280,7 @@ public class RenderTarget { ) { float depth = this.depth--; - return Faces.createRectangle( + return ShapeParts.createRectangle( FlatRenderProgram.getDefault(), texture, color, @@ -291,7 +291,7 @@ public class RenderTarget { ); } - public Face createRectagleFace( + public ShapePart createRectagleFace( int x, int y, int width, diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/font/SpriteTypeface.java b/src/main/java/ru/windcorp/progressia/client/graphics/font/SpriteTypeface.java index 7920799..d1db43a 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/font/SpriteTypeface.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/font/SpriteTypeface.java @@ -33,8 +33,8 @@ import gnu.trove.stack.TIntStack; import gnu.trove.stack.array.TIntArrayStack; import ru.windcorp.progressia.client.graphics.Colors; import ru.windcorp.progressia.client.graphics.backend.Usage; -import ru.windcorp.progressia.client.graphics.model.Face; -import ru.windcorp.progressia.client.graphics.model.Faces; +import ru.windcorp.progressia.client.graphics.model.ShapePart; +import ru.windcorp.progressia.client.graphics.model.ShapeParts; import ru.windcorp.progressia.client.graphics.model.Shape; import ru.windcorp.progressia.client.graphics.model.ShapeRenderHelper; import ru.windcorp.progressia.client.graphics.model.ShapeRenderProgram; @@ -144,7 +144,7 @@ public abstract class SpriteTypeface extends Typeface { return new Shape( Usage.STATIC, getProgram(), - Faces.createRectangle( + ShapeParts.createRectangle( getProgram(), getTexture(c), Colors.WHITE, @@ -167,7 +167,7 @@ public abstract class SpriteTypeface extends Typeface { private final Renderable unitLine = new Shape( Usage.STATIC, getProgram(), - Faces.createRectangle( + ShapeParts.createRectangle( getProgram(), null, Vectors.UNIT_4, @@ -257,7 +257,7 @@ public abstract class SpriteTypeface extends Typeface { private class SDWorkspace extends SpriteTypeface.Workspace { - private final Collection faces = new ArrayList<>(); + private final Collection faces = new ArrayList<>(); private final Vec3 origin = new Vec3(); private final Vec3 width = new Vec3(); @@ -298,7 +298,7 @@ public abstract class SpriteTypeface extends Typeface { workspace.height.sub(workspace.origin); workspace.faces.add( - Faces.createRectangle( + ShapeParts.createRectangle( getProgram(), texture, color, @@ -314,7 +314,7 @@ public abstract class SpriteTypeface extends Typeface { return new Shape( Usage.STATIC, getProgram(), - workspace.faces.toArray(new Face[workspace.faces.size()]) + workspace.faces.toArray(new ShapePart[workspace.faces.size()]) ); } diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/model/BlockFaceVectors.java b/src/main/java/ru/windcorp/progressia/client/graphics/model/BlockFaceVectors.java index 0b07363..7d94fb2 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/model/BlockFaceVectors.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/model/BlockFaceVectors.java @@ -18,12 +18,12 @@ package ru.windcorp.progressia.client.graphics.model; -import static ru.windcorp.progressia.common.world.block.AbsFace.*; +import static ru.windcorp.progressia.common.world.rels.AbsFace.*; import com.google.common.collect.ImmutableMap; import glm.vec._3.Vec3; -import ru.windcorp.progressia.common.world.block.AbsFace; +import ru.windcorp.progressia.common.world.rels.AbsFace; class BlockFaceVectors { diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/model/Shape.java b/src/main/java/ru/windcorp/progressia/client/graphics/model/Shape.java index 145b149..d465ad2 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/model/Shape.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/model/Shape.java @@ -30,10 +30,10 @@ import ru.windcorp.progressia.client.graphics.backend.VertexBufferObject; public class Shape implements Renderable { private final ShapeRenderProgram program; - private final Face[] faces; + private final ShapePart[] parts; private final Usage usage; - private FaceGroup[] groups; + private ShapePartGroup[] groups; private ByteBuffer vertices; private ShortBuffer indices; @@ -45,33 +45,33 @@ public class Shape implements Renderable { private VertexBufferObject verticesVbo; private VertexBufferObject indicesVbo; - public Shape(Usage usage, ShapeRenderProgram program, Face... faces) { + public Shape(Usage usage, ShapeRenderProgram program, ShapePart... parts) { this.program = program; - this.faces = faces; + this.parts = parts; this.usage = usage; - configureFaces(); + configureParts(); program.preprocess(this); assembleBuffers(); } - private void configureFaces() { - for (Face face : faces) { - face.setShape(this); + private void configureParts() { + for (ShapePart part : parts) { + part.setShape(this); } } private void assembleBuffers() { // TODO optimize: only update faces that requested it - sortFaces(); + sortParts(); resizeBuffers(); - for (Face face : faces) { - assembleVertices(face); - assembleIndices(face); - face.resetUpdateFlags(); + for (ShapePart part : parts) { + assembleVertices(part); + assembleIndices(part); + part.resetUpdateFlags(); } this.vertices.flip(); @@ -85,110 +85,110 @@ public class Shape implements Renderable { private void resizeBuffers() { int verticesRequired = 0, indicesRequired = 0; - for (Face face : faces) { - verticesRequired += face.getVertices().remaining(); - indicesRequired += face.getIndices().remaining(); + for (ShapePart part : parts) { + verticesRequired += part.getVertices().remaining(); + indicesRequired += part.getIndices().remaining(); } - if (this.vertices == null || vertices.capacity() < verticesRequired) { + if (vertices == null || vertices.capacity() < verticesRequired) { this.vertices = BufferUtils.createByteBuffer(verticesRequired); } else { - this.vertices.position(0).limit(verticesRequired); + vertices.position(0).limit(verticesRequired); } - if (this.indices == null || this.indices.capacity() < indicesRequired) { + if (indices == null || indices.capacity() < indicesRequired) { this.indices = BufferUtils.createShortBuffer(indicesRequired); } else { - this.indices.position(0).limit(indicesRequired); + indices.position(0).limit(indicesRequired); } } - private void assembleVertices(Face face) { - face.locationOfVertices = this.vertices.position(); + private void assembleVertices(ShapePart part) { + part.locationOfVertices = this.vertices.position(); - insertVertices(face); - linkVerticesWith(face); + insertVertices(part); + linkVerticesWith(part); } - private void insertVertices(Face face) { - ByteBuffer faceVertices = face.getVertices(); + private void insertVertices(ShapePart part) { + ByteBuffer partVertices = part.getVertices(); - faceVertices.mark(); - this.vertices.put(faceVertices); - faceVertices.reset(); + partVertices.mark(); + this.vertices.put(partVertices); + partVertices.reset(); } - private void linkVerticesWith(Face face) { + private void linkVerticesWith(ShapePart part) { int limit = vertices.limit(); int position = vertices.position(); - vertices.limit(position).position(face.getLocationOfVertices()); - face.vertices = vertices.slice(); + vertices.limit(position).position(part.getLocationOfVertices()); + part.vertices = vertices.slice(); vertices.position(position).limit(limit); } - private void assembleIndices(Face face) { - short vertexOffset = (short) (face.getLocationOfVertices() / program.getBytesPerVertex()); + private void assembleIndices(ShapePart part) { + short vertexOffset = (short) (part.getLocationOfVertices() / program.getBytesPerVertex()); - face.locationOfIndices = indices.position(); + part.locationOfIndices = indices.position(); - ShortBuffer faceIndices = face.getIndices(); + ShortBuffer partIndices = part.getIndices(); - if (faceIndices == null) { - for (int i = 0; i < face.getVertexCount(); ++i) { + if (partIndices == null) { + for (int i = 0; i < part.getVertexCount(); ++i) { this.indices.put((short) (vertexOffset + i)); } } else { - for (int i = faceIndices.position(); i < faceIndices.limit(); ++i) { - short faceIndex = faceIndices.get(i); - faceIndex += vertexOffset; - this.indices.put(faceIndex); + for (int i = partIndices.position(); i < partIndices.limit(); ++i) { + short partIndex = partIndices.get(i); + partIndex += vertexOffset; + this.indices.put(partIndex); } } } - private void sortFaces() { - Arrays.sort(faces); + private void sortParts() { + Arrays.sort(parts); } private void assembleGroups() { - int unique = countUniqueFaces(); - this.groups = new FaceGroup[unique]; + int unique = countUniqueParts(); + this.groups = new ShapePartGroup[unique]; - if (faces.length == 0) + if (parts.length == 0) return; - int previousHandle = faces[0].getSortingIndex(); + int previousHandle = parts[0].getSortingIndex(); int start = 0; int groupIndex = 0; - for (int i = 1; i < faces.length; ++i) { - if (previousHandle != faces[i].getSortingIndex()) { + for (int i = 1; i < parts.length; ++i) { + if (previousHandle != parts[i].getSortingIndex()) { - groups[groupIndex] = new FaceGroup(faces, start, i); + groups[groupIndex] = new ShapePartGroup(parts, start, i); start = i; groupIndex++; - previousHandle = faces[i].getSortingIndex(); + previousHandle = parts[i].getSortingIndex(); } } assert groupIndex == groups.length - 1; - groups[groupIndex] = new FaceGroup(faces, start, faces.length); + groups[groupIndex] = new ShapePartGroup(parts, start, parts.length); } - private int countUniqueFaces() { - if (faces.length == 0) + private int countUniqueParts() { + if (parts.length == 0) return 0; int result = 1; - int previousHandle = faces[0].getSortingIndex(); + int previousHandle = parts[0].getSortingIndex(); - for (int i = 1; i < faces.length; ++i) { - if (previousHandle != faces[i].getSortingIndex()) { + for (int i = 1; i < parts.length; ++i) { + if (previousHandle != parts[i].getSortingIndex()) { result++; - previousHandle = faces[i].getSortingIndex(); + previousHandle = parts[i].getSortingIndex(); } } @@ -238,11 +238,11 @@ public class Shape implements Renderable { return program; } - public Face[] getFaces() { - return faces; + public ShapePart[] getParts() { + return parts; } - public FaceGroup[] getGroups() { + public ShapePartGroup[] getGroups() { return groups; } diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/model/Face.java b/src/main/java/ru/windcorp/progressia/client/graphics/model/ShapePart.java similarity index 95% rename from src/main/java/ru/windcorp/progressia/client/graphics/model/Face.java rename to src/main/java/ru/windcorp/progressia/client/graphics/model/ShapePart.java index 79da464..aef0ad9 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/model/Face.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/model/ShapePart.java @@ -24,7 +24,7 @@ import java.util.Objects; import ru.windcorp.progressia.client.graphics.texture.Texture; -public class Face implements Comparable { +public class ShapePart implements Comparable { private static final ShortBuffer GENERATE_SUCCESSIVE_LATER = null; @@ -40,7 +40,7 @@ public class Face implements Comparable { private ShortBuffer userIndices; private boolean userIndicesUpdated = true; - public Face( + public ShapePart( Texture texture, ByteBuffer vertices, ShortBuffer indices @@ -50,7 +50,7 @@ public class Face implements Comparable { setIndices(indices); } - public Face( + public ShapePart( Texture texture, ByteBuffer vertices ) { @@ -155,7 +155,7 @@ public class Face implements Comparable { return vertices; } - public Face setVertices(ByteBuffer vertices) { + public ShapePart setVertices(ByteBuffer vertices) { this.vertices = Objects.requireNonNull(vertices, "vertices"); markForVertexUpdate(); return this; @@ -202,7 +202,7 @@ public class Face implements Comparable { return userIndices.remaining(); } - public Face setIndices(ShortBuffer indices) { + public ShapePart setIndices(ShortBuffer indices) { if (indices == null) { indices = GENERATE_SUCCESSIVE_LATER; } @@ -245,7 +245,7 @@ public class Face implements Comparable { } @Override - public int compareTo(Face o) { + public int compareTo(ShapePart o) { return Integer.compare(getSortingIndex(), o.getSortingIndex()); } diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/model/FaceGroup.java b/src/main/java/ru/windcorp/progressia/client/graphics/model/ShapePartGroup.java similarity index 93% rename from src/main/java/ru/windcorp/progressia/client/graphics/model/FaceGroup.java rename to src/main/java/ru/windcorp/progressia/client/graphics/model/ShapePartGroup.java index ee91544..4f138fe 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/model/FaceGroup.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/model/ShapePartGroup.java @@ -21,13 +21,13 @@ package ru.windcorp.progressia.client.graphics.model; import ru.windcorp.progressia.client.graphics.texture.Texture; import ru.windcorp.progressia.client.graphics.texture.TexturePrimitive; -public class FaceGroup { +public class ShapePartGroup { private final TexturePrimitive texture; private final int indexCount; private final int byteOffsetOfIndices; - FaceGroup(Face[] faces, int start, int end) { + ShapePartGroup(ShapePart[] faces, int start, int end) { Texture t = faces[start].getTexture(); this.texture = t == null ? null : t.getSprite().getPrimitive(); @@ -36,7 +36,7 @@ public class FaceGroup { int indexCount = 0; for (int i = start; i < end; ++i) { - Face face = faces[i]; + ShapePart face = faces[i]; assert this.texture == null ? (face.getTexture() == null) diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/model/Faces.java b/src/main/java/ru/windcorp/progressia/client/graphics/model/ShapeParts.java similarity index 91% rename from src/main/java/ru/windcorp/progressia/client/graphics/model/Faces.java rename to src/main/java/ru/windcorp/progressia/client/graphics/model/ShapeParts.java index ff0f08f..50f744f 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/model/Faces.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/model/ShapeParts.java @@ -25,14 +25,14 @@ import glm.vec._3.Vec3; import glm.vec._4.Vec4; import ru.windcorp.progressia.client.graphics.model.ShapeRenderProgram.VertexBuilder; import ru.windcorp.progressia.client.graphics.texture.Texture; -import ru.windcorp.progressia.common.world.block.AbsFace; +import ru.windcorp.progressia.common.world.rels.AbsFace; -public class Faces { +public class ShapeParts { - private Faces() { + private ShapeParts() { } - public static Face createRectangle( + public static ShapePart createRectangle( ShapeRenderProgram program, Texture texture, Vec4 colorMultiplier, @@ -82,14 +82,14 @@ public class Faces { } ); - return new Face( + return new ShapePart( texture, builder.assemble(), buffer ); } - public static Face createBlockFace( + public static ShapePart createBlockFace( ShapeRenderProgram program, Texture texture, Vec4 colorMultiplier, diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/model/ShapeRenderProgram.java b/src/main/java/ru/windcorp/progressia/client/graphics/model/ShapeRenderProgram.java index e27bc77..6c7bdf6 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/model/ShapeRenderProgram.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/model/ShapeRenderProgram.java @@ -116,7 +116,7 @@ public class ShapeRenderProgram extends Program { try { enableAttributes(); - for (FaceGroup group : shape.getGroups()) { + for (ShapePartGroup group : shape.getGroups()) { renderFaceGroup(group); } } finally { @@ -182,7 +182,7 @@ public class ShapeRenderProgram extends Program { indices.bind(BindTarget.ELEMENT_ARRAY); } - protected void renderFaceGroup(FaceGroup group) { + protected void renderFaceGroup(ShapePartGroup group) { TexturePrimitive texture = group.getTexture(); if (texture != null) { @@ -206,12 +206,12 @@ public class ShapeRenderProgram extends Program { } public void preprocess(Shape shape) { - for (Face face : shape.getFaces()) { + for (ShapePart face : shape.getParts()) { applySprites(face); } } - private void applySprites(Face face) { + private void applySprites(ShapePart face) { if (face.getTexture() == null) return; diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/model/Shapes.java b/src/main/java/ru/windcorp/progressia/client/graphics/model/Shapes.java index 8e30d14..92d9872 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/model/Shapes.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/model/Shapes.java @@ -24,7 +24,7 @@ import glm.vec._3.Vec3; import glm.vec._4.Vec4; import ru.windcorp.progressia.client.graphics.backend.Usage; import ru.windcorp.progressia.client.graphics.texture.Texture; -import ru.windcorp.progressia.common.world.block.AbsFace; +import ru.windcorp.progressia.common.world.rels.AbsFace; public class Shapes { @@ -50,7 +50,7 @@ public class Shapes { boolean flip ) { - Face top = Faces.createRectangle( + ShapePart top = ShapeParts.createRectangle( program, topTexture, colorMultiplier, @@ -60,7 +60,7 @@ public class Shapes { flip ); - Face bottom = Faces.createRectangle( + ShapePart bottom = ShapeParts.createRectangle( program, bottomTexture, colorMultiplier, @@ -70,7 +70,7 @@ public class Shapes { flip ); - Face north = Faces.createRectangle( + ShapePart north = ShapeParts.createRectangle( program, northTexture, colorMultiplier, @@ -80,7 +80,7 @@ public class Shapes { flip ); - Face south = Faces.createRectangle( + ShapePart south = ShapeParts.createRectangle( program, southTexture, colorMultiplier, @@ -90,7 +90,7 @@ public class Shapes { flip ); - Face east = Faces.createRectangle( + ShapePart east = ShapeParts.createRectangle( program, eastTexture, colorMultiplier, @@ -100,7 +100,7 @@ public class Shapes { flip ); - Face west = Faces.createRectangle( + ShapePart west = ShapeParts.createRectangle( program, westTexture, colorMultiplier, diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/texture/ComplexTexture.java b/src/main/java/ru/windcorp/progressia/client/graphics/texture/ComplexTexture.java index 40fefbd..a54ca51 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/texture/ComplexTexture.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/texture/ComplexTexture.java @@ -21,7 +21,7 @@ package ru.windcorp.progressia.client.graphics.texture; import java.util.Map; import glm.vec._2.Vec2; -import ru.windcorp.progressia.common.world.block.AbsFace; +import ru.windcorp.progressia.common.world.rels.AbsFace; public class ComplexTexture { diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/world/Selection.java b/src/main/java/ru/windcorp/progressia/client/graphics/world/Selection.java index b4dc7dc..f3d6394 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/world/Selection.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/world/Selection.java @@ -23,8 +23,8 @@ import glm.vec._3.Vec3; import glm.vec._3.i.Vec3i; import ru.windcorp.progressia.client.world.WorldRender; import ru.windcorp.progressia.common.world.BlockRay; -import ru.windcorp.progressia.common.world.block.AbsFace; import ru.windcorp.progressia.common.world.entity.EntityData; +import ru.windcorp.progressia.common.world.rels.AbsFace; public class Selection { diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/world/WorldRenderProgram.java b/src/main/java/ru/windcorp/progressia/client/graphics/world/WorldRenderProgram.java index 5e55297..c005454 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/world/WorldRenderProgram.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/world/WorldRenderProgram.java @@ -33,7 +33,7 @@ import glm.vec._4.Vec4; import ru.windcorp.progressia.client.graphics.backend.VertexBufferObject; import ru.windcorp.progressia.client.graphics.backend.shaders.attributes.*; import ru.windcorp.progressia.client.graphics.backend.shaders.uniforms.*; -import ru.windcorp.progressia.client.graphics.model.Face; +import ru.windcorp.progressia.client.graphics.model.ShapePart; import ru.windcorp.progressia.client.graphics.model.Shape; import ru.windcorp.progressia.client.graphics.model.ShapeRenderHelper; import ru.windcorp.progressia.client.graphics.model.ShapeRenderProgram; @@ -138,12 +138,12 @@ public class WorldRenderProgram extends ShapeRenderProgram { public void preprocess(Shape shape) { super.preprocess(shape); - for (Face face : shape.getFaces()) { + for (ShapePart face : shape.getParts()) { computeNormals(face); } } - private void computeNormals(Face face) { + private void computeNormals(ShapePart face) { Vec3 a = Vectors.grab3(); Vec3 b = Vectors.grab3(); Vec3 c = Vectors.grab3(); @@ -183,7 +183,7 @@ public class WorldRenderProgram extends ShapeRenderProgram { normal.normalize(); } - private void loadVertexPosition(Face face, int index, Vec3 result) { + private void loadVertexPosition(ShapePart face, int index, Vec3 result) { ByteBuffer vertices = face.getVertices(); int offset = vertices.position() + index * getBytesPerVertex(); @@ -194,7 +194,7 @@ public class WorldRenderProgram extends ShapeRenderProgram { ); } - private void saveVertexNormal(Face face, int index, Vec3 normal) { + private void saveVertexNormal(ShapePart face, int index, Vec3 normal) { ByteBuffer vertices = face.getVertices(); int offset = vertices.position() + index * getBytesPerVertex() + (3 * Float.BYTES + 4 * Float.BYTES + diff --git a/src/main/java/ru/windcorp/progressia/client/world/ChunkRender.java b/src/main/java/ru/windcorp/progressia/client/world/ChunkRender.java index b746843..02f6dd3 100644 --- a/src/main/java/ru/windcorp/progressia/client/world/ChunkRender.java +++ b/src/main/java/ru/windcorp/progressia/client/world/ChunkRender.java @@ -30,8 +30,8 @@ import ru.windcorp.progressia.client.world.tile.TileRender; import ru.windcorp.progressia.client.world.tile.TileRenderRegistry; import ru.windcorp.progressia.client.world.tile.TileRenderStack; import ru.windcorp.progressia.common.world.ChunkData; -import ru.windcorp.progressia.common.world.block.AbsFace; import ru.windcorp.progressia.common.world.generic.GenericChunk; +import ru.windcorp.progressia.common.world.rels.AbsFace; import ru.windcorp.progressia.common.world.tile.TileDataStack; public class ChunkRender diff --git a/src/main/java/ru/windcorp/progressia/client/world/ChunkRenderModel.java b/src/main/java/ru/windcorp/progressia/client/world/ChunkRenderModel.java index 2b4ead7..1da9163 100644 --- a/src/main/java/ru/windcorp/progressia/client/world/ChunkRenderModel.java +++ b/src/main/java/ru/windcorp/progressia/client/world/ChunkRenderModel.java @@ -36,7 +36,7 @@ import ru.windcorp.progressia.client.world.tile.TileRender; import ru.windcorp.progressia.client.world.tile.TileRenderNone; import ru.windcorp.progressia.client.world.tile.TileRenderStack; import ru.windcorp.progressia.common.world.ChunkData; -import ru.windcorp.progressia.common.world.block.AbsFace; +import ru.windcorp.progressia.common.world.rels.AbsFace; public class ChunkRenderModel implements Renderable { diff --git a/src/main/java/ru/windcorp/progressia/client/world/ChunkUpdateListener.java b/src/main/java/ru/windcorp/progressia/client/world/ChunkUpdateListener.java index 9b873ee..e87e623 100644 --- a/src/main/java/ru/windcorp/progressia/client/world/ChunkUpdateListener.java +++ b/src/main/java/ru/windcorp/progressia/client/world/ChunkUpdateListener.java @@ -22,7 +22,7 @@ import glm.vec._3.i.Vec3i; import ru.windcorp.progressia.common.world.ChunkData; import ru.windcorp.progressia.common.world.ChunkDataListener; import ru.windcorp.progressia.common.world.block.BlockData; -import ru.windcorp.progressia.common.world.block.AbsFace; +import ru.windcorp.progressia.common.world.rels.AbsFace; import ru.windcorp.progressia.common.world.tile.TileData; class ChunkUpdateListener implements ChunkDataListener { diff --git a/src/main/java/ru/windcorp/progressia/client/world/block/BlockRenderOpaqueCube.java b/src/main/java/ru/windcorp/progressia/client/world/block/BlockRenderOpaqueCube.java index 7913fa8..4948206 100644 --- a/src/main/java/ru/windcorp/progressia/client/world/block/BlockRenderOpaqueCube.java +++ b/src/main/java/ru/windcorp/progressia/client/world/block/BlockRenderOpaqueCube.java @@ -19,7 +19,7 @@ package ru.windcorp.progressia.client.world.block; import ru.windcorp.progressia.client.graphics.texture.Texture; -import ru.windcorp.progressia.common.world.block.AbsFace; +import ru.windcorp.progressia.common.world.rels.AbsFace; public class BlockRenderOpaqueCube extends BlockRenderTexturedCube { diff --git a/src/main/java/ru/windcorp/progressia/client/world/block/BlockRenderTexturedCube.java b/src/main/java/ru/windcorp/progressia/client/world/block/BlockRenderTexturedCube.java index b1b41d5..918ea55 100644 --- a/src/main/java/ru/windcorp/progressia/client/world/block/BlockRenderTexturedCube.java +++ b/src/main/java/ru/windcorp/progressia/client/world/block/BlockRenderTexturedCube.java @@ -18,7 +18,7 @@ package ru.windcorp.progressia.client.world.block; -import static ru.windcorp.progressia.common.world.block.AbsFace.*; +import static ru.windcorp.progressia.common.world.rels.AbsFace.*; import java.util.HashMap; import java.util.Map; @@ -29,8 +29,8 @@ import glm.vec._3.i.Vec3i; import glm.vec._4.Vec4; import ru.windcorp.progressia.client.graphics.Colors; import ru.windcorp.progressia.client.graphics.backend.Usage; -import ru.windcorp.progressia.client.graphics.model.Face; -import ru.windcorp.progressia.client.graphics.model.Faces; +import ru.windcorp.progressia.client.graphics.model.ShapePart; +import ru.windcorp.progressia.client.graphics.model.ShapeParts; import ru.windcorp.progressia.client.graphics.model.Renderable; import ru.windcorp.progressia.client.graphics.model.Shape; import ru.windcorp.progressia.client.graphics.texture.Texture; @@ -38,7 +38,7 @@ import ru.windcorp.progressia.client.graphics.world.WorldRenderProgram; import ru.windcorp.progressia.client.world.cro.ChunkRenderOptimizerSurface.BlockOptimizedSurface; import ru.windcorp.progressia.common.util.Vectors; import ru.windcorp.progressia.common.world.ChunkData; -import ru.windcorp.progressia.common.world.block.AbsFace; +import ru.windcorp.progressia.common.world.rels.AbsFace; public abstract class BlockRenderTexturedCube extends BlockRender @@ -74,21 +74,21 @@ public abstract class BlockRenderTexturedCube } @Override - public final void getFaces( + public final void getShapeParts( ChunkData chunk, Vec3i blockInChunk, AbsFace blockFace, boolean inner, - Consumer output, + Consumer output, Vec3 offset ) { output.accept(createFace(chunk, blockInChunk, blockFace, inner, offset)); } - private Face createFace( + private ShapePart createFace( ChunkData chunk, Vec3i blockInChunk, AbsFace blockFace, boolean inner, Vec3 offset ) { - return Faces.createBlockFace( + return ShapeParts.createBlockFace( WorldRenderProgram.getDefault(), getTexture(blockFace), getColorMultiplier(blockFace), @@ -102,7 +102,7 @@ public abstract class BlockRenderTexturedCube public Renderable createRenderable(ChunkData chunk, Vec3i blockInChunk) { boolean opaque = isBlockOpaque(); - Face[] faces = new Face[BLOCK_FACE_COUNT + (opaque ? BLOCK_FACE_COUNT : 0)]; + ShapePart[] faces = new ShapePart[BLOCK_FACE_COUNT + (opaque ? BLOCK_FACE_COUNT : 0)]; for (int i = 0; i < BLOCK_FACE_COUNT; ++i) { faces[i] = createFace(chunk, blockInChunk, AbsFace.getFaces().get(i), false, Vectors.ZERO_3); diff --git a/src/main/java/ru/windcorp/progressia/client/world/block/BlockRenderTransparentCube.java b/src/main/java/ru/windcorp/progressia/client/world/block/BlockRenderTransparentCube.java index 424e4f0..9b03802 100644 --- a/src/main/java/ru/windcorp/progressia/client/world/block/BlockRenderTransparentCube.java +++ b/src/main/java/ru/windcorp/progressia/client/world/block/BlockRenderTransparentCube.java @@ -19,7 +19,7 @@ package ru.windcorp.progressia.client.world.block; import ru.windcorp.progressia.client.graphics.texture.Texture; -import ru.windcorp.progressia.common.world.block.AbsFace; +import ru.windcorp.progressia.common.world.rels.AbsFace; public class BlockRenderTransparentCube extends BlockRenderTexturedCube { diff --git a/src/main/java/ru/windcorp/progressia/client/world/cro/ChunkRenderOptimizer.java b/src/main/java/ru/windcorp/progressia/client/world/cro/ChunkRenderOptimizer.java index a42aa6f..56e7537 100644 --- a/src/main/java/ru/windcorp/progressia/client/world/cro/ChunkRenderOptimizer.java +++ b/src/main/java/ru/windcorp/progressia/client/world/cro/ChunkRenderOptimizer.java @@ -24,7 +24,7 @@ import ru.windcorp.progressia.client.world.ChunkRender; import ru.windcorp.progressia.client.world.block.BlockRender; import ru.windcorp.progressia.client.world.tile.TileRender; import ru.windcorp.progressia.common.util.namespaces.Namespaced; -import ru.windcorp.progressia.common.world.block.AbsFace; +import ru.windcorp.progressia.common.world.rels.AbsFace; /** * Chunk render optimizer (CRO) is an object that produces optimized models for diff --git a/src/main/java/ru/windcorp/progressia/client/world/cro/ChunkRenderOptimizerSurface.java b/src/main/java/ru/windcorp/progressia/client/world/cro/ChunkRenderOptimizerSurface.java index fc0bd5c..0f0eeb8 100644 --- a/src/main/java/ru/windcorp/progressia/client/world/cro/ChunkRenderOptimizerSurface.java +++ b/src/main/java/ru/windcorp/progressia/client/world/cro/ChunkRenderOptimizerSurface.java @@ -19,8 +19,8 @@ package ru.windcorp.progressia.client.world.cro; import static ru.windcorp.progressia.common.world.ChunkData.BLOCKS_PER_CHUNK; -import static ru.windcorp.progressia.common.world.block.AbsFace.BLOCK_FACE_COUNT; import static ru.windcorp.progressia.common.world.generic.GenericTileStack.TILES_PER_FACE; +import static ru.windcorp.progressia.common.world.rels.AbsFace.BLOCK_FACE_COUNT; import java.util.ArrayList; import java.util.Collection; @@ -29,7 +29,7 @@ import java.util.function.Consumer; import glm.vec._3.Vec3; import glm.vec._3.i.Vec3i; import ru.windcorp.progressia.client.graphics.backend.Usage; -import ru.windcorp.progressia.client.graphics.model.Face; +import ru.windcorp.progressia.client.graphics.model.ShapePart; import ru.windcorp.progressia.client.graphics.model.Renderable; import ru.windcorp.progressia.client.graphics.model.Shape; import ru.windcorp.progressia.client.graphics.world.WorldRenderProgram; @@ -38,7 +38,7 @@ import ru.windcorp.progressia.client.world.block.BlockRender; import ru.windcorp.progressia.client.world.tile.TileRender; import ru.windcorp.progressia.common.util.Vectors; import ru.windcorp.progressia.common.world.ChunkData; -import ru.windcorp.progressia.common.world.block.AbsFace; +import ru.windcorp.progressia.common.world.rels.AbsFace; public class ChunkRenderOptimizerSurface extends ChunkRenderOptimizer { @@ -52,26 +52,26 @@ public class ChunkRenderOptimizerSurface extends ChunkRenderOptimizer { private static interface OptimizedSurface { /** - * Creates and outputs a set of faces that correspond to this surface. - * The coordinates of the face vertices must be in chunk coordinate - * system. + * Creates and outputs a set of shape parts that correspond to this + * surface. The coordinates of the face vertices must be in chunk + * coordinate system. * * @param chunk the chunk that contains the requested face * @param blockInChunk the block in chunk * @param blockFace the requested face * @param inner whether this face should be visible from inside * ({@code true}) or outside ({@code false}) - * @param output a consumer that the created faces must be given - * to + * @param output a consumer that the created shape parts must be + * given to * @param offset an additional offset that must be applied to all * vertices */ - void getFaces( + void getShapeParts( ChunkData chunk, Vec3i blockInChunk, AbsFace blockFace, boolean inner, - Consumer output, + Consumer output, Vec3 offset /* kostyl 156% */ ); @@ -207,12 +207,12 @@ public class ChunkRenderOptimizerSurface extends ChunkRenderOptimizer { @Override public Renderable endRender() { - Collection shapeFaces = new ArrayList<>( + Collection shapeParts = new ArrayList<>( BLOCKS_PER_CHUNK * BLOCKS_PER_CHUNK * BLOCKS_PER_CHUNK * 3 ); Vec3i cursor = new Vec3i(); - Consumer consumer = shapeFaces::add; + Consumer consumer = shapeParts::add; for (cursor.x = 0; cursor.x < BLOCKS_PER_CHUNK; ++cursor.x) { for (cursor.y = 0; cursor.y < BLOCKS_PER_CHUNK; ++cursor.y) { @@ -223,27 +223,27 @@ public class ChunkRenderOptimizerSurface extends ChunkRenderOptimizer { } } - if (shapeFaces.isEmpty()) { + if (shapeParts.isEmpty()) { return null; } return new Shape( Usage.STATIC, WorldRenderProgram.getDefault(), - shapeFaces.toArray(new Face[shapeFaces.size()]) + shapeParts.toArray(new ShapePart[shapeParts.size()]) ); } private void processOuterFaces( Vec3i blockInChunk, - Consumer output + Consumer output ) { for (AbsFace blockFace : AbsFace.getFaces()) { processOuterFace(blockInChunk, blockFace, output); } } - private void processOuterFace(Vec3i blockInChunk, AbsFace blockFace, Consumer output) { + private void processOuterFace(Vec3i blockInChunk, AbsFace blockFace, Consumer output) { if (!shouldRenderOuterFace(blockInChunk, blockFace)) return; @@ -264,7 +264,7 @@ public class ChunkRenderOptimizerSurface extends ChunkRenderOptimizer { if (surface == null) continue; // layer may be BLOCK_LAYER, then block may be null - surface.getFaces(chunk.getData(), blockInChunk, blockFace, false, output, faceOrigin); + surface.getShapeParts(chunk.getData(), blockInChunk, blockFace, false, output, faceOrigin); faceOrigin.add(offset); } @@ -272,14 +272,14 @@ public class ChunkRenderOptimizerSurface extends ChunkRenderOptimizer { private void processInnerFaces( Vec3i blockInChunk, - Consumer output + Consumer output ) { for (AbsFace blockFace : AbsFace.getFaces()) { processInnerFace(blockInChunk, blockFace, output); } } - private void processInnerFace(Vec3i blockInChunk, AbsFace blockFace, Consumer output) { + private void processInnerFace(Vec3i blockInChunk, AbsFace blockFace, Consumer output) { if (!shouldRenderInnerFace(blockInChunk, blockFace)) return; @@ -300,7 +300,7 @@ public class ChunkRenderOptimizerSurface extends ChunkRenderOptimizer { if (surface == null) continue; // layer may be BLOCK_LAYER, then block may be null - surface.getFaces(chunk.getData(), blockInChunk, blockFace, true, output, faceOrigin); + surface.getShapeParts(chunk.getData(), blockInChunk, blockFace, true, output, faceOrigin); faceOrigin.add(offset); } diff --git a/src/main/java/ru/windcorp/progressia/client/world/tile/TileRender.java b/src/main/java/ru/windcorp/progressia/client/world/tile/TileRender.java index 4cef07e..52519ed 100644 --- a/src/main/java/ru/windcorp/progressia/client/world/tile/TileRender.java +++ b/src/main/java/ru/windcorp/progressia/client/world/tile/TileRender.java @@ -24,8 +24,8 @@ import ru.windcorp.progressia.client.graphics.model.Renderable; import ru.windcorp.progressia.client.world.cro.ChunkRenderOptimizer; import ru.windcorp.progressia.common.util.namespaces.Namespaced; import ru.windcorp.progressia.common.world.ChunkData; -import ru.windcorp.progressia.common.world.block.AbsFace; import ru.windcorp.progressia.common.world.generic.GenericTile; +import ru.windcorp.progressia.common.world.rels.AbsFace; public class TileRender extends Namespaced implements GenericTile { diff --git a/src/main/java/ru/windcorp/progressia/client/world/tile/TileRenderGrass.java b/src/main/java/ru/windcorp/progressia/client/world/tile/TileRenderGrass.java index 86ed0dc..1845fa6 100644 --- a/src/main/java/ru/windcorp/progressia/client/world/tile/TileRenderGrass.java +++ b/src/main/java/ru/windcorp/progressia/client/world/tile/TileRenderGrass.java @@ -19,7 +19,7 @@ package ru.windcorp.progressia.client.world.tile; import ru.windcorp.progressia.client.graphics.texture.Texture; -import ru.windcorp.progressia.common.world.block.AbsFace; +import ru.windcorp.progressia.common.world.rels.AbsFace; public class TileRenderGrass extends TileRenderSurface { diff --git a/src/main/java/ru/windcorp/progressia/client/world/tile/TileRenderNone.java b/src/main/java/ru/windcorp/progressia/client/world/tile/TileRenderNone.java index 3b3c345..fd26e8d 100644 --- a/src/main/java/ru/windcorp/progressia/client/world/tile/TileRenderNone.java +++ b/src/main/java/ru/windcorp/progressia/client/world/tile/TileRenderNone.java @@ -21,7 +21,7 @@ import glm.vec._3.i.Vec3i; import ru.windcorp.progressia.client.graphics.model.EmptyModel; import ru.windcorp.progressia.client.graphics.model.Renderable; import ru.windcorp.progressia.common.world.ChunkData; -import ru.windcorp.progressia.common.world.block.AbsFace; +import ru.windcorp.progressia.common.world.rels.AbsFace; public class TileRenderNone extends TileRender { diff --git a/src/main/java/ru/windcorp/progressia/client/world/tile/TileRenderOpaqueSurface.java b/src/main/java/ru/windcorp/progressia/client/world/tile/TileRenderOpaqueSurface.java index 62bf758..8abaa5f 100644 --- a/src/main/java/ru/windcorp/progressia/client/world/tile/TileRenderOpaqueSurface.java +++ b/src/main/java/ru/windcorp/progressia/client/world/tile/TileRenderOpaqueSurface.java @@ -19,7 +19,7 @@ package ru.windcorp.progressia.client.world.tile; import ru.windcorp.progressia.client.graphics.texture.Texture; -import ru.windcorp.progressia.common.world.block.AbsFace; +import ru.windcorp.progressia.common.world.rels.AbsFace; public class TileRenderOpaqueSurface extends TileRenderSurface { diff --git a/src/main/java/ru/windcorp/progressia/client/world/tile/TileRenderSurface.java b/src/main/java/ru/windcorp/progressia/client/world/tile/TileRenderSurface.java index 76d8fbb..3773699 100644 --- a/src/main/java/ru/windcorp/progressia/client/world/tile/TileRenderSurface.java +++ b/src/main/java/ru/windcorp/progressia/client/world/tile/TileRenderSurface.java @@ -25,8 +25,8 @@ import glm.vec._3.i.Vec3i; import glm.vec._4.Vec4; import ru.windcorp.progressia.client.graphics.Colors; import ru.windcorp.progressia.client.graphics.backend.Usage; -import ru.windcorp.progressia.client.graphics.model.Face; -import ru.windcorp.progressia.client.graphics.model.Faces; +import ru.windcorp.progressia.client.graphics.model.ShapePart; +import ru.windcorp.progressia.client.graphics.model.ShapeParts; import ru.windcorp.progressia.client.graphics.model.Shape; import ru.windcorp.progressia.client.graphics.model.Renderable; import ru.windcorp.progressia.client.graphics.texture.Texture; @@ -34,7 +34,7 @@ import ru.windcorp.progressia.client.graphics.world.WorldRenderProgram; import ru.windcorp.progressia.client.world.cro.ChunkRenderOptimizerSurface.TileOptimizedSurface; import ru.windcorp.progressia.common.util.Vectors; import ru.windcorp.progressia.common.world.ChunkData; -import ru.windcorp.progressia.common.world.block.AbsFace; +import ru.windcorp.progressia.common.world.rels.AbsFace; public abstract class TileRenderSurface extends TileRender implements TileOptimizedSurface { @@ -58,21 +58,21 @@ public abstract class TileRenderSurface extends TileRender implements TileOptimi } @Override - public final void getFaces( + public final void getShapeParts( ChunkData chunk, Vec3i blockInChunk, AbsFace blockFace, boolean inner, - Consumer output, + Consumer output, Vec3 offset ) { output.accept(createFace(chunk, blockInChunk, blockFace, inner, offset)); } - private Face createFace( + private ShapePart createFace( ChunkData chunk, Vec3i blockInChunk, AbsFace blockFace, boolean inner, Vec3 offset ) { - return Faces.createBlockFace( + return ShapeParts.createBlockFace( WorldRenderProgram.getDefault(), getTexture(blockFace), getColorMultiplier(blockFace), diff --git a/src/main/java/ru/windcorp/progressia/client/world/tile/TileRenderTransparentSurface.java b/src/main/java/ru/windcorp/progressia/client/world/tile/TileRenderTransparentSurface.java index 29a99ac..e2a2d69 100644 --- a/src/main/java/ru/windcorp/progressia/client/world/tile/TileRenderTransparentSurface.java +++ b/src/main/java/ru/windcorp/progressia/client/world/tile/TileRenderTransparentSurface.java @@ -19,7 +19,7 @@ package ru.windcorp.progressia.client.world.tile; import ru.windcorp.progressia.client.graphics.texture.Texture; -import ru.windcorp.progressia.common.world.block.AbsFace; +import ru.windcorp.progressia.common.world.rels.AbsFace; public class TileRenderTransparentSurface extends TileRenderSurface { diff --git a/src/main/java/ru/windcorp/progressia/common/collision/AABBoid.java b/src/main/java/ru/windcorp/progressia/common/collision/AABBoid.java index c22d4b6..17fffff 100644 --- a/src/main/java/ru/windcorp/progressia/common/collision/AABBoid.java +++ b/src/main/java/ru/windcorp/progressia/common/collision/AABBoid.java @@ -19,7 +19,7 @@ package ru.windcorp.progressia.common.collision; import glm.vec._3.Vec3; -import ru.windcorp.progressia.common.world.block.AbsFace; +import ru.windcorp.progressia.common.world.rels.AbsFace; public interface AABBoid extends CollisionModel { diff --git a/src/main/java/ru/windcorp/progressia/common/collision/TranslatedAABB.java b/src/main/java/ru/windcorp/progressia/common/collision/TranslatedAABB.java index 4568f75..cdc41a3 100644 --- a/src/main/java/ru/windcorp/progressia/common/collision/TranslatedAABB.java +++ b/src/main/java/ru/windcorp/progressia/common/collision/TranslatedAABB.java @@ -20,7 +20,7 @@ package ru.windcorp.progressia.common.collision; import glm.vec._3.Vec3; import ru.windcorp.progressia.common.util.Vectors; -import ru.windcorp.progressia.common.world.block.AbsFace; +import ru.windcorp.progressia.common.world.rels.AbsFace; public class TranslatedAABB implements AABBoid { diff --git a/src/main/java/ru/windcorp/progressia/common/collision/colliders/AABBoidCollider.java b/src/main/java/ru/windcorp/progressia/common/collision/colliders/AABBoidCollider.java index 28802b2..d6c31c1 100644 --- a/src/main/java/ru/windcorp/progressia/common/collision/colliders/AABBoidCollider.java +++ b/src/main/java/ru/windcorp/progressia/common/collision/colliders/AABBoidCollider.java @@ -25,7 +25,7 @@ import ru.windcorp.progressia.common.collision.colliders.Collider.ColliderWorksp import ru.windcorp.progressia.common.collision.colliders.Collider.Collision; import ru.windcorp.progressia.common.util.Matrices; import ru.windcorp.progressia.common.util.Vectors; -import ru.windcorp.progressia.common.world.block.AbsFace; +import ru.windcorp.progressia.common.world.rels.AbsFace; class AABBoidCollider { diff --git a/src/main/java/ru/windcorp/progressia/common/world/BlockRay.java b/src/main/java/ru/windcorp/progressia/common/world/BlockRay.java index 6dc4750..9f35d4c 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/BlockRay.java +++ b/src/main/java/ru/windcorp/progressia/common/world/BlockRay.java @@ -22,7 +22,7 @@ import glm.vec._3.Vec3; import glm.vec._3.i.Vec3i; import ru.windcorp.progressia.common.util.VectorUtil; import ru.windcorp.progressia.common.util.VectorUtil.Axis; -import ru.windcorp.progressia.common.world.block.AbsFace; +import ru.windcorp.progressia.common.world.rels.AbsFace; import static java.lang.Math.*; diff --git a/src/main/java/ru/windcorp/progressia/common/world/ChunkData.java b/src/main/java/ru/windcorp/progressia/common/world/ChunkData.java index 4857479..93c596d 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/ChunkData.java +++ b/src/main/java/ru/windcorp/progressia/common/world/ChunkData.java @@ -18,7 +18,7 @@ package ru.windcorp.progressia.common.world; -import static ru.windcorp.progressia.common.world.block.AbsFace.*; +import static ru.windcorp.progressia.common.world.rels.AbsFace.*; import java.util.ArrayList; import java.util.Arrays; @@ -31,8 +31,8 @@ import java.util.function.Consumer; import glm.vec._3.i.Vec3i; import ru.windcorp.progressia.common.util.VectorUtil; import ru.windcorp.progressia.common.world.block.BlockData; -import ru.windcorp.progressia.common.world.block.AbsFace; import ru.windcorp.progressia.common.world.generic.GenericChunk; +import ru.windcorp.progressia.common.world.rels.AbsFace; import ru.windcorp.progressia.common.world.tile.TileData; import ru.windcorp.progressia.common.world.tile.TileDataStack; import ru.windcorp.progressia.common.world.tile.TileReference; diff --git a/src/main/java/ru/windcorp/progressia/common/world/ChunkDataListener.java b/src/main/java/ru/windcorp/progressia/common/world/ChunkDataListener.java index 3913468..e366c93 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/ChunkDataListener.java +++ b/src/main/java/ru/windcorp/progressia/common/world/ChunkDataListener.java @@ -20,7 +20,7 @@ package ru.windcorp.progressia.common.world; import glm.vec._3.i.Vec3i; import ru.windcorp.progressia.common.world.block.BlockData; -import ru.windcorp.progressia.common.world.block.AbsFace; +import ru.windcorp.progressia.common.world.rels.AbsFace; import ru.windcorp.progressia.common.world.tile.TileData; public interface ChunkDataListener { diff --git a/src/main/java/ru/windcorp/progressia/common/world/generic/GenericChunk.java b/src/main/java/ru/windcorp/progressia/common/world/generic/GenericChunk.java index c2e9611..e9f2c50 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/generic/GenericChunk.java +++ b/src/main/java/ru/windcorp/progressia/common/world/generic/GenericChunk.java @@ -24,7 +24,7 @@ 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.world.Coordinates; -import ru.windcorp.progressia.common.world.block.AbsFace; +import ru.windcorp.progressia.common.world.rels.AbsFace; public interface GenericChunk, B extends GenericBlock, T extends GenericTile, TS extends GenericTileStack> { diff --git a/src/main/java/ru/windcorp/progressia/common/world/generic/GenericTileStack.java b/src/main/java/ru/windcorp/progressia/common/world/generic/GenericTileStack.java index 5b6ea89..9cda66c 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/generic/GenericTileStack.java +++ b/src/main/java/ru/windcorp/progressia/common/world/generic/GenericTileStack.java @@ -25,7 +25,7 @@ import java.util.function.Consumer; import glm.vec._3.i.Vec3i; import ru.windcorp.progressia.common.world.Coordinates; -import ru.windcorp.progressia.common.world.block.AbsFace; +import ru.windcorp.progressia.common.world.rels.AbsFace; public abstract class GenericTileStack, T extends GenericTile, C extends GenericChunk> extends AbstractList diff --git a/src/main/java/ru/windcorp/progressia/common/world/generic/GenericWorld.java b/src/main/java/ru/windcorp/progressia/common/world/generic/GenericWorld.java index af5ebb9..4dd3d07 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/generic/GenericWorld.java +++ b/src/main/java/ru/windcorp/progressia/common/world/generic/GenericWorld.java @@ -26,7 +26,7 @@ import glm.vec._3.Vec3; import glm.vec._3.i.Vec3i; import ru.windcorp.progressia.common.util.Vectors; import ru.windcorp.progressia.common.world.Coordinates; -import ru.windcorp.progressia.common.world.block.AbsFace; +import ru.windcorp.progressia.common.world.rels.AbsFace; public interface GenericWorld, C extends GenericChunk, E extends GenericEntity> { diff --git a/src/main/java/ru/windcorp/progressia/common/world/block/AbsFace.java b/src/main/java/ru/windcorp/progressia/common/world/rels/AbsFace.java similarity index 98% rename from src/main/java/ru/windcorp/progressia/common/world/block/AbsFace.java rename to src/main/java/ru/windcorp/progressia/common/world/rels/AbsFace.java index 06747d6..e341ad3 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/block/AbsFace.java +++ b/src/main/java/ru/windcorp/progressia/common/world/rels/AbsFace.java @@ -16,7 +16,7 @@ * along with this program. If not, see . */ -package ru.windcorp.progressia.common.world.block; +package ru.windcorp.progressia.common.world.rels; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; diff --git a/src/main/java/ru/windcorp/progressia/common/world/rels/AbsRelation.java b/src/main/java/ru/windcorp/progressia/common/world/rels/AbsRelation.java new file mode 100644 index 0000000..6744770 --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/common/world/rels/AbsRelation.java @@ -0,0 +1,76 @@ +/* + * 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.common.world.rels; + +import glm.vec._3.Vec3; +import glm.vec._3.i.Vec3i; + +public class AbsRelation extends BlockRelation { + + private final Vec3i vector = new Vec3i(); + private final Vec3 floatVector = new Vec3(); + private final Vec3 normalized = new Vec3(); + + public AbsRelation(int x, int y, int z) { + vector.set(x, y, z); + floatVector.set(x, y, z); + normalized.set(x, y, z); + + if (x != 0 || y != 0 || z != 0) { + normalized.normalize(); + } + } + + public AbsRelation(Vec3i vector) { + this(vector.x, vector.y, vector.z); + } + + @Override + public AbsRelation resolve(AbsFace up) { + return this; + } + + @Override + public Vec3i getVector(AbsFace up) { + return vector; + } + + @Override + public Vec3 getFloatVector(AbsFace up) { + return floatVector; + } + + @Override + public Vec3 getNormalized(AbsFace up) { + return normalized; + } + + public Vec3i getVector() { + return vector; + } + + public Vec3 getFloatVector() { + return floatVector; + } + + public Vec3 getNormalized() { + return normalized; + } + +} diff --git a/src/main/java/ru/windcorp/progressia/common/world/block/AbsRelation.java b/src/main/java/ru/windcorp/progressia/common/world/rels/BlockRelation.java similarity index 76% rename from src/main/java/ru/windcorp/progressia/common/world/block/AbsRelation.java rename to src/main/java/ru/windcorp/progressia/common/world/rels/BlockRelation.java index a14b4f0..c55a122 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/block/AbsRelation.java +++ b/src/main/java/ru/windcorp/progressia/common/world/rels/BlockRelation.java @@ -15,8 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - -package ru.windcorp.progressia.common.world.block; +package ru.windcorp.progressia.common.world.rels; import static java.lang.Math.abs; import static java.lang.Math.max; @@ -24,34 +23,22 @@ import static java.lang.Math.max; import glm.vec._3.Vec3; import glm.vec._3.i.Vec3i; -public class AbsRelation { +public abstract class BlockRelation { - private final Vec3i vector = new Vec3i(); - private final Vec3 floatVector = new Vec3(); - private final Vec3 normalized = new Vec3(); - - public AbsRelation(int x, int y, int z) { - vector.set(x, y, z); - floatVector.set(x, y, z); - normalized.set(x, y, z).normalize(); - } - - public AbsRelation(Vec3i vector) { - this(vector.x, vector.y, vector.z); - } - - public Vec3i getVector() { - return vector; + public abstract AbsRelation resolve(AbsFace up); + + public Vec3i getVector(AbsFace up) { + return resolve(up).getVector(); } - public Vec3 getFloatVector() { - return floatVector; + public Vec3 getFloatVector(AbsFace up) { + return resolve(up).getFloatVector(); } - - public Vec3 getNormalized() { - return normalized; + + public Vec3 getNormalized(AbsFace up) { + return resolve(up).getNormalized(); } - + /** * Returns the distance between the source and destination blocks, as * defined by the Euclidean space. Your everyday distance. @@ -59,7 +46,7 @@ public class AbsRelation { * @return square root of the sum of the squares of the coordinates */ public float getEuclideanDistance() { - return vector.length(); + return getVector(AbsFace.POS_Z).length(); } /** @@ -72,6 +59,7 @@ public class AbsRelation { * @return the sum of the absolute values of the coordinates */ public int getManhattanDistance() { + Vec3i vector = getVector(AbsFace.POS_Z); return abs(vector.x) + abs(vector.y) + abs(vector.z); } @@ -83,7 +71,8 @@ public class AbsRelation { * @return the maximum of the absolute values of the coordinates */ public int getChebyshevDistance() { + Vec3i vector = getVector(AbsFace.POS_Z); return max(abs(vector.x), max(abs(vector.y), abs(vector.z))); } - + } diff --git a/src/main/java/ru/windcorp/progressia/common/world/tile/PacketAddTile.java b/src/main/java/ru/windcorp/progressia/common/world/tile/PacketAddTile.java index 296d315..4a1e7a0 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/tile/PacketAddTile.java +++ b/src/main/java/ru/windcorp/progressia/common/world/tile/PacketAddTile.java @@ -25,7 +25,7 @@ import java.io.IOException; import glm.vec._3.i.Vec3i; import ru.windcorp.progressia.common.world.DecodingException; import ru.windcorp.progressia.common.world.WorldData; -import ru.windcorp.progressia.common.world.block.AbsFace; +import ru.windcorp.progressia.common.world.rels.AbsFace; public class PacketAddTile extends PacketAffectTile { diff --git a/src/main/java/ru/windcorp/progressia/common/world/tile/PacketAffectTile.java b/src/main/java/ru/windcorp/progressia/common/world/tile/PacketAffectTile.java index 47498b9..9be01e2 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/tile/PacketAffectTile.java +++ b/src/main/java/ru/windcorp/progressia/common/world/tile/PacketAffectTile.java @@ -26,7 +26,7 @@ import glm.vec._3.i.Vec3i; import ru.windcorp.progressia.common.world.Coordinates; import ru.windcorp.progressia.common.world.DecodingException; import ru.windcorp.progressia.common.world.PacketAffectChunk; -import ru.windcorp.progressia.common.world.block.AbsFace; +import ru.windcorp.progressia.common.world.rels.AbsFace; public abstract class PacketAffectTile extends PacketAffectChunk { diff --git a/src/main/java/ru/windcorp/progressia/common/world/tile/PacketRemoveTile.java b/src/main/java/ru/windcorp/progressia/common/world/tile/PacketRemoveTile.java index 320a916..9bb66af 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/tile/PacketRemoveTile.java +++ b/src/main/java/ru/windcorp/progressia/common/world/tile/PacketRemoveTile.java @@ -26,7 +26,7 @@ import glm.vec._3.i.Vec3i; import ru.windcorp.progressia.common.util.crash.CrashReports; import ru.windcorp.progressia.common.world.DecodingException; import ru.windcorp.progressia.common.world.WorldData; -import ru.windcorp.progressia.common.world.block.AbsFace; +import ru.windcorp.progressia.common.world.rels.AbsFace; public class PacketRemoveTile extends PacketAffectTile { diff --git a/src/main/java/ru/windcorp/progressia/server/world/ChunkLogic.java b/src/main/java/ru/windcorp/progressia/server/world/ChunkLogic.java index 420bd08..612c1b9 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/ChunkLogic.java +++ b/src/main/java/ru/windcorp/progressia/server/world/ChunkLogic.java @@ -28,8 +28,8 @@ import java.util.function.BiConsumer; import glm.vec._3.i.Vec3i; import ru.windcorp.progressia.common.world.ChunkData; import ru.windcorp.progressia.common.world.Coordinates; -import ru.windcorp.progressia.common.world.block.AbsFace; import ru.windcorp.progressia.common.world.generic.GenericChunk; +import ru.windcorp.progressia.common.world.rels.AbsFace; import ru.windcorp.progressia.common.world.tile.TileDataStack; import ru.windcorp.progressia.common.world.tile.TileReference; import ru.windcorp.progressia.server.world.block.BlockLogic; diff --git a/src/main/java/ru/windcorp/progressia/server/world/TickAndUpdateUtil.java b/src/main/java/ru/windcorp/progressia/server/world/TickAndUpdateUtil.java index ded4750..4c92990 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/TickAndUpdateUtil.java +++ b/src/main/java/ru/windcorp/progressia/server/world/TickAndUpdateUtil.java @@ -20,8 +20,8 @@ package ru.windcorp.progressia.server.world; import glm.vec._3.i.Vec3i; import ru.windcorp.progressia.common.util.crash.CrashReports; -import ru.windcorp.progressia.common.world.block.AbsFace; import ru.windcorp.progressia.common.world.entity.EntityData; +import ru.windcorp.progressia.common.world.rels.AbsFace; import ru.windcorp.progressia.server.Server; import ru.windcorp.progressia.server.world.block.BlockLogic; import ru.windcorp.progressia.server.world.block.BlockTickContext; diff --git a/src/main/java/ru/windcorp/progressia/server/world/TickContextMutable.java b/src/main/java/ru/windcorp/progressia/server/world/TickContextMutable.java index 86e75bb..6b0d789 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/TickContextMutable.java +++ b/src/main/java/ru/windcorp/progressia/server/world/TickContextMutable.java @@ -25,8 +25,8 @@ import java.util.function.Function; import glm.vec._3.i.Vec3i; import ru.windcorp.progressia.common.world.ChunkData; import ru.windcorp.progressia.common.world.Coordinates; -import ru.windcorp.progressia.common.world.block.AbsFace; import ru.windcorp.progressia.common.world.generic.GenericTileStack; +import ru.windcorp.progressia.common.world.rels.AbsFace; import ru.windcorp.progressia.common.world.tile.TileDataStack; import ru.windcorp.progressia.common.world.tile.TileReference; import ru.windcorp.progressia.server.Server; diff --git a/src/main/java/ru/windcorp/progressia/server/world/UpdateTriggerer.java b/src/main/java/ru/windcorp/progressia/server/world/UpdateTriggerer.java index 6d8bf22..2262f00 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/UpdateTriggerer.java +++ b/src/main/java/ru/windcorp/progressia/server/world/UpdateTriggerer.java @@ -23,7 +23,7 @@ import ru.windcorp.progressia.common.world.ChunkData; import ru.windcorp.progressia.common.world.ChunkDataListener; import ru.windcorp.progressia.common.world.Coordinates; import ru.windcorp.progressia.common.world.block.BlockData; -import ru.windcorp.progressia.common.world.block.AbsFace; +import ru.windcorp.progressia.common.world.rels.AbsFace; import ru.windcorp.progressia.common.world.tile.TileData; import ru.windcorp.progressia.server.Server; diff --git a/src/main/java/ru/windcorp/progressia/server/world/block/BlockLogic.java b/src/main/java/ru/windcorp/progressia/server/world/block/BlockLogic.java index 5522813..7a313c0 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/block/BlockLogic.java +++ b/src/main/java/ru/windcorp/progressia/server/world/block/BlockLogic.java @@ -19,8 +19,8 @@ package ru.windcorp.progressia.server.world.block; import ru.windcorp.progressia.common.util.namespaces.Namespaced; -import ru.windcorp.progressia.common.world.block.AbsFace; import ru.windcorp.progressia.common.world.generic.GenericBlock; +import ru.windcorp.progressia.common.world.rels.AbsFace; public class BlockLogic extends Namespaced implements GenericBlock { diff --git a/src/main/java/ru/windcorp/progressia/server/world/block/BlockTickContext.java b/src/main/java/ru/windcorp/progressia/server/world/block/BlockTickContext.java index 3f3dbc2..358fe71 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/block/BlockTickContext.java +++ b/src/main/java/ru/windcorp/progressia/server/world/block/BlockTickContext.java @@ -25,8 +25,8 @@ import java.util.function.Function; import glm.vec._3.i.Vec3i; import ru.windcorp.progressia.common.world.Coordinates; import ru.windcorp.progressia.common.world.block.BlockData; -import ru.windcorp.progressia.common.world.block.AbsFace; -import ru.windcorp.progressia.common.world.block.AbsRelation; +import ru.windcorp.progressia.common.world.rels.AbsFace; +import ru.windcorp.progressia.common.world.rels.AbsRelation; import ru.windcorp.progressia.server.world.ChunkTickContext; import ru.windcorp.progressia.server.world.TickContextMutable; import ru.windcorp.progressia.server.world.tile.TSTickContext; diff --git a/src/main/java/ru/windcorp/progressia/server/world/tasks/BlockTriggeredUpdate.java b/src/main/java/ru/windcorp/progressia/server/world/tasks/BlockTriggeredUpdate.java index 369492e..5ddd08f 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/tasks/BlockTriggeredUpdate.java +++ b/src/main/java/ru/windcorp/progressia/server/world/tasks/BlockTriggeredUpdate.java @@ -22,7 +22,7 @@ import java.util.function.Consumer; import glm.vec._3.i.Vec3i; import ru.windcorp.progressia.common.world.Coordinates; -import ru.windcorp.progressia.common.world.block.AbsFace; +import ru.windcorp.progressia.common.world.rels.AbsFace; import ru.windcorp.progressia.server.Server; import ru.windcorp.progressia.server.world.TickAndUpdateUtil; import ru.windcorp.progressia.server.world.WorldLogic; diff --git a/src/main/java/ru/windcorp/progressia/server/world/tasks/TickChunk.java b/src/main/java/ru/windcorp/progressia/server/world/tasks/TickChunk.java index 07fab12..186fa55 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/tasks/TickChunk.java +++ b/src/main/java/ru/windcorp/progressia/server/world/tasks/TickChunk.java @@ -28,7 +28,7 @@ import com.google.common.collect.ImmutableList; import glm.vec._3.i.Vec3i; import ru.windcorp.progressia.common.util.FloatMathUtil; import ru.windcorp.progressia.common.world.ChunkData; -import ru.windcorp.progressia.common.world.block.AbsFace; +import ru.windcorp.progressia.common.world.rels.AbsFace; import ru.windcorp.progressia.common.world.tile.TileDataStack; import ru.windcorp.progressia.server.Server; import ru.windcorp.progressia.server.world.ChunkLogic; diff --git a/src/main/java/ru/windcorp/progressia/server/world/tasks/TileTriggeredUpdate.java b/src/main/java/ru/windcorp/progressia/server/world/tasks/TileTriggeredUpdate.java index b69ca2b..bb9d480 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/tasks/TileTriggeredUpdate.java +++ b/src/main/java/ru/windcorp/progressia/server/world/tasks/TileTriggeredUpdate.java @@ -22,7 +22,7 @@ import java.util.function.Consumer; import glm.vec._3.i.Vec3i; import ru.windcorp.progressia.common.world.Coordinates; -import ru.windcorp.progressia.common.world.block.AbsFace; +import ru.windcorp.progressia.common.world.rels.AbsFace; import ru.windcorp.progressia.server.Server; import ru.windcorp.progressia.server.world.TickAndUpdateUtil; import ru.windcorp.progressia.server.world.WorldLogic; diff --git a/src/main/java/ru/windcorp/progressia/server/world/tasks/WorldAccessor.java b/src/main/java/ru/windcorp/progressia/server/world/tasks/WorldAccessor.java index 0b34bcf..9389b8f 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/tasks/WorldAccessor.java +++ b/src/main/java/ru/windcorp/progressia/server/world/tasks/WorldAccessor.java @@ -24,8 +24,8 @@ import glm.vec._3.i.Vec3i; import ru.windcorp.progressia.common.util.MultiLOC; import ru.windcorp.progressia.common.world.block.BlockData; import ru.windcorp.progressia.common.world.block.BlockDataRegistry; -import ru.windcorp.progressia.common.world.block.AbsFace; import ru.windcorp.progressia.common.world.entity.EntityData; +import ru.windcorp.progressia.common.world.rels.AbsFace; import ru.windcorp.progressia.common.world.tile.TileData; import ru.windcorp.progressia.common.world.tile.TileDataRegistry; import ru.windcorp.progressia.server.Server; diff --git a/src/main/java/ru/windcorp/progressia/server/world/tile/TSTickContext.java b/src/main/java/ru/windcorp/progressia/server/world/tile/TSTickContext.java index 0110469..6a670bf 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/tile/TSTickContext.java +++ b/src/main/java/ru/windcorp/progressia/server/world/tile/TSTickContext.java @@ -23,7 +23,7 @@ import java.util.function.Consumer; import java.util.function.Function; import ru.windcorp.progressia.common.world.ChunkData; -import ru.windcorp.progressia.common.world.block.AbsFace; +import ru.windcorp.progressia.common.world.rels.AbsFace; import ru.windcorp.progressia.common.world.tile.TileDataStack; import ru.windcorp.progressia.server.world.ChunkLogic; import ru.windcorp.progressia.server.world.TickContextMutable; diff --git a/src/main/java/ru/windcorp/progressia/server/world/tile/TileLogic.java b/src/main/java/ru/windcorp/progressia/server/world/tile/TileLogic.java index f10283b..c5343b0 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/tile/TileLogic.java +++ b/src/main/java/ru/windcorp/progressia/server/world/tile/TileLogic.java @@ -19,8 +19,8 @@ package ru.windcorp.progressia.server.world.tile; import ru.windcorp.progressia.common.util.namespaces.Namespaced; -import ru.windcorp.progressia.common.world.block.AbsFace; import ru.windcorp.progressia.common.world.generic.GenericTile; +import ru.windcorp.progressia.common.world.rels.AbsFace; public class TileLogic extends Namespaced implements GenericTile { diff --git a/src/main/java/ru/windcorp/progressia/test/ControlPlaceTileData.java b/src/main/java/ru/windcorp/progressia/test/ControlPlaceTileData.java index 6df061c..7944116 100644 --- a/src/main/java/ru/windcorp/progressia/test/ControlPlaceTileData.java +++ b/src/main/java/ru/windcorp/progressia/test/ControlPlaceTileData.java @@ -20,7 +20,7 @@ package ru.windcorp.progressia.test; import glm.vec._3.i.Vec3i; import ru.windcorp.progressia.common.comms.controls.ControlData; -import ru.windcorp.progressia.common.world.block.AbsFace; +import ru.windcorp.progressia.common.world.rels.AbsFace; import ru.windcorp.progressia.common.world.tile.TileData; public class ControlPlaceTileData extends ControlData { diff --git a/src/main/java/ru/windcorp/progressia/test/TestBlockLogicAir.java b/src/main/java/ru/windcorp/progressia/test/TestBlockLogicAir.java index a31f521..8fed375 100644 --- a/src/main/java/ru/windcorp/progressia/test/TestBlockLogicAir.java +++ b/src/main/java/ru/windcorp/progressia/test/TestBlockLogicAir.java @@ -18,7 +18,7 @@ package ru.windcorp.progressia.test; -import ru.windcorp.progressia.common.world.block.AbsFace; +import ru.windcorp.progressia.common.world.rels.AbsFace; import ru.windcorp.progressia.server.world.block.BlockLogic; public class TestBlockLogicAir extends BlockLogic { diff --git a/src/main/java/ru/windcorp/progressia/test/TestBlockLogicGlass.java b/src/main/java/ru/windcorp/progressia/test/TestBlockLogicGlass.java index f0386d6..3d29519 100644 --- a/src/main/java/ru/windcorp/progressia/test/TestBlockLogicGlass.java +++ b/src/main/java/ru/windcorp/progressia/test/TestBlockLogicGlass.java @@ -18,7 +18,7 @@ package ru.windcorp.progressia.test; -import ru.windcorp.progressia.common.world.block.AbsFace; +import ru.windcorp.progressia.common.world.rels.AbsFace; import ru.windcorp.progressia.server.world.block.BlockLogic; public class TestBlockLogicGlass extends BlockLogic { diff --git a/src/main/java/ru/windcorp/progressia/test/TestChunkCodec.java b/src/main/java/ru/windcorp/progressia/test/TestChunkCodec.java index 82c14f7..6a47d41 100644 --- a/src/main/java/ru/windcorp/progressia/test/TestChunkCodec.java +++ b/src/main/java/ru/windcorp/progressia/test/TestChunkCodec.java @@ -38,8 +38,8 @@ import ru.windcorp.progressia.common.world.DecodingException; import ru.windcorp.progressia.common.world.WorldData; import ru.windcorp.progressia.common.world.block.BlockData; import ru.windcorp.progressia.common.world.block.BlockDataRegistry; -import ru.windcorp.progressia.common.world.block.AbsFace; import ru.windcorp.progressia.common.world.io.ChunkCodec; +import ru.windcorp.progressia.common.world.rels.AbsFace; import ru.windcorp.progressia.common.world.tile.TileData; import ru.windcorp.progressia.common.world.tile.TileDataRegistry; diff --git a/src/main/java/ru/windcorp/progressia/test/TestContent.java b/src/main/java/ru/windcorp/progressia/test/TestContent.java index 2f7d461..9b5b28f 100644 --- a/src/main/java/ru/windcorp/progressia/test/TestContent.java +++ b/src/main/java/ru/windcorp/progressia/test/TestContent.java @@ -51,6 +51,7 @@ import ru.windcorp.progressia.common.world.GravityModelRegistry; import ru.windcorp.progressia.common.world.block.*; import ru.windcorp.progressia.common.world.entity.*; import ru.windcorp.progressia.common.world.io.ChunkIO; +import ru.windcorp.progressia.common.world.rels.AbsFace; import ru.windcorp.progressia.common.world.tile.*; import ru.windcorp.progressia.server.Server; import ru.windcorp.progressia.server.comms.controls.*; diff --git a/src/main/java/ru/windcorp/progressia/test/TestEntityRenderJavapony.java b/src/main/java/ru/windcorp/progressia/test/TestEntityRenderJavapony.java index 0b6c7a2..00c3005 100644 --- a/src/main/java/ru/windcorp/progressia/test/TestEntityRenderJavapony.java +++ b/src/main/java/ru/windcorp/progressia/test/TestEntityRenderJavapony.java @@ -25,8 +25,8 @@ import glm.vec._3.Vec3; import ru.windcorp.progressia.client.graphics.Colors; import ru.windcorp.progressia.client.graphics.backend.GraphicsInterface; import ru.windcorp.progressia.client.graphics.backend.Usage; -import ru.windcorp.progressia.client.graphics.model.Face; -import ru.windcorp.progressia.client.graphics.model.Faces; +import ru.windcorp.progressia.client.graphics.model.ShapePart; +import ru.windcorp.progressia.client.graphics.model.ShapeParts; import ru.windcorp.progressia.client.graphics.model.LambdaModel; import ru.windcorp.progressia.client.graphics.model.Renderable; import ru.windcorp.progressia.client.graphics.model.Shape; @@ -39,8 +39,8 @@ import ru.windcorp.progressia.client.world.entity.EntityRender; import ru.windcorp.progressia.client.world.entity.EntityRenderRegistry; import ru.windcorp.progressia.client.world.entity.EntityRenderable; import ru.windcorp.progressia.client.world.entity.QuadripedModel; -import ru.windcorp.progressia.common.world.block.AbsFace; import ru.windcorp.progressia.common.world.entity.EntityData; +import ru.windcorp.progressia.common.world.rels.AbsFace; public class TestEntityRenderJavapony extends EntityRender { @@ -124,11 +124,11 @@ public class TestEntityRenderJavapony extends EntityRender { private static Renderable createMainBody(ComplexTexture texture) { WorldRenderProgram program = WorldRenderProgram.getDefault(); - List faces = new ArrayList<>(); + List faces = new ArrayList<>(); // F BODY faces.add( - Faces.createRectangle( + ShapeParts.createRectangle( program, texture.get(80, 16, 32, 32), Colors.WHITE, @@ -141,7 +141,7 @@ public class TestEntityRenderJavapony extends EntityRender { // NECK BASE faces.add( - Faces.createRectangle( + ShapeParts.createRectangle( program, texture.get(80, 48, 32, 16), Colors.WHITE, @@ -154,7 +154,7 @@ public class TestEntityRenderJavapony extends EntityRender { // T BODY (BACK) faces.add( - Faces.createRectangle( + ShapeParts.createRectangle( program, texture.get(128, 0, 32, 48), Colors.WHITE, @@ -167,7 +167,7 @@ public class TestEntityRenderJavapony extends EntityRender { // BOTTOM B (upper) faces.add( - Faces.createRectangle( + ShapeParts.createRectangle( program, texture.get(144, 48, 32, 16), Colors.WHITE, @@ -180,7 +180,7 @@ public class TestEntityRenderJavapony extends EntityRender { // BOTTOM B (lower) faces.add( - Faces.createRectangle( + ShapeParts.createRectangle( program, texture.get(144, 48, 32, 16), Colors.WHITE, @@ -193,7 +193,7 @@ public class TestEntityRenderJavapony extends EntityRender { // BOTTOM B (stomach) faces.add( - Faces.createRectangle( + ShapeParts.createRectangle( program, texture.get(144, 48, 32, 16), Colors.WHITE, @@ -206,7 +206,7 @@ public class TestEntityRenderJavapony extends EntityRender { // STOMACH faces.add( - Faces.createRectangle( + ShapeParts.createRectangle( program, texture.get(224, 96, 32, 32), Colors.WHITE, @@ -219,7 +219,7 @@ public class TestEntityRenderJavapony extends EntityRender { // BOTTOM F faces.add( - Faces.createRectangle( + ShapeParts.createRectangle( program, texture.get(112, 48, 32, 16), Colors.WHITE, @@ -232,7 +232,7 @@ public class TestEntityRenderJavapony extends EntityRender { // BODY L faces.add( - Faces.createRectangle( + ShapeParts.createRectangle( program, texture.get(112, 16, 16, 32), Colors.WHITE, @@ -245,7 +245,7 @@ public class TestEntityRenderJavapony extends EntityRender { // BODY SIDES (left) faces.add( - Faces.createRectangle( + ShapeParts.createRectangle( program, texture.get(96, 96, 32, 32), Colors.WHITE, @@ -258,7 +258,7 @@ public class TestEntityRenderJavapony extends EntityRender { // QT MARK (left) faces.add( - Faces.createRectangle( + ShapeParts.createRectangle( program, texture.get(16, 96, 16, 32), Colors.WHITE, @@ -271,7 +271,7 @@ public class TestEntityRenderJavapony extends EntityRender { // BODY R faces.add( - Faces.createRectangle( + ShapeParts.createRectangle( program, texture.get(64, 16, 16, 32), Colors.WHITE, @@ -284,7 +284,7 @@ public class TestEntityRenderJavapony extends EntityRender { // BODY SIDES (right) faces.add( - Faces.createRectangle( + ShapeParts.createRectangle( program, texture.get(96, 96, 32, 32), Colors.WHITE, @@ -297,7 +297,7 @@ public class TestEntityRenderJavapony extends EntityRender { // QT MARK (right) faces.add( - Faces.createRectangle( + ShapeParts.createRectangle( program, texture.get(16, 96, 16, 32), Colors.WHITE, @@ -311,7 +311,7 @@ public class TestEntityRenderJavapony extends EntityRender { return new Shape( Usage.STATIC, program, - faces.toArray(new Face[faces.size()]) + faces.toArray(new ShapePart[faces.size()]) ); } diff --git a/src/main/java/ru/windcorp/progressia/test/TestTileLogicGrass.java b/src/main/java/ru/windcorp/progressia/test/TestTileLogicGrass.java index 9c96d16..e2141d8 100644 --- a/src/main/java/ru/windcorp/progressia/test/TestTileLogicGrass.java +++ b/src/main/java/ru/windcorp/progressia/test/TestTileLogicGrass.java @@ -18,7 +18,7 @@ package ru.windcorp.progressia.test; -import ru.windcorp.progressia.common.world.block.AbsFace; +import ru.windcorp.progressia.common.world.rels.AbsFace; import ru.windcorp.progressia.server.world.block.BlockLogic; import ru.windcorp.progressia.server.world.block.BlockTickContext; import ru.windcorp.progressia.server.world.ticking.TickingPolicy; diff --git a/src/main/java/ru/windcorp/progressia/test/gen/TestWorldGenerator.java b/src/main/java/ru/windcorp/progressia/test/gen/TestWorldGenerator.java index e206ebb..6a2f1cb 100644 --- a/src/main/java/ru/windcorp/progressia/test/gen/TestWorldGenerator.java +++ b/src/main/java/ru/windcorp/progressia/test/gen/TestWorldGenerator.java @@ -33,7 +33,7 @@ import ru.windcorp.progressia.common.world.WorldData; import ru.windcorp.progressia.common.world.WorldDataListener; import ru.windcorp.progressia.common.world.block.BlockData; import ru.windcorp.progressia.common.world.block.BlockDataRegistry; -import ru.windcorp.progressia.common.world.block.AbsFace; +import ru.windcorp.progressia.common.world.rels.AbsFace; import ru.windcorp.progressia.common.world.tile.TileData; import ru.windcorp.progressia.common.world.tile.TileDataRegistry; import ru.windcorp.progressia.server.world.WorldLogic; From 10d271059c9f197655bdd776505ef2c4c64f691f Mon Sep 17 00:00:00 2001 From: OLEGSHA Date: Tue, 2 Feb 2021 18:49:55 +0300 Subject: [PATCH 07/55] Added RelRelation and RelFace; added discrete up vector to GravityModel --- .../progressia/common/util/VectorUtil.java | 34 +++++ .../progressia/common/world/GravityModel.java | 85 ++++++++++- .../progressia/common/world/rels/AbsFace.java | 121 +++++++++++++++ .../common/world/rels/BlockRelation.java | 10 +- .../progressia/common/world/rels/RelFace.java | 124 ++++++++++++++++ .../common/world/rels/RelRelation.java | 140 ++++++++++++++++++ .../progressia/test/gen/TestGravityModel.java | 8 + 7 files changed, 513 insertions(+), 9 deletions(-) create mode 100644 src/main/java/ru/windcorp/progressia/common/world/rels/RelFace.java create mode 100644 src/main/java/ru/windcorp/progressia/common/world/rels/RelRelation.java diff --git a/src/main/java/ru/windcorp/progressia/common/util/VectorUtil.java b/src/main/java/ru/windcorp/progressia/common/util/VectorUtil.java index 1d86fce..6bef350 100644 --- a/src/main/java/ru/windcorp/progressia/common/util/VectorUtil.java +++ b/src/main/java/ru/windcorp/progressia/common/util/VectorUtil.java @@ -38,6 +38,40 @@ public class VectorUtil { public static enum Axis { X, Y, Z, W; } + + public static enum SignedAxis { + POS_X(Axis.X, +1), + NEG_X(Axis.X, -1), + POS_Y(Axis.Y, +1), + NEG_Y(Axis.Y, -1), + POS_Z(Axis.Z, +1), + NEG_Z(Axis.Z, -1), + POS_W(Axis.W, +1), + NEG_W(Axis.W, -1); + + private final Axis axis; + private final boolean isPositive; + + private SignedAxis(Axis axis, int sign) { + this.axis = axis; + this.isPositive = (sign == +1 ? true : false); + } + + /** + * @return the axis + */ + public Axis getAxis() { + return axis; + } + + public boolean isPositive() { + return isPositive; + } + + public int getSign() { + return isPositive ? +1 : -1; + } + } public static void iterateCuboid( int x0, 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 eecfc3b..14f61e9 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/GravityModel.java +++ b/src/main/java/ru/windcorp/progressia/common/world/GravityModel.java @@ -20,15 +20,33 @@ package ru.windcorp.progressia.common.world; import java.util.Objects; import glm.vec._3.Vec3; +import glm.vec._3.i.Vec3i; import ru.windcorp.progressia.common.util.crash.CrashReports; import ru.windcorp.progressia.common.util.namespaces.Namespaced; +import ru.windcorp.progressia.common.world.rels.AbsFace; /** - * Gravity model specifies the gravitational acceleration field. A gravity model - * may be queried for the vector of gravitational acceleration that should - * affect an object. This vector is, generally speaking, a function of space: - * gravity in two different locations may vary. Gravity may also be a zero - * vector. + * Gravity model specifies the gravitational acceleration field, the up + * direction field and the discrete up direction field. + *

    + * A gravity model may be queried for the vector of gravitational acceleration + * that should affect an object. This vector is, generally speaking, a function + * of space: gravity in two different locations may vary. Gravity may also be a + * zero vector. + *

    + * The vector of gravitational acceleration defines the up direction. Up vector + * is defined as the additive inverse of the normalized gravitational + * acceleration vector or {@code (0; 0; 0)} if there is no gravity. + *

    + * Separately from the gravitational acceleration and the up vectors, a + * discrete up vector field is specified by a gravity model. This field + * is defined for each chunk uniquely and may only take the value of one of the + * six {@linkplain AbsFace absolute directions}. This vector specifies the + * rotation of blocks, tiles and other objects that may not have a + * non-axis-aligned direction. Discrete up vector must be specified even for + * chunks that have a zero or an ambiguous up direction. Although discrete up + * direction is not technically linked to the up direction, is it expected by + * the players that they generally align. * * @author javapony */ @@ -77,11 +95,54 @@ public abstract class GravityModel extends Namespaced { */ public Vec3 getUp(Vec3 pos, Vec3 output) { output = getGravity(pos, output); - if (output.any()) + + if (output.any()) { output.normalize().negate(); + } + return output; } + /** + * Computes the discrete up vector for the chunk at the specified + * coordinates. + * + * @param chunkPos the coordinates of chunk to compute discrete up at + * @return an {@link AbsFace} that corresponds to the up direction in the + * specified chunk. Never {@code null}. + */ + public AbsFace getDiscreteUp(Vec3i chunkPos) { + Objects.requireNonNull(chunkPos, "chunkPos"); + + final AbsFace result; + + try { + result = doGetDiscreteUp(chunkPos); + } catch (Exception e) { + throw CrashReports.report( + e, + "%s failed to compute discrete up at (%d; %d; %d)", + this, + chunkPos.x, + chunkPos.y, + chunkPos.z + ); + } + + if (result == null) { + throw CrashReports.report( + null, + "%s has computed null as the discrete up at (%d; %d; %d). This is forbidden.", + this, + chunkPos.x, + chunkPos.y, + chunkPos.z + ); + } + + return result; + } + /** * Computes the gravitational acceleration vector at the provided location. * Actual computation of gravity is delegated to this method by the other @@ -93,4 +154,16 @@ public abstract class GravityModel extends Namespaced { */ protected abstract void doGetGravity(Vec3 pos, Vec3 output); + /** + * Computes the discrete up vector for the chunk at the specified + * coordinates. A direction must be assigned under any circumstances. Actual + * computation of discrete up is delegated to this method by the other + * methods in this class. + * + * @param chunkPos the coordinates of chunk to compute discrete up at + * @return an {@link AbsFace} that corresponds to the up direction in the + * specified chunk. Never {@code null}. + */ + protected abstract AbsFace doGetDiscreteUp(Vec3i chunkPos); + } diff --git a/src/main/java/ru/windcorp/progressia/common/world/rels/AbsFace.java b/src/main/java/ru/windcorp/progressia/common/world/rels/AbsFace.java index e341ad3..5e9db57 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/rels/AbsFace.java +++ b/src/main/java/ru/windcorp/progressia/common/world/rels/AbsFace.java @@ -18,9 +18,12 @@ package ru.windcorp.progressia.common.world.rels; +import java.util.Objects; + import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; +import glm.vec._3.Vec3; import glm.vec._3.i.Vec3i; public final class AbsFace extends AbsRelation { @@ -87,6 +90,124 @@ public final class AbsFace extends AbsRelation { .put(POS_Y, posY) .build(); } + + /** + * Rounds the provided vector to one of {@link AbsFace}s. The returned face + * is pointing in the same general direction as the provided vector. The + * result is undefined for arguments where two largest in absolute values + * coordinates are equal (e.g. for {@code (5; -5; 2)}). For a zero vector + * the result is {@code null}. Infinite vectors are handled correctly. + * + * @param vector the vector to round + * @return the face most adequately describing the provided vector, or + * {@code null} iff {@code vector.x = vector.y = vector.z = 0} + * @throws IllegalArgumentException if one of the coordinates is a NaN + */ + public static AbsFace roundToFace(Vec3 vector) { + Objects.requireNonNull(vector, "vector"); + return roundToFace(vector.x, vector.y, vector.z); + } + + /** + * Rounds the provided vector to one of {@link AbsFace}s. The returned face + * is pointing in the same general direction as the provided vector. The + * result is undefined for arguments where two largest in absolute values + * coordinates are equal (e.g. for {@code (5; -5; 2)}). For a zero vector + * the result is {@code null}. Infinite arguments are handled correctly. + * + * @param x the X coordinate + * @param y the Y coordinate + * @param z the Z coordinate + * @return the face most adequately describing the provided vector, or + * {@code null} iff {@code x = y = z = 0} + * @throws IllegalArgumentException if one of the coordinates is a NaN + */ + public static AbsFace roundToFace(float x, float y, float z) { + if (x == 0 && y == 0 && z == 0) { + return null; + } + + if (Float.isNaN(x) || Float.isNaN(y) || Float.isNaN(z)) { + throw new IllegalArgumentException("Vector contains NaN: (" + x + "; " + y + "; " + z + ")"); + } + + // The following code handles infinite x, y or z properly + + float absX = Math.abs(x); + float absY = Math.abs(y); + float absZ = Math.abs(z); + + if (absX > absY) { + if (absX > absZ) { + return x > 0 ? POS_X : NEG_X; + } else { + // Z is the answer; exit decision tree + } + } else { + if (absY > absZ) { + return y > 0 ? POS_Y : NEG_Y; + } else { + // Z is the answer; exit decision tree + } + } + + return z > 0 ? POS_Z : NEG_Z; + } + + /** + * Rounds the provided vector to one of {@link AbsFace}s. The returned face + * is pointing in the same general direction as the provided vector. The + * result is undefined for arguments where two largest in absolute values + * coordinates are equal (e.g. for {@code (5; -5; 2)}). For a zero vector + * the result is {@code null}. + * + * @param vector the vector to round + * @return the face most adequately describing the provided vector, or + * {@code null} iff {@code vector.x = vector.y = vector.z = 0} + */ + public static AbsFace roundToFace(Vec3i vector) { + Objects.requireNonNull(vector, "vector"); + return roundToFace(vector.x, vector.y, vector.z); + } + + /** + * Rounds the provided vector to one of {@link AbsFace}s. The returned face + * is pointing in the same general direction as the provided vector. The + * result is undefined for arguments where two largest in absolute values + * coordinates are equal (e.g. for {@code (5; -5; 2)}). For a zero vector + * the result is {@code null}. + * + * @param x the X coordinate + * @param y the Y coordinate + * @param z the Z coordinate + * @return the face most adequately describing the provided vector, or + * {@code null} iff {@code x = y = z = 0} + */ + public static AbsFace roundToFace(int x, int y, int z) { + if (x == 0 && y == 0 && z == 0) { + return null; + } + + int absX = Math.abs(x); + int absY = Math.abs(y); + int absZ = Math.abs(z); + + if (absX > absY) { + if (absX > absZ) { + return x > 0 ? POS_X : NEG_X; + } else { + // Z is the answer; exit decision tree + } + } else { + if (absY > absZ) { + return y > 0 ? POS_Y : NEG_Y; + } else { + // Z is the answer; exit decision tree + } + } + + return z > 0 ? POS_Z : NEG_Z; + } private static int nextId = 0; diff --git a/src/main/java/ru/windcorp/progressia/common/world/rels/BlockRelation.java b/src/main/java/ru/windcorp/progressia/common/world/rels/BlockRelation.java index c55a122..f235fc4 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/rels/BlockRelation.java +++ b/src/main/java/ru/windcorp/progressia/common/world/rels/BlockRelation.java @@ -39,6 +39,10 @@ public abstract class BlockRelation { return resolve(up).getNormalized(); } + protected Vec3i getSample() { + return getVector(AbsFace.POS_Z); + } + /** * Returns the distance between the source and destination blocks, as * defined by the Euclidean space. Your everyday distance. @@ -46,7 +50,7 @@ public abstract class BlockRelation { * @return square root of the sum of the squares of the coordinates */ public float getEuclideanDistance() { - return getVector(AbsFace.POS_Z).length(); + return getSample().length(); } /** @@ -59,7 +63,7 @@ public abstract class BlockRelation { * @return the sum of the absolute values of the coordinates */ public int getManhattanDistance() { - Vec3i vector = getVector(AbsFace.POS_Z); + Vec3i vector = getSample(); return abs(vector.x) + abs(vector.y) + abs(vector.z); } @@ -71,7 +75,7 @@ public abstract class BlockRelation { * @return the maximum of the absolute values of the coordinates */ public int getChebyshevDistance() { - Vec3i vector = getVector(AbsFace.POS_Z); + Vec3i vector = getSample(); return max(abs(vector.x), max(abs(vector.y), abs(vector.z))); } diff --git a/src/main/java/ru/windcorp/progressia/common/world/rels/RelFace.java b/src/main/java/ru/windcorp/progressia/common/world/rels/RelFace.java new file mode 100644 index 0000000..9d4b658 --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/common/world/rels/RelFace.java @@ -0,0 +1,124 @@ +/* + * 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.common.world.rels; + +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; + +import glm.vec._3.i.Vec3i; + +public class RelFace extends RelRelation { + + // @formatter:off + public static final RelFace + UP = new RelFace( 0, 0, +1, "UP"), + DOWN = new RelFace( 0, 0, -1, "DOWN"), + NORTH = new RelFace(+1, 0, 0, "NORTH"), + SOUTH = new RelFace(-1, 0, 0, "SOUTH"), + WEST = new RelFace( 0, +1, 0, "WEST"), + EAST = new RelFace( 0, -1, 0, "EAST"); + // @formatter:on + + private static final ImmutableList ALL_FACES = ImmutableList.of(UP, DOWN, NORTH, SOUTH, WEST, EAST); + + static { + link(UP, DOWN); + link(NORTH, SOUTH); + link(WEST, EAST); + } + + public static ImmutableList getFaces() { + return ALL_FACES; + } + + private static void link(RelFace a, RelFace b) { + a.counterFace = b; + b.counterFace = a; + } + + public static ImmutableMap mapToFaces( + E up, + E down, + E north, + E south, + E west, + E east + ) { + return ImmutableMap.builderWithExpectedSize(6) + .put(UP, up) + .put(DOWN, down) + .put(NORTH, north) + .put(SOUTH, south) + .put(WEST, west) + .put(EAST, east) + .build(); + } + + private static int nextId = 0; + + private final int id; + private final String name; + private RelFace counterFace; + + private RelFace(int x, int y, int z, String name) { + super(x, y, z, true); + this.id = nextId++; + this.name = name; + } + + public String getName() { + return name; + } + + /** + * @return the id + */ + public int getId() { + return id; + } + + public RelFace getCounter() { + return counterFace; + } + + public RelFace getCounterAndMoveCursor(Vec3i cursor) { + cursor.add(getVector()); + return counterFace; + } + + @Override + public float getEuclideanDistance() { + return 1.0f; + } + + @Override + public int getChebyshevDistance() { + return 1; + } + + @Override + public int getManhattanDistance() { + return 1; + } + + @Override + public String toString() { + return getName(); + } + +} diff --git a/src/main/java/ru/windcorp/progressia/common/world/rels/RelRelation.java b/src/main/java/ru/windcorp/progressia/common/world/rels/RelRelation.java new file mode 100644 index 0000000..a4d23d4 --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/common/world/rels/RelRelation.java @@ -0,0 +1,140 @@ +/* + * 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.common.world.rels; + +import java.util.Map; + +import glm.vec._3.i.Vec3i; +import ru.windcorp.progressia.common.util.VectorUtil; +import ru.windcorp.progressia.common.util.VectorUtil.SignedAxis; + +import static ru.windcorp.progressia.common.util.VectorUtil.SignedAxis.*; + +/** + * Name stands for Relative Relation + */ +public class RelRelation extends BlockRelation { + + private static class Rotation { + private final SignedAxis northDestination; + private final SignedAxis westDestination; + private final SignedAxis upDestination; + + public Rotation(SignedAxis northDestination, SignedAxis westDestination, SignedAxis upDestination) { + this.northDestination = northDestination; + this.westDestination = westDestination; + this.upDestination = upDestination; + } + + public Vec3i apply(Vec3i output, Vec3i input) { + if (output == null) { + return output; + } + + set(output, input.x, northDestination); + set(output, input.y, westDestination); + set(output, input.z, upDestination); + + return output; + } + + private static void set(Vec3i output, int value, SignedAxis axis) { + VectorUtil.set(output, axis.getAxis(), axis.isPositive() ? +value : -value); + } + } + + private final static Map TRANSFORMATIONS = AbsFace.mapToFaces( + new Rotation(POS_X, POS_Y, POS_Z), + new Rotation(POS_X, NEG_Y, NEG_Z), + new Rotation(POS_Z, NEG_Y, POS_X), + new Rotation(POS_Z, POS_Y, NEG_X), + new Rotation(POS_Z, NEG_X, NEG_Y), + new Rotation(POS_Z, POS_X, POS_Y) + ); + + private final Vec3i vector = new Vec3i(); + private AbsRelation[] resolved = null; + + public RelRelation(int north, int west, int up) { + this(north, west, up, false); + } + + protected RelRelation(int north, int west, int up, boolean precomputeAllResolutions) { + vector.set(north, west, up); + + if (precomputeAllResolutions) { + for (AbsFace face : AbsFace.getFaces()) { + resolve(face); + } + } + } + + /** + * @return the relative vector (northward, westward, upward) + */ + public Vec3i getVector() { + return vector; + } + + public int getNorthward() { + return vector.x; + } + + public int getWestward() { + return vector.y; + } + + public int getUpward() { + return vector.z; + } + + public int getSouthward() { + return -getNorthward(); + } + + public int getEastward() { + return -getWestward(); + } + + public int getDownward() { + return -getUpward(); + } + + @Override + public AbsRelation resolve(AbsFace up) { + if (resolved == null) { + resolved = new AbsRelation[AbsFace.BLOCK_FACE_COUNT]; + } + + if (resolved[up.getId()] == null) { + resolved[up.getId()] = computeResolution(up); + } + + return resolved[up.getId()]; + } + + private AbsRelation computeResolution(AbsFace up) { + return new AbsRelation(TRANSFORMATIONS.get(up).apply(new Vec3i(), vector)); + } + + @Override + protected Vec3i getSample() { + return getVector(); + } + +} 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 39e889e..24dbf2b 100644 --- a/src/main/java/ru/windcorp/progressia/test/gen/TestGravityModel.java +++ b/src/main/java/ru/windcorp/progressia/test/gen/TestGravityModel.java @@ -18,7 +18,9 @@ package ru.windcorp.progressia.test.gen; import glm.vec._3.Vec3; +import glm.vec._3.i.Vec3i; import ru.windcorp.progressia.common.world.GravityModel; +import ru.windcorp.progressia.common.world.rels.AbsFace; public class TestGravityModel extends GravityModel { @@ -37,5 +39,11 @@ public class TestGravityModel extends GravityModel { output.normalize().mul(-9.8f); } + + @Override + protected AbsFace doGetDiscreteUp(Vec3i chunkPos) { + AbsFace rounded = AbsFace.roundToFace(chunkPos.x, chunkPos.y, chunkPos.z - 54); + return rounded == null ? AbsFace.POS_Z : rounded; + } } From d3c5011063b6fd8e20a9905f747dde34dc8bc78a Mon Sep 17 00:00:00 2001 From: OLEGSHA Date: Sun, 7 Feb 2021 00:45:43 +0300 Subject: [PATCH 08/55] Replaced AbsFace with RelFace or BlockFace where appropriate - Added BlockFace - a *Face superclass - Refactored and optimized Rel{Relation, Face} - Replaced most AbsFace references with BlockFace or RelFace - Chunks now have an up direction - Determined by GravityModel's discrete up - Static; cannot change unless chunk is reloaded - Chunk models are now rendered rotated accordingly - Fixed some minor bugs that were somehow revealed by these changes - Moved TileLogicGrass to .test, where it belongs - Disabled grass despawn until a new worldgen is implemented --- .../progressia/client/world/ChunkRender.java | 13 +- .../client/world/ChunkRenderModel.java | 53 +++--- .../client/world/ChunkUpdateListener.java | 3 +- .../client/world/block/BlockRender.java | 9 +- .../world/block/BlockRenderOpaqueCube.java | 40 +++-- .../world/block/BlockRenderTexturedCube.java | 38 ++--- .../block/BlockRenderTransparentCube.java | 40 +++-- .../world/cro/ChunkRenderOptimizer.java | 30 ++-- .../cro/ChunkRenderOptimizerSurface.java | 159 +++++++++--------- .../client/world/tile/TileRender.java | 11 +- .../client/world/tile/TileRenderNone.java | 4 +- .../world/tile/TileRenderOpaqueSurface.java | 4 +- .../client/world/tile/TileRenderSurface.java | 15 +- .../tile/TileRenderTransparentSurface.java | 4 +- .../progressia/common/world/ChunkData.java | 89 ++++++---- .../common/world/ChunkDataListener.java | 4 +- .../common/world/generic/GenericChunk.java | 70 +++++++- .../world/generic/GenericTileStack.java | 4 +- .../common/world/generic/GenericWorld.java | 13 +- .../progressia/common/world/rels/AbsFace.java | 13 +- .../common/world/rels/AbsRelation.java | 12 ++ .../common/world/rels/BlockFace.java | 42 +++++ .../common/world/rels/BlockFaceResolver.java | 78 +++++++++ .../progressia/common/world/rels/RelFace.java | 24 ++- .../common/world/rels/RelRelation.java | 159 +++++++++++++++++- .../ru/windcorp/progressia/server/Server.java | 2 +- .../progressia/server/world/ChunkLogic.java | 13 +- .../server/world/ChunkTickContext.java | 5 + .../server/world/TickAndUpdateUtil.java | 24 ++- .../server/world/TickContextMutable.java | 38 +++-- .../server/world/UpdateTriggerer.java | 4 +- .../progressia/server/world/WorldLogic.java | 9 +- .../server/world/block/BlockLogic.java | 6 +- .../server/world/block/BlockTickContext.java | 14 +- .../server/world/tasks/WorldAccessor.java | 17 +- .../server/world/tile/TSTickContext.java | 6 +- .../server/world/tile/TileLogic.java | 4 +- .../progressia/test/TestBlockLogicAir.java | 4 +- .../progressia/test/TestBlockLogicGlass.java | 4 +- .../progressia/test/TestChunkCodec.java | 7 +- .../windcorp/progressia/test/TestContent.java | 5 +- .../test/TestEntityRenderJavapony.java | 18 +- .../progressia/test/TestTileLogicGrass.java | 12 +- .../TestTileRenderGrass.java} | 17 +- .../progressia/test/gen/TestGravityModel.java | 9 +- 45 files changed, 781 insertions(+), 368 deletions(-) create mode 100644 src/main/java/ru/windcorp/progressia/common/world/rels/BlockFace.java create mode 100644 src/main/java/ru/windcorp/progressia/common/world/rels/BlockFaceResolver.java rename src/main/java/ru/windcorp/progressia/{client/world/tile/TileRenderGrass.java => test/TestTileRenderGrass.java} (70%) diff --git a/src/main/java/ru/windcorp/progressia/client/world/ChunkRender.java b/src/main/java/ru/windcorp/progressia/client/world/ChunkRender.java index 02f6dd3..ca58bf7 100644 --- a/src/main/java/ru/windcorp/progressia/client/world/ChunkRender.java +++ b/src/main/java/ru/windcorp/progressia/client/world/ChunkRender.java @@ -32,6 +32,8 @@ import ru.windcorp.progressia.client.world.tile.TileRenderStack; import ru.windcorp.progressia.common.world.ChunkData; import ru.windcorp.progressia.common.world.generic.GenericChunk; import ru.windcorp.progressia.common.world.rels.AbsFace; +import ru.windcorp.progressia.common.world.rels.BlockFace; +import ru.windcorp.progressia.common.world.rels.RelFace; import ru.windcorp.progressia.common.world.tile.TileDataStack; public class ChunkRender @@ -55,6 +57,11 @@ public class ChunkRender public Vec3i getPosition() { return getData().getPosition(); } + + @Override + public AbsFace getUp() { + return getData().getUp(); + } @Override public BlockRender getBlock(Vec3i posInChunk) { @@ -64,12 +71,12 @@ public class ChunkRender } @Override - public TileRenderStack getTiles(Vec3i blockInChunk, AbsFace face) { + public TileRenderStack getTiles(Vec3i blockInChunk, BlockFace face) { return getTileStackWrapper(getData().getTiles(blockInChunk, face)); } @Override - public boolean hasTiles(Vec3i blockInChunk, AbsFace face) { + public boolean hasTiles(Vec3i blockInChunk, BlockFace face) { return getData().hasTiles(blockInChunk, face); } @@ -119,7 +126,7 @@ public class ChunkRender } @Override - public AbsFace getFace() { + public RelFace getFace() { return parent.getFace(); } diff --git a/src/main/java/ru/windcorp/progressia/client/world/ChunkRenderModel.java b/src/main/java/ru/windcorp/progressia/client/world/ChunkRenderModel.java index 1da9163..471fb92 100644 --- a/src/main/java/ru/windcorp/progressia/client/world/ChunkRenderModel.java +++ b/src/main/java/ru/windcorp/progressia/client/world/ChunkRenderModel.java @@ -36,7 +36,8 @@ import ru.windcorp.progressia.client.world.tile.TileRender; import ru.windcorp.progressia.client.world.tile.TileRenderNone; import ru.windcorp.progressia.client.world.tile.TileRenderStack; import ru.windcorp.progressia.common.world.ChunkData; -import ru.windcorp.progressia.common.world.rels.AbsFace; +import ru.windcorp.progressia.common.world.rels.RelFace; +import ru.windcorp.progressia.common.world.rels.RelRelation; public class ChunkRenderModel implements Renderable { @@ -53,11 +54,15 @@ public class ChunkRenderModel implements Renderable { public void render(ShapeRenderHelper renderer) { if (model == null) return; + float offset = ChunkData.BLOCKS_PER_CHUNK / 2 - 0.5f; + renderer.pushTransform().translate( chunk.getX() * ChunkData.BLOCKS_PER_CHUNK, chunk.getY() * ChunkData.BLOCKS_PER_CHUNK, chunk.getZ() * ChunkData.BLOCKS_PER_CHUNK - ); + ).translate(offset, offset, offset) + .mul(RelRelation.getResolutionMatrix4(chunk.getUp())) + .translate(-offset, -offset, -offset); model.render(renderer); @@ -71,8 +76,8 @@ public class ChunkRenderModel implements Renderable { optimizers.forEach(ChunkRenderOptimizer::startRender); - chunk.forEachBiC(blockInChunk -> { - processBlockAndTiles(blockInChunk, sink); + chunk.forEachBiC(relBlockInChunk -> { + processBlockAndTiles(relBlockInChunk, sink); }); for (ChunkRenderOptimizer optimizer : optimizers) { @@ -96,16 +101,16 @@ public class ChunkRenderModel implements Renderable { } } - private void processBlockAndTiles(Vec3i blockInChunk, Builder sink) { - processBlock(blockInChunk, sink); + private void processBlockAndTiles(Vec3i relBlockInChunk, Builder sink) { + processBlock(relBlockInChunk, sink); - for (AbsFace face : AbsFace.getFaces()) { - processTileStack(blockInChunk, face, sink); + for (RelFace face : RelFace.getFaces()) { + processTileStack(relBlockInChunk, face, sink); } } - private void processBlock(Vec3i blockInChunk, Builder sink) { - BlockRender block = chunk.getBlock(blockInChunk); + private void processBlock(Vec3i relBlockInChunk, Builder sink) { + BlockRender block = chunk.getBlockRel(relBlockInChunk); if (block instanceof BlockRenderNone) { return; @@ -113,48 +118,48 @@ public class ChunkRenderModel implements Renderable { if (block.needsOwnRenderable()) { sink.addPart( - block.createRenderable(chunk.getData(), blockInChunk), - new Mat4().identity().translate(blockInChunk.x, blockInChunk.y, blockInChunk.z) + block.createRenderable(chunk.getData(), relBlockInChunk), + new Mat4().identity().translate(relBlockInChunk.x, relBlockInChunk.y, relBlockInChunk.z) ); } - processBlockWithCROs(block, blockInChunk); + processBlockWithCROs(block, relBlockInChunk); } - private void processBlockWithCROs(BlockRender block, Vec3i blockInChunk) { + private void processBlockWithCROs(BlockRender block, Vec3i relBlockInChunk) { for (ChunkRenderOptimizer optimizer : optimizers) { - optimizer.addBlock(block, blockInChunk); + optimizer.addBlock(block, relBlockInChunk); } } - private void processTileStack(Vec3i blockInChunk, AbsFace face, Builder sink) { - TileRenderStack trs = chunk.getTilesOrNull(blockInChunk, face); + private void processTileStack(Vec3i relBlockInChunk, RelFace face, Builder sink) { + TileRenderStack trs = chunk.getTilesOrNullRel(relBlockInChunk, face); if (trs == null || trs.isEmpty()) { return; } - trs.forEach(tile -> processTile(tile, blockInChunk, face, sink)); + trs.forEach(tile -> processTile(tile, relBlockInChunk, face, sink)); } - private void processTile(TileRender tile, Vec3i blockInChunk, AbsFace face, Builder sink) { + private void processTile(TileRender tile, Vec3i relBlockInChunk, RelFace face, Builder sink) { if (tile instanceof TileRenderNone) { return; } if (tile.needsOwnRenderable()) { sink.addPart( - tile.createRenderable(chunk.getData(), blockInChunk, face), - new Mat4().identity().translate(blockInChunk.x, blockInChunk.y, blockInChunk.z) + tile.createRenderable(chunk.getData(), relBlockInChunk, face), + new Mat4().identity().translate(relBlockInChunk.x, relBlockInChunk.y, relBlockInChunk.z) ); } - processTileWithCROs(tile, blockInChunk, face); + processTileWithCROs(tile, relBlockInChunk, face); } - private void processTileWithCROs(TileRender tile, Vec3i blockInChunk, AbsFace face) { + private void processTileWithCROs(TileRender tile, Vec3i relBlockInChunk, RelFace face) { for (ChunkRenderOptimizer optimizer : optimizers) { - optimizer.addTile(tile, blockInChunk, face); + optimizer.addTile(tile, relBlockInChunk, face); } } diff --git a/src/main/java/ru/windcorp/progressia/client/world/ChunkUpdateListener.java b/src/main/java/ru/windcorp/progressia/client/world/ChunkUpdateListener.java index e87e623..37ea0ba 100644 --- a/src/main/java/ru/windcorp/progressia/client/world/ChunkUpdateListener.java +++ b/src/main/java/ru/windcorp/progressia/client/world/ChunkUpdateListener.java @@ -23,6 +23,7 @@ import ru.windcorp.progressia.common.world.ChunkData; import ru.windcorp.progressia.common.world.ChunkDataListener; import ru.windcorp.progressia.common.world.block.BlockData; import ru.windcorp.progressia.common.world.rels.AbsFace; +import ru.windcorp.progressia.common.world.rels.RelFace; import ru.windcorp.progressia.common.world.tile.TileData; class ChunkUpdateListener implements ChunkDataListener { @@ -57,7 +58,7 @@ class ChunkUpdateListener implements ChunkDataListener { public void onChunkTilesChanged( ChunkData chunk, Vec3i blockInChunk, - AbsFace face, + RelFace face, TileData tile, boolean wasAdded ) { diff --git a/src/main/java/ru/windcorp/progressia/client/world/block/BlockRender.java b/src/main/java/ru/windcorp/progressia/client/world/block/BlockRender.java index d350fa8..2a3c8e1 100644 --- a/src/main/java/ru/windcorp/progressia/client/world/block/BlockRender.java +++ b/src/main/java/ru/windcorp/progressia/client/world/block/BlockRender.java @@ -18,7 +18,6 @@ package ru.windcorp.progressia.client.world.block; -import ru.windcorp.progressia.client.graphics.model.ShapeRenderHelper; import ru.windcorp.progressia.common.util.namespaces.Namespaced; import ru.windcorp.progressia.common.world.ChunkData; import ru.windcorp.progressia.common.world.generic.GenericBlock; @@ -31,13 +30,7 @@ public abstract class BlockRender extends Namespaced implements GenericBlock { super(id); } - public void render(ShapeRenderHelper renderer) { - throw new UnsupportedOperationException( - "BlockRender.render() not implemented in " + this - ); - } - - public Renderable createRenderable(ChunkData chunk, Vec3i blockInChunk) { + public Renderable createRenderable(ChunkData chunk, Vec3i relBlockInChunk) { return null; } diff --git a/src/main/java/ru/windcorp/progressia/client/world/block/BlockRenderOpaqueCube.java b/src/main/java/ru/windcorp/progressia/client/world/block/BlockRenderOpaqueCube.java index 4948206..01a6011 100644 --- a/src/main/java/ru/windcorp/progressia/client/world/block/BlockRenderOpaqueCube.java +++ b/src/main/java/ru/windcorp/progressia/client/world/block/BlockRenderOpaqueCube.java @@ -19,27 +19,27 @@ package ru.windcorp.progressia.client.world.block; import ru.windcorp.progressia.client.graphics.texture.Texture; -import ru.windcorp.progressia.common.world.rels.AbsFace; +import ru.windcorp.progressia.common.world.rels.RelFace; public class BlockRenderOpaqueCube extends BlockRenderTexturedCube { public BlockRenderOpaqueCube( String id, - Texture posZTexture, - Texture negZTexture, - Texture posXTexture, - Texture negXTexture, - Texture negYTexture, - Texture posYTexture + Texture topTexture, + Texture bottomTexture, + Texture northTexture, + Texture southTexture, + Texture westTexture, + Texture eastTexture ) { super( id, - posZTexture, - negZTexture, - posXTexture, - negXTexture, - negYTexture, - posYTexture + topTexture, + bottomTexture, + northTexture, + southTexture, + westTexture, + eastTexture ); } @@ -54,9 +54,21 @@ public class BlockRenderOpaqueCube extends BlockRenderTexturedCube { texture ); } + + public BlockRenderOpaqueCube(String id, Texture topTexture, Texture bottomTexture, Texture sideTexture) { + this( + id, + topTexture, + bottomTexture, + sideTexture, + sideTexture, + sideTexture, + sideTexture + ); + } @Override - public boolean isOpaque(AbsFace face) { + public boolean isOpaque(RelFace face) { return true; } diff --git a/src/main/java/ru/windcorp/progressia/client/world/block/BlockRenderTexturedCube.java b/src/main/java/ru/windcorp/progressia/client/world/block/BlockRenderTexturedCube.java index 918ea55..6ed7ef7 100644 --- a/src/main/java/ru/windcorp/progressia/client/world/block/BlockRenderTexturedCube.java +++ b/src/main/java/ru/windcorp/progressia/client/world/block/BlockRenderTexturedCube.java @@ -20,7 +20,6 @@ package ru.windcorp.progressia.client.world.block; import static ru.windcorp.progressia.common.world.rels.AbsFace.*; -import java.util.HashMap; import java.util.Map; import java.util.function.Consumer; @@ -39,43 +38,38 @@ import ru.windcorp.progressia.client.world.cro.ChunkRenderOptimizerSurface.Block import ru.windcorp.progressia.common.util.Vectors; import ru.windcorp.progressia.common.world.ChunkData; import ru.windcorp.progressia.common.world.rels.AbsFace; +import ru.windcorp.progressia.common.world.rels.RelFace; public abstract class BlockRenderTexturedCube extends BlockRender implements BlockOptimizedSurface { - private final Map textures = new HashMap<>(); + private final Map textures; public BlockRenderTexturedCube( String id, - Texture posZTexture, - Texture negZTexture, - Texture posXTexture, - Texture negXTexture, - Texture negYTexture, - Texture posYTexture + Texture topTexture, + Texture bottomTexture, + Texture northTexture, + Texture southTexture, + Texture westTexture, + Texture eastTexture ) { super(id); - - textures.put(POS_Z, posZTexture); - textures.put(NEG_Z, negZTexture); - textures.put(POS_X, posXTexture); - textures.put(NEG_X, negXTexture); - textures.put(NEG_Y, negYTexture); - textures.put(POS_Y, posYTexture); + this.textures = RelFace.mapToFaces(topTexture, bottomTexture, northTexture, southTexture, westTexture, eastTexture); } - public Texture getTexture(AbsFace blockFace) { + public Texture getTexture(RelFace blockFace) { return textures.get(blockFace); } - public Vec4 getColorMultiplier(AbsFace blockFace) { + public Vec4 getColorMultiplier(RelFace blockFace) { return Colors.WHITE; } @Override public final void getShapeParts( - ChunkData chunk, Vec3i blockInChunk, AbsFace blockFace, + ChunkData chunk, Vec3i blockInChunk, RelFace blockFace, boolean inner, Consumer output, Vec3 offset @@ -84,7 +78,7 @@ public abstract class BlockRenderTexturedCube } private ShapePart createFace( - ChunkData chunk, Vec3i blockInChunk, AbsFace blockFace, + ChunkData chunk, Vec3i blockInChunk, RelFace blockFace, boolean inner, Vec3 offset ) { @@ -93,7 +87,7 @@ public abstract class BlockRenderTexturedCube getTexture(blockFace), getColorMultiplier(blockFace), offset, - blockFace, + blockFace.resolve(AbsFace.POS_Z), inner ); } @@ -105,12 +99,12 @@ public abstract class BlockRenderTexturedCube ShapePart[] faces = new ShapePart[BLOCK_FACE_COUNT + (opaque ? BLOCK_FACE_COUNT : 0)]; for (int i = 0; i < BLOCK_FACE_COUNT; ++i) { - faces[i] = createFace(chunk, blockInChunk, AbsFace.getFaces().get(i), false, Vectors.ZERO_3); + faces[i] = createFace(chunk, blockInChunk, RelFace.getFaces().get(i), false, Vectors.ZERO_3); } if (!opaque) { for (int i = 0; i < BLOCK_FACE_COUNT; ++i) { - faces[i + BLOCK_FACE_COUNT] = createFace(chunk, blockInChunk, AbsFace.getFaces().get(i), true, Vectors.ZERO_3); + faces[i + BLOCK_FACE_COUNT] = createFace(chunk, blockInChunk, RelFace.getFaces().get(i), true, Vectors.ZERO_3); } } diff --git a/src/main/java/ru/windcorp/progressia/client/world/block/BlockRenderTransparentCube.java b/src/main/java/ru/windcorp/progressia/client/world/block/BlockRenderTransparentCube.java index 9b03802..f9801ca 100644 --- a/src/main/java/ru/windcorp/progressia/client/world/block/BlockRenderTransparentCube.java +++ b/src/main/java/ru/windcorp/progressia/client/world/block/BlockRenderTransparentCube.java @@ -19,27 +19,27 @@ package ru.windcorp.progressia.client.world.block; import ru.windcorp.progressia.client.graphics.texture.Texture; -import ru.windcorp.progressia.common.world.rels.AbsFace; +import ru.windcorp.progressia.common.world.rels.RelFace; public class BlockRenderTransparentCube extends BlockRenderTexturedCube { public BlockRenderTransparentCube( String id, - Texture posZTexture, - Texture negZTexture, - Texture posXTexture, - Texture negXTexture, - Texture negYTexture, - Texture posYTexture + Texture topTexture, + Texture bottomTexture, + Texture northTexture, + Texture southTexture, + Texture westTexture, + Texture eastTexture ) { super( id, - posZTexture, - negZTexture, - posXTexture, - negXTexture, - negYTexture, - posYTexture + topTexture, + bottomTexture, + northTexture, + southTexture, + westTexture, + eastTexture ); } @@ -54,9 +54,21 @@ public class BlockRenderTransparentCube extends BlockRenderTexturedCube { texture ); } + + public BlockRenderTransparentCube(String id, Texture topTexture, Texture bottomTexture, Texture sideTexture) { + this( + id, + topTexture, + bottomTexture, + sideTexture, + sideTexture, + sideTexture, + sideTexture + ); + } @Override - public boolean isOpaque(AbsFace face) { + public boolean isOpaque(RelFace face) { return false; } diff --git a/src/main/java/ru/windcorp/progressia/client/world/cro/ChunkRenderOptimizer.java b/src/main/java/ru/windcorp/progressia/client/world/cro/ChunkRenderOptimizer.java index 56e7537..12396dc 100644 --- a/src/main/java/ru/windcorp/progressia/client/world/cro/ChunkRenderOptimizer.java +++ b/src/main/java/ru/windcorp/progressia/client/world/cro/ChunkRenderOptimizer.java @@ -24,7 +24,7 @@ import ru.windcorp.progressia.client.world.ChunkRender; import ru.windcorp.progressia.client.world.block.BlockRender; import ru.windcorp.progressia.client.world.tile.TileRender; import ru.windcorp.progressia.common.util.namespaces.Namespaced; -import ru.windcorp.progressia.common.world.rels.AbsFace; +import ru.windcorp.progressia.common.world.rels.RelFace; /** * Chunk render optimizer (CRO) is an object that produces optimized models for @@ -35,6 +35,12 @@ import ru.windcorp.progressia.common.world.rels.AbsFace; * tiles. An example of a CRO is {@link ChunkRenderOptimizerSurface}: it removes * block surfaces and tiles that it knows cannot be seen, thus significantly * reducing total polygon count. + *

    + * As with everything related to rendering chunks, CROs are interacted with + * using the relative local chunk coordinate system. In this coordinate system, + * the coordinates are the chunk coordinates relativized using the chunks's up + * direction. In simpler terms, coordinates are {@code [0; BLOCKS_PER_CHUNK)} + * and Z is always up. *

    CRO lifecycle

    * A CRO instance is created by {@link ChunkRenderOptimizerRegistry}. It may * then be used to work on multiple chunks sequentially. Each chunk is processed @@ -44,7 +50,7 @@ import ru.windcorp.progressia.common.world.rels.AbsFace; * instance.
  • *
  • {@link #startRender()} is invoked. The CRO must reset its state.
  • *
  • {@link #addBlock(BlockRender, Vec3i)} and - * {@link #addTile(TileRender, Vec3i, AbsFace)} are invoked for each block and + * {@link #addTile(TileRender, Vec3i, RelFace)} are invoked for each block and * tile that this CRO should optimize. {@code addTile} specifies tiles in order * of ascension within a tile stack.
  • *
  • {@link #endRender()} is invoked. The CRO may perform any pending @@ -98,12 +104,13 @@ public abstract class ChunkRenderOptimizer extends Namespaced { * method is only invoked once per block. This method is not necessarily * invoked for each block. * - * @param block a {@link BlockRender} instance describing the block. - * It corresponds to - * {@code getChunk().getBlock(blockInChunk)}. - * @param blockInChunk the position of the block + * @param block a {@link BlockRender} instance describing the + * block. + * It corresponds to + * {@code getChunk().getBlock(blockInChunk)}. + * @param relBlockInChunk the relative position of the block */ - public abstract void addBlock(BlockRender block, Vec3i blockInChunk); + public abstract void addBlock(BlockRender block, Vec3i relBlockInChunk); /** * Requests that this CRO processes the provided tile. This method may only @@ -112,11 +119,12 @@ public abstract class ChunkRenderOptimizer extends Namespaced { * invoked for each tile. When multiple tiles in a tile stack are requested, * this method is invoked for lower tiles first. * - * @param tile a {@link BlockRender} instance describing the tile - * @param blockInChunk the position of the block that the tile belongs to - * @param blockFace the face that the tile belongs to + * @param tile a {@link BlockRender} instance describing the tile + * @param relBlockInChunk the relative position of the block that the tile + * belongs to + * @param blockFace the face that the tile belongs to */ - public abstract void addTile(TileRender tile, Vec3i blockInChunk, AbsFace blockFace); + public abstract void addTile(TileRender tile, Vec3i relBlockInChunk, RelFace blockFace); /** * Requests that the CRO assembles and outputs its model. This method may diff --git a/src/main/java/ru/windcorp/progressia/client/world/cro/ChunkRenderOptimizerSurface.java b/src/main/java/ru/windcorp/progressia/client/world/cro/ChunkRenderOptimizerSurface.java index 0f0eeb8..f30b91c 100644 --- a/src/main/java/ru/windcorp/progressia/client/world/cro/ChunkRenderOptimizerSurface.java +++ b/src/main/java/ru/windcorp/progressia/client/world/cro/ChunkRenderOptimizerSurface.java @@ -38,7 +38,7 @@ import ru.windcorp.progressia.client.world.block.BlockRender; import ru.windcorp.progressia.client.world.tile.TileRender; import ru.windcorp.progressia.common.util.Vectors; import ru.windcorp.progressia.common.world.ChunkData; -import ru.windcorp.progressia.common.world.rels.AbsFace; +import ru.windcorp.progressia.common.world.rels.RelFace; public class ChunkRenderOptimizerSurface extends ChunkRenderOptimizer { @@ -56,20 +56,23 @@ public class ChunkRenderOptimizerSurface extends ChunkRenderOptimizer { * surface. The coordinates of the face vertices must be in chunk * coordinate system. * - * @param chunk the chunk that contains the requested face - * @param blockInChunk the block in chunk - * @param blockFace the requested face - * @param inner whether this face should be visible from inside - * ({@code true}) or outside ({@code false}) - * @param output a consumer that the created shape parts must be - * given to - * @param offset an additional offset that must be applied to all - * vertices + * @param chunk the chunk that contains the requested face + * @param relBlockInChunk the relative block in chunk + * @param blockFace the requested face + * @param inner whether this face should be visible from + * inside + * ({@code true}) or outside ({@code false}) + * @param output a consumer that the created shape parts must + * be + * given to + * @param offset an additional offset that must be applied to + * all + * vertices */ void getShapeParts( ChunkData chunk, - Vec3i blockInChunk, - AbsFace blockFace, + Vec3i relBlockInChunk, + RelFace blockFace, boolean inner, Consumer output, Vec3 offset /* kostyl 156% */ @@ -77,14 +80,14 @@ public class ChunkRenderOptimizerSurface extends ChunkRenderOptimizer { /** * Returns the opacity of the surface identified by the provided - * {@link AbsFace}. + * {@link RelFace}. * Opaque surfaces prevent surfaces behind them from being included in * chunk models. * * @param blockFace the face to query * @return {@code true} iff the surface is opaque. */ - boolean isOpaque(AbsFace blockFace); + boolean isOpaque(RelFace blockFace); } /** @@ -159,29 +162,29 @@ public class ChunkRenderOptimizerSurface extends ChunkRenderOptimizer { } @Override - public void addBlock(BlockRender block, Vec3i pos) { + public void addBlock(BlockRender block, Vec3i relBlockInChunk) { if (!(block instanceof BlockOptimizedSurface)) return; BlockOptimizedSurface bos = (BlockOptimizedSurface) block; - addBlock(pos, bos); + addBlock(relBlockInChunk, bos); } @Override - public void addTile(TileRender tile, Vec3i pos, AbsFace face) { + public void addTile(TileRender tile, Vec3i relBlockInChunk, RelFace face) { if (!(tile instanceof TileOptimizedSurface)) return; TileOptimizedSurface tos = (TileOptimizedSurface) tile; - addTile(pos, face, tos); + addTile(relBlockInChunk, face, tos); } - protected void addBlock(Vec3i pos, BlockOptimizedSurface block) { - getBlock(pos).block = block; + private void addBlock(Vec3i relBlockInChunk, BlockOptimizedSurface block) { + getBlock(relBlockInChunk).block = block; } - private void addTile(Vec3i pos, AbsFace face, TileOptimizedSurface tile) { - FaceInfo faceInfo = getFace(pos, face); + private void addTile(Vec3i relBlockInChunk, RelFace face, TileOptimizedSurface tile) { + FaceInfo faceInfo = getFace(relBlockInChunk, face); int index = faceInfo.tileCount; faceInfo.tileCount++; @@ -197,12 +200,12 @@ public class ChunkRenderOptimizerSurface extends ChunkRenderOptimizer { } } - protected BlockInfo getBlock(Vec3i cursor) { - return data[cursor.x][cursor.y][cursor.z]; + protected BlockInfo getBlock(Vec3i relBlockInChunk) { + return data[relBlockInChunk.x][relBlockInChunk.y][relBlockInChunk.z]; } - protected FaceInfo getFace(Vec3i cursor, AbsFace face) { - return getBlock(cursor).faces[face.getId()]; + protected FaceInfo getFace(Vec3i relBlockInChunk, RelFace face) { + return getBlock(relBlockInChunk).faces[face.getId()]; } @Override @@ -211,17 +214,12 @@ public class ChunkRenderOptimizerSurface extends ChunkRenderOptimizer { BLOCKS_PER_CHUNK * BLOCKS_PER_CHUNK * BLOCKS_PER_CHUNK * 3 ); - Vec3i cursor = new Vec3i(); Consumer consumer = shapeParts::add; - for (cursor.x = 0; cursor.x < BLOCKS_PER_CHUNK; ++cursor.x) { - for (cursor.y = 0; cursor.y < BLOCKS_PER_CHUNK; ++cursor.y) { - for (cursor.z = 0; cursor.z < BLOCKS_PER_CHUNK; ++cursor.z) { - processInnerFaces(cursor, consumer); - processOuterFaces(cursor, consumer); - } - } - } + chunk.forEachBiC(relBlockInChunk -> { + processInnerFaces(relBlockInChunk, consumer); + processOuterFaces(relBlockInChunk, consumer); + }); if (shapeParts.isEmpty()) { return null; @@ -235,25 +233,25 @@ public class ChunkRenderOptimizerSurface extends ChunkRenderOptimizer { } private void processOuterFaces( - Vec3i blockInChunk, + Vec3i relBlockInChunk, Consumer output ) { - for (AbsFace blockFace : AbsFace.getFaces()) { - processOuterFace(blockInChunk, blockFace, output); + for (RelFace blockFace : RelFace.getFaces()) { + processOuterFace(relBlockInChunk, blockFace, output); } } - private void processOuterFace(Vec3i blockInChunk, AbsFace blockFace, Consumer output) { - if (!shouldRenderOuterFace(blockInChunk, blockFace)) + private void processOuterFace(Vec3i relBlockInChunk, RelFace blockFace, Consumer output) { + if (!shouldRenderOuterFace(relBlockInChunk, blockFace)) return; - FaceInfo info = getFace(blockInChunk, blockFace); + FaceInfo info = getFace(relBlockInChunk, blockFace); if (info.tileCount == 0 && info.block.block == null) return; - Vec3 faceOrigin = new Vec3(blockInChunk.x, blockInChunk.y, blockInChunk.z); - Vec3 offset = new Vec3(blockFace.getFloatVector()).mul(OVERLAY_OFFSET); + Vec3 faceOrigin = new Vec3(relBlockInChunk.x, relBlockInChunk.y, relBlockInChunk.z); + Vec3 offset = new Vec3(blockFace.getRelFloatVector()).mul(OVERLAY_OFFSET); for ( int layer = info.topOpaqueSurface; @@ -264,32 +262,29 @@ public class ChunkRenderOptimizerSurface extends ChunkRenderOptimizer { if (surface == null) continue; // layer may be BLOCK_LAYER, then block may be null - surface.getShapeParts(chunk.getData(), blockInChunk, blockFace, false, output, faceOrigin); + surface.getShapeParts(chunk.getData(), relBlockInChunk, blockFace, false, output, faceOrigin); faceOrigin.add(offset); } } - private void processInnerFaces( - Vec3i blockInChunk, - Consumer output - ) { - for (AbsFace blockFace : AbsFace.getFaces()) { - processInnerFace(blockInChunk, blockFace, output); + private void processInnerFaces(Vec3i relBlockInChunk, Consumer output) { + for (RelFace blockFace : RelFace.getFaces()) { + processInnerFace(relBlockInChunk, blockFace, output); } } - private void processInnerFace(Vec3i blockInChunk, AbsFace blockFace, Consumer output) { - if (!shouldRenderInnerFace(blockInChunk, blockFace)) + private void processInnerFace(Vec3i relBlockInChunk, RelFace blockFace, Consumer output) { + if (!shouldRenderInnerFace(relBlockInChunk, blockFace)) return; - FaceInfo info = getFace(blockInChunk, blockFace); + FaceInfo info = getFace(relBlockInChunk, blockFace); if (info.tileCount == 0 && info.block.block == null) return; - Vec3 faceOrigin = new Vec3(blockInChunk.x, blockInChunk.y, blockInChunk.z); - Vec3 offset = new Vec3(blockFace.getFloatVector()).mul(OVERLAY_OFFSET); + Vec3 faceOrigin = new Vec3(relBlockInChunk.x, relBlockInChunk.y, relBlockInChunk.z); + Vec3 offset = new Vec3(blockFace.getRelFloatVector()).mul(OVERLAY_OFFSET); for ( int layer = FaceInfo.BLOCK_LAYER; @@ -300,35 +295,35 @@ public class ChunkRenderOptimizerSurface extends ChunkRenderOptimizer { if (surface == null) continue; // layer may be BLOCK_LAYER, then block may be null - surface.getShapeParts(chunk.getData(), blockInChunk, blockFace, true, output, faceOrigin); + surface.getShapeParts(chunk.getData(), relBlockInChunk, blockFace, true, output, faceOrigin); faceOrigin.add(offset); } } - private boolean shouldRenderOuterFace(Vec3i blockInChunk, AbsFace face) { - blockInChunk.add(face.getVector()); + private boolean shouldRenderOuterFace(Vec3i relBlockInChunk, RelFace face) { + relBlockInChunk.add(face.getRelVector()); try { - return shouldRenderWhenFacing(blockInChunk, face); + return shouldRenderWhenFacing(relBlockInChunk, face); } finally { - blockInChunk.sub(face.getVector()); + relBlockInChunk.sub(face.getRelVector()); } } - private boolean shouldRenderInnerFace(Vec3i blockInChunk, AbsFace face) { - return shouldRenderWhenFacing(blockInChunk, face); + private boolean shouldRenderInnerFace(Vec3i relBlockInChunk, RelFace face) { + return shouldRenderWhenFacing(relBlockInChunk, face); } - private boolean shouldRenderWhenFacing(Vec3i blockInChunk, AbsFace face) { - if (chunk.containsBiC(blockInChunk)) { - return shouldRenderWhenFacingLocal(blockInChunk, face); + private boolean shouldRenderWhenFacing(Vec3i relBlockInChunk, RelFace face) { + if (chunk.containsBiC(relBlockInChunk)) { + return shouldRenderWhenFacingLocal(relBlockInChunk, face); } else { - return shouldRenderWhenFacingNeighbor(blockInChunk, face); + return shouldRenderWhenFacingNeighbor(relBlockInChunk, face); } } - private boolean shouldRenderWhenFacingLocal(Vec3i blockInChunk, AbsFace face) { - BlockOptimizedSurface block = getBlock(blockInChunk).block; + private boolean shouldRenderWhenFacingLocal(Vec3i relBlockInChunk, RelFace face) { + BlockOptimizedSurface block = getBlock(relBlockInChunk).block; if (block == null) { return true; @@ -340,36 +335,37 @@ public class ChunkRenderOptimizerSurface extends ChunkRenderOptimizer { return true; } - private boolean shouldRenderWhenFacingNeighbor(Vec3i blockInLocalChunk, AbsFace face) { - Vec3i blockInChunk = Vectors.grab3i().set(blockInLocalChunk.x, blockInLocalChunk.y, blockInLocalChunk.z); + private boolean shouldRenderWhenFacingNeighbor(Vec3i relBlockInLocalChunk, RelFace face) { + Vec3i blockInChunk = Vectors.grab3i(); + chunk.resolve(relBlockInLocalChunk, blockInChunk); Vec3i chunkPos = Vectors.grab3i().set(chunk.getX(), chunk.getY(), chunk.getZ()); try { // Determine blockInChunk and chunkPos - if (blockInLocalChunk.x == -1) { + if (blockInChunk.x == -1) { blockInChunk.x = BLOCKS_PER_CHUNK - 1; chunkPos.x -= 1; - } else if (blockInLocalChunk.x == BLOCKS_PER_CHUNK) { + } else if (blockInChunk.x == BLOCKS_PER_CHUNK) { blockInChunk.x = 0; chunkPos.x += 1; - } else if (blockInLocalChunk.y == -1) { + } else if (blockInChunk.y == -1) { blockInChunk.y = BLOCKS_PER_CHUNK - 1; chunkPos.y -= 1; - } else if (blockInLocalChunk.y == BLOCKS_PER_CHUNK) { + } else if (blockInChunk.y == BLOCKS_PER_CHUNK) { blockInChunk.y = 0; chunkPos.y += 1; - } else if (blockInLocalChunk.z == -1) { + } else if (blockInChunk.z == -1) { blockInChunk.z = BLOCKS_PER_CHUNK - 1; chunkPos.z -= 1; - } else if (blockInLocalChunk.z == BLOCKS_PER_CHUNK) { + } else if (blockInChunk.z == BLOCKS_PER_CHUNK) { blockInChunk.z = 0; chunkPos.z += 1; } else { throw new AssertionError( "Requested incorrent neighbor (" - + blockInLocalChunk.x + "; " - + blockInLocalChunk.y + "; " - + blockInLocalChunk.z + ")" + + relBlockInLocalChunk.x + "; " + + relBlockInLocalChunk.y + "; " + + relBlockInLocalChunk.z + ")" ); } @@ -382,8 +378,11 @@ public class ChunkRenderOptimizerSurface extends ChunkRenderOptimizer { return true; BlockOptimizedSurface bos = (BlockOptimizedSurface) block; - if (!bos.isOpaque(face)) + RelFace rotatedFace = face.rotate(this.chunk.getUp(), chunk.getUp()); + + if (!bos.isOpaque(rotatedFace)) { return true; + } return false; diff --git a/src/main/java/ru/windcorp/progressia/client/world/tile/TileRender.java b/src/main/java/ru/windcorp/progressia/client/world/tile/TileRender.java index 52519ed..38c4ae9 100644 --- a/src/main/java/ru/windcorp/progressia/client/world/tile/TileRender.java +++ b/src/main/java/ru/windcorp/progressia/client/world/tile/TileRender.java @@ -18,14 +18,13 @@ package ru.windcorp.progressia.client.world.tile; -import ru.windcorp.progressia.client.graphics.model.ShapeRenderHelper; import glm.vec._3.i.Vec3i; import ru.windcorp.progressia.client.graphics.model.Renderable; import ru.windcorp.progressia.client.world.cro.ChunkRenderOptimizer; import ru.windcorp.progressia.common.util.namespaces.Namespaced; import ru.windcorp.progressia.common.world.ChunkData; import ru.windcorp.progressia.common.world.generic.GenericTile; -import ru.windcorp.progressia.common.world.rels.AbsFace; +import ru.windcorp.progressia.common.world.rels.RelFace; public class TileRender extends Namespaced implements GenericTile { @@ -33,13 +32,7 @@ public class TileRender extends Namespaced implements GenericTile { super(id); } - public void render(ShapeRenderHelper renderer, AbsFace face) { - throw new UnsupportedOperationException( - "TileRender.render() not implemented in " + this - ); - } - - public Renderable createRenderable(ChunkData chunk, Vec3i blockInChunk, AbsFace face) { + public Renderable createRenderable(ChunkData chunk, Vec3i blockInChunk, RelFace face) { return null; } diff --git a/src/main/java/ru/windcorp/progressia/client/world/tile/TileRenderNone.java b/src/main/java/ru/windcorp/progressia/client/world/tile/TileRenderNone.java index fd26e8d..f8ad55b 100644 --- a/src/main/java/ru/windcorp/progressia/client/world/tile/TileRenderNone.java +++ b/src/main/java/ru/windcorp/progressia/client/world/tile/TileRenderNone.java @@ -21,7 +21,7 @@ import glm.vec._3.i.Vec3i; import ru.windcorp.progressia.client.graphics.model.EmptyModel; import ru.windcorp.progressia.client.graphics.model.Renderable; import ru.windcorp.progressia.common.world.ChunkData; -import ru.windcorp.progressia.common.world.rels.AbsFace; +import ru.windcorp.progressia.common.world.rels.RelFace; public class TileRenderNone extends TileRender { @@ -30,7 +30,7 @@ public class TileRenderNone extends TileRender { } @Override - public Renderable createRenderable(ChunkData chunk, Vec3i blockInChunk, AbsFace face) { + public Renderable createRenderable(ChunkData chunk, Vec3i blockInChunk, RelFace face) { return EmptyModel.getInstance(); } diff --git a/src/main/java/ru/windcorp/progressia/client/world/tile/TileRenderOpaqueSurface.java b/src/main/java/ru/windcorp/progressia/client/world/tile/TileRenderOpaqueSurface.java index 8abaa5f..102da82 100644 --- a/src/main/java/ru/windcorp/progressia/client/world/tile/TileRenderOpaqueSurface.java +++ b/src/main/java/ru/windcorp/progressia/client/world/tile/TileRenderOpaqueSurface.java @@ -19,7 +19,7 @@ package ru.windcorp.progressia.client.world.tile; import ru.windcorp.progressia.client.graphics.texture.Texture; -import ru.windcorp.progressia.common.world.rels.AbsFace; +import ru.windcorp.progressia.common.world.rels.RelFace; public class TileRenderOpaqueSurface extends TileRenderSurface { @@ -28,7 +28,7 @@ public class TileRenderOpaqueSurface extends TileRenderSurface { } @Override - public boolean isOpaque(AbsFace face) { + public boolean isOpaque(RelFace face) { return true; } diff --git a/src/main/java/ru/windcorp/progressia/client/world/tile/TileRenderSurface.java b/src/main/java/ru/windcorp/progressia/client/world/tile/TileRenderSurface.java index 3773699..91eeb00 100644 --- a/src/main/java/ru/windcorp/progressia/client/world/tile/TileRenderSurface.java +++ b/src/main/java/ru/windcorp/progressia/client/world/tile/TileRenderSurface.java @@ -35,6 +35,7 @@ import ru.windcorp.progressia.client.world.cro.ChunkRenderOptimizerSurface.TileO import ru.windcorp.progressia.common.util.Vectors; import ru.windcorp.progressia.common.world.ChunkData; import ru.windcorp.progressia.common.world.rels.AbsFace; +import ru.windcorp.progressia.common.world.rels.RelFace; public abstract class TileRenderSurface extends TileRender implements TileOptimizedSurface { @@ -49,26 +50,26 @@ public abstract class TileRenderSurface extends TileRender implements TileOptimi this(id, null); } - public Texture getTexture(AbsFace blockFace) { + public Texture getTexture(RelFace blockFace) { return texture; } - public Vec4 getColorMultiplier(AbsFace blockFace) { + public Vec4 getColorMultiplier(RelFace blockFace) { return Colors.WHITE; } @Override public final void getShapeParts( - ChunkData chunk, Vec3i blockInChunk, AbsFace blockFace, + ChunkData chunk, Vec3i relBlockInChunk, RelFace blockFace, boolean inner, Consumer output, Vec3 offset ) { - output.accept(createFace(chunk, blockInChunk, blockFace, inner, offset)); + output.accept(createFace(chunk, relBlockInChunk, blockFace, inner, offset)); } private ShapePart createFace( - ChunkData chunk, Vec3i blockInChunk, AbsFace blockFace, + ChunkData chunk, Vec3i blockInChunk, RelFace blockFace, boolean inner, Vec3 offset ) { @@ -77,13 +78,13 @@ public abstract class TileRenderSurface extends TileRender implements TileOptimi getTexture(blockFace), getColorMultiplier(blockFace), offset, - blockFace, + blockFace.resolve(AbsFace.POS_Z), inner ); } @Override - public Renderable createRenderable(ChunkData chunk, Vec3i blockInChunk, AbsFace blockFace) { + public Renderable createRenderable(ChunkData chunk, Vec3i blockInChunk, RelFace blockFace) { return new Shape( Usage.STATIC, WorldRenderProgram.getDefault(), diff --git a/src/main/java/ru/windcorp/progressia/client/world/tile/TileRenderTransparentSurface.java b/src/main/java/ru/windcorp/progressia/client/world/tile/TileRenderTransparentSurface.java index e2a2d69..72f9fcf 100644 --- a/src/main/java/ru/windcorp/progressia/client/world/tile/TileRenderTransparentSurface.java +++ b/src/main/java/ru/windcorp/progressia/client/world/tile/TileRenderTransparentSurface.java @@ -19,7 +19,7 @@ package ru.windcorp.progressia.client.world.tile; import ru.windcorp.progressia.client.graphics.texture.Texture; -import ru.windcorp.progressia.common.world.rels.AbsFace; +import ru.windcorp.progressia.common.world.rels.RelFace; public class TileRenderTransparentSurface extends TileRenderSurface { @@ -28,7 +28,7 @@ public class TileRenderTransparentSurface extends TileRenderSurface { } @Override - public boolean isOpaque(AbsFace face) { + public boolean isOpaque(RelFace face) { return false; } diff --git a/src/main/java/ru/windcorp/progressia/common/world/ChunkData.java b/src/main/java/ru/windcorp/progressia/common/world/ChunkData.java index 93c596d..ac0fb93 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/ChunkData.java +++ b/src/main/java/ru/windcorp/progressia/common/world/ChunkData.java @@ -18,7 +18,7 @@ package ru.windcorp.progressia.common.world; -import static ru.windcorp.progressia.common.world.rels.AbsFace.*; +import static ru.windcorp.progressia.common.world.rels.BlockFace.BLOCK_FACE_COUNT; import java.util.ArrayList; import java.util.Arrays; @@ -33,6 +33,8 @@ import ru.windcorp.progressia.common.util.VectorUtil; import ru.windcorp.progressia.common.world.block.BlockData; import ru.windcorp.progressia.common.world.generic.GenericChunk; import ru.windcorp.progressia.common.world.rels.AbsFace; +import ru.windcorp.progressia.common.world.rels.BlockFace; +import ru.windcorp.progressia.common.world.rels.RelFace; import ru.windcorp.progressia.common.world.tile.TileData; import ru.windcorp.progressia.common.world.tile.TileDataStack; import ru.windcorp.progressia.common.world.tile.TileReference; @@ -50,6 +52,8 @@ public class ChunkData private final TileDataStack[] tiles = new TileDataStack[BLOCKS_PER_CHUNK * BLOCKS_PER_CHUNK * BLOCKS_PER_CHUNK * BLOCK_FACE_COUNT]; + + private final AbsFace up; private Object generationHint = null; @@ -58,12 +62,18 @@ public class ChunkData public ChunkData(Vec3i position, WorldData world) { this.position.set(position.x, position.y, position.z); this.world = world; + this.up = world.getGravityModel().getDiscreteUp(position); } @Override public Vec3i getPosition() { return position; } + + @Override + public AbsFace getUp() { + return up; + } @Override public BlockData getBlock(Vec3i posInChunk) { @@ -83,31 +93,31 @@ public class ChunkData } @Override - public TileDataStack getTilesOrNull(Vec3i blockInChunk, AbsFace face) { + public TileDataStack getTilesOrNull(Vec3i blockInChunk, BlockFace face) { return tiles[getTileIndex(blockInChunk, face)]; } /** * Internal use only. Modify a list returned by - * {@link #getTiles(Vec3i, AbsFace)} or - * {@link #getTilesOrNull(Vec3i, AbsFace)} + * {@link #getTiles(Vec3i, BlockFace)} or + * {@link #getTilesOrNull(Vec3i, BlockFace)} * to change tiles. */ protected void setTiles( Vec3i blockInChunk, - AbsFace face, + BlockFace face, TileDataStack tiles ) { this.tiles[getTileIndex(blockInChunk, face)] = tiles; } @Override - public boolean hasTiles(Vec3i blockInChunk, AbsFace face) { + public boolean hasTiles(Vec3i blockInChunk, BlockFace face) { return getTilesOrNull(blockInChunk, face) != null; } @Override - public TileDataStack getTiles(Vec3i blockInChunk, AbsFace face) { + public TileDataStack getTiles(Vec3i blockInChunk, BlockFace face) { int index = getTileIndex(blockInChunk, face); if (tiles[index] == null) { @@ -117,7 +127,7 @@ public class ChunkData return tiles[index]; } - private void createTileStack(Vec3i blockInChunk, AbsFace face) { + private void createTileStack(Vec3i blockInChunk, BlockFace face) { Vec3i independentBlockInChunk = conjureIndependentBlockInChunkVec3i(blockInChunk); TileDataStackImpl stack = new TileDataStackImpl(independentBlockInChunk, face); setTiles(blockInChunk, face, stack); @@ -142,15 +152,15 @@ public class ChunkData posInChunk.x; } - private static int getTileIndex(Vec3i posInChunk, AbsFace face) { + private int getTileIndex(Vec3i posInChunk, BlockFace face) { return getBlockIndex(posInChunk) * BLOCK_FACE_COUNT + - face.getId(); + face.resolve(getUp()).getId(); } private static void checkLocalCoordinates(Vec3i posInChunk) { if (!isInBounds(posInChunk)) { throw new IllegalCoordinatesException( - "Coordinates " + str(posInChunk) + " " + "Coordinates (" + posInChunk.x + "; " + posInChunk.y + "; " + posInChunk.z + ") " + "are not legal chunk coordinates" ); } @@ -162,14 +172,15 @@ public class ChunkData posInChunk.z >= 0 && posInChunk.z < BLOCKS_PER_CHUNK; } - public boolean isBorder(Vec3i blockInChunk, AbsFace face) { + public boolean isBorder(Vec3i blockInChunk, BlockFace face) { final int min = 0, max = BLOCKS_PER_CHUNK - 1; - return (blockInChunk.x == min && face == NEG_X) || - (blockInChunk.x == max && face == POS_X) || - (blockInChunk.y == min && face == NEG_Y) || - (blockInChunk.y == max && face == POS_Y) || - (blockInChunk.z == min && face == NEG_Z) || - (blockInChunk.z == max && face == POS_Z); + AbsFace absFace = face.resolve(getUp()); + return (blockInChunk.x == min && absFace == AbsFace.NEG_X) || + (blockInChunk.x == max && absFace == AbsFace.POS_X) || + (blockInChunk.y == min && absFace == AbsFace.NEG_Y) || + (blockInChunk.y == max && absFace == AbsFace.POS_Y) || + (blockInChunk.z == min && absFace == AbsFace.NEG_Z) || + (blockInChunk.z == max && absFace == AbsFace.POS_Z); } public void forEachBlock(Consumer action) { @@ -221,10 +232,6 @@ public class ChunkData this.listeners.remove(listener); } - private static String str(Vec3i v) { - return "(" + v.x + "; " + v.y + "; " + v.z + ")"; - } - protected void onLoaded() { getListeners().forEach(l -> l.onChunkLoaded(this)); } @@ -309,11 +316,11 @@ public class ChunkData * Potentially shared */ private final Vec3i blockInChunk; - private final AbsFace face; + private final RelFace face; - public TileDataStackImpl(Vec3i blockInChunk, AbsFace face) { + public TileDataStackImpl(Vec3i blockInChunk, BlockFace face) { this.blockInChunk = blockInChunk; - this.face = face; + this.face = face.relativize(getUp()); } @Override @@ -325,7 +332,7 @@ public class ChunkData } @Override - public AbsFace getFace() { + public RelFace getFace() { return face; } @@ -389,7 +396,7 @@ public class ChunkData references[index] = null; for (int tag = 0; tag < indicesByTag.length; ++tag) { - if (tagsByIndex[tag] == -1) { + if (indicesByTag[tag] == -1) { indicesByTag[tag] = index; tagsByIndex[index] = tag; break; @@ -405,21 +412,29 @@ public class ChunkData @Override public void load(TileData tile, int tag) { addFarthest(tile); - - int assignedTag = getIndexByTag(tag); - - if (assignedTag == tag) + + int assignedIndex = size() - 1; + + // Skip if we already have the correct tag + int assignedTag = getTagByIndex(assignedIndex); + if (assignedTag == tag) { return; - if (assignedTag == -1) { + } + assert assignedTag != -1 : "Adding farthest tile resulted in -1 tag"; + + // Make sure we aren't trying to assign a tag already in use + int tileWithRequestedTag = getIndexByTag(tag); + if (tileWithRequestedTag != -1) { throw new IllegalArgumentException( - "Tag " + tag + " already used by tile at index " + getIndexByTag(tag) + "Tag " + tag + " already used by tile at index " + tileWithRequestedTag ); } + assert tileWithRequestedTag != assignedIndex : "tag == assignedTag yet tileWithRequestedTag != assignedIndex"; - indicesByTag[tagsByIndex[size() - 1]] = -1; - tagsByIndex[size() - 1] = tag; - indicesByTag[tag] = size() - 1; - + // Do the tag editing + indicesByTag[assignedTag] = -1; // Release assigned tag + tagsByIndex[assignedIndex] = tag; // Reroute assigned index to requested tag + indicesByTag[tag] = assignedIndex; // Claim requested tag assert checkConsistency(); } diff --git a/src/main/java/ru/windcorp/progressia/common/world/ChunkDataListener.java b/src/main/java/ru/windcorp/progressia/common/world/ChunkDataListener.java index e366c93..0dc7088 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/ChunkDataListener.java +++ b/src/main/java/ru/windcorp/progressia/common/world/ChunkDataListener.java @@ -20,7 +20,7 @@ package ru.windcorp.progressia.common.world; import glm.vec._3.i.Vec3i; import ru.windcorp.progressia.common.world.block.BlockData; -import ru.windcorp.progressia.common.world.rels.AbsFace; +import ru.windcorp.progressia.common.world.rels.RelFace; import ru.windcorp.progressia.common.world.tile.TileData; public interface ChunkDataListener { @@ -55,7 +55,7 @@ public interface ChunkDataListener { default void onChunkTilesChanged( ChunkData chunk, Vec3i blockInChunk, - AbsFace face, + RelFace face, TileData tile, boolean wasAdded ) { diff --git a/src/main/java/ru/windcorp/progressia/common/world/generic/GenericChunk.java b/src/main/java/ru/windcorp/progressia/common/world/generic/GenericChunk.java index e9f2c50..1768119 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/generic/GenericChunk.java +++ b/src/main/java/ru/windcorp/progressia/common/world/generic/GenericChunk.java @@ -25,19 +25,64 @@ import ru.windcorp.progressia.common.util.VectorUtil; import ru.windcorp.progressia.common.util.Vectors; import ru.windcorp.progressia.common.world.Coordinates; import ru.windcorp.progressia.common.world.rels.AbsFace; +import ru.windcorp.progressia.common.world.rels.BlockFace; +import ru.windcorp.progressia.common.world.rels.RelRelation; public interface GenericChunk, B extends GenericBlock, T extends GenericTile, TS extends GenericTileStack> { public static final int BLOCKS_PER_CHUNK = Coordinates.CHUNK_SIZE; Vec3i getPosition(); + + AbsFace getUp(); B getBlock(Vec3i blockInChunk); - TS getTiles(Vec3i blockInChunk, AbsFace face); - - boolean hasTiles(Vec3i blockInChunk, AbsFace face); + TS getTiles(Vec3i blockInChunk, BlockFace face); + boolean hasTiles(Vec3i blockInChunk, BlockFace face); + + default Vec3i resolve(Vec3i relativeBlockInChunk, Vec3i output) { + if (output == null) { + output = new Vec3i(); + } + + final int offset = BLOCKS_PER_CHUNK - 1; + + output.set(relativeBlockInChunk.x, relativeBlockInChunk.y, relativeBlockInChunk.z); + output.mul(2).sub(offset); + + RelRelation.resolve(output, getUp(), output); + + output.add(offset).div(2); + + return output; + } + + default B getBlockRel(Vec3i relativeBlockInChunk) { + Vec3i absoluteBlockInChunk = Vectors.grab3i(); + resolve(relativeBlockInChunk, absoluteBlockInChunk); + B result = getBlock(absoluteBlockInChunk); + Vectors.release(absoluteBlockInChunk); + return result; + } + + default TS getTilesRel(Vec3i relativeBlockInChunk, BlockFace face) { + Vec3i absoluteBlockInChunk = Vectors.grab3i(); + resolve(relativeBlockInChunk, absoluteBlockInChunk); + TS result = getTiles(absoluteBlockInChunk, face); + Vectors.release(absoluteBlockInChunk); + return result; + } + + default boolean hasTilesRel(Vec3i relativeBlockInChunk, BlockFace face) { + Vec3i absoluteBlockInChunk = Vectors.grab3i(); + resolve(relativeBlockInChunk, absoluteBlockInChunk); + boolean result = hasTiles(absoluteBlockInChunk, face); + Vectors.release(absoluteBlockInChunk); + return result; + } + default int getX() { return getPosition().x; } @@ -182,12 +227,29 @@ public interface GenericChunk, B exten ); } - default TS getTilesOrNull(Vec3i blockInChunk, AbsFace face) { + default TS getTilesOrNull(Vec3i blockInChunk, BlockFace face) { if (hasTiles(blockInChunk, face)) { return getTiles(blockInChunk, face); } return null; } + + default TS getTilesOrNullRel(Vec3i relativeBlockInChunk, BlockFace face) { + Vec3i absoluteBlockInChunk = Vectors.grab3i(); + resolve(relativeBlockInChunk, absoluteBlockInChunk); + + TS result; + + if (hasTiles(absoluteBlockInChunk, face)) { + result = getTiles(absoluteBlockInChunk, face); + } else { + result = null; + } + + Vectors.release(absoluteBlockInChunk); + + return result; + } } diff --git a/src/main/java/ru/windcorp/progressia/common/world/generic/GenericTileStack.java b/src/main/java/ru/windcorp/progressia/common/world/generic/GenericTileStack.java index 9cda66c..a2e8a4d 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/generic/GenericTileStack.java +++ b/src/main/java/ru/windcorp/progressia/common/world/generic/GenericTileStack.java @@ -25,7 +25,7 @@ import java.util.function.Consumer; import glm.vec._3.i.Vec3i; import ru.windcorp.progressia.common.world.Coordinates; -import ru.windcorp.progressia.common.world.rels.AbsFace; +import ru.windcorp.progressia.common.world.rels.RelFace; public abstract class GenericTileStack, T extends GenericTile, C extends GenericChunk> extends AbstractList @@ -41,7 +41,7 @@ public abstract class GenericTileStack public abstract C getChunk(); - public abstract AbsFace getFace(); + public abstract RelFace getFace(); public Vec3i getBlockInWorld(Vec3i output) { // This is safe diff --git a/src/main/java/ru/windcorp/progressia/common/world/generic/GenericWorld.java b/src/main/java/ru/windcorp/progressia/common/world/generic/GenericWorld.java index 4dd3d07..c71ef54 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/generic/GenericWorld.java +++ b/src/main/java/ru/windcorp/progressia/common/world/generic/GenericWorld.java @@ -27,6 +27,7 @@ import glm.vec._3.i.Vec3i; import ru.windcorp.progressia.common.util.Vectors; import ru.windcorp.progressia.common.world.Coordinates; import ru.windcorp.progressia.common.world.rels.AbsFace; +import ru.windcorp.progressia.common.world.rels.BlockFace; public interface GenericWorld, C extends GenericChunk, E extends GenericEntity> { @@ -47,6 +48,10 @@ public interface GenericWorld SECONDARY_FACES = ALL_FACES.stream().filter(AbsFace::isSecondary) .collect(ImmutableList.toImmutableList()); - public static final int BLOCK_FACE_COUNT = ALL_FACES.size(); public static final int PRIMARY_BLOCK_FACE_COUNT = PRIMARY_FACES.size(); public static final int SECONDARY_BLOCK_FACE_COUNT = SECONDARY_FACES.size(); @@ -226,6 +225,16 @@ public final class AbsFace extends AbsRelation { public String getName() { return name; } + + @Override + public AbsFace resolve(AbsFace up) { + return this; + } + + @Override + public RelFace relativize(AbsFace up) { + return BlockFaceResolver.relativize(this, up); + } public boolean isPrimary() { return isPrimary; diff --git a/src/main/java/ru/windcorp/progressia/common/world/rels/AbsRelation.java b/src/main/java/ru/windcorp/progressia/common/world/rels/AbsRelation.java index 6744770..b14abdd 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/rels/AbsRelation.java +++ b/src/main/java/ru/windcorp/progressia/common/world/rels/AbsRelation.java @@ -41,6 +41,18 @@ public class AbsRelation extends BlockRelation { this(vector.x, vector.y, vector.z); } + public static AbsRelation of(Vec3i vector) { + return of(vector.x, vector.y, vector.z); + } + + public static AbsRelation of(int x, int y, int z) { + if (Math.abs(x) + Math.abs(y) + Math.abs(z) == 1) { + return AbsFace.roundToFace(x, y, z); + } + + return new AbsRelation(x, y, z); + } + @Override public AbsRelation resolve(AbsFace up) { return this; diff --git a/src/main/java/ru/windcorp/progressia/common/world/rels/BlockFace.java b/src/main/java/ru/windcorp/progressia/common/world/rels/BlockFace.java new file mode 100644 index 0000000..bdbccaf --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/common/world/rels/BlockFace.java @@ -0,0 +1,42 @@ +/* + * 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.common.world.rels; + +import glm.vec._3.Vec3; +import glm.vec._3.i.Vec3i; + +public interface BlockFace { + + public static final int BLOCK_FACE_COUNT = 6; + + AbsFace resolve(AbsFace up); + RelFace relativize(AbsFace up); + + public default Vec3i getVector(AbsFace up) { + return resolve(up).getVector(); + } + + public default Vec3 getFloatVector(AbsFace up) { + return resolve(up).getFloatVector(); + } + + public default Vec3 getNormalized(AbsFace up) { + return resolve(up).getNormalized(); + } + +} diff --git a/src/main/java/ru/windcorp/progressia/common/world/rels/BlockFaceResolver.java b/src/main/java/ru/windcorp/progressia/common/world/rels/BlockFaceResolver.java new file mode 100644 index 0000000..3e25e1b --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/common/world/rels/BlockFaceResolver.java @@ -0,0 +1,78 @@ +/* + * 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.common.world.rels; + +import java.util.Objects; + +import static ru.windcorp.progressia.common.world.rels.AbsFace.BLOCK_FACE_COUNT; + +public class BlockFaceResolver { + + /** + * A mapping from (up; relative) to absolute. Face IDs are used as keys. + */ + private static final AbsFace[][] RESOLUTION_TABLE = new AbsFace[BLOCK_FACE_COUNT][BLOCK_FACE_COUNT]; + + /** + * A mapping from (up; absolute) to relative. Face IDs are used as keys. + */ + private static final RelFace[][] RELATIVIZATION_TABLE = new RelFace[BLOCK_FACE_COUNT][BLOCK_FACE_COUNT]; + + static { + for (AbsFace up : AbsFace.getFaces()) { + for (RelFace relative : RelFace.getFaces()) { + + AbsFace absolute = (AbsFace) AbsRelation.of(RelRelation.resolve(relative.getRelVector(), up, null)); + + RESOLUTION_TABLE[up.getId()][relative.getId()] = absolute; + RELATIVIZATION_TABLE[up.getId()][absolute.getId()] = relative; + + } + } + } + + public static AbsFace resolve(RelFace relative, AbsFace up) { + Objects.requireNonNull(relative, "relative"); + Objects.requireNonNull(up, "up"); + + if (relative == RelFace.UP) { + return up; + } else if (relative == RelFace.DOWN) { + return up.getCounter(); + } + + return RESOLUTION_TABLE[up.getId()][relative.getId()]; + } + + public static RelFace relativize(AbsFace absolute, AbsFace up) { + Objects.requireNonNull(absolute, "absolute"); + Objects.requireNonNull(up, "up"); + + if (absolute == up) { + return RelFace.UP; + } else if (absolute.getCounter() == up) { + return RelFace.DOWN; + } + + return RELATIVIZATION_TABLE[up.getId()][absolute.getId()]; + } + + private BlockFaceResolver() { + } + +} diff --git a/src/main/java/ru/windcorp/progressia/common/world/rels/RelFace.java b/src/main/java/ru/windcorp/progressia/common/world/rels/RelFace.java index 9d4b658..7f3ddb7 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/rels/RelFace.java +++ b/src/main/java/ru/windcorp/progressia/common/world/rels/RelFace.java @@ -22,7 +22,7 @@ import com.google.common.collect.ImmutableMap; import glm.vec._3.i.Vec3i; -public class RelFace extends RelRelation { +public class RelFace extends RelRelation implements BlockFace { // @formatter:off public static final RelFace @@ -76,7 +76,7 @@ public class RelFace extends RelRelation { private RelFace counterFace; private RelFace(int x, int y, int z, String name) { - super(x, y, z, true); + super(x, y, z, false); this.id = nextId++; this.name = name; } @@ -84,6 +84,24 @@ public class RelFace extends RelRelation { public String getName() { return name; } + + @Override + public AbsFace resolve(AbsFace up) { + return BlockFaceResolver.resolve(this, up); + } + + @Override + public RelFace relativize(AbsFace up) { + return this; + } + + public RelFace rotate(AbsFace fromUp, AbsFace toUp) { + if (fromUp == toUp) { + return this; + } + + return resolve(fromUp).relativize(toUp); + } /** * @return the id @@ -97,7 +115,7 @@ public class RelFace extends RelRelation { } public RelFace getCounterAndMoveCursor(Vec3i cursor) { - cursor.add(getVector()); + cursor.add(getRelVector()); return counterFace; } diff --git a/src/main/java/ru/windcorp/progressia/common/world/rels/RelRelation.java b/src/main/java/ru/windcorp/progressia/common/world/rels/RelRelation.java index a4d23d4..5268a26 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/rels/RelRelation.java +++ b/src/main/java/ru/windcorp/progressia/common/world/rels/RelRelation.java @@ -19,8 +19,12 @@ package ru.windcorp.progressia.common.world.rels; import java.util.Map; +import glm.mat._3.Mat3; +import glm.mat._4.Mat4; +import glm.vec._3.Vec3; 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.VectorUtil.SignedAxis; import static ru.windcorp.progressia.common.util.VectorUtil.SignedAxis.*; @@ -35,20 +39,64 @@ public class RelRelation extends BlockRelation { private final SignedAxis westDestination; private final SignedAxis upDestination; - public Rotation(SignedAxis northDestination, SignedAxis westDestination, SignedAxis upDestination) { + private final Mat3 resolutionMatrix3 = new Mat3(); + private final Mat4 resolutionMatrix4 = new Mat4(); + + private final Mat3 relativizationMatrix3 = new Mat3(); + private final Mat4 relativizationMatrix4 = new Mat4(); + + private Rotation(SignedAxis northDestination, SignedAxis westDestination, SignedAxis upDestination) { this.northDestination = northDestination; this.westDestination = westDestination; this.upDestination = upDestination; + + resolutionMatrix3.c0(apply(null, new Vec3(1, 0, 0))); + resolutionMatrix3.c1(apply(null, new Vec3(0, 1, 0))); + resolutionMatrix3.c2(apply(null, new Vec3(0, 0, 1))); + resolutionMatrix3.toMat4(resolutionMatrix4); + + relativizationMatrix3.set(resolutionMatrix3).transpose(); + relativizationMatrix4.set(resolutionMatrix4).transpose(); + } + + /** + * @return the resolutionMatrix3 + */ + public Mat3 getResolutionMatrix3() { + return resolutionMatrix3; + } + + /** + * @return the resolutionMatrix4 + */ + public Mat4 getResolutionMatrix4() { + return resolutionMatrix4; + } + + /** + * @return the relativizationMatrix3 + */ + public Mat3 getRelativizationMatrix3() { + return relativizationMatrix3; + } + + /** + * @return the relativizationMatrix4 + */ + public Mat4 getRelativizationMatrix4() { + return relativizationMatrix4; } public Vec3i apply(Vec3i output, Vec3i input) { if (output == null) { - return output; + output = new Vec3i(); } - set(output, input.x, northDestination); - set(output, input.y, westDestination); - set(output, input.z, upDestination); + int inX = input.x, inY = input.y, inZ = input.z; + + set(output, inX, northDestination); + set(output, inY, westDestination); + set(output, inZ, upDestination); return output; } @@ -56,6 +104,24 @@ public class RelRelation extends BlockRelation { private static void set(Vec3i output, int value, SignedAxis axis) { VectorUtil.set(output, axis.getAxis(), axis.isPositive() ? +value : -value); } + + public Vec3 apply(Vec3 output, Vec3 input) { + if (output == null) { + output = new Vec3(); + } + + float inX = input.x, inY = input.y, inZ = input.z; + + set(output, inX, northDestination); + set(output, inY, westDestination); + set(output, inZ, upDestination); + + return output; + } + + private static void set(Vec3 output, float value, SignedAxis axis) { + VectorUtil.set(output, axis.getAxis(), axis.isPositive() ? +value : -value); + } } private final static Map TRANSFORMATIONS = AbsFace.mapToFaces( @@ -68,14 +134,27 @@ public class RelRelation extends BlockRelation { ); private final Vec3i vector = new Vec3i(); + private final Vec3 floatVector = new Vec3(); + private final Vec3 normalized = new Vec3(); + private AbsRelation[] resolved = null; public RelRelation(int north, int west, int up) { this(north, west, up, false); } + public RelRelation(Vec3i vector) { + this(vector.x, vector.y, vector.z, false); + } + protected RelRelation(int north, int west, int up, boolean precomputeAllResolutions) { vector.set(north, west, up); + floatVector.set(north, west, up); + normalized.set(north, west, up); + + if (normalized.any()) { + normalized.normalize(); + } if (precomputeAllResolutions) { for (AbsFace face : AbsFace.getFaces()) { @@ -84,13 +163,46 @@ public class RelRelation extends BlockRelation { } } + public static RelRelation of(Vec3i vector) { + return of(vector.x, vector.y, vector.z); + } + + public static RelRelation of(int north, int west, int up) { + if (Math.abs(north) + Math.abs(west) + Math.abs(up) == 1) { + if (up == 1) { + return RelFace.UP; + } else if (up == -1) { + return RelFace.DOWN; + } else if (north == 1) { + return RelFace.NORTH; + } else if (north == -1) { + return RelFace.SOUTH; + } else if (west == 1) { + return RelFace.WEST; + } else { + assert west == -1; + return RelFace.EAST; + } + } + + return new RelRelation(north, west, up); + } + /** * @return the relative vector (northward, westward, upward) */ - public Vec3i getVector() { + public Vec3i getRelVector() { return vector; } + public Vec3 getRelFloatVector() { + return floatVector; + } + + public Vec3 getRelNormalized() { + return normalized; + } + public int getNorthward() { return vector.x; } @@ -129,12 +241,43 @@ public class RelRelation extends BlockRelation { } private AbsRelation computeResolution(AbsFace up) { - return new AbsRelation(TRANSFORMATIONS.get(up).apply(new Vec3i(), vector)); + Vec3i resolution = Vectors.grab3i(); + resolve(vector, up, resolution); + AbsRelation result = AbsRelation.of(resolution); + Vectors.release(resolution); + return result; + } + + public static Vec3i resolve(Vec3i relative, AbsFace up, Vec3i output) { + if (output == null) { + output = new Vec3i(); + } + + TRANSFORMATIONS.get(up).apply(output, relative); + + return output; + } + + public static Mat3 getResolutionMatrix3(AbsFace up) { + return TRANSFORMATIONS.get(up).getResolutionMatrix3(); + } + + public static Mat4 getResolutionMatrix4(AbsFace up) { + return TRANSFORMATIONS.get(up).getResolutionMatrix4(); + } + + + public static Mat3 getRelativizationMatrix3(AbsFace up) { + return TRANSFORMATIONS.get(up).getRelativizationMatrix3(); + } + + public static Mat4 getRelativizationMatrix4(AbsFace up) { + return TRANSFORMATIONS.get(up).getRelativizationMatrix4(); } @Override protected Vec3i getSample() { - return getVector(); + return getRelVector(); } } diff --git a/src/main/java/ru/windcorp/progressia/server/Server.java b/src/main/java/ru/windcorp/progressia/server/Server.java index 8aca03c..a46100a 100644 --- a/src/main/java/ru/windcorp/progressia/server/Server.java +++ b/src/main/java/ru/windcorp/progressia/server/Server.java @@ -68,9 +68,9 @@ public class Server { this.chunkManager = new ChunkManager(this); this.entityManager = new EntityManager(this); - schedule(this::scheduleWorldTicks); schedule(chunkManager::tick); schedule(entityManager::tick); + schedule(this::scheduleWorldTicks); // Must run after chunkManager so it only schedules chunks that hadn't unloaded } /** diff --git a/src/main/java/ru/windcorp/progressia/server/world/ChunkLogic.java b/src/main/java/ru/windcorp/progressia/server/world/ChunkLogic.java index 612c1b9..2ee89d6 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/ChunkLogic.java +++ b/src/main/java/ru/windcorp/progressia/server/world/ChunkLogic.java @@ -30,6 +30,8 @@ import ru.windcorp.progressia.common.world.ChunkData; import ru.windcorp.progressia.common.world.Coordinates; import ru.windcorp.progressia.common.world.generic.GenericChunk; import ru.windcorp.progressia.common.world.rels.AbsFace; +import ru.windcorp.progressia.common.world.rels.BlockFace; +import ru.windcorp.progressia.common.world.rels.RelFace; import ru.windcorp.progressia.common.world.tile.TileDataStack; import ru.windcorp.progressia.common.world.tile.TileReference; import ru.windcorp.progressia.server.world.block.BlockLogic; @@ -66,6 +68,11 @@ public class ChunkLogic implements GenericChunk action) { TickContextMutable context = TickContextMutable.uninitialized(); diff --git a/src/main/java/ru/windcorp/progressia/server/world/TickAndUpdateUtil.java b/src/main/java/ru/windcorp/progressia/server/world/TickAndUpdateUtil.java index 4c92990..9f8f265 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/TickAndUpdateUtil.java +++ b/src/main/java/ru/windcorp/progressia/server/world/TickAndUpdateUtil.java @@ -21,7 +21,7 @@ package ru.windcorp.progressia.server.world; import glm.vec._3.i.Vec3i; import ru.windcorp.progressia.common.util.crash.CrashReports; import ru.windcorp.progressia.common.world.entity.EntityData; -import ru.windcorp.progressia.common.world.rels.AbsFace; +import ru.windcorp.progressia.common.world.rels.BlockFace; import ru.windcorp.progressia.server.Server; import ru.windcorp.progressia.server.world.block.BlockLogic; import ru.windcorp.progressia.server.world.block.BlockTickContext; @@ -61,17 +61,22 @@ public class TickAndUpdateUtil { } } - public static void tickTile(WorldLogic world, Vec3i blockInWorld, AbsFace face, int layer) { + public static void tickTile(WorldLogic world, Vec3i blockInWorld, BlockFace face, int layer) { TileLogic tile = world.getTile(blockInWorld, face, layer); - if (!(tile instanceof TickableTile)) + if (!(tile instanceof TickableTile)) { return; + } TileTickContext tickContext = TickContextMutable.start().withWorld(world).withBlock(blockInWorld).withFace(face) .withLayer(layer); tickTile((TickableTile) tile, tickContext); } - public static void tickTiles(WorldLogic world, Vec3i blockInWorld, AbsFace face) { + public static void tickTiles(WorldLogic world, Vec3i blockInWorld, BlockFace face) { + if (!world.isBlockLoaded(blockInWorld)) { + return; + } + TickContextMutable.start().withWorld(world).withBlock(blockInWorld).withFace(face).build() .forEachTile(context -> { TileLogic tile = context.getTile(); @@ -106,17 +111,22 @@ public class TickAndUpdateUtil { } } - public static void updateTile(WorldLogic world, Vec3i blockInWorld, AbsFace face, int layer) { + public static void updateTile(WorldLogic world, Vec3i blockInWorld, BlockFace face, int layer) { TileLogic tile = world.getTile(blockInWorld, face, layer); - if (!(tile instanceof UpdateableTile)) + if (!(tile instanceof UpdateableTile)) { return; + } TileTickContext tickContext = TickContextMutable.start().withWorld(world).withBlock(blockInWorld).withFace(face) .withLayer(layer); updateTile((UpdateableTile) tile, tickContext); } - public static void updateTiles(WorldLogic world, Vec3i blockInWorld, AbsFace face) { + public static void updateTiles(WorldLogic world, Vec3i blockInWorld, BlockFace face) { + if (!world.isBlockLoaded(blockInWorld)) { + return; + } + TickContextMutable.start().withWorld(world).withBlock(blockInWorld).withFace(face).build() .forEachTile(context -> { TileLogic tile = context.getTile(); diff --git a/src/main/java/ru/windcorp/progressia/server/world/TickContextMutable.java b/src/main/java/ru/windcorp/progressia/server/world/TickContextMutable.java index 6b0d789..6eb1cbf 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/TickContextMutable.java +++ b/src/main/java/ru/windcorp/progressia/server/world/TickContextMutable.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.server.world; import java.util.Objects; @@ -26,7 +26,8 @@ import glm.vec._3.i.Vec3i; import ru.windcorp.progressia.common.world.ChunkData; import ru.windcorp.progressia.common.world.Coordinates; import ru.windcorp.progressia.common.world.generic.GenericTileStack; -import ru.windcorp.progressia.common.world.rels.AbsFace; +import ru.windcorp.progressia.common.world.rels.BlockFace; +import ru.windcorp.progressia.common.world.rels.RelFace; import ru.windcorp.progressia.common.world.tile.TileDataStack; import ru.windcorp.progressia.common.world.tile.TileReference; import ru.windcorp.progressia.server.Server; @@ -126,7 +127,7 @@ public abstract class TickContextMutable implements BlockTickContext, TSTickCont } public static interface Block extends Builder { - Builder.TileStack withFace(AbsFace face); + Builder.TileStack withFace(BlockFace face); } public static interface TileStack extends Builder { @@ -148,7 +149,7 @@ public abstract class TickContextMutable implements BlockTickContext, TSTickCont protected Server server; protected final Vec3i chunk = new Vec3i(); protected final Vec3i blockInWorld = new Vec3i(); - protected AbsFace face; + protected RelFace face; protected int layer; protected Role role = Role.NONE; @@ -188,7 +189,7 @@ public abstract class TickContextMutable implements BlockTickContext, TSTickCont } @Override - public AbsFace getFace() { + public RelFace getFace() { checkContextState(Role.TILE_STACK); return this.face; } @@ -261,8 +262,9 @@ public abstract class TickContextMutable implements BlockTickContext, TSTickCont public TileStack withTS(GenericTileStack tileStack) { Objects.requireNonNull(tileStack, "tileStack"); - return withBlock(tileStack.getBlockInWorld(this.blockInWorld)).withFace(tileStack.getFace()); - // ^^^^^^^^^^^^^^^^^ This is safe + return withBlock( + tileStack.getBlockInWorld(this.blockInWorld) // This is safe + ).withFace(tileStack.getFace()); } @Override @@ -277,11 +279,11 @@ public abstract class TickContextMutable implements BlockTickContext, TSTickCont } @Override - public TileStack withFace(AbsFace face) { + public TileStack withFace(BlockFace face) { Objects.requireNonNull(face, "face"); checkBuilderState(Role.BLOCK); - this.face = face; + this.face = face.relativize(server.getWorld().getChunk(chunk).getUp()); this.role = Role.TILE_STACK; return this; @@ -339,12 +341,12 @@ public abstract class TickContextMutable implements BlockTickContext, TSTickCont @Override public void forEachFace(Consumer action) { checkContextState(Role.BLOCK); - AbsFace previousFace = this.face; + RelFace previousFace = this.face; Role previousRole = this.role; this.role = Role.TILE_STACK; - for (int i = 0; i < AbsFace.BLOCK_FACE_COUNT; ++i) { - this.face = AbsFace.getFaces().get(i); + for (int i = 0; i < BlockFace.BLOCK_FACE_COUNT; ++i) { + this.face = RelFace.getFaces().get(i); action.accept(this); } @@ -393,11 +395,13 @@ public abstract class TickContextMutable implements BlockTickContext, TSTickCont Objects.requireNonNull(action, "action"); checkContextState(Role.TILE_STACK); - this.blockInWorld.add(this.face.getVector()); + Vec3i vector = this.face.getVector(getUp()); + + this.blockInWorld.add(vector); this.face = this.face.getCounter(); R result = action.apply(this); this.face = this.face.getCounter(); - this.blockInWorld.sub(this.face.getVector()); + this.blockInWorld.sub(vector); return result; } @@ -407,11 +411,13 @@ public abstract class TickContextMutable implements BlockTickContext, TSTickCont Objects.requireNonNull(action, "action"); checkContextState(Role.TILE_STACK); - this.blockInWorld.add(this.face.getVector()); + Vec3i vector = this.face.getVector(getUp()); + + this.blockInWorld.add(vector); this.face = this.face.getCounter(); action.accept(this); this.face = this.face.getCounter(); - this.blockInWorld.sub(this.face.getVector()); + this.blockInWorld.sub(vector); } /* diff --git a/src/main/java/ru/windcorp/progressia/server/world/UpdateTriggerer.java b/src/main/java/ru/windcorp/progressia/server/world/UpdateTriggerer.java index 2262f00..d0b9562 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/UpdateTriggerer.java +++ b/src/main/java/ru/windcorp/progressia/server/world/UpdateTriggerer.java @@ -23,7 +23,7 @@ import ru.windcorp.progressia.common.world.ChunkData; import ru.windcorp.progressia.common.world.ChunkDataListener; import ru.windcorp.progressia.common.world.Coordinates; import ru.windcorp.progressia.common.world.block.BlockData; -import ru.windcorp.progressia.common.world.rels.AbsFace; +import ru.windcorp.progressia.common.world.rels.RelFace; import ru.windcorp.progressia.common.world.tile.TileData; import ru.windcorp.progressia.server.Server; @@ -49,7 +49,7 @@ public class UpdateTriggerer implements ChunkDataListener { public void onChunkTilesChanged( ChunkData chunk, Vec3i blockInChunk, - AbsFace face, + RelFace face, TileData tile, boolean wasAdded ) { diff --git a/src/main/java/ru/windcorp/progressia/server/world/WorldLogic.java b/src/main/java/ru/windcorp/progressia/server/world/WorldLogic.java index 93a1028..ad255f0 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/WorldLogic.java +++ b/src/main/java/ru/windcorp/progressia/server/world/WorldLogic.java @@ -39,13 +39,8 @@ import ru.windcorp.progressia.server.world.tile.TileLogic; import ru.windcorp.progressia.server.world.tile.TileLogicStack; public class WorldLogic - implements GenericWorld { private final WorldData data; diff --git a/src/main/java/ru/windcorp/progressia/server/world/block/BlockLogic.java b/src/main/java/ru/windcorp/progressia/server/world/block/BlockLogic.java index 7a313c0..fdc35e2 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/block/BlockLogic.java +++ b/src/main/java/ru/windcorp/progressia/server/world/block/BlockLogic.java @@ -20,7 +20,7 @@ package ru.windcorp.progressia.server.world.block; import ru.windcorp.progressia.common.util.namespaces.Namespaced; import ru.windcorp.progressia.common.world.generic.GenericBlock; -import ru.windcorp.progressia.common.world.rels.AbsFace; +import ru.windcorp.progressia.common.world.rels.RelFace; public class BlockLogic extends Namespaced implements GenericBlock { @@ -28,11 +28,11 @@ public class BlockLogic extends Namespaced implements GenericBlock { super(id); } - public boolean isSolid(BlockTickContext context, AbsFace face) { + public boolean isSolid(BlockTickContext context, RelFace face) { return isSolid(face); } - public boolean isSolid(AbsFace face) { + public boolean isSolid(RelFace face) { return true; } diff --git a/src/main/java/ru/windcorp/progressia/server/world/block/BlockTickContext.java b/src/main/java/ru/windcorp/progressia/server/world/block/BlockTickContext.java index 358fe71..7069aa9 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/block/BlockTickContext.java +++ b/src/main/java/ru/windcorp/progressia/server/world/block/BlockTickContext.java @@ -26,7 +26,7 @@ import glm.vec._3.i.Vec3i; import ru.windcorp.progressia.common.world.Coordinates; import ru.windcorp.progressia.common.world.block.BlockData; import ru.windcorp.progressia.common.world.rels.AbsFace; -import ru.windcorp.progressia.common.world.rels.AbsRelation; +import ru.windcorp.progressia.common.world.rels.BlockRelation; import ru.windcorp.progressia.server.world.ChunkTickContext; import ru.windcorp.progressia.server.world.TickContextMutable; import ru.windcorp.progressia.server.world.tile.TSTickContext; @@ -67,9 +67,9 @@ public interface BlockTickContext extends ChunkTickContext { return TickContextMutable.copyWorld(this).withBlock(getBlockInWorld().add_(direction)).build(); } - default BlockTickContext getNeighbor(AbsRelation relation) { + default BlockTickContext getNeighbor(BlockRelation relation) { Objects.requireNonNull(relation, "relation"); - return getNeighbor(relation.getVector()); + return getNeighbor(relation.getVector(getChunkData().getUp())); } default R evalNeighbor(Vec3i direction, Function action) { @@ -78,10 +78,10 @@ public interface BlockTickContext extends ChunkTickContext { return action.apply(getNeighbor(direction)); } - default R evalNeighbor(AbsRelation relation, Function action) { + default R evalNeighbor(BlockRelation relation, Function action) { Objects.requireNonNull(action, "action"); Objects.requireNonNull(relation, "relation"); - return evalNeighbor(relation.getVector(), action); + return evalNeighbor(relation.getVector(getChunkData().getUp()), action); } default void forNeighbor(Vec3i direction, Consumer action) { @@ -93,10 +93,10 @@ public interface BlockTickContext extends ChunkTickContext { }); } - default void forNeighbor(AbsRelation relation, Consumer action) { + default void forNeighbor(BlockRelation relation, Consumer action) { Objects.requireNonNull(action, "action"); Objects.requireNonNull(relation, "relation"); - forNeighbor(relation.getVector(), action); + forNeighbor(relation.getVector(getChunkData().getUp()), action); } /* diff --git a/src/main/java/ru/windcorp/progressia/server/world/tasks/WorldAccessor.java b/src/main/java/ru/windcorp/progressia/server/world/tasks/WorldAccessor.java index 9389b8f..15ab504 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/tasks/WorldAccessor.java +++ b/src/main/java/ru/windcorp/progressia/server/world/tasks/WorldAccessor.java @@ -25,7 +25,7 @@ import ru.windcorp.progressia.common.util.MultiLOC; import ru.windcorp.progressia.common.world.block.BlockData; import ru.windcorp.progressia.common.world.block.BlockDataRegistry; import ru.windcorp.progressia.common.world.entity.EntityData; -import ru.windcorp.progressia.common.world.rels.AbsFace; +import ru.windcorp.progressia.common.world.rels.BlockFace; import ru.windcorp.progressia.common.world.tile.TileData; import ru.windcorp.progressia.common.world.tile.TileDataRegistry; import ru.windcorp.progressia.server.Server; @@ -64,19 +64,19 @@ public class WorldAccessor { setBlock(blockInWorld, BlockDataRegistry.getInstance().get(id)); } - public void addTile(Vec3i blockInWorld, AbsFace face, TileData tile) { + public void addTile(Vec3i blockInWorld, BlockFace face, TileData tile) { AddTile change = cache.grab(AddTile.class); - change.getPacket().set(tile, blockInWorld, face); + change.getPacket().set(tile, blockInWorld, face.resolve(server.getWorld().getUp(blockInWorld))); server.requestChange(change); } - public void addTile(Vec3i blockInWorld, AbsFace face, String id) { + public void addTile(Vec3i blockInWorld, BlockFace face, String id) { addTile(blockInWorld, face, TileDataRegistry.getInstance().get(id)); } - public void removeTile(Vec3i blockInWorld, AbsFace face, int tag) { + public void removeTile(Vec3i blockInWorld, BlockFace face, int tag) { RemoveTile change = cache.grab(RemoveTile.class); - change.getPacket().set(blockInWorld, face, tag); + change.getPacket().set(blockInWorld, face.resolve(server.getWorld().getUp(blockInWorld)), tag); server.requestChange(change); } @@ -91,6 +91,7 @@ public class WorldAccessor { public void tickBlock(Vec3i blockInWorld) { // TODO + System.err.println("WorldAccessor.tickBlock(Vec3i) NYI!"); } /** @@ -112,9 +113,9 @@ public class WorldAccessor { * @param face */ // TODO rename to something meaningful - public void triggerUpdates(Vec3i blockInWorld, AbsFace face) { + public void triggerUpdates(Vec3i blockInWorld, BlockFace face) { TileTriggeredUpdate evaluation = cache.grab(TileTriggeredUpdate.class); - evaluation.init(blockInWorld, face); + evaluation.init(blockInWorld, face.resolve(server.getWorld().getUp(blockInWorld))); server.requestEvaluation(evaluation); } diff --git a/src/main/java/ru/windcorp/progressia/server/world/tile/TSTickContext.java b/src/main/java/ru/windcorp/progressia/server/world/tile/TSTickContext.java index 6a670bf..e965ffb 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/tile/TSTickContext.java +++ b/src/main/java/ru/windcorp/progressia/server/world/tile/TSTickContext.java @@ -23,7 +23,7 @@ import java.util.function.Consumer; import java.util.function.Function; import ru.windcorp.progressia.common.world.ChunkData; -import ru.windcorp.progressia.common.world.rels.AbsFace; +import ru.windcorp.progressia.common.world.rels.RelFace; import ru.windcorp.progressia.common.world.tile.TileDataStack; import ru.windcorp.progressia.server.world.ChunkLogic; import ru.windcorp.progressia.server.world.TickContextMutable; @@ -35,7 +35,7 @@ public interface TSTickContext extends BlockTickContext { * Specifications */ - AbsFace getFace(); + RelFace getFace(); /* * Getters @@ -91,7 +91,7 @@ public interface TSTickContext extends BlockTickContext { default TSTickContext getComplementary() { return TickContextMutable.copyWorld(this) - .withBlock(getBlockInWorld().add_(getFace().getVector())) + .withBlock(getBlockInWorld().add_(getFace().getVector(getUp()))) .withFace(getFace().getCounter()) .build(); } diff --git a/src/main/java/ru/windcorp/progressia/server/world/tile/TileLogic.java b/src/main/java/ru/windcorp/progressia/server/world/tile/TileLogic.java index c5343b0..2bd43f5 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/tile/TileLogic.java +++ b/src/main/java/ru/windcorp/progressia/server/world/tile/TileLogic.java @@ -20,7 +20,7 @@ package ru.windcorp.progressia.server.world.tile; import ru.windcorp.progressia.common.util.namespaces.Namespaced; import ru.windcorp.progressia.common.world.generic.GenericTile; -import ru.windcorp.progressia.common.world.rels.AbsFace; +import ru.windcorp.progressia.common.world.rels.RelFace; public class TileLogic extends Namespaced implements GenericTile { @@ -32,7 +32,7 @@ public class TileLogic extends Namespaced implements GenericTile { return canOccupyFace(context.getFace()); } - public boolean canOccupyFace(AbsFace face) { + public boolean canOccupyFace(RelFace face) { return true; } diff --git a/src/main/java/ru/windcorp/progressia/test/TestBlockLogicAir.java b/src/main/java/ru/windcorp/progressia/test/TestBlockLogicAir.java index 8fed375..e596092 100644 --- a/src/main/java/ru/windcorp/progressia/test/TestBlockLogicAir.java +++ b/src/main/java/ru/windcorp/progressia/test/TestBlockLogicAir.java @@ -18,7 +18,7 @@ package ru.windcorp.progressia.test; -import ru.windcorp.progressia.common.world.rels.AbsFace; +import ru.windcorp.progressia.common.world.rels.RelFace; import ru.windcorp.progressia.server.world.block.BlockLogic; public class TestBlockLogicAir extends BlockLogic { @@ -28,7 +28,7 @@ public class TestBlockLogicAir extends BlockLogic { } @Override - public boolean isSolid(AbsFace face) { + public boolean isSolid(RelFace face) { return false; } diff --git a/src/main/java/ru/windcorp/progressia/test/TestBlockLogicGlass.java b/src/main/java/ru/windcorp/progressia/test/TestBlockLogicGlass.java index 3d29519..cd73ab3 100644 --- a/src/main/java/ru/windcorp/progressia/test/TestBlockLogicGlass.java +++ b/src/main/java/ru/windcorp/progressia/test/TestBlockLogicGlass.java @@ -18,7 +18,7 @@ package ru.windcorp.progressia.test; -import ru.windcorp.progressia.common.world.rels.AbsFace; +import ru.windcorp.progressia.common.world.rels.RelFace; import ru.windcorp.progressia.server.world.block.BlockLogic; public class TestBlockLogicGlass extends BlockLogic { @@ -28,7 +28,7 @@ public class TestBlockLogicGlass extends BlockLogic { } @Override - public boolean isSolid(AbsFace face) { + public boolean isSolid(RelFace face) { return false; } diff --git a/src/main/java/ru/windcorp/progressia/test/TestChunkCodec.java b/src/main/java/ru/windcorp/progressia/test/TestChunkCodec.java index 6a47d41..9e94d64 100644 --- a/src/main/java/ru/windcorp/progressia/test/TestChunkCodec.java +++ b/src/main/java/ru/windcorp/progressia/test/TestChunkCodec.java @@ -39,7 +39,7 @@ import ru.windcorp.progressia.common.world.WorldData; import ru.windcorp.progressia.common.world.block.BlockData; import ru.windcorp.progressia.common.world.block.BlockDataRegistry; import ru.windcorp.progressia.common.world.io.ChunkCodec; -import ru.windcorp.progressia.common.world.rels.AbsFace; +import ru.windcorp.progressia.common.world.rels.RelFace; import ru.windcorp.progressia.common.world.tile.TileData; import ru.windcorp.progressia.common.world.tile.TileDataRegistry; @@ -91,6 +91,9 @@ public class TestChunkCodec extends ChunkCodec { TileData[] tilePalette = readTilePalette(input); ChunkData chunk = new ChunkData(position, world); + + assert chunk.getUp() == ru.windcorp.progressia.server.ServerState.getInstance().getWorld().getData().getChunk(position).getUp(); + readBlocks(input, blockPalette, chunk); readTiles(input, tilePalette, chunk); @@ -138,7 +141,7 @@ public class TestChunkCodec extends ChunkCodec { break; bic.set(xOrEndMarker, input.readByte() & 0xFF, input.readByte() & 0xFF); - AbsFace face = AbsFace.getFaces().get(input.readByte() & 0xFF); + RelFace face = RelFace.getFaces().get(input.readByte() & 0xFF); int tiles = input.readByte() & 0xFF; diff --git a/src/main/java/ru/windcorp/progressia/test/TestContent.java b/src/main/java/ru/windcorp/progressia/test/TestContent.java index 9b5b28f..2b0b90c 100644 --- a/src/main/java/ru/windcorp/progressia/test/TestContent.java +++ b/src/main/java/ru/windcorp/progressia/test/TestContent.java @@ -137,9 +137,6 @@ public class TestContent { "Test:Log", getBlockTexture("LogTop"), getBlockTexture("LogTop"), - getBlockTexture("LogSide"), - getBlockTexture("LogSide"), - getBlockTexture("LogSide"), getBlockTexture("LogSide") ) ); @@ -159,7 +156,7 @@ public class TestContent { Set placeableBlacklist = new HashSet<>(); register(new TileData("Test:Grass")); - register(new TileRenderGrass("Test:Grass", getTileTexture("GrassTop"), getTileTexture("GrassSide"))); + register(new TestTileRenderGrass("Test:Grass", getTileTexture("GrassTop"), getTileTexture("GrassSide"))); register(new TestTileLogicGrass("Test:Grass")); register(new TileData("Test:Stones")); diff --git a/src/main/java/ru/windcorp/progressia/test/TestEntityRenderJavapony.java b/src/main/java/ru/windcorp/progressia/test/TestEntityRenderJavapony.java index 00c3005..56b71ea 100644 --- a/src/main/java/ru/windcorp/progressia/test/TestEntityRenderJavapony.java +++ b/src/main/java/ru/windcorp/progressia/test/TestEntityRenderJavapony.java @@ -78,14 +78,7 @@ public class TestEntityRenderJavapony extends EntityRender { b.addStaticPart( new PppBuilder( WorldRenderProgram.getDefault(), - AbsFace.mapToFaces( - tailStartTexture, - tailStartTexture, - tailStartTexture, - tailStartTexture, - tailStartTexture, - tailStartTexture - ) + tailStartTexture ) .setOrigin(-60, -4, 14) .setDepth(32, 0, -16).setWidth(8).setHeight(8) @@ -97,14 +90,7 @@ public class TestEntityRenderJavapony extends EntityRender { b.addStaticPart( new PppBuilder( WorldRenderProgram.getDefault(), - AbsFace.mapToFaces( - neckTexture, - neckTexture, - neckTexture, - neckTexture, - neckTexture, - neckTexture - ) + neckTexture ) .setOrigin(0, -8, 8) .setWidth(16).setDepth(16).setHeight(2, 0, 16) diff --git a/src/main/java/ru/windcorp/progressia/test/TestTileLogicGrass.java b/src/main/java/ru/windcorp/progressia/test/TestTileLogicGrass.java index e2141d8..246c882 100644 --- a/src/main/java/ru/windcorp/progressia/test/TestTileLogicGrass.java +++ b/src/main/java/ru/windcorp/progressia/test/TestTileLogicGrass.java @@ -18,7 +18,7 @@ package ru.windcorp.progressia.test; -import ru.windcorp.progressia.common.world.rels.AbsFace; +import ru.windcorp.progressia.common.world.rels.RelFace; import ru.windcorp.progressia.server.world.block.BlockLogic; import ru.windcorp.progressia.server.world.block.BlockTickContext; import ru.windcorp.progressia.server.world.ticking.TickingPolicy; @@ -34,12 +34,12 @@ public class TestTileLogicGrass extends HangingTileLogic implements TickableTile @Override public boolean canOccupyFace(TileTickContext context) { - return context.getFace() != AbsFace.NEG_Z && super.canOccupyFace(context); + return context.getFace() != RelFace.DOWN && super.canOccupyFace(context); } @Override - public boolean canOccupyFace(AbsFace face) { - return face != AbsFace.NEG_Z; + public boolean canOccupyFace(RelFace face) { + return face != RelFace.DOWN; } @Override @@ -50,7 +50,7 @@ public class TestTileLogicGrass extends HangingTileLogic implements TickableTile @Override public void tick(TileTickContext context) { if (!isLocationSuitable(context)) { - context.removeThisTile(); +// context.removeThisTile(); } } @@ -64,7 +64,7 @@ public class TestTileLogicGrass extends HangingTileLogic implements TickableTile } private boolean isBlockAboveTransparent(BlockTickContext context) { - return context.evalNeighbor(AbsFace.POS_Z, bctxt -> { + return context.evalNeighbor(RelFace.UP, bctxt -> { BlockLogic block = bctxt.getBlock(); if (block == null) return true; diff --git a/src/main/java/ru/windcorp/progressia/client/world/tile/TileRenderGrass.java b/src/main/java/ru/windcorp/progressia/test/TestTileRenderGrass.java similarity index 70% rename from src/main/java/ru/windcorp/progressia/client/world/tile/TileRenderGrass.java rename to src/main/java/ru/windcorp/progressia/test/TestTileRenderGrass.java index 1845fa6..14b56c7 100644 --- a/src/main/java/ru/windcorp/progressia/client/world/tile/TileRenderGrass.java +++ b/src/main/java/ru/windcorp/progressia/test/TestTileRenderGrass.java @@ -16,17 +16,18 @@ * along with this program. If not, see . */ -package ru.windcorp.progressia.client.world.tile; +package ru.windcorp.progressia.test; import ru.windcorp.progressia.client.graphics.texture.Texture; -import ru.windcorp.progressia.common.world.rels.AbsFace; +import ru.windcorp.progressia.client.world.tile.TileRenderSurface; +import ru.windcorp.progressia.common.world.rels.RelFace; -public class TileRenderGrass extends TileRenderSurface { +public class TestTileRenderGrass extends TileRenderSurface { private final Texture topTexture; private final Texture sideTexture; - public TileRenderGrass( + public TestTileRenderGrass( String id, Texture top, Texture side @@ -37,13 +38,13 @@ public class TileRenderGrass extends TileRenderSurface { } @Override - public Texture getTexture(AbsFace face) { - return (face == AbsFace.POS_Z) ? topTexture : sideTexture; + public Texture getTexture(RelFace face) { + return (face == RelFace.UP) ? topTexture : sideTexture; } @Override - public boolean isOpaque(AbsFace face) { - return face == AbsFace.POS_Z; + public boolean isOpaque(RelFace face) { + return face == RelFace.UP; } } 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 24dbf2b..02bb12e 100644 --- a/src/main/java/ru/windcorp/progressia/test/gen/TestGravityModel.java +++ b/src/main/java/ru/windcorp/progressia/test/gen/TestGravityModel.java @@ -30,14 +30,7 @@ public class TestGravityModel extends GravityModel { @Override protected void doGetGravity(Vec3 pos, Vec3 output) { - output.set(pos); - - if (output.length() < 10) { - output.set(0); - return; - } - - output.normalize().mul(-9.8f); + output.set(0, 0, -9.8f); } @Override From d438d2aa14f4679fb889ade4a3240b857bbfd7f8 Mon Sep 17 00:00:00 2001 From: OLEGSHA Date: Sun, 7 Feb 2021 01:01:37 +0300 Subject: [PATCH 09/55] Linked GravityModel to a WorldGenerator and added GM comms transfer - WorldData no longer acquires a GravityModel automatically - On the server, GravityModel is specified by WorldGenerator - On the client, GravityModel is received from the server via a PacketSetGravityModel --- .../common/world/PacketSetGravityModel.java | 56 +++++++++++++++++++ .../progressia/common/world/WorldData.java | 17 ++++-- .../server/comms/ClientManager.java | 5 ++ .../progressia/server/world/WorldLogic.java | 2 + .../generation/AbstractWorldGenerator.java | 16 +++++- .../world/generation/WorldGenerator.java | 3 + .../test/gen/TestWorldGenerator.java | 2 +- 7 files changed, 94 insertions(+), 7 deletions(-) create mode 100644 src/main/java/ru/windcorp/progressia/common/world/PacketSetGravityModel.java diff --git a/src/main/java/ru/windcorp/progressia/common/world/PacketSetGravityModel.java b/src/main/java/ru/windcorp/progressia/common/world/PacketSetGravityModel.java new file mode 100644 index 0000000..7e7f95e --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/common/world/PacketSetGravityModel.java @@ -0,0 +1,56 @@ +/* + * 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.common.world; + +import java.io.DataInput; +import java.io.DataOutput; +import java.io.IOException; + +public class PacketSetGravityModel extends PacketAffectWorld { + + private String gravityModelId; + + public PacketSetGravityModel() { + this("Core:SetGravityModel"); + } + + protected PacketSetGravityModel(String id) { + super(id); + } + + public void set(GravityModel model) { + this.gravityModelId = model.getId(); + } + + @Override + public void read(DataInput input) throws IOException, DecodingException { + gravityModelId = input.readUTF(); + } + + @Override + public void write(DataOutput output) throws IOException { + output.writeUTF(gravityModelId); + } + + @Override + public void apply(WorldData world) { + GravityModel model = GravityModelRegistry.getInstance().get(gravityModelId); + world.setGravityModel(model); + } + +} diff --git a/src/main/java/ru/windcorp/progressia/common/world/WorldData.java b/src/main/java/ru/windcorp/progressia/common/world/WorldData.java index 6806c1b..625b8c2 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/WorldData.java +++ b/src/main/java/ru/windcorp/progressia/common/world/WorldData.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.common.world; import java.util.ArrayList; @@ -51,8 +51,8 @@ public class WorldData private final TLongObjectMap entitiesById = TCollections.synchronizedMap(new TLongObjectHashMap<>()); private final Collection entities = Collections.unmodifiableCollection(entitiesById.valueCollection()); - - private GravityModel gravityModel = GravityModelRegistry.getInstance().get("Test:TheGravityModel"); + + private GravityModel gravityModel = null; private float time = 0; @@ -202,18 +202,25 @@ public class WorldData return null; return block.getCollisionModel(); } - + /** * @return the gravity model */ public GravityModel getGravityModel() { return gravityModel; } - + /** * @param gravityModel the gravity model to set */ public void setGravityModel(GravityModel gravityModel) { + if (!chunks.isEmpty()) { + throw new IllegalStateException( + "Attempted to change gravity model to " + gravityModel + " while " + chunks.size() + + " chunks were loaded" + ); + } + this.gravityModel = gravityModel; } diff --git a/src/main/java/ru/windcorp/progressia/server/comms/ClientManager.java b/src/main/java/ru/windcorp/progressia/server/comms/ClientManager.java index cb4b80b..74c636d 100644 --- a/src/main/java/ru/windcorp/progressia/server/comms/ClientManager.java +++ b/src/main/java/ru/windcorp/progressia/server/comms/ClientManager.java @@ -28,6 +28,7 @@ import gnu.trove.map.TIntObjectMap; import gnu.trove.map.hash.TIntObjectHashMap; import ru.windcorp.progressia.common.comms.CommsChannel.State; import ru.windcorp.progressia.common.comms.packets.Packet; +import ru.windcorp.progressia.common.world.PacketSetGravityModel; import ru.windcorp.progressia.common.world.PacketSetLocalPlayer; import ru.windcorp.progressia.common.world.entity.EntityData; import ru.windcorp.progressia.server.Player; @@ -73,6 +74,10 @@ public class ClientManager { private void addClientPlayer(ClientPlayer client) { String login = client.getLogin(); + + PacketSetGravityModel setGravityModelPacket = new PacketSetGravityModel(); + setGravityModelPacket.set(getServer().getWorld().getData().getGravityModel()); + client.sendPacket(setGravityModelPacket); EntityData entity = getServer().getPlayerManager().conjurePlayerEntity(login); Player player = new Player(entity, getServer(), client); diff --git a/src/main/java/ru/windcorp/progressia/server/world/WorldLogic.java b/src/main/java/ru/windcorp/progressia/server/world/WorldLogic.java index ad255f0..5931e34 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/WorldLogic.java +++ b/src/main/java/ru/windcorp/progressia/server/world/WorldLogic.java @@ -55,7 +55,9 @@ public class WorldLogic public WorldLogic(WorldData data, Server server, Function worldGeneratorConstructor) { this.data = data; this.server = server; + this.generator = worldGeneratorConstructor.apply(this); + data.setGravityModel(getGenerator().getGravityModel()); data.addListener(new WorldDataListener() { @Override 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 ffb5c06..74583ff 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 @@ -25,14 +25,23 @@ import java.util.Objects; import ru.windcorp.progressia.common.world.ChunkData; import ru.windcorp.progressia.common.world.DecodingException; +import ru.windcorp.progressia.common.world.GravityModel; +import ru.windcorp.progressia.common.world.GravityModelRegistry; public abstract class AbstractWorldGenerator extends WorldGenerator { private final Class hintClass; + + private final GravityModel gravityModel; - public AbstractWorldGenerator(String id, Class hintClass) { + 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")); + + if (this.gravityModel == null) { + throw new IllegalArgumentException("Gravity model with ID \"" + gravityModelId + "\" not found"); + } } @Override @@ -63,5 +72,10 @@ public abstract class AbstractWorldGenerator extends WorldGenerator { protected void setHint(ChunkData chunk, H hint) { chunk.setGenerationHint(hint); } + + @Override + public GravityModel getGravityModel() { + return gravityModel; + } } diff --git a/src/main/java/ru/windcorp/progressia/server/world/generation/WorldGenerator.java b/src/main/java/ru/windcorp/progressia/server/world/generation/WorldGenerator.java index afed281..6a85e45 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/generation/WorldGenerator.java +++ b/src/main/java/ru/windcorp/progressia/server/world/generation/WorldGenerator.java @@ -26,6 +26,7 @@ import glm.vec._3.i.Vec3i; import ru.windcorp.progressia.common.util.namespaces.Namespaced; import ru.windcorp.progressia.common.world.ChunkData; import ru.windcorp.progressia.common.world.DecodingException; +import ru.windcorp.progressia.common.world.GravityModel; import ru.windcorp.progressia.common.world.WorldData; public abstract class WorldGenerator extends Namespaced { @@ -42,5 +43,7 @@ public abstract class WorldGenerator extends Namespaced { public abstract void writeGenerationHint(DataOutputStream output, Object hint) throws IOException; public abstract boolean isChunkReady(Object hint); + + public abstract GravityModel getGravityModel(); } diff --git a/src/main/java/ru/windcorp/progressia/test/gen/TestWorldGenerator.java b/src/main/java/ru/windcorp/progressia/test/gen/TestWorldGenerator.java index 6a2f1cb..9d4ff6e 100644 --- a/src/main/java/ru/windcorp/progressia/test/gen/TestWorldGenerator.java +++ b/src/main/java/ru/windcorp/progressia/test/gen/TestWorldGenerator.java @@ -44,7 +44,7 @@ public class TestWorldGenerator extends AbstractWorldGenerator { private final TestTerrainGenerator terrainGen; public TestWorldGenerator(WorldLogic world) { - super("Test:WorldGenerator", Boolean.class); + super("Test:WorldGenerator", Boolean.class, "Test:TheGravityModel"); this.terrainGen = new TestTerrainGenerator(this, world); world.getData().addListener(new WorldDataListener() { From 2d55d4db51ae7a84cd4ecd36c1db0d88a88a06f1 Mon Sep 17 00:00:00 2001 From: OLEGSHA Date: Mon, 22 Feb 2021 15:38:14 +0300 Subject: [PATCH 10/55] Added a cubic gravity model and fixed some stuff - Added TestPlanetGenerator and a corresponding gravity model - Fixed gravity-triggered camera rotation --- .../collision/colliders/AABBoidCollider.java | 67 ++++--- .../common/collision/colliders/Collider.java | 94 ++++----- .../progressia/common/world/ChunkData.java | 14 +- .../common/world/entity/EntityData.java | 6 +- .../ru/windcorp/progressia/server/Player.java | 2 +- .../ru/windcorp/progressia/server/Server.java | 6 +- .../windcorp/progressia/test/TestContent.java | 5 +- .../test/gen/TestPlanetGenerator.java | 181 ++++++++++++++++++ .../test/gen/TestPlanetGravityModel.java | 132 +++++++++++++ 9 files changed, 422 insertions(+), 85 deletions(-) create mode 100644 src/main/java/ru/windcorp/progressia/test/gen/TestPlanetGenerator.java create mode 100644 src/main/java/ru/windcorp/progressia/test/gen/TestPlanetGravityModel.java diff --git a/src/main/java/ru/windcorp/progressia/common/collision/colliders/AABBoidCollider.java b/src/main/java/ru/windcorp/progressia/common/collision/colliders/AABBoidCollider.java index d6c31c1..ed42594 100644 --- a/src/main/java/ru/windcorp/progressia/common/collision/colliders/AABBoidCollider.java +++ b/src/main/java/ru/windcorp/progressia/common/collision/colliders/AABBoidCollider.java @@ -122,46 +122,51 @@ class AABBoidCollider { return output; } + // @formatter:off /* - * Here we determine whether a collision has actually happened, and if it - * did, at what moment. - * The basic idea is to compute the moment of collision and impact - * coordinates in wall coordinate space. - * Then, we can check impact coordinates to determine if we actually hit the - * wall or flew by and then - * check time to make sure the collision is not too far in the future and - * not in the past. + * Here we determine whether a collision has actually happened, and if it did, at what moment. + * + * The basic idea is to compute the moment of collision and impact coordinates in wall coordinate space. + * Then, we can check impact coordinates to determine if we actually hit the wall or flew by and then + * check time to make sure the collision is not too far in the future and not in the past. + * * DETAILED EXPLANATION: - * Consider a surface defined by an origin r_wall and two noncollinear - * nonzero vectors w and h. + * + * Consider a surface defined by an origin r_wall and two noncollinear nonzero vectors w and h. * Consider a line defined by an origin r_line and a nonzero vector v. + * * Then, a collision occurs if there exist x, y and t such that - * ______ _ - * r_line + v * t + * ______ _ + * r_line + v * t + * * and - * ______ _ _ - * r_wall + w * x + h * y - * describe the same location (indeed, this corresponds to a collision at - * moment t0 + t - * with a point on the wall with coordinates (x; y) in (w; h) coordinate - * system). + * ______ _ _ + * r_wall + w * x + h * y + * + * describe the same location (indeed, this corresponds to a collision at moment t0 + t + * with a point on the wall with coordinates (x; y) in (w; h) coordinate system). + * * Therefore, - * ______ _ ______ _ _ - * r_line + v*t = r_wall + w*x + h*y; - * _ ⎡w_x h_x -v_x⎤ ⎡x⎤ _ ______ ______ - * r = ⎢w_y h_y -v_y⎥ * ⎢y⎥, where r = r_line - r_wall; - * ⎣w_z h_z -v_z⎦ ⎣t⎦ - * ⎡x⎤ ⎡w_x h_x -v_x⎤ -1 _ - * ⎢y⎥ = ⎢w_y h_y -v_y⎥ * r, if the matrix is invertible. - * ⎣t⎦ ⎣w_z h_z -v_z⎦ + * ______ _ ______ _ _ + * r_line + v*t = r_wall + w*x + h*y; + * + * _ ⎡w_x h_x -v_x⎤ ⎡x⎤ _ ______ ______ + * r = ⎢w_y h_y -v_y⎥ * ⎢y⎥, where r = r_line - r_wall; + * ⎣w_z h_z -v_z⎦ ⎣t⎦ + * + * ⎡x⎤ ⎡w_x h_x -v_x⎤ -1 _ + * ⎢y⎥ = ⎢w_y h_y -v_y⎥ * r, if the matrix is invertible. + * ⎣t⎦ ⎣w_z h_z -v_z⎦ + * * Then, one only needs to ensure that: - * 0 < x < 1, - * 0 < y < 1, and - * 0 < t < T, where T is remaining tick time. - * If the matrix is not invertible or any of the conditions are not met, no - * collision happened. + * 0 < x < 1, + * 0 < y < 1, and + * 0 < t < T, where T is remaining tick time. + * + * If the matrix is not invertible or any of the conditions are not met, no collision happened. * If all conditions are satisfied, then the moment of impact is t0 + t. */ + // @formatter:on private static Collision computeWallCollision( Wall obstacleWall, AABBoid colliderModel, diff --git a/src/main/java/ru/windcorp/progressia/common/collision/colliders/Collider.java b/src/main/java/ru/windcorp/progressia/common/collision/colliders/Collider.java index 56bc8ad..62a7808 100644 --- a/src/main/java/ru/windcorp/progressia/common/collision/colliders/Collider.java +++ b/src/main/java/ru/windcorp/progressia/common/collision/colliders/Collider.java @@ -212,66 +212,72 @@ public class Collider { handlePhysics(collision); } + // @formatter:off /* * Here we compute the change in body velocities due to a collision. + * * We make the following simplifications: - * 1) The bodies are perfectly rigid; - * 2) The collision is perfectly inelastic - * (no bouncing); - * 3) The bodies are spherical; - * 4) No tangential friction exists - * (bodies do not experience friction when sliding against each other); - * 5) Velocities are not relativistic. + * 1) The bodies are perfectly rigid; + * 2) The collision is perfectly inelastic + * (no bouncing); + * 3) The bodies are spherical; + * 4) No tangential friction exists + * (bodies do not experience friction when sliding against each other); + * 5) Velocities are not relativistic. + * * Angular momentum is ignored per 3) and 4), - * e.g. when something pushes an end of a long stick, the stick does not - * rotate. + * e.g. when something pushes an end of a long stick, the stick does not rotate. + * * DETAILED EXPLANATION: - * Two spherical (sic) bodies, a and b, experience a perfectly inelastic - * collision + * + * Two spherical (sic) bodies, a and b, experience a perfectly inelastic collision * along a unit vector - * _ _ _ _ _ - * n = (w ⨯ h) / (|w ⨯ h|), - * _ _ + * _ _ _ _ _ + * n = (w ⨯ h) / (|w ⨯ h|), + * _ _ * where w and h are two noncollinear nonzero vectors on the dividing plane. - * ___ ___ + * ___ ___ * Body masses and velocities are M_a, M_b and v_a, v_b, respectively. - * ___ ___ + * ___ ___ * After the collision desired velocities are u_a and u_b, respectively. - * _ - * (Notation convention: suffix 'n' denotes a vector projection onto vector - * n, + * _ + * (Notation convention: suffix 'n' denotes a vector projection onto vector n, * and suffix 't' denotes a vector projection onto the dividing plane.) - * Consider the law of conservation of momentum for axis n and the dividing - * plane: - * ____________ ____________ ________________ - * n: ⎧ p_a_before_n + p_b_before_n = p_common_after_n; - * ⎨ ___________ ____________ - * t: ⎩ p_i_after_t = p_i_before_t for any i in {a, b}. + * + * Consider the law of conservation of momentum for axis n and the dividing plane: + * ____________ ____________ ________________ + * n: ⎧ p_a_before_n + p_b_before_n = p_common_after_n; + * ⎨ ___________ ____________ + * t: ⎩ p_i_after_t = p_i_before_t for any i in {a, b}. + * * Expressing all p_* in given terms: - * ___ _ ___ _ ___ ___ ____ ____ - * n: ⎧ M_a * (v_a ⋅ n) + M_b * (v_b ⋅ n) = (M_a + M_b) * u_n, where u_n ≡ - * u_an = u_bn; - * ⎨ ____ ___ _ ___ _ - * t: ⎩ u_it = v_i - n * (v_i ⋅ n) for any i in {a, b}. + * ___ _ ___ _ ___ ___ ____ ____ + * n: ⎧ M_a * (v_a ⋅ n) + M_b * (v_b ⋅ n) = (M_a + M_b) * u_n, where u_n ≡ u_an = u_bn; + * ⎨ ____ ___ _ ___ _ + * t: ⎩ u_it = v_i - n * (v_i ⋅ n) for any i in {a, b}. + * * Therefore: - * ___ _ ___ _ ___ _ - * u_n = n * ( M_a/(M_a + M_b) * v_a ⋅ n + M_b/(M_a + M_b) * v_b ⋅ n ); + * ___ _ ___ _ ___ _ + * u_n = n * ( M_a/(M_a + M_b) * v_a ⋅ n + M_b/(M_a + M_b) * v_b ⋅ n ); + * * or, equivalently, - * ___ _ ___ _ ___ _ - * u_n = n * ( m_a * v_a ⋅ n + m_b * v_b ⋅ n ), + * ___ _ ___ _ ___ _ + * u_n = n * ( m_a * v_a ⋅ n + m_b * v_b ⋅ n ), + * * where m_a and m_b are relative masses (see below). + * * Finally, - * ___ ____ ___ - * u_i = u_it + u_n for any i in {a, b}. - * The usage of relative masses m_i permits a convenient generalization of - * the algorithm - * for infinite masses, signifying masses "significantly greater" than - * finite masses: - * 1) If both M_a and M_b are finite, let m_i = M_i / (M_a + M_b) for any i - * in {a, b}. - * 2) If M_i is finite but M_j is infinite, let m_i = 0 and m_j = 1. - * 3) If both M_a and M_b are infinite, let m_i = 1/2 for any i in {a, b}. + * ___ ____ ___ + * u_i = u_it + u_n for any i in {a, b}. + * + * The usage of relative masses m_i permits a convenient generalization of the algorithm + * for infinite masses, signifying masses "significantly greater" than finite masses: + * + * 1) If both M_a and M_b are finite, let m_i = M_i / (M_a + M_b) for any i in {a, b}. + * 2) If M_i is finite but M_j is infinite, let m_i = 0 and m_j = 1. + * 3) If both M_a and M_b are infinite, let m_i = 1/2 for any i in {a, b}. */ + // @formatter:on private static void handlePhysics(Collision collision) { // Fuck JGLM Vec3 n = Vectors.grab3(); diff --git a/src/main/java/ru/windcorp/progressia/common/world/ChunkData.java b/src/main/java/ru/windcorp/progressia/common/world/ChunkData.java index ac0fb93..5788053 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/ChunkData.java +++ b/src/main/java/ru/windcorp/progressia/common/world/ChunkData.java @@ -30,6 +30,7 @@ import java.util.function.Consumer; 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.world.block.BlockData; import ru.windcorp.progressia.common.world.generic.GenericChunk; import ru.windcorp.progressia.common.world.rels.AbsFace; @@ -44,14 +45,16 @@ public class ChunkData implements GenericChunk { public static final int BLOCKS_PER_CHUNK = Coordinates.CHUNK_SIZE; + public static final int CHUNK_RADIUS = BLOCKS_PER_CHUNK / 2; private final Vec3i position = new Vec3i(); private final WorldData world; private final BlockData[] blocks = new BlockData[BLOCKS_PER_CHUNK * BLOCKS_PER_CHUNK * BLOCKS_PER_CHUNK]; - private final TileDataStack[] tiles = new TileDataStack[BLOCKS_PER_CHUNK * BLOCKS_PER_CHUNK * BLOCKS_PER_CHUNK * - BLOCK_FACE_COUNT]; + private final TileDataStack[] tiles = new TileDataStack[ + BLOCKS_PER_CHUNK * BLOCKS_PER_CHUNK * BLOCKS_PER_CHUNK * BLOCK_FACE_COUNT + ]; private final AbsFace up; @@ -91,6 +94,13 @@ public class ChunkData }); } } + + public void setBlockRel(Vec3i relativeBlockInChunk, BlockData block, boolean notify) { + Vec3i absoluteBlockInChunk = Vectors.grab3i(); + resolve(relativeBlockInChunk, absoluteBlockInChunk); + setBlock(absoluteBlockInChunk, block, notify); + Vectors.release(absoluteBlockInChunk); + } @Override public TileDataStack getTilesOrNull(Vec3i blockInChunk, BlockFace face) { diff --git a/src/main/java/ru/windcorp/progressia/common/world/entity/EntityData.java b/src/main/java/ru/windcorp/progressia/common/world/entity/EntityData.java index 344439a..e776e6a 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/entity/EntityData.java +++ b/src/main/java/ru/windcorp/progressia/common/world/entity/EntityData.java @@ -282,9 +282,9 @@ public class EntityData extends StatefulObject implements Collideable, GenericEn // Don't format. @formatter:off matrix.set( - cos + (1 - cos)*x*x, (1 - cos)*x*y - sin*z, (1 - cos)*x*z + sin*y, - (1 - cos)*y*x + sin*z, cos + (1 - cos)*y*y, (1 - cos)*y*z - sin*x, - (1 - cos)*z*x - sin*y, (1 - cos)*z*y + sin*x, cos + (1 - cos)*z*z + cos + (1 - cos)*x*x, (1 - cos)*y*x + sin*z, (1 - cos)*z*x - sin*y, + (1 - cos)*x*y - sin*z, cos + (1 - cos)*y*y, (1 - cos)*z*y + sin*x, + (1 - cos)*x*z + sin*y, (1 - cos)*y*z - sin*x, cos + (1 - cos)*z*z ); // @formatter:on diff --git a/src/main/java/ru/windcorp/progressia/server/Player.java b/src/main/java/ru/windcorp/progressia/server/Player.java index ea373a8..734783f 100644 --- a/src/main/java/ru/windcorp/progressia/server/Player.java +++ b/src/main/java/ru/windcorp/progressia/server/Player.java @@ -63,7 +63,7 @@ public class Player extends PlayerData implements ChunkLoader { for (cursor.x = -iRadius; cursor.x <= +iRadius; ++cursor.x) { for (cursor.y = -iRadius; cursor.y <= +iRadius; ++cursor.y) { for (cursor.z = -iRadius; cursor.z <= +iRadius; ++cursor.z) { - if (cursor.x * cursor.x + cursor.y * cursor.y + (cursor.z * 2) * (cursor.z * 2) <= radiusSq) { + if (cursor.x * cursor.x + cursor.y * cursor.y + (cursor.z/* * 2*/) * (cursor.z/* * 2*/) <= radiusSq) { cursor.add(start); chunkConsumer.accept(cursor); diff --git a/src/main/java/ru/windcorp/progressia/server/Server.java b/src/main/java/ru/windcorp/progressia/server/Server.java index a46100a..40fdca6 100644 --- a/src/main/java/ru/windcorp/progressia/server/Server.java +++ b/src/main/java/ru/windcorp/progressia/server/Server.java @@ -31,7 +31,7 @@ import ru.windcorp.progressia.server.world.WorldLogic; 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.test.gen.TestWorldGenerator; +import ru.windcorp.progressia.test.gen.TestPlanetGenerator; public class Server { @@ -60,7 +60,7 @@ public class Server { private final TickingSettings tickingSettings = new TickingSettings(); public Server(WorldData world) { - this.world = new WorldLogic(world, this, TestWorldGenerator::new); + this.world = new WorldLogic(world, this, w -> new TestPlanetGenerator("Test:PlanetGenerator", Units.get("48 m"), w)); this.serverThread = new ServerThread(this); this.clientManager = new ClientManager(this); @@ -206,7 +206,7 @@ public class Server { } public float getLoadDistance(Player player) { - return Units.get(150.0f, "m"); + return Units.get(100.5f, "m"); } /** diff --git a/src/main/java/ru/windcorp/progressia/test/TestContent.java b/src/main/java/ru/windcorp/progressia/test/TestContent.java index 2b0b90c..d34c3ba 100644 --- a/src/main/java/ru/windcorp/progressia/test/TestContent.java +++ b/src/main/java/ru/windcorp/progressia/test/TestContent.java @@ -59,13 +59,15 @@ import ru.windcorp.progressia.server.world.block.*; import ru.windcorp.progressia.server.world.entity.*; import ru.windcorp.progressia.server.world.tile.*; import ru.windcorp.progressia.test.gen.TestGravityModel; +import ru.windcorp.progressia.test.gen.TestPlanetGravityModel; public class TestContent { public static final String PLAYER_LOGIN = "Sasha"; public static final long PLAYER_ENTITY_ID = 0x42; public static final long STATIE_ENTITY_ID = 0xDEADBEEF; - public static final Vec3 SPAWN = new Vec3(8, 8, 880); +// public static final Vec3 SPAWN = new Vec3(8, 8, 880); + public static final Vec3 SPAWN = new Vec3(0, 0, 66); public static final List PLACEABLE_BLOCKS = new ArrayList<>(); public static final List PLACEABLE_TILES = new ArrayList<>(); @@ -424,6 +426,7 @@ public class TestContent { ChunkIO.registerCodec(new TestChunkCodec()); ChunkRenderOptimizerRegistry.getInstance().register("Core:SurfaceOptimizer", ChunkRenderOptimizerSurface::new); GravityModelRegistry.getInstance().register(new TestGravityModel()); + GravityModelRegistry.getInstance().register(new TestPlanetGravityModel()); } } diff --git a/src/main/java/ru/windcorp/progressia/test/gen/TestPlanetGenerator.java b/src/main/java/ru/windcorp/progressia/test/gen/TestPlanetGenerator.java new file mode 100644 index 0000000..bbcdbfd --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/test/gen/TestPlanetGenerator.java @@ -0,0 +1,181 @@ +/* + * 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; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.util.Arrays; + +import glm.vec._3.i.Vec3i; +import ru.windcorp.progressia.common.util.VectorUtil; +import ru.windcorp.progressia.common.world.ChunkData; +import ru.windcorp.progressia.common.world.DecodingException; +import ru.windcorp.progressia.common.world.WorldData; +import ru.windcorp.progressia.common.world.block.BlockData; +import ru.windcorp.progressia.common.world.block.BlockDataRegistry; +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.WorldLogic; +import ru.windcorp.progressia.server.world.generation.AbstractWorldGenerator; + +public class TestPlanetGenerator extends AbstractWorldGenerator { + + private final int surfaceLevel; + + public TestPlanetGenerator(String id, float planetRadius, WorldLogic world) { + super(id, Boolean.class, "Test:PlanetGravityModel"); + + this.surfaceLevel = (int) (planetRadius / ChunkData.BLOCKS_PER_CHUNK); + if (surfaceLevel < 2) { + throw new IllegalArgumentException("planetRadius too small, must be at least 32 m"); + } + } + + @Override + protected Boolean doReadGenerationHint(DataInputStream input) throws IOException, DecodingException { + return input.readBoolean(); + } + + @Override + protected void doWriteGenerationHint(DataOutputStream output, Boolean hint) throws IOException { + output.writeBoolean(hint); + } + + @Override + protected boolean checkIsChunkReady(Boolean hint) { + return hint; + } + + @Override + public ChunkData generate(Vec3i chunkPos, WorldData world) { + ChunkData chunk = new ChunkData(chunkPos, world); + + generate(chunk); + chunk.setGenerationHint(true); + + world.addChunk(chunk); + return chunk; + } + + private enum ChunkType { + SURFACE, UNDERGROUND, EDGE_SURFACE, EDGE_UNDERGROUND, CORE, AIR; + } + + private void generate(ChunkData chunk) { + switch (getChunkType(chunk.getPosition())) { + case SURFACE: + fillSurface(chunk); + break; + case UNDERGROUND: + fillUndeground(chunk); + break; + case EDGE_SURFACE: + fillEdgeSurface(chunk); + break; + case EDGE_UNDERGROUND: + fillEdgeUnderground(chunk); + break; + case CORE: + fillCore(chunk); + break; + case AIR: + fillAir(chunk); + break; + } + } + + private void fillSurface(ChunkData chunk) { + final int bpc = ChunkData.BLOCKS_PER_CHUNK; + + BlockData dirt = BlockDataRegistry.getInstance().get("Test:Dirt"); + BlockData granite = BlockDataRegistry.getInstance().get("Test:GraniteMonolith"); + + TileData grass = TileDataRegistry.getInstance().get("Test:Grass"); + + chunk.forEachBiC(bic -> { + + BlockData block; + + if (bic.z > bpc - 4) { + block = dirt; + } else { + block = granite; + } + + chunk.setBlockRel(bic, block, false); + + }); + + VectorUtil.iterateCuboid(0, 0, bpc - 1, bpc, bpc, bpc, bic -> { + chunk.getTilesRel(bic, RelFace.UP).add(grass); + }); + } + + private void fillUndeground(ChunkData chunk) { + fill(chunk, BlockDataRegistry.getInstance().get("Test:GraniteMonolith")); + } + + private void fillEdgeSurface(ChunkData chunk) { + fill(chunk, BlockDataRegistry.getInstance().get("Test:Stone")); + } + + private void fillEdgeUnderground(ChunkData chunk) { + fill(chunk, BlockDataRegistry.getInstance().get("Test:Stone")); + } + + private void fillCore(ChunkData chunk) { + fill(chunk, BlockDataRegistry.getInstance().get("Test:Stone")); + } + + private void fillAir(ChunkData chunk) { + fill(chunk, BlockDataRegistry.getInstance().get("Test:Air")); + } + + private void fill(ChunkData chunk, BlockData block) { + chunk.forEachBiC(bic -> chunk.setBlock(bic, block, false)); + } + + private ChunkType getChunkType(Vec3i pos) { + int[] abs = pos.abs_().toIA_(); + Arrays.sort(abs); + + int medium = abs[1]; + int largest = abs[2]; + + int level = largest; + + if (level == 0) { + return ChunkType.CORE; + } + + if (largest > surfaceLevel) { + return ChunkType.AIR; + } + + boolean isSurface = largest == surfaceLevel; + + if (medium == largest) { + return isSurface ? ChunkType.EDGE_SURFACE : ChunkType.EDGE_UNDERGROUND; + } else { + return isSurface ? ChunkType.SURFACE : ChunkType.UNDERGROUND; + } + } + +} diff --git a/src/main/java/ru/windcorp/progressia/test/gen/TestPlanetGravityModel.java b/src/main/java/ru/windcorp/progressia/test/gen/TestPlanetGravityModel.java new file mode 100644 index 0000000..05d659a --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/test/gen/TestPlanetGravityModel.java @@ -0,0 +1,132 @@ +/* + * 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; + +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.GravityModel; +import ru.windcorp.progressia.common.world.rels.AbsFace; + +import static java.lang.Math.*; + +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 TestPlanetGravityModel() { + this("Test:PlanetGravityModel"); + } + + protected TestPlanetGravityModel(String id) { + super(id); + } + + @Override + protected void doGetGravity(Vec3 pos, Vec3 output) { + // Change to a CS where (0;0;0) is the center of the center chunk + float px = pos.x - ChunkData.CHUNK_RADIUS; + float py = pos.y - ChunkData.CHUNK_RADIUS; + float pz = pos.z - ChunkData.CHUNK_RADIUS; + + // Assume weightlessness when too close to center + if ((px*px + py*py + pz*pz) < INNER_RADIUS*INNER_RADIUS) { + output.set(0, 0, 0); + return; + } + + // Cache absolute coordinates + float ax = abs(px); + float ay = abs(py); + float az = abs(pz); + + // Determine maximum and middle coordinates by absolute value + final float maxAbs; + final float midAbs; + + // herptyderp + if (ax > ay) { + if (ax > az) { + maxAbs = ax; + midAbs = ay > az ? ay : az; + } else { + maxAbs = az; + midAbs = ax; + } + } else { + if (ay > az) { + maxAbs = ay; + midAbs = ax > az ? ax : az; + } else { + maxAbs = az; + midAbs = ay; + } + } + + 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; + + if (maxAbs - midAbs < ROUNDNESS) { + 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"; + } + + output.mul(-GRAVITATIONAL_ACCELERATION); + } + + private void computeEdgeGravity(float lx, float ly, float lz, float rx, float ry, float rz, Vec3 output) { + // da math is gud, no worry + // - Javapony + + if (lx == 0) rx = 0; + if (ly == 0) ry = 0; + if (lz == 0) rz = 0; + + float scalarProduct = rx*lx + ry*ly + rz*lz; + float rSquared = rx*rx + ry*ry + rz*rz; + + float distanceAlongEdge = scalarProduct - (float) sqrt( + scalarProduct*scalarProduct - rSquared + ROUNDNESS*ROUNDNESS + ); + + output.set(lx, ly, lz).mul(-distanceAlongEdge).add(rx, ry, rz).div(ROUNDNESS); + + final float f = (float) sqrt(3.0/2); + + if (signum(lx) != signum(output.x)) { + computeEdgeGravity(0, ly*f, lz*f, rx, ry, rz, output); + } else if (signum(ly) != signum(output.y)) { + computeEdgeGravity(lx*f, 0, lz*f, rx, ry, rz, output); + } else if (signum(lz) != signum(output.z)) { + computeEdgeGravity(lx*f, ly*f, 0, rx, ry, rz, output); + } + } + + @Override + protected AbsFace doGetDiscreteUp(Vec3i chunkPos) { + AbsFace rounded = AbsFace.roundToFace(chunkPos.x, chunkPos.y, chunkPos.z); + return rounded == null ? AbsFace.POS_Z : rounded; + } + +} From bd5a1fa04e554aa7518eab4a50cf19df1cce81fd Mon Sep 17 00:00:00 2001 From: OLEGSHA Date: Sun, 28 Feb 2021 22:55:51 +0300 Subject: [PATCH 11/55] Added rotating AABBs through lots of pain and suffering - Collision models now rotate to match entity's general up direction - Extracted rotation logic from RelRelation into AxisRotations - Test:PlanetGravityModel is now properly centered - Fixed some small bugs --- .../client/world/ChunkRenderModel.java | 4 +- .../common/collision/AABBRotator.java | 134 ++++++++++++ .../common/world/entity/EntityData.java | 12 ++ .../common/world/generic/GenericChunk.java | 4 +- .../common/world/rels/AxisRotations.java | 193 ++++++++++++++++++ .../common/world/rels/BlockFaceResolver.java | 2 +- .../common/world/rels/RelRelation.java | 136 +----------- .../test/gen/TestPlanetGravityModel.java | 6 +- 8 files changed, 348 insertions(+), 143 deletions(-) create mode 100644 src/main/java/ru/windcorp/progressia/common/collision/AABBRotator.java create mode 100644 src/main/java/ru/windcorp/progressia/common/world/rels/AxisRotations.java diff --git a/src/main/java/ru/windcorp/progressia/client/world/ChunkRenderModel.java b/src/main/java/ru/windcorp/progressia/client/world/ChunkRenderModel.java index 471fb92..75857b8 100644 --- a/src/main/java/ru/windcorp/progressia/client/world/ChunkRenderModel.java +++ b/src/main/java/ru/windcorp/progressia/client/world/ChunkRenderModel.java @@ -36,8 +36,8 @@ import ru.windcorp.progressia.client.world.tile.TileRender; import ru.windcorp.progressia.client.world.tile.TileRenderNone; import ru.windcorp.progressia.client.world.tile.TileRenderStack; import ru.windcorp.progressia.common.world.ChunkData; +import ru.windcorp.progressia.common.world.rels.AxisRotations; import ru.windcorp.progressia.common.world.rels.RelFace; -import ru.windcorp.progressia.common.world.rels.RelRelation; public class ChunkRenderModel implements Renderable { @@ -61,7 +61,7 @@ public class ChunkRenderModel implements Renderable { chunk.getY() * ChunkData.BLOCKS_PER_CHUNK, chunk.getZ() * ChunkData.BLOCKS_PER_CHUNK ).translate(offset, offset, offset) - .mul(RelRelation.getResolutionMatrix4(chunk.getUp())) + .mul(AxisRotations.getResolutionMatrix4(chunk.getUp())) .translate(-offset, -offset, -offset); model.render(renderer); diff --git a/src/main/java/ru/windcorp/progressia/common/collision/AABBRotator.java b/src/main/java/ru/windcorp/progressia/common/collision/AABBRotator.java new file mode 100644 index 0000000..cbacb29 --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/common/collision/AABBRotator.java @@ -0,0 +1,134 @@ +/* + * 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.common.collision; + +import java.util.function.Supplier; + +import com.google.common.collect.ImmutableList; + +import glm.vec._3.Vec3; +import ru.windcorp.progressia.common.util.Vectors; +import ru.windcorp.progressia.common.world.rels.AbsFace; +import ru.windcorp.progressia.common.world.rels.AxisRotations; + +public class AABBRotator implements AABBoid { + + private class AABBRotatorWall implements Wall { + + private final int id; + + public AABBRotatorWall(int id) { + this.id = id; + } + + @Override + public void getOrigin(Vec3 output) { + parent.getWall(id).getOrigin(output); + AxisRotations.resolve(output, upSupplier.get(), output); + } + + @Override + public void getWidth(Vec3 output) { + parent.getWall(id).getWidth(output); + AxisRotations.resolve(output, upSupplier.get(), output); + } + + @Override + public void getHeight(Vec3 output) { + parent.getWall(id).getHeight(output); + AxisRotations.resolve(output, upSupplier.get(), output); + } + + } + + private final Supplier upSupplier; + private final Supplier hingeSupplier; + private final AABBoid parent; + + private final AABBRotatorWall[] walls = new AABBRotatorWall[AbsFace.BLOCK_FACE_COUNT]; + + { + for (int id = 0; id < walls.length; ++id) { + walls[id] = new AABBRotatorWall(id); + } + } + + public AABBRotator(Supplier upSupplier, Supplier hingeSupplier, AABBoid parent) { + this.upSupplier = upSupplier; + this.hingeSupplier = hingeSupplier; + this.parent = parent; + } + + @Override + public void setOrigin(Vec3 origin) { + Vec3 relativeOrigin = Vectors.grab3(); + Vec3 hinge = hingeSupplier.get(); + + origin.sub(hinge, relativeOrigin); + AxisRotations.relativize(relativeOrigin, upSupplier.get(), relativeOrigin); + relativeOrigin.add(hinge); + + parent.setOrigin(relativeOrigin); + + Vectors.release(relativeOrigin); + } + + @Override + public void moveOrigin(Vec3 displacement) { + parent.moveOrigin(displacement); + } + + @Override + public void getOrigin(Vec3 output) { + parent.getOrigin(output); + Vec3 hinge = hingeSupplier.get(); + + output.sub(hinge); + AxisRotations.resolve(output, upSupplier.get(), output); + output.add(hinge); + } + + @Override + public void getSize(Vec3 output) { + parent.getSize(output); + AxisRotations.resolve(output, upSupplier.get(), output); + output.abs(); + } + + @Override + public Wall getWall(int faceId) { + return walls[faceId]; + } + + public static CollisionModel rotate(Supplier upSupplier, Supplier hingeSupplier, CollisionModel parent) { + if (parent instanceof AABBoid) { + return new AABBRotator(upSupplier, hingeSupplier, (AABBoid) parent); + } else if (parent instanceof CompoundCollisionModel) { + ImmutableList.Builder models = ImmutableList.builder(); + + for (CollisionModel original : ((CompoundCollisionModel) parent).getModels()) { + models.add(rotate(upSupplier, hingeSupplier, original)); + } + + return new CompoundCollisionModel(models.build()); + } else { + throw new RuntimeException("not supported"); + } + } + +} diff --git a/src/main/java/ru/windcorp/progressia/common/world/entity/EntityData.java b/src/main/java/ru/windcorp/progressia/common/world/entity/EntityData.java index e776e6a..d54cca1 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/entity/EntityData.java +++ b/src/main/java/ru/windcorp/progressia/common/world/entity/EntityData.java @@ -26,12 +26,14 @@ import java.util.Objects; import glm.mat._3.Mat3; import glm.vec._3.Vec3; import ru.windcorp.jputil.chars.StringUtil; +import ru.windcorp.progressia.common.collision.AABBRotator; import ru.windcorp.progressia.common.collision.Collideable; import ru.windcorp.progressia.common.collision.CollisionModel; import ru.windcorp.progressia.common.state.IOContext; import ru.windcorp.progressia.common.state.StatefulObject; import ru.windcorp.progressia.common.util.Matrices; import ru.windcorp.progressia.common.world.generic.GenericEntity; +import ru.windcorp.progressia.common.world.rels.AbsFace; public class EntityData extends StatefulObject implements Collideable, GenericEntity { @@ -51,6 +53,7 @@ public class EntityData extends StatefulObject implements Collideable, GenericEn private long entityId; private CollisionModel collisionModel = null; + private CollisionModel rotatedCollisionModel = null; private double age = 0; @@ -107,11 +110,16 @@ public class EntityData extends StatefulObject implements Collideable, GenericEn @Override public CollisionModel getCollisionModel() { + return rotatedCollisionModel; + } + + public CollisionModel getOriginalCollisionModel() { return collisionModel; } public void setCollisionModel(CollisionModel collisionModel) { this.collisionModel = collisionModel; + this.rotatedCollisionModel = AABBRotator.rotate(this::getUpFace, this::getPosition, collisionModel); } @Override @@ -164,6 +172,10 @@ public class EntityData extends StatefulObject implements Collideable, GenericEn public Vec3 getUpVector() { return upVector; } + + public AbsFace getUpFace() { + return AbsFace.roundToFace(getUpVector()); + } /** * Sets this entity's up vector without updating looking at-vector. diff --git a/src/main/java/ru/windcorp/progressia/common/world/generic/GenericChunk.java b/src/main/java/ru/windcorp/progressia/common/world/generic/GenericChunk.java index 1768119..95c18be 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/generic/GenericChunk.java +++ b/src/main/java/ru/windcorp/progressia/common/world/generic/GenericChunk.java @@ -25,8 +25,8 @@ import ru.windcorp.progressia.common.util.VectorUtil; import ru.windcorp.progressia.common.util.Vectors; import ru.windcorp.progressia.common.world.Coordinates; import ru.windcorp.progressia.common.world.rels.AbsFace; +import ru.windcorp.progressia.common.world.rels.AxisRotations; import ru.windcorp.progressia.common.world.rels.BlockFace; -import ru.windcorp.progressia.common.world.rels.RelRelation; public interface GenericChunk, B extends GenericBlock, T extends GenericTile, TS extends GenericTileStack> { @@ -52,7 +52,7 @@ public interface GenericChunk, B exten output.set(relativeBlockInChunk.x, relativeBlockInChunk.y, relativeBlockInChunk.z); output.mul(2).sub(offset); - RelRelation.resolve(output, getUp(), output); + AxisRotations.resolve(output, getUp(), output); output.add(offset).div(2); diff --git a/src/main/java/ru/windcorp/progressia/common/world/rels/AxisRotations.java b/src/main/java/ru/windcorp/progressia/common/world/rels/AxisRotations.java new file mode 100644 index 0000000..2d13c19 --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/common/world/rels/AxisRotations.java @@ -0,0 +1,193 @@ +/* + * 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.common.world.rels; + +import static ru.windcorp.progressia.common.util.VectorUtil.SignedAxis.NEG_X; +import static ru.windcorp.progressia.common.util.VectorUtil.SignedAxis.NEG_Y; +import static ru.windcorp.progressia.common.util.VectorUtil.SignedAxis.NEG_Z; +import static ru.windcorp.progressia.common.util.VectorUtil.SignedAxis.POS_X; +import static ru.windcorp.progressia.common.util.VectorUtil.SignedAxis.POS_Y; +import static ru.windcorp.progressia.common.util.VectorUtil.SignedAxis.POS_Z; + +import java.util.Map; + +import glm.mat._3.Mat3; +import glm.mat._4.Mat4; +import glm.vec._3.Vec3; +import glm.vec._3.i.Vec3i; +import ru.windcorp.progressia.common.util.VectorUtil; +import ru.windcorp.progressia.common.util.VectorUtil.SignedAxis; + +public class AxisRotations { + + private static class Rotation { + private static class MyMat3i { + private final int m00, m01, m02, m10, m11, m12, m20, m21, m22; + + public MyMat3i(Mat3 integerMatrix) { + this.m00 = (int) integerMatrix.m00; + this.m01 = (int) integerMatrix.m01; + this.m02 = (int) integerMatrix.m02; + this.m10 = (int) integerMatrix.m10; + this.m11 = (int) integerMatrix.m11; + this.m12 = (int) integerMatrix.m12; + this.m20 = (int) integerMatrix.m20; + this.m21 = (int) integerMatrix.m21; + this.m22 = (int) integerMatrix.m22; + } + + public Vec3i mul(Vec3i right, Vec3i res) { + res.set( + m00 * right.x + m10 * right.y + m20 * right.z, + m01 * right.x + m11 * right.y + m21 * right.z, + m02 * right.x + m12 * right.y + m22 * right.z + ); + return res; + } + } + + private final Mat3 resolutionMatrix3 = new Mat3(); + private final Mat4 resolutionMatrix4 = new Mat4(); + private final MyMat3i resolutionMatrix3i; + + private final Mat3 relativizationMatrix3 = new Mat3(); + private final Mat4 relativizationMatrix4 = new Mat4(); + private final MyMat3i relativizationMatrix3i; + + private Rotation(SignedAxis northDestination, SignedAxis westDestination, SignedAxis upDestination) { + resolutionMatrix3.c0(computeUnitVectorAlong(northDestination)); + resolutionMatrix3.c1(computeUnitVectorAlong(westDestination)); + resolutionMatrix3.c2(computeUnitVectorAlong(upDestination)); + + resolutionMatrix3.toMat4(resolutionMatrix4); + resolutionMatrix3i = new MyMat3i(resolutionMatrix3); + + relativizationMatrix3.set(resolutionMatrix3).transpose(); + relativizationMatrix4.set(resolutionMatrix4).transpose(); + relativizationMatrix3i = new MyMat3i(relativizationMatrix3); + } + + private static Vec3 computeUnitVectorAlong(SignedAxis signedAxis) { + Vec3 result = new Vec3(0, 0, 0); + VectorUtil.set(result, signedAxis.getAxis(), signedAxis.getSign()); + return result; + } + + /** + * @return the resolutionMatrix3 + */ + public Mat3 getResolutionMatrix3() { + return resolutionMatrix3; + } + + /** + * @return the resolutionMatrix4 + */ + public Mat4 getResolutionMatrix4() { + return resolutionMatrix4; + } + + /** + * @return the relativizationMatrix3 + */ + public Mat3 getRelativizationMatrix3() { + return relativizationMatrix3; + } + + /** + * @return the relativizationMatrix4 + */ + public Mat4 getRelativizationMatrix4() { + return relativizationMatrix4; + } + + public Vec3i resolve(Vec3i output, Vec3i input) { + if (output == null) { + output = new Vec3i(); + } + resolutionMatrix3i.mul(input, output); + return output; + } + + public Vec3i relativize(Vec3i output, Vec3i input) { + if (output == null) { + output = new Vec3i(); + } + relativizationMatrix3i.mul(input, output); + return output; + } + + public Vec3 resolve(Vec3 output, Vec3 input) { + if (output == null) { + output = new Vec3(); + } + resolutionMatrix3.mul(input, output); + return output; + } + + public Vec3 relativize(Vec3 output, Vec3 input) { + if (output == null) { + output = new Vec3(); + } + relativizationMatrix3.mul(input, output); + return output; + } + } + + private final static Map TRANSFORMATIONS = AbsFace.mapToFaces( + new Rotation(POS_X, POS_Y, POS_Z), + new Rotation(POS_X, NEG_Y, NEG_Z), + new Rotation(POS_Z, NEG_Y, POS_X), + new Rotation(POS_Z, POS_Y, NEG_X), + new Rotation(POS_Z, NEG_X, NEG_Y), + new Rotation(POS_Z, POS_X, POS_Y) + ); + + public static Vec3i resolve(Vec3i relative, AbsFace up, Vec3i output) { + return TRANSFORMATIONS.get(up).resolve(output, relative); + } + + public static Vec3 resolve(Vec3 relative, AbsFace up, Vec3 output) { + return TRANSFORMATIONS.get(up).resolve(output, relative); + } + + public static Vec3i relativize(Vec3i absolute, AbsFace up, Vec3i output) { + return TRANSFORMATIONS.get(up).relativize(output, absolute); + } + + public static Vec3 relativize(Vec3 absolute, AbsFace up, Vec3 output) { + return TRANSFORMATIONS.get(up).relativize(output, absolute); + } + + public static Mat3 getResolutionMatrix3(AbsFace up) { + return TRANSFORMATIONS.get(up).getResolutionMatrix3(); + } + + public static Mat4 getResolutionMatrix4(AbsFace up) { + return TRANSFORMATIONS.get(up).getResolutionMatrix4(); + } + + public static Mat3 getRelativizationMatrix3(AbsFace up) { + return TRANSFORMATIONS.get(up).getRelativizationMatrix3(); + } + + public static Mat4 getRelativizationMatrix4(AbsFace up) { + return TRANSFORMATIONS.get(up).getRelativizationMatrix4(); + } + +} diff --git a/src/main/java/ru/windcorp/progressia/common/world/rels/BlockFaceResolver.java b/src/main/java/ru/windcorp/progressia/common/world/rels/BlockFaceResolver.java index 3e25e1b..e1f469e 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/rels/BlockFaceResolver.java +++ b/src/main/java/ru/windcorp/progressia/common/world/rels/BlockFaceResolver.java @@ -37,7 +37,7 @@ public class BlockFaceResolver { for (AbsFace up : AbsFace.getFaces()) { for (RelFace relative : RelFace.getFaces()) { - AbsFace absolute = (AbsFace) AbsRelation.of(RelRelation.resolve(relative.getRelVector(), up, null)); + AbsFace absolute = (AbsFace) AbsRelation.of(AxisRotations.resolve(relative.getRelVector(), up, null)); RESOLUTION_TABLE[up.getId()][relative.getId()] = absolute; RELATIVIZATION_TABLE[up.getId()][absolute.getId()] = relative; diff --git a/src/main/java/ru/windcorp/progressia/common/world/rels/RelRelation.java b/src/main/java/ru/windcorp/progressia/common/world/rels/RelRelation.java index 5268a26..6eec211 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/rels/RelRelation.java +++ b/src/main/java/ru/windcorp/progressia/common/world/rels/RelRelation.java @@ -17,122 +17,15 @@ */ package ru.windcorp.progressia.common.world.rels; -import java.util.Map; - -import glm.mat._3.Mat3; -import glm.mat._4.Mat4; import glm.vec._3.Vec3; 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.VectorUtil.SignedAxis; - -import static ru.windcorp.progressia.common.util.VectorUtil.SignedAxis.*; /** * Name stands for Relative Relation */ public class RelRelation extends BlockRelation { - private static class Rotation { - private final SignedAxis northDestination; - private final SignedAxis westDestination; - private final SignedAxis upDestination; - - private final Mat3 resolutionMatrix3 = new Mat3(); - private final Mat4 resolutionMatrix4 = new Mat4(); - - private final Mat3 relativizationMatrix3 = new Mat3(); - private final Mat4 relativizationMatrix4 = new Mat4(); - - private Rotation(SignedAxis northDestination, SignedAxis westDestination, SignedAxis upDestination) { - this.northDestination = northDestination; - this.westDestination = westDestination; - this.upDestination = upDestination; - - resolutionMatrix3.c0(apply(null, new Vec3(1, 0, 0))); - resolutionMatrix3.c1(apply(null, new Vec3(0, 1, 0))); - resolutionMatrix3.c2(apply(null, new Vec3(0, 0, 1))); - resolutionMatrix3.toMat4(resolutionMatrix4); - - relativizationMatrix3.set(resolutionMatrix3).transpose(); - relativizationMatrix4.set(resolutionMatrix4).transpose(); - } - - /** - * @return the resolutionMatrix3 - */ - public Mat3 getResolutionMatrix3() { - return resolutionMatrix3; - } - - /** - * @return the resolutionMatrix4 - */ - public Mat4 getResolutionMatrix4() { - return resolutionMatrix4; - } - - /** - * @return the relativizationMatrix3 - */ - public Mat3 getRelativizationMatrix3() { - return relativizationMatrix3; - } - - /** - * @return the relativizationMatrix4 - */ - public Mat4 getRelativizationMatrix4() { - return relativizationMatrix4; - } - - public Vec3i apply(Vec3i output, Vec3i input) { - if (output == null) { - output = new Vec3i(); - } - - int inX = input.x, inY = input.y, inZ = input.z; - - set(output, inX, northDestination); - set(output, inY, westDestination); - set(output, inZ, upDestination); - - return output; - } - - private static void set(Vec3i output, int value, SignedAxis axis) { - VectorUtil.set(output, axis.getAxis(), axis.isPositive() ? +value : -value); - } - - public Vec3 apply(Vec3 output, Vec3 input) { - if (output == null) { - output = new Vec3(); - } - - float inX = input.x, inY = input.y, inZ = input.z; - - set(output, inX, northDestination); - set(output, inY, westDestination); - set(output, inZ, upDestination); - - return output; - } - - private static void set(Vec3 output, float value, SignedAxis axis) { - VectorUtil.set(output, axis.getAxis(), axis.isPositive() ? +value : -value); - } - } - - private final static Map TRANSFORMATIONS = AbsFace.mapToFaces( - new Rotation(POS_X, POS_Y, POS_Z), - new Rotation(POS_X, NEG_Y, NEG_Z), - new Rotation(POS_Z, NEG_Y, POS_X), - new Rotation(POS_Z, POS_Y, NEG_X), - new Rotation(POS_Z, NEG_X, NEG_Y), - new Rotation(POS_Z, POS_X, POS_Y) - ); - private final Vec3i vector = new Vec3i(); private final Vec3 floatVector = new Vec3(); private final Vec3 normalized = new Vec3(); @@ -242,38 +135,11 @@ public class RelRelation extends BlockRelation { private AbsRelation computeResolution(AbsFace up) { Vec3i resolution = Vectors.grab3i(); - resolve(vector, up, resolution); + AxisRotations.resolve(vector, up, resolution); AbsRelation result = AbsRelation.of(resolution); Vectors.release(resolution); return result; } - - public static Vec3i resolve(Vec3i relative, AbsFace up, Vec3i output) { - if (output == null) { - output = new Vec3i(); - } - - TRANSFORMATIONS.get(up).apply(output, relative); - - return output; - } - - public static Mat3 getResolutionMatrix3(AbsFace up) { - return TRANSFORMATIONS.get(up).getResolutionMatrix3(); - } - - public static Mat4 getResolutionMatrix4(AbsFace up) { - return TRANSFORMATIONS.get(up).getResolutionMatrix4(); - } - - - public static Mat3 getRelativizationMatrix3(AbsFace up) { - return TRANSFORMATIONS.get(up).getRelativizationMatrix3(); - } - - public static Mat4 getRelativizationMatrix4(AbsFace up) { - return TRANSFORMATIONS.get(up).getRelativizationMatrix4(); - } @Override protected Vec3i getSample() { diff --git a/src/main/java/ru/windcorp/progressia/test/gen/TestPlanetGravityModel.java b/src/main/java/ru/windcorp/progressia/test/gen/TestPlanetGravityModel.java index 05d659a..f3dc35f 100644 --- a/src/main/java/ru/windcorp/progressia/test/gen/TestPlanetGravityModel.java +++ b/src/main/java/ru/windcorp/progressia/test/gen/TestPlanetGravityModel.java @@ -43,9 +43,9 @@ public class TestPlanetGravityModel extends GravityModel { @Override protected void doGetGravity(Vec3 pos, Vec3 output) { // Change to a CS where (0;0;0) is the center of the center chunk - float px = pos.x - ChunkData.CHUNK_RADIUS; - float py = pos.y - ChunkData.CHUNK_RADIUS; - float pz = pos.z - ChunkData.CHUNK_RADIUS; + 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) { From a9a21ce66476fc81b9fd9dee938fcb8e69adad47 Mon Sep 17 00:00:00 2001 From: OLEGSHA Date: Sun, 28 Feb 2021 23:03:23 +0300 Subject: [PATCH 12/55] Moved planet generation code to its own package --- src/main/java/ru/windcorp/progressia/server/Server.java | 2 +- src/main/java/ru/windcorp/progressia/test/TestContent.java | 2 +- .../progressia/test/gen/{ => planet}/TestPlanetGenerator.java | 2 +- .../test/gen/{ => planet}/TestPlanetGravityModel.java | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) rename src/main/java/ru/windcorp/progressia/test/gen/{ => planet}/TestPlanetGenerator.java (99%) rename src/main/java/ru/windcorp/progressia/test/gen/{ => planet}/TestPlanetGravityModel.java (98%) diff --git a/src/main/java/ru/windcorp/progressia/server/Server.java b/src/main/java/ru/windcorp/progressia/server/Server.java index 40fdca6..fcdee16 100644 --- a/src/main/java/ru/windcorp/progressia/server/Server.java +++ b/src/main/java/ru/windcorp/progressia/server/Server.java @@ -31,7 +31,7 @@ import ru.windcorp.progressia.server.world.WorldLogic; 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.test.gen.TestPlanetGenerator; +import ru.windcorp.progressia.test.gen.planet.TestPlanetGenerator; public class Server { diff --git a/src/main/java/ru/windcorp/progressia/test/TestContent.java b/src/main/java/ru/windcorp/progressia/test/TestContent.java index d34c3ba..464dc46 100644 --- a/src/main/java/ru/windcorp/progressia/test/TestContent.java +++ b/src/main/java/ru/windcorp/progressia/test/TestContent.java @@ -59,7 +59,7 @@ import ru.windcorp.progressia.server.world.block.*; import ru.windcorp.progressia.server.world.entity.*; import ru.windcorp.progressia.server.world.tile.*; import ru.windcorp.progressia.test.gen.TestGravityModel; -import ru.windcorp.progressia.test.gen.TestPlanetGravityModel; +import ru.windcorp.progressia.test.gen.planet.TestPlanetGravityModel; public class TestContent { diff --git a/src/main/java/ru/windcorp/progressia/test/gen/TestPlanetGenerator.java b/src/main/java/ru/windcorp/progressia/test/gen/planet/TestPlanetGenerator.java similarity index 99% rename from src/main/java/ru/windcorp/progressia/test/gen/TestPlanetGenerator.java rename to src/main/java/ru/windcorp/progressia/test/gen/planet/TestPlanetGenerator.java index bbcdbfd..edc1811 100644 --- a/src/main/java/ru/windcorp/progressia/test/gen/TestPlanetGenerator.java +++ b/src/main/java/ru/windcorp/progressia/test/gen/planet/TestPlanetGenerator.java @@ -15,7 +15,7 @@ * 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; +package ru.windcorp.progressia.test.gen.planet; import java.io.DataInputStream; import java.io.DataOutputStream; diff --git a/src/main/java/ru/windcorp/progressia/test/gen/TestPlanetGravityModel.java b/src/main/java/ru/windcorp/progressia/test/gen/planet/TestPlanetGravityModel.java similarity index 98% rename from src/main/java/ru/windcorp/progressia/test/gen/TestPlanetGravityModel.java rename to src/main/java/ru/windcorp/progressia/test/gen/planet/TestPlanetGravityModel.java index f3dc35f..309e0de 100644 --- a/src/main/java/ru/windcorp/progressia/test/gen/TestPlanetGravityModel.java +++ b/src/main/java/ru/windcorp/progressia/test/gen/planet/TestPlanetGravityModel.java @@ -15,7 +15,7 @@ * 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; +package ru.windcorp.progressia.test.gen.planet; import glm.vec._3.Vec3; import glm.vec._3.i.Vec3i; From abd8d9eebbd52e2a40b196e98269d122ce337a57 Mon Sep 17 00:00:00 2001 From: OLEGSHA Date: Sun, 28 Feb 2021 23:31:57 +0300 Subject: [PATCH 13/55] Moved some functionality into WorldGenerator - WorldGenerators now suggest a spawn location - WorldGenerators are no longer responsible for adding chunks --- .../ru/windcorp/progressia/server/PlayerManager.java | 2 +- .../windcorp/progressia/server/world/WorldLogic.java | 4 +++- .../server/world/generation/WorldGenerator.java | 3 +++ .../java/ru/windcorp/progressia/test/TestContent.java | 3 --- .../progressia/test/gen/TestWorldGenerator.java | 10 +++++++--- .../test/gen/planet/TestPlanetGenerator.java | 7 ++++++- 6 files changed, 20 insertions(+), 9 deletions(-) diff --git a/src/main/java/ru/windcorp/progressia/server/PlayerManager.java b/src/main/java/ru/windcorp/progressia/server/PlayerManager.java index 8e34b49..60b07f1 100644 --- a/src/main/java/ru/windcorp/progressia/server/PlayerManager.java +++ b/src/main/java/ru/windcorp/progressia/server/PlayerManager.java @@ -60,7 +60,7 @@ public class PlayerManager { EntityData player = EntityDataRegistry.getInstance().create("Test:Player"); player.setEntityId(TestContent.PLAYER_ENTITY_ID); - player.setPosition(TestContent.SPAWN); + player.setPosition(getServer().getWorld().getGenerator().suggestSpawnLocation()); player.setUpVector(new Vec3(0, 0, 1)); player.setLookingAt(new Vec3(2, 1, 0)); diff --git a/src/main/java/ru/windcorp/progressia/server/world/WorldLogic.java b/src/main/java/ru/windcorp/progressia/server/world/WorldLogic.java index 5931e34..bf5da5e 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/WorldLogic.java +++ b/src/main/java/ru/windcorp/progressia/server/world/WorldLogic.java @@ -106,7 +106,9 @@ public class WorldLogic } public ChunkData generate(Vec3i chunkPos) { - return getGenerator().generate(chunkPos, getData()); + ChunkData chunk = getGenerator().generate(chunkPos, getData()); + getData().addChunk(chunk); + return chunk; } public ChunkLogic getChunk(ChunkData chunkData) { diff --git a/src/main/java/ru/windcorp/progressia/server/world/generation/WorldGenerator.java b/src/main/java/ru/windcorp/progressia/server/world/generation/WorldGenerator.java index 6a85e45..f31cbc4 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/generation/WorldGenerator.java +++ b/src/main/java/ru/windcorp/progressia/server/world/generation/WorldGenerator.java @@ -22,6 +22,7 @@ import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; +import glm.vec._3.Vec3; import glm.vec._3.i.Vec3i; import ru.windcorp.progressia.common.util.namespaces.Namespaced; import ru.windcorp.progressia.common.world.ChunkData; @@ -45,5 +46,7 @@ public abstract class WorldGenerator extends Namespaced { public abstract boolean isChunkReady(Object hint); public abstract GravityModel getGravityModel(); + + public abstract Vec3 suggestSpawnLocation(); } diff --git a/src/main/java/ru/windcorp/progressia/test/TestContent.java b/src/main/java/ru/windcorp/progressia/test/TestContent.java index 464dc46..dd72aa8 100644 --- a/src/main/java/ru/windcorp/progressia/test/TestContent.java +++ b/src/main/java/ru/windcorp/progressia/test/TestContent.java @@ -30,7 +30,6 @@ import java.util.function.Consumer; import org.lwjgl.glfw.GLFW; -import glm.vec._3.Vec3; import glm.vec._3.i.Vec3i; import ru.windcorp.progressia.client.ClientState; import ru.windcorp.progressia.client.audio.SoundEffect; @@ -66,8 +65,6 @@ public class TestContent { public static final String PLAYER_LOGIN = "Sasha"; public static final long PLAYER_ENTITY_ID = 0x42; public static final long STATIE_ENTITY_ID = 0xDEADBEEF; -// public static final Vec3 SPAWN = new Vec3(8, 8, 880); - public static final Vec3 SPAWN = new Vec3(0, 0, 66); public static final List PLACEABLE_BLOCKS = new ArrayList<>(); public static final List PLACEABLE_TILES = new ArrayList<>(); diff --git a/src/main/java/ru/windcorp/progressia/test/gen/TestWorldGenerator.java b/src/main/java/ru/windcorp/progressia/test/gen/TestWorldGenerator.java index 9d4ff6e..e66d9b7 100644 --- a/src/main/java/ru/windcorp/progressia/test/gen/TestWorldGenerator.java +++ b/src/main/java/ru/windcorp/progressia/test/gen/TestWorldGenerator.java @@ -23,6 +23,7 @@ import java.io.DataOutputStream; import java.io.IOException; import java.util.Random; +import glm.vec._3.Vec3; import glm.vec._3.i.Vec3i; import ru.windcorp.progressia.common.util.VectorUtil; import ru.windcorp.progressia.common.util.Vectors; @@ -54,6 +55,11 @@ public class TestWorldGenerator extends AbstractWorldGenerator { } }); } + + @Override + public Vec3 suggestSpawnLocation() { + return new Vec3(8, 8, 880); + } @Override protected Boolean doReadGenerationHint(DataInputStream input) throws IOException, DecodingException { @@ -72,9 +78,7 @@ public class TestWorldGenerator extends AbstractWorldGenerator { @Override public ChunkData generate(Vec3i chunkPos, WorldData world) { - ChunkData chunk = generateUnpopulated(chunkPos, world); - world.addChunk(chunk); - return chunk; + return generateUnpopulated(chunkPos, world); } private ChunkData generateUnpopulated(Vec3i chunkPos, WorldData world) { 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 edc1811..ea45d1e 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 @@ -22,6 +22,7 @@ import java.io.DataOutputStream; import java.io.IOException; import java.util.Arrays; +import glm.vec._3.Vec3; import glm.vec._3.i.Vec3i; import ru.windcorp.progressia.common.util.VectorUtil; import ru.windcorp.progressia.common.world.ChunkData; @@ -47,6 +48,11 @@ public class TestPlanetGenerator extends AbstractWorldGenerator { throw new IllegalArgumentException("planetRadius too small, must be at least 32 m"); } } + + @Override + public Vec3 suggestSpawnLocation() { + return new Vec3(0, 0, 66); + } @Override protected Boolean doReadGenerationHint(DataInputStream input) throws IOException, DecodingException { @@ -70,7 +76,6 @@ public class TestPlanetGenerator extends AbstractWorldGenerator { generate(chunk); chunk.setGenerationHint(true); - world.addChunk(chunk); return chunk; } From f4311fb27c28fc81e3468c728bf1e925052058c0 Mon Sep 17 00:00:00 2001 From: OLEGSHA Date: Mon, 15 Mar 2021 18:54:53 +0300 Subject: [PATCH 14/55] Created a bare-bones implementation of the final planet generator - Added Planet generator - Uses temporary generation algorithms - Added Surface generator - Added FloatRangeMap --- .../common/util/ArrayFloatRangeMap.java | 225 ++++++++++++++++++ .../progressia/common/util/FloatRangeMap.java | 36 +++ .../progressia/common/util/VectorUtil.java | 82 +++++++ .../progressia/common/world/BlockRay.java | 6 +- .../common/world/generic/GenericChunk.java | 59 +++++ .../progressia/server/ChunkManager.java | 17 +- .../ru/windcorp/progressia/server/Server.java | 3 +- .../progressia/test/gen/TerrainLayer.java | 30 +++ .../progressia/test/gen/planet/Planet.java | 82 +++++++ .../gen/planet/PlanetScatterGenerator.java | 41 ++++ .../gen/planet/PlanetTerrainGenerator.java | 107 +++++++++ .../test/gen/planet/TestHeightMap.java | 70 ++++++ .../test/gen/planet/TestPlanetGenerator.java | 142 ++--------- .../test/gen/surface/SurfaceFloatField.java | 27 +++ .../gen/surface/SurfaceScatterGenerator.java | 28 +++ .../gen/surface/SurfaceTerrainGenerator.java | 74 ++++++ 16 files changed, 896 insertions(+), 133 deletions(-) create mode 100644 src/main/java/ru/windcorp/progressia/common/util/ArrayFloatRangeMap.java create mode 100644 src/main/java/ru/windcorp/progressia/common/util/FloatRangeMap.java create mode 100644 src/main/java/ru/windcorp/progressia/test/gen/TerrainLayer.java create mode 100644 src/main/java/ru/windcorp/progressia/test/gen/planet/Planet.java create mode 100644 src/main/java/ru/windcorp/progressia/test/gen/planet/PlanetScatterGenerator.java create mode 100644 src/main/java/ru/windcorp/progressia/test/gen/planet/PlanetTerrainGenerator.java create mode 100644 src/main/java/ru/windcorp/progressia/test/gen/planet/TestHeightMap.java create mode 100644 src/main/java/ru/windcorp/progressia/test/gen/surface/SurfaceFloatField.java create mode 100644 src/main/java/ru/windcorp/progressia/test/gen/surface/SurfaceScatterGenerator.java create mode 100644 src/main/java/ru/windcorp/progressia/test/gen/surface/SurfaceTerrainGenerator.java diff --git a/src/main/java/ru/windcorp/progressia/common/util/ArrayFloatRangeMap.java b/src/main/java/ru/windcorp/progressia/common/util/ArrayFloatRangeMap.java new file mode 100644 index 0000000..4eea3f6 --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/common/util/ArrayFloatRangeMap.java @@ -0,0 +1,225 @@ +/* + * 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.common.util; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.ListIterator; +import java.util.Objects; + +public class ArrayFloatRangeMap implements FloatRangeMap { + + protected static class Node implements Comparable> { + public float pos; + public E value; + + public Node(float pos, E value) { + this.pos = pos; + this.value = value; + } + + @Override + public int compareTo(Node o) { + return Float.compare(pos, o.pos); + } + } + + /* + * Expects a random-access list + */ + protected final List> nodes; + protected int ranges = 0; + + protected static final int DEFAULT_CAPACITY = 16; + + public ArrayFloatRangeMap(int capacity) { + this.nodes = new ArrayList<>(2 * capacity); + } + + public ArrayFloatRangeMap() { + this(DEFAULT_CAPACITY); + } + + @Override + public int size() { + return this.ranges; + } + + @Override + public Iterator iterator() { + return new Iterator() { + + private int nextIndex = 0; + + { + assert nodes.isEmpty() || nodes.get(nextIndex).value != null; + } + + private void findNext() { + while (nextIndex < nodes.size()) { + nextIndex++; + Node node = nodes.get(nextIndex); + if (node.value != null) return; + } + } + + @Override + public boolean hasNext() { + return nextIndex < nodes.size(); + } + + @Override + public E next() { + E result = nodes.get(nextIndex).value; + findNext(); + return result; + } + }; + } + + /** + * Returns an index of the smallest {@link Node} larger than or exactly at + * {@code position}. + * + * @param position the position to look up + * @return an index in the {@link #nodes} list containing the first + * {@link Node} whose {@link Node#pos} is not smaller than + * {@code position}, or {@code nodes.size()} if no such index exists + */ + protected int findCeiling(float position) { + + /* + * Implementation based on OpenJDK's + * Collections.indexedBinarySearch(List, Comparator) + */ + + int low = 0; + int high = nodes.size() - 1; + + while (low <= high) { + int mid = (low + high) >>> 1; + float midVal = nodes.get(mid).pos; + int cmp = Float.compare(midVal, position); + + if (cmp < 0) + low = mid + 1; + else if (cmp > 0) + high = mid - 1; + else + return mid; // key found + } + + return low; // the insertion point is the desired index + } + + /** + * Returns an index of the largest {@link Node} smaller than or exactly at + * {@code position}. + * + * @param position the position to look up + * @return an index in the {@link #nodes} list containing the last + * {@link Node} whose {@link Node#pos} is not greater than + * {@code position}, or {@code -1} if no such index exists + */ + protected int findFloor(float position) { + + /* + * Implementation based on OpenJDK's + * Collections.indexedBinarySearch(List, Comparator) + */ + + int low = 0; + int high = nodes.size() - 1; + + while (low <= high) { + int mid = (low + high) >>> 1; + float midVal = nodes.get(mid).pos; + int cmp = Float.compare(midVal, position); + + if (cmp < 0) + low = mid + 1; + else if (cmp > 0) + high = mid - 1; + else + return mid; // key found + } + + return low - 1; // the insertion point immediately follows the desired index + } + + protected Node getEffectiveNode(float at) { + int effectiveNodeIndex = findFloor(at); + if (effectiveNodeIndex < 0) return null; + return nodes.get(effectiveNodeIndex); + } + + @Override + public E get(float at) { + Node effectiveNode = getEffectiveNode(at); + return effectiveNode == null ? null : effectiveNode.value; + } + + @Override + public void put(float min, float max, E element) { + Objects.requireNonNull(element, "element"); + + if (!(max > min)) // This funky construction also deals with NaNs since NaNs always fail any comparison + { + throw new IllegalArgumentException(max + " is not greater than " + min); + } + + int indexOfInsertionOfMin = findCeiling(min); + + nodes.add(indexOfInsertionOfMin, new Node(min, element)); + ranges++; + + ListIterator> it = nodes.listIterator(indexOfInsertionOfMin + 1); + E elementEffectiveImmediatelyAfterInsertedRange = null; + + if (indexOfInsertionOfMin > 0) { + elementEffectiveImmediatelyAfterInsertedRange = nodes.get(indexOfInsertionOfMin - 1).value; + } + + while (it.hasNext()) { + Node node = it.next(); + + if (node.pos >= max) { + break; + } + + elementEffectiveImmediatelyAfterInsertedRange = node.value; + if (elementEffectiveImmediatelyAfterInsertedRange != null) { + // Removing an actual range + ranges--; + } + it.remove(); + } + + if (max != Float.POSITIVE_INFINITY) { + nodes.add(indexOfInsertionOfMin + 1, new Node(max, elementEffectiveImmediatelyAfterInsertedRange)); + + if (elementEffectiveImmediatelyAfterInsertedRange != null) { + // We might have added one right back + ranges++; + } + } + + } + +} diff --git a/src/main/java/ru/windcorp/progressia/common/util/FloatRangeMap.java b/src/main/java/ru/windcorp/progressia/common/util/FloatRangeMap.java new file mode 100644 index 0000000..303d6a8 --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/common/util/FloatRangeMap.java @@ -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 . + */ +package ru.windcorp.progressia.common.util; + +public interface FloatRangeMap extends Iterable { + + void put(float min, float max, E element); + E get(float at); + + int size(); + + default boolean defines(float position) { + return get(position) != null; + } + + default E getOrDefault(float at, E def) { + E result = get(at); + return result == null ? def : result; + } + +} diff --git a/src/main/java/ru/windcorp/progressia/common/util/VectorUtil.java b/src/main/java/ru/windcorp/progressia/common/util/VectorUtil.java index 6bef350..f25368f 100644 --- a/src/main/java/ru/windcorp/progressia/common/util/VectorUtil.java +++ b/src/main/java/ru/windcorp/progressia/common/util/VectorUtil.java @@ -290,6 +290,88 @@ public class VectorUtil { ); return output; } + + public static Vec3i sort(Vec3i input, Vec3i output) { + if (output == null) { + output = new Vec3i(); + } + + int ax = input.x, ay = input.y, az = input.z; + + if (ax > ay) { + if (ax > az) { + output.x = ax; + output.y = ay > az ? ay : az; + output.z = ay > az ? az : ay; + } else { + output.x = az; + output.y = ax; + output.z = ay; + } + } else { + if (ay > az) { + output.x = ay; + output.y = ax > az ? ax : az; + output.z = ax > az ? az : ax; + } else { + output.x = az; + output.y = ay; + output.z = ax; + } + } + + return output; + } + + public static Vec3 sort(Vec3 input, Vec3 output) { + if (output == null) { + output = new Vec3(); + } + + float ax = input.x, ay = input.y, az = input.z; + + if (ax > ay) { + if (ax > az) { + output.x = ax; + output.y = ay > az ? ay : az; + output.z = ay > az ? az : ay; + } else { + output.x = az; + output.y = ax; + output.z = ay; + } + } else { + if (ay > az) { + output.x = ay; + output.y = ax > az ? ax : az; + output.z = ax > az ? az : ax; + } else { + output.x = az; + output.y = ay; + output.z = ax; + } + } + + return output; + } + + public static Vec3i sortAfterAbs(Vec3i input, Vec3i output) { + if (output == null) { + output = new Vec3i(); + } + + input.abs(output); + return sort(output, output); + } + + public static Vec3 sortAfterAbs(Vec3 input, Vec3 output) { + if (output == null) { + output = new Vec3(); + } + + input.abs(output); + return sort(output, output); + } public static float get(Vec2 v, Axis a) { switch (a) { diff --git a/src/main/java/ru/windcorp/progressia/common/world/BlockRay.java b/src/main/java/ru/windcorp/progressia/common/world/BlockRay.java index 9f35d4c..d7dffc1 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/BlockRay.java +++ b/src/main/java/ru/windcorp/progressia/common/world/BlockRay.java @@ -90,11 +90,7 @@ public class BlockRay { VectorUtil.set(block, axis, VectorUtil.get(block, axis) + (int) signum(VectorUtil.get(direction, axis))); // position += direction * tMin - VectorUtil.linearCombination(position, 1, direction, tMin, position); // position - // += - // direction - // * - // tMin + VectorUtil.linearCombination(position, 1, direction, tMin, position); distance += tMin; // position.(axis) = round(position.(axis)) diff --git a/src/main/java/ru/windcorp/progressia/common/world/generic/GenericChunk.java b/src/main/java/ru/windcorp/progressia/common/world/generic/GenericChunk.java index 95c18be..fa80269 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/generic/GenericChunk.java +++ b/src/main/java/ru/windcorp/progressia/common/world/generic/GenericChunk.java @@ -20,6 +20,7 @@ package ru.windcorp.progressia.common.world.generic; 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; @@ -118,6 +119,64 @@ public interface GenericChunk, B exten default int getMaxZ() { return Coordinates.getInWorld(getZ(), BLOCKS_PER_CHUNK - 1); } + + default Vec3i getMinBIW(Vec3i output) { + if (output == null) { + output = new Vec3i(); + } + + output.set(getMinX(), getMinY(), getMinZ()); + + return output; + } + + default Vec3i getMaxBIW(Vec3i output) { + if (output == null) { + output = new Vec3i(); + } + + output.set(getMaxX(), getMaxY(), getMaxZ()); + + return output; + } + + default Vec3i getMinBIWRel(Vec3i output) { + if (output == null) { + output = new Vec3i(); + } + + Vec3i absMin = getMinBIW(Vectors.grab3i()); + Vec3i absMax = getMaxBIW(Vectors.grab3i()); + + AxisRotations.relativize(absMin, getUp(), absMin); + AxisRotations.relativize(absMax, getUp(), absMax); + + Glm.min(absMin, absMax, output); + + Vectors.release(absMax); + Vectors.release(absMin); + + return output; + } + + default Vec3i getMaxBIWRel(Vec3i output) { + if (output == null) { + output = new Vec3i(); + } + + Vec3i absMin = getMinBIW(Vectors.grab3i()); + Vec3i absMax = getMaxBIW(Vectors.grab3i()); + + AxisRotations.relativize(absMin, getUp(), absMin); + AxisRotations.relativize(absMax, getUp(), absMax); + + Glm.max(absMin, absMax, output); + + Vectors.release(absMax); + Vectors.release(absMin); + + return output; + } default boolean containsBiC(Vec3i blockInChunk) { return blockInChunk.x >= 0 && blockInChunk.x < BLOCKS_PER_CHUNK && diff --git a/src/main/java/ru/windcorp/progressia/server/ChunkManager.java b/src/main/java/ru/windcorp/progressia/server/ChunkManager.java index b0b0777..ede6d70 100644 --- a/src/main/java/ru/windcorp/progressia/server/ChunkManager.java +++ b/src/main/java/ru/windcorp/progressia/server/ChunkManager.java @@ -128,7 +128,7 @@ public class ChunkManager { private void processQueues() { toUnload.forEach(this::unloadChunk); toUnload.clear(); - toLoad.forEach(this::loadChunk); + toLoad.forEach(this::loadOrGenerateChunk); toLoad.clear(); visions.forEach((p, v) -> { @@ -140,15 +140,26 @@ public class ChunkManager { return createIfMissing ? visions.computeIfAbsent(player, k -> new PlayerVision()) : visions.get(player); } - public void loadChunk(Vec3i chunkPos) { + public void loadOrGenerateChunk(Vec3i chunkPos) { + + boolean chunkLoadedFromDisk = loadChunk(chunkPos); + + if (!chunkLoadedFromDisk) { + getServer().getWorld().generate(chunkPos); + } + + } + + public boolean loadChunk(Vec3i chunkPos) { WorldData world = getServer().getWorld().getData(); ChunkData chunk = TestWorldDiskIO.tryToLoad(chunkPos, world, getServer()); if (chunk != null) { world.addChunk(chunk); + return true; } else { - getServer().getWorld().generate(chunkPos); + return false; } } diff --git a/src/main/java/ru/windcorp/progressia/server/Server.java b/src/main/java/ru/windcorp/progressia/server/Server.java index fcdee16..ceafa47 100644 --- a/src/main/java/ru/windcorp/progressia/server/Server.java +++ b/src/main/java/ru/windcorp/progressia/server/Server.java @@ -31,6 +31,7 @@ import ru.windcorp.progressia.server.world.WorldLogic; 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.test.gen.planet.Planet; import ru.windcorp.progressia.test.gen.planet.TestPlanetGenerator; public class Server { @@ -60,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", Units.get("48 m"), w)); + this.world = new WorldLogic(world, this, w -> new TestPlanetGenerator("Test:PlanetGenerator", new Planet(4, 16f, 9.8f, 16f), w)); this.serverThread = new ServerThread(this); this.clientManager = new ClientManager(this); diff --git a/src/main/java/ru/windcorp/progressia/test/gen/TerrainLayer.java b/src/main/java/ru/windcorp/progressia/test/gen/TerrainLayer.java new file mode 100644 index 0000000..74e3335 --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/test/gen/TerrainLayer.java @@ -0,0 +1,30 @@ +/* + * 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; + +import java.util.Random; + +import ru.windcorp.progressia.common.world.ChunkData; +import ru.windcorp.progressia.common.world.block.BlockData; + +@FunctionalInterface +public interface TerrainLayer { + + BlockData get(float north, float west, float depth, Random random, ChunkData chunk); + +} 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 new file mode 100644 index 0000000..795c85f --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/test/gen/planet/Planet.java @@ -0,0 +1,82 @@ +/* + * 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.planet; + +import ru.windcorp.progressia.common.world.ChunkData; + +public class Planet { + + private final int radiusInChunks; + + private final float curvature; + private final float surfaceGravitationalAcceleration; + private final float innerGravityRadius; + + public Planet( + int radiusInChunks, + float curvature, + float surfaceGravitationalAcceleration, + float innerGravityRadius + ) { + this.radiusInChunks = radiusInChunks; + this.curvature = curvature; + this.surfaceGravitationalAcceleration = surfaceGravitationalAcceleration; + this.innerGravityRadius = innerGravityRadius; + } + + /** + * @return the radiusInChunks + */ + public int getRadiusInChunks() { + return radiusInChunks; + } + + public float getRadius() { + return radiusInChunks * ChunkData.BLOCKS_PER_CHUNK + ChunkData.CHUNK_RADIUS; + } + + public int getDiameterInChunks() { + return radiusInChunks * 2 + 1; + } + + public float getDiameter() { + return getDiameterInChunks() * ChunkData.BLOCKS_PER_CHUNK; + } + + /** + * @return the curvature + */ + public float getCurvature() { + return curvature; + } + + /** + * @return the innerGravityRadius + */ + public float getInnerGravityRadius() { + return innerGravityRadius; + } + + /** + * @return the surfaceGravitationalAcceleration + */ + public float getSurfaceGravitationalAcceleration() { + return surfaceGravitationalAcceleration; + } + +} diff --git a/src/main/java/ru/windcorp/progressia/test/gen/planet/PlanetScatterGenerator.java b/src/main/java/ru/windcorp/progressia/test/gen/planet/PlanetScatterGenerator.java new file mode 100644 index 0000000..da0f8d3 --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/test/gen/planet/PlanetScatterGenerator.java @@ -0,0 +1,41 @@ +/* + * 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.planet; + +import ru.windcorp.progressia.common.world.ChunkData; +import ru.windcorp.progressia.test.gen.surface.SurfaceScatterGenerator; + +public class PlanetScatterGenerator { + + private final TestPlanetGenerator parent; + private final SurfaceScatterGenerator surfaceGenerator; + + public PlanetScatterGenerator(TestPlanetGenerator generator) { + this.parent = generator; + this.surfaceGenerator = new SurfaceScatterGenerator(); + } + + public TestPlanetGenerator getGenerator() { + return parent; + } + + public void generateScatter(ChunkData chunk) { + surfaceGenerator.generateScatter(chunk); + } + +} diff --git a/src/main/java/ru/windcorp/progressia/test/gen/planet/PlanetTerrainGenerator.java b/src/main/java/ru/windcorp/progressia/test/gen/planet/PlanetTerrainGenerator.java new file mode 100644 index 0000000..d59984a --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/test/gen/planet/PlanetTerrainGenerator.java @@ -0,0 +1,107 @@ +/* + * 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.planet; + +import glm.vec._3.Vec3; +import glm.vec._3.i.Vec3i; +import ru.windcorp.progressia.common.util.ArrayFloatRangeMap; +import ru.windcorp.progressia.common.util.FloatRangeMap; +import ru.windcorp.progressia.common.util.VectorUtil; +import ru.windcorp.progressia.common.world.ChunkData; +import ru.windcorp.progressia.common.world.Coordinates; +import ru.windcorp.progressia.common.world.WorldData; +import ru.windcorp.progressia.common.world.block.BlockData; +import ru.windcorp.progressia.common.world.block.BlockDataRegistry; +import ru.windcorp.progressia.test.gen.TerrainLayer; +import ru.windcorp.progressia.test.gen.surface.SurfaceFloatField; +import ru.windcorp.progressia.test.gen.surface.SurfaceTerrainGenerator; + +class PlanetTerrainGenerator { + + private final TestPlanetGenerator parent; + private final SurfaceTerrainGenerator surfaceGenerator; + + public PlanetTerrainGenerator(TestPlanetGenerator generator) { + this.parent = generator; + + SurfaceFloatField heightMap = new TestHeightMap( + generator.getPlanet().getRadius() - ChunkData.BLOCKS_PER_CHUNK, + generator.getPlanet().getRadius() / 4, + 5, + 6 + ); + + FloatRangeMap layers = new ArrayFloatRangeMap<>(); + BlockData granite = BlockDataRegistry.getInstance().get("Test:GraniteMonolith"); + BlockData air = BlockDataRegistry.getInstance().get("Test:Air"); + layers.put(Float.NEGATIVE_INFINITY, 0, (n, w, d, r, c) -> air); + layers.put(0, Float.POSITIVE_INFINITY, (n, w, d, r, c) -> granite); + + this.surfaceGenerator = new SurfaceTerrainGenerator((f, n, w) -> heightMap.get(f, n, w) + generator.getPlanet().getRadius(), layers); + } + + public TestPlanetGenerator getGenerator() { + return parent; + } + + public ChunkData generateTerrain(Vec3i chunkPos, WorldData world) { + ChunkData chunk = new ChunkData(chunkPos, world); + + if (isOrdinaryChunk(chunkPos)) { + generateOrdinaryTerrain(chunk); + } else { + generateBorderTerrain(chunk); + } + + return chunk; + } + + private boolean isOrdinaryChunk(Vec3i chunkPos) { + Vec3i sorted = VectorUtil.sortAfterAbs(chunkPos, null); + return sorted.x != sorted.y; + } + + private void generateOrdinaryTerrain(ChunkData chunk) { + surfaceGenerator.generateTerrain(chunk); + } + + private void generateBorderTerrain(ChunkData chunk) { + BlockData stone = BlockDataRegistry.getInstance().get("Test:Stone"); + BlockData air = BlockDataRegistry.getInstance().get("Test:Air"); + + float radius = parent.getPlanet().getRadius(); + + Vec3 biw = new Vec3(); + + chunk.forEachBiC(bic -> { + + biw.set( + Coordinates.getInWorld(chunk.getX(), bic.x), + Coordinates.getInWorld(chunk.getY(), bic.y), + Coordinates.getInWorld(chunk.getZ(), bic.z) + ); + + biw.sub(ChunkData.CHUNK_RADIUS - 0.5f); + VectorUtil.sortAfterAbs(biw, biw); + + chunk.setBlock(bic, biw.x <= radius ? stone : air, false); + + }); + } + +} diff --git a/src/main/java/ru/windcorp/progressia/test/gen/planet/TestHeightMap.java b/src/main/java/ru/windcorp/progressia/test/gen/planet/TestHeightMap.java new file mode 100644 index 0000000..2141c63 --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/test/gen/planet/TestHeightMap.java @@ -0,0 +1,70 @@ +/* + * 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.planet; + +import ru.windcorp.progressia.common.world.rels.AbsFace; +import ru.windcorp.progressia.test.gen.surface.SurfaceFloatField; + +public class TestHeightMap implements SurfaceFloatField { + + private final float cutoffPoint; + private final float cutoffDistance; + private final float amplitude; + private final float characteristicSize; + + public TestHeightMap( + float cutoffPoint, + float cutoffDistance, + float amplitude, + float characteristicSize + ) { + this.cutoffPoint = cutoffPoint; + this.cutoffDistance = cutoffDistance; + this.amplitude = amplitude; + this.characteristicSize = characteristicSize; + } + + @Override + public float get(AbsFace face, float north, float west) { + double cutoffCoefficient = 1; + cutoffCoefficient *= cutoffFunction(cutoffPoint - north); + cutoffCoefficient *= cutoffFunction(cutoffPoint + north); + cutoffCoefficient *= cutoffFunction(cutoffPoint - west); + cutoffCoefficient *= cutoffFunction(cutoffPoint + west); + + if (cutoffCoefficient == 0) { + return 0; + } + + double base = Math.sin(north / characteristicSize) * Math.sin(west / characteristicSize); + base *= amplitude; + + return (float) (base * cutoffCoefficient); + } + + private double cutoffFunction(float distanceToCutoffPoint) { + if (distanceToCutoffPoint < 0) { + return 0; + } else if (distanceToCutoffPoint < cutoffDistance) { + return (1 - Math.cos(Math.PI * distanceToCutoffPoint / cutoffDistance)) / 2; + } else { + return 1; + } + } + +} 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 ea45d1e..b21d985 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 @@ -20,38 +20,39 @@ package ru.windcorp.progressia.test.gen.planet; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; -import java.util.Arrays; - import glm.vec._3.Vec3; import glm.vec._3.i.Vec3i; -import ru.windcorp.progressia.common.util.VectorUtil; import ru.windcorp.progressia.common.world.ChunkData; import ru.windcorp.progressia.common.world.DecodingException; import ru.windcorp.progressia.common.world.WorldData; -import ru.windcorp.progressia.common.world.block.BlockData; -import ru.windcorp.progressia.common.world.block.BlockDataRegistry; -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.WorldLogic; import ru.windcorp.progressia.server.world.generation.AbstractWorldGenerator; public class TestPlanetGenerator extends AbstractWorldGenerator { - private final int surfaceLevel; + private final Planet planet; + + private final PlanetTerrainGenerator terrainGenerator; + private final PlanetScatterGenerator scatterGenerator; - public TestPlanetGenerator(String id, float planetRadius, WorldLogic world) { + public TestPlanetGenerator(String id, Planet planet, WorldLogic world) { super(id, Boolean.class, "Test:PlanetGravityModel"); + this.planet = planet; - this.surfaceLevel = (int) (planetRadius / ChunkData.BLOCKS_PER_CHUNK); - if (surfaceLevel < 2) { - throw new IllegalArgumentException("planetRadius too small, must be at least 32 m"); - } + this.terrainGenerator = new PlanetTerrainGenerator(this); + this.scatterGenerator = new PlanetScatterGenerator(this); + } + + /** + * @return the planet + */ + public Planet getPlanet() { + return planet; } @Override public Vec3 suggestSpawnLocation() { - return new Vec3(0, 0, 66); + return new Vec3(7f, 7f, getPlanet().getRadius() + 10); } @Override @@ -71,116 +72,9 @@ public class TestPlanetGenerator extends AbstractWorldGenerator { @Override public ChunkData generate(Vec3i chunkPos, WorldData world) { - ChunkData chunk = new ChunkData(chunkPos, world); - - generate(chunk); - chunk.setGenerationHint(true); - + ChunkData chunk = terrainGenerator.generateTerrain(chunkPos, world); + scatterGenerator.generateScatter(chunk); return chunk; } - - private enum ChunkType { - SURFACE, UNDERGROUND, EDGE_SURFACE, EDGE_UNDERGROUND, CORE, AIR; - } - - private void generate(ChunkData chunk) { - switch (getChunkType(chunk.getPosition())) { - case SURFACE: - fillSurface(chunk); - break; - case UNDERGROUND: - fillUndeground(chunk); - break; - case EDGE_SURFACE: - fillEdgeSurface(chunk); - break; - case EDGE_UNDERGROUND: - fillEdgeUnderground(chunk); - break; - case CORE: - fillCore(chunk); - break; - case AIR: - fillAir(chunk); - break; - } - } - - private void fillSurface(ChunkData chunk) { - final int bpc = ChunkData.BLOCKS_PER_CHUNK; - - BlockData dirt = BlockDataRegistry.getInstance().get("Test:Dirt"); - BlockData granite = BlockDataRegistry.getInstance().get("Test:GraniteMonolith"); - - TileData grass = TileDataRegistry.getInstance().get("Test:Grass"); - - chunk.forEachBiC(bic -> { - - BlockData block; - - if (bic.z > bpc - 4) { - block = dirt; - } else { - block = granite; - } - - chunk.setBlockRel(bic, block, false); - - }); - - VectorUtil.iterateCuboid(0, 0, bpc - 1, bpc, bpc, bpc, bic -> { - chunk.getTilesRel(bic, RelFace.UP).add(grass); - }); - } - - private void fillUndeground(ChunkData chunk) { - fill(chunk, BlockDataRegistry.getInstance().get("Test:GraniteMonolith")); - } - - private void fillEdgeSurface(ChunkData chunk) { - fill(chunk, BlockDataRegistry.getInstance().get("Test:Stone")); - } - - private void fillEdgeUnderground(ChunkData chunk) { - fill(chunk, BlockDataRegistry.getInstance().get("Test:Stone")); - } - - private void fillCore(ChunkData chunk) { - fill(chunk, BlockDataRegistry.getInstance().get("Test:Stone")); - } - - private void fillAir(ChunkData chunk) { - fill(chunk, BlockDataRegistry.getInstance().get("Test:Air")); - } - - private void fill(ChunkData chunk, BlockData block) { - chunk.forEachBiC(bic -> chunk.setBlock(bic, block, false)); - } - - private ChunkType getChunkType(Vec3i pos) { - int[] abs = pos.abs_().toIA_(); - Arrays.sort(abs); - - int medium = abs[1]; - int largest = abs[2]; - - int level = largest; - - if (level == 0) { - return ChunkType.CORE; - } - - if (largest > surfaceLevel) { - return ChunkType.AIR; - } - - boolean isSurface = largest == surfaceLevel; - - if (medium == largest) { - return isSurface ? ChunkType.EDGE_SURFACE : ChunkType.EDGE_UNDERGROUND; - } else { - return isSurface ? ChunkType.SURFACE : ChunkType.UNDERGROUND; - } - } } diff --git a/src/main/java/ru/windcorp/progressia/test/gen/surface/SurfaceFloatField.java b/src/main/java/ru/windcorp/progressia/test/gen/surface/SurfaceFloatField.java new file mode 100644 index 0000000..4b368d4 --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/test/gen/surface/SurfaceFloatField.java @@ -0,0 +1,27 @@ +/* + * 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.world.rels.AbsFace; + +@FunctionalInterface +public interface SurfaceFloatField { + + float get(AbsFace face, float north, float west); + +} diff --git a/src/main/java/ru/windcorp/progressia/test/gen/surface/SurfaceScatterGenerator.java b/src/main/java/ru/windcorp/progressia/test/gen/surface/SurfaceScatterGenerator.java new file mode 100644 index 0000000..a9f08d9 --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/test/gen/surface/SurfaceScatterGenerator.java @@ -0,0 +1,28 @@ +/* + * 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.world.ChunkData; + +public class SurfaceScatterGenerator { + + public void generateScatter(ChunkData chunk) { + chunk.setGenerationHint(true); + } + +} diff --git a/src/main/java/ru/windcorp/progressia/test/gen/surface/SurfaceTerrainGenerator.java b/src/main/java/ru/windcorp/progressia/test/gen/surface/SurfaceTerrainGenerator.java new file mode 100644 index 0000000..b05df5a --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/test/gen/surface/SurfaceTerrainGenerator.java @@ -0,0 +1,74 @@ +/* + * 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.util.Random; + +import glm.vec._3.Vec3; +import glm.vec._3.i.Vec3i; +import ru.windcorp.progressia.common.util.CoordinatePacker; +import ru.windcorp.progressia.common.util.FloatRangeMap; +import ru.windcorp.progressia.common.world.ChunkData; +import ru.windcorp.progressia.common.world.block.BlockData; +import ru.windcorp.progressia.common.world.rels.AxisRotations; +import ru.windcorp.progressia.test.gen.TerrainLayer; + +public class SurfaceTerrainGenerator { + + private final SurfaceFloatField heightMap; + private final FloatRangeMap layers; + + public SurfaceTerrainGenerator(SurfaceFloatField heightMap, FloatRangeMap layers) { + this.heightMap = heightMap; + this.layers = layers; + } + + public void generateTerrain(ChunkData chunk) { + + Vec3i relBIC = new Vec3i(); + + Vec3 offset = new Vec3(chunk.getMinX(), chunk.getMinY(), chunk.getMinZ()); + AxisRotations.relativize(offset, chunk.getUp(), offset); + offset.sub(ChunkData.CHUNK_RADIUS - 0.5f); + + Random random = new Random(CoordinatePacker.pack3IntsIntoLong(chunk.getPosition()) /* ^ seed*/); + + for (relBIC.x = 0; relBIC.x < ChunkData.BLOCKS_PER_CHUNK; ++relBIC.x) { + for (relBIC.y = 0; relBIC.y < ChunkData.BLOCKS_PER_CHUNK; ++relBIC.y) { + generateColumn(chunk, relBIC, offset, random); + } + } + + } + + public void generateColumn(ChunkData chunk, Vec3i relBIC, Vec3 offset, Random random) { + + float north = relBIC.x + offset.x; + float west = relBIC.y + offset.y; + + float relSurface = heightMap.get(chunk.getUp(), north, west) - offset.z; + + for (relBIC.z = 0; relBIC.z < ChunkData.BLOCKS_PER_CHUNK; ++relBIC.z) { + float depth = relSurface - relBIC.z; + BlockData block = layers.get(depth).get(north, west, depth, random, chunk); + chunk.setBlockRel(relBIC, block, false); + } + + } + +} From f28c765e3ff95582fe3aabb875c265356af2be4f Mon Sep 17 00:00:00 2001 From: OLEGSHA Date: Mon, 15 Mar 2021 21:02:33 +0300 Subject: [PATCH 15/55] Made Gravity Models configurable with packets --- .../progressia/common/world/GravityModel.java | 61 ++++++++++++ .../common/world/GravityModelRegistry.java | 4 +- .../common/world/PacketSetGravityModel.java | 22 ++++- .../ru/windcorp/progressia/server/Server.java | 2 +- .../generation/AbstractWorldGenerator.java | 2 +- .../windcorp/progressia/test/TestContent.java | 4 +- .../progressia/test/gen/TestGravityModel.java | 19 +++- .../progressia/test/gen/planet/Planet.java | 27 ++++-- .../test/gen/planet/TestPlanetGenerator.java | 4 + .../gen/planet/TestPlanetGravityModel.java | 96 +++++++++++++++---- .../gen/surface/SurfaceCachingFloatField.java | 77 +++++++++++++++ .../gen/surface/SurfaceFieldRegistry.java | 29 ++++++ .../test/gen/surface/SurfaceNodeStorage.java | 57 +++++++++++ 13 files changed, 368 insertions(+), 36 deletions(-) create mode 100644 src/main/java/ru/windcorp/progressia/test/gen/surface/SurfaceCachingFloatField.java create mode 100644 src/main/java/ru/windcorp/progressia/test/gen/surface/SurfaceFieldRegistry.java create mode 100644 src/main/java/ru/windcorp/progressia/test/gen/surface/SurfaceNodeStorage.java 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"); + } + +} From ef572c43c7948988214df0363c1e6084265dd6fe Mon Sep 17 00:00:00 2001 From: OLEGSHA Date: Thu, 25 Mar 2021 17:15:03 +0300 Subject: [PATCH 16/55] Updated documentation for GuavaEventBusHijacker and ReportingEventBus --- .../common/hacks/GuavaEventBusHijacker.java | 19 +++++++++---------- .../common/util/crash/ReportingEventBus.java | 18 +++++++++++++++++- 2 files changed, 26 insertions(+), 11 deletions(-) diff --git a/src/main/java/ru/windcorp/progressia/common/hacks/GuavaEventBusHijacker.java b/src/main/java/ru/windcorp/progressia/common/hacks/GuavaEventBusHijacker.java index 6bc7901..8ee2c60 100644 --- a/src/main/java/ru/windcorp/progressia/common/hacks/GuavaEventBusHijacker.java +++ b/src/main/java/ru/windcorp/progressia/common/hacks/GuavaEventBusHijacker.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.common.hacks; import java.lang.reflect.Constructor; @@ -29,15 +29,14 @@ import com.google.common.util.concurrent.MoreExecutors; import ru.windcorp.progressia.common.util.crash.CrashReports; /** - * This class had to be written because there is not legal way to instantiate a - * non-async - * {@link EventBus} with both a custom identifier and a custom exception - * handler. Which - * is a shame. Guava maintainers know about the issue but have rejected - * solutions multiple - * times without a clearly stated reason; looks like some dirty - * reflection will - * have to do. + * This class had to be written because there is no legal way to instantiate a + * non-async {@link EventBus} with both a custom identifier and a custom + * exception handler. Which is a shame. Guava maintainers know about the issue + * but have rejected solutions multiple times without a clearly stated + * reason; looks like some dirty reflection will have to do. + *

    + * When explicitly referencing this class, please mention its usage in + * implementation notes because it is unreliable long-term. * * @author javapony */ diff --git a/src/main/java/ru/windcorp/progressia/common/util/crash/ReportingEventBus.java b/src/main/java/ru/windcorp/progressia/common/util/crash/ReportingEventBus.java index 141efa9..a95365e 100644 --- a/src/main/java/ru/windcorp/progressia/common/util/crash/ReportingEventBus.java +++ b/src/main/java/ru/windcorp/progressia/common/util/crash/ReportingEventBus.java @@ -15,18 +15,34 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.common.util.crash; import com.google.common.eventbus.EventBus; import ru.windcorp.progressia.common.hacks.GuavaEventBusHijacker; +/** + * A utility for creating Guava's {@link EventBus}es that + * {@linkplain CrashReports report} exceptions instead of suppressing them. + * + * @author javapony + */ public class ReportingEventBus { private ReportingEventBus() { } + /** + * Instantiates a new {@link EventBus} with the provided identifier that + * reports any unhandled exceptions with {@link CrashReports}. + * + * @param identifier the identifier of the new bus + * @return the created event bus + * @implNote This implementation relies on {@link GuavaEventBusHijacker} for + * creating buses with custom identifiers and uncaught exception + * handlers. It may break suddenly with a Guava update. + */ public static EventBus create(String identifier) { return GuavaEventBusHijacker.newEventBus( identifier, From 4332a782214e05ed64f662c717e6da1ab5c9e661 Mon Sep 17 00:00:00 2001 From: OLEGSHA Date: Fri, 26 Mar 2021 20:26:12 +0300 Subject: [PATCH 17/55] Refactored ChunkManager and EntityManager, added server event bus --- .../common/world/generic/ChunkMaps.java | 261 ++++++++++++++++++ .../progressia/server/ChunkManager.java | 245 ---------------- .../progressia/server/EntityManager.java | 197 ------------- .../progressia/server/PlayerManager.java | 7 + .../ru/windcorp/progressia/server/Server.java | 89 +++--- .../server/comms/ClientManager.java | 2 +- .../progressia/server/comms/ClientPlayer.java | 4 +- .../progressia/server/events/ClientEvent.java | 46 +++ .../progressia/server/events/PlayerEvent.java | 49 ++++ .../server/events/PlayerJoinedEvent.java | 33 +++ .../server/events/PlayerLeftEvent.java | 33 +++ .../progressia/server/events/ServerEvent.java | 68 +++++ .../server/management/load/ChunkManager.java | 192 +++++++++++++ .../management/load/ChunkRequestDaemon.java | 206 ++++++++++++++ .../server/management/load/EntityManager.java | 97 +++++++ .../management/load/EntityRequestDaemon.java | 121 ++++++++ .../server/management/load/LoadManager.java | 65 +++++ .../server/management/load/PlayerVision.java | 85 ++++++ .../server/management/load/VisionManager.java | 108 ++++++++ 19 files changed, 1429 insertions(+), 479 deletions(-) create mode 100644 src/main/java/ru/windcorp/progressia/common/world/generic/ChunkMaps.java delete mode 100644 src/main/java/ru/windcorp/progressia/server/ChunkManager.java delete mode 100644 src/main/java/ru/windcorp/progressia/server/EntityManager.java create mode 100644 src/main/java/ru/windcorp/progressia/server/events/ClientEvent.java create mode 100644 src/main/java/ru/windcorp/progressia/server/events/PlayerEvent.java create mode 100644 src/main/java/ru/windcorp/progressia/server/events/PlayerJoinedEvent.java create mode 100644 src/main/java/ru/windcorp/progressia/server/events/PlayerLeftEvent.java create mode 100644 src/main/java/ru/windcorp/progressia/server/events/ServerEvent.java create mode 100644 src/main/java/ru/windcorp/progressia/server/management/load/ChunkManager.java create mode 100644 src/main/java/ru/windcorp/progressia/server/management/load/ChunkRequestDaemon.java create mode 100644 src/main/java/ru/windcorp/progressia/server/management/load/EntityManager.java create mode 100644 src/main/java/ru/windcorp/progressia/server/management/load/EntityRequestDaemon.java create mode 100644 src/main/java/ru/windcorp/progressia/server/management/load/LoadManager.java create mode 100644 src/main/java/ru/windcorp/progressia/server/management/load/PlayerVision.java create mode 100644 src/main/java/ru/windcorp/progressia/server/management/load/VisionManager.java diff --git a/src/main/java/ru/windcorp/progressia/common/world/generic/ChunkMaps.java b/src/main/java/ru/windcorp/progressia/common/world/generic/ChunkMaps.java new file mode 100644 index 0000000..e67f67e --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/common/world/generic/ChunkMaps.java @@ -0,0 +1,261 @@ +/* + * 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.common.world.generic; + +import java.util.Collection; +import java.util.Collections; +import java.util.Objects; +import java.util.function.BiConsumer; +import java.util.function.BiFunction; +import java.util.function.BiPredicate; +import glm.vec._3.i.Vec3i; +import gnu.trove.map.hash.TLongObjectHashMap; + +public class ChunkMaps { + + public static ChunkMap newHashMap() { + return new LongBasedChunkMap(new TLongObjectHashMap()); + } + + public static ChunkMap newSyncHashMap(Object mutex) { + return new SynchronizedChunkMap(new LongBasedChunkMap(new TLongObjectHashMap()), mutex); + } + + public static ChunkMap newSyncHashMap() { + return newSyncHashMap(null); + } + + @SuppressWarnings("unchecked") + public static ChunkMap empty() { + return (ChunkMap) EMPTY_MAP; + } + + private ChunkMaps() { + } + + private final static ChunkMap EMPTY_MAP = new ChunkMap() { + + @Override + public int size() { + return 0; + } + + @Override + public boolean containsKey(Vec3i pos) { + return false; + } + + @Override + public Object get(Vec3i pos) { + return null; + } + + @Override + public Object put(Vec3i pos, Object obj) { + throw new UnsupportedOperationException(); + } + + @Override + public Object remove(Vec3i pos) { + throw new UnsupportedOperationException(); + } + + @Override + public Collection values() { + return Collections.emptyList(); + } + + @Override + public ChunkSet keys() { + return ChunkSets.empty(); + } + + @Override + public boolean removeIf(BiPredicate condition) { + return false; + } + + @Override + public void forEach(BiConsumer action) { + // Do nothing + } + + }; + + private static class SynchronizedChunkMap implements ChunkMap { + + private final ChunkMap parent; + private final Object mutex; + + public SynchronizedChunkMap(ChunkMap parent, Object mutex) { + Objects.requireNonNull(parent, "parent"); + this.parent = parent; + + this.mutex = mutex == null ? this : mutex; + } + + @Override + public int size() { + synchronized (mutex) { + return parent.size(); + } + } + + @Override + public boolean isEmpty() { + synchronized (mutex) { + return parent.isEmpty(); + } + } + + @Override + public boolean containsKey(Vec3i pos) { + synchronized (mutex) { + return parent.containsKey(pos); + } + } + + @Override + public V get(Vec3i pos) { + synchronized (mutex) { + return parent.get(pos); + } + } + + @Override + public V put(Vec3i pos, V obj) { + synchronized (mutex) { + return parent.put(pos, obj); + } + } + + @Override + public V remove(Vec3i pos) { + synchronized (mutex) { + return parent.remove(pos); + } + } + + @Override + public boolean containsValue(V value) { + synchronized (mutex) { + return parent.containsValue(value); + } + } + + @Override + public V getOrDefault(Vec3i pos, V def) { + synchronized (mutex) { + return parent.getOrDefault(pos, def); + } + } + + @Override + public V compute(Vec3i pos, BiFunction remappingFunction) { + synchronized (mutex) { + return parent.compute(pos, remappingFunction); + } + } + + @Override + public boolean containsChunk(GenericChunk chunk) { + synchronized (mutex) { + return parent.containsChunk(chunk); + } + } + + @Override + public V get(GenericChunk chunk) { + synchronized (mutex) { + return parent.get(chunk); + } + } + + @Override + public V put(GenericChunk chunk, V obj) { + synchronized (mutex) { + return parent.put(chunk, obj); + } + } + + @Override + public V remove(GenericChunk chunk) { + synchronized (mutex) { + return parent.remove(chunk); + } + } + + @Override + public V getOrDefault(GenericChunk chunk, V def) { + synchronized (mutex) { + return parent.getOrDefault(chunk, def); + } + } + + @Override + public > V compute( + C chunk, + BiFunction remappingFunction + ) { + synchronized (mutex) { + return parent.compute(chunk, remappingFunction); + } + } + + @Override + public Collection values() { + synchronized (mutex) { + return parent.values(); + } + } + + @Override + public ChunkSet keys() { + synchronized (mutex) { + return parent.keys(); + } + } + + @Override + public boolean removeIf(BiPredicate condition) { + synchronized (mutex) { + return parent.removeIf(condition); + } + } + + @Override + public void forEach(BiConsumer action) { + synchronized (mutex) { + parent.forEach(action); + } + } + + @Override + public > void forEachIn( + GenericWorld world, + BiConsumer action + ) { + synchronized (mutex) { + parent.forEachIn(world, action); + } + } + + } + +} diff --git a/src/main/java/ru/windcorp/progressia/server/ChunkManager.java b/src/main/java/ru/windcorp/progressia/server/ChunkManager.java deleted file mode 100644 index ede6d70..0000000 --- a/src/main/java/ru/windcorp/progressia/server/ChunkManager.java +++ /dev/null @@ -1,245 +0,0 @@ -/* - * 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.server; - -import java.util.Collections; -import java.util.Map; -import java.util.WeakHashMap; - -import glm.vec._3.i.Vec3i; -import ru.windcorp.progressia.common.world.ChunkData; -import ru.windcorp.progressia.common.world.PacketRevokeChunk; -import ru.windcorp.progressia.common.world.PacketSendChunk; -import ru.windcorp.progressia.common.world.WorldData; -import ru.windcorp.progressia.common.world.generic.ChunkSet; -import ru.windcorp.progressia.common.world.generic.ChunkSets; -import ru.windcorp.progressia.test.TestWorldDiskIO; - -public class ChunkManager { - - private class PlayerVision { - - private final ChunkSet visible = ChunkSets.newSyncHashSet(); - private final ChunkSet requested = ChunkSets.newHashSet(); - private final ChunkSet toSend = ChunkSets.newHashSet(); - private final ChunkSet toRevoke = ChunkSets.newHashSet(); - - public boolean isChunkVisible(Vec3i chunkPos) { - return visible.contains(chunkPos); - } - - public void gatherRequests(Player player) { - requested.clear(); - player.requestChunksToLoad(requested::add); - } - - public void updateQueues(Player player) { - toSend.clear(); - - requested.forEachIn(server.getWorld(), chunk -> { - if (!chunk.isReady()) - return; - if (visible.contains(chunk)) - return; - toSend.add(chunk); - }); - - toRevoke.clear(); - toRevoke.addAll(visible); - toRevoke.removeIf(v -> loaded.contains(v) && requested.contains(v)); - } - - public void processQueues(Player player) { - toRevoke.forEach(chunkPos -> revokeChunk(player, chunkPos)); - toRevoke.clear(); - - toSend.forEach(chunkPos -> sendChunk(player, chunkPos)); - toSend.clear(); - } - - } - - private final Server server; - - private final ChunkSet loaded; - private final ChunkSet requested = ChunkSets.newHashSet(); - private final ChunkSet toLoad = ChunkSets.newHashSet(); - private final ChunkSet toUnload = ChunkSets.newHashSet(); - - // TODO replace with a normal Map managed by some sort of PlayerListener, - // weak maps are weak - private final Map visions = Collections.synchronizedMap(new WeakHashMap<>()); - - public ChunkManager(Server server) { - this.server = server; - this.loaded = server.getWorld().getData().getLoadedChunks(); - } - - public void tick() { - synchronized (getServer().getWorld().getData()) { - synchronized (visions) { - gatherRequests(); - updateQueues(); - processQueues(); - } - } - } - - private void gatherRequests() { - requested.clear(); - - server.getPlayerManager().getPlayers().forEach(p -> { - PlayerVision vision = getVision(p, true); - vision.gatherRequests(p); - requested.addAll(vision.requested); - }); - } - - private void updateQueues() { - toLoad.clear(); - toLoad.addAll(requested); - toLoad.removeAll(loaded); - - toUnload.clear(); - toUnload.addAll(loaded); - toUnload.removeAll(requested); - - visions.forEach((p, v) -> { - v.updateQueues(p); - }); - } - - private void processQueues() { - toUnload.forEach(this::unloadChunk); - toUnload.clear(); - toLoad.forEach(this::loadOrGenerateChunk); - toLoad.clear(); - - visions.forEach((p, v) -> { - v.processQueues(p); - }); - } - - private PlayerVision getVision(Player player, boolean createIfMissing) { - return createIfMissing ? visions.computeIfAbsent(player, k -> new PlayerVision()) : visions.get(player); - } - - public void loadOrGenerateChunk(Vec3i chunkPos) { - - boolean chunkLoadedFromDisk = loadChunk(chunkPos); - - if (!chunkLoadedFromDisk) { - getServer().getWorld().generate(chunkPos); - } - - } - - public boolean loadChunk(Vec3i chunkPos) { - - WorldData world = getServer().getWorld().getData(); - - ChunkData chunk = TestWorldDiskIO.tryToLoad(chunkPos, world, getServer()); - if (chunk != null) { - world.addChunk(chunk); - return true; - } else { - return false; - } - - } - - public void unloadChunk(Vec3i chunkPos) { - - WorldData world = getServer().getWorld().getData(); - - ChunkData chunk = world.getChunk(chunkPos); - if (chunk == null) { - throw new IllegalStateException( - String.format( - "Chunk (%d; %d; %d) not loaded, cannot unload", - chunkPos.x, - chunkPos.y, - chunkPos.z - ) - ); - } - - world.removeChunk(chunk); - - TestWorldDiskIO.saveChunk(chunk, getServer()); - - } - - public void sendChunk(Player player, Vec3i chunkPos) { - ChunkData chunk = server.getWorld().getData().getChunk(chunkPos); - - if (chunk == null) { - throw new IllegalStateException( - String.format( - "Chunk (%d; %d; %d) is not loaded, cannot send", - chunkPos.x, - chunkPos.y, - chunkPos.z - ) - ); - } - - PacketSendChunk packet = new PacketSendChunk(); - packet.set(chunk); - player.getClient().sendPacket(packet); - - getVision(player, true).visible.add(chunkPos); - } - - public void revokeChunk(Player player, Vec3i chunkPos) { - PacketRevokeChunk packet = new PacketRevokeChunk(); - packet.set(chunkPos); - player.getClient().sendPacket(packet); - - PlayerVision vision = getVision(player, false); - if (vision != null) { - vision.visible.remove(chunkPos); - } - } - - public boolean isChunkVisible(Vec3i chunkPos, Player player) { - PlayerVision vision = getVision(player, false); - - if (vision == null) { - return false; - } - - return vision.isChunkVisible(chunkPos); - } - - public ChunkSet getVisibleChunks(Player player) { - PlayerVision vision = getVision(player, false); - - if (vision == null) { - return ChunkSets.empty(); - } - - return vision.visible; - } - - public Server getServer() { - return server; - } - -} diff --git a/src/main/java/ru/windcorp/progressia/server/EntityManager.java b/src/main/java/ru/windcorp/progressia/server/EntityManager.java deleted file mode 100644 index d904c83..0000000 --- a/src/main/java/ru/windcorp/progressia/server/EntityManager.java +++ /dev/null @@ -1,197 +0,0 @@ -/* - * 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.server; - -import java.util.Collections; -import java.util.Map; -import java.util.WeakHashMap; - -import glm.vec._3.i.Vec3i; -import gnu.trove.TCollections; -import gnu.trove.iterator.TLongIterator; -import gnu.trove.set.TLongSet; -import gnu.trove.set.hash.TLongHashSet; -import ru.windcorp.jputil.chars.StringUtil; -import ru.windcorp.progressia.common.util.Vectors; -import ru.windcorp.progressia.common.world.entity.EntityData; -import ru.windcorp.progressia.common.world.entity.PacketRevokeEntity; -import ru.windcorp.progressia.common.world.entity.PacketSendEntity; -import ru.windcorp.progressia.common.world.generic.ChunkSet; - -public class EntityManager { - - private class PlayerVision { - - private final TLongSet visible = TCollections.synchronizedSet(new TLongHashSet()); - private final TLongSet requested = new TLongHashSet(); - private final TLongSet toSend = new TLongHashSet(); - private final TLongSet toRevoke = new TLongHashSet(); - - public boolean isEntityVisible(long entityId) { - return visible.contains(entityId); - } - - public void gatherRequests(Player player) { - requested.clear(); - - ChunkSet visibleChunks = player.getClient().getVisibleChunks(); - Vec3i v = Vectors.grab3i(); - - getServer().getWorld().forEachEntity(entity -> { - if (visibleChunks.contains(entity.getChunkCoords(v))) { - requested.add(entity.getEntityId()); - } - }); - - Vectors.release(v); - } - - public void updateQueues(Player player) { - toSend.clear(); - toSend.addAll(requested); - toSend.removeAll(visible); - toSend.retainAll(loaded); - - toRevoke.clear(); - - for (TLongIterator it = visible.iterator(); it.hasNext();) { - long entityId = it.next(); - if (!loaded.contains(entityId) || !requested.contains(entityId)) { - toRevoke.add(entityId); - } - } - } - - public void processQueues(Player player) { - toRevoke.forEach(entityId -> { - revokeEntity(player, entityId); - return true; - }); - toRevoke.clear(); - - toSend.forEach(entityId -> { - sendEntity(player, entityId); - return true; - }); - toSend.clear(); - } - - } - - private final Server server; - - private final TLongSet loaded; - - // TODO replace with a normal Map managed by some sort of PlayerListener, - // weak maps are weak - private final Map visions = Collections.synchronizedMap(new WeakHashMap<>()); - - public EntityManager(Server server) { - this.server = server; - this.loaded = server.getWorld().getData().getLoadedEntities(); - } - - public void tick() { - synchronized (getServer().getWorld().getData()) { - synchronized (visions) { - gatherRequests(); - updateQueues(); - processQueues(); - } - } - } - - private void gatherRequests() { - server.getPlayerManager().getPlayers().forEach(p -> { - PlayerVision vision = getVision(p, true); - vision.gatherRequests(p); - }); - } - - private void updateQueues() { - visions.forEach((p, v) -> { - v.updateQueues(p); - }); - } - - private void processQueues() { - visions.forEach((p, v) -> { - v.processQueues(p); - }); - } - - private PlayerVision getVision(Player player, boolean createIfMissing) { - return createIfMissing ? visions.computeIfAbsent(player, k -> new PlayerVision()) : visions.get(player); - } - - public void sendEntity(Player player, long entityId) { - - EntityData entity = server.getWorld().getData().getEntity(entityId); - - if (entity == null) { - throw new IllegalStateException( - "Entity with entity ID " + new String(StringUtil.toFullHex(entityId)) + " is not loaded, cannot send" - ); - } - - PacketSendEntity packet = new PacketSendEntity(); - packet.set(entity); - player.getClient().sendPacket(packet); - - getVision(player, true).visible.add(entityId); - } - - public void revokeEntity(Player player, long entityId) { - PacketRevokeEntity packet = new PacketRevokeEntity(); - packet.set(entityId); - player.getClient().sendPacket(packet); - - PlayerVision vision = getVision(player, false); - if (vision != null) { - vision.visible.remove(entityId); - } - } - - public boolean isEntityVisible(long entityId, Player player) { - PlayerVision vision = getVision(player, false); - - if (vision == null) { - return false; - } - - return vision.isEntityVisible(entityId); - } - - private static final TLongSet EMPTY_LONG_SET = TCollections.unmodifiableSet(new TLongHashSet()); - - public TLongSet getVisibleEntities(Player player) { - PlayerVision vision = getVision(player, false); - - if (vision == null) { - return EMPTY_LONG_SET; - } - - return vision.visible; - } - - public Server getServer() { - return server; - } - -} diff --git a/src/main/java/ru/windcorp/progressia/server/PlayerManager.java b/src/main/java/ru/windcorp/progressia/server/PlayerManager.java index 60b07f1..10799e0 100644 --- a/src/main/java/ru/windcorp/progressia/server/PlayerManager.java +++ b/src/main/java/ru/windcorp/progressia/server/PlayerManager.java @@ -26,6 +26,7 @@ import glm.vec._3.Vec3; import ru.windcorp.progressia.common.util.crash.CrashReports; import ru.windcorp.progressia.common.world.entity.EntityData; import ru.windcorp.progressia.common.world.entity.EntityDataRegistry; +import ru.windcorp.progressia.server.events.PlayerJoinedEvent; import ru.windcorp.progressia.test.TestContent; public class PlayerManager { @@ -44,6 +45,8 @@ public class PlayerManager { public void addPlayer(Player player) { this.players.add(player); + System.out.println("PlayerManager.addPlayer()"); + getServer().postEvent(new PlayerJoinedEvent.Immutable(getServer(), player)); } public EntityData conjurePlayerEntity(String login) { @@ -69,6 +72,10 @@ public class PlayerManager { return player; } + + public Object getMutex() { + return players; + } public Server getServer() { return server; diff --git a/src/main/java/ru/windcorp/progressia/server/Server.java b/src/main/java/ru/windcorp/progressia/server/Server.java index 8ca9383..d4d1883 100644 --- a/src/main/java/ru/windcorp/progressia/server/Server.java +++ b/src/main/java/ru/windcorp/progressia/server/Server.java @@ -15,18 +15,25 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.server; import java.util.function.Consumer; import org.apache.logging.log4j.LogManager; +import com.google.common.eventbus.EventBus; + import ru.windcorp.jputil.functions.ThrowingRunnable; import ru.windcorp.progressia.common.Units; import ru.windcorp.progressia.common.util.TaskQueue; +import ru.windcorp.progressia.common.util.crash.ReportingEventBus; import ru.windcorp.progressia.common.world.WorldData; import ru.windcorp.progressia.server.comms.ClientManager; +import ru.windcorp.progressia.server.events.ServerEvent; +import ru.windcorp.progressia.server.management.load.ChunkRequestDaemon; +import ru.windcorp.progressia.server.management.load.EntityRequestDaemon; +import ru.windcorp.progressia.server.management.load.LoadManager; import ru.windcorp.progressia.server.world.WorldLogic; import ru.windcorp.progressia.server.world.tasks.WorldAccessor; import ru.windcorp.progressia.server.world.ticking.Change; @@ -53,25 +60,32 @@ public class Server { private final ClientManager clientManager; private final PlayerManager playerManager; - private final ChunkManager chunkManager; - private final EntityManager entityManager; + private final LoadManager loadManager; private final TaskQueue taskQueue = new TaskQueue(this::isServerThread); + private final EventBus eventBus = ReportingEventBus.create("ServerEvents"); + private final TickingSettings tickingSettings = new TickingSettings(); public Server(WorldData world) { - this.world = new WorldLogic(world, this, w -> new TestPlanetGenerator("Test:PlanetGenerator", new Planet(4, 9.8f, 16f, 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); this.playerManager = new PlayerManager(this); - this.chunkManager = new ChunkManager(this); - this.entityManager = new EntityManager(this); + this.loadManager = new LoadManager(this); - schedule(chunkManager::tick); - schedule(entityManager::tick); - schedule(this::scheduleWorldTicks); // Must run after chunkManager so it only schedules chunks that hadn't unloaded + schedule(new ChunkRequestDaemon(loadManager.getChunkManager())::tick); + schedule(new EntityRequestDaemon(loadManager.getEntityManager())::tick); + + // Must run after request daemons so it only schedules chunks that + // hadn't unloaded + schedule(this::scheduleWorldTicks); } /** @@ -84,8 +98,8 @@ public class Server { } /** - * Returns this server's {@link ClientManager}. - * Use this to deal with communications, e.g. send packets. + * Returns this server's {@link ClientManager}. Use this to deal with + * communications, e.g. send packets. * * @return the {@link ClientManager} that handles this server */ @@ -97,8 +111,8 @@ public class Server { return playerManager; } - public ChunkManager getChunkManager() { - return chunkManager; + public LoadManager getLoadManager() { + return loadManager; } /** @@ -111,9 +125,9 @@ public class Server { } /** - * Requests that the provided task is executed once on next server tick. - * The task will be run in the main server thread. The task object is - * discarded after execution. + * Requests that the provided task is executed once on next server tick. The + * task will be run in the main server thread. The task object is discarded + * after execution. *

    * Use this method to request a one-time (rare) action that must necessarily * happen in the main server thread, such as initialization tasks or @@ -130,13 +144,12 @@ public class Server { /** * Executes the tasks in the server main thread as soon as possible. *

    - * If this method is invoked in the server main thread, then the task is - * run immediately (the method blocks until the task finishes). Otherwise - * this method behaves exactly like {@link #invokeLater(Runnable)}. + * If this method is invoked in the server main thread, then the task is run + * immediately (the method blocks until the task finishes). Otherwise this + * method behaves exactly like {@link #invokeLater(Runnable)}. *

    * Use this method to make sure that a piece of code is run in the main - * server - * thread. + * server thread. * * @param task the task to run * @see #invokeLater(Runnable) @@ -146,11 +159,7 @@ public class Server { taskQueue.invokeNow(task); } - public void waitAndInvoke( - ThrowingRunnable task - ) - throws InterruptedException, - E { + public void waitAndInvoke(ThrowingRunnable task) throws InterruptedException, E { taskQueue.waitAndInvoke(task); } @@ -170,6 +179,20 @@ public class Server { serverThread.getTicker().requestEvaluation(evaluation); } + public void subscribe(Object object) { + eventBus.register(object); + } + + public void unsubscribe(Object object) { + eventBus.unregister(object); + } + + public void postEvent(ServerEvent event) { + event.setServer(this); + eventBus.post(event); + event.setServer(null); + } + /** * Returns the duration of the last server tick. Server logic should assume * that this much in-world time has passed. @@ -186,8 +209,8 @@ public class Server { /** * Returns the {@link WorldAccessor} object for this server. Use the - * provided accessor to - * request common {@link Evaluation}s and {@link Change}s. + * provided accessor to request common {@link Evaluation}s and + * {@link Change}s. * * @return a {@link WorldAccessor} * @see #requestChange(Change) @@ -227,8 +250,7 @@ public class Server { /** * Shuts the server down, disconnecting the clients with the provided - * message. - * This method blocks until the shutdown is complete. + * message. This method blocks until the shutdown is complete. * * @param message the message to send to the clients as the disconnect * reason @@ -245,10 +267,9 @@ public class Server { /** * Returns an instance of {@link java.util.Random Random} that can be used - * as a source of indeterministic - * randomness. World generation and other algorithms that must have random - * but reproducible results should - * not use this. + * as a source of indeterministic randomness. World generation and other + * algorithms that must have random but reproducible results should not use + * this. * * @return a thread-safe indeterministic instance of * {@link java.util.Random}. diff --git a/src/main/java/ru/windcorp/progressia/server/comms/ClientManager.java b/src/main/java/ru/windcorp/progressia/server/comms/ClientManager.java index 74c636d..dfa631a 100644 --- a/src/main/java/ru/windcorp/progressia/server/comms/ClientManager.java +++ b/src/main/java/ru/windcorp/progressia/server/comms/ClientManager.java @@ -81,7 +81,7 @@ public class ClientManager { EntityData entity = getServer().getPlayerManager().conjurePlayerEntity(login); Player player = new Player(entity, getServer(), client); - getServer().getPlayerManager().getPlayers().add(player); + getServer().getPlayerManager().addPlayer(player); PacketSetLocalPlayer packet = new PacketSetLocalPlayer(); packet.set(entity.getEntityId()); diff --git a/src/main/java/ru/windcorp/progressia/server/comms/ClientPlayer.java b/src/main/java/ru/windcorp/progressia/server/comms/ClientPlayer.java index c455b8e..c05d952 100644 --- a/src/main/java/ru/windcorp/progressia/server/comms/ClientPlayer.java +++ b/src/main/java/ru/windcorp/progressia/server/comms/ClientPlayer.java @@ -44,13 +44,13 @@ public abstract class ClientPlayer extends ClientChat { public boolean isChunkVisible(Vec3i chunkPos) { if (player == null) return false; - return player.getServer().getChunkManager().isChunkVisible(chunkPos, player); + return player.getServer().getLoadManager().getVisionManager().isChunkVisible(chunkPos, player); } public ChunkSet getVisibleChunks() { if (player == null) return ChunkSets.empty(); - return player.getServer().getChunkManager().getVisibleChunks(player); + return player.getServer().getLoadManager().getVisionManager().getVisibleChunks(player); } public boolean isChunkVisible(long entityId) { diff --git a/src/main/java/ru/windcorp/progressia/server/events/ClientEvent.java b/src/main/java/ru/windcorp/progressia/server/events/ClientEvent.java new file mode 100644 index 0000000..c795fa8 --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/server/events/ClientEvent.java @@ -0,0 +1,46 @@ +/* + * 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.server.events; + +import ru.windcorp.progressia.server.Server; +import ru.windcorp.progressia.server.comms.Client; + +public interface ClientEvent extends ServerEvent { + + Client getClient(); + + public static abstract class Immutable extends ServerEvent.Default implements ClientEvent { + + private final Client client; + + public Immutable(Server server, Client client) { + super(server); + this.client = client; + } + + /** + * @return the client + */ + @Override + public Client getClient() { + return client; + } + + } + +} diff --git a/src/main/java/ru/windcorp/progressia/server/events/PlayerEvent.java b/src/main/java/ru/windcorp/progressia/server/events/PlayerEvent.java new file mode 100644 index 0000000..544418e --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/server/events/PlayerEvent.java @@ -0,0 +1,49 @@ +/* + * 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.server.events; + +import ru.windcorp.progressia.server.Player; +import ru.windcorp.progressia.server.Server; +import ru.windcorp.progressia.server.comms.Client; + +public interface PlayerEvent extends ClientEvent { + + Player getPlayer(); + + public static abstract class Immutable extends ServerEvent.Default implements PlayerEvent { + + private final Player player; + + public Immutable(Server server, Player player) { + super(server); + this.player = player; + } + + @Override + public Player getPlayer() { + return player; + } + + @Override + public Client getClient() { + return player.getClient(); + } + + } + +} diff --git a/src/main/java/ru/windcorp/progressia/server/events/PlayerJoinedEvent.java b/src/main/java/ru/windcorp/progressia/server/events/PlayerJoinedEvent.java new file mode 100644 index 0000000..eed2a90 --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/server/events/PlayerJoinedEvent.java @@ -0,0 +1,33 @@ +/* + * 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.server.events; + +import ru.windcorp.progressia.server.Player; +import ru.windcorp.progressia.server.Server; + +public interface PlayerJoinedEvent extends PlayerEvent { + + public static class Immutable extends PlayerEvent.Immutable implements PlayerJoinedEvent { + + public Immutable(Server server, Player player) { + super(server, player); + } + + } + +} diff --git a/src/main/java/ru/windcorp/progressia/server/events/PlayerLeftEvent.java b/src/main/java/ru/windcorp/progressia/server/events/PlayerLeftEvent.java new file mode 100644 index 0000000..d6e4417 --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/server/events/PlayerLeftEvent.java @@ -0,0 +1,33 @@ +/* + * 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.server.events; + +import ru.windcorp.progressia.server.Player; +import ru.windcorp.progressia.server.Server; + +public interface PlayerLeftEvent extends PlayerEvent { + + public static class Immutable extends PlayerEvent.Immutable implements PlayerLeftEvent { + + public Immutable(Server server, Player player) { + super(server, player); + } + + } + +} diff --git a/src/main/java/ru/windcorp/progressia/server/events/ServerEvent.java b/src/main/java/ru/windcorp/progressia/server/events/ServerEvent.java new file mode 100644 index 0000000..b63f727 --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/server/events/ServerEvent.java @@ -0,0 +1,68 @@ +/* + * 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.server.events; + +import ru.windcorp.progressia.server.Server; + +/** + * An interface for all events issued by a {@link Server}. + */ +public interface ServerEvent { + + /** + * Returns the server instance that this event happened on. + * + * @return the relevant server + */ + Server getServer(); + + /** + * Sets the server instance that the event is posted on. The value provided + * to this method must be returned by subsequent calls to + * {@link #getServer()}. Do not call this method when handling the event. + * + * @param server the server dispatching the event or {@code null} to unbind + * any previously bound server + */ + void setServer(Server server); + + /** + * A default implementation of {@link ServerEvent}. This is not necessarily + * extended by server events. + */ + public static abstract class Default implements ServerEvent { + + private Server server; + + public Default(Server server) { + this.server = server; + } + + @Override + public Server getServer() { + return server; + } + + @Override + public void setServer(Server server) { + this.server = server; + } + + } + +} diff --git a/src/main/java/ru/windcorp/progressia/server/management/load/ChunkManager.java b/src/main/java/ru/windcorp/progressia/server/management/load/ChunkManager.java new file mode 100644 index 0000000..a31a9cd --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/server/management/load/ChunkManager.java @@ -0,0 +1,192 @@ +/* + * 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.server.management.load; + +import glm.vec._3.i.Vec3i; +import ru.windcorp.progressia.common.world.ChunkData; +import ru.windcorp.progressia.common.world.PacketRevokeChunk; +import ru.windcorp.progressia.common.world.PacketSendChunk; +import ru.windcorp.progressia.common.world.WorldData; +import ru.windcorp.progressia.server.Player; +import ru.windcorp.progressia.server.Server; +import ru.windcorp.progressia.test.TestWorldDiskIO; + +/** + * Chunk manager provides facilities to load, unload and generate chunks for a + * {@link Server} on demand. + */ +public class ChunkManager { + + private final LoadManager loadManager; + + public ChunkManager(LoadManager loadManager) { + this.loadManager = loadManager; + } + + /** + * @return the loadManager + */ + public LoadManager getLoadManager() { + return loadManager; + } + + /** + * @return the server + */ + public Server getServer() { + return getLoadManager().getServer(); + } + + /** + * Describes the result of an attempt to load a chunk. + */ + public static enum LoadResult { + /** + * A chunk has successfully been read from disk and is now loaded. + */ + LOADED_FROM_DISK, + + /** + * A chunk has successfully been generated and is now loaded. + */ + GENERATED, + + /** + * A chunk has already been loaded and so no action has been taken. + */ + ALREADY_LOADED, + + /** + * A chunk has not been loaded previously and the operation has failed + * to load it. It is not currently loaded. + */ + NOT_LOADED + } + + /** + * Loads or generates the chunk at the given location unless it is already + * loaded. The chunk is loaded after this method completes normally. + * + * @param chunkPos the position of the chunk + * @return one of {@link LoadResult#LOADED_FROM_DISK LOADED_FROM_DISK}, + * {@link LoadResult#GENERATED GENERATED} or + * {@link LoadResult#ALREADY_LOADED ALREADY_LOADED} + */ + public LoadResult loadOrGenerateChunk(Vec3i chunkPos) { + LoadResult loadResult = loadChunk(chunkPos); + + if (loadResult == LoadResult.NOT_LOADED) { + getServer().getWorld().generate(chunkPos); + return LoadResult.GENERATED; + } else { + return loadResult; + } + } + + /** + * Attempts to load the chunk from disk unless it is already loaded. If the + * chunk is not currently loaded and it is not available on the disk this + * method does nothing. + * + * @param chunkPos the position of the chunk + * @return one of {@link LoadResult#LOADED_FROM_DISK LOADED_FROM_DISK}, + * {@link LoadResult#NOT_LOADED NOT_LOADED} or + * {@link LoadResult#ALREADY_LOADED ALREADY_LOADED} + */ + public LoadResult loadChunk(Vec3i chunkPos) { + if (isChunkLoaded(chunkPos)) { + return LoadResult.ALREADY_LOADED; + } + + WorldData world = getServer().getWorld().getData(); + + ChunkData chunk = TestWorldDiskIO.tryToLoad(chunkPos, world, getServer()); + if (chunk != null) { + world.addChunk(chunk); + return LoadResult.LOADED_FROM_DISK; + } else { + return LoadResult.NOT_LOADED; + } + } + + /** + * Unloads the chunk and saves it to disk if the chunk is loaded, otherwise + * does nothing. + * + * @param chunkPos the position of the chunk + * @return {@code true} iff the chunk had been loaded and was unloaded by + * this method + */ + public boolean unloadChunk(Vec3i chunkPos) { + WorldData world = getServer().getWorld().getData(); + ChunkData chunk = world.getChunk(chunkPos); + + if (chunk == null) { + return false; + } + + world.removeChunk(chunk); + TestWorldDiskIO.saveChunk(chunk, getServer()); + + return true; + } + + public void sendChunk(Player player, Vec3i chunkPos) { + ChunkData chunk = getServer().getWorld().getData().getChunk(chunkPos); + + if (chunk == null) { + throw new IllegalStateException( + String.format( + "Chunk (%d; %d; %d) is not loaded, cannot send", + chunkPos.x, + chunkPos.y, + chunkPos.z + ) + ); + } + + PacketSendChunk packet = new PacketSendChunk(); + packet.set(chunk); + player.getClient().sendPacket(packet); + + getLoadManager().getVisionManager().getVision(player, true).getVisibleChunks().add(chunkPos); + } + + public void revokeChunk(Player player, Vec3i chunkPos) { + PacketRevokeChunk packet = new PacketRevokeChunk(); + packet.set(chunkPos); + player.getClient().sendPacket(packet); + + PlayerVision vision = getLoadManager().getVisionManager().getVision(player, false); + if (vision != null) { + vision.getVisibleChunks().remove(chunkPos); + } + } + + /** + * Checks whether or not the chunk at the specified location is loaded. A + * loaded chunk is accessible through the server's {@link WorldData} object. + * + * @param chunkPos the position of the chunk + * @return {@code true} iff the chunk is loaded + */ + public boolean isChunkLoaded(Vec3i chunkPos) { + return getServer().getWorld().isChunkLoaded(chunkPos); + } + +} diff --git a/src/main/java/ru/windcorp/progressia/server/management/load/ChunkRequestDaemon.java b/src/main/java/ru/windcorp/progressia/server/management/load/ChunkRequestDaemon.java new file mode 100644 index 0000000..ff3c7e0 --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/server/management/load/ChunkRequestDaemon.java @@ -0,0 +1,206 @@ +/* + * 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.server.management.load; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Iterator; + +import glm.vec._3.i.Vec3i; +import ru.windcorp.progressia.common.Units; +import ru.windcorp.progressia.common.world.generic.ChunkMap; +import ru.windcorp.progressia.common.world.generic.ChunkMaps; +import ru.windcorp.progressia.common.world.generic.ChunkSet; +import ru.windcorp.progressia.common.world.generic.ChunkSets; +import ru.windcorp.progressia.server.Server; + +/** + * Chunk request daemon gathers chunk requests from players (via {@link VisionManager}) and loads or unloads chunks appropriately. + */ +public class ChunkRequestDaemon { + + private static final float CHUNK_UNLOAD_DELAY = Units.get(5, "s"); + + private final ChunkManager chunkManager; + + private final ChunkSet loaded; + private final ChunkSet requested = ChunkSets.newHashSet(); + private final ChunkSet toLoad = ChunkSets.newHashSet(); + private final ChunkSet toRequestUnload = ChunkSets.newHashSet(); + + private final Collection buffer = new ArrayList<>(); + + private static class ChunkUnloadRequest { + private final Vec3i chunkPos; + private final long unloadAt; + + public ChunkUnloadRequest(Vec3i chunkPos, long unloadAt) { + this.chunkPos = chunkPos; + this.unloadAt = unloadAt; + } + + /** + * @return the chunk position + */ + public Vec3i getChunkPos() { + return chunkPos; + } + + /** + * @return the moment when the chunks becomes eligible for unloading + */ + public long getUnloadAt() { + return unloadAt; + } + } + + private final ChunkMap unloadSchedule = ChunkMaps.newHashMap(); + + public ChunkRequestDaemon(ChunkManager chunkManager) { + this.chunkManager = chunkManager; + this.loaded = getServer().getWorld().getData().getLoadedChunks(); + } + + public void tick() { + synchronized (getServer().getWorld().getData()) { + synchronized (getServer().getPlayerManager().getMutex()) { + loadAndUnloadChunks(); + sendAndRevokeChunks(); + } + } + } + + private void loadAndUnloadChunks() { + gatherLoadRequests(); + updateLoadQueues(); + processLoadQueues(); + } + + private void gatherLoadRequests() { + requested.clear(); + + getChunkManager().getLoadManager().getVisionManager().forEachVision(vision -> { + vision.getRequestedChunks().clear(); + vision.getPlayer().requestChunksToLoad(vision.getRequestedChunks()::add); + requested.addAll(vision.getRequestedChunks()); + }); + } + + private void updateLoadQueues() { + toLoad.clear(); + toLoad.addAll(requested); + toLoad.removeAll(loaded); + + toRequestUnload.clear(); + toRequestUnload.addAll(loaded); + toRequestUnload.removeAll(requested); + } + + private void processLoadQueues() { + toRequestUnload.forEach(this::scheduleUnload); + toRequestUnload.clear(); + + toLoad.forEach(getChunkManager()::loadOrGenerateChunk); + toLoad.clear(); + + unloadScheduledChunks(); + } + + private void scheduleUnload(Vec3i chunkPos) { + if (unloadSchedule.containsKey(chunkPos)) { + // Unload already requested, skip + return; + } + + long unloadAt = System.currentTimeMillis() + (long) (getUnloadDelay() * 1000); + Vec3i chunkPosCopy = new Vec3i(chunkPos); + + unloadSchedule.put(chunkPosCopy, new ChunkUnloadRequest(chunkPosCopy, unloadAt)); + } + + private void unloadScheduledChunks() { + long now = System.currentTimeMillis(); + + for (Iterator it = unloadSchedule.values().iterator(); it.hasNext();) { + ChunkUnloadRequest request = it.next(); + + if (request.getUnloadAt() < now) { + it.remove(); + getChunkManager().unloadChunk(request.getChunkPos()); + } + } + } + + private void sendAndRevokeChunks() { + getChunkManager().getLoadManager().getVisionManager().forEachVision(vision -> { + revokeChunks(vision); + sendChunks(vision); + }); + } + + private void sendChunks(PlayerVision vision) { + vision.getRequestedChunks().forEachIn(getServer().getWorld(), chunk -> { + if (!chunk.isReady()) + return; + if (vision.isChunkVisible(chunk.getPosition())) + return; + buffer.add(chunk.getPosition()); + }); + + if (buffer.isEmpty()) return; + for (Vec3i chunkPos : buffer) { + getChunkManager().sendChunk(vision.getPlayer(), chunkPos); + } + + buffer.clear(); + } + + private void revokeChunks(PlayerVision vision) { + vision.getVisibleChunks().forEach(chunkPos -> { + if (getChunkManager().isChunkLoaded(chunkPos) && vision.getRequestedChunks().contains(chunkPos)) + return; + buffer.add(new Vec3i(chunkPos)); + }); + + if (buffer.isEmpty()) return; + for (Vec3i chunkPos : buffer) { + getChunkManager().revokeChunk(vision.getPlayer(), chunkPos); + } + + buffer.clear(); + } + + /** + * @return the minimum amount of time a chunk will spend in the unload queue + */ + public float getUnloadDelay() { + return CHUNK_UNLOAD_DELAY; + } + + /** + * @return the manager + */ + public ChunkManager getChunkManager() { + return chunkManager; + } + + public Server getServer() { + return getChunkManager().getServer(); + } + +} diff --git a/src/main/java/ru/windcorp/progressia/server/management/load/EntityManager.java b/src/main/java/ru/windcorp/progressia/server/management/load/EntityManager.java new file mode 100644 index 0000000..6aa3853 --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/server/management/load/EntityManager.java @@ -0,0 +1,97 @@ +/* + * 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.server.management.load; + +import gnu.trove.set.TLongSet; +import ru.windcorp.progressia.common.world.entity.EntityData; +import ru.windcorp.progressia.common.world.entity.PacketRevokeEntity; +import ru.windcorp.progressia.common.world.entity.PacketSendEntity; +import ru.windcorp.progressia.server.Player; +import ru.windcorp.progressia.server.Server; + +public class EntityManager { + + private final LoadManager loadManager; + + private final TLongSet loaded; + + public EntityManager(LoadManager loadManager) { + this.loadManager = loadManager; + this.loaded = getServer().getWorld().getData().getLoadedEntities(); + } + + public void sendEntity(Player player, long entityId) { + PlayerVision vision = getLoadManager().getVisionManager().getVision(player, true); + if (!vision.getVisibleEntities().add(entityId)) { + return; + } + + EntityData entity = getServer().getWorld().getData().getEntity(entityId); + + if (entity == null) { + throw new IllegalStateException( + "Entity with entity ID " + EntityData.formatEntityId(entityId) + " is not loaded, cannot send" + ); + } + + PacketSendEntity packet = new PacketSendEntity(); + packet.set(entity); + player.getClient().sendPacket(packet); + } + + public void revokeEntity(Player player, long entityId) { + PlayerVision vision = getLoadManager().getVisionManager().getVision(player, false); + if (vision == null) { + return; + } + if (!vision.getVisibleEntities().remove(entityId)) { + return; + } + + PacketRevokeEntity packet = new PacketRevokeEntity(); + packet.set(entityId); + player.getClient().sendPacket(packet); + } + + public boolean isEntityVisible(Player player, long entityId) { + PlayerVision vision = getLoadManager().getVisionManager().getVision(player, false); + + if (vision == null) { + return false; + } + + return vision.isEntityVisible(entityId); + } + + public boolean isEntityLoaded(long entityId) { + return loaded.contains(entityId); + } + + /** + * @return the loadManager + */ + public LoadManager getLoadManager() { + return loadManager; + } + + public Server getServer() { + return getLoadManager().getServer(); + } + +} diff --git a/src/main/java/ru/windcorp/progressia/server/management/load/EntityRequestDaemon.java b/src/main/java/ru/windcorp/progressia/server/management/load/EntityRequestDaemon.java new file mode 100644 index 0000000..9605ffe --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/server/management/load/EntityRequestDaemon.java @@ -0,0 +1,121 @@ +/* + * 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.server.management.load; + +import java.util.function.Consumer; + +import glm.vec._3.i.Vec3i; +import gnu.trove.TLongCollection; +import gnu.trove.iterator.TLongIterator; +import gnu.trove.list.array.TLongArrayList; +import gnu.trove.set.TLongSet; +import ru.windcorp.progressia.common.util.Vectors; +import ru.windcorp.progressia.common.world.generic.ChunkSet; +import ru.windcorp.progressia.server.Server; + +public class EntityRequestDaemon { + + private final EntityManager entityManager; + + private final TLongCollection buffer = new TLongArrayList(); + + public EntityRequestDaemon(EntityManager entityManager) { + this.entityManager = entityManager; + } + + public void tick() { + synchronized (getServer().getWorld().getData()) { + synchronized (getServer().getPlayerManager().getMutex()) { + gatherRequests(); + revokeEntities(); + sendEntities(); + } + } + } + + private void gatherRequests() { + Vec3i v = Vectors.grab3i(); + + forEachVision(vision -> { + + TLongSet requestedEntities = vision.getRequestedEntities(); + requestedEntities.clear(); + + ChunkSet visibleChunks = vision.getVisibleChunks(); + getServer().getWorld().forEachEntity(entity -> { + if (visibleChunks.contains(entity.getChunkCoords(v))) { + requestedEntities.add(entity.getEntityId()); + } + }); + }); + + Vectors.release(v); + } + + private void sendEntities() { + forEachVision(vision -> { + for (TLongIterator it = vision.getRequestedEntities().iterator(); it.hasNext();) { + long entityId = it.next(); + if (getEntityManager().isEntityLoaded(entityId) && !vision.getVisibleEntities().contains(entityId)) { + buffer.add(entityId); + } + } + + if (buffer.isEmpty()) return; + for (TLongIterator it = buffer.iterator(); it.hasNext();) { + getEntityManager().sendEntity(vision.getPlayer(), it.next()); + } + + buffer.clear(); + }); + } + + private void revokeEntities() { + forEachVision(vision -> { + for (TLongIterator it = vision.getVisibleEntities().iterator(); it.hasNext();) { + long entityId = it.next(); + if (!getEntityManager().isEntityLoaded(entityId) || !vision.getRequestedEntities().contains(entityId)) { + buffer.add(entityId); + } + } + + if (buffer.isEmpty()) return; + for (TLongIterator it = buffer.iterator(); it.hasNext();) { + getEntityManager().revokeEntity(vision.getPlayer(), it.next()); + } + + buffer.clear(); + }); + } + + /** + * @return the entityManager + */ + public EntityManager getEntityManager() { + return entityManager; + } + + public Server getServer() { + return getEntityManager().getServer(); + } + + private void forEachVision(Consumer action) { + getEntityManager().getLoadManager().getVisionManager().forEachVision(action); + } + +} diff --git a/src/main/java/ru/windcorp/progressia/server/management/load/LoadManager.java b/src/main/java/ru/windcorp/progressia/server/management/load/LoadManager.java new file mode 100644 index 0000000..3670116 --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/server/management/load/LoadManager.java @@ -0,0 +1,65 @@ +/* + * 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.server.management.load; + +import ru.windcorp.progressia.server.Server; + +public class LoadManager { + + private final Server server; + private final ChunkManager chunkManager; + private final EntityManager entityManager; + private final VisionManager visionManager; + + public LoadManager(Server server) { + this.server = server; + + this.chunkManager = new ChunkManager(this); + this.entityManager = new EntityManager(this); + this.visionManager = new VisionManager(this); + } + + /** + * @return the chunkManager + */ + public ChunkManager getChunkManager() { + return chunkManager; + } + + /** + * @return the entityManager + */ + public EntityManager getEntityManager() { + return entityManager; + } + + /** + * @return the visionManager + */ + public VisionManager getVisionManager() { + return visionManager; + } + + /** + * @return the server + */ + public Server getServer() { + return server; + } + +} diff --git a/src/main/java/ru/windcorp/progressia/server/management/load/PlayerVision.java b/src/main/java/ru/windcorp/progressia/server/management/load/PlayerVision.java new file mode 100644 index 0000000..bb8e474 --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/server/management/load/PlayerVision.java @@ -0,0 +1,85 @@ +/* + * 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.server.management.load; + +import glm.vec._3.i.Vec3i; +import gnu.trove.TCollections; +import gnu.trove.set.TLongSet; +import gnu.trove.set.hash.TLongHashSet; +import ru.windcorp.progressia.common.world.generic.ChunkSet; +import ru.windcorp.progressia.common.world.generic.ChunkSets; +import ru.windcorp.progressia.server.Player; + +public class PlayerVision { + + private final Player player; + + private final ChunkSet visibleChunks = ChunkSets.newSyncHashSet(); + private final ChunkSet requestedChunks = ChunkSets.newHashSet(); + + private final TLongSet visibleEntities = TCollections.synchronizedSet(new TLongHashSet()); + private final TLongSet requestedEntities = new TLongHashSet(); + + public PlayerVision(Player player) { + this.player = player; + } + + public boolean isChunkVisible(Vec3i chunkPos) { + return visibleChunks.contains(chunkPos); + } + + public boolean isEntityVisible(long entityId) { + return visibleEntities.contains(entityId); + } + + /** + * @return the requestedChunks + */ + public ChunkSet getRequestedChunks() { + return requestedChunks; + } + + /** + * @return the visibleChunks + */ + public ChunkSet getVisibleChunks() { + return visibleChunks; + } + + /** + * @return the requestedEntities + */ + public TLongSet getRequestedEntities() { + return requestedEntities; + } + + /** + * @return the visibleEntities + */ + public TLongSet getVisibleEntities() { + return visibleEntities; + } + + /** + * @return the player + */ + public Player getPlayer() { + return player; + } + +} diff --git a/src/main/java/ru/windcorp/progressia/server/management/load/VisionManager.java b/src/main/java/ru/windcorp/progressia/server/management/load/VisionManager.java new file mode 100644 index 0000000..cdf2d8e --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/server/management/load/VisionManager.java @@ -0,0 +1,108 @@ +/* + * 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.server.management.load; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import java.util.function.Consumer; + +import com.google.common.eventbus.Subscribe; + +import glm.vec._3.i.Vec3i; +import ru.windcorp.progressia.common.world.generic.ChunkSet; +import ru.windcorp.progressia.common.world.generic.ChunkSets; +import ru.windcorp.progressia.server.Player; +import ru.windcorp.progressia.server.Server; +import ru.windcorp.progressia.server.events.PlayerJoinedEvent; +import ru.windcorp.progressia.server.events.PlayerLeftEvent; + +public class VisionManager { + + private final LoadManager loadManager; + + private final Map visions = Collections.synchronizedMap(new HashMap<>()); + + public VisionManager(LoadManager loadManager) { + this.loadManager = loadManager; + getServer().subscribe(this); + } + + @Subscribe + private void onPlayerJoined(PlayerJoinedEvent event) { + System.out.println("VisionManager.onPlayerJoined()"); + getVision(event.getPlayer(), true); + } + + @Subscribe + private void onPlayerLeft(PlayerLeftEvent event) { + System.out.println("VisionManager.onPlayerLeft()"); + visions.remove(event.getPlayer()); + } + + public PlayerVision getVision(Player player, boolean createIfMissing) { + if (createIfMissing) { + return visions.computeIfAbsent(player, PlayerVision::new); + } else { + return visions.get(player); + } + } + + public void forEachVision(Consumer action) { + visions.values().forEach(action); + } + + public boolean isChunkVisible(Vec3i chunkPos, Player player) { + PlayerVision vision = getVision(player, false); + + if (vision == null) { + return false; + } + + return vision.isChunkVisible(chunkPos); + } + + public ChunkSet getVisibleChunks(Player player) { + PlayerVision vision = getVision(player, false); + + if (vision == null) { + return ChunkSets.empty(); + } + + return vision.getVisibleChunks(); + } + + /** + * @return the loadManager + */ + public LoadManager getLoadManager() { + return loadManager; + } + + /** + * @return the chunkManager + */ + public ChunkManager getChunkManager() { + return getLoadManager().getChunkManager(); + } + + public Server getServer() { + return getLoadManager().getServer(); + } + +} From 7ecdfdfb4dfd508648405adf33e96089d0d537c0 Mon Sep 17 00:00:00 2001 From: OLEGSHA Date: Fri, 26 Mar 2021 21:26:05 +0300 Subject: [PATCH 18/55] Added scatter generation logic to TestPlanetGenerator - Scatter generation is now triggered properly in TestPlanetGenerator - WorldGenerators are now required to call addChunk() themselves (again) - ChunkManager now generates loaded chunks that are not ready - Chunks scheduled for unloading no longer unload if they become requested while in queue --- .../server/management/load/ChunkManager.java | 2 +- .../management/load/ChunkRequestDaemon.java | 6 ++++ .../progressia/server/world/WorldLogic.java | 4 +-- .../test/gen/TestWorldGenerator.java | 4 ++- .../gen/planet/PlanetScatterGenerator.java | 3 ++ .../gen/planet/PlanetTerrainGenerator.java | 4 ++- .../test/gen/planet/TestPlanetGenerator.java | 31 +++++++++++++++++-- 7 files changed, 45 insertions(+), 9 deletions(-) diff --git a/src/main/java/ru/windcorp/progressia/server/management/load/ChunkManager.java b/src/main/java/ru/windcorp/progressia/server/management/load/ChunkManager.java index a31a9cd..baf68f6 100644 --- a/src/main/java/ru/windcorp/progressia/server/management/load/ChunkManager.java +++ b/src/main/java/ru/windcorp/progressia/server/management/load/ChunkManager.java @@ -90,7 +90,7 @@ public class ChunkManager { public LoadResult loadOrGenerateChunk(Vec3i chunkPos) { LoadResult loadResult = loadChunk(chunkPos); - if (loadResult == LoadResult.NOT_LOADED) { + if (loadResult == LoadResult.NOT_LOADED || !getServer().getWorld().getChunk(chunkPos).isReady()) { getServer().getWorld().generate(chunkPos); return LoadResult.GENERATED; } else { diff --git a/src/main/java/ru/windcorp/progressia/server/management/load/ChunkRequestDaemon.java b/src/main/java/ru/windcorp/progressia/server/management/load/ChunkRequestDaemon.java index ff3c7e0..502f68f 100644 --- a/src/main/java/ru/windcorp/progressia/server/management/load/ChunkRequestDaemon.java +++ b/src/main/java/ru/windcorp/progressia/server/management/load/ChunkRequestDaemon.java @@ -140,7 +140,13 @@ public class ChunkRequestDaemon { ChunkUnloadRequest request = it.next(); if (request.getUnloadAt() < now) { + it.remove(); + + if (requested.contains(request.getChunkPos())) { + continue; // do not unload chunks that became requested + } + getChunkManager().unloadChunk(request.getChunkPos()); } } diff --git a/src/main/java/ru/windcorp/progressia/server/world/WorldLogic.java b/src/main/java/ru/windcorp/progressia/server/world/WorldLogic.java index bf5da5e..5931e34 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/WorldLogic.java +++ b/src/main/java/ru/windcorp/progressia/server/world/WorldLogic.java @@ -106,9 +106,7 @@ public class WorldLogic } public ChunkData generate(Vec3i chunkPos) { - ChunkData chunk = getGenerator().generate(chunkPos, getData()); - getData().addChunk(chunk); - return chunk; + return getGenerator().generate(chunkPos, getData()); } public ChunkLogic getChunk(ChunkData chunkData) { diff --git a/src/main/java/ru/windcorp/progressia/test/gen/TestWorldGenerator.java b/src/main/java/ru/windcorp/progressia/test/gen/TestWorldGenerator.java index e66d9b7..8e0195a 100644 --- a/src/main/java/ru/windcorp/progressia/test/gen/TestWorldGenerator.java +++ b/src/main/java/ru/windcorp/progressia/test/gen/TestWorldGenerator.java @@ -78,7 +78,9 @@ public class TestWorldGenerator extends AbstractWorldGenerator { @Override public ChunkData generate(Vec3i chunkPos, WorldData world) { - return generateUnpopulated(chunkPos, world); + ChunkData chunk = generateUnpopulated(chunkPos, world); + world.addChunk(chunk); + return chunk; } private ChunkData generateUnpopulated(Vec3i chunkPos, WorldData world) { diff --git a/src/main/java/ru/windcorp/progressia/test/gen/planet/PlanetScatterGenerator.java b/src/main/java/ru/windcorp/progressia/test/gen/planet/PlanetScatterGenerator.java index da0f8d3..a2af1d4 100644 --- a/src/main/java/ru/windcorp/progressia/test/gen/planet/PlanetScatterGenerator.java +++ b/src/main/java/ru/windcorp/progressia/test/gen/planet/PlanetScatterGenerator.java @@ -17,7 +17,9 @@ */ package ru.windcorp.progressia.test.gen.planet; +import glm.vec._3.i.Vec3i; import ru.windcorp.progressia.common.world.ChunkData; +import ru.windcorp.progressia.common.world.block.BlockDataRegistry; import ru.windcorp.progressia.test.gen.surface.SurfaceScatterGenerator; public class PlanetScatterGenerator { @@ -35,6 +37,7 @@ public class PlanetScatterGenerator { } public void generateScatter(ChunkData chunk) { + chunk.setBlock(new Vec3i(8, 8, 8), BlockDataRegistry.getInstance().get("Test:Log"), false); surfaceGenerator.generateScatter(chunk); } diff --git a/src/main/java/ru/windcorp/progressia/test/gen/planet/PlanetTerrainGenerator.java b/src/main/java/ru/windcorp/progressia/test/gen/planet/PlanetTerrainGenerator.java index d59984a..5948b92 100644 --- a/src/main/java/ru/windcorp/progressia/test/gen/planet/PlanetTerrainGenerator.java +++ b/src/main/java/ru/windcorp/progressia/test/gen/planet/PlanetTerrainGenerator.java @@ -48,9 +48,11 @@ class PlanetTerrainGenerator { FloatRangeMap layers = new ArrayFloatRangeMap<>(); BlockData granite = BlockDataRegistry.getInstance().get("Test:GraniteMonolith"); + BlockData dirt = BlockDataRegistry.getInstance().get("Test:Dirt"); BlockData air = BlockDataRegistry.getInstance().get("Test:Air"); layers.put(Float.NEGATIVE_INFINITY, 0, (n, w, d, r, c) -> air); - layers.put(0, Float.POSITIVE_INFINITY, (n, w, d, r, c) -> granite); + layers.put(0, 4, (n, w, d, r, c) -> dirt); + layers.put(4, Float.POSITIVE_INFINITY, (n, w, d, r, c) -> granite); this.surfaceGenerator = new SurfaceTerrainGenerator((f, n, w) -> heightMap.get(f, n, w) + generator.getPlanet().getRadius(), layers); } 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 3012715..3f548e9 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 @@ -20,16 +20,21 @@ package ru.windcorp.progressia.test.gen.planet; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; + import glm.vec._3.Vec3; import glm.vec._3.i.Vec3i; +import ru.windcorp.progressia.common.util.VectorUtil; import ru.windcorp.progressia.common.world.ChunkData; import ru.windcorp.progressia.common.world.DecodingException; import ru.windcorp.progressia.common.world.WorldData; +import ru.windcorp.progressia.server.Server; import ru.windcorp.progressia.server.world.WorldLogic; import ru.windcorp.progressia.server.world.generation.AbstractWorldGenerator; public class TestPlanetGenerator extends AbstractWorldGenerator { + private final Server server; + private final Planet planet; private final PlanetTerrainGenerator terrainGenerator; @@ -38,6 +43,7 @@ public class TestPlanetGenerator extends AbstractWorldGenerator { public TestPlanetGenerator(String id, Planet planet, WorldLogic world) { super(id, Boolean.class, "Test:PlanetGravityModel"); + this.server = world.getServer(); this.planet = planet; TestPlanetGravityModel model = (TestPlanetGravityModel) this.getGravityModel(); @@ -71,14 +77,33 @@ public class TestPlanetGenerator extends AbstractWorldGenerator { @Override protected boolean checkIsChunkReady(Boolean hint) { - return hint; + return hint == Boolean.TRUE; // Avoid NPE } @Override public ChunkData generate(Vec3i chunkPos, WorldData world) { - ChunkData chunk = terrainGenerator.generateTerrain(chunkPos, world); - scatterGenerator.generateScatter(chunk); + VectorUtil.iterateCuboidAround(chunkPos, 3, r -> conjureTerrain(r, world)); + ChunkData chunk = world.getChunk(chunkPos); + + if (!isChunkReady(chunk.getGenerationHint())) { + scatterGenerator.generateScatter(chunk); + } + return chunk; } + + private void conjureTerrain(Vec3i chunkPos, WorldData world) { + ChunkData chunk = world.getChunk(chunkPos); + + if (chunk == null) { + server.getLoadManager().getChunkManager().loadChunk(chunkPos); + chunk = world.getChunk(chunkPos); + } + + if (chunk == null) { + chunk = terrainGenerator.generateTerrain(chunkPos, world); + world.addChunk(chunk); + } + } } From 2d3d250f92efecea018b66f4d913fe511ae433f6 Mon Sep 17 00:00:00 2001 From: OLEGSHA Date: Fri, 2 Apr 2021 21:29:09 +0300 Subject: [PATCH 19/55] Renamed Scatter to Feature and added a generation feature interface - Renamed SurfaceScatterGenerator to SurfaceFeatureGenerator - Renamed PlanetScatterGenerator to PlanetFeatureGenerator - Added a very basic interface for adding generation features - Removed debug leftovers from PlayerManager and VisionManager --- .../progressia/server/PlayerManager.java | 1 - .../server/management/load/VisionManager.java | 2 - .../gen/planet/PlanetFeatureGenerator.java | 78 +++++++++++++++++++ .../test/gen/planet/TestPlanetGenerator.java | 6 +- ...tterGenerator.java => SurfaceFeature.java} | 13 +++- .../SurfaceFeatureGenerator.java} | 37 ++++----- 6 files changed, 109 insertions(+), 28 deletions(-) create mode 100644 src/main/java/ru/windcorp/progressia/test/gen/planet/PlanetFeatureGenerator.java rename src/main/java/ru/windcorp/progressia/test/gen/surface/{SurfaceScatterGenerator.java => SurfaceFeature.java} (76%) rename src/main/java/ru/windcorp/progressia/test/gen/{planet/PlanetScatterGenerator.java => surface/SurfaceFeatureGenerator.java} (51%) diff --git a/src/main/java/ru/windcorp/progressia/server/PlayerManager.java b/src/main/java/ru/windcorp/progressia/server/PlayerManager.java index 10799e0..f762778 100644 --- a/src/main/java/ru/windcorp/progressia/server/PlayerManager.java +++ b/src/main/java/ru/windcorp/progressia/server/PlayerManager.java @@ -45,7 +45,6 @@ public class PlayerManager { public void addPlayer(Player player) { this.players.add(player); - System.out.println("PlayerManager.addPlayer()"); getServer().postEvent(new PlayerJoinedEvent.Immutable(getServer(), player)); } diff --git a/src/main/java/ru/windcorp/progressia/server/management/load/VisionManager.java b/src/main/java/ru/windcorp/progressia/server/management/load/VisionManager.java index cdf2d8e..b4d2a93 100644 --- a/src/main/java/ru/windcorp/progressia/server/management/load/VisionManager.java +++ b/src/main/java/ru/windcorp/progressia/server/management/load/VisionManager.java @@ -45,13 +45,11 @@ public class VisionManager { @Subscribe private void onPlayerJoined(PlayerJoinedEvent event) { - System.out.println("VisionManager.onPlayerJoined()"); getVision(event.getPlayer(), true); } @Subscribe private void onPlayerLeft(PlayerLeftEvent event) { - System.out.println("VisionManager.onPlayerLeft()"); visions.remove(event.getPlayer()); } 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 new file mode 100644 index 0000000..79f0593 --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/test/gen/planet/PlanetFeatureGenerator.java @@ -0,0 +1,78 @@ +/* + * 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.planet; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Random; + +import glm.vec._3.i.Vec3i; +import ru.windcorp.progressia.common.util.VectorUtil; +import ru.windcorp.progressia.common.world.ChunkData; +import ru.windcorp.progressia.common.world.block.BlockDataRegistry; +import ru.windcorp.progressia.test.gen.surface.SurfaceFeature; +import ru.windcorp.progressia.test.gen.surface.SurfaceFeatureGenerator; + +public class PlanetFeatureGenerator { + + private final TestPlanetGenerator parent; + private final SurfaceFeatureGenerator surfaceGenerator; + + public PlanetFeatureGenerator(TestPlanetGenerator generator) { + this.parent = generator; + + Collection features = new ArrayList<>(); + features.add(new SurfaceFeature("Test:GlassFeature") { + @Override + public void process(ChunkData chunk, Random random) { + + chunk.setBlockRel(new Vec3i(8, 8, 8), BlockDataRegistry.getInstance().get("Test:Glass"), true); + + } + }); + + this.surfaceGenerator = new SurfaceFeatureGenerator(features); + } + + public TestPlanetGenerator getGenerator() { + return parent; + } + + public void generateFeatures(ChunkData chunk) { + if (isOrdinaryChunk(chunk.getPosition())) { + generateOrdinaryFeatures(chunk); + } else { + generateBorderFeatures(chunk); + } + } + + private boolean isOrdinaryChunk(Vec3i chunkPos) { + Vec3i sorted = VectorUtil.sortAfterAbs(chunkPos, null); + return sorted.x != sorted.y; + } + + private void generateOrdinaryFeatures(ChunkData chunk) { + surfaceGenerator.generateFeatures(chunk); + } + + private void generateBorderFeatures(ChunkData chunk) { + // Do nothing + chunk.setGenerationHint(true); + } + +} 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 3f548e9..7206edc 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 @@ -38,7 +38,7 @@ public class TestPlanetGenerator extends AbstractWorldGenerator { private final Planet planet; private final PlanetTerrainGenerator terrainGenerator; - private final PlanetScatterGenerator scatterGenerator; + private final PlanetFeatureGenerator featureGenerator; public TestPlanetGenerator(String id, Planet planet, WorldLogic world) { super(id, Boolean.class, "Test:PlanetGravityModel"); @@ -50,7 +50,7 @@ public class TestPlanetGenerator extends AbstractWorldGenerator { model.configure(planet.getGravityModelSettings()); this.terrainGenerator = new PlanetTerrainGenerator(this); - this.scatterGenerator = new PlanetScatterGenerator(this); + this.featureGenerator = new PlanetFeatureGenerator(this); } /** @@ -86,7 +86,7 @@ public class TestPlanetGenerator extends AbstractWorldGenerator { ChunkData chunk = world.getChunk(chunkPos); if (!isChunkReady(chunk.getGenerationHint())) { - scatterGenerator.generateScatter(chunk); + featureGenerator.generateFeatures(chunk); } return chunk; diff --git a/src/main/java/ru/windcorp/progressia/test/gen/surface/SurfaceScatterGenerator.java b/src/main/java/ru/windcorp/progressia/test/gen/surface/SurfaceFeature.java similarity index 76% rename from src/main/java/ru/windcorp/progressia/test/gen/surface/SurfaceScatterGenerator.java rename to src/main/java/ru/windcorp/progressia/test/gen/surface/SurfaceFeature.java index a9f08d9..649b414 100644 --- a/src/main/java/ru/windcorp/progressia/test/gen/surface/SurfaceScatterGenerator.java +++ b/src/main/java/ru/windcorp/progressia/test/gen/surface/SurfaceFeature.java @@ -17,12 +17,17 @@ */ package ru.windcorp.progressia.test.gen.surface; +import java.util.Random; + +import ru.windcorp.progressia.common.util.namespaces.Namespaced; import ru.windcorp.progressia.common.world.ChunkData; -public class SurfaceScatterGenerator { - - public void generateScatter(ChunkData chunk) { - chunk.setGenerationHint(true); +public abstract class SurfaceFeature extends Namespaced { + + public SurfaceFeature(String id) { + super(id); } + + public abstract void process(ChunkData chunk, Random random); } diff --git a/src/main/java/ru/windcorp/progressia/test/gen/planet/PlanetScatterGenerator.java b/src/main/java/ru/windcorp/progressia/test/gen/surface/SurfaceFeatureGenerator.java similarity index 51% rename from src/main/java/ru/windcorp/progressia/test/gen/planet/PlanetScatterGenerator.java rename to src/main/java/ru/windcorp/progressia/test/gen/surface/SurfaceFeatureGenerator.java index a2af1d4..753256a 100644 --- a/src/main/java/ru/windcorp/progressia/test/gen/planet/PlanetScatterGenerator.java +++ b/src/main/java/ru/windcorp/progressia/test/gen/surface/SurfaceFeatureGenerator.java @@ -15,30 +15,31 @@ * 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.planet; +package ru.windcorp.progressia.test.gen.surface; -import glm.vec._3.i.Vec3i; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Random; + +import ru.windcorp.progressia.common.util.CoordinatePacker; import ru.windcorp.progressia.common.world.ChunkData; -import ru.windcorp.progressia.common.world.block.BlockDataRegistry; -import ru.windcorp.progressia.test.gen.surface.SurfaceScatterGenerator; -public class PlanetScatterGenerator { +public class SurfaceFeatureGenerator { - private final TestPlanetGenerator parent; - private final SurfaceScatterGenerator surfaceGenerator; - - public PlanetScatterGenerator(TestPlanetGenerator generator) { - this.parent = generator; - this.surfaceGenerator = new SurfaceScatterGenerator(); + private final Collection features; // TODO make ordered + + public SurfaceFeatureGenerator(Collection features) { + this.features = new ArrayList<>(features); } - public TestPlanetGenerator getGenerator() { - return parent; - } - - public void generateScatter(ChunkData chunk) { - chunk.setBlock(new Vec3i(8, 8, 8), BlockDataRegistry.getInstance().get("Test:Log"), false); - surfaceGenerator.generateScatter(chunk); + public void generateFeatures(ChunkData chunk) { + Random random = new Random(CoordinatePacker.pack3IntsIntoLong(chunk.getPosition()) /* ^ seed*/); + + for (SurfaceFeature feature : features) { + feature.process(chunk, random); + } + + chunk.setGenerationHint(true); } } From 3c3f3816df85b4dc214b1c871f1d30e7a65aeceb Mon Sep 17 00:00:00 2001 From: OLEGSHA Date: Fri, 2 Apr 2021 21:51:52 +0300 Subject: [PATCH 20/55] Fixed a generation issue and refactored some code around WorldGenerators - ChunkRequestDaemon now attempts to generate requested loaded non-ready chunks upon discovery - The server is now only specified once for WorldGenerator - WorldLogic now actively checks the generation contract --- .../ru/windcorp/progressia/server/Server.java | 2 +- .../management/load/ChunkRequestDaemon.java | 13 +++++- .../progressia/server/world/WorldLogic.java | 40 +++++++++++++++++-- .../generation/AbstractWorldGenerator.java | 23 ++++++++++- .../world/generation/WorldGenerator.java | 8 +++- .../test/gen/TestWorldGenerator.java | 16 ++++---- .../gen/planet/PlanetTerrainGenerator.java | 5 +-- .../test/gen/planet/TestPlanetGenerator.java | 27 +++++-------- 8 files changed, 98 insertions(+), 36 deletions(-) diff --git a/src/main/java/ru/windcorp/progressia/server/Server.java b/src/main/java/ru/windcorp/progressia/server/Server.java index d4d1883..63435a1 100644 --- a/src/main/java/ru/windcorp/progressia/server/Server.java +++ b/src/main/java/ru/windcorp/progressia/server/Server.java @@ -72,7 +72,7 @@ public class Server { this.world = new WorldLogic( world, this, - w -> new TestPlanetGenerator("Test:PlanetGenerator", new Planet(4, 9.8f, 16f, 16f), w) + new TestPlanetGenerator("Test:PlanetGenerator", this, new Planet(4, 9.8f, 16f, 16f)) ); this.serverThread = new ServerThread(this); diff --git a/src/main/java/ru/windcorp/progressia/server/management/load/ChunkRequestDaemon.java b/src/main/java/ru/windcorp/progressia/server/management/load/ChunkRequestDaemon.java index 502f68f..f720c7f 100644 --- a/src/main/java/ru/windcorp/progressia/server/management/load/ChunkRequestDaemon.java +++ b/src/main/java/ru/windcorp/progressia/server/management/load/ChunkRequestDaemon.java @@ -41,6 +41,7 @@ public class ChunkRequestDaemon { private final ChunkSet loaded; private final ChunkSet requested = ChunkSets.newHashSet(); private final ChunkSet toLoad = ChunkSets.newHashSet(); + private final ChunkSet toGenerate = ChunkSets.newHashSet(); private final ChunkSet toRequestUnload = ChunkSets.newHashSet(); private final Collection buffer = new ArrayList<>(); @@ -118,6 +119,9 @@ public class ChunkRequestDaemon { toLoad.forEach(getChunkManager()::loadOrGenerateChunk); toLoad.clear(); + toGenerate.forEach(getChunkManager()::loadOrGenerateChunk); + toGenerate.clear(); + unloadScheduledChunks(); } @@ -161,10 +165,15 @@ public class ChunkRequestDaemon { private void sendChunks(PlayerVision vision) { vision.getRequestedChunks().forEachIn(getServer().getWorld(), chunk -> { - if (!chunk.isReady()) + if (!chunk.isReady()) { + toGenerate.add(chunk); return; - if (vision.isChunkVisible(chunk.getPosition())) + } + + if (vision.isChunkVisible(chunk.getPosition())) { return; + } + buffer.add(chunk.getPosition()); }); diff --git a/src/main/java/ru/windcorp/progressia/server/world/WorldLogic.java b/src/main/java/ru/windcorp/progressia/server/world/WorldLogic.java index 5931e34..4111646 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/WorldLogic.java +++ b/src/main/java/ru/windcorp/progressia/server/world/WorldLogic.java @@ -21,9 +21,10 @@ package ru.windcorp.progressia.server.world; import java.util.Collection; import java.util.HashMap; import java.util.Map; -import java.util.function.Function; +import glm.Glm; import glm.vec._3.i.Vec3i; +import ru.windcorp.progressia.common.util.crash.CrashReports; import ru.windcorp.progressia.common.world.ChunkData; import ru.windcorp.progressia.common.world.ChunkDataListeners; import ru.windcorp.progressia.common.world.WorldData; @@ -52,11 +53,11 @@ public class WorldLogic private final Evaluation tickEntitiesTask = new TickEntitiesTask(); - public WorldLogic(WorldData data, Server server, Function worldGeneratorConstructor) { + public WorldLogic(WorldData data, Server server, WorldGenerator generator) { this.data = data; this.server = server; - this.generator = worldGeneratorConstructor.apply(this); + this.generator = generator; data.setGravityModel(getGenerator().getGravityModel()); data.addListener(new WorldDataListener() { @@ -106,7 +107,38 @@ public class WorldLogic } public ChunkData generate(Vec3i chunkPos) { - return getGenerator().generate(chunkPos, getData()); + ChunkData chunk = getGenerator().generate(chunkPos); + + if (!Glm.equals(chunkPos, chunk.getPosition())) { + throw CrashReports.report(null, "Generator %s has generated a chunk at (%d; %d; %d) when requested to generate a chunk at (%d; %d; %d)", + getGenerator(), + chunk.getX(), chunk.getY(), chunk.getZ(), + chunkPos.x, chunkPos.y, chunkPos.z + ); + } + + if (getData().getChunk(chunk.getPosition()) != chunk) { + if (isChunkLoaded(chunkPos)) { + throw CrashReports.report(null, "Generator %s has returned a chunk different to the chunk that is located at (%d; %d; %d)", + getGenerator(), + chunkPos.x, chunkPos.y, chunkPos.z + ); + } else { + throw CrashReports.report(null, "Generator %s has returned a chunk that is not loaded when requested to generate a chunk at (%d; %d; %d)", + getGenerator(), + chunkPos.x, chunkPos.y, chunkPos.z + ); + } + } + + if (!getChunk(chunk).isReady()) { + throw CrashReports.report(null, "Generator %s has returned a chunk that is not ready when requested to generate a chunk at (%d; %d; %d)", + getGenerator(), + chunkPos.x, chunkPos.y, chunkPos.z + ); + } + + return chunk; } public ChunkLogic getChunk(ChunkData chunkData) { diff --git a/src/main/java/ru/windcorp/progressia/server/world/generation/AbstractWorldGenerator.java b/src/main/java/ru/windcorp/progressia/server/world/generation/AbstractWorldGenerator.java index 6856887..e765d85 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/generation/AbstractWorldGenerator.java +++ b/src/main/java/ru/windcorp/progressia/server/world/generation/AbstractWorldGenerator.java @@ -27,17 +27,23 @@ import ru.windcorp.progressia.common.world.ChunkData; import ru.windcorp.progressia.common.world.DecodingException; import ru.windcorp.progressia.common.world.GravityModel; import ru.windcorp.progressia.common.world.GravityModelRegistry; +import ru.windcorp.progressia.common.world.WorldData; +import ru.windcorp.progressia.server.Server; +import ru.windcorp.progressia.server.world.WorldLogic; public abstract class AbstractWorldGenerator extends WorldGenerator { private final Class hintClass; private final GravityModel gravityModel; + + private final Server server; - public AbstractWorldGenerator(String id, Class hintClass, String gravityModelId) { + public AbstractWorldGenerator(String id, Server server, Class hintClass, String gravityModelId) { super(id); this.hintClass = Objects.requireNonNull(hintClass, "hintClass"); this.gravityModel = GravityModelRegistry.getInstance().create(Objects.requireNonNull(gravityModelId, "gravityModelId")); + this.server = server; if (this.gravityModel == null) { throw new IllegalArgumentException("Gravity model with ID \"" + gravityModelId + "\" not found"); @@ -77,5 +83,20 @@ public abstract class AbstractWorldGenerator extends WorldGenerator { public GravityModel getGravityModel() { return gravityModel; } + + @Override + public Server getServer() { + return server; + } + + @Override + public WorldLogic getWorldLogic() { + return server.getWorld(); + } + + @Override + public WorldData getWorldData() { + return server.getWorld().getData(); + } } diff --git a/src/main/java/ru/windcorp/progressia/server/world/generation/WorldGenerator.java b/src/main/java/ru/windcorp/progressia/server/world/generation/WorldGenerator.java index f31cbc4..f05674d 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/generation/WorldGenerator.java +++ b/src/main/java/ru/windcorp/progressia/server/world/generation/WorldGenerator.java @@ -29,6 +29,8 @@ import ru.windcorp.progressia.common.world.ChunkData; import ru.windcorp.progressia.common.world.DecodingException; import ru.windcorp.progressia.common.world.GravityModel; import ru.windcorp.progressia.common.world.WorldData; +import ru.windcorp.progressia.server.Server; +import ru.windcorp.progressia.server.world.WorldLogic; public abstract class WorldGenerator extends Namespaced { @@ -37,7 +39,7 @@ public abstract class WorldGenerator extends Namespaced { // package-private constructor; extend AbstractWorldGeneration } - public abstract ChunkData generate(Vec3i chunkPos, WorldData world); + public abstract ChunkData generate(Vec3i chunkPos); public abstract Object readGenerationHint(DataInputStream input) throws IOException, DecodingException; @@ -48,5 +50,9 @@ public abstract class WorldGenerator extends Namespaced { public abstract GravityModel getGravityModel(); public abstract Vec3 suggestSpawnLocation(); + + public abstract Server getServer(); + public abstract WorldLogic getWorldLogic(); + public abstract WorldData getWorldData(); } diff --git a/src/main/java/ru/windcorp/progressia/test/gen/TestWorldGenerator.java b/src/main/java/ru/windcorp/progressia/test/gen/TestWorldGenerator.java index 8e0195a..e8c8641 100644 --- a/src/main/java/ru/windcorp/progressia/test/gen/TestWorldGenerator.java +++ b/src/main/java/ru/windcorp/progressia/test/gen/TestWorldGenerator.java @@ -37,18 +37,18 @@ import ru.windcorp.progressia.common.world.block.BlockDataRegistry; import ru.windcorp.progressia.common.world.rels.AbsFace; import ru.windcorp.progressia.common.world.tile.TileData; import ru.windcorp.progressia.common.world.tile.TileDataRegistry; -import ru.windcorp.progressia.server.world.WorldLogic; +import ru.windcorp.progressia.server.Server; import ru.windcorp.progressia.server.world.generation.AbstractWorldGenerator; public class TestWorldGenerator extends AbstractWorldGenerator { private final TestTerrainGenerator terrainGen; - public TestWorldGenerator(WorldLogic world) { - super("Test:WorldGenerator", Boolean.class, "Test:TheGravityModel"); - this.terrainGen = new TestTerrainGenerator(this, world); + public TestWorldGenerator(Server server) { + super("Test:WorldGenerator", server, Boolean.class, "Test:TheGravityModel"); + this.terrainGen = new TestTerrainGenerator(this, server.getWorld()); - world.getData().addListener(new WorldDataListener() { + getWorldData().addListener(new WorldDataListener() { @Override public void onChunkLoaded(WorldData world, ChunkData chunk) { findAndPopulate(chunk.getPosition(), world); @@ -77,9 +77,9 @@ public class TestWorldGenerator extends AbstractWorldGenerator { } @Override - public ChunkData generate(Vec3i chunkPos, WorldData world) { - ChunkData chunk = generateUnpopulated(chunkPos, world); - world.addChunk(chunk); + public ChunkData generate(Vec3i chunkPos) { + ChunkData chunk = generateUnpopulated(chunkPos, getWorldData()); + getWorldData().addChunk(chunk); return chunk; } diff --git a/src/main/java/ru/windcorp/progressia/test/gen/planet/PlanetTerrainGenerator.java b/src/main/java/ru/windcorp/progressia/test/gen/planet/PlanetTerrainGenerator.java index 5948b92..bd144a9 100644 --- a/src/main/java/ru/windcorp/progressia/test/gen/planet/PlanetTerrainGenerator.java +++ b/src/main/java/ru/windcorp/progressia/test/gen/planet/PlanetTerrainGenerator.java @@ -24,7 +24,6 @@ import ru.windcorp.progressia.common.util.FloatRangeMap; import ru.windcorp.progressia.common.util.VectorUtil; import ru.windcorp.progressia.common.world.ChunkData; import ru.windcorp.progressia.common.world.Coordinates; -import ru.windcorp.progressia.common.world.WorldData; import ru.windcorp.progressia.common.world.block.BlockData; import ru.windcorp.progressia.common.world.block.BlockDataRegistry; import ru.windcorp.progressia.test.gen.TerrainLayer; @@ -61,8 +60,8 @@ class PlanetTerrainGenerator { return parent; } - public ChunkData generateTerrain(Vec3i chunkPos, WorldData world) { - ChunkData chunk = new ChunkData(chunkPos, world); + public ChunkData generateTerrain(Vec3i chunkPos) { + ChunkData chunk = new ChunkData(chunkPos, getGenerator().getWorldData()); if (isOrdinaryChunk(chunkPos)) { generateOrdinaryTerrain(chunk); diff --git a/src/main/java/ru/windcorp/progressia/test/gen/planet/TestPlanetGenerator.java b/src/main/java/ru/windcorp/progressia/test/gen/planet/TestPlanetGenerator.java index 7206edc..82f0f55 100644 --- a/src/main/java/ru/windcorp/progressia/test/gen/planet/TestPlanetGenerator.java +++ b/src/main/java/ru/windcorp/progressia/test/gen/planet/TestPlanetGenerator.java @@ -26,24 +26,19 @@ import glm.vec._3.i.Vec3i; import ru.windcorp.progressia.common.util.VectorUtil; import ru.windcorp.progressia.common.world.ChunkData; import ru.windcorp.progressia.common.world.DecodingException; -import ru.windcorp.progressia.common.world.WorldData; import ru.windcorp.progressia.server.Server; -import ru.windcorp.progressia.server.world.WorldLogic; import ru.windcorp.progressia.server.world.generation.AbstractWorldGenerator; public class TestPlanetGenerator extends AbstractWorldGenerator { - private final Server server; - private final Planet planet; private final PlanetTerrainGenerator terrainGenerator; private final PlanetFeatureGenerator featureGenerator; - public TestPlanetGenerator(String id, Planet planet, WorldLogic world) { - super(id, Boolean.class, "Test:PlanetGravityModel"); + public TestPlanetGenerator(String id, Server server, Planet planet) { + super(id, server, Boolean.class, "Test:PlanetGravityModel"); - this.server = world.getServer(); this.planet = planet; TestPlanetGravityModel model = (TestPlanetGravityModel) this.getGravityModel(); @@ -81,9 +76,9 @@ public class TestPlanetGenerator extends AbstractWorldGenerator { } @Override - public ChunkData generate(Vec3i chunkPos, WorldData world) { - VectorUtil.iterateCuboidAround(chunkPos, 3, r -> conjureTerrain(r, world)); - ChunkData chunk = world.getChunk(chunkPos); + public ChunkData generate(Vec3i chunkPos) { + VectorUtil.iterateCuboidAround(chunkPos, 3, r -> conjureTerrain(r)); + ChunkData chunk = getWorldData().getChunk(chunkPos); if (!isChunkReady(chunk.getGenerationHint())) { featureGenerator.generateFeatures(chunk); @@ -92,17 +87,17 @@ public class TestPlanetGenerator extends AbstractWorldGenerator { return chunk; } - private void conjureTerrain(Vec3i chunkPos, WorldData world) { - ChunkData chunk = world.getChunk(chunkPos); + private void conjureTerrain(Vec3i chunkPos) { + ChunkData chunk = getWorldData().getChunk(chunkPos); if (chunk == null) { - server.getLoadManager().getChunkManager().loadChunk(chunkPos); - chunk = world.getChunk(chunkPos); + getServer().getLoadManager().getChunkManager().loadChunk(chunkPos); + chunk = getWorldData().getChunk(chunkPos); } if (chunk == null) { - chunk = terrainGenerator.generateTerrain(chunkPos, world); - world.addChunk(chunk); + chunk = terrainGenerator.generateTerrain(chunkPos); + getWorldData().addChunk(chunk); } } From 2532e80f6a56d9a1daa2fe5760003ccfb614e7b2 Mon Sep 17 00:00:00 2001 From: OLEGSHA Date: Mon, 5 Apr 2021 17:30:37 +0300 Subject: [PATCH 21/55] Moved some methods from ChunkData to GenericChunk - Moved some method definitions from ChunkData to GenericChunk - Moved some method definitions from ChunkData to GenericWritableChunk - Refactored GenericChunk including changing some method signatures - Added some documentation for GenericChunk --- .../client/world/ChunkRenderModel.java | 3 +- .../cro/ChunkRenderOptimizerSurface.java | 5 +- .../progressia/common/world/ChunkData.java | 61 +---- .../common/world/generic/GenericChunk.java | 236 ++++++++++-------- .../world/generic/GenericWritableChunk.java | 31 +++ .../progressia/common/world/generic/Util.java | 53 ++++ .../server/world/ChunkTickContext.java | 3 +- .../progressia/test/TestChunkCodec.java | 7 +- .../gen/planet/PlanetTerrainGenerator.java | 3 +- 9 files changed, 233 insertions(+), 169 deletions(-) create mode 100644 src/main/java/ru/windcorp/progressia/common/world/generic/GenericWritableChunk.java create mode 100644 src/main/java/ru/windcorp/progressia/common/world/generic/Util.java diff --git a/src/main/java/ru/windcorp/progressia/client/world/ChunkRenderModel.java b/src/main/java/ru/windcorp/progressia/client/world/ChunkRenderModel.java index 75857b8..46a3f28 100644 --- a/src/main/java/ru/windcorp/progressia/client/world/ChunkRenderModel.java +++ b/src/main/java/ru/windcorp/progressia/client/world/ChunkRenderModel.java @@ -36,6 +36,7 @@ import ru.windcorp.progressia.client.world.tile.TileRender; import ru.windcorp.progressia.client.world.tile.TileRenderNone; import ru.windcorp.progressia.client.world.tile.TileRenderStack; import ru.windcorp.progressia.common.world.ChunkData; +import ru.windcorp.progressia.common.world.generic.GenericChunk; import ru.windcorp.progressia.common.world.rels.AxisRotations; import ru.windcorp.progressia.common.world.rels.RelFace; @@ -76,7 +77,7 @@ public class ChunkRenderModel implements Renderable { optimizers.forEach(ChunkRenderOptimizer::startRender); - chunk.forEachBiC(relBlockInChunk -> { + GenericChunk.forEachBiC(relBlockInChunk -> { processBlockAndTiles(relBlockInChunk, sink); }); diff --git a/src/main/java/ru/windcorp/progressia/client/world/cro/ChunkRenderOptimizerSurface.java b/src/main/java/ru/windcorp/progressia/client/world/cro/ChunkRenderOptimizerSurface.java index f30b91c..5ede1ef 100644 --- a/src/main/java/ru/windcorp/progressia/client/world/cro/ChunkRenderOptimizerSurface.java +++ b/src/main/java/ru/windcorp/progressia/client/world/cro/ChunkRenderOptimizerSurface.java @@ -38,6 +38,7 @@ import ru.windcorp.progressia.client.world.block.BlockRender; import ru.windcorp.progressia.client.world.tile.TileRender; import ru.windcorp.progressia.common.util.Vectors; import ru.windcorp.progressia.common.world.ChunkData; +import ru.windcorp.progressia.common.world.generic.GenericChunk; import ru.windcorp.progressia.common.world.rels.RelFace; public class ChunkRenderOptimizerSurface extends ChunkRenderOptimizer { @@ -216,7 +217,7 @@ public class ChunkRenderOptimizerSurface extends ChunkRenderOptimizer { Consumer consumer = shapeParts::add; - chunk.forEachBiC(relBlockInChunk -> { + GenericChunk.forEachBiC(relBlockInChunk -> { processInnerFaces(relBlockInChunk, consumer); processOuterFaces(relBlockInChunk, consumer); }); @@ -315,7 +316,7 @@ public class ChunkRenderOptimizerSurface extends ChunkRenderOptimizer { } private boolean shouldRenderWhenFacing(Vec3i relBlockInChunk, RelFace face) { - if (chunk.containsBiC(relBlockInChunk)) { + if (GenericChunk.containsBiC(relBlockInChunk)) { return shouldRenderWhenFacingLocal(relBlockInChunk, face); } else { return shouldRenderWhenFacingNeighbor(relBlockInChunk, face); diff --git a/src/main/java/ru/windcorp/progressia/common/world/ChunkData.java b/src/main/java/ru/windcorp/progressia/common/world/ChunkData.java index 5788053..54b922d 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/ChunkData.java +++ b/src/main/java/ru/windcorp/progressia/common/world/ChunkData.java @@ -25,14 +25,13 @@ import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.Objects; -import java.util.function.BiConsumer; -import java.util.function.Consumer; 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.world.block.BlockData; import ru.windcorp.progressia.common.world.generic.GenericChunk; +import ru.windcorp.progressia.common.world.generic.GenericWritableChunk; import ru.windcorp.progressia.common.world.rels.AbsFace; import ru.windcorp.progressia.common.world.rels.BlockFace; import ru.windcorp.progressia.common.world.rels.RelFace; @@ -42,7 +41,7 @@ import ru.windcorp.progressia.common.world.tile.TileReference; import ru.windcorp.progressia.common.world.tile.TileStackIsFullException; public class ChunkData - implements GenericChunk { + implements GenericWritableChunk { public static final int BLOCKS_PER_CHUNK = Coordinates.CHUNK_SIZE; public static final int CHUNK_RADIUS = BLOCKS_PER_CHUNK / 2; @@ -83,6 +82,7 @@ public class ChunkData return blocks[getBlockIndex(posInChunk)]; } + @Override public void setBlock(Vec3i posInChunk, BlockData block, boolean notify) { BlockData previous = blocks[getBlockIndex(posInChunk)]; blocks[getBlockIndex(posInChunk)] = block; @@ -95,6 +95,7 @@ public class ChunkData } } + @Override public void setBlockRel(Vec3i relativeBlockInChunk, BlockData block, boolean notify) { Vec3i absoluteBlockInChunk = Vectors.grab3i(); resolve(relativeBlockInChunk, absoluteBlockInChunk); @@ -168,7 +169,7 @@ public class ChunkData } private static void checkLocalCoordinates(Vec3i posInChunk) { - if (!isInBounds(posInChunk)) { + if (!GenericChunk.containsBiC(posInChunk)) { throw new IllegalCoordinatesException( "Coordinates (" + posInChunk.x + "; " + posInChunk.y + "; " + posInChunk.z + ") " + "are not legal chunk coordinates" @@ -176,56 +177,6 @@ public class ChunkData } } - public static boolean isInBounds(Vec3i posInChunk) { - return posInChunk.x >= 0 && posInChunk.x < BLOCKS_PER_CHUNK && - posInChunk.y >= 0 && posInChunk.y < BLOCKS_PER_CHUNK && - posInChunk.z >= 0 && posInChunk.z < BLOCKS_PER_CHUNK; - } - - public boolean isBorder(Vec3i blockInChunk, BlockFace face) { - final int min = 0, max = BLOCKS_PER_CHUNK - 1; - AbsFace absFace = face.resolve(getUp()); - return (blockInChunk.x == min && absFace == AbsFace.NEG_X) || - (blockInChunk.x == max && absFace == AbsFace.POS_X) || - (blockInChunk.y == min && absFace == AbsFace.NEG_Y) || - (blockInChunk.y == max && absFace == AbsFace.POS_Y) || - (blockInChunk.z == min && absFace == AbsFace.NEG_Z) || - (blockInChunk.z == max && absFace == AbsFace.POS_Z); - } - - public void forEachBlock(Consumer action) { - VectorUtil.iterateCuboid( - 0, - 0, - 0, - BLOCKS_PER_CHUNK, - BLOCKS_PER_CHUNK, - BLOCKS_PER_CHUNK, - action - ); - } - - public void forEachTileStack(Consumer action) { - forEachBlock(blockInChunk -> { - for (AbsFace face : AbsFace.getFaces()) { - TileDataStack stack = getTilesOrNull(blockInChunk, face); - if (stack == null) - continue; - action.accept(stack); - } - }); - } - - /** - * Iterates over all tiles in this chunk. - * - * @param action the action to perform. {@code TileLocation} refers to each - * tile using its primary block - */ - public void forEachTile(BiConsumer action) { - forEachTileStack(stack -> stack.forEach(tileData -> action.accept(stack, tileData))); - } - public WorldData getWorld() { return world; } diff --git a/src/main/java/ru/windcorp/progressia/common/world/generic/GenericChunk.java b/src/main/java/ru/windcorp/progressia/common/world/generic/GenericChunk.java index fa80269..e51ac02 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/generic/GenericChunk.java +++ b/src/main/java/ru/windcorp/progressia/common/world/generic/GenericChunk.java @@ -15,9 +15,10 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.common.world.generic; +import java.util.function.BiConsumer; import java.util.function.Consumer; import glm.Glm; @@ -29,37 +30,90 @@ import ru.windcorp.progressia.common.world.rels.AbsFace; import ru.windcorp.progressia.common.world.rels.AxisRotations; import ru.windcorp.progressia.common.world.rels.BlockFace; +/** + * An unmodifiable chunk representation. Per default, it is usually one of + * {@link ru.windcorp.progressia.common.world.ChunkData ChunkData}, + * {@link ru.windcorp.progressia.client.world.ChunkRender ChunkRender} or + * {@link ru.windcorp.progressia.server.world.ChunkLogic ChunkLogic}, but this + * interface may be implemented differently for various reasons. + *

    + * A generic chunk contains {@linkplain GenericBlock blocks} and + * {@linkplain GenericTileStack tile stacks} and is characterized by its + * location. It also bears a discrete up direction. Note that no + * {@linkplain GenericWorld world} object is directly accessible through this + * interface. + *

    + * This interface defines the most common methods for examining a chunk and + * implements many of them as default methods. It also contains several static + * methods useful when dealing with chunks. {@code GenericChunk} does not + * provide a way to modify a chunk; use {@link GenericWritableChunk} methods + * when applicable. + * + * @param a reference to itself (required to properly reference a + * {@link GenericTileStack}) + * @param block type + * @param tile type + * @param tile stack type + * @author javapony + */ public interface GenericChunk, B extends GenericBlock, T extends GenericTile, TS extends GenericTileStack> { + /** + * The count of blocks in a side of a chunk. This is guaranteed to be a + * power of two. This is always equal to {@link Coordinates#CHUNK_SIZE}. + */ public static final int BLOCKS_PER_CHUNK = Coordinates.CHUNK_SIZE; + /* + * Abstract methods + */ + + /** + * Returns the position of this chunk in {@linkplain Coordinates#chunk + * coordinates of chunk}. The returned object must not be modified. + * + * @return this chunk's position + */ Vec3i getPosition(); - + + /** + * Returns the discrete up direction for this chunk. + * + * @return this chunk's discrete up direction + */ AbsFace getUp(); + /** + * Retrieves the block at the location specified by its + * {@linkplain Coordinates#blockInChunk chunk coordinates}. During chunk + * generation it may be {@code null}. + * + * @param blockInChunk local coordinates of the block to fetch + * @return the block at the requested location or {@code null}. + */ B getBlock(Vec3i blockInChunk); TS getTiles(Vec3i blockInChunk, BlockFace face); boolean hasTiles(Vec3i blockInChunk, BlockFace face); - + default Vec3i resolve(Vec3i relativeBlockInChunk, Vec3i output) { if (output == null) { output = new Vec3i(); } - + final int offset = BLOCKS_PER_CHUNK - 1; - + output.set(relativeBlockInChunk.x, relativeBlockInChunk.y, relativeBlockInChunk.z); output.mul(2).sub(offset); - + AxisRotations.resolve(output, getUp(), output); - + output.add(offset).div(2); - + return output; } - + default B getBlockRel(Vec3i relativeBlockInChunk) { Vec3i absoluteBlockInChunk = Vectors.grab3i(); resolve(relativeBlockInChunk, absoluteBlockInChunk); @@ -67,7 +121,7 @@ public interface GenericChunk, B exten Vectors.release(absoluteBlockInChunk); return result; } - + default TS getTilesRel(Vec3i relativeBlockInChunk, BlockFace face) { Vec3i absoluteBlockInChunk = Vectors.grab3i(); resolve(relativeBlockInChunk, absoluteBlockInChunk); @@ -75,7 +129,7 @@ public interface GenericChunk, B exten Vectors.release(absoluteBlockInChunk); return result; } - + default boolean hasTilesRel(Vec3i relativeBlockInChunk, BlockFace face) { Vec3i absoluteBlockInChunk = Vectors.grab3i(); resolve(relativeBlockInChunk, absoluteBlockInChunk); @@ -83,7 +137,7 @@ public interface GenericChunk, B exten Vectors.release(absoluteBlockInChunk); return result; } - + default int getX() { return getPosition().x; } @@ -119,150 +173,100 @@ public interface GenericChunk, B exten default int getMaxZ() { return Coordinates.getInWorld(getZ(), BLOCKS_PER_CHUNK - 1); } - + default Vec3i getMinBIW(Vec3i output) { if (output == null) { output = new Vec3i(); } - + output.set(getMinX(), getMinY(), getMinZ()); - + return output; } - + default Vec3i getMaxBIW(Vec3i output) { if (output == null) { output = new Vec3i(); } - + output.set(getMaxX(), getMaxY(), getMaxZ()); - + return output; } - + default Vec3i getMinBIWRel(Vec3i output) { if (output == null) { output = new Vec3i(); } - + Vec3i absMin = getMinBIW(Vectors.grab3i()); Vec3i absMax = getMaxBIW(Vectors.grab3i()); - + AxisRotations.relativize(absMin, getUp(), absMin); AxisRotations.relativize(absMax, getUp(), absMax); - + Glm.min(absMin, absMax, output); - + Vectors.release(absMax); Vectors.release(absMin); - + return output; } - + default Vec3i getMaxBIWRel(Vec3i output) { if (output == null) { output = new Vec3i(); } - + Vec3i absMin = getMinBIW(Vectors.grab3i()); Vec3i absMax = getMaxBIW(Vectors.grab3i()); - + AxisRotations.relativize(absMin, getUp(), absMin); AxisRotations.relativize(absMax, getUp(), absMax); - + Glm.max(absMin, absMax, output); - + Vectors.release(absMax); Vectors.release(absMin); - + return output; } - default boolean containsBiC(Vec3i blockInChunk) { + public static boolean containsBiC(Vec3i blockInChunk) { return blockInChunk.x >= 0 && blockInChunk.x < BLOCKS_PER_CHUNK && blockInChunk.y >= 0 && blockInChunk.y < BLOCKS_PER_CHUNK && blockInChunk.z >= 0 && blockInChunk.z < BLOCKS_PER_CHUNK; } + public static boolean isSurfaceBiC(Vec3i blockInChunk) { + return Util.getBorderHits(blockInChunk) >= 1; + } + + public static boolean isEdgeBiC(Vec3i blockInChunk) { + return Util.getBorderHits(blockInChunk) >= 2; + } + + public static boolean isVertexBiC(Vec3i blockInChunk) { + return Util.getBorderHits(blockInChunk) == 3; + } + default boolean containsBiW(Vec3i blockInWorld) { - Vec3i v = Vectors.grab3i(); - - v = Coordinates.getInWorld(getPosition(), Vectors.ZERO_3i, v); - v = blockInWorld.sub(v, v); - - boolean result = containsBiC(v); - - Vectors.release(v); - return result; + return Util.testBiC(blockInWorld, this, GenericChunk::containsBiC); } - - default boolean isSurfaceBiC(Vec3i blockInChunk) { - int hits = 0; - - if (Coordinates.isOnChunkBorder(blockInChunk.x)) hits++; - if (Coordinates.isOnChunkBorder(blockInChunk.y)) hits++; - if (Coordinates.isOnChunkBorder(blockInChunk.z)) hits++; - - return hits >= 1; - } - + default boolean isSurfaceBiW(Vec3i blockInWorld) { - Vec3i v = Vectors.grab3i(); - - v = Coordinates.getInWorld(getPosition(), Vectors.ZERO_3i, v); - v = blockInWorld.sub(v, v); - - boolean result = isSurfaceBiC(v); - - Vectors.release(v); - return result; + return Util.testBiC(blockInWorld, this, GenericChunk::isSurfaceBiC); } - - default boolean isEdgeBiC(Vec3i blockInChunk) { - int hits = 0; - - if (Coordinates.isOnChunkBorder(blockInChunk.x)) hits++; - if (Coordinates.isOnChunkBorder(blockInChunk.y)) hits++; - if (Coordinates.isOnChunkBorder(blockInChunk.z)) hits++; - - return hits >= 2; - } - + default boolean isEdgeBiW(Vec3i blockInWorld) { - Vec3i v = Vectors.grab3i(); - - v = Coordinates.getInWorld(getPosition(), Vectors.ZERO_3i, v); - v = blockInWorld.sub(v, v); - - boolean result = isEdgeBiC(v); - - Vectors.release(v); - return result; + return Util.testBiC(blockInWorld, this, GenericChunk::isEdgeBiC); } - - default boolean isVertexBiC(Vec3i blockInChunk) { - int hits = 0; - - if (Coordinates.isOnChunkBorder(blockInChunk.x)) hits++; - if (Coordinates.isOnChunkBorder(blockInChunk.y)) hits++; - if (Coordinates.isOnChunkBorder(blockInChunk.z)) hits++; - - return hits == 3; - } - + default boolean isVertexBiW(Vec3i blockInWorld) { - Vec3i v = Vectors.grab3i(); - - v = Coordinates.getInWorld(getPosition(), Vectors.ZERO_3i, v); - v = blockInWorld.sub(v, v); - - boolean result = isVertexBiC(v); - - Vectors.release(v); - return result; + return Util.testBiC(blockInWorld, this, GenericChunk::isVertexBiC); } - default void forEachBiC(Consumer action) { + public static void forEachBiC(Consumer action) { VectorUtil.iterateCuboid( 0, 0, @@ -293,22 +297,42 @@ public interface GenericChunk, B exten return null; } - + default TS getTilesOrNullRel(Vec3i relativeBlockInChunk, BlockFace face) { Vec3i absoluteBlockInChunk = Vectors.grab3i(); resolve(relativeBlockInChunk, absoluteBlockInChunk); - + TS result; - + if (hasTiles(absoluteBlockInChunk, face)) { result = getTiles(absoluteBlockInChunk, face); } else { result = null; } - + Vectors.release(absoluteBlockInChunk); - + return result; } + default void forEachTileStack(Consumer action) { + forEachBiC(blockInChunk -> { + for (AbsFace face : AbsFace.getFaces()) { + TS stack = getTilesOrNull(blockInChunk, face); + if (stack == null) + continue; + action.accept(stack); + } + }); + } + + /** + * Iterates over all tiles in this chunk. + * + * @param action the action to perform + */ + default void forEachTile(BiConsumer action) { + forEachTileStack(stack -> stack.forEach(tileData -> action.accept(stack, tileData))); + } + } diff --git a/src/main/java/ru/windcorp/progressia/common/world/generic/GenericWritableChunk.java b/src/main/java/ru/windcorp/progressia/common/world/generic/GenericWritableChunk.java new file mode 100644 index 0000000..9dc1557 --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/common/world/generic/GenericWritableChunk.java @@ -0,0 +1,31 @@ +/* + * 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.common.world.generic; + +import glm.vec._3.i.Vec3i; + +import ru.windcorp.progressia.common.world.block.BlockData; + +public interface GenericWritableChunk, B extends GenericBlock, T extends GenericTile, TS extends GenericTileStack> + extends GenericChunk { + + void setBlock(Vec3i posInChunk, BlockData block, boolean notify); + + void setBlockRel(Vec3i relativeBlockInChunk, B block, boolean notify); + +} diff --git a/src/main/java/ru/windcorp/progressia/common/world/generic/Util.java b/src/main/java/ru/windcorp/progressia/common/world/generic/Util.java new file mode 100644 index 0000000..8f6f79f --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/common/world/generic/Util.java @@ -0,0 +1,53 @@ +/* + * 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.common.world.generic; + +import java.util.function.Predicate; + +import glm.vec._3.i.Vec3i; +import ru.windcorp.progressia.common.util.Vectors; +import ru.windcorp.progressia.common.world.Coordinates; + +class Util { + + public static int getBorderHits(Vec3i blockInChunk) { + int hits = 0; + + if (Coordinates.isOnChunkBorder(blockInChunk.x)) hits++; + if (Coordinates.isOnChunkBorder(blockInChunk.y)) hits++; + if (Coordinates.isOnChunkBorder(blockInChunk.z)) hits++; + + return hits; + } + + public static boolean testBiC(Vec3i blockInWorld, GenericChunk chunk, Predicate test) { + Vec3i v = Vectors.grab3i(); + + v = Coordinates.getInWorld(chunk.getPosition(), Vectors.ZERO_3i, v); + v = blockInWorld.sub(v, v); + + boolean result = test.test(v); + + Vectors.release(v); + + return result; + } + + + +} diff --git a/src/main/java/ru/windcorp/progressia/server/world/ChunkTickContext.java b/src/main/java/ru/windcorp/progressia/server/world/ChunkTickContext.java index d32503d..0480a6e 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/ChunkTickContext.java +++ b/src/main/java/ru/windcorp/progressia/server/world/ChunkTickContext.java @@ -22,6 +22,7 @@ import java.util.function.Consumer; import glm.vec._3.i.Vec3i; import ru.windcorp.progressia.common.world.ChunkData; +import ru.windcorp.progressia.common.world.generic.GenericChunk; import ru.windcorp.progressia.common.world.rels.AbsFace; import ru.windcorp.progressia.server.world.block.BlockTickContext; @@ -45,7 +46,7 @@ public interface ChunkTickContext extends TickContext { default void forEachBlock(Consumer action) { TickContextMutable context = TickContextMutable.uninitialized(); - getChunkData().forEachBlock(blockInChunk -> { + GenericChunk.forEachBiC(blockInChunk -> { context.rebuild().withServer(getServer()).withChunk(getChunk()).withBlockInChunk(blockInChunk).build(); action.accept(context); }); diff --git a/src/main/java/ru/windcorp/progressia/test/TestChunkCodec.java b/src/main/java/ru/windcorp/progressia/test/TestChunkCodec.java index 9e94d64..050b94e 100644 --- a/src/main/java/ru/windcorp/progressia/test/TestChunkCodec.java +++ b/src/main/java/ru/windcorp/progressia/test/TestChunkCodec.java @@ -38,6 +38,7 @@ import ru.windcorp.progressia.common.world.DecodingException; import ru.windcorp.progressia.common.world.WorldData; import ru.windcorp.progressia.common.world.block.BlockData; import ru.windcorp.progressia.common.world.block.BlockDataRegistry; +import ru.windcorp.progressia.common.world.generic.GenericChunk; import ru.windcorp.progressia.common.world.io.ChunkCodec; import ru.windcorp.progressia.common.world.rels.RelFace; import ru.windcorp.progressia.common.world.tile.TileData; @@ -124,7 +125,7 @@ public class TestChunkCodec extends ChunkCodec { private void readBlocks(DataInput input, BlockData[] blockPalette, ChunkData chunk) throws IOException { try { - chunk.forEachBiC(guard(v -> { + GenericChunk.forEachBiC(guard(v -> { chunk.setBlock(v, blockPalette[input.readInt()], false); })); } catch (UncheckedIOException e) { @@ -171,7 +172,7 @@ public class TestChunkCodec extends ChunkCodec { private Palette createBlockPalette(ChunkData chunk) { Palette blockPalette = new Palette<>(); - chunk.forEachBiC(v -> blockPalette.add(chunk.getBlock(v))); + GenericChunk.forEachBiC(v -> blockPalette.add(chunk.getBlock(v))); return blockPalette; } @@ -199,7 +200,7 @@ public class TestChunkCodec extends ChunkCodec { private void writeBlocks(ChunkData chunk, Palette blockPalette, DataOutput output) throws IOException { try { - chunk.forEachBiC(guard(v -> { + GenericChunk.forEachBiC(guard(v -> { output.writeInt(blockPalette.getNid(chunk.getBlock(v))); })); } catch (UncheckedIOException e) { diff --git a/src/main/java/ru/windcorp/progressia/test/gen/planet/PlanetTerrainGenerator.java b/src/main/java/ru/windcorp/progressia/test/gen/planet/PlanetTerrainGenerator.java index bd144a9..a5b086f 100644 --- a/src/main/java/ru/windcorp/progressia/test/gen/planet/PlanetTerrainGenerator.java +++ b/src/main/java/ru/windcorp/progressia/test/gen/planet/PlanetTerrainGenerator.java @@ -26,6 +26,7 @@ import ru.windcorp.progressia.common.world.ChunkData; import ru.windcorp.progressia.common.world.Coordinates; import ru.windcorp.progressia.common.world.block.BlockData; import ru.windcorp.progressia.common.world.block.BlockDataRegistry; +import ru.windcorp.progressia.common.world.generic.GenericChunk; import ru.windcorp.progressia.test.gen.TerrainLayer; import ru.windcorp.progressia.test.gen.surface.SurfaceFloatField; import ru.windcorp.progressia.test.gen.surface.SurfaceTerrainGenerator; @@ -89,7 +90,7 @@ class PlanetTerrainGenerator { Vec3 biw = new Vec3(); - chunk.forEachBiC(bic -> { + GenericChunk.forEachBiC(bic -> { biw.set( Coordinates.getInWorld(chunk.getX(), bic.x), From e0a03cad1d2725a086178e780da9ae8bc0ac229f Mon Sep 17 00:00:00 2001 From: OLEGSHA Date: Tue, 6 Apr 2021 00:36:38 +0300 Subject: [PATCH 22/55] More refactoring of GenericChunk and pals - Genericized TileReference - Unified template arguments --- .../progressia/client/world/ChunkRender.java | 41 ++++- .../progressia/client/world/WorldRender.java | 3 +- .../world/tile/TileRenderReference.java | 27 +++ .../client/world/tile/TileRenderStack.java | 3 +- .../progressia/common/world/ChunkData.java | 16 +- .../progressia/common/world/WorldData.java | 3 +- .../common/world/generic/ChunkMap.java | 16 +- .../common/world/generic/ChunkMaps.java | 16 +- .../common/world/generic/ChunkSet.java | 18 +- .../common/world/generic/ChunkSets.java | 18 +- .../common/world/generic/GenericChunk.java | 10 +- .../world/generic/GenericTileReference.java | 41 +++++ .../world/generic/GenericTileStack.java | 22 ++- .../common/world/generic/GenericWorld.java | 11 +- .../world/generic/GenericWritableChunk.java | 16 +- .../generic/GenericWritableTileStack.java | 160 ++++++++++++++++++ .../world/generic/LongBasedChunkSet.java | 2 +- .../progressia/common/world/generic/Util.java | 2 +- ...eReference.java => TileDataReference.java} | 14 +- .../common/world/tile/TileDataStack.java | 142 +--------------- .../progressia/server/world/ChunkLogic.java | 46 ++++- .../server/world/TickContextMutable.java | 8 +- .../progressia/server/world/WorldLogic.java | 3 +- .../server/world/tile/TileLogicReference.java | 27 +++ .../server/world/tile/TileLogicStack.java | 3 +- .../server/world/tile/TileTickContext.java | 4 +- 26 files changed, 452 insertions(+), 220 deletions(-) create mode 100644 src/main/java/ru/windcorp/progressia/client/world/tile/TileRenderReference.java create mode 100644 src/main/java/ru/windcorp/progressia/common/world/generic/GenericTileReference.java create mode 100644 src/main/java/ru/windcorp/progressia/common/world/generic/GenericWritableTileStack.java rename src/main/java/ru/windcorp/progressia/common/world/tile/{TileReference.java => TileDataReference.java} (71%) create mode 100644 src/main/java/ru/windcorp/progressia/server/world/tile/TileLogicReference.java diff --git a/src/main/java/ru/windcorp/progressia/client/world/ChunkRender.java b/src/main/java/ru/windcorp/progressia/client/world/ChunkRender.java index ca58bf7..c69fcf3 100644 --- a/src/main/java/ru/windcorp/progressia/client/world/ChunkRender.java +++ b/src/main/java/ru/windcorp/progressia/client/world/ChunkRender.java @@ -27,6 +27,7 @@ import ru.windcorp.progressia.client.graphics.model.ShapeRenderHelper; import ru.windcorp.progressia.client.world.block.BlockRender; import ru.windcorp.progressia.client.world.block.BlockRenderRegistry; import ru.windcorp.progressia.client.world.tile.TileRender; +import ru.windcorp.progressia.client.world.tile.TileRenderReference; import ru.windcorp.progressia.client.world.tile.TileRenderRegistry; import ru.windcorp.progressia.client.world.tile.TileRenderStack; import ru.windcorp.progressia.common.world.ChunkData; @@ -34,10 +35,11 @@ import ru.windcorp.progressia.common.world.generic.GenericChunk; import ru.windcorp.progressia.common.world.rels.AbsFace; import ru.windcorp.progressia.common.world.rels.BlockFace; import ru.windcorp.progressia.common.world.rels.RelFace; +import ru.windcorp.progressia.common.world.tile.TileDataReference; import ru.windcorp.progressia.common.world.tile.TileDataStack; public class ChunkRender - implements GenericChunk { + implements GenericChunk { private final WorldRender world; private final ChunkData data; @@ -108,6 +110,28 @@ public class ChunkRender } private class TileRenderStackImpl extends TileRenderStack { + private class TileRenderReferenceImpl implements TileRenderReference { + private final TileDataReference parent; + + public TileRenderReferenceImpl(TileDataReference parent) { + this.parent = parent; + } + + @Override + public TileRender get() { + return TileRenderRegistry.getInstance().get(parent.get().getId()); + } + + @Override + public int getIndex() { + return parent.getIndex(); + } + + @Override + public TileRenderStack getStack() { + return TileRenderStackImpl.this; + } + } private final TileDataStack parent; @@ -129,6 +153,21 @@ public class ChunkRender public RelFace getFace() { return parent.getFace(); } + + @Override + public TileRenderReference getReference(int index) { + return new TileRenderReferenceImpl(parent.getReference(index)); + } + + @Override + public int getIndexByTag(int tag) { + return parent.getIndexByTag(tag); + } + + @Override + public int getTagByIndex(int index) { + return parent.getTagByIndex(index); + } @Override public TileRender get(int index) { diff --git a/src/main/java/ru/windcorp/progressia/client/world/WorldRender.java b/src/main/java/ru/windcorp/progressia/client/world/WorldRender.java index 8be08c2..2e674f0 100644 --- a/src/main/java/ru/windcorp/progressia/client/world/WorldRender.java +++ b/src/main/java/ru/windcorp/progressia/client/world/WorldRender.java @@ -34,6 +34,7 @@ import ru.windcorp.progressia.client.world.block.BlockRender; import ru.windcorp.progressia.client.world.entity.EntityRenderRegistry; import ru.windcorp.progressia.client.world.entity.EntityRenderable; import ru.windcorp.progressia.client.world.tile.TileRender; +import ru.windcorp.progressia.client.world.tile.TileRenderReference; import ru.windcorp.progressia.client.world.tile.TileRenderStack; import ru.windcorp.progressia.common.util.VectorUtil; import ru.windcorp.progressia.common.util.Vectors; @@ -47,7 +48,7 @@ import ru.windcorp.progressia.common.world.generic.ChunkSets; import ru.windcorp.progressia.common.world.generic.GenericWorld; public class WorldRender - implements GenericWorld { + implements GenericWorld { private final WorldData data; private final Client client; diff --git a/src/main/java/ru/windcorp/progressia/client/world/tile/TileRenderReference.java b/src/main/java/ru/windcorp/progressia/client/world/tile/TileRenderReference.java new file mode 100644 index 0000000..3def556 --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/client/world/tile/TileRenderReference.java @@ -0,0 +1,27 @@ +/* + * 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.client.world.tile; + +import ru.windcorp.progressia.client.world.ChunkRender; +import ru.windcorp.progressia.client.world.block.BlockRender; +import ru.windcorp.progressia.common.world.generic.GenericTileReference; + +public interface TileRenderReference + extends GenericTileReference { + +} diff --git a/src/main/java/ru/windcorp/progressia/client/world/tile/TileRenderStack.java b/src/main/java/ru/windcorp/progressia/client/world/tile/TileRenderStack.java index 6bb8fb0..ca95cd2 100644 --- a/src/main/java/ru/windcorp/progressia/client/world/tile/TileRenderStack.java +++ b/src/main/java/ru/windcorp/progressia/client/world/tile/TileRenderStack.java @@ -19,11 +19,12 @@ package ru.windcorp.progressia.client.world.tile; import ru.windcorp.progressia.client.world.ChunkRender; +import ru.windcorp.progressia.client.world.block.BlockRender; import ru.windcorp.progressia.common.world.generic.GenericTileStack; import ru.windcorp.progressia.common.world.tile.TileDataStack; public abstract class TileRenderStack - extends GenericTileStack { + extends GenericTileStack { public abstract TileDataStack getData(); diff --git a/src/main/java/ru/windcorp/progressia/common/world/ChunkData.java b/src/main/java/ru/windcorp/progressia/common/world/ChunkData.java index 54b922d..9a00e25 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/ChunkData.java +++ b/src/main/java/ru/windcorp/progressia/common/world/ChunkData.java @@ -36,12 +36,12 @@ import ru.windcorp.progressia.common.world.rels.AbsFace; import ru.windcorp.progressia.common.world.rels.BlockFace; import ru.windcorp.progressia.common.world.rels.RelFace; import ru.windcorp.progressia.common.world.tile.TileData; +import ru.windcorp.progressia.common.world.tile.TileDataReference; import ru.windcorp.progressia.common.world.tile.TileDataStack; -import ru.windcorp.progressia.common.world.tile.TileReference; import ru.windcorp.progressia.common.world.tile.TileStackIsFullException; public class ChunkData - implements GenericWritableChunk { + implements GenericWritableChunk { public static final int BLOCKS_PER_CHUNK = Coordinates.CHUNK_SIZE; public static final int CHUNK_RADIUS = BLOCKS_PER_CHUNK / 2; @@ -219,10 +219,10 @@ public class ChunkData * @author javapony */ private class TileDataStackImpl extends TileDataStack { - private class TileReferenceImpl implements TileReference { + private class TileDataReferenceImpl implements TileDataReference { private int index; - public TileReferenceImpl(int index) { + public TileDataReferenceImpl(int index) { this.index = index; } @@ -264,7 +264,7 @@ public class ChunkData private final TileData[] tiles = new TileData[TILES_PER_FACE]; private int size = 0; - private final TileReferenceImpl[] references = new TileReferenceImpl[tiles.length]; + private final TileDataReferenceImpl[] references = new TileDataReferenceImpl[tiles.length]; private final int[] indicesByTag = new int[tiles.length]; private final int[] tagsByIndex = new int[tiles.length]; @@ -437,11 +437,11 @@ public class ChunkData } @Override - public TileReference getReference(int index) { + public TileDataReference getReference(int index) { checkIndex(index, false); if (references[index] == null) { - references[index] = new TileReferenceImpl(index); + references[index] = new TileDataReferenceImpl(index); } return references[index]; @@ -500,7 +500,7 @@ public class ChunkData throw new AssertionError("get(index) is null"); if (references[index] != null) { - TileReference ref = getReference(index); + TileDataReference ref = getReference(index); if (ref == null) throw new AssertionError("references[index] is not null but getReference(index) is"); if (!ref.isValid()) diff --git a/src/main/java/ru/windcorp/progressia/common/world/WorldData.java b/src/main/java/ru/windcorp/progressia/common/world/WorldData.java index 625b8c2..7fec468 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/WorldData.java +++ b/src/main/java/ru/windcorp/progressia/common/world/WorldData.java @@ -38,9 +38,10 @@ import ru.windcorp.progressia.common.world.generic.GenericWorld; import ru.windcorp.progressia.common.world.generic.LongBasedChunkMap; import ru.windcorp.progressia.common.world.tile.TileData; import ru.windcorp.progressia.common.world.tile.TileDataStack; +import ru.windcorp.progressia.common.world.tile.TileDataReference; public class WorldData - implements GenericWorld { + implements GenericWorld { private final ChunkMap chunksByPos = new LongBasedChunkMap<>( TCollections.synchronizedMap(new TLongObjectHashMap<>()) diff --git a/src/main/java/ru/windcorp/progressia/common/world/generic/ChunkMap.java b/src/main/java/ru/windcorp/progressia/common/world/generic/ChunkMap.java index 6c35781..5b4f6f6 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/generic/ChunkMap.java +++ b/src/main/java/ru/windcorp/progressia/common/world/generic/ChunkMap.java @@ -77,27 +77,27 @@ public interface ChunkMap { // TODO implement (int, int, int) and GenericChunk versions of all of the // above - default boolean containsChunk(GenericChunk chunk) { + default boolean containsChunk(GenericChunk chunk) { return containsKey(chunk.getPosition()); } - default V get(GenericChunk chunk) { + default V get(GenericChunk chunk) { return get(chunk.getPosition()); } - default V put(GenericChunk chunk, V obj) { + default V put(GenericChunk chunk, V obj) { return put(chunk.getPosition(), obj); } - default V remove(GenericChunk chunk) { + default V remove(GenericChunk chunk) { return remove(chunk.getPosition()); } - default V getOrDefault(GenericChunk chunk, V def) { + default V getOrDefault(GenericChunk chunk, V def) { return containsChunk(chunk) ? def : get(chunk); } - default > V compute( + default > V compute( C chunk, BiFunction remappingFunction ) { @@ -128,8 +128,8 @@ public interface ChunkMap { void forEach(BiConsumer action); - default > void forEachIn( - GenericWorld world, + default > void forEachIn( + GenericWorld world, BiConsumer action ) { forEach((pos, value) -> { diff --git a/src/main/java/ru/windcorp/progressia/common/world/generic/ChunkMaps.java b/src/main/java/ru/windcorp/progressia/common/world/generic/ChunkMaps.java index e67f67e..c194351 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/generic/ChunkMaps.java +++ b/src/main/java/ru/windcorp/progressia/common/world/generic/ChunkMaps.java @@ -174,42 +174,42 @@ public class ChunkMaps { } @Override - public boolean containsChunk(GenericChunk chunk) { + public boolean containsChunk(GenericChunk chunk) { synchronized (mutex) { return parent.containsChunk(chunk); } } @Override - public V get(GenericChunk chunk) { + public V get(GenericChunk chunk) { synchronized (mutex) { return parent.get(chunk); } } @Override - public V put(GenericChunk chunk, V obj) { + public V put(GenericChunk chunk, V obj) { synchronized (mutex) { return parent.put(chunk, obj); } } @Override - public V remove(GenericChunk chunk) { + public V remove(GenericChunk chunk) { synchronized (mutex) { return parent.remove(chunk); } } @Override - public V getOrDefault(GenericChunk chunk, V def) { + public V getOrDefault(GenericChunk chunk, V def) { synchronized (mutex) { return parent.getOrDefault(chunk, def); } } @Override - public > V compute( + public > V compute( C chunk, BiFunction remappingFunction ) { @@ -247,8 +247,8 @@ public class ChunkMaps { } @Override - public > void forEachIn( - GenericWorld world, + public > void forEachIn( + GenericWorld world, BiConsumer action ) { synchronized (mutex) { diff --git a/src/main/java/ru/windcorp/progressia/common/world/generic/ChunkSet.java b/src/main/java/ru/windcorp/progressia/common/world/generic/ChunkSet.java index 73c2267..6f26ef0 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/generic/ChunkSet.java +++ b/src/main/java/ru/windcorp/progressia/common/world/generic/ChunkSet.java @@ -75,20 +75,20 @@ public interface ChunkSet extends Iterable { return result; } - default boolean contains(GenericChunk chunk) { + default boolean contains(GenericChunk chunk) { return contains(chunk.getPosition()); } - default boolean add(GenericChunk chunk) { + default boolean add(GenericChunk chunk) { return add(chunk.getPosition()); } - default boolean remove(GenericChunk chunk) { + default boolean remove(GenericChunk chunk) { return remove(chunk.getPosition()); } - default > void forEachIn( - GenericWorld world, + default > void forEachIn( + GenericWorld world, Consumer action ) { forEach(position -> { @@ -207,7 +207,7 @@ public interface ChunkSet extends Iterable { } } - default boolean containsAllChunks(Iterable> chunks) { + default boolean containsAllChunks(Iterable> chunks) { boolean[] hasMissing = new boolean[] { false }; chunks.forEach(c -> { @@ -219,7 +219,7 @@ public interface ChunkSet extends Iterable { return hasMissing[0]; } - default boolean containsAnyChunks(Iterable> chunks) { + default boolean containsAnyChunks(Iterable> chunks) { boolean[] hasPresent = new boolean[] { false }; chunks.forEach(c -> { @@ -231,11 +231,11 @@ public interface ChunkSet extends Iterable { return hasPresent[0]; } - default void addAllChunks(Iterable> chunks) { + default void addAllChunks(Iterable> chunks) { chunks.forEach(this::add); } - default void removeAllChunks(Iterable> chunks) { + default void removeAllChunks(Iterable> chunks) { chunks.forEach(this::remove); } diff --git a/src/main/java/ru/windcorp/progressia/common/world/generic/ChunkSets.java b/src/main/java/ru/windcorp/progressia/common/world/generic/ChunkSets.java index 93413e4..4ee643b 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/generic/ChunkSets.java +++ b/src/main/java/ru/windcorp/progressia/common/world/generic/ChunkSets.java @@ -198,29 +198,29 @@ public class ChunkSets { } @Override - public boolean contains(GenericChunk chunk) { + public boolean contains(GenericChunk chunk) { synchronized (mutex) { return parent.contains(chunk); } } @Override - public boolean add(GenericChunk chunk) { + public boolean add(GenericChunk chunk) { synchronized (mutex) { return parent.add(chunk); } } @Override - public boolean remove(GenericChunk chunk) { + public boolean remove(GenericChunk chunk) { synchronized (mutex) { return parent.remove(chunk); } } @Override - public > void forEachIn( - GenericWorld world, + public > void forEachIn( + GenericWorld world, Consumer action ) { synchronized (mutex) { @@ -320,28 +320,28 @@ public class ChunkSets { } @Override - public boolean containsAllChunks(Iterable> chunks) { + public boolean containsAllChunks(Iterable> chunks) { synchronized (mutex) { return parent.containsAllChunks(chunks); } } @Override - public boolean containsAnyChunks(Iterable> chunks) { + public boolean containsAnyChunks(Iterable> chunks) { synchronized (mutex) { return parent.containsAnyChunks(chunks); } } @Override - public void addAllChunks(Iterable> chunks) { + public void addAllChunks(Iterable> chunks) { synchronized (mutex) { parent.addAllChunks(chunks); } } @Override - public void removeAllChunks(Iterable> chunks) { + public void removeAllChunks(Iterable> chunks) { synchronized (mutex) { parent.removeAllChunks(chunks); } diff --git a/src/main/java/ru/windcorp/progressia/common/world/generic/GenericChunk.java b/src/main/java/ru/windcorp/progressia/common/world/generic/GenericChunk.java index e51ac02..281b697 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/generic/GenericChunk.java +++ b/src/main/java/ru/windcorp/progressia/common/world/generic/GenericChunk.java @@ -56,7 +56,15 @@ import ru.windcorp.progressia.common.world.rels.BlockFace; * @param tile stack type * @author javapony */ -public interface GenericChunk, B extends GenericBlock, T extends GenericTile, TS extends GenericTileStack> { +// @formatter:off +public interface GenericChunk< + B extends GenericBlock, + T extends GenericTile, + TS extends GenericTileStack , + TR extends GenericTileReference , + C extends GenericChunk +> { +// @formatter:on /** * The count of blocks in a side of a chunk. This is guaranteed to be a diff --git a/src/main/java/ru/windcorp/progressia/common/world/generic/GenericTileReference.java b/src/main/java/ru/windcorp/progressia/common/world/generic/GenericTileReference.java new file mode 100644 index 0000000..b3e7289 --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/common/world/generic/GenericTileReference.java @@ -0,0 +1,41 @@ +/* + * 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.common.world.generic; + +// @formatter:off +public interface GenericTileReference< + B extends GenericBlock, + T extends GenericTile, + TS extends GenericTileStack , + TR extends GenericTileReference , + C extends GenericChunk +> { +// @formatter:on + + T get(); + + int getIndex(); + + TS getStack(); + + default boolean isValid() { + return get() != null; + } + +} diff --git a/src/main/java/ru/windcorp/progressia/common/world/generic/GenericTileStack.java b/src/main/java/ru/windcorp/progressia/common/world/generic/GenericTileStack.java index a2e8a4d..ddf7e00 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/generic/GenericTileStack.java +++ b/src/main/java/ru/windcorp/progressia/common/world/generic/GenericTileStack.java @@ -27,9 +27,15 @@ import glm.vec._3.i.Vec3i; import ru.windcorp.progressia.common.world.Coordinates; import ru.windcorp.progressia.common.world.rels.RelFace; -public abstract class GenericTileStack, T extends GenericTile, C extends GenericChunk> - extends AbstractList - implements RandomAccess { +// @formatter:off +public abstract class GenericTileStack< + B extends GenericBlock, + T extends GenericTile, + TS extends GenericTileStack , + TR extends GenericTileReference , + C extends GenericChunk +> extends AbstractList implements RandomAccess { +// @formatter:on public static interface TSConsumer { void accept(int layer, T tile); @@ -43,6 +49,12 @@ public abstract class GenericTileStack public abstract RelFace getFace(); + public abstract TR getReference(int index); + + public abstract int getIndexByTag(int tag); + + public abstract int getTagByIndex(int index); + public Vec3i getBlockInWorld(Vec3i output) { // This is safe return Coordinates.getInWorld(getChunk().getPosition(), getBlockInChunk(output), output); @@ -105,4 +117,8 @@ public abstract class GenericTileStack return findClosest(id) != null; } + public B getHost() { + return getChunk().getBlock(getBlockInChunk(null)); + } + } diff --git a/src/main/java/ru/windcorp/progressia/common/world/generic/GenericWorld.java b/src/main/java/ru/windcorp/progressia/common/world/generic/GenericWorld.java index c71ef54..c945461 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/generic/GenericWorld.java +++ b/src/main/java/ru/windcorp/progressia/common/world/generic/GenericWorld.java @@ -29,7 +29,16 @@ import ru.windcorp.progressia.common.world.Coordinates; import ru.windcorp.progressia.common.world.rels.AbsFace; import ru.windcorp.progressia.common.world.rels.BlockFace; -public interface GenericWorld, C extends GenericChunk, E extends GenericEntity> { +// @formatter:off +public interface GenericWorld< + B extends GenericBlock, + T extends GenericTile, + TS extends GenericTileStack , + TR extends GenericTileReference , + C extends GenericChunk , + E extends GenericEntity +> { +// @formatter:on Collection getChunks(); diff --git a/src/main/java/ru/windcorp/progressia/common/world/generic/GenericWritableChunk.java b/src/main/java/ru/windcorp/progressia/common/world/generic/GenericWritableChunk.java index 9dc1557..baf6cc2 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/generic/GenericWritableChunk.java +++ b/src/main/java/ru/windcorp/progressia/common/world/generic/GenericWritableChunk.java @@ -19,12 +19,18 @@ package ru.windcorp.progressia.common.world.generic; import glm.vec._3.i.Vec3i; -import ru.windcorp.progressia.common.world.block.BlockData; +// @formatter:off +public interface GenericWritableChunk< + B extends GenericBlock, + T extends GenericTile, + TS extends GenericWritableTileStack , + TR extends GenericTileReference , + C extends GenericWritableChunk +> + extends GenericChunk { +// @formatter:on -public interface GenericWritableChunk, B extends GenericBlock, T extends GenericTile, TS extends GenericTileStack> - extends GenericChunk { - - void setBlock(Vec3i posInChunk, BlockData block, boolean notify); + void setBlock(Vec3i posInChunk, B block, boolean notify); void setBlockRel(Vec3i relativeBlockInChunk, B block, boolean notify); diff --git a/src/main/java/ru/windcorp/progressia/common/world/generic/GenericWritableTileStack.java b/src/main/java/ru/windcorp/progressia/common/world/generic/GenericWritableTileStack.java new file mode 100644 index 0000000..b2363e3 --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/common/world/generic/GenericWritableTileStack.java @@ -0,0 +1,160 @@ +/* + * 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.common.world.generic; + +// @formatter:off +public abstract class GenericWritableTileStack< + B extends GenericBlock, + T extends GenericTile, + TS extends GenericWritableTileStack, + TR extends GenericTileReference, + C extends GenericWritableChunk +> + extends GenericTileStack { +// @formatter:on + + /** + * Inserts the specified tile at the specified position in this stack. + * Shifts the tile currently at that position (if any) and any tiles above + * to + * the top (adds one to their indices). + * + * @param index index at which the specified tile is to be inserted + * @param tile tile to be inserted + * @throws TileStackIsFullException if this stack is {@linkplain #isFull() + * full} + */ + /* + * Impl note: AbstractList provides a useless implementation of this method, + * make sure to override it in subclass + */ + @Override + public abstract void add(int index, T tile); + + /** + * Adds the specified tile at the end of this stack assigning it the + * provided tag. + * This method is useful for copying stacks when preserving tags is + * necessary. + * + * @param tile the tile to add + * @param tag the tag to assign the new tile + * @throws IllegalArgumentException if this stack already contains a tile + * with the + * provided tag + */ + public abstract void load(T tile, int tag); + + /** + * Replaces the tile at the specified position in this stack with the + * specified tile. + * + * @param index index of the tile to replace + * @param tile tile to be stored at the specified position + * @return the tile previously at the specified position + */ + /* + * Impl note: AbstractList provides a useless implementation of this method, + * make sure to override it in subclass + */ + @Override + public abstract T set(int index, T tile); + + /** + * Removes the tile at the specified position in this list. Shifts any + * subsequent tiles + * to the left (subtracts one from their indices). Returns the tile that was + * removed + * from the list. + * + * @param index the index of the tile to be removed + * @return the tile previously at the specified position + */ + /* + * Impl note: AbstractList provides a useless implementation of this method, + * make sure to override it in subclass + */ + @Override + public abstract T remove(int index); + + /* + * Aliases and overloads + */ + + public void addClosest(T tile) { + add(0, tile); + } + + public void addFarthest(T tile) { + add(size(), tile); + } + + /** + * Attempts to {@link #add(int, TileData) add} the provided {@code tile} + * at {@code index}. If the stack is {@linkplain #isFull() full}, does + * nothing. + * + * @param index the index to insert the tile at + * @param tile the tile to try to add + * @return {@code true} iff this stack has changed + */ + public boolean offer(int index, T tile) { + if (isFull()) + return false; + add(index, tile); + return true; + } + + public boolean offerClosest(T tile) { + return offer(0, tile); + } + + public boolean offerFarthest(T tile) { + return offer(size(), tile); + } + + public T removeClosest() { + return remove(0); + } + + public T removeFarthest() { + return remove(size() - 1); + } + + public T poll(int index) { + if (size() <= index) + return null; + return remove(index); + } + + public T pollClosest() { + return poll(0); + } + + public T pollFarthest() { + return poll(size() - 1); + } + + @Override + public boolean add(T tile) { + addFarthest(tile); + return true; + } + +} diff --git a/src/main/java/ru/windcorp/progressia/common/world/generic/LongBasedChunkSet.java b/src/main/java/ru/windcorp/progressia/common/world/generic/LongBasedChunkSet.java index cd5a755..11559ca 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/generic/LongBasedChunkSet.java +++ b/src/main/java/ru/windcorp/progressia/common/world/generic/LongBasedChunkSet.java @@ -45,7 +45,7 @@ public class LongBasedChunkSet implements ChunkSet { addAll(copyFrom); } - public LongBasedChunkSet(TLongSet impl, GenericWorld copyFrom) { + public LongBasedChunkSet(TLongSet impl, GenericWorld copyFrom) { this(impl); addAllChunks(copyFrom.getChunks()); } diff --git a/src/main/java/ru/windcorp/progressia/common/world/generic/Util.java b/src/main/java/ru/windcorp/progressia/common/world/generic/Util.java index 8f6f79f..f3765d7 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/generic/Util.java +++ b/src/main/java/ru/windcorp/progressia/common/world/generic/Util.java @@ -35,7 +35,7 @@ class Util { return hits; } - public static boolean testBiC(Vec3i blockInWorld, GenericChunk chunk, Predicate test) { + public static boolean testBiC(Vec3i blockInWorld, GenericChunk chunk, Predicate test) { Vec3i v = Vectors.grab3i(); v = Coordinates.getInWorld(chunk.getPosition(), Vectors.ZERO_3i, v); diff --git a/src/main/java/ru/windcorp/progressia/common/world/tile/TileReference.java b/src/main/java/ru/windcorp/progressia/common/world/tile/TileDataReference.java similarity index 71% rename from src/main/java/ru/windcorp/progressia/common/world/tile/TileReference.java rename to src/main/java/ru/windcorp/progressia/common/world/tile/TileDataReference.java index 75fde58..b9699c2 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/tile/TileReference.java +++ b/src/main/java/ru/windcorp/progressia/common/world/tile/TileDataReference.java @@ -18,16 +18,10 @@ package ru.windcorp.progressia.common.world.tile; -public interface TileReference { +import ru.windcorp.progressia.common.world.ChunkData; +import ru.windcorp.progressia.common.world.block.BlockData; +import ru.windcorp.progressia.common.world.generic.GenericTileReference; - TileData get(); - - int getIndex(); - - TileDataStack getStack(); - - default boolean isValid() { - return get() != null; - } +public interface TileDataReference extends GenericTileReference { } diff --git a/src/main/java/ru/windcorp/progressia/common/world/tile/TileDataStack.java b/src/main/java/ru/windcorp/progressia/common/world/tile/TileDataStack.java index 80f0ba4..7e88402 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/tile/TileDataStack.java +++ b/src/main/java/ru/windcorp/progressia/common/world/tile/TileDataStack.java @@ -20,147 +20,9 @@ package ru.windcorp.progressia.common.world.tile; import ru.windcorp.progressia.common.world.ChunkData; import ru.windcorp.progressia.common.world.block.BlockData; -import ru.windcorp.progressia.common.world.generic.GenericTileStack; +import ru.windcorp.progressia.common.world.generic.GenericWritableTileStack; public abstract class TileDataStack - extends GenericTileStack { - - /** - * Inserts the specified tile at the specified position in this stack. - * Shifts the tile currently at that position (if any) and any tiles above - * to - * the top (adds one to their indices). - * - * @param index index at which the specified tile is to be inserted - * @param tile tile to be inserted - * @throws TileStackIsFullException if this stack is {@linkplain #isFull() - * full} - */ - /* - * Impl note: AbstractList provides a useless implementation of this method, - * make sure to override it in subclass - */ - @Override - public abstract void add(int index, TileData tile); - - /** - * Adds the specified tile at the end of this stack assigning it the - * provided tag. - * This method is useful for copying stacks when preserving tags is - * necessary. - * - * @param tile the tile to add - * @param tag the tag to assign the new tile - * @throws IllegalArgumentException if this stack already contains a tile - * with the - * provided tag - */ - public abstract void load(TileData tile, int tag); - - /** - * Replaces the tile at the specified position in this stack with the - * specified tile. - * - * @param index index of the tile to replace - * @param tile tile to be stored at the specified position - * @return the tile previously at the specified position - */ - /* - * Impl note: AbstractList provides a useless implementation of this method, - * make sure to override it in subclass - */ - @Override - public abstract TileData set(int index, TileData tile); - - /** - * Removes the tile at the specified position in this list. Shifts any - * subsequent tiles - * to the left (subtracts one from their indices). Returns the tile that was - * removed - * from the list. - * - * @param index the index of the tile to be removed - * @return the tile previously at the specified position - */ - /* - * Impl note: AbstractList provides a useless implementation of this method, - * make sure to override it in subclass - */ - @Override - public abstract TileData remove(int index); - - public abstract TileReference getReference(int index); - - public abstract int getIndexByTag(int tag); - - public abstract int getTagByIndex(int index); - - /* - * Aliases and overloads - */ - - public void addClosest(TileData tile) { - add(0, tile); - } - - public void addFarthest(TileData tile) { - add(size(), tile); - } - - /** - * Attempts to {@link #add(int, TileData) add} the provided {@code tile} - * at {@code index}. If the stack is {@linkplain #isFull() full}, does - * nothing. - * - * @param index the index to insert the tile at - * @param tile the tile to try to add - * @return {@code true} iff this stack has changed - */ - public boolean offer(int index, TileData tile) { - if (isFull()) - return false; - add(index, tile); - return true; - } - - public boolean offerClosest(TileData tile) { - return offer(0, tile); - } - - public boolean offerFarthest(TileData tile) { - return offer(size(), tile); - } - - public TileData removeClosest() { - return remove(0); - } - - public TileData removeFarthest() { - return remove(size() - 1); - } - - public TileData poll(int index) { - if (size() <= index) - return null; - return remove(index); - } - - public TileData pollClosest() { - return poll(0); - } - - public TileData pollFarthest() { - return poll(size() - 1); - } - - @Override - public boolean add(TileData tile) { - addFarthest(tile); - return true; - } - - public BlockData getHost() { - return getChunk().getBlock(getBlockInChunk(null)); - } + extends GenericWritableTileStack { } diff --git a/src/main/java/ru/windcorp/progressia/server/world/ChunkLogic.java b/src/main/java/ru/windcorp/progressia/server/world/ChunkLogic.java index 2ee89d6..a5177fe 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/ChunkLogic.java +++ b/src/main/java/ru/windcorp/progressia/server/world/ChunkLogic.java @@ -33,7 +33,7 @@ import ru.windcorp.progressia.common.world.rels.AbsFace; import ru.windcorp.progressia.common.world.rels.BlockFace; import ru.windcorp.progressia.common.world.rels.RelFace; import ru.windcorp.progressia.common.world.tile.TileDataStack; -import ru.windcorp.progressia.common.world.tile.TileReference; +import ru.windcorp.progressia.common.world.tile.TileDataReference; import ru.windcorp.progressia.server.world.block.BlockLogic; import ru.windcorp.progressia.server.world.block.BlockLogicRegistry; import ru.windcorp.progressia.server.world.block.TickableBlock; @@ -41,16 +41,17 @@ import ru.windcorp.progressia.server.world.tasks.TickChunk; import ru.windcorp.progressia.server.world.ticking.TickingPolicy; import ru.windcorp.progressia.server.world.tile.TickableTile; import ru.windcorp.progressia.server.world.tile.TileLogic; +import ru.windcorp.progressia.server.world.tile.TileLogicReference; import ru.windcorp.progressia.server.world.tile.TileLogicRegistry; import ru.windcorp.progressia.server.world.tile.TileLogicStack; -public class ChunkLogic implements GenericChunk { +public class ChunkLogic implements GenericChunk { private final WorldLogic world; private final ChunkData data; private final Collection tickingBlocks = new ArrayList<>(); - private final Collection tickingTiles = new ArrayList<>(); + private final Collection tickingTiles = new ArrayList<>(); private final TickChunk tickTask = new TickChunk(this); @@ -124,7 +125,7 @@ public class ChunkLogic implements GenericChunk action) { + public void forEachTickingTile(BiConsumer action) { tickingTiles.forEach(ref -> { action.accept( ref, @@ -138,7 +139,29 @@ public class ChunkLogic implements GenericChunk tileStack); + TileStack withTS(GenericTileStack tileStack); default Builder.Chunk withChunk(ChunkData chunk) { Objects.requireNonNull(chunk, "chunk"); return withChunk(chunk.getPosition()); } - default TileTickContext withTile(TileReference ref) { + default TileTickContext withTile(TileDataReference ref) { Objects.requireNonNull(ref, "ref"); return withTS(ref.getStack()).withLayer(ref.getIndex()); } @@ -259,7 +259,7 @@ public abstract class TickContextMutable implements BlockTickContext, TSTickCont } @Override - public TileStack withTS(GenericTileStack tileStack) { + public TileStack withTS(GenericTileStack tileStack) { Objects.requireNonNull(tileStack, "tileStack"); return withBlock( diff --git a/src/main/java/ru/windcorp/progressia/server/world/WorldLogic.java b/src/main/java/ru/windcorp/progressia/server/world/WorldLogic.java index 4111646..0b80b89 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/WorldLogic.java +++ b/src/main/java/ru/windcorp/progressia/server/world/WorldLogic.java @@ -37,10 +37,11 @@ import ru.windcorp.progressia.server.world.generation.WorldGenerator; import ru.windcorp.progressia.server.world.tasks.TickEntitiesTask; import ru.windcorp.progressia.server.world.ticking.Evaluation; import ru.windcorp.progressia.server.world.tile.TileLogic; +import ru.windcorp.progressia.server.world.tile.TileLogicReference; import ru.windcorp.progressia.server.world.tile.TileLogicStack; public class WorldLogic - implements GenericWorld { diff --git a/src/main/java/ru/windcorp/progressia/server/world/tile/TileLogicReference.java b/src/main/java/ru/windcorp/progressia/server/world/tile/TileLogicReference.java new file mode 100644 index 0000000..97bf35c --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/server/world/tile/TileLogicReference.java @@ -0,0 +1,27 @@ +/* + * 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.server.world.tile; + +import ru.windcorp.progressia.common.world.generic.GenericTileReference; +import ru.windcorp.progressia.server.world.ChunkLogic; +import ru.windcorp.progressia.server.world.block.BlockLogic; + +public interface TileLogicReference + extends GenericTileReference { + +} diff --git a/src/main/java/ru/windcorp/progressia/server/world/tile/TileLogicStack.java b/src/main/java/ru/windcorp/progressia/server/world/tile/TileLogicStack.java index 5e91963..b38a6f6 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/tile/TileLogicStack.java +++ b/src/main/java/ru/windcorp/progressia/server/world/tile/TileLogicStack.java @@ -21,9 +21,10 @@ package ru.windcorp.progressia.server.world.tile; import ru.windcorp.progressia.common.world.generic.GenericTileStack; import ru.windcorp.progressia.common.world.tile.TileDataStack; import ru.windcorp.progressia.server.world.ChunkLogic; +import ru.windcorp.progressia.server.world.block.BlockLogic; public abstract class TileLogicStack - extends GenericTileStack { + extends GenericTileStack { public abstract TileDataStack getData(); diff --git a/src/main/java/ru/windcorp/progressia/server/world/tile/TileTickContext.java b/src/main/java/ru/windcorp/progressia/server/world/tile/TileTickContext.java index 45f41ec..7e7ae88 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/tile/TileTickContext.java +++ b/src/main/java/ru/windcorp/progressia/server/world/tile/TileTickContext.java @@ -20,7 +20,7 @@ package ru.windcorp.progressia.server.world.tile; import ru.windcorp.progressia.common.world.tile.TileData; import ru.windcorp.progressia.common.world.tile.TileDataStack; -import ru.windcorp.progressia.common.world.tile.TileReference; +import ru.windcorp.progressia.common.world.tile.TileDataReference; public interface TileTickContext extends TSTickContext { @@ -53,7 +53,7 @@ public interface TileTickContext extends TSTickContext { return stack.get(getLayer()); } - default TileReference getReference() { + default TileDataReference getReference() { return getTDS().getReference(getLayer()); } From a95bdf1efe2c36a85ca2a6325c6dfd4d309b8574 Mon Sep 17 00:00:00 2001 From: OLEGSHA Date: Fri, 9 Apr 2021 20:15:07 +0300 Subject: [PATCH 23/55] Moved .setBlockRel(...) implementation to GenericWritableChunk --- .../ru/windcorp/progressia/common/world/ChunkData.java | 9 --------- .../progressia/common/world/generic/GenericChunk.java | 4 ++-- .../common/world/generic/GenericWritableChunk.java | 8 +++++++- 3 files changed, 9 insertions(+), 12 deletions(-) diff --git a/src/main/java/ru/windcorp/progressia/common/world/ChunkData.java b/src/main/java/ru/windcorp/progressia/common/world/ChunkData.java index 9a00e25..2202f99 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/ChunkData.java +++ b/src/main/java/ru/windcorp/progressia/common/world/ChunkData.java @@ -28,7 +28,6 @@ import java.util.Objects; import glm.vec._3.i.Vec3i; -import ru.windcorp.progressia.common.util.Vectors; import ru.windcorp.progressia.common.world.block.BlockData; import ru.windcorp.progressia.common.world.generic.GenericChunk; import ru.windcorp.progressia.common.world.generic.GenericWritableChunk; @@ -94,14 +93,6 @@ public class ChunkData }); } } - - @Override - public void setBlockRel(Vec3i relativeBlockInChunk, BlockData block, boolean notify) { - Vec3i absoluteBlockInChunk = Vectors.grab3i(); - resolve(relativeBlockInChunk, absoluteBlockInChunk); - setBlock(absoluteBlockInChunk, block, notify); - Vectors.release(absoluteBlockInChunk); - } @Override public TileDataStack getTilesOrNull(Vec3i blockInChunk, BlockFace face) { diff --git a/src/main/java/ru/windcorp/progressia/common/world/generic/GenericChunk.java b/src/main/java/ru/windcorp/progressia/common/world/generic/GenericChunk.java index 281b697..6c15195 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/generic/GenericChunk.java +++ b/src/main/java/ru/windcorp/progressia/common/world/generic/GenericChunk.java @@ -105,14 +105,14 @@ public interface GenericChunk< boolean hasTiles(Vec3i blockInChunk, BlockFace face); - default Vec3i resolve(Vec3i relativeBlockInChunk, Vec3i output) { + default Vec3i resolve(Vec3i relativeCoords, Vec3i output) { if (output == null) { output = new Vec3i(); } final int offset = BLOCKS_PER_CHUNK - 1; - output.set(relativeBlockInChunk.x, relativeBlockInChunk.y, relativeBlockInChunk.z); + output.set(relativeCoords.x, relativeCoords.y, relativeCoords.z); output.mul(2).sub(offset); AxisRotations.resolve(output, getUp(), output); diff --git a/src/main/java/ru/windcorp/progressia/common/world/generic/GenericWritableChunk.java b/src/main/java/ru/windcorp/progressia/common/world/generic/GenericWritableChunk.java index baf6cc2..40fb010 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/generic/GenericWritableChunk.java +++ b/src/main/java/ru/windcorp/progressia/common/world/generic/GenericWritableChunk.java @@ -18,6 +18,7 @@ package ru.windcorp.progressia.common.world.generic; import glm.vec._3.i.Vec3i; +import ru.windcorp.progressia.common.util.Vectors; // @formatter:off public interface GenericWritableChunk< @@ -32,6 +33,11 @@ public interface GenericWritableChunk< void setBlock(Vec3i posInChunk, B block, boolean notify); - void setBlockRel(Vec3i relativeBlockInChunk, B block, boolean notify); + default void setBlockRel(Vec3i relativeBlockInChunk, B block, boolean notify) { + Vec3i absoluteBlockInChunk = Vectors.grab3i(); + resolve(relativeBlockInChunk, absoluteBlockInChunk); + setBlock(absoluteBlockInChunk, block, notify); + Vectors.release(absoluteBlockInChunk); + } } From 20dccf3d12f4d0fb148bd86f569ec8a81e26bc13 Mon Sep 17 00:00:00 2001 From: OLEGSHA Date: Fri, 9 Apr 2021 23:13:21 +0300 Subject: [PATCH 24/55] Some more refactoring of generic world-related classes. May not compile. - Added GenericWritableWorld - Moved static methods from GenericChunk to GenericChunks - GenericEntity now declares getEntityId() - GenericWorld now declares getEntity(long) - Added a lambda-based mapToFaces variations for AbsFace and RelFace --- .../client/world/ChunkRenderModel.java | 4 +- .../progressia/client/world/WorldRender.java | 7 ++ .../cro/ChunkRenderOptimizerSurface.java | 6 +- .../client/world/entity/EntityRenderable.java | 5 + .../progressia/common/world/ChunkData.java | 4 +- .../progressia/common/world/WorldData.java | 9 +- .../common/world/entity/EntityData.java | 1 + .../common/world/generic/GenericChunk.java | 55 ++-------- .../common/world/generic/GenericChunks.java | 102 ++++++++++++++++++ .../common/world/generic/GenericEntity.java | 2 + .../common/world/generic/GenericWorld.java | 2 + .../{Util.java => GenericWritableWorld.java} | 50 ++++----- .../progressia/common/world/rels/AbsFace.java | 12 +++ .../progressia/common/world/rels/RelFace.java | 13 +++ .../server/world/ChunkTickContext.java | 4 +- .../progressia/server/world/WorldLogic.java | 5 + .../progressia/test/TestChunkCodec.java | 8 +- 17 files changed, 196 insertions(+), 93 deletions(-) create mode 100644 src/main/java/ru/windcorp/progressia/common/world/generic/GenericChunks.java rename src/main/java/ru/windcorp/progressia/common/world/generic/{Util.java => GenericWritableWorld.java} (52%) diff --git a/src/main/java/ru/windcorp/progressia/client/world/ChunkRenderModel.java b/src/main/java/ru/windcorp/progressia/client/world/ChunkRenderModel.java index 46a3f28..832a7ee 100644 --- a/src/main/java/ru/windcorp/progressia/client/world/ChunkRenderModel.java +++ b/src/main/java/ru/windcorp/progressia/client/world/ChunkRenderModel.java @@ -36,7 +36,7 @@ import ru.windcorp.progressia.client.world.tile.TileRender; import ru.windcorp.progressia.client.world.tile.TileRenderNone; import ru.windcorp.progressia.client.world.tile.TileRenderStack; import ru.windcorp.progressia.common.world.ChunkData; -import ru.windcorp.progressia.common.world.generic.GenericChunk; +import ru.windcorp.progressia.common.world.generic.GenericChunks; import ru.windcorp.progressia.common.world.rels.AxisRotations; import ru.windcorp.progressia.common.world.rels.RelFace; @@ -77,7 +77,7 @@ public class ChunkRenderModel implements Renderable { optimizers.forEach(ChunkRenderOptimizer::startRender); - GenericChunk.forEachBiC(relBlockInChunk -> { + GenericChunks.forEachBiC(relBlockInChunk -> { processBlockAndTiles(relBlockInChunk, sink); }); diff --git a/src/main/java/ru/windcorp/progressia/client/world/WorldRender.java b/src/main/java/ru/windcorp/progressia/client/world/WorldRender.java index 2e674f0..7ff4df6 100644 --- a/src/main/java/ru/windcorp/progressia/client/world/WorldRender.java +++ b/src/main/java/ru/windcorp/progressia/client/world/WorldRender.java @@ -111,6 +111,13 @@ public class WorldRender public Collection getEntities() { return entityModels.values(); } + + @Override + public EntityRenderable getEntity(long entityId) { + EntityData entityData = getData().getEntity(entityId); + if (entityData == null) return null; + return getEntityRenderable(entityData); + } public void render(ShapeRenderHelper renderer) { updateChunks(); diff --git a/src/main/java/ru/windcorp/progressia/client/world/cro/ChunkRenderOptimizerSurface.java b/src/main/java/ru/windcorp/progressia/client/world/cro/ChunkRenderOptimizerSurface.java index 5ede1ef..26ee23c 100644 --- a/src/main/java/ru/windcorp/progressia/client/world/cro/ChunkRenderOptimizerSurface.java +++ b/src/main/java/ru/windcorp/progressia/client/world/cro/ChunkRenderOptimizerSurface.java @@ -38,7 +38,7 @@ import ru.windcorp.progressia.client.world.block.BlockRender; import ru.windcorp.progressia.client.world.tile.TileRender; import ru.windcorp.progressia.common.util.Vectors; import ru.windcorp.progressia.common.world.ChunkData; -import ru.windcorp.progressia.common.world.generic.GenericChunk; +import ru.windcorp.progressia.common.world.generic.GenericChunks; import ru.windcorp.progressia.common.world.rels.RelFace; public class ChunkRenderOptimizerSurface extends ChunkRenderOptimizer { @@ -217,7 +217,7 @@ public class ChunkRenderOptimizerSurface extends ChunkRenderOptimizer { Consumer consumer = shapeParts::add; - GenericChunk.forEachBiC(relBlockInChunk -> { + GenericChunks.forEachBiC(relBlockInChunk -> { processInnerFaces(relBlockInChunk, consumer); processOuterFaces(relBlockInChunk, consumer); }); @@ -316,7 +316,7 @@ public class ChunkRenderOptimizerSurface extends ChunkRenderOptimizer { } private boolean shouldRenderWhenFacing(Vec3i relBlockInChunk, RelFace face) { - if (GenericChunk.containsBiC(relBlockInChunk)) { + if (GenericChunks.containsBiC(relBlockInChunk)) { return shouldRenderWhenFacingLocal(relBlockInChunk, face); } else { return shouldRenderWhenFacingNeighbor(relBlockInChunk, face); diff --git a/src/main/java/ru/windcorp/progressia/client/world/entity/EntityRenderable.java b/src/main/java/ru/windcorp/progressia/client/world/entity/EntityRenderable.java index 24ea147..fcd50f6 100644 --- a/src/main/java/ru/windcorp/progressia/client/world/entity/EntityRenderable.java +++ b/src/main/java/ru/windcorp/progressia/client/world/entity/EntityRenderable.java @@ -71,6 +71,11 @@ public abstract class EntityRenderable implements Renderable, GenericEntity { public String getId() { return getData().getId(); } + + @Override + public long getEntityId() { + return getData().getEntityId(); + } public final Vec3 getLookingAt(Vec3 output) { if (output == null) output = new Vec3(); diff --git a/src/main/java/ru/windcorp/progressia/common/world/ChunkData.java b/src/main/java/ru/windcorp/progressia/common/world/ChunkData.java index 2202f99..728bc80 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/ChunkData.java +++ b/src/main/java/ru/windcorp/progressia/common/world/ChunkData.java @@ -29,7 +29,7 @@ import java.util.Objects; import glm.vec._3.i.Vec3i; import ru.windcorp.progressia.common.world.block.BlockData; -import ru.windcorp.progressia.common.world.generic.GenericChunk; +import ru.windcorp.progressia.common.world.generic.GenericChunks; import ru.windcorp.progressia.common.world.generic.GenericWritableChunk; import ru.windcorp.progressia.common.world.rels.AbsFace; import ru.windcorp.progressia.common.world.rels.BlockFace; @@ -160,7 +160,7 @@ public class ChunkData } private static void checkLocalCoordinates(Vec3i posInChunk) { - if (!GenericChunk.containsBiC(posInChunk)) { + if (!GenericChunks.containsBiC(posInChunk)) { throw new IllegalCoordinatesException( "Coordinates (" + posInChunk.x + "; " + posInChunk.y + "; " + posInChunk.z + ") " + "are not legal chunk coordinates" diff --git a/src/main/java/ru/windcorp/progressia/common/world/WorldData.java b/src/main/java/ru/windcorp/progressia/common/world/WorldData.java index 7fec468..13138c5 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/WorldData.java +++ b/src/main/java/ru/windcorp/progressia/common/world/WorldData.java @@ -34,14 +34,14 @@ import ru.windcorp.progressia.common.world.block.BlockData; import ru.windcorp.progressia.common.world.entity.EntityData; import ru.windcorp.progressia.common.world.generic.ChunkMap; import ru.windcorp.progressia.common.world.generic.ChunkSet; -import ru.windcorp.progressia.common.world.generic.GenericWorld; +import ru.windcorp.progressia.common.world.generic.GenericWritableWorld; import ru.windcorp.progressia.common.world.generic.LongBasedChunkMap; import ru.windcorp.progressia.common.world.tile.TileData; import ru.windcorp.progressia.common.world.tile.TileDataStack; import ru.windcorp.progressia.common.world.tile.TileDataReference; public class WorldData - implements GenericWorld { + implements GenericWritableWorld { private final ChunkMap chunksByPos = new LongBasedChunkMap<>( TCollections.synchronizedMap(new TLongObjectHashMap<>()) @@ -128,6 +128,7 @@ public class WorldData chunksByPos.remove(chunk); } + @Override public void setBlock(Vec3i blockInWorld, BlockData block, boolean notify) { ChunkData chunk = getChunkByBlock(blockInWorld); if (chunk == null) @@ -140,10 +141,12 @@ public class WorldData chunk.setBlock(Coordinates.convertInWorldToInChunk(blockInWorld, null), block, notify); } + @Override public EntityData getEntity(long entityId) { return entitiesById.get(entityId); } + @Override public void addEntity(EntityData entity) { Objects.requireNonNull(entity, "entity"); @@ -164,6 +167,7 @@ public class WorldData getListeners().forEach(l -> l.onEntityAdded(this, entity)); } + @Override public void removeEntity(long entityId) { synchronized (entitiesById) { EntityData entity = entitiesById.get(entityId); @@ -178,6 +182,7 @@ public class WorldData } } + @Override public void removeEntity(EntityData entity) { Objects.requireNonNull(entity, "entity"); diff --git a/src/main/java/ru/windcorp/progressia/common/world/entity/EntityData.java b/src/main/java/ru/windcorp/progressia/common/world/entity/EntityData.java index d54cca1..ed6876d 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/entity/EntityData.java +++ b/src/main/java/ru/windcorp/progressia/common/world/entity/EntityData.java @@ -85,6 +85,7 @@ public class EntityData extends StatefulObject implements Collideable, GenericEn this.velocity.set(velocity); } + @Override public long getEntityId() { return entityId; } diff --git a/src/main/java/ru/windcorp/progressia/common/world/generic/GenericChunk.java b/src/main/java/ru/windcorp/progressia/common/world/generic/GenericChunk.java index 6c15195..f9401d8 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/generic/GenericChunk.java +++ b/src/main/java/ru/windcorp/progressia/common/world/generic/GenericChunk.java @@ -106,20 +106,7 @@ public interface GenericChunk< boolean hasTiles(Vec3i blockInChunk, BlockFace face); default Vec3i resolve(Vec3i relativeCoords, Vec3i output) { - if (output == null) { - output = new Vec3i(); - } - - final int offset = BLOCKS_PER_CHUNK - 1; - - output.set(relativeCoords.x, relativeCoords.y, relativeCoords.z); - output.mul(2).sub(offset); - - AxisRotations.resolve(output, getUp(), output); - - output.add(offset).div(2); - - return output; + return GenericChunks.resolve(relativeCoords, output, getUp()); } default B getBlockRel(Vec3i relativeBlockInChunk) { @@ -240,50 +227,20 @@ public interface GenericChunk< return output; } - public static boolean containsBiC(Vec3i blockInChunk) { - return blockInChunk.x >= 0 && blockInChunk.x < BLOCKS_PER_CHUNK && - blockInChunk.y >= 0 && blockInChunk.y < BLOCKS_PER_CHUNK && - blockInChunk.z >= 0 && blockInChunk.z < BLOCKS_PER_CHUNK; - } - - public static boolean isSurfaceBiC(Vec3i blockInChunk) { - return Util.getBorderHits(blockInChunk) >= 1; - } - - public static boolean isEdgeBiC(Vec3i blockInChunk) { - return Util.getBorderHits(blockInChunk) >= 2; - } - - public static boolean isVertexBiC(Vec3i blockInChunk) { - return Util.getBorderHits(blockInChunk) == 3; - } - default boolean containsBiW(Vec3i blockInWorld) { - return Util.testBiC(blockInWorld, this, GenericChunk::containsBiC); + return GenericChunks.testBiC(blockInWorld, this, GenericChunks::containsBiC); } default boolean isSurfaceBiW(Vec3i blockInWorld) { - return Util.testBiC(blockInWorld, this, GenericChunk::isSurfaceBiC); + return GenericChunks.testBiC(blockInWorld, this, GenericChunks::isSurfaceBiC); } default boolean isEdgeBiW(Vec3i blockInWorld) { - return Util.testBiC(blockInWorld, this, GenericChunk::isEdgeBiC); + return GenericChunks.testBiC(blockInWorld, this, GenericChunks::isEdgeBiC); } default boolean isVertexBiW(Vec3i blockInWorld) { - return Util.testBiC(blockInWorld, this, GenericChunk::isVertexBiC); - } - - public static void forEachBiC(Consumer action) { - VectorUtil.iterateCuboid( - 0, - 0, - 0, - BLOCKS_PER_CHUNK, - BLOCKS_PER_CHUNK, - BLOCKS_PER_CHUNK, - action - ); + return GenericChunks.testBiC(blockInWorld, this, GenericChunks::isVertexBiC); } default void forEachBiW(Consumer action) { @@ -324,7 +281,7 @@ public interface GenericChunk< } default void forEachTileStack(Consumer action) { - forEachBiC(blockInChunk -> { + GenericChunks.forEachBiC(blockInChunk -> { for (AbsFace face : AbsFace.getFaces()) { TS stack = getTilesOrNull(blockInChunk, face); if (stack == null) diff --git a/src/main/java/ru/windcorp/progressia/common/world/generic/GenericChunks.java b/src/main/java/ru/windcorp/progressia/common/world/generic/GenericChunks.java new file mode 100644 index 0000000..ac97578 --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/common/world/generic/GenericChunks.java @@ -0,0 +1,102 @@ +/* + * 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.common.world.generic; + +import java.util.function.Consumer; +import java.util.function.Predicate; + +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.world.Coordinates; +import ru.windcorp.progressia.common.world.rels.AbsFace; +import ru.windcorp.progressia.common.world.rels.AxisRotations; + +public class GenericChunks { + + public static Vec3i resolve(Vec3i relativeCoords, Vec3i output, AbsFace up) { + if (output == null) { + output = new Vec3i(); + } + + final int offset = GenericChunk.BLOCKS_PER_CHUNK - 1; + + output.set(relativeCoords.x, relativeCoords.y, relativeCoords.z); + output.mul(2).sub(offset); + + AxisRotations.resolve(output, up, output); + + output.add(offset).div(2); + + return output; + } + + private static int getBorderHits(Vec3i blockInChunk) { + int hits = 0; + + if (Coordinates.isOnChunkBorder(blockInChunk.x)) hits++; + if (Coordinates.isOnChunkBorder(blockInChunk.y)) hits++; + if (Coordinates.isOnChunkBorder(blockInChunk.z)) hits++; + + return hits; + } + + static boolean testBiC(Vec3i blockInWorld, GenericChunk chunk, Predicate test) { + Vec3i v = Vectors.grab3i(); + + v = Coordinates.getInWorld(chunk.getPosition(), Vectors.ZERO_3i, v); + v = blockInWorld.sub(v, v); + + boolean result = test.test(v); + + Vectors.release(v); + + return result; + } + + public static boolean containsBiC(Vec3i blockInChunk) { + return blockInChunk.x >= 0 && blockInChunk.x < GenericChunk.BLOCKS_PER_CHUNK && + blockInChunk.y >= 0 && blockInChunk.y < GenericChunk.BLOCKS_PER_CHUNK && + blockInChunk.z >= 0 && blockInChunk.z < GenericChunk.BLOCKS_PER_CHUNK; + } + + public static boolean isSurfaceBiC(Vec3i blockInChunk) { + return GenericChunks.getBorderHits(blockInChunk) >= 1; + } + + public static boolean isEdgeBiC(Vec3i blockInChunk) { + return GenericChunks.getBorderHits(blockInChunk) >= 2; + } + + public static boolean isVertexBiC(Vec3i blockInChunk) { + return GenericChunks.getBorderHits(blockInChunk) == 3; + } + + public static void forEachBiC(Consumer action) { + VectorUtil.iterateCuboid( + 0, + 0, + 0, + GenericChunk.BLOCKS_PER_CHUNK, + GenericChunk.BLOCKS_PER_CHUNK, + GenericChunk.BLOCKS_PER_CHUNK, + action + ); + } + +} diff --git a/src/main/java/ru/windcorp/progressia/common/world/generic/GenericEntity.java b/src/main/java/ru/windcorp/progressia/common/world/generic/GenericEntity.java index c15bd39..3acfc23 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/generic/GenericEntity.java +++ b/src/main/java/ru/windcorp/progressia/common/world/generic/GenericEntity.java @@ -25,6 +25,8 @@ import ru.windcorp.progressia.common.world.Coordinates; public interface GenericEntity { String getId(); + + long getEntityId(); Vec3 getPosition(); diff --git a/src/main/java/ru/windcorp/progressia/common/world/generic/GenericWorld.java b/src/main/java/ru/windcorp/progressia/common/world/generic/GenericWorld.java index c945461..e17cf66 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/generic/GenericWorld.java +++ b/src/main/java/ru/windcorp/progressia/common/world/generic/GenericWorld.java @@ -46,6 +46,8 @@ public interface GenericWorld< Collection getEntities(); + E getEntity(long entityId); + /* * Chunks */ diff --git a/src/main/java/ru/windcorp/progressia/common/world/generic/Util.java b/src/main/java/ru/windcorp/progressia/common/world/generic/GenericWritableWorld.java similarity index 52% rename from src/main/java/ru/windcorp/progressia/common/world/generic/Util.java rename to src/main/java/ru/windcorp/progressia/common/world/generic/GenericWritableWorld.java index f3765d7..b970f89 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/generic/Util.java +++ b/src/main/java/ru/windcorp/progressia/common/world/generic/GenericWritableWorld.java @@ -17,37 +17,29 @@ */ package ru.windcorp.progressia.common.world.generic; -import java.util.function.Predicate; - import glm.vec._3.i.Vec3i; -import ru.windcorp.progressia.common.util.Vectors; -import ru.windcorp.progressia.common.world.Coordinates; +import ru.windcorp.progressia.common.world.block.BlockData; -class Util { - - public static int getBorderHits(Vec3i blockInChunk) { - int hits = 0; - - if (Coordinates.isOnChunkBorder(blockInChunk.x)) hits++; - if (Coordinates.isOnChunkBorder(blockInChunk.y)) hits++; - if (Coordinates.isOnChunkBorder(blockInChunk.z)) hits++; - - return hits; +//@formatter:off +public interface GenericWritableWorld< + B extends GenericBlock, + T extends GenericTile, + TS extends GenericWritableTileStack , + TR extends GenericTileReference , + C extends GenericWritableChunk , + E extends GenericEntity +> + extends GenericWorld { +//@formatter:on + + void setBlock(Vec3i blockInWorld, BlockData block, boolean notify); + + void addEntity(E entity); + + void removeEntity(long entityId); + + default void removeEntity(E entity) { + removeEntity(entity.getEntityId()); } - - public static boolean testBiC(Vec3i blockInWorld, GenericChunk chunk, Predicate test) { - Vec3i v = Vectors.grab3i(); - - v = Coordinates.getInWorld(chunk.getPosition(), Vectors.ZERO_3i, v); - v = blockInWorld.sub(v, v); - - boolean result = test.test(v); - - Vectors.release(v); - - return result; - } - - } diff --git a/src/main/java/ru/windcorp/progressia/common/world/rels/AbsFace.java b/src/main/java/ru/windcorp/progressia/common/world/rels/AbsFace.java index 9ffb5e9..d741bac 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/rels/AbsFace.java +++ b/src/main/java/ru/windcorp/progressia/common/world/rels/AbsFace.java @@ -19,6 +19,7 @@ package ru.windcorp.progressia.common.world.rels; import java.util.Objects; +import java.util.function.Function; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; @@ -90,6 +91,17 @@ public final class AbsFace extends AbsRelation implements BlockFace { .build(); } + public static ImmutableMap mapToFaces(Function generator) { + return mapToFaces( + generator.apply(POS_Z), + generator.apply(NEG_Z), + generator.apply(POS_X), + generator.apply(NEG_X), + generator.apply(NEG_Y), + generator.apply(POS_Y) + ); + } + /** * Rounds the provided vector to one of {@link AbsFace}s. The returned face * is pointing in the same general direction as the provided vector. The diff --git a/src/main/java/ru/windcorp/progressia/common/world/rels/RelFace.java b/src/main/java/ru/windcorp/progressia/common/world/rels/RelFace.java index 7f3ddb7..99e97fb 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/rels/RelFace.java +++ b/src/main/java/ru/windcorp/progressia/common/world/rels/RelFace.java @@ -17,6 +17,8 @@ */ package ru.windcorp.progressia.common.world.rels; +import java.util.function.Function; + import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; @@ -68,6 +70,17 @@ public class RelFace extends RelRelation implements BlockFace { .put(EAST, east) .build(); } + + public static ImmutableMap mapToFaces(Function generator) { + return mapToFaces( + generator.apply(UP), + generator.apply(DOWN), + generator.apply(NORTH), + generator.apply(SOUTH), + generator.apply(WEST), + generator.apply(EAST) + ); + } private static int nextId = 0; diff --git a/src/main/java/ru/windcorp/progressia/server/world/ChunkTickContext.java b/src/main/java/ru/windcorp/progressia/server/world/ChunkTickContext.java index 0480a6e..64778cd 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/ChunkTickContext.java +++ b/src/main/java/ru/windcorp/progressia/server/world/ChunkTickContext.java @@ -22,7 +22,7 @@ import java.util.function.Consumer; import glm.vec._3.i.Vec3i; import ru.windcorp.progressia.common.world.ChunkData; -import ru.windcorp.progressia.common.world.generic.GenericChunk; +import ru.windcorp.progressia.common.world.generic.GenericChunks; import ru.windcorp.progressia.common.world.rels.AbsFace; import ru.windcorp.progressia.server.world.block.BlockTickContext; @@ -46,7 +46,7 @@ public interface ChunkTickContext extends TickContext { default void forEachBlock(Consumer action) { TickContextMutable context = TickContextMutable.uninitialized(); - GenericChunk.forEachBiC(blockInChunk -> { + GenericChunks.forEachBiC(blockInChunk -> { context.rebuild().withServer(getServer()).withChunk(getChunk()).withBlockInChunk(blockInChunk).build(); action.accept(context); }); diff --git a/src/main/java/ru/windcorp/progressia/server/world/WorldLogic.java b/src/main/java/ru/windcorp/progressia/server/world/WorldLogic.java index 0b80b89..d080551 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/WorldLogic.java +++ b/src/main/java/ru/windcorp/progressia/server/world/WorldLogic.java @@ -90,6 +90,11 @@ public class WorldLogic public Collection getEntities() { return getData().getEntities(); } + + @Override + public EntityData getEntity(long entityId) { + return getData().getEntity(entityId); + } public Evaluation getTickEntitiesTask() { return tickEntitiesTask; diff --git a/src/main/java/ru/windcorp/progressia/test/TestChunkCodec.java b/src/main/java/ru/windcorp/progressia/test/TestChunkCodec.java index 050b94e..0f4dcd2 100644 --- a/src/main/java/ru/windcorp/progressia/test/TestChunkCodec.java +++ b/src/main/java/ru/windcorp/progressia/test/TestChunkCodec.java @@ -38,7 +38,7 @@ import ru.windcorp.progressia.common.world.DecodingException; import ru.windcorp.progressia.common.world.WorldData; import ru.windcorp.progressia.common.world.block.BlockData; import ru.windcorp.progressia.common.world.block.BlockDataRegistry; -import ru.windcorp.progressia.common.world.generic.GenericChunk; +import ru.windcorp.progressia.common.world.generic.GenericChunks; import ru.windcorp.progressia.common.world.io.ChunkCodec; import ru.windcorp.progressia.common.world.rels.RelFace; import ru.windcorp.progressia.common.world.tile.TileData; @@ -125,7 +125,7 @@ public class TestChunkCodec extends ChunkCodec { private void readBlocks(DataInput input, BlockData[] blockPalette, ChunkData chunk) throws IOException { try { - GenericChunk.forEachBiC(guard(v -> { + GenericChunks.forEachBiC(guard(v -> { chunk.setBlock(v, blockPalette[input.readInt()], false); })); } catch (UncheckedIOException e) { @@ -172,7 +172,7 @@ public class TestChunkCodec extends ChunkCodec { private Palette createBlockPalette(ChunkData chunk) { Palette blockPalette = new Palette<>(); - GenericChunk.forEachBiC(v -> blockPalette.add(chunk.getBlock(v))); + GenericChunks.forEachBiC(v -> blockPalette.add(chunk.getBlock(v))); return blockPalette; } @@ -200,7 +200,7 @@ public class TestChunkCodec extends ChunkCodec { private void writeBlocks(ChunkData chunk, Palette blockPalette, DataOutput output) throws IOException { try { - GenericChunk.forEachBiC(guard(v -> { + GenericChunks.forEachBiC(guard(v -> { output.writeInt(blockPalette.getNid(chunk.getBlock(v))); })); } catch (UncheckedIOException e) { From 6fb7e7fc04ff4f6c3dfa9195c5d574a64db6f9ab Mon Sep 17 00:00:00 2001 From: OLEGSHA Date: Tue, 13 Apr 2021 15:18:15 +0300 Subject: [PATCH 25/55] Added SurfaceWorld to facilitate surface feature generation --- .../common/world/generic/GenericChunk.java | 16 +- .../progressia/test/TestBushFeature.java | 45 +++++ .../gen/planet/PlanetFeatureGenerator.java | 34 ++-- .../gen/planet/PlanetTerrainGenerator.java | 4 +- .../progressia/test/gen/surface/Surface.java | 46 +++++ .../test/gen/surface/SurfaceFeature.java | 125 ++++++++++++- .../gen/surface/SurfaceFeatureGenerator.java | 17 +- .../test/gen/surface/SurfaceWorld.java | 168 ++++++++++++++++++ 8 files changed, 426 insertions(+), 29 deletions(-) create mode 100644 src/main/java/ru/windcorp/progressia/test/TestBushFeature.java create mode 100644 src/main/java/ru/windcorp/progressia/test/gen/surface/Surface.java create mode 100644 src/main/java/ru/windcorp/progressia/test/gen/surface/SurfaceWorld.java diff --git a/src/main/java/ru/windcorp/progressia/common/world/generic/GenericChunk.java b/src/main/java/ru/windcorp/progressia/common/world/generic/GenericChunk.java index f9401d8..0748a34 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/generic/GenericChunk.java +++ b/src/main/java/ru/windcorp/progressia/common/world/generic/GenericChunk.java @@ -244,13 +244,17 @@ public interface GenericChunk< } default void forEachBiW(Consumer action) { + int minX = Coordinates.getInWorld(getX(), 0); + int minY = Coordinates.getInWorld(getY(), 0); + int minZ = Coordinates.getInWorld(getZ(), 0); + VectorUtil.iterateCuboid( - Coordinates.getInWorld(getX(), 0), - Coordinates.getInWorld(getY(), 0), - Coordinates.getInWorld(getZ(), 0), - BLOCKS_PER_CHUNK, - BLOCKS_PER_CHUNK, - BLOCKS_PER_CHUNK, + minX, + minY, + minZ, + minX + BLOCKS_PER_CHUNK, + minY + BLOCKS_PER_CHUNK, + minZ + BLOCKS_PER_CHUNK, action ); } diff --git a/src/main/java/ru/windcorp/progressia/test/TestBushFeature.java b/src/main/java/ru/windcorp/progressia/test/TestBushFeature.java new file mode 100644 index 0000000..9e99314 --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/test/TestBushFeature.java @@ -0,0 +1,45 @@ +/* + * 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; + +import glm.vec._3.i.Vec3i; +import ru.windcorp.progressia.common.world.ChunkData; +import ru.windcorp.progressia.common.world.block.BlockData; +import ru.windcorp.progressia.common.world.block.BlockDataRegistry; +import ru.windcorp.progressia.test.gen.surface.SurfaceFeature; +import ru.windcorp.progressia.test.gen.surface.SurfaceWorld; + +public class TestBushFeature extends SurfaceFeature { + + public TestBushFeature(String id) { + super(id); + } + + @Override + public void process(SurfaceWorld world, Request request) { + BlockData block = BlockDataRegistry.getInstance().get("Test:Log"); + + Vec3i location = new Vec3i(request.getRandom().nextInt(ChunkData.BLOCKS_PER_CHUNK), request.getRandom().nextInt(ChunkData.BLOCKS_PER_CHUNK), request.getRandom().nextInt(ChunkData.BLOCKS_PER_CHUNK)).add(request.getMin()); + if (world.getBlockSfc(location) == BlockDataRegistry.getInstance().get("Test:Air")) { + + world.setBlockSfc(location, block, false); + + } + } + +} 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 79f0593..1f69e00 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 @@ -19,40 +19,40 @@ package ru.windcorp.progressia.test.gen.planet; import java.util.ArrayList; import java.util.Collection; -import java.util.Random; +import java.util.Map; import glm.vec._3.i.Vec3i; import ru.windcorp.progressia.common.util.VectorUtil; import ru.windcorp.progressia.common.world.ChunkData; -import ru.windcorp.progressia.common.world.block.BlockDataRegistry; +import ru.windcorp.progressia.common.world.rels.AbsFace; +import ru.windcorp.progressia.test.TestBushFeature; +import ru.windcorp.progressia.test.gen.surface.Surface; import ru.windcorp.progressia.test.gen.surface.SurfaceFeature; import ru.windcorp.progressia.test.gen.surface.SurfaceFeatureGenerator; public class PlanetFeatureGenerator { - + private final TestPlanetGenerator parent; - private final SurfaceFeatureGenerator surfaceGenerator; + + private final Map surfaceGenerators; public PlanetFeatureGenerator(TestPlanetGenerator generator) { this.parent = generator; - + Collection features = new ArrayList<>(); - features.add(new SurfaceFeature("Test:GlassFeature") { - @Override - public void process(ChunkData chunk, Random random) { - - chunk.setBlockRel(new Vec3i(8, 8, 8), BlockDataRegistry.getInstance().get("Test:Glass"), true); - - } - }); + features.add(new TestBushFeature("Test:BushFeature")); - this.surfaceGenerator = new SurfaceFeatureGenerator(features); + int seaLevel = (int) parent.getPlanet().getRadius(); + this.surfaceGenerators = AbsFace.mapToFaces(face -> new SurfaceFeatureGenerator( + new Surface(face, seaLevel), + features + )); } - + public TestPlanetGenerator getGenerator() { return parent; } - + public void generateFeatures(ChunkData chunk) { if (isOrdinaryChunk(chunk.getPosition())) { generateOrdinaryFeatures(chunk); @@ -67,7 +67,7 @@ public class PlanetFeatureGenerator { } private void generateOrdinaryFeatures(ChunkData chunk) { - surfaceGenerator.generateFeatures(chunk); + surfaceGenerators.get(chunk.getUp()).generateFeatures(chunk); } private void generateBorderFeatures(ChunkData chunk) { diff --git a/src/main/java/ru/windcorp/progressia/test/gen/planet/PlanetTerrainGenerator.java b/src/main/java/ru/windcorp/progressia/test/gen/planet/PlanetTerrainGenerator.java index a5b086f..649a6e9 100644 --- a/src/main/java/ru/windcorp/progressia/test/gen/planet/PlanetTerrainGenerator.java +++ b/src/main/java/ru/windcorp/progressia/test/gen/planet/PlanetTerrainGenerator.java @@ -26,7 +26,7 @@ import ru.windcorp.progressia.common.world.ChunkData; import ru.windcorp.progressia.common.world.Coordinates; import ru.windcorp.progressia.common.world.block.BlockData; import ru.windcorp.progressia.common.world.block.BlockDataRegistry; -import ru.windcorp.progressia.common.world.generic.GenericChunk; +import ru.windcorp.progressia.common.world.generic.GenericChunks; import ru.windcorp.progressia.test.gen.TerrainLayer; import ru.windcorp.progressia.test.gen.surface.SurfaceFloatField; import ru.windcorp.progressia.test.gen.surface.SurfaceTerrainGenerator; @@ -90,7 +90,7 @@ class PlanetTerrainGenerator { Vec3 biw = new Vec3(); - GenericChunk.forEachBiC(bic -> { + GenericChunks.forEachBiC(bic -> { biw.set( Coordinates.getInWorld(chunk.getX(), bic.x), diff --git a/src/main/java/ru/windcorp/progressia/test/gen/surface/Surface.java b/src/main/java/ru/windcorp/progressia/test/gen/surface/Surface.java new file mode 100644 index 0000000..0baa6f0 --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/test/gen/surface/Surface.java @@ -0,0 +1,46 @@ +/* + * 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.world.rels.AbsFace; + +public class Surface { + + private final AbsFace up; + private final int seaLevel; + + public Surface(AbsFace up, int seaLevel) { + this.up = up; + this.seaLevel = seaLevel; + } + + /** + * @return the up + */ + public AbsFace getUp() { + return up; + } + + /** + * @return the seaLevel + */ + public int getSeaLevel() { + return seaLevel; + } + +} 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 649b414..aa0ef6c 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,16 +18,137 @@ 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.ChunkData; +import ru.windcorp.progressia.common.world.generic.GenericChunks; +import ru.windcorp.progressia.common.world.rels.AxisRotations; public abstract class SurfaceFeature extends Namespaced { + public static class Request { + + private final ChunkData chunk; + private final Vec3i minSfc = new Vec3i(); + private final Vec3i maxSfc = new Vec3i(); + + private final Random random; + + public Request(ChunkData chunk, Random random) { + this.chunk = chunk; + this.random = random; + + Vec3i absMin = chunk.getMinBIW(null); + Vec3i absMax = chunk.getMaxBIW(null); + + AxisRotations.relativize(absMin, chunk.getUp(), absMin); + AxisRotations.relativize(absMax, chunk.getUp(), absMax); + + Glm.min(absMin, absMax, minSfc); + Glm.max(absMin, absMax, maxSfc); + } + + public ChunkData getChunk() { + return chunk; + } + + public Random getRandom() { + return random; + } + + public int getMinX() { + return minSfc.x; + } + + public int getMaxX() { + return maxSfc.x; + } + + public int getMinY() { + return minSfc.y; + } + + public int getMaxY() { + return maxSfc.y; + } + + public int getMinZ() { + return minSfc.z; + } + + public int getMaxZ() { + return maxSfc.z; + } + + public Vec3i getMin() { + return minSfc; + } + + public Vec3i getMax() { + return maxSfc; + } + + public boolean contains(Vec3i surfaceBlockInWorld) { + Vec3i bic = Vectors.grab3i(); + bic.set(surfaceBlockInWorld.x, surfaceBlockInWorld.y, surfaceBlockInWorld.z); + bic.sub(minSfc); + boolean result = GenericChunks.containsBiC(bic); + Vectors.release(bic); + return result; + } + + public void forEach(Consumer action) { + VectorUtil.iterateCuboid( + minSfc.x, + minSfc.y, + minSfc.z, + maxSfc.x + 1, + maxSfc.y + 1, + maxSfc.z + 1, + action + ); + } + + /** + * Provided vectors have z set to {@link #getMinZ()}. + */ + public void forEachOnFloor(Consumer action) { + forEachOnLayer(action, getMinZ()); + } + + /** + * Provided vectors have z set to {@link #getMaxZ()}. + */ + public void forEachOnCeiling(Consumer action) { + forEachOnLayer(action, getMaxZ()); + } + + /** + * Provided vectors have z set to layer. + */ + public void forEachOnLayer(Consumer action, int layer) { + VectorUtil.iterateCuboid( + minSfc.x, + minSfc.y, + layer, + maxSfc.x + 1, + maxSfc.y + 1, + layer + 1, + action + ); + } + + } + public SurfaceFeature(String id) { super(id); } - - public abstract void process(ChunkData chunk, Random random); + + public abstract void process(SurfaceWorld world, Request request); } 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 753256a..ade7869 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 @@ -26,17 +26,30 @@ import ru.windcorp.progressia.common.world.ChunkData; public class SurfaceFeatureGenerator { + private final Surface surface; + private final Collection features; // TODO make ordered - public SurfaceFeatureGenerator(Collection features) { + public SurfaceFeatureGenerator(Surface surface, Collection features) { + this.surface = surface; this.features = new ArrayList<>(features); } + /** + * @return the surface + */ + public Surface getSurface() { + return surface; + } + public void generateFeatures(ChunkData chunk) { + SurfaceWorld world = new SurfaceWorld(surface, chunk.getWorld()); + Random random = new Random(CoordinatePacker.pack3IntsIntoLong(chunk.getPosition()) /* ^ seed*/); + SurfaceFeature.Request request = new SurfaceFeature.Request(chunk, random); for (SurfaceFeature feature : features) { - feature.process(chunk, random); + feature.process(world, request); } chunk.setGenerationHint(true); diff --git a/src/main/java/ru/windcorp/progressia/test/gen/surface/SurfaceWorld.java b/src/main/java/ru/windcorp/progressia/test/gen/surface/SurfaceWorld.java new file mode 100644 index 0000000..740cc50 --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/test/gen/surface/SurfaceWorld.java @@ -0,0 +1,168 @@ +/* + * 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.util.Collection; + +import glm.vec._3.i.Vec3i; +import ru.windcorp.progressia.common.util.Vectors; +import ru.windcorp.progressia.common.world.ChunkData; +import ru.windcorp.progressia.common.world.block.BlockData; +import ru.windcorp.progressia.common.world.entity.EntityData; +import ru.windcorp.progressia.common.world.generic.GenericChunks; +import ru.windcorp.progressia.common.world.generic.GenericWritableWorld; +import ru.windcorp.progressia.common.world.rels.BlockFace; +import ru.windcorp.progressia.common.world.tile.TileData; +import ru.windcorp.progressia.common.world.tile.TileDataReference; +import ru.windcorp.progressia.common.world.tile.TileDataStack; + +public class SurfaceWorld implements GenericWritableWorld { + + private final Surface surface; + private final GenericWritableWorld parent; + + public SurfaceWorld( + Surface surface, + GenericWritableWorld parent + ) { + this.surface = surface; + this.parent = parent; + } + + /** + * @return the surface + */ + public Surface getSurface() { + return surface; + } + + /** + * @return the parent + */ + public GenericWritableWorld getParent() { + return parent; + } + + /* + * Delegate methods + */ + + @Override + public Collection getChunks() { + return parent.getChunks(); + } + + @Override + public ChunkData getChunk(Vec3i pos) { + return parent.getChunk(pos); + } + + @Override + public Collection getEntities() { + return parent.getEntities(); + } + + @Override + public EntityData getEntity(long entityId) { + return parent.getEntity(entityId); + } + + @Override + public void setBlock(Vec3i blockInWorld, BlockData block, boolean notify) { + parent.setBlock(blockInWorld, block, notify); + } + + @Override + public void addEntity(EntityData entity) { + parent.addEntity(entity); + } + + @Override + public void removeEntity(long entityId) { + parent.removeEntity(entityId); + } + + public Vec3i resolve(Vec3i surfacePosition, Vec3i output) { + if (output == null) { + output = new Vec3i(); + } + + output.set(surfacePosition.x, surfacePosition.y, surfacePosition.z); + output.z -= getSurface().getSeaLevel(); + + GenericChunks.resolve(surfacePosition, output, getSurface().getUp()); + + return output; + } + + public BlockData getBlockSfc(Vec3i surfaceBlockInWorld) { + Vec3i blockInWorld = Vectors.grab3i(); + resolve(surfaceBlockInWorld, blockInWorld); + BlockData result = parent.getBlock(blockInWorld); + Vectors.release(blockInWorld); + return result; + } + + public void setBlockSfc(Vec3i surfaceBlockInWorld, BlockData block, boolean notify) { + Vec3i blockInWorld = Vectors.grab3i(); + resolve(surfaceBlockInWorld, blockInWorld); + parent.setBlock(blockInWorld, block, notify); + Vectors.release(blockInWorld); + } + + public TileDataStack getTilesSfc(Vec3i surfaceBlockInWorld, BlockFace face) { + Vec3i blockInWorld = Vectors.grab3i(); + resolve(surfaceBlockInWorld, blockInWorld); + TileDataStack result = parent.getTiles(blockInWorld, face); + Vectors.release(blockInWorld); + return result; + } + + public TileDataStack getTilesOrNullSfc(Vec3i surfaceBlockInWorld, BlockFace face) { + Vec3i blockInWorld = Vectors.grab3i(); + resolve(surfaceBlockInWorld, blockInWorld); + TileDataStack result = parent.getTilesOrNull(blockInWorld, face); + Vectors.release(blockInWorld); + return result; + } + + public boolean hasTilesSfc(Vec3i surfaceBlockInWorld, BlockFace face) { + Vec3i blockInWorld = Vectors.grab3i(); + resolve(surfaceBlockInWorld, blockInWorld); + boolean result = parent.hasTiles(blockInWorld, face); + Vectors.release(blockInWorld); + return result; + } + + public TileData getTileSfc(Vec3i surfaceBlockInWorld, BlockFace face, int layer) { + Vec3i blockInWorld = Vectors.grab3i(); + resolve(surfaceBlockInWorld, blockInWorld); + TileData result = parent.getTile(blockInWorld, face, layer); + Vectors.release(blockInWorld); + return result; + } + + public boolean isBlockLoadedSfc(Vec3i surfaceBlockInWorld) { + Vec3i blockInWorld = Vectors.grab3i(); + resolve(surfaceBlockInWorld, blockInWorld); + boolean result = parent.isBlockLoaded(blockInWorld); + Vectors.release(blockInWorld); + return result; + } + +} From 737b495fc4b50b5899e2b91ec313eafb22698bb1 Mon Sep 17 00:00:00 2001 From: opfromthestart Date: Fri, 25 Jun 2021 14:35:36 +0300 Subject: [PATCH 26/55] Ported GUI improvements from opfromthestart/Progressia These changes were originally implemented by opfromthestart. OLEGSHA then patched a whole bunch of stuff - Components can now be disabled - Added BasicButton - Added Button, Checkbox and RadioButton (with RadioButtonGroup) - Added some new colors to Colors - Pressing Esc in game pops up a menu (WIP) - Fixed text z-ordering - Fixed LayoutGrid Y-direction --- .../progressia/client/graphics/Colors.java | 8 +- .../client/graphics/flat/RenderTarget.java | 11 +- .../client/graphics/gui/BasicButton.java | 151 ++++++++++++ .../client/graphics/gui/Button.java | 79 +++++++ .../client/graphics/gui/Checkbox.java | 149 ++++++++++++ .../client/graphics/gui/Component.java | 215 +++++++++++++++++- .../progressia/client/graphics/gui/Label.java | 11 +- .../client/graphics/gui/RadioButton.java | 205 +++++++++++++++++ .../client/graphics/gui/RadioButtonGroup.java | 119 ++++++++++ .../graphics/gui/event/ButtonEvent.java | 60 +++++ .../graphics/gui/event/EnableEvent.java | 11 + .../graphics/gui/layout/LayoutGrid.java | 33 ++- .../progressia/test/LayerButtonTest.java | 104 +++++++++ .../progressia/test/TestPlayerControls.java | 20 +- 14 files changed, 1141 insertions(+), 35 deletions(-) create mode 100644 src/main/java/ru/windcorp/progressia/client/graphics/gui/BasicButton.java create mode 100644 src/main/java/ru/windcorp/progressia/client/graphics/gui/Button.java create mode 100644 src/main/java/ru/windcorp/progressia/client/graphics/gui/Checkbox.java create mode 100644 src/main/java/ru/windcorp/progressia/client/graphics/gui/RadioButton.java create mode 100644 src/main/java/ru/windcorp/progressia/client/graphics/gui/RadioButtonGroup.java create mode 100644 src/main/java/ru/windcorp/progressia/client/graphics/gui/event/ButtonEvent.java create mode 100644 src/main/java/ru/windcorp/progressia/client/graphics/gui/event/EnableEvent.java create mode 100644 src/main/java/ru/windcorp/progressia/test/LayerButtonTest.java diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/Colors.java b/src/main/java/ru/windcorp/progressia/client/graphics/Colors.java index 78aa79b..b37a6a8 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/Colors.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/Colors.java @@ -34,7 +34,13 @@ public class Colors { DEBUG_BLUE = toVector(0xFF0000FF), DEBUG_CYAN = toVector(0xFF00FFFF), DEBUG_MAGENTA = toVector(0xFFFF00FF), - DEBUG_YELLOW = toVector(0xFFFFFF00); + DEBUG_YELLOW = toVector(0xFFFFFF00), + + LIGHT_GRAY = toVector(0xFFCBCBD0), + BLUE = toVector(0xFF37A2E6), + HOVER_BLUE = toVector(0xFFC3E4F7), + DISABLED_GRAY = toVector(0xFFE5E5E5), + DISABLED_BLUE = toVector(0xFFB2D8ED); public static Vec4 toVector(int argb) { return toVector(argb, new Vec4()); diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/flat/RenderTarget.java b/src/main/java/ru/windcorp/progressia/client/graphics/flat/RenderTarget.java index 1fea54e..658b02d 100755 --- a/src/main/java/ru/windcorp/progressia/client/graphics/flat/RenderTarget.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/flat/RenderTarget.java @@ -189,13 +189,10 @@ public class RenderTarget { public void addCustomRenderer(Renderable renderable) { assembleCurrentClipFromFaces(); - assembled.add( - new Clip( - maskStack, - getTransform(), - renderable - ) - ); + + float depth = this.depth--; + Mat4 transform = new Mat4().translate(0, 0, depth).mul(getTransform()); + assembled.add(new Clip(maskStack, transform, renderable)); } protected void addFaceToCurrentClip(Face face) { diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/gui/BasicButton.java b/src/main/java/ru/windcorp/progressia/client/graphics/gui/BasicButton.java new file mode 100644 index 0000000..cd30152 --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/client/graphics/gui/BasicButton.java @@ -0,0 +1,151 @@ +/* + * 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.client.graphics.gui; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Objects; +import java.util.function.Consumer; + +import org.lwjgl.glfw.GLFW; + +import com.google.common.eventbus.Subscribe; + +import ru.windcorp.progressia.client.graphics.font.Font; +import ru.windcorp.progressia.client.graphics.gui.event.ButtonEvent; +import ru.windcorp.progressia.client.graphics.gui.event.EnableEvent; +import ru.windcorp.progressia.client.graphics.gui.event.FocusEvent; +import ru.windcorp.progressia.client.graphics.gui.event.HoverEvent; +import ru.windcorp.progressia.client.graphics.gui.layout.LayoutAlign; +import ru.windcorp.progressia.client.graphics.input.KeyEvent; + +public abstract class BasicButton extends Component { + + private final Label label; + + private boolean isPressed = false; + private final Collection> actions = Collections.synchronizedCollection(new ArrayList<>()); + + public BasicButton(String name, String label, Font labelFont) { + super(name); + this.label = new Label(name + ".Label", labelFont, label); + + setLayout(new LayoutAlign(10)); + addChild(this.label); + + setFocusable(true); + reassembleAt(ARTrigger.HOVER, ARTrigger.FOCUS, ARTrigger.ENABLE); + + // Click triggers + addListener(KeyEvent.class, e -> { + if (e.isRepeat()) { + return false; + } else if ( + e.isLeftMouseButton() || + e.getKey() == GLFW.GLFW_KEY_SPACE || + e.getKey() == GLFW.GLFW_KEY_ENTER + ) { + setPressed(e.isPress()); + return true; + } else { + return false; + } + }); + + addListener(new Object() { + + // Release when losing focus + @Subscribe + public void onFocusChange(FocusEvent e) { + if (!e.getNewState()) { + setPressed(false); + } + } + + // Release when hover ends + @Subscribe + public void onHoverEnded(HoverEvent e) { + if (!e.isNowHovered()) { + setPressed(false); + } + } + + // Release when disabled + @Subscribe + public void onDisabled(EnableEvent e) { + if (!e.getComponent().isEnabled()) { + setPressed(false); + } + } + + // Trigger virtualClick when button is released + @Subscribe + public void onRelease(ButtonEvent.Release e) { + virtualClick(); + } + + }); + } + + public BasicButton(String name, String label) { + this(name, label, new Font()); + } + + public boolean isPressed() { + return isPressed; + } + + public void click() { + setPressed(true); + setPressed(false); + } + + public void setPressed(boolean isPressed) { + if (this.isPressed != isPressed) { + this.isPressed = isPressed; + + if (isPressed) { + takeFocus(); + } + + dispatchEvent(ButtonEvent.create(this, this.isPressed)); + } + } + + public BasicButton addAction(Consumer action) { + this.actions.add(Objects.requireNonNull(action, "action")); + return this; + } + + public boolean removeAction(Consumer action) { + return this.actions.remove(action); + } + + public void virtualClick() { + this.actions.forEach(action -> { + action.accept(this); + }); + } + + public Label getLabel() { + return label; + } + +} diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/gui/Button.java b/src/main/java/ru/windcorp/progressia/client/graphics/gui/Button.java new file mode 100644 index 0000000..bbeb361 --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/client/graphics/gui/Button.java @@ -0,0 +1,79 @@ +/* + * 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.client.graphics.gui; + +import glm.vec._4.Vec4; +import ru.windcorp.progressia.client.graphics.flat.RenderTarget; +import ru.windcorp.progressia.client.graphics.font.Font; +import ru.windcorp.progressia.client.graphics.Colors; + +public class Button extends BasicButton { + + public Button(String name, String label, Font labelFont) { + super(name, label, labelFont); + } + + public Button(String name, String label) { + this(name, label, new Font()); + } + + @Override + protected void assembleSelf(RenderTarget target) { + // Border + + Vec4 borderColor; + if (isPressed() || isHovered() || isFocused()) { + borderColor = Colors.BLUE; + } else { + borderColor = Colors.LIGHT_GRAY; + } + target.fill(getX(), getY(), getWidth(), getHeight(), borderColor); + + // Inside area + + if (isPressed()) { + // Do nothing + } else { + Vec4 backgroundColor; + if (isHovered() && isEnabled()) { + backgroundColor = Colors.HOVER_BLUE; + } else { + backgroundColor = Colors.WHITE; + } + target.fill(getX() + 2, getY() + 2, getWidth() - 4, getHeight() - 4, backgroundColor); + } + + // Change label font color + + if (isPressed()) { + getLabel().setFont(getLabel().getFont().withColor(Colors.WHITE)); + } else { + getLabel().setFont(getLabel().getFont().withColor(Colors.BLACK)); + } + } + + @Override + protected void postAssembleSelf(RenderTarget target) { + // Apply disable tint + + if (!isEnabled()) { + target.fill(getX(), getY(), getWidth(), getHeight(), Colors.toVector(0x88FFFFFF)); + } + } +} diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/gui/Checkbox.java b/src/main/java/ru/windcorp/progressia/client/graphics/gui/Checkbox.java new file mode 100644 index 0000000..cb2d52a --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/client/graphics/gui/Checkbox.java @@ -0,0 +1,149 @@ +/* + * 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.client.graphics.gui; + +import glm.vec._2.i.Vec2i; +import glm.vec._4.Vec4; +import ru.windcorp.progressia.client.graphics.Colors; +import ru.windcorp.progressia.client.graphics.flat.RenderTarget; +import ru.windcorp.progressia.client.graphics.font.Font; +import ru.windcorp.progressia.client.graphics.font.Typefaces; +import ru.windcorp.progressia.client.graphics.gui.layout.LayoutAlign; +import ru.windcorp.progressia.client.graphics.gui.layout.LayoutHorizontal; + +public class Checkbox extends BasicButton { + + private class Tick extends Component { + + public Tick() { + super(Checkbox.this.getName() + ".Tick"); + + setPreferredSize(new Vec2i(Typefaces.getDefault().getLineHeight() * 3 / 2)); + } + + @Override + protected void assembleSelf(RenderTarget target) { + + int size = getPreferredSize().x; + int x = getX(); + int y = getY() + (getHeight() - size) / 2; + + // Border + + Vec4 borderColor; + if (Checkbox.this.isPressed() || Checkbox.this.isHovered() || Checkbox.this.isFocused()) { + borderColor = Colors.BLUE; + } else { + borderColor = Colors.LIGHT_GRAY; + } + target.fill(x, y, size, size, borderColor); + + // Inside area + + if (Checkbox.this.isPressed()) { + // Do nothing + } else { + Vec4 backgroundColor; + if (Checkbox.this.isHovered() && Checkbox.this.isEnabled()) { + backgroundColor = Colors.HOVER_BLUE; + } else { + backgroundColor = Colors.WHITE; + } + target.fill(x + 2, y + 2, size - 4, size - 4, backgroundColor); + } + + // "Tick" + + if (Checkbox.this.isChecked()) { + target.fill(x + 4, y + 4, size - 8, size - 8, Colors.BLUE); + } + } + + } + + private boolean checked; + + public Checkbox(String name, String label, Font labelFont, boolean check) { + super(name, label, labelFont); + this.checked = check; + + assert getChildren().size() == 1 : "Checkbox expects that BasicButton contains exactly one child"; + Component basicChild = getChild(0); + + Panel panel = new Panel(getName() + ".LabelAndTick", new LayoutHorizontal(0, 10)); + removeChild(basicChild); + setLayout(new LayoutAlign(0, 0.5f, 10)); + panel.setLayoutHint(basicChild.getLayoutHint()); + panel.addChild(new Tick()); + panel.addChild(basicChild); + addChild(panel); + + addAction(b -> switchState()); + } + + public Checkbox(String name, String label, Font labelFont) { + this(name, label, labelFont, false); + } + + public Checkbox(String name, String label, boolean check) { + this(name, label, new Font(), check); + } + + public Checkbox(String name, String label) { + this(name, label, false); + } + + public void switchState() { + setChecked(!isChecked()); + } + + /** + * @return the checked + */ + public boolean isChecked() { + return checked; + } + + /** + * @param checked the checked to set + */ + public void setChecked(boolean checked) { + this.checked = checked; + } + + @Override + protected void assembleSelf(RenderTarget target) { + // Change label font color + + if (isPressed()) { + getLabel().setFont(getLabel().getFont().withColor(Colors.BLUE)); + } else { + getLabel().setFont(getLabel().getFont().withColor(Colors.BLACK)); + } + } + + @Override + protected void postAssembleSelf(RenderTarget target) { + // Apply disable tint + + if (!isEnabled()) { + target.fill(getX(), getY(), getWidth(), getHeight(), Colors.toVector(0x88FFFFFF)); + } + } + +} diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/gui/Component.java b/src/main/java/ru/windcorp/progressia/client/graphics/gui/Component.java index 4a131d8..bb6f24d 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/gui/Component.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/gui/Component.java @@ -19,18 +19,23 @@ package ru.windcorp.progressia.client.graphics.gui; import java.util.Collections; +import java.util.EnumMap; import java.util.List; +import java.util.Map; +import java.util.Objects; import java.util.concurrent.CopyOnWriteArrayList; import org.lwjgl.glfw.GLFW; import com.google.common.eventbus.EventBus; +import com.google.common.eventbus.Subscribe; import glm.vec._2.i.Vec2i; import ru.windcorp.progressia.client.graphics.backend.InputTracker; import ru.windcorp.progressia.client.graphics.flat.RenderTarget; import ru.windcorp.progressia.client.graphics.gui.event.ChildAddedEvent; import ru.windcorp.progressia.client.graphics.gui.event.ChildRemovedEvent; +import ru.windcorp.progressia.client.graphics.gui.event.EnableEvent; import ru.windcorp.progressia.client.graphics.gui.event.FocusEvent; import ru.windcorp.progressia.client.graphics.gui.event.HoverEvent; import ru.windcorp.progressia.client.graphics.gui.event.ParentChangedEvent; @@ -61,6 +66,8 @@ public class Component extends Named { private Object layoutHint = null; private Layout layout = null; + + private boolean isEnabled = true; private boolean isFocusable = false; private boolean isFocused = false; @@ -285,9 +292,30 @@ public class Component extends Named { return this; } + /** + * Checks whether this component is focusable. A component needs to be + * focusable to become focused. A component that is focusable may not + * necessarily be ready to gain focus (see {@link #canGainFocusNow()}). + * + * @return {@code true} iff the component is focusable + * @see #canGainFocusNow() + */ public boolean isFocusable() { return isFocusable; } + + /** + * Checks whether this component can become focused at this moment. + *

    + * The implementation of this method in {@link Component} considers the + * component a focus candidate if it is both focusable and enabled. + * + * @return {@code true} iff the component can receive focus + * @see #isFocusable() + */ + public boolean canGainFocusNow() { + return isFocusable() && isEnabled(); + } public Component setFocusable(boolean focusable) { this.isFocusable = focusable; @@ -337,7 +365,7 @@ public class Component extends Named { return; } - if (component.isFocusable()) { + if (component.canGainFocusNow()) { setFocused(false); component.setFocused(true); return; @@ -379,7 +407,7 @@ public class Component extends Named { return; } - if (component.isFocusable()) { + if (component.canGainFocusNow()) { setFocused(false); component.setFocused(true); return; @@ -432,13 +460,52 @@ public class Component extends Named { return null; } + + public boolean isEnabled() { + return isEnabled; + } + + /** + * Enables or disables this component. An {@link EnableEvent} is dispatched + * if the state changes. + * + * @param enabled {@code true} to enable the component, {@code false} to + * disable the component + * @see #setEnabledRecursively(boolean) + */ + public void setEnabled(boolean enabled) { + if (this.isEnabled != enabled) { + if (isFocused() && isEnabled()) { + focusNext(); + } + + if (isEnabled()) { + setHovered(false); + } + + this.isEnabled = enabled; + dispatchEvent(new EnableEvent(this)); + } + } + + /** + * Enables or disables this component and all of its children recursively. + * + * @param enabled {@code true} to enable the components, {@code false} to + * disable the components + * @see #setEnabled(boolean) + */ + public void setEnabledRecursively(boolean enabled) { + setEnabled(enabled); + getChildren().forEach(c -> c.setEnabledRecursively(enabled)); + } public boolean isHovered() { return isHovered; } protected void setHovered(boolean isHovered) { - if (this.isHovered != isHovered) { + if (this.isHovered != isHovered && isEnabled()) { this.isHovered = isHovered; if (!isHovered && !getChildren().isEmpty()) { @@ -502,7 +569,7 @@ public class Component extends Named { } protected void handleInput(Input input) { - if (inputBus != null) { + if (inputBus != null && isEnabled()) { inputBus.dispatch(input); } } @@ -598,6 +665,17 @@ public class Component extends Named { } } + /** + * Schedules the reassembly to occur. + *

    + * This method is invoked in root components whenever a + * {@linkplain #requestReassembly() reassembly request} is made by one of + * its children. When creating the dedicated root component, override this + * method to perform any implementation-specific actions that will cause a + * reassembly as soon as possible. + *

    + * The default implementation of this method does nothing. + */ protected void handleReassemblyRequest() { // To be overridden } @@ -637,6 +715,135 @@ public class Component extends Named { protected void assembleChildren(RenderTarget target) { getChildren().forEach(child -> child.assemble(target)); } + + /* + * Automatic Reassembly + */ + + /** + * The various kinds of changes that may be used with + * {@link Component#reassembleAt(ARTrigger...)}. + */ + protected static enum ARTrigger { + /** + * Reassemble the component whenever its hover status changes, e.g. + * whenever the pointer enters or leaves its bounds. + */ + HOVER, + + /** + * Reassemble the component whenever it gains or loses focus. + *

    + * Component must be focusable to be able to gain focus. The + * component will not be reassembled unless + * {@link Component#setFocusable(boolean) setFocusable(true)} has been + * invoked. + */ + FOCUS, + + /** + * Reassemble the component whenever it is enabled or disabled. + */ + ENABLE + } + + /** + * All trigger objects (event listeners) that are currently registered with + * {@link #eventBus}. The field is {@code null} until the first trigger is + * installed. + */ + private Map autoReassemblyTriggerObjects = null; + + private Object createTriggerObject(ARTrigger type) { + switch (type) { + case HOVER: + return new Object() { + @Subscribe + public void onHoverChanged(HoverEvent e) { + requestReassembly(); + } + }; + case FOCUS: + return new Object() { + @Subscribe + public void onFocusChanged(FocusEvent e) { + requestReassembly(); + } + }; + case ENABLE: + return new Object() { + @Subscribe + public void onEnabled(EnableEvent e) { + requestReassembly(); + } + }; + default: + throw new NullPointerException("type"); + } + } + + /** + * Requests that {@link #requestReassembly()} is invoked on this component + * whenever any of the specified changes occur. Duplicate attempts to + * register the same trigger are silently ignored. + *

    + * {@code triggers} may be empty, which results in a no-op. It must not be + * {@code null}. + * + * @param triggers the {@linkplain ARTrigger triggers} to + * request reassembly with. + * @see #disableAutoReassemblyAt(ARTrigger...) + */ + protected synchronized void reassembleAt(ARTrigger... triggers) { + + Objects.requireNonNull(triggers, "triggers"); + if (triggers.length == 0) + return; + + if (autoReassemblyTriggerObjects == null) { + autoReassemblyTriggerObjects = new EnumMap<>(ARTrigger.class); + } + + for (ARTrigger trigger : triggers) { + if (!autoReassemblyTriggerObjects.containsKey(trigger)) { + Object triggerObject = createTriggerObject(trigger); + addListener(trigger); + autoReassemblyTriggerObjects.put(trigger, triggerObject); + } + } + + } + + /** + * Requests that {@link #requestReassembly()} is no longer invoked on this + * component whenever any of the specified changes occur. After a trigger is + * removed, it may be reinstalled with + * {@link #reassembleAt(ARTrigger...)}. Attempts to remove a + * nonexistant trigger are silently ignored. + *

    + * {@code triggers} may be empty, which results in a no-op. It must not be + * {@code null}. + * + * @param triggers the {@linkplain ARTrigger triggers} to remove + * @see #reassemblyAt(ARTrigger...) + */ + protected synchronized void disableAutoReassemblyAt(ARTrigger... triggers) { + + Objects.requireNonNull(triggers, "triggers"); + if (triggers.length == 0) + return; + + if (autoReassemblyTriggerObjects == null) + return; + + for (ARTrigger trigger : triggers) { + Object triggerObject = autoReassemblyTriggerObjects.remove(trigger); + if (triggerObject != null) { + removeListener(trigger); + } + } + + } // /** // * Returns a component that displays this component in its center. diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/gui/Label.java b/src/main/java/ru/windcorp/progressia/client/graphics/gui/Label.java index f7dbe33..4450f33 100755 --- a/src/main/java/ru/windcorp/progressia/client/graphics/gui/Label.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/gui/Label.java @@ -82,6 +82,11 @@ public class Label extends Component { public Font getFont() { return font; } + + public void setFont(Font font) { + this.font = font; + requestReassembly(); + } public String getCurrentText() { return currentText; @@ -96,11 +101,7 @@ public class Label extends Component { float startX = getX() + font.getAlign() * (getWidth() - currentSize.x); target.pushTransform( - new Mat4().identity().translate(startX, getY(), -1000) // TODO wtf - // is this - // magic - // <--- - .scale(2) + new Mat4().identity().translate(startX, getY(), 0).scale(2) ); target.addCustomRenderer(font.assemble(currentText, maxWidth)); diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/gui/RadioButton.java b/src/main/java/ru/windcorp/progressia/client/graphics/gui/RadioButton.java new file mode 100644 index 0000000..bb9cee6 --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/client/graphics/gui/RadioButton.java @@ -0,0 +1,205 @@ +/* + * 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.client.graphics.gui; + +import org.lwjgl.glfw.GLFW; + +import glm.vec._2.i.Vec2i; +import glm.vec._4.Vec4; +import ru.windcorp.progressia.client.graphics.Colors; +import ru.windcorp.progressia.client.graphics.flat.RenderTarget; +import ru.windcorp.progressia.client.graphics.font.Font; +import ru.windcorp.progressia.client.graphics.font.Typefaces; +import ru.windcorp.progressia.client.graphics.gui.layout.LayoutAlign; +import ru.windcorp.progressia.client.graphics.gui.layout.LayoutHorizontal; +import ru.windcorp.progressia.client.graphics.input.KeyEvent; + +public class RadioButton extends BasicButton { + + private class Tick extends Component { + + public Tick() { + super(RadioButton.this.getName() + ".Tick"); + + setPreferredSize(new Vec2i(Typefaces.getDefault().getLineHeight() * 3 / 2)); + } + + private void cross(RenderTarget target, int x, int y, int size, Vec4 color) { + target.fill(x + 4, y, size - 8, size, color); + target.fill(x + 2, y + 2, size - 4, size - 4, color); + target.fill(x, y + 4, size, size - 8, color); + } + + @Override + protected void assembleSelf(RenderTarget target) { + + int size = getPreferredSize().x; + int x = getX(); + int y = getY() + (getHeight() - size) / 2; + + // Border + + Vec4 borderColor; + if (RadioButton.this.isPressed() || RadioButton.this.isHovered() || RadioButton.this.isFocused()) { + borderColor = Colors.BLUE; + } else { + borderColor = Colors.LIGHT_GRAY; + } + cross(target, x, y, size, borderColor); + + // Inside area + + if (RadioButton.this.isPressed()) { + // Do nothing + } else { + Vec4 backgroundColor; + if (RadioButton.this.isHovered() && RadioButton.this.isEnabled()) { + backgroundColor = Colors.HOVER_BLUE; + } else { + backgroundColor = Colors.WHITE; + } + cross(target, x + 2, y + 2, size - 4, backgroundColor); + } + + // "Tick" + + if (RadioButton.this.isChecked()) { + cross(target, x + 4, y + 4, size - 8, Colors.BLUE); + } + } + + } + + private boolean checked; + + private RadioButtonGroup group = null; + + public RadioButton(String name, String label, Font labelFont, boolean check) { + super(name, label, labelFont); + this.checked = check; + + assert getChildren().size() == 1 : "RadioButton expects that BasicButton contains exactly one child"; + Component basicChild = getChild(0); + + Panel panel = new Panel(getName() + ".LabelAndTick", new LayoutHorizontal(0, 10)); + removeChild(basicChild); + setLayout(new LayoutAlign(0, 0.5f, 10)); + panel.setLayoutHint(basicChild.getLayoutHint()); + panel.addChild(new Tick()); + panel.addChild(basicChild); + addChild(panel); + + addListener(KeyEvent.class, e -> { + if (e.isRelease()) return false; + + if (e.getKey() == GLFW.GLFW_KEY_LEFT || e.getKey() == GLFW.GLFW_KEY_UP) { + if (group != null) { + group.selectPrevious(); + group.getSelected().takeFocus(); + } + + return true; + } else if (e.getKey() == GLFW.GLFW_KEY_RIGHT || e.getKey() == GLFW.GLFW_KEY_DOWN) { + if (group != null) { + group.selectNext(); + group.getSelected().takeFocus(); + } + return true; + } + + return false; + }); + + addAction(b -> setChecked(true)); + } + + public RadioButton(String name, String label, Font labelFont) { + this(name, label, labelFont, false); + } + + public RadioButton(String name, String label, boolean check) { + this(name, label, new Font(), check); + } + + public RadioButton(String name, String label) { + this(name, label, false); + } + + /** + * @param group the group to set + */ + public RadioButton setGroup(RadioButtonGroup group) { + + if (this.group != null) { + group.selectNext(); + removeAction(group.listener); + group.buttons.remove(this); + group.getSelected(); // Clear reference if this was the only button in the group + } + + this.group = group; + + if (this.group != null) { + group.buttons.add(this); + addAction(group.listener); + } + + setChecked(false); + + return this; + } + + /** + * @return the checked + */ + public boolean isChecked() { + return checked; + } + + /** + * @param checked the checked to set + */ + public void setChecked(boolean checked) { + this.checked = checked; + + if (group != null) { + group.listener.accept(this); // Failsafe for manual invocations of setChecked() + } + } + + @Override + protected void assembleSelf(RenderTarget target) { + // Change label font color + + if (isPressed()) { + getLabel().setFont(getLabel().getFont().withColor(Colors.BLUE)); + } else { + getLabel().setFont(getLabel().getFont().withColor(Colors.BLACK)); + } + } + + @Override + protected void postAssembleSelf(RenderTarget target) { + // Apply disable tint + + if (!isEnabled()) { + target.fill(getX(), getY(), getWidth(), getHeight(), Colors.toVector(0x88FFFFFF)); + } + } + +} diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/gui/RadioButtonGroup.java b/src/main/java/ru/windcorp/progressia/client/graphics/gui/RadioButtonGroup.java new file mode 100644 index 0000000..3887018 --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/client/graphics/gui/RadioButtonGroup.java @@ -0,0 +1,119 @@ +/* + * 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.client.graphics.gui; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Objects; +import java.util.function.Consumer; + +public class RadioButtonGroup { + + private final Collection> actions = Collections.synchronizedCollection(new ArrayList<>()); + final List buttons = Collections.synchronizedList(new ArrayList<>()); + + private RadioButton selected = null; + + Consumer listener = b -> { + if (b instanceof RadioButton && ((RadioButton) b).isChecked() && buttons.contains(b)) { + select((RadioButton) b); + } + }; + + public RadioButtonGroup addAction(Consumer action) { + this.actions.add(Objects.requireNonNull(action, "action")); + return this; + } + + public boolean removeAction(Consumer action) { + return this.actions.remove(action); + } + + public List getButtons() { + return Collections.unmodifiableList(buttons); + } + + public synchronized RadioButton getSelected() { + if (!buttons.contains(selected)) { + selected = null; + } + return selected; + } + + public synchronized void select(RadioButton button) { + if (button != null && !buttons.contains(button)) { + throw new IllegalArgumentException("Button " + button + " is not in the group"); + } + + getSelected(); // Clear if invalid + + if (selected == button) { + return; // Terminate listener-setter recursion + } + + if (selected != null) { + selected.setChecked(false); + } + + selected = button; + + if (selected != null) { + selected.setChecked(true); + } + + actions.forEach(action -> action.accept(this)); + } + + public void selectNext() { + selectNeighbour(+1); + } + + public void selectPrevious() { + selectNeighbour(-1); + } + + private synchronized void selectNeighbour(int direction) { + if (getSelected() == null) { + if (buttons.isEmpty()) { + throw new IllegalStateException("Cannot select neighbour button: group empty"); + } + + select(buttons.get(0)); + } else { + RadioButton button; + int index = buttons.indexOf(selected); + + do { + index += direction; + + if (index >= buttons.size()) { + index = 0; + } else if (index < 0) { + index = buttons.size() - 1; + } + + button = buttons.get(index); + } while (button != getSelected() && !button.isEnabled()); + + select(button); + } + } + +} diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/gui/event/ButtonEvent.java b/src/main/java/ru/windcorp/progressia/client/graphics/gui/event/ButtonEvent.java new file mode 100644 index 0000000..071f06e --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/client/graphics/gui/event/ButtonEvent.java @@ -0,0 +1,60 @@ +/* + * 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.client.graphics.gui.event; + +import ru.windcorp.progressia.client.graphics.gui.BasicButton; + +public class ButtonEvent extends ComponentEvent { + + public static class Press extends ButtonEvent { + public Press(BasicButton button) { + super(button, true); + } + } + + public static class Release extends ButtonEvent { + public Release(BasicButton button) { + super(button, false); + } + } + + private final boolean isPress; + + protected ButtonEvent(BasicButton button, boolean isPress) { + super(button); + this.isPress = isPress; + } + + public static ButtonEvent create(BasicButton button, boolean isPress) { + if (isPress) { + return new Press(button); + } else { + return new Release(button); + } + } + + public boolean isPress() { + return isPress; + } + + public boolean isRelease() { + return !isPress; + } + +} diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/gui/event/EnableEvent.java b/src/main/java/ru/windcorp/progressia/client/graphics/gui/event/EnableEvent.java new file mode 100644 index 0000000..f56df2c --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/client/graphics/gui/event/EnableEvent.java @@ -0,0 +1,11 @@ +package ru.windcorp.progressia.client.graphics.gui.event; + +import ru.windcorp.progressia.client.graphics.gui.Component; + +public class EnableEvent extends ComponentEvent { + + public EnableEvent(Component component) { + super(component); + } + +} diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/gui/layout/LayoutGrid.java b/src/main/java/ru/windcorp/progressia/client/graphics/gui/layout/LayoutGrid.java index fa2cdfe..a164378 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/gui/layout/LayoutGrid.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/gui/layout/LayoutGrid.java @@ -97,16 +97,27 @@ public class LayoutGrid implements Layout { void setBounds(int column, int row, Component child, Component parent) { if (!isSummed) throw new IllegalStateException("Not summed yet"); + + int width, height; + + if (column == columns.length - 1) { + width = parent.getWidth() - margin - columns[column]; + } else { + width = columns[column + 1] - columns[column] - gap; + } + + if (row == rows.length - 1) { + height = parent.getHeight() - margin - rows[row]; + } else { + height = rows[row + 1] - rows[row] - gap; + } child.setBounds( parent.getX() + columns[column], - parent.getY() + rows[row], + parent.getY() + parent.getHeight() - (rows[row] + height), - (column != (columns.length - 1) ? (columns[column + 1] - columns[column] - gap) - : (parent.getWidth() - margin - columns[column])), - - (row != (rows.length - 1) ? (rows[row + 1] - rows[row] - gap) - : (parent.getHeight() - margin - rows[row])) + width, + height ); } } @@ -132,10 +143,9 @@ public class LayoutGrid implements Layout { GridDimensions grid = calculateGrid(c); grid.sum(); - int[] coords; for (Component child : c.getChildren()) { - coords = (int[]) child.getLayoutHint(); - grid.setBounds(coords[0], coords[1], child, c); + Vec2i coords = (Vec2i) child.getLayoutHint(); + grid.setBounds(coords.x, coords.y, child, c); } } } @@ -149,11 +159,10 @@ public class LayoutGrid implements Layout { private GridDimensions calculateGrid(Component parent) { GridDimensions result = new GridDimensions(); - int[] coords; for (Component child : parent.getChildren()) { - coords = (int[]) child.getLayoutHint(); - result.add(coords[0], coords[1], child.getPreferredSize()); + Vec2i coords = (Vec2i) child.getLayoutHint(); + result.add(coords.x, coords.y, child.getPreferredSize()); } return result; diff --git a/src/main/java/ru/windcorp/progressia/test/LayerButtonTest.java b/src/main/java/ru/windcorp/progressia/test/LayerButtonTest.java new file mode 100644 index 0000000..5e413e2 --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/test/LayerButtonTest.java @@ -0,0 +1,104 @@ +/* + * 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; + +import org.lwjgl.glfw.GLFW; + +import ru.windcorp.progressia.client.graphics.Colors; +import ru.windcorp.progressia.client.graphics.GUI; +import ru.windcorp.progressia.client.graphics.backend.GraphicsBackend; +import ru.windcorp.progressia.client.graphics.flat.RenderTarget; +import ru.windcorp.progressia.client.graphics.gui.Button; +import ru.windcorp.progressia.client.graphics.gui.Checkbox; +import ru.windcorp.progressia.client.graphics.gui.GUILayer; +import ru.windcorp.progressia.client.graphics.gui.Panel; +import ru.windcorp.progressia.client.graphics.gui.RadioButton; +import ru.windcorp.progressia.client.graphics.gui.RadioButtonGroup; +import ru.windcorp.progressia.client.graphics.gui.layout.LayoutAlign; +import ru.windcorp.progressia.client.graphics.gui.layout.LayoutBorderHorizontal; +import ru.windcorp.progressia.client.graphics.gui.layout.LayoutVertical; +import ru.windcorp.progressia.client.graphics.input.InputEvent; +import ru.windcorp.progressia.client.graphics.input.KeyEvent; +import ru.windcorp.progressia.client.graphics.input.bus.Input; + +public class LayerButtonTest extends GUILayer { + + public LayerButtonTest() { + super("LayerButtonTest", new LayoutBorderHorizontal(0)); + + Panel background = new Panel("Background", new LayoutAlign(10)) { + @Override + protected void assembleSelf(RenderTarget target) { + target.fill(Colors.toVector(0x88FFFFFF)); + } + }; + + Panel panel = new Panel("Panel", new LayoutVertical(10)) { + @Override + protected void assembleSelf(RenderTarget target) { + target.fill(getX(), getY(), getWidth(), getHeight(), Colors.LIGHT_GRAY); + target.fill(getX() + 2, getY() + 2, getWidth() - 4, getHeight() - 4, Colors.WHITE); + } + }; + + Button blockableButton; + panel.addChild((blockableButton = new Button("BlockableButton", "Blockable")).addAction(b -> { + System.out.println("Button Blockable!"); + })); + blockableButton.setEnabled(false); + + panel.addChild(new Checkbox("EnableButton", "Enable").addAction(b -> { + blockableButton.setEnabled(((Checkbox) b).isChecked()); + })); + + RadioButtonGroup group = new RadioButtonGroup().addAction(g -> { + System.out.println("RBG! " + g.getSelected().getLabel().getCurrentText()); + }); + + panel.addChild(new RadioButton("RB1", "Moon").setGroup(group)); + panel.addChild(new RadioButton("RB2", "Type").setGroup(group)); + panel.addChild(new RadioButton("RB3", "Ice").setGroup(group)); + panel.addChild(new RadioButton("RB4", "Cream").setGroup(group)); + + panel.getChild(panel.getChildren().size() - 1).setEnabled(false); + + panel.getChild(1).takeFocus(); + + background.addChild(panel); + getRoot().addChild(background.setLayoutHint(LayoutBorderHorizontal.CENTER)); + } + + @Override + protected void handleInput(Input input) { + + if (!input.isConsumed()) { + + InputEvent e = input.getEvent(); + + if ((e instanceof KeyEvent) && ((KeyEvent) e).isPress() && ((KeyEvent) e).getKey() == GLFW.GLFW_KEY_ESCAPE) { + GUI.removeLayer(this); + GLFW.glfwSetInputMode(GraphicsBackend.getWindowHandle(), GLFW.GLFW_CURSOR, GLFW.GLFW_CURSOR_DISABLED); + } + + } + + super.handleInput(input); + input.consume(); + } + +} diff --git a/src/main/java/ru/windcorp/progressia/test/TestPlayerControls.java b/src/main/java/ru/windcorp/progressia/test/TestPlayerControls.java index f129255..e73dcb4 100644 --- a/src/main/java/ru/windcorp/progressia/test/TestPlayerControls.java +++ b/src/main/java/ru/windcorp/progressia/test/TestPlayerControls.java @@ -184,6 +184,7 @@ public class TestPlayerControls { case GLFW.GLFW_KEY_ESCAPE: if (!event.isPress()) return false; + handleEscape(); break; @@ -293,13 +294,20 @@ public class TestPlayerControls { } private void handleEscape() { - if (captureMouse) { - GLFW.glfwSetInputMode(GraphicsBackend.getWindowHandle(), GLFW.GLFW_CURSOR, GLFW.GLFW_CURSOR_NORMAL); - } else { - GLFW.glfwSetInputMode(GraphicsBackend.getWindowHandle(), GLFW.GLFW_CURSOR, GLFW.GLFW_CURSOR_DISABLED); - } +// if (captureMouse) { +// GLFW.glfwSetInputMode(GraphicsBackend.getWindowHandle(), GLFW.GLFW_CURSOR, GLFW.GLFW_CURSOR_NORMAL); +// } else { +// GLFW.glfwSetInputMode(GraphicsBackend.getWindowHandle(), GLFW.GLFW_CURSOR, GLFW.GLFW_CURSOR_DISABLED); +// } +// +// captureMouse = !captureMouse; - captureMouse = !captureMouse; + movementForward = 0; + movementRight = 0; + movementUp = 0; + GLFW.glfwSetInputMode(GraphicsBackend.getWindowHandle(), GLFW.GLFW_CURSOR, GLFW.GLFW_CURSOR_NORMAL); + GUI.addTopLayer(new LayerButtonTest()); + updateGUI(); } From 085f602427dbb5cedf8204fcf39656a274e7d369 Mon Sep 17 00:00:00 2001 From: OLEGSHA Date: Fri, 25 Jun 2021 17:33:46 +0300 Subject: [PATCH 27/55] Panel now has decorations; functionality moved to new superclass Group --- .../client/graphics/gui/Checkbox.java | 10 +++--- .../progressia/client/graphics/gui/Group.java | 28 +++++++++++++++ .../progressia/client/graphics/gui/Panel.java | 15 +++++--- .../client/graphics/gui/RadioButton.java | 22 ++++++------ .../windcorp/progressia/test/LayerAbout.java | 12 +++---- .../progressia/test/LayerButtonTest.java | 11 ++---- .../progressia/test/LayerTestGUI.java | 36 +++++++++---------- 7 files changed, 82 insertions(+), 52 deletions(-) create mode 100755 src/main/java/ru/windcorp/progressia/client/graphics/gui/Group.java mode change 100755 => 100644 src/main/java/ru/windcorp/progressia/client/graphics/gui/Panel.java diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/gui/Checkbox.java b/src/main/java/ru/windcorp/progressia/client/graphics/gui/Checkbox.java index cb2d52a..5f9d0df 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/gui/Checkbox.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/gui/Checkbox.java @@ -85,13 +85,13 @@ public class Checkbox extends BasicButton { assert getChildren().size() == 1 : "Checkbox expects that BasicButton contains exactly one child"; Component basicChild = getChild(0); - Panel panel = new Panel(getName() + ".LabelAndTick", new LayoutHorizontal(0, 10)); + Group group = new Group(getName() + ".LabelAndTick", new LayoutHorizontal(0, 10)); removeChild(basicChild); setLayout(new LayoutAlign(0, 0.5f, 10)); - panel.setLayoutHint(basicChild.getLayoutHint()); - panel.addChild(new Tick()); - panel.addChild(basicChild); - addChild(panel); + group.setLayoutHint(basicChild.getLayoutHint()); + group.addChild(new Tick()); + group.addChild(basicChild); + addChild(group); addAction(b -> switchState()); } diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/gui/Group.java b/src/main/java/ru/windcorp/progressia/client/graphics/gui/Group.java new file mode 100755 index 0000000..d8a8b23 --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/client/graphics/gui/Group.java @@ -0,0 +1,28 @@ +/* + * 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.client.graphics.gui; + +public class Group extends Component { + + public Group(String name, Layout layout) { + super(name); + setLayout(layout); + } + +} diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/gui/Panel.java b/src/main/java/ru/windcorp/progressia/client/graphics/gui/Panel.java old mode 100755 new mode 100644 index 88e10f1..3d47ed1 --- a/src/main/java/ru/windcorp/progressia/client/graphics/gui/Panel.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/gui/Panel.java @@ -15,14 +15,21 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - package ru.windcorp.progressia.client.graphics.gui; -public class Panel extends Component { +import ru.windcorp.progressia.client.graphics.Colors; +import ru.windcorp.progressia.client.graphics.flat.RenderTarget; + +public class Panel extends Group { public Panel(String name, Layout layout) { - super(name); - setLayout(layout); + super(name, layout); + } + + @Override + protected void assembleSelf(RenderTarget target) { + target.fill(getX(), getY(), getWidth(), getHeight(), Colors.LIGHT_GRAY); + target.fill(getX() + 2, getY() + 2, getWidth() - 4, getHeight() - 4, Colors.WHITE); } } diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/gui/RadioButton.java b/src/main/java/ru/windcorp/progressia/client/graphics/gui/RadioButton.java index bb9cee6..471efb6 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/gui/RadioButton.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/gui/RadioButton.java @@ -96,28 +96,28 @@ public class RadioButton extends BasicButton { assert getChildren().size() == 1 : "RadioButton expects that BasicButton contains exactly one child"; Component basicChild = getChild(0); - Panel panel = new Panel(getName() + ".LabelAndTick", new LayoutHorizontal(0, 10)); + Group group = new Group(getName() + ".LabelAndTick", new LayoutHorizontal(0, 10)); removeChild(basicChild); setLayout(new LayoutAlign(0, 0.5f, 10)); - panel.setLayoutHint(basicChild.getLayoutHint()); - panel.addChild(new Tick()); - panel.addChild(basicChild); - addChild(panel); + group.setLayoutHint(basicChild.getLayoutHint()); + group.addChild(new Tick()); + group.addChild(basicChild); + addChild(group); addListener(KeyEvent.class, e -> { if (e.isRelease()) return false; if (e.getKey() == GLFW.GLFW_KEY_LEFT || e.getKey() == GLFW.GLFW_KEY_UP) { - if (group != null) { - group.selectPrevious(); - group.getSelected().takeFocus(); + if (this.group != null) { + this.group.selectPrevious(); + this.group.getSelected().takeFocus(); } return true; } else if (e.getKey() == GLFW.GLFW_KEY_RIGHT || e.getKey() == GLFW.GLFW_KEY_DOWN) { - if (group != null) { - group.selectNext(); - group.getSelected().takeFocus(); + if (this.group != null) { + this.group.selectNext(); + this.group.getSelected().takeFocus(); } return true; } diff --git a/src/main/java/ru/windcorp/progressia/test/LayerAbout.java b/src/main/java/ru/windcorp/progressia/test/LayerAbout.java index 3eaff87..7b45fd4 100644 --- a/src/main/java/ru/windcorp/progressia/test/LayerAbout.java +++ b/src/main/java/ru/windcorp/progressia/test/LayerAbout.java @@ -23,7 +23,7 @@ import ru.windcorp.progressia.client.graphics.font.Font; import ru.windcorp.progressia.client.graphics.font.Typeface; import ru.windcorp.progressia.client.graphics.gui.GUILayer; import ru.windcorp.progressia.client.graphics.gui.Label; -import ru.windcorp.progressia.client.graphics.gui.Panel; +import ru.windcorp.progressia.client.graphics.gui.Group; import ru.windcorp.progressia.client.graphics.gui.layout.LayoutAlign; import ru.windcorp.progressia.client.graphics.gui.layout.LayoutVertical; import ru.windcorp.progressia.client.localization.MutableStringLocalized; @@ -33,12 +33,12 @@ public class LayerAbout extends GUILayer { public LayerAbout() { super("LayerAbout", new LayoutAlign(1, 1, 5)); - Panel panel = new Panel("ControlDisplays", new LayoutVertical(5)); + Group group = new Group("ControlDisplays", new LayoutVertical(5)); Font font = new Font().withColor(Colors.WHITE).deriveOutlined().withAlign(Typeface.ALIGN_RIGHT); Font aboutFont = font.withColor(0xFF37A3E6).deriveBold(); - panel.addChild( + group.addChild( new Label( "About", aboutFont, @@ -46,7 +46,7 @@ public class LayerAbout extends GUILayer { ) ); - panel.addChild( + group.addChild( new Label( "Version", font, @@ -54,7 +54,7 @@ public class LayerAbout extends GUILayer { ) ); - panel.addChild( + group.addChild( new Label( "DebugHint", font, @@ -62,7 +62,7 @@ public class LayerAbout extends GUILayer { ) ); - getRoot().addChild(panel); + getRoot().addChild(group); } diff --git a/src/main/java/ru/windcorp/progressia/test/LayerButtonTest.java b/src/main/java/ru/windcorp/progressia/test/LayerButtonTest.java index 5e413e2..96274b7 100644 --- a/src/main/java/ru/windcorp/progressia/test/LayerButtonTest.java +++ b/src/main/java/ru/windcorp/progressia/test/LayerButtonTest.java @@ -26,6 +26,7 @@ import ru.windcorp.progressia.client.graphics.flat.RenderTarget; import ru.windcorp.progressia.client.graphics.gui.Button; import ru.windcorp.progressia.client.graphics.gui.Checkbox; import ru.windcorp.progressia.client.graphics.gui.GUILayer; +import ru.windcorp.progressia.client.graphics.gui.Group; import ru.windcorp.progressia.client.graphics.gui.Panel; import ru.windcorp.progressia.client.graphics.gui.RadioButton; import ru.windcorp.progressia.client.graphics.gui.RadioButtonGroup; @@ -41,20 +42,14 @@ public class LayerButtonTest extends GUILayer { public LayerButtonTest() { super("LayerButtonTest", new LayoutBorderHorizontal(0)); - Panel background = new Panel("Background", new LayoutAlign(10)) { + Group background = new Group("Background", new LayoutAlign(10)) { @Override protected void assembleSelf(RenderTarget target) { target.fill(Colors.toVector(0x88FFFFFF)); } }; - Panel panel = new Panel("Panel", new LayoutVertical(10)) { - @Override - protected void assembleSelf(RenderTarget target) { - target.fill(getX(), getY(), getWidth(), getHeight(), Colors.LIGHT_GRAY); - target.fill(getX() + 2, getY() + 2, getWidth() - 4, getHeight() - 4, Colors.WHITE); - } - }; + Panel panel = new Panel("Panel", new LayoutVertical(10)); Button blockableButton; panel.addChild((blockableButton = new Button("BlockableButton", "Blockable")).addAction(b -> { diff --git a/src/main/java/ru/windcorp/progressia/test/LayerTestGUI.java b/src/main/java/ru/windcorp/progressia/test/LayerTestGUI.java index ca02ed8..2115e78 100755 --- a/src/main/java/ru/windcorp/progressia/test/LayerTestGUI.java +++ b/src/main/java/ru/windcorp/progressia/test/LayerTestGUI.java @@ -29,7 +29,7 @@ import ru.windcorp.progressia.client.graphics.font.Font; import ru.windcorp.progressia.client.graphics.gui.DynamicLabel; import ru.windcorp.progressia.client.graphics.gui.GUILayer; import ru.windcorp.progressia.client.graphics.gui.Label; -import ru.windcorp.progressia.client.graphics.gui.Panel; +import ru.windcorp.progressia.client.graphics.gui.Group; import ru.windcorp.progressia.client.graphics.gui.layout.LayoutAlign; import ru.windcorp.progressia.client.graphics.gui.layout.LayoutVertical; import ru.windcorp.progressia.client.localization.Localizer; @@ -50,14 +50,14 @@ public class LayerTestGUI extends GUILayer { public LayerTestGUI() { super("LayerTestGui", new LayoutAlign(0, 1, 5)); - Panel panel = new Panel("ControlDisplays", new LayoutVertical(5)); + Group group = new Group("ControlDisplays", new LayoutVertical(5)); Vec4 color = Colors.WHITE; Font font = new Font().withColor(color).deriveOutlined(); TestPlayerControls tpc = TestPlayerControls.getInstance(); - panel.addChild( + group.addChild( new Label( "IsFlyingDisplay", font, @@ -65,7 +65,7 @@ public class LayerTestGUI extends GUILayer { ) ); - panel.addChild( + group.addChild( new Label( "IsSprintingDisplay", font, @@ -73,7 +73,7 @@ public class LayerTestGUI extends GUILayer { ) ); - panel.addChild( + group.addChild( new Label( "IsMouseCapturedDisplay", font, @@ -81,7 +81,7 @@ public class LayerTestGUI extends GUILayer { ) ); - panel.addChild( + group.addChild( new Label( "CameraModeDisplay", font, @@ -92,7 +92,7 @@ public class LayerTestGUI extends GUILayer { ) ); - panel.addChild( + group.addChild( new Label( "GravityModeDisplay", font, @@ -103,7 +103,7 @@ public class LayerTestGUI extends GUILayer { ) ); - panel.addChild( + group.addChild( new Label( "LanguageDisplay", font, @@ -111,7 +111,7 @@ public class LayerTestGUI extends GUILayer { ) ); - panel.addChild( + group.addChild( new Label( "FullscreenDisplay", font, @@ -119,7 +119,7 @@ public class LayerTestGUI extends GUILayer { ) ); - panel.addChild( + group.addChild( new Label( "VSyncDisplay", font, @@ -127,7 +127,7 @@ public class LayerTestGUI extends GUILayer { ) ); - panel.addChild( + group.addChild( new DynamicLabel( "FPSDisplay", font, @@ -139,7 +139,7 @@ public class LayerTestGUI extends GUILayer { ) ); - panel.addChild( + group.addChild( new DynamicLabel( "TPSDisplay", font, @@ -148,7 +148,7 @@ public class LayerTestGUI extends GUILayer { ) ); - panel.addChild( + group.addChild( new DynamicLabel( "ChunkUpdatesDisplay", font, @@ -160,7 +160,7 @@ public class LayerTestGUI extends GUILayer { ) ); - panel.addChild( + group.addChild( new DynamicLabel( "PosDisplay", font, @@ -169,7 +169,7 @@ public class LayerTestGUI extends GUILayer { ) ); - panel.addChild( + group.addChild( new Label( "SelectedBlockDisplay", font, @@ -180,7 +180,7 @@ public class LayerTestGUI extends GUILayer { ) ) ); - panel.addChild( + group.addChild( new Label( "SelectedTileDisplay", font, @@ -191,7 +191,7 @@ public class LayerTestGUI extends GUILayer { ) ) ); - panel.addChild( + group.addChild( new Label( "PlacementModeHint", font, @@ -199,7 +199,7 @@ public class LayerTestGUI extends GUILayer { ) ); - getRoot().addChild(panel); + getRoot().addChild(group); } public Runnable getUpdateCallback() { From eace6733ce6671a1c5945340ebcd679ec813c370 Mon Sep 17 00:00:00 2001 From: OLEGSHA Date: Mon, 28 Jun 2021 17:45:49 +0300 Subject: [PATCH 28/55] Added Menus and cursor visibility management - Layers now have a CursorPolicy - Used to enable/disable cursor based on top layer - Added a default menu layer implementation --- .../progressia/client/graphics/GUI.java | 43 ++++++- .../progressia/client/graphics/Layer.java | 45 +++++++ .../graphics/backend/GraphicsBackend.java | 14 +++ .../graphics/backend/GraphicsInterface.java | 8 ++ .../graphics/backend/LWJGLInitializer.java | 2 - .../progressia/client/graphics/gui/Panel.java | 51 +++++++- .../graphics/gui/layout/LayoutFill.java | 78 ++++++++++++ .../client/graphics/gui/menu/MenuLayer.java | 117 ++++++++++++++++++ .../client/graphics/world/LayerWorld.java | 2 + .../progressia/test/LayerButtonTest.java | 71 ++++------- .../progressia/test/LayerTestGUI.java | 8 -- .../progressia/test/TestPlayerControls.java | 19 --- .../resources/assets/languages/en-US.lang | 5 +- .../resources/assets/languages/ru-RU.lang | 5 +- 14 files changed, 376 insertions(+), 92 deletions(-) create mode 100644 src/main/java/ru/windcorp/progressia/client/graphics/gui/layout/LayoutFill.java create mode 100644 src/main/java/ru/windcorp/progressia/client/graphics/gui/menu/MenuLayer.java diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/GUI.java b/src/main/java/ru/windcorp/progressia/client/graphics/GUI.java index fc099d2..bb4d85b 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/GUI.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/GUI.java @@ -24,6 +24,7 @@ import java.util.List; import com.google.common.eventbus.Subscribe; +import ru.windcorp.progressia.client.graphics.backend.GraphicsInterface; import ru.windcorp.progressia.client.graphics.input.CursorEvent; import ru.windcorp.progressia.client.graphics.input.FrameResizeEvent; import ru.windcorp.progressia.client.graphics.input.InputEvent; @@ -57,15 +58,24 @@ public class GUI { } public static void addBottomLayer(Layer layer) { - modify(layers -> layers.add(layer)); + modify(layers -> { + layers.add(layer); + layer.onAdded(); + }); } public static void addTopLayer(Layer layer) { - modify(layers -> layers.add(0, layer)); + modify(layers -> { + layers.add(0, layer); + layer.onAdded(); + }); } public static void removeLayer(Layer layer) { - modify(layers -> layers.remove(layer)); + modify(layers -> { + layers.remove(layer); + layer.onRemoved(); + }); } private static void modify(LayerStackModification mod) { @@ -78,12 +88,33 @@ public class GUI { public static void render() { synchronized (LAYERS) { - MODIFICATION_QUEUE.forEach(action -> action.affect(LAYERS)); - MODIFICATION_QUEUE.clear(); - + + if (!MODIFICATION_QUEUE.isEmpty()) { + MODIFICATION_QUEUE.forEach(action -> action.affect(LAYERS)); + MODIFICATION_QUEUE.clear(); + + boolean isMouseCurrentlyCaptured = GraphicsInterface.isMouseCaptured(); + Layer.CursorPolicy policy = Layer.CursorPolicy.REQUIRE; + + for (Layer layer : LAYERS) { + Layer.CursorPolicy currentPolicy = layer.getCursorPolicy(); + + if (currentPolicy != Layer.CursorPolicy.INDIFFERENT) { + policy = currentPolicy; + break; + } + } + + boolean shouldCaptureMouse = (policy == Layer.CursorPolicy.FORBID); + if (shouldCaptureMouse != isMouseCurrentlyCaptured) { + GraphicsInterface.setMouseCaptured(shouldCaptureMouse); + } + } + for (int i = LAYERS.size() - 1; i >= 0; --i) { LAYERS.get(i).render(); } + } } diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/Layer.java b/src/main/java/ru/windcorp/progressia/client/graphics/Layer.java index 2dbef4a..dfa72d5 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/Layer.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/Layer.java @@ -30,15 +30,52 @@ public abstract class Layer { private boolean hasInitialized = false; private final AtomicBoolean isValid = new AtomicBoolean(false); + + /** + * Represents various requests that a {@link Layer} can make regarding the + * presence of a visible cursor. The value of the highest layer that is not + * {@link #INDIFFERENT} is used. + */ + public static enum CursorPolicy { + /** + * Require that a cursor is visible. + */ + REQUIRE, + + /** + * The {@link Layer} should not affect the presence or absence of a + * visible cursor; lower layers should be consulted. + */ + INDIFFERENT, + + /** + * Forbid a visible cursor. + */ + FORBID + } + + private CursorPolicy cursorPolicy = CursorPolicy.INDIFFERENT; public Layer(String name) { this.name = name; } + + public String getName() { + return name; + } @Override public String toString() { return "Layer " + name; } + + public CursorPolicy getCursorPolicy() { + return cursorPolicy; + } + + public void setCursorPolicy(CursorPolicy cursorPolicy) { + this.cursorPolicy = cursorPolicy; + } void render() { GraphicsInterface.startNextLayer(); @@ -78,5 +115,13 @@ public abstract class Layer { protected int getHeight() { return GraphicsInterface.getFrameHeight(); } + + protected void onAdded() { + // Do nothing + } + + protected void onRemoved() { + // Do nothing + } } diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/backend/GraphicsBackend.java b/src/main/java/ru/windcorp/progressia/client/graphics/backend/GraphicsBackend.java index 04c4a3d..1635c7a 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/backend/GraphicsBackend.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/backend/GraphicsBackend.java @@ -192,4 +192,18 @@ public class GraphicsBackend { GLFWVidMode vidmode = glfwGetVideoMode(glfwGetPrimaryMonitor()); return vidmode.refreshRate(); } + + public static boolean isMouseCaptured() { + return glfwGetInputMode(windowHandle, GLFW_CURSOR) == GLFW_CURSOR_DISABLED; + } + + public static void setMouseCaptured(boolean capture) { + int mode = capture ? GLFW_CURSOR_DISABLED : GLFW_CURSOR_NORMAL; + glfwSetInputMode(windowHandle, GLFW_CURSOR, mode); + + if (!capture) { + glfwSetCursorPos(windowHandle, FRAME_SIZE.x / 2.0, FRAME_SIZE.y / 2.0); + } + } + } diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/backend/GraphicsInterface.java b/src/main/java/ru/windcorp/progressia/client/graphics/backend/GraphicsInterface.java index 799edfd..ffd0b49 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/backend/GraphicsInterface.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/backend/GraphicsInterface.java @@ -81,5 +81,13 @@ public class GraphicsInterface { } GraphicsBackend.setVSyncEnabled(GraphicsBackend.isVSyncEnabled()); } + + public static boolean isMouseCaptured() { + return GraphicsBackend.isMouseCaptured(); + } + + public static void setMouseCaptured(boolean capture) { + GraphicsBackend.setMouseCaptured(capture); + } } diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/backend/LWJGLInitializer.java b/src/main/java/ru/windcorp/progressia/client/graphics/backend/LWJGLInitializer.java index 83c06c8..9239150 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/backend/LWJGLInitializer.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/backend/LWJGLInitializer.java @@ -65,8 +65,6 @@ class LWJGLInitializer { GraphicsBackend.setWindowHandle(handle); - glfwSetInputMode(handle, GLFW_CURSOR, GLFW_CURSOR_DISABLED); - glfwMakeContextCurrent(handle); glfwSwapInterval(0); // TODO: remove after config system is added } diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/gui/Panel.java b/src/main/java/ru/windcorp/progressia/client/graphics/gui/Panel.java index 3d47ed1..90357ef 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/gui/Panel.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/gui/Panel.java @@ -17,19 +17,64 @@ */ package ru.windcorp.progressia.client.graphics.gui; +import java.util.Objects; + +import glm.vec._4.Vec4; import ru.windcorp.progressia.client.graphics.Colors; import ru.windcorp.progressia.client.graphics.flat.RenderTarget; public class Panel extends Group { - public Panel(String name, Layout layout) { + private Vec4 fill; + private Vec4 border; + + public Panel(String name, Layout layout, Vec4 fill, Vec4 border) { super(name, layout); + + this.fill = Objects.requireNonNull(fill, "fill"); + this.border = border; + } + + public Panel(String name, Layout layout) { + this(name, layout, Colors.WHITE, Colors.LIGHT_GRAY); + } + + /** + * @return the fill + */ + public Vec4 getFill() { + return fill; + } + + /** + * @param fill the fill to set + */ + public void setFill(Vec4 fill) { + this.fill = Objects.requireNonNull(fill, "fill"); + } + + /** + * @return the border + */ + public Vec4 getBorder() { + return border; + } + + /** + * @param border the border to set + */ + public void setBorder(Vec4 border) { + this.border = border; } @Override protected void assembleSelf(RenderTarget target) { - target.fill(getX(), getY(), getWidth(), getHeight(), Colors.LIGHT_GRAY); - target.fill(getX() + 2, getY() + 2, getWidth() - 4, getHeight() - 4, Colors.WHITE); + if (border == null) { + target.fill(getX(), getY(), getWidth(), getHeight(), fill); + } else { + target.fill(getX(), getY(), getWidth(), getHeight(), border); + target.fill(getX() + 2, getY() + 2, getWidth() - 4, getHeight() - 4, fill); + } } } diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/gui/layout/LayoutFill.java b/src/main/java/ru/windcorp/progressia/client/graphics/gui/layout/LayoutFill.java new file mode 100644 index 0000000..c65fc4a --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/client/graphics/gui/layout/LayoutFill.java @@ -0,0 +1,78 @@ +/* + * 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.client.graphics.gui.layout; + +import static java.lang.Math.max; + +import glm.vec._2.i.Vec2i; +import ru.windcorp.progressia.client.graphics.gui.Component; +import ru.windcorp.progressia.client.graphics.gui.Layout; + +public class LayoutFill implements Layout { + + private final int margin; + + public LayoutFill(int margin) { + this.margin = margin; + } + + public LayoutFill() { + this(0); + } + + @Override + public void layout(Component c) { + c.getChildren().forEach(child -> { + + int cWidth = c.getWidth() - 2 * margin; + int cHeight = c.getHeight() - 2 * margin; + + child.setBounds( + c.getX() + margin, + c.getY() + margin, + cWidth, + cHeight + ); + + }); + } + + @Override + public Vec2i calculatePreferredSize(Component c) { + Vec2i result = new Vec2i(0, 0); + + c.getChildren().stream() + .map(child -> child.getPreferredSize()) + .forEach(size -> { + result.x = max(size.x, result.x); + result.y = max(size.y, result.y); + }); + + result.x += 2 * margin; + result.y += 2 * margin; + + return result; + } + + @Override + public String toString() { + return getClass().getSimpleName() + "(" + margin + ")"; + } + +} diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/gui/menu/MenuLayer.java b/src/main/java/ru/windcorp/progressia/client/graphics/gui/menu/MenuLayer.java new file mode 100644 index 0000000..4fa155c --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/client/graphics/gui/menu/MenuLayer.java @@ -0,0 +1,117 @@ +/* + * 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.client.graphics.gui.menu; + +import org.lwjgl.glfw.GLFW; + +import glm.vec._2.i.Vec2i; +import ru.windcorp.progressia.client.graphics.Colors; +import ru.windcorp.progressia.client.graphics.GUI; +import ru.windcorp.progressia.client.graphics.font.Font; +import ru.windcorp.progressia.client.graphics.gui.Component; +import ru.windcorp.progressia.client.graphics.gui.GUILayer; +import ru.windcorp.progressia.client.graphics.gui.Label; +import ru.windcorp.progressia.client.graphics.gui.Layout; +import ru.windcorp.progressia.client.graphics.gui.Panel; +import ru.windcorp.progressia.client.graphics.gui.layout.LayoutAlign; +import ru.windcorp.progressia.client.graphics.gui.layout.LayoutFill; +import ru.windcorp.progressia.client.graphics.gui.layout.LayoutVertical; +import ru.windcorp.progressia.client.graphics.input.InputEvent; +import ru.windcorp.progressia.client.graphics.input.KeyEvent; +import ru.windcorp.progressia.client.graphics.input.bus.Input; +import ru.windcorp.progressia.client.localization.MutableString; +import ru.windcorp.progressia.client.localization.MutableStringLocalized; + +public class MenuLayer extends GUILayer { + + private final Component content; + private final Component background; + + private final Runnable closeAction = () -> { + GUI.removeLayer(this); + }; + + public MenuLayer(String name, Component content) { + super(name, new LayoutFill(0)); + + setCursorPolicy(CursorPolicy.REQUIRE); + + this.background = new Panel(name + ".Background", new LayoutAlign(10), Colors.toVector(0x66000000), null); + this.content = content; + + background.addChild(content); + getRoot().addChild(background); + } + + public MenuLayer(String name, Layout contentLayout) { + this(name, new Panel(name + ".Content", contentLayout)); + } + + public MenuLayer(String name) { + this(name, new LayoutVertical(20, 10)); + } + + public Component getContent() { + return content; + } + + public Component getBackground() { + return background; + } + + protected void addTitle() { + String translationKey = "Layer" + getName() + ".Title"; + MutableString titleText = new MutableStringLocalized(translationKey); + Font titleFont = new Font().deriveBold().withColor(Colors.BLACK).withAlign(0.5f); + + Label label = new Label(getName() + ".Title", titleFont, titleText); + getContent().addChild(label); + + Panel panel = new Panel(getName() + ".Title.Underscore", null, Colors.BLUE, null); + panel.setLayout(new LayoutFill() { + @Override + public Vec2i calculatePreferredSize(Component c) { + return new Vec2i(label.getPreferredSize().x + 40, 4); + } + }); + getContent().addChild(panel); + } + + protected Runnable getCloseAction() { + return closeAction; + } + + @Override + protected void handleInput(Input input) { + + if (!input.isConsumed()) { + InputEvent event = input.getEvent(); + + if (event instanceof KeyEvent) { + KeyEvent keyEvent = (KeyEvent) event; + if (keyEvent.isPress() && keyEvent.getKey() == GLFW.GLFW_KEY_ESCAPE) { + getCloseAction().run(); + } + } + } + + super.handleInput(input); + input.consume(); + } + +} diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/world/LayerWorld.java b/src/main/java/ru/windcorp/progressia/client/graphics/world/LayerWorld.java index 317dfa2..50709ac 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/world/LayerWorld.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/world/LayerWorld.java @@ -57,6 +57,8 @@ public class LayerWorld extends Layer { super("World"); this.client = client; this.inputBasedControls = new InputBasedControls(client); + + setCursorPolicy(CursorPolicy.FORBID); } @Override diff --git a/src/main/java/ru/windcorp/progressia/test/LayerButtonTest.java b/src/main/java/ru/windcorp/progressia/test/LayerButtonTest.java index 96274b7..e505291 100644 --- a/src/main/java/ru/windcorp/progressia/test/LayerButtonTest.java +++ b/src/main/java/ru/windcorp/progressia/test/LayerButtonTest.java @@ -17,47 +17,29 @@ */ package ru.windcorp.progressia.test; -import org.lwjgl.glfw.GLFW; - import ru.windcorp.progressia.client.graphics.Colors; -import ru.windcorp.progressia.client.graphics.GUI; -import ru.windcorp.progressia.client.graphics.backend.GraphicsBackend; -import ru.windcorp.progressia.client.graphics.flat.RenderTarget; +import ru.windcorp.progressia.client.graphics.font.Font; import ru.windcorp.progressia.client.graphics.gui.Button; import ru.windcorp.progressia.client.graphics.gui.Checkbox; -import ru.windcorp.progressia.client.graphics.gui.GUILayer; -import ru.windcorp.progressia.client.graphics.gui.Group; -import ru.windcorp.progressia.client.graphics.gui.Panel; +import ru.windcorp.progressia.client.graphics.gui.Label; import ru.windcorp.progressia.client.graphics.gui.RadioButton; import ru.windcorp.progressia.client.graphics.gui.RadioButtonGroup; -import ru.windcorp.progressia.client.graphics.gui.layout.LayoutAlign; -import ru.windcorp.progressia.client.graphics.gui.layout.LayoutBorderHorizontal; -import ru.windcorp.progressia.client.graphics.gui.layout.LayoutVertical; -import ru.windcorp.progressia.client.graphics.input.InputEvent; -import ru.windcorp.progressia.client.graphics.input.KeyEvent; -import ru.windcorp.progressia.client.graphics.input.bus.Input; +import ru.windcorp.progressia.client.graphics.gui.menu.MenuLayer; -public class LayerButtonTest extends GUILayer { +public class LayerButtonTest extends MenuLayer { public LayerButtonTest() { - super("LayerButtonTest", new LayoutBorderHorizontal(0)); + super("ButtonTest"); - Group background = new Group("Background", new LayoutAlign(10)) { - @Override - protected void assembleSelf(RenderTarget target) { - target.fill(Colors.toVector(0x88FFFFFF)); - } - }; - - Panel panel = new Panel("Panel", new LayoutVertical(10)); + addTitle(); Button blockableButton; - panel.addChild((blockableButton = new Button("BlockableButton", "Blockable")).addAction(b -> { + getContent().addChild((blockableButton = new Button("BlockableButton", "Blockable")).addAction(b -> { System.out.println("Button Blockable!"); })); blockableButton.setEnabled(false); - panel.addChild(new Checkbox("EnableButton", "Enable").addAction(b -> { + getContent().addChild(new Checkbox("EnableButton", "Enable").addAction(b -> { blockableButton.setEnabled(((Checkbox) b).isChecked()); })); @@ -65,35 +47,24 @@ public class LayerButtonTest extends GUILayer { System.out.println("RBG! " + g.getSelected().getLabel().getCurrentText()); }); - panel.addChild(new RadioButton("RB1", "Moon").setGroup(group)); - panel.addChild(new RadioButton("RB2", "Type").setGroup(group)); - panel.addChild(new RadioButton("RB3", "Ice").setGroup(group)); - panel.addChild(new RadioButton("RB4", "Cream").setGroup(group)); + getContent().addChild(new RadioButton("RB1", "Moon").setGroup(group)); + getContent().addChild(new RadioButton("RB2", "Type").setGroup(group)); + getContent().addChild(new RadioButton("RB3", "Ice").setGroup(group)); + getContent().addChild(new RadioButton("RB4", "Cream").setGroup(group)); - panel.getChild(panel.getChildren().size() - 1).setEnabled(false); + getContent().getChild(getContent().getChildren().size() - 1).setEnabled(false); - panel.getChild(1).takeFocus(); + getContent().addChild(new Label("Hint", new Font().withColor(Colors.LIGHT_GRAY), "This is a MenuLayer")); - background.addChild(panel); - getRoot().addChild(background.setLayoutHint(LayoutBorderHorizontal.CENTER)); - } - - @Override - protected void handleInput(Input input) { + getContent().addChild(new Button("Continue", "Continue").addAction(b -> { + getCloseAction().run(); + })); - if (!input.isConsumed()) { - - InputEvent e = input.getEvent(); - - if ((e instanceof KeyEvent) && ((KeyEvent) e).isPress() && ((KeyEvent) e).getKey() == GLFW.GLFW_KEY_ESCAPE) { - GUI.removeLayer(this); - GLFW.glfwSetInputMode(GraphicsBackend.getWindowHandle(), GLFW.GLFW_CURSOR, GLFW.GLFW_CURSOR_DISABLED); - } - - } + getContent().addChild(new Button("Quit", "Quit").addAction(b -> { + System.exit(0); + })); - super.handleInput(input); - input.consume(); + getContent().takeFocus(); } } diff --git a/src/main/java/ru/windcorp/progressia/test/LayerTestGUI.java b/src/main/java/ru/windcorp/progressia/test/LayerTestGUI.java index 2115e78..fb69ca3 100755 --- a/src/main/java/ru/windcorp/progressia/test/LayerTestGUI.java +++ b/src/main/java/ru/windcorp/progressia/test/LayerTestGUI.java @@ -73,14 +73,6 @@ public class LayerTestGUI extends GUILayer { ) ); - group.addChild( - new Label( - "IsMouseCapturedDisplay", - font, - tmp_dynFormat("LayerTestGUI.IsMouseCapturedDisplay", tpc::isMouseCaptured) - ) - ); - group.addChild( new Label( "CameraModeDisplay", diff --git a/src/main/java/ru/windcorp/progressia/test/TestPlayerControls.java b/src/main/java/ru/windcorp/progressia/test/TestPlayerControls.java index e73dcb4..80e2146 100644 --- a/src/main/java/ru/windcorp/progressia/test/TestPlayerControls.java +++ b/src/main/java/ru/windcorp/progressia/test/TestPlayerControls.java @@ -82,7 +82,6 @@ public class TestPlayerControls { private double lastSpacePress = Double.NEGATIVE_INFINITY; private double lastSprintPress = Double.NEGATIVE_INFINITY; - private boolean captureMouse = true; private boolean useMinecraftGravity = false; private int selectedBlock = 0; @@ -294,21 +293,10 @@ public class TestPlayerControls { } private void handleEscape() { -// if (captureMouse) { -// GLFW.glfwSetInputMode(GraphicsBackend.getWindowHandle(), GLFW.GLFW_CURSOR, GLFW.GLFW_CURSOR_NORMAL); -// } else { -// GLFW.glfwSetInputMode(GraphicsBackend.getWindowHandle(), GLFW.GLFW_CURSOR, GLFW.GLFW_CURSOR_DISABLED); -// } -// -// captureMouse = !captureMouse; - movementForward = 0; movementRight = 0; movementUp = 0; - GLFW.glfwSetInputMode(GraphicsBackend.getWindowHandle(), GLFW.GLFW_CURSOR, GLFW.GLFW_CURSOR_NORMAL); GUI.addTopLayer(new LayerButtonTest()); - - updateGUI(); } private void handleDebugLayerSwitch() { @@ -352,9 +340,6 @@ public class TestPlayerControls { } private void onMouseMoved(CursorMoveEvent event) { - if (!captureMouse) - return; - if (ClientState.getInstance() == null || !ClientState.getInstance().isReady()) { return; } @@ -445,10 +430,6 @@ public class TestPlayerControls { return isSprinting; } - public boolean isMouseCaptured() { - return captureMouse; - } - public boolean useMinecraftGravity() { return useMinecraftGravity; } diff --git a/src/main/resources/assets/languages/en-US.lang b/src/main/resources/assets/languages/en-US.lang index 2697fda..4935e77 100644 --- a/src/main/resources/assets/languages/en-US.lang +++ b/src/main/resources/assets/languages/en-US.lang @@ -6,7 +6,6 @@ LayerAbout.DebugHint = Debug GUI: F3 LayerTestGUI.IsFlyingDisplay = Flying: %5s (Space bar x2) LayerTestGUI.IsSprintingDisplay = Sprinting: %5s (W x2) -LayerTestGUI.IsMouseCapturedDisplay = Mouse captured: %5s (Esc) LayerTestGUI.CameraModeDisplay = Camera mode: %5d (F5) LayerTestGUI.GravityModeDisplay = Gravity: %9s (G) LayerTestGUI.LanguageDisplay = Language: %5s (L) @@ -21,4 +20,6 @@ LayerTestGUI.SelectedBlockDisplay = %s Block: %s LayerTestGUI.SelectedTileDisplay = %s Tile: %s LayerTestGUI.PlacementModeHint = (Blocks %s Tiles: Ctrl + Mouse Wheel) LayerTestGUI.IsFullscreen = Fullscreen: %5s (F11) -LayerTestGUI.IsVSync = VSync: %5s (F12) \ No newline at end of file +LayerTestGUI.IsVSync = VSync: %5s (F12) + +LayerButtonTest.Title = Button Test \ No newline at end of file diff --git a/src/main/resources/assets/languages/ru-RU.lang b/src/main/resources/assets/languages/ru-RU.lang index 1b67b24..cd10faa 100644 --- a/src/main/resources/assets/languages/ru-RU.lang +++ b/src/main/resources/assets/languages/ru-RU.lang @@ -6,7 +6,6 @@ LayerAbout.DebugHint = Отладочный GUI: F3 LayerTestGUI.IsFlyingDisplay = Полёт: %5s (Пробел x2) LayerTestGUI.IsSprintingDisplay = Бег: %5s (W x2) -LayerTestGUI.IsMouseCapturedDisplay = Захват мыши: %5s (Esc) LayerTestGUI.CameraModeDisplay = Камера: %5d (F5) LayerTestGUI.GravityModeDisplay = Гравитация: %9s (G) LayerTestGUI.LanguageDisplay = Язык: %5s (L) @@ -21,4 +20,6 @@ LayerTestGUI.SelectedBlockDisplay = %s Блок: %s LayerTestGUI.SelectedTileDisplay = %s Плитка: %s LayerTestGUI.PlacementModeHint = (Блок %s плитки: Ctrl + прокрутка) LayerTestGUI.IsFullscreen = Полный экран: %5s (F11) -LayerTestGUI.IsVSync = Верт. синхр.: %5s (F12) \ No newline at end of file +LayerTestGUI.IsVSync = Верт. синхр.: %5s (F12) + +LayerButtonTest.Title = Тест Кнопок \ No newline at end of file From e47fb3c4bd2ac56011ad8d885cd2845adfd2dbe6 Mon Sep 17 00:00:00 2001 From: OLEGSHA Date: Wed, 7 Jul 2021 17:37:08 +0300 Subject: [PATCH 29/55] Added surface features. Tree generation is currently broken! - Added SurfaceFeature - Used to generate chunk features - Added SurfaceTopLayerFeature - A superclass for features that are only concerned with editing the surface - Added grass, temporary bushes and temporary trees - Bushes and trees do not generate properly due to bugs - Added Test:TemporaryLeaves - Added SurfaceWorld (a GenericWritableWorld wrapper) - Added some unit tests for rotation utilities - Fixed a whole lot of bugs --- .../common/world/generic/ChunkSet.java | 3 + .../common/world/generic/GenericChunk.java | 6 +- .../common/world/generic/GenericChunks.java | 19 ++- .../progressia/test/TestBushFeature.java | 47 +++++-- .../progressia/test/TestChunkCodec.java | 2 - .../windcorp/progressia/test/TestContent.java | 3 + .../progressia/test/TestGrassFeature.java | 68 +++++++++ .../progressia/test/TestTreeFeature.java | 103 ++++++++++++++ .../gen/planet/PlanetFeatureGenerator.java | 7 +- .../gen/planet/PlanetTerrainGenerator.java | 2 + .../test/gen/planet/TestPlanetGenerator.java | 3 +- .../test/gen/surface/SurfaceFeature.java | 130 ++++++++++-------- .../gen/surface/SurfaceFeatureGenerator.java | 2 +- .../gen/surface/SurfaceTopLayerFeature.java | 58 ++++++++ .../test/gen/surface/SurfaceWorld.java | 48 ++++--- .../textures/blocks/TemporaryLeaves.png | Bin 0 -> 13841 bytes .../textures/items/MoonTypeIceCream.png | Bin 0 -> 705 bytes .../generic/GenericChunkRotationsTest.java | 83 +++++++++++ .../common/world/rels/AxisRotationsTest.java | 100 ++++++++++++++ 19 files changed, 587 insertions(+), 97 deletions(-) create mode 100644 src/main/java/ru/windcorp/progressia/test/TestGrassFeature.java create mode 100644 src/main/java/ru/windcorp/progressia/test/TestTreeFeature.java create mode 100644 src/main/java/ru/windcorp/progressia/test/gen/surface/SurfaceTopLayerFeature.java create mode 100644 src/main/resources/assets/textures/blocks/TemporaryLeaves.png create mode 100644 src/main/resources/assets/textures/items/MoonTypeIceCream.png create mode 100644 src/test/java/ru/windcorp/progressia/common/world/generic/GenericChunkRotationsTest.java create mode 100644 src/test/java/ru/windcorp/progressia/common/world/rels/AxisRotationsTest.java diff --git a/src/main/java/ru/windcorp/progressia/common/world/generic/ChunkSet.java b/src/main/java/ru/windcorp/progressia/common/world/generic/ChunkSet.java index 6f26ef0..199e780 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/generic/ChunkSet.java +++ b/src/main/java/ru/windcorp/progressia/common/world/generic/ChunkSet.java @@ -56,6 +56,7 @@ public interface ChunkSet extends Iterable { default boolean contains(int x, int y, int z) { Vec3i v = Vectors.grab3i(); + v.set(x, y, z); boolean result = contains(v); Vectors.release(v); return result; @@ -63,6 +64,7 @@ public interface ChunkSet extends Iterable { default boolean add(int x, int y, int z) { Vec3i v = Vectors.grab3i(); + v.set(x, y, z); boolean result = add(v); Vectors.release(v); return result; @@ -70,6 +72,7 @@ public interface ChunkSet extends Iterable { default boolean remove(int x, int y, int z) { Vec3i v = Vectors.grab3i(); + v.set(x, y, z); boolean result = remove(v); Vectors.release(v); return result; diff --git a/src/main/java/ru/windcorp/progressia/common/world/generic/GenericChunk.java b/src/main/java/ru/windcorp/progressia/common/world/generic/GenericChunk.java index 0748a34..3643564 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/generic/GenericChunk.java +++ b/src/main/java/ru/windcorp/progressia/common/world/generic/GenericChunk.java @@ -106,7 +106,11 @@ public interface GenericChunk< boolean hasTiles(Vec3i blockInChunk, BlockFace face); default Vec3i resolve(Vec3i relativeCoords, Vec3i output) { - return GenericChunks.resolve(relativeCoords, output, getUp()); + return GenericChunks.resolve(relativeCoords, getUp(), output); + } + + default Vec3i relativize(Vec3i absoluteCoords, Vec3i output) { + return GenericChunks.relativize(absoluteCoords, getUp(), output); } default B getBlockRel(Vec3i relativeBlockInChunk) { diff --git a/src/main/java/ru/windcorp/progressia/common/world/generic/GenericChunks.java b/src/main/java/ru/windcorp/progressia/common/world/generic/GenericChunks.java index ac97578..3d65785 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/generic/GenericChunks.java +++ b/src/main/java/ru/windcorp/progressia/common/world/generic/GenericChunks.java @@ -29,7 +29,7 @@ import ru.windcorp.progressia.common.world.rels.AxisRotations; public class GenericChunks { - public static Vec3i resolve(Vec3i relativeCoords, Vec3i output, AbsFace up) { + public static Vec3i resolve(Vec3i relativeCoords, AbsFace up, Vec3i output) { if (output == null) { output = new Vec3i(); } @@ -46,6 +46,23 @@ public class GenericChunks { return output; } + public static Vec3i relativize(Vec3i absoluteCoords, AbsFace up, Vec3i output) { + if (output == null) { + output = new Vec3i(); + } + + final int offset = GenericChunk.BLOCKS_PER_CHUNK - 1; + + output.set(absoluteCoords.x, absoluteCoords.y, absoluteCoords.z); + output.mul(2).sub(offset); + + AxisRotations.relativize(output, up, output); + + output.add(offset).div(2); + + return output; + } + private static int getBorderHits(Vec3i blockInChunk) { int hits = 0; diff --git a/src/main/java/ru/windcorp/progressia/test/TestBushFeature.java b/src/main/java/ru/windcorp/progressia/test/TestBushFeature.java index 9e99314..50a56aa 100644 --- a/src/main/java/ru/windcorp/progressia/test/TestBushFeature.java +++ b/src/main/java/ru/windcorp/progressia/test/TestBushFeature.java @@ -18,28 +18,49 @@ package ru.windcorp.progressia.test; import glm.vec._3.i.Vec3i; -import ru.windcorp.progressia.common.world.ChunkData; +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.test.gen.surface.SurfaceFeature; +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; -public class TestBushFeature extends SurfaceFeature { +public class TestBushFeature extends SurfaceTopLayerFeature { public TestBushFeature(String id) { super(id); } - - @Override - public void process(SurfaceWorld world, Request request) { - BlockData block = BlockDataRegistry.getInstance().get("Test:Log"); - - Vec3i location = new Vec3i(request.getRandom().nextInt(ChunkData.BLOCKS_PER_CHUNK), request.getRandom().nextInt(ChunkData.BLOCKS_PER_CHUNK), request.getRandom().nextInt(ChunkData.BLOCKS_PER_CHUNK)).add(request.getMin()); - if (world.getBlockSfc(location) == BlockDataRegistry.getInstance().get("Test:Air")) { - - world.setBlockSfc(location, block, false); - + + private void tryToSetLeaves(SurfaceWorld world, Vec3i posSfc, BlockData leaves) { + if (world.getBlockSfc(posSfc).getId().equals("Test:Air")) { + world.setBlockSfc(posSfc, leaves, false); } } + + @Override + protected void processTopBlock(SurfaceWorld world, Request request, Vec3i topBlock) { + if (request.getRandom().nextInt(10*10) > 0) return; + + Vec3i center = topBlock.add_(0, 0, 1); + + BlockData log = BlockDataRegistry.getInstance().get("Test:Log"); + BlockData leaves = BlockDataRegistry.getInstance().get("Test:TemporaryLeaves"); + + world.setBlockSfc(center, log, false); + + VectorUtil.iterateCuboidAround(center.x, center.y, center.z, 3, 3, 3, p -> { + tryToSetLeaves(world, p, leaves); + }); + + VectorUtil.iterateCuboidAround(center.x, center.y, center.z, 5, 5, 1, p -> { + tryToSetLeaves(world, p, leaves); + }); + } + + @Override + protected boolean isSolid(SurfaceWorld world, Vec3i surfaceBlockInWorld) { + return BlockLogicRegistry.getInstance().get(world.getBlockSfc(surfaceBlockInWorld).getId()).isSolid(RelFace.UP); + } } diff --git a/src/main/java/ru/windcorp/progressia/test/TestChunkCodec.java b/src/main/java/ru/windcorp/progressia/test/TestChunkCodec.java index 0f4dcd2..caba6ea 100644 --- a/src/main/java/ru/windcorp/progressia/test/TestChunkCodec.java +++ b/src/main/java/ru/windcorp/progressia/test/TestChunkCodec.java @@ -93,8 +93,6 @@ public class TestChunkCodec extends ChunkCodec { ChunkData chunk = new ChunkData(position, world); - assert chunk.getUp() == ru.windcorp.progressia.server.ServerState.getInstance().getWorld().getData().getChunk(position).getUp(); - readBlocks(input, blockPalette, chunk); readTiles(input, tilePalette, chunk); diff --git a/src/main/java/ru/windcorp/progressia/test/TestContent.java b/src/main/java/ru/windcorp/progressia/test/TestContent.java index e65ae68..0c78b35 100644 --- a/src/main/java/ru/windcorp/progressia/test/TestContent.java +++ b/src/main/java/ru/windcorp/progressia/test/TestContent.java @@ -140,6 +140,9 @@ public class TestContent { ) ); register(new BlockLogic("Test:Log")); + register(new BlockData("Test:TemporaryLeaves")); + register(new BlockRenderTransparentCube("Test:TemporaryLeaves", getBlockTexture("TemporaryLeaves"))); + register(new TestBlockLogicGlass("Test:TemporaryLeaves")); // Sic, using Glass logic for leaves because Test register(new BlockData("Test:WoodenPlank")); register(new BlockRenderOpaqueCube("Test:WoodenPlank", getBlockTexture("WoodenPlank"))); diff --git a/src/main/java/ru/windcorp/progressia/test/TestGrassFeature.java b/src/main/java/ru/windcorp/progressia/test/TestGrassFeature.java new file mode 100644 index 0000000..3689998 --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/test/TestGrassFeature.java @@ -0,0 +1,68 @@ +/* + * 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; + +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; + +public class TestGrassFeature extends SurfaceTopLayerFeature { + + private static final Set WHITELIST = ImmutableSet.of( + "Test:Dirt", + "Test:Stone", + "Test:GraniteMonolith", + "Test:GraniteCracked", + "Test:GraniteGravel" + ); + + public TestGrassFeature(String id) { + super(id); + } + + @Override + protected void processTopBlock(SurfaceWorld world, Request request, Vec3i topBlock) { + if (!WHITELIST.contains(world.getBlockSfc(topBlock).getId())) { + return; + } + + TileData grass = TileDataRegistry.getInstance().get("Test:Grass"); + + 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); + } + } + } + + @Override + protected boolean isSolid(SurfaceWorld world, Vec3i surfaceBlockInWorld) { + return BlockLogicRegistry.getInstance().get(world.getBlockSfc(surfaceBlockInWorld).getId()).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 new file mode 100644 index 0000000..5ca923a --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/test/TestTreeFeature.java @@ -0,0 +1,103 @@ +/* + * 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; + +import java.util.function.Consumer; + +import glm.vec._3.i.Vec3i; +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; + +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 iterateSpheroid(Vec3i center, double horDiameter, double vertDiameter, Consumer action) { + VectorUtil.iterateCuboidAround( + 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, + pos -> { + 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) { + 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); + + 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; + for (; center.z < start.z + height; ++center.z) { + world.setBlockSfc(center, log, false); + } + + 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); + + 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); + }); + + branchHorDistance = 1 + 2 * request.getRandom().nextDouble(); + } while (request.getRandom().nextInt(8) > 1); + } + + @Override + protected boolean isSolid(SurfaceWorld world, Vec3i surfaceBlockInWorld) { + return BlockLogicRegistry.getInstance().get(world.getBlockSfc(surfaceBlockInWorld).getId()).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 1f69e00..6c14a2b 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 @@ -26,6 +26,8 @@ import ru.windcorp.progressia.common.util.VectorUtil; import ru.windcorp.progressia.common.world.ChunkData; import ru.windcorp.progressia.common.world.rels.AbsFace; import ru.windcorp.progressia.test.TestBushFeature; +import ru.windcorp.progressia.test.TestGrassFeature; +import ru.windcorp.progressia.test.TestTreeFeature; import ru.windcorp.progressia.test.gen.surface.Surface; import ru.windcorp.progressia.test.gen.surface.SurfaceFeature; import ru.windcorp.progressia.test.gen.surface.SurfaceFeatureGenerator; @@ -41,6 +43,8 @@ public class PlanetFeatureGenerator { Collection features = new ArrayList<>(); features.add(new TestBushFeature("Test:BushFeature")); + features.add(new TestTreeFeature("Test:TreeFeature")); + features.add(new TestGrassFeature("Test:GrassFeature")); int seaLevel = (int) parent.getPlanet().getRadius(); this.surfaceGenerators = AbsFace.mapToFaces(face -> new SurfaceFeatureGenerator( @@ -59,6 +63,8 @@ public class PlanetFeatureGenerator { } else { generateBorderFeatures(chunk); } + + chunk.setGenerationHint(true); } private boolean isOrdinaryChunk(Vec3i chunkPos) { @@ -72,7 +78,6 @@ public class PlanetFeatureGenerator { private void generateBorderFeatures(ChunkData chunk) { // Do nothing - chunk.setGenerationHint(true); } } diff --git a/src/main/java/ru/windcorp/progressia/test/gen/planet/PlanetTerrainGenerator.java b/src/main/java/ru/windcorp/progressia/test/gen/planet/PlanetTerrainGenerator.java index 649a6e9..e8307cb 100644 --- a/src/main/java/ru/windcorp/progressia/test/gen/planet/PlanetTerrainGenerator.java +++ b/src/main/java/ru/windcorp/progressia/test/gen/planet/PlanetTerrainGenerator.java @@ -69,6 +69,8 @@ class PlanetTerrainGenerator { } else { generateBorderTerrain(chunk); } + + chunk.setGenerationHint(false); return chunk; } diff --git a/src/main/java/ru/windcorp/progressia/test/gen/planet/TestPlanetGenerator.java b/src/main/java/ru/windcorp/progressia/test/gen/planet/TestPlanetGenerator.java index 82f0f55..1dbd5b8 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 @@ -72,7 +72,7 @@ public class TestPlanetGenerator extends AbstractWorldGenerator { @Override protected boolean checkIsChunkReady(Boolean hint) { - return hint == Boolean.TRUE; // Avoid NPE + return Boolean.TRUE.equals(hint); // Avoid NPE } @Override @@ -91,7 +91,6 @@ public class TestPlanetGenerator extends AbstractWorldGenerator { ChunkData chunk = getWorldData().getChunk(chunkPos); if (chunk == null) { - getServer().getLoadManager().getChunkManager().loadChunk(chunkPos); chunk = getWorldData().getChunk(chunkPos); } 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 aa0ef6c..69e6d8b 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 @@ -27,36 +27,44 @@ import ru.windcorp.progressia.common.util.Vectors; import ru.windcorp.progressia.common.util.namespaces.Namespaced; import ru.windcorp.progressia.common.world.ChunkData; import ru.windcorp.progressia.common.world.generic.GenericChunks; -import ru.windcorp.progressia.common.world.rels.AxisRotations; public abstract class SurfaceFeature extends Namespaced { public static class Request { + private final SurfaceWorld world; private final ChunkData chunk; private final Vec3i minSfc = new Vec3i(); private final Vec3i maxSfc = new Vec3i(); private final Random random; - public Request(ChunkData chunk, Random random) { + public Request(SurfaceWorld world, ChunkData chunk, Random random) { + this.world = world; this.chunk = chunk; this.random = random; - Vec3i absMin = chunk.getMinBIW(null); - Vec3i absMax = chunk.getMaxBIW(null); + Vec3i tmpMin = chunk.getMinBIW(null); + Vec3i tmpMax = chunk.getMaxBIW(null); + + GenericChunks.relativize(tmpMin, chunk.getUp(), tmpMin); + GenericChunks.relativize(tmpMax, chunk.getUp(), tmpMax); - AxisRotations.relativize(absMin, chunk.getUp(), absMin); - AxisRotations.relativize(absMax, chunk.getUp(), absMax); - - Glm.min(absMin, absMax, minSfc); - Glm.max(absMin, absMax, maxSfc); + Glm.min(tmpMin, tmpMax, minSfc); + Glm.max(tmpMin, tmpMax, maxSfc); + + minSfc.z -= world.getSurface().getSeaLevel(); + maxSfc.z -= world.getSurface().getSeaLevel(); } public ChunkData getChunk() { return chunk; } + public SurfaceWorld getWorld() { + return world; + } + public Random getRandom() { return random; } @@ -93,56 +101,6 @@ public abstract class SurfaceFeature extends Namespaced { return maxSfc; } - public boolean contains(Vec3i surfaceBlockInWorld) { - Vec3i bic = Vectors.grab3i(); - bic.set(surfaceBlockInWorld.x, surfaceBlockInWorld.y, surfaceBlockInWorld.z); - bic.sub(minSfc); - boolean result = GenericChunks.containsBiC(bic); - Vectors.release(bic); - return result; - } - - public void forEach(Consumer action) { - VectorUtil.iterateCuboid( - minSfc.x, - minSfc.y, - minSfc.z, - maxSfc.x + 1, - maxSfc.y + 1, - maxSfc.z + 1, - action - ); - } - - /** - * Provided vectors have z set to {@link #getMinZ()}. - */ - public void forEachOnFloor(Consumer action) { - forEachOnLayer(action, getMinZ()); - } - - /** - * Provided vectors have z set to {@link #getMaxZ()}. - */ - public void forEachOnCeiling(Consumer action) { - forEachOnLayer(action, getMaxZ()); - } - - /** - * Provided vectors have z set to layer. - */ - public void forEachOnLayer(Consumer action, int layer) { - VectorUtil.iterateCuboid( - minSfc.x, - minSfc.y, - layer, - maxSfc.x + 1, - maxSfc.y + 1, - layer + 1, - action - ); - } - } public SurfaceFeature(String id) { @@ -150,5 +108,59 @@ public abstract class SurfaceFeature extends Namespaced { } 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 + ); + } } 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 ade7869..9a3c909 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 @@ -46,7 +46,7 @@ public class SurfaceFeatureGenerator { SurfaceWorld world = new SurfaceWorld(surface, chunk.getWorld()); Random random = new Random(CoordinatePacker.pack3IntsIntoLong(chunk.getPosition()) /* ^ seed*/); - SurfaceFeature.Request request = new SurfaceFeature.Request(chunk, random); + SurfaceFeature.Request request = new SurfaceFeature.Request(world, chunk, random); for (SurfaceFeature feature : features) { feature.process(world, request); 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 new file mode 100644 index 0000000..5947950 --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/test/gen/surface/SurfaceTopLayerFeature.java @@ -0,0 +1,58 @@ +/* + * 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 glm.vec._3.i.Vec3i; +import ru.windcorp.progressia.common.util.Vectors; + +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); + + @Override + public void process(SurfaceWorld world, Request request) { + Vec3i cursor = Vectors.grab3i(); + + forEachOnLayer(request, pos -> { + + cursor.set(pos.x, pos.y, pos.z); + + if (!isSolid(world, cursor)) { + return; + } + + for (cursor.z += 1; cursor.z <= request.getMaxZ() + 1; ++cursor.z) { + if (!isSolid(world, cursor)) { + cursor.z -= 1; + processTopBlock(world, request, cursor); + return; + } + } + + }, request.getMinZ()); + + Vectors.release(cursor); + } + +} diff --git a/src/main/java/ru/windcorp/progressia/test/gen/surface/SurfaceWorld.java b/src/main/java/ru/windcorp/progressia/test/gen/surface/SurfaceWorld.java index 740cc50..12ff59a 100644 --- a/src/main/java/ru/windcorp/progressia/test/gen/surface/SurfaceWorld.java +++ b/src/main/java/ru/windcorp/progressia/test/gen/surface/SurfaceWorld.java @@ -31,8 +31,9 @@ import ru.windcorp.progressia.common.world.tile.TileData; import ru.windcorp.progressia.common.world.tile.TileDataReference; import ru.windcorp.progressia.common.world.tile.TileDataStack; -public class SurfaceWorld implements GenericWritableWorld { - +public class SurfaceWorld + implements GenericWritableWorld { + private final Surface surface; private final GenericWritableWorld parent; @@ -61,7 +62,7 @@ public class SurfaceWorld implements GenericWritableWorld getChunks() { return parent.getChunks(); @@ -76,37 +77,50 @@ public class SurfaceWorld implements GenericWritableWorld getEntities() { return parent.getEntities(); } - + @Override public EntityData getEntity(long entityId) { return parent.getEntity(entityId); } - + @Override public void setBlock(Vec3i blockInWorld, BlockData block, boolean notify) { parent.setBlock(blockInWorld, block, notify); } - + @Override public void addEntity(EntityData entity) { parent.addEntity(entity); } - + @Override public void removeEntity(long entityId) { parent.removeEntity(entityId); } - + public Vec3i resolve(Vec3i surfacePosition, Vec3i output) { if (output == null) { - output = new Vec3i(); + output = new Vec3i(); } - + output.set(surfacePosition.x, surfacePosition.y, surfacePosition.z); + output.z += getSurface().getSeaLevel(); + + GenericChunks.resolve(output, getSurface().getUp(), output); + + return output; + } + + public Vec3i relativize(Vec3i absolutePosition, Vec3i output) { + if (output == null) { + output = new Vec3i(); + } + + output.set(absolutePosition.x, absolutePosition.y, absolutePosition.z); + + GenericChunks.relativize(output, getSurface().getUp(), output); output.z -= getSurface().getSeaLevel(); - - GenericChunks.resolve(surfacePosition, output, getSurface().getUp()); - + return output; } @@ -117,7 +131,7 @@ public class SurfaceWorld implements GenericWritableWorld zaB^>EX>4U6ba`-PAZ2)IW&i+q+O3>va%8)Xr2lgjwFJ(?ayXjx4tn|hIT@i;-uJ4k z%DV25Qieh&cnHAZ4uHq(|NDQA`H%nj4`*AoCZ`u)?{c>jEV z`TorP{kr-2f#;>b*YN&Y^XK)=>z?=f&+GGZozCm&*M-{t{9ye3gZ{aYub&V2y#D>5 z;NAz=&xK9@TqyX@C&%~q@ovlJR?F{On4kBb&(H5R@W0U?F%+Lub|vy>^tP1T_`Z4@ z3;VXT&@+A0@1^m%&_DiezHjxc$?xET< zlXL$05?f zN=QunXyIgof2V8CW5(m6Tdup~_We5DWQoylU-;_%#JJP&V#OHE&miMQ{p*e|p@oI1 zeVDjI;8p*#7I#0k-H)4u*s{x2gLgPCCeQf)`q%t--gJ%v$~jwq_KJ0RMH;J+<(xCt z@ir{t&Sz88-Qe%P|NKXG4OlSUZLZv4w?kLJ{3E$P&K0hq18+=xeF5ys`dol5Vg-rC zxPS$0b|Ja!Z1LU{=h(=KfjUd~A^L$?TuOeiNFPJU7>6j}v-zFk?puBG?`41xL!^)m z0a>w7$5=5Y{HMf<5A_sMOey75QcW%O9I_%T=aPk}y@V1=D!G(WODo;fP-9Is*HUY3 zwKv}ah?^Sm*lKI7cRsXp<<4(+-q8E-BaArG$fJxp+UV1p8D^Ym=2>Q)ZT96?Sj6$l ztE{@(>f3ExX~&&*-euR_c0ah<2`8R(@+qgDW={XH+Q+Q_^6&q^YVKn-e=VgqmLIF} zYAN4KIKfGh&9In{4ucn2zy;&IY-X#A(aUnOnQfk^NS;L|8D}|J3=78Xd^+yOc7H6F zOvwK`b~6~l|8H2%$aMb=%l)g}{+-oUzlknf3n>h>sWuROys4j%POa%2?@kS8kCn>d zXVI5Fx4x^X2h*3nou}`1^j+EOeyyX|b&_vmrp$}0OzcqnEN3)jQh?2tux4Y8na!?q zcfyMs%6+nby_GY|=(^b0;b5G}-(p(6OpmSmS}UZH=3JPp_L`%`4ki)07=KN7QeUj9 zrc}DH<*ePq;pQBF>NhI;*wS*odwx`p-F=Pa#@S&mqfg$0-`x0-GC<4gti!qjueroM zRevTKH*c)QuY`yx7G_%$!eHy}cSXJJJ@!fXS*|sY6xtX;mrrbmeqp2)@>uxd0G{_u ze&^NmXiBsezl(kLXfhyFhOZ~~U9_QGbh63*G`5d@o74B=`SIi)mSw48?!WBm5)3Kr}8#Z!g22p@K z{IO5&ZuPPqnQ+!#3jUMWc==SvD*=#&Llyj0CaGZU9BuhvVrYHgCf*TAqhqmE;BWK9;1FXO-fL}X5Tu&l}jSP-2g6#%mK#bxD_bl^i<-tD|`*cHe4Co z1wNv(Ms4kmZ)+Xz9B!31$_#sXzlio#c4^=l7*pkxXKqqmUDMQppZ2kQ?j2X05wmi; zv&iF)^ZJCCS$E%&$ZLJqGiN@)?40Z!<{-|A_!PVi4Ijj@6e&e+w2Gvfx_2sj!-;_Nf=V0kMG&LI8@9kw*Ze+kId z3Q$*i$?R5~rf2*J-XC($XVkDqvWv97c5G~Y5`TgOmg+EquUI@b5-Ynya!^DZVII^E zx~BWeY-a)T{MlSSg8_T8BOVD-LD@uHCZSeac&3{tj~6JrUROyA>UVrd6`TPk2#y&u z*2Aw3ur}~)J|TgXs||Y*v`01@m`-`c))OR;eBhlab0^-NmL-Yw3IQZcNg0Fq1(mA} z%a*YUtL7KVh0mc+DTgcz2u3iE#hSHtCAotn>?NScmibY00{_$Wq(9gsS86BA@IW0* zw%uI``{0%b0KR*42qwVW;^(q;+bsbyKDpu9=SW;*gqtY}Tl^BmOk8rE`#Q0*_>5*+ zSwt#s+eTd6b=rhEp$Gu2Op5aOG&%=2f)!&3ejPv{Y$ri^(-Nq%YB0)E?USdpdi)E& zjG!d;DKV~1#JRZY9u8CBHTmeKNvtsL)?A8q0<&h%cnI>q{R#Yf$HKV*w`A>+SqBTj z%SrKmoP3d1e%b`Hd2*X%`nyN?F_;6L@V=}CT8`A_>UU9{Eg~L{-*pujXiY#?X7_Q{ z3nvP$!Ht9FkcfEEhOJUCY&NxHKTtN{P~1`Q`YN!;h@+5)1DpW+oofXQkTIfzAJw?J zGBUS;^~w7M@mOrYAz2W2yUR!~$Dao=9W(3hNaz9C7f}S!Oxpt z;Nl^*HbD!U3YyI{z#}*cZxoG!7{T7fZNBd8aL*+v;`7}RU3xrv;qHgl&Rsa|Dk&TP zVK2NR`O1%PXx2!=y6b2g+~$@9bkKWd8=;+S`swwh=Y^+C zQvMlGbzuyy?evFu90-UX4IvZUAdg|$B{l~1+ISK0+y`h?*ujb8RTkjEF7UBM2! zL?;JGwcuMMc;o{x;6Qu%5qd3g!}jg-k~}C>;T=s2|~;V#^!25G~v9&y<<(V_yns0$vvim zOOx68%G-$i;5JcM@;5LGZ+Y@}WtK)Oc{ zp{2wF;Q<0VTcVMv$tX3f-KJv+v1E+vdrwPz#EFlLA>}q&a$psAjCx#<=XB-Qxd?4Y zs`bFqm&6s}TPI?FRChvI77|iO^Q>n*677TBm{g2ebFUF9y%Rim7PIZTMA#L1$=Sb% zFp`2uQBWKJ@(~;YVgh_v3)y(0s0>P##9`{%8w&4p5-D!!l42MwDg;B#6hcnQFnJ+e z4l#!2y?}E3^&>=f!lm(Sd@F4a@+~5j%kNE)aXmn4llp#0vC<##yqpw9&fMH3#PfM> zFcA2P57z(OYaL2~oJc+wVMR6KZ^+CLCFF;s2TlBG=d&_Z(N8&B$}1{?#s=J|KZe_8EACOrjaLJ3?BUzrLQIuVX2M zTX9{e46iDHzm4Z@UVMlHd&(^yxC4+KNRxi+T7c4c@0$;`t(Z%2{9Z<14l~2ZjYUX& zpyi46qUZtN@DV>T5(r*knh^gg;wC465pv57s3PP+NKnf_lu`zdGq_l{^@Q|*Qez^b z12c*y=pISZD8QIoXXH5GB~kKJd!NR8vyzA*v-XgODTy#z+x`S)i6^+dyKlos{F7 z42YX2Lm)#Zb;mAlnVev_VG{M@WeH2zQ;0*m3Qr;WYbePf))Uyd(LkUgv<9&8kVJB< zCxbcgJQkurS```zMxQDX>%DlJ#L?xjyIRSpk(>nKM)#P_wr~q# z1#N)2ky8>m+9H}HW>ZU&oY!64#~nrzy8 zX%#D~H&ky!)Iu7QpNTN$M_F_djXBSNI>3oZ*~rOj2UN3Dq+?m3g>Ghn{ToINiW6@0 zZcGmuG9F1B>UNMMqAW5yG7F9d$cTZX@<`FesaN81FP7Zysz6!=;cx;r;%|PdfIzZ_ zjkDLvQllF9B}oi)Ya|NMcxV(~#AO$#MY>mQQ&yJWxi?%Vro6wJj+8=!d`WY`vyYX znWREyJ0%u&L%=j58Z|k{x|b#oN?TBA+^pZ;!7jVwoB4N6zttMV$%+I|Y84vHYcTEV zRU6{26;WlEO9pof^R33)^?VPvevTPCp3UYX(Fq+bDn#r~99PH;5*pS52H=|s8Ueyp z(63p1JZY;%?{BSYk!g{^2@+Npp}$F+B;A*Q?B8Td)hd*1DH4BTJC$Xp=UD5O#R`$s4f{ND-sL6cA~q<)q@{#M8Mh)D?!e$lGINaulSe30 z!(9TsN}<6=|gE7q>;SB*Q2^FDGCrEi|`w)Kuux;O`7s(*!#;6@LP!U zzZ9B2b*6$7+ya|GlsKc&Xib=8^0rCDPUX~LPhMJOAkprsdAIp8~!a1h# zD)Q;plMD%L!oi_lgOn*6_-ZmJDj3}j&(rQJs7HxJfQ!{(YVx=x-?GLPPYnz{N9r#SK3fqhh*g$cyNRRNRs!YVN9}y&0^F~s1i;SZVJsxInUaGh7`R2QTp^fUnipWQTSl-ja%kJpFjl{&;pX$!)Zk%}l(sQ){yv=}W z>baEW)xRouqOY%l#&xgq+Y-tkp1v95(NPk|U zkk|Go4P5S{UZO#v#7-Vo$S6gT2ltw%1#z!iVul>RCL{^)E4UJJO$#oP_*>wGd?ES~ zmiz#0(e~Br`B;=q!*QV(B|^tnp8XcwBbtdA3u+$#B7j8OGY@WfnTVcU$zR%gL$V0* z;r+liyW*iNH{m=&r;vD*?p7va>Z%Tt;*zN_ShWe*8avdp6PSGJVqIOop_-stTf5>- z+ytMTCoFW5m4dB=W3jLiHIim)2s9LOfuUec7DkY;5O&pmiZf)f+ip7UC8AFT&j{GW zkD^h226c)G_~`2x@c#t!|G>r|GrHcN@2m?fquxp#9<^~t(kVJ(Y~#E*2tz|Ri^;_F zE?xY+S9U^pNZfWgg|tTuo4=3~k`-=npX2985XzonBSRa&KEUABlL<@c8p##tQP&_S z;2R`FH8KdwpH}McPU;|Sk${j{73Q99{Vc|2!OK@LWEa&NiQb>92XT1;vI@g+87MTN zRJoDBop2-E8jkR9i%j$3qF?z&eE|M~s^RHnJ<{0>Zd*re^LYz(L|`Bb;oHD3zy&ed zRTWj>hN~@=ue0(o`UzR@&zR4@NNwaaJP<-zvpG?}@6mE{UE&G#>p~F00U3)D}R3YR}hXCPKOSAZtN8b$L9X&ibD&W2CJJN0cypo3WT zUPBkI?X1R;Bfj{3yecJ?)CE)GOk8+_nn6?U?5!bDf zYqz^Ze2EF(n!A6%rUAJQymqA6sR7k7lsbtyh19F39nFBCdDe|luEu|*3JJ%2tAvd# z)eVn2xC`SPl{R~IFPH>(8ro3%CJ9q}o)KoqnwIRZpz6c}s&^R+M=Ne$?^WGAzM7so zDv}VW1*jq4j`D8hfU-9X&LuRg-UGxNqBX^`+A5$X3{^yH$2*KAfMO#{yA`OY_WDMm zlHnj1b!fa}LSh8&e7a%VvQ?$7E0j<6@zWogSGKd|FcLYbSCtZ85f;mC8drELd<`WM zhL$CgSene5s;@sja(h{9aJZqGplxwhgu&vifdJ`9M72K zV0@a-AoreOfAZJ56dF>3FgLy;i(t{8@)7u}I?!a|67!sbPfk@#K0*tpe zO#&yC>fxsu75eSIHi-F4`dOIg1-rAy(+p5V%b`{_>tBd4$s!;i7K6d3{0gQ%^Zb+h_P8c0+rOrP!JN0qP#99vVDl; zrmfcR9Skvjs$VK@LB7gCozhRHzjGnvD)tLsmx5Cr5>Jl*t_5sf4|vDOZC5fBi8j_~ z@0iDs(B>-P^>E)*6NzdyiRB61%}xUa7iuTW#0?~`$|$Wvnh~#T6v>3V&%Q%AQGuKH zb!pHGd1|stFN#9LTI8I@I?N1jf`;T0<=H6Cjc!+GS%no}l#A8+xbuA)IgB8#28(id zy;!1fnxVS33b+nn;!~O$kZ^z`4_7~|p}V3OT5})^++bFlT|4o zV%C(QjwXV{`+dI6B(&pacmUoqeKMQfQELXV(XwV{5H_SBLUJwuvGb!_1w~e*quD=F zgS$Cr-I^%C*|1YFDraTUvz!2DOR_*dSR5Z&&X$h{9AqW?h}RH65;ogw9PM@)!S%5; zfpELqP$1N2QnPF3*H?F{3~99Ltw5vJ2}Yt4y-X8PWv6ItMDoRGD#TBX(}0Xb*3qqy zk}ytDTd$GFi}Xo(y<-$gcnW1IZl)-CA#ThDUsEfZ7s*j2JH&F+$dp)zrlp4Fr6Bqm zl(IMJlTAT#buQj0-7UbHN4a|vLDhT&pTF-|!>1L%9c&*O3>#?wbe{Jwao<+5=%HXN zu!kr7heMo8pNBs_Z`>($C_1Z0B5@O zPSP~-HutAu`!lxm5hWvac{^&mo70Ml8QqcyB@Wf0f+RvQWo9T&Wq*=up3l_`=QVy{ zXOCtvl>qAPs+)Ry2N6VbI!XYMB)88Lhxc1VP7}p6L+iNW3@a=EMPs#O4JFkW=?uO+JE{5!3E5I{X)f9oB%kpj9 za%8y*&uXgHX1m4k9H9_6$F}Pba*tcll*w9e#I3@J)b>Z_Q z3ffi^9`itKARoq-P(3_Pw%^ati zxy?urr689#nX0SzEF!C#pTljkS3Mab6yLtUK1l`;r=ffbCQ8%7fPv4DJZuIm^cj~* zL}S8jx(>X!00HgaNvn_gPPdb(!n7MIvKocvsYF=t%Rhwp1Am~v2~yovBgOSqv_vuf zb?nNhTLQ2kuT;f}>oW{2yN0$X<;{2yai8f^dqK|X)EhB_mo;!=3o9nC2I(`Cya$mb1F_wSNYrk5-w1o^#eG)B4t zoHk&6sEv)uY62T7bc0(A%$K6FkwymRKSl=eR|$C%Bpee%MU`ZwH8q?RUNy7rH}8+z zWOq*>JTWZ91yfPnQ@!`2Vrh07Vn)4L@e_7us$o-=MF#RDp!&c|KhUQCxZiiT_g;HP zUELY>(h7eguZzxe_qg_e1?tq3=3f1sdo3whwavnC7jcNNKh=9yX_Cen;~jHu6<89- zMS4MJ3B4_v{3V?o`JwWxjjCw2d+o6nncLknlZ+^Z>t!sXyzh1{F67+8n2{xw^g~pVMZJ_d;0p16k)?jgTOCnsr zh>CG{8WLciiWcv}rE?lhxZ6p}%L2es^d_ z(ss9~kBew98kmus&f(4Y)=vzU`D)DYY|JQJIX{KBtOG58K=2aza?TB?YtleI00Tx$ zcJZF9<5aWaXO2W@7CWdJJCesfmr$Vblxw^2w5rSt<+^h1Lh4pcc}EQZpmmk|d6S>u z5j$98d7n(vIl>S<_?@bVoyqS;5MN~SenGeV_m1_i3fEf1+7 zwwyGxKBHo8+X|haAbsajx37@yaE}z)^?LCZ z8wW+OQS}7N)FR1q?wl}M?o~|O?U_Lw{laOun=b`=`YgRkHT$k9!KR(LBWT+-$fOTdb>oNh^_0&MhFbstg-I?7Us7v2yVTz!U`Vg3(u*-@AZBQ>F>8{~IcWC-axhU<55j>! zHL>D)HNY}w7`;*$!(g>S$1(ZEJt#6*# zmj?Th`z02goPu*z9jsCv_|8bde9#IIKzv?j6f}kN8H`!#Ws|*NWVyFHFBz=*hM>W4 zZRv2<_|8PDNQ$r{MZmrA^QBhKKxeD(S4|$0@= z-oLpR^CqrzoXuir`v$Il=B-pl8yaO5{ir%mqS2r&0z@D-)TN^!wKFJCFSn|{ zCau&lfJv{WsmyP~SRDOows3BXtUYA!-jHH5u9li+VzQ?Abc#<3GD!E|S*w%QNUDc( zgG(nW8tJtE8n&u$YD^l+NkVFx6_YmQImEz1+-rWRtAbwDXn8aQ5~9;SKEG2x5bb_N z&DiPBxrU}OL41-ZZyK@kI`nsJhR5q%QO<=uN*sdT*cq>i&xCw z8rF44OBf1k{Flj|Pbc!Ge#9?~6+c2tk%YWj*{Y#PYAUC%d}VN+Lc>qHL(L7ivT`SY z5Tm+J5L|YyneE=pgVJBDofTY)Do6bDniA>Om1{i^u4QyOWN+(y{PxTC`HO|%a^_23^vgF5F6Z~zv5 zSb}bb7^Q)MG4b{B*~{KaBt{|9WYJ9qD9c3PV4XXX7WBQEW-LAGjNcm!^$@CXyDFd4 zzy9~>-`-UUaNVe&4nt%iuNI=wgV$Rt0uOiKppvF+QBqSyNB+|IvP}nR!AWW^25Ohd z#%}4%_P(>1B>*1;g&q+QBsPX1K&N8%_gG$uKC2@X5nxZ{nm31dncO|=rbZT|_!hg@ zcMJy(;?!(Jjced)B@O(la-7vwhA+oy>aSs{eP@ar_y(H-QLNGvON#xD<2#^`n`F;a zq4Ve3Ey>x~-|LXKKl-6la32+=H5~`Yj`ZMVs$%Lid-ZcXMe(3B9X^5e))^8UTtka5 z@37}RLW8PRHw=zXN>6{LafTZA>C@F!RhRv5_r#SEZxF3W8l2nr438)A``ZIPTfQXu z4NJMRNSY!Vb*nx}@(}6Xfef*LT7*&2jKbp<8`O_;?5tzDApgE&^g4?B>CLngKTXm3 zori*k)?#KF&T23+}`#l+z34=ZNR7i6ZX>QrBCJgM*U`$U3aCs72Y>c}Y= zpEVw;U|rH!8n6M-xrqH%behHm1L${I1eCI95Q`2bBTeKkerqK#jXU&nfX!0GErXzv@@LEt>;hdXKu&Z7Bf>>iHI!lEK zU~}Y<+s>NE2ZI#$D%`&r<>EBZ%*VB4+0~-CEb;`-r&^Nk@s8rGtdSBh&*^lXrsmje zR2{5Fokgzrb9@ftRCS(_biyZ=4r;m;(%ZT8~~5>`E`4yqgvWY=Hi z0PzwHE0VIK9+r}t&JyCMlMEIwI^J{r+}wHR+T$CtB-KB{k@@zd5HwC&HMV6I6duD_ zNO*uZ!{$JWrU7C8XpO6U4{WFo7s}HC^>f~*+_F$0kC}t}=8c5VoP7ZmBa*liX|}_H z0&2bDKPX>t82r(hwB)KzTX#0sX#ieW>x_E$8k5(gY1ip3SO0l917BLZ)@^DY^_0~CZ4;Ux{Yz-vxykm<(<<%(XC3h;>Fd}4xfWndO_hl^VQ|+5 zZNa&?%oM*Q`@?5M=Fy;~nOj&x@~ChW*&5tg)8g-7q@E-NLzmPZK*t-fyBV$Dj0Ul~ zr3JseIrljpnptVmK++umP$$OJ8BrHZYC=0h}Anf_vx{ zK#BNlPg#iFeYqX@h~LFMHEI#=s0GOSIks_&QP4E3=DjNN@Sy~oDS}zvxvHqW>C>{g*3GS zpQ{o5Xr#}xPP0pI-NxnVfV(0gf!S5wAtbt3spCKAbKE)91c3=dPv1zAqS#OQGLFw7 zlkpw)Zt7(se{}pBF0I0ns@*KGFK=&`LPMK+BoFssAP4sm3{p5MBmQ}+Pa_~zYYRbh z>){?S;F>yK&~F+adNpgpJq530u*hnDi3AS0wzGrqaqA?``gkszKBfp1mV(-4A|@Qo zyrJ@xLJA)|%{>mLu{w3BXCK^MBVzi|t+TBJjvBX6wH3k}xH9Db?^*v9V)Zk-ve+ecogh$T5}>UbH8?t7-&TkA^_MZWnJ6biL;cy+dW>E)AZ?du+7(dB5V(E*(5c z(-p(SQT3o09VAPd7DaulqPY5f;*^rlJ1*e<7QbT2&fWQ-_e?DF+PW$#@>wc5wH0t? zlm#iUX;>(|xu>CnR=ghHi6J$Kl?-%FLil1rCUK^sw5&mis&mYmaVT%ZA*!X`bYKVK z$gim?qKV);fWW1ctQM)-8_SO0)xr_SJ8N(O<91KL7#%!vI#_p>&vzhbqZ~d1L7=Ff zxbzu4*E6y3Z%{LQi>dn^^KL)KykVqAe%iVw%oWUFE)Iga4bs^&nT9+oc7F~Htam<) zJh9cX0deN}l^PLSvM1|^LxX0ui~QX2Nb}|+vk1J}qDK+7L>f3RP!R=$s_+N-2Jvql-@Nfr%4Gtj*LW7JQgt0g5zf_&uPe| zu7L_(x6S(ZxivxCorNUD5PlPcgwozFrYRpHs0W3hhK{DbIv$@tLFN1(nlX#H2-k7v1#y6(`~anK@EDP=&c_9AQ5fxHaNKuGIn)r1=2cd z;59}sCR=ZF`U)3ub;Q0%8`4Je-hD{TSv_B0IYN7+Qy%~T00v@9M??Vs0RI60puMM)00009 za7bBm001r{001r{0eGc9b^rhX2XskIMF-^v0uKxyxRo)^0000PbVXQnLvL+uWo~o; zLvm$dbY)~9cWHEJAV*0}P*;Ht7XSbUXGugsR7l4)l>2jBbsa#@=ezgrBm2l}lQc=w z+N2>((>A3qEEE+L7{Ebblma3uBM*_5XL(4i5r$67Oa+1kL{X-KGQ|M}2Gn8f@DN*p zLYe?g+NMeKVw2s?zIX55z4z-69nU{-emQeQYt4@Sdl(%b)#=#+J*$>Vs0}?Go51H* zQ?8_$8MJwM-|O<=zO8!4b^UVn&6nvvKmAwP_3EAa@M|XtM!lq_3!HoLnNrSbg0%)m zVxQ{RdpXqg_g}5sR@CwQp1;VdHOpkzwtfOeog_c^Fm+^}k@r(ng~L4c_g$286)ySy zh5DRJ)(JqVsBtU@k5VjJ72){F5nb`vOr&RZXS9vB&M2yswHO>etbh5;?fT(6e#OuB zZPl4dLN~V6N!6@_CE?7kAUQ`B6!y)3kTD%c+43#f;1F zz=$@(a4b1Zu~X|>D_$XAOyD(59G@nv{Y)KlSaen$dtToGKA4J6XaJ8VK&9dUu>be3NcV!(l9^Pv z7AUP;UijrJf+a-HG%$T8o9+mdGC|OLKR%Rsh@f-lF}jWda7^ z_Yr@`ARGyE(Iw|eq3lqc@G?9+LRHu=I$K73ip~{FaBV&67-~h^!0n?&0_J`qi7nXIAiM)^$ovQ;;*dy5yRz zm&?F^KGL?gj5_$%A?+04`?cr3niQ^lLA^DF8P;bhS3> zh1m~^gu1-sMvK%g58;L^mV`Q_oU`@xa2z8y?vOr_$Agz8XL(7aEDpSRK(}<%W7`h) zQ4jU2lQr3l8n1eB2QOla?XBiVEs=YZmv0hYlrIF}zMLu5yAn2$H$KM${ zy%w~M*S7H+CKqqMP+LIe zSad^gZEa<4bO1wgWnpw>WFU8GbZ8()Nlj2!fese{00JpVL_t(Y$JLb0OH^SLhoAS( zojc=vs3Q{vWvC^&X&ua>FP8~Hxi$#tFNhYkiwassxQYtJvPBRsB5)xslC~zIIO?c_ zALHma-0{xmz3+Y7xe0A_?#AEtJ?A|9&Uw#)(=Kt`gl}sFW%@LPE)iwPKxdoq1n?nU zRAEChziF|QUuCp6QCF^3PtbVQQt5nwO9C>xsk)2T<>1p+QKig1M5WB^+7@5#-Z)lU zk96>P&r#i)gK0VtZX%%jk3Hlg0a~fb__j$)EX2(062o^A!ZX0fWKR7~Wr#{YZp9|* z51i$l>PorHM|GU7Bed1*z8&kVa*`u7pyKPc@dmLL|bU8IYe$h5GQu< zviqDUmK4p+2BE0pen*U5p(BN0ZY5V&@&9h}z}H`@{Yn>IZLKV9W{@`QY_2oXf8D!N zF*yEHU2N~fj`)ZuLBY%uYmV`_=e#$^?o}|!N_v6HzRS(9ffkD4mTaC(udC%4( z=G3T?RhyaBEMxI<TeJ;ui?ZDl(|CUr}g=!M%73Q^hhHy2k5{Gomg)eqvZv?F#c- zIc^O;J&2o1t*fCwNdi*x@akpWFQ##E80qU3bvxLe98#_&SgGkG`X31z&_6TSnRugI nEyQfD)^PDdH97WHaa!~j!ua4Ld5*~=00000NkvXXu0mjfkFYs! literal 0 HcmV?d00001 diff --git a/src/test/java/ru/windcorp/progressia/common/world/generic/GenericChunkRotationsTest.java b/src/test/java/ru/windcorp/progressia/common/world/generic/GenericChunkRotationsTest.java new file mode 100644 index 0000000..ef3d4c3 --- /dev/null +++ b/src/test/java/ru/windcorp/progressia/common/world/generic/GenericChunkRotationsTest.java @@ -0,0 +1,83 @@ +/* + * 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.common.world.generic; + +import static org.junit.Assert.fail; +import static ru.windcorp.progressia.common.world.generic.GenericChunks.*; + +import java.util.Random; + +import org.junit.Test; + +import glm.Glm; +import glm.vec._3.i.Vec3i; +import ru.windcorp.progressia.common.world.rels.AbsFace; + +public class GenericChunkRotationsTest { + + private static void assertVecEquals(String message, AbsFace up, Vec3i a, Vec3i b) { + if (a == b) { + return; + } + + if (Glm.equals(a, b)) { + return; + } + + fail(String.format("%s. x = (%4d; %4d; %4d), got (%4d; %4d; %4d) (up = %s)", message, a.x, a.y, a.z, b.x, b.y, b.z, up)); + } + + private void check(int x, int y, int z) { + for (AbsFace up : AbsFace.getFaces()) { + + Vec3i veci = new Vec3i(x, y, z); + + assertVecEquals("Vec3i, x != resolve(relativize(x))", up, veci, resolve(relativize(veci, up, null), up, null)); + assertVecEquals("Vec3i, x != relativize(resolve(x))", up, veci, relativize(resolve(veci, up, null), up, null)); + + } + } + + @Test + public void specialCases() { + + for (int x = -1; x <= 1; ++x) { + for (int y = -1; y <= 1; ++y) { + for (int z = -1; z <= 1; ++z) { + check(x, y, z); + } + } + } + + } + + @Test + public void randomValues() { + + final int iterations = 2 << 16; + final long seed = 0; + + Random random = new Random(seed); + + for (int i = 0; i < iterations; ++i) { + check(random.nextInt(200) - 100, random.nextInt(200) - 100, random.nextInt(200) - 100); + } + + } + +} diff --git a/src/test/java/ru/windcorp/progressia/common/world/rels/AxisRotationsTest.java b/src/test/java/ru/windcorp/progressia/common/world/rels/AxisRotationsTest.java new file mode 100644 index 0000000..27d6368 --- /dev/null +++ b/src/test/java/ru/windcorp/progressia/common/world/rels/AxisRotationsTest.java @@ -0,0 +1,100 @@ +/* + * 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.common.world.rels; + +import static org.junit.Assert.fail; +import static ru.windcorp.progressia.common.world.rels.AxisRotations.*; + +import java.util.Random; + +import org.junit.Test; + +import glm.Glm; +import glm.vec._3.Vec3; +import glm.vec._3.i.Vec3i; + +public class AxisRotationsTest { + + private static void assertVecEquals(String message, AbsFace up, Vec3i a, Vec3i b) { + if (a == b) { + return; + } + + if (Glm.equals(a, b)) { + return; + } + + fail(String.format("%s. x = (%4d; %4d; %4d), got (%4d; %4d; %4d) (up = %s)", message, a.x, a.y, a.z, b.x, b.y, b.z, up)); + } + + private static void assertVecEquals(String message, AbsFace up, Vec3 a, Vec3 b) { + if (a == b) { + return; + } + + if (b.sub_(a).length() <= 1e-3) { + return; + } + + fail(String.format("%s. x = (%4f; %4f; %4f), got (%4f; %4f; %4f), d = %f (up = %s)", message, a.x, a.y, a.z, b.x, b.y, b.z, b.sub_(a).length(), up)); + } + + private void check(int x, int y, int z) { + for (AbsFace up : AbsFace.getFaces()) { + + Vec3i veci = new Vec3i(x, y, z); + + assertVecEquals("Vec3i, x != resolve(relativize(x))", up, veci, resolve(relativize(veci, up, null), up, null)); + assertVecEquals("Vec3i, x != relativize(resolve(x))", up, veci, relativize(resolve(veci, up, null), up, null)); + + Vec3 vecf = new Vec3(x, y, z); + + assertVecEquals("Vec3, x != resolve(relativize(x))", up, vecf, resolve(relativize(vecf, up, null), up, null)); + assertVecEquals("Vec3, x != relativize(resolve(x))", up, vecf, relativize(resolve(vecf, up, null), up, null)); + + } + } + + @Test + public void specialCases() { + + for (int x = -1; x <= 1; ++x) { + for (int y = -1; y <= 1; ++y) { + for (int z = -1; z <= 1; ++z) { + check(x, y, z); + } + } + } + + } + + @Test + public void randomValues() { + + final int iterations = 2 << 16; + final long seed = 0; + + Random random = new Random(seed); + + for (int i = 0; i < iterations; ++i) { + check(random.nextInt(200) - 100, random.nextInt(200) - 100, random.nextInt(200) - 100); + } + + } + +} From d7afe39f00a7e50242ed3376b7e348bd02027232 Mon Sep 17 00:00:00 2001 From: OLEGSHA Date: Thu, 15 Jul 2021 22:26:20 +0300 Subject: [PATCH 30/55] Added more generic Contexts. WIP. --- .../common/world/context/Context.java | 105 ++++++++++++ .../context/GenericROBlockContext.java | 119 ++++++++++++++ .../context/GenericROBlockFaceContext.java | 93 +++++++++++ .../generic/context/GenericROTileContext.java | 85 ++++++++++ .../context/GenericROWorldContext.java | 45 ++++++ .../context/GenericRWBlockContext.java | 92 +++++++++++ .../context/GenericRWBlockFaceContext.java | 78 +++++++++ .../generic/context/GenericRWTileContext.java | 50 ++++++ .../context/GenericRWWorldContext.java | 151 ++++++++++++++++++ .../server/world/context/ServerContext.java | 84 ++++++++++ 10 files changed, 902 insertions(+) create mode 100644 src/main/java/ru/windcorp/progressia/common/world/context/Context.java create mode 100644 src/main/java/ru/windcorp/progressia/common/world/generic/context/GenericROBlockContext.java create mode 100644 src/main/java/ru/windcorp/progressia/common/world/generic/context/GenericROBlockFaceContext.java create mode 100644 src/main/java/ru/windcorp/progressia/common/world/generic/context/GenericROTileContext.java create mode 100644 src/main/java/ru/windcorp/progressia/common/world/generic/context/GenericROWorldContext.java create mode 100644 src/main/java/ru/windcorp/progressia/common/world/generic/context/GenericRWBlockContext.java create mode 100644 src/main/java/ru/windcorp/progressia/common/world/generic/context/GenericRWBlockFaceContext.java create mode 100644 src/main/java/ru/windcorp/progressia/common/world/generic/context/GenericRWTileContext.java create mode 100644 src/main/java/ru/windcorp/progressia/common/world/generic/context/GenericRWWorldContext.java create mode 100644 src/main/java/ru/windcorp/progressia/server/world/context/ServerContext.java diff --git a/src/main/java/ru/windcorp/progressia/common/world/context/Context.java b/src/main/java/ru/windcorp/progressia/common/world/context/Context.java new file mode 100644 index 0000000..bfbd164 --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/common/world/context/Context.java @@ -0,0 +1,105 @@ +/* + * 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.common.world.context; + +/** + * A cursor-like object for retrieving information about an in-game environment. + * A context object typically holds a reference to some sort of data structure + * and a cursor pointing to a location in that data structure. The exact meaning + * of "environment" and "location" is defined by extending interfaces. + *

    + * Context objects are intended to be the primary way of interacting for in-game + * content. Wherever possible, context objects should be preferred over other + * means of accessing game structures. + *

    Context Validity

    + * Context objects may only be used while they are valid to avoid undefined + * behavior. There exists no programmatic way to determine a context's validity; + * it is the responsibility of the programmer to avoid interacting with invalid + * contexts. + *

    + * Contexts are usually acquired as method parameters. Unless stated otherwise, + * the context is valid until the invoked method returns; the only exception to + * this rule is subcontexting (see below). Consequently, contexts should never + * be stored outside their intended methods. + *

    + * In practice, context objects are typically highly volatile. They are not + * thread-safe and are often pooled and reused. + *

    + *

    Subcontexting

    + * Subcontexting is the invocation of user-provided code with a context + * object derived from an existing one. For example, block context provides a + * convenience method for referencing the block's neighbor: + * + *
    + * blockContextA.forNeighbor(RelFace.UP, blockContextB -> {
    + * 	foo(blockContextA); // undefined behavior!
    + * 	foo(blockContextB); // correct
    + * });
    + * 
    + * + * In this example, {@code forNeighbor} is a subcontexting method, + * {@code blockContextA} is the parent context, {@code blockContextB} is the + * subcontext, and the lambda is the context consumer. + *

    + * Parent contexts are invalid while the subcontexting method is + * running. Referencing {@code blockContextA} from inside the lambda + * creates undefined behavior. + *

    + * This restriction exists because some implementations of contexts may + * implement subcontexting by simply modifying the parent context for the + * duration of the call and presenting the temporarily modified parent context + * as the subcontext: + * + *

    + * public void forNeighbor(BlockFace face, Consumer<BlockContext> action) {
    + * 	this.position.add(face);
    + * 	action.accept(this);
    + * 	this.position.sub(face);
    + * }
    + * 
    + */ +public interface Context { + + /** + * Tests whether the environment is "real". Any actions carried out in an + * environment that is not "real" should not have any side effects outside + * of the environment. + *

    + * A typical "real" environment is the world of the client that is actually + * displayed or a world of the server that the clients actually interact + * with. An example of a non-"real" environment is a fake world used by + * developer tools to query the properties or behaviors of in-game content. + * While in-game events may well trigger global-scope actions, such as + * writing files, this may become an unintended or even harmful byproduct in + * some scenarios that are not actually linked to an actual in-game world. + *

    + * This flag should generally only be consulted before taking action through + * means other than a provided changer object. The interactions with the + * context should otherwise remain unaltered. + *

    + * When querying game content for purposes other than directly applying + * results in-game, {@code isReal()} should return {@code false}. In all + * other cases, where possible, the call should be delegated to a provided + * context object. + * + * @return {@code false} iff side effects outside the environment should be + * suppressed + */ + boolean isReal(); + +} diff --git a/src/main/java/ru/windcorp/progressia/common/world/generic/context/GenericROBlockContext.java b/src/main/java/ru/windcorp/progressia/common/world/generic/context/GenericROBlockContext.java new file mode 100644 index 0000000..4411407 --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/common/world/generic/context/GenericROBlockContext.java @@ -0,0 +1,119 @@ +/* + * 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.common.world.generic.context; + +import glm.vec._3.i.Vec3i; +import ru.windcorp.progressia.common.world.context.Context; +import ru.windcorp.progressia.common.world.generic.GenericBlock; +import ru.windcorp.progressia.common.world.generic.GenericROChunk; +import ru.windcorp.progressia.common.world.generic.GenericEntity; +import ru.windcorp.progressia.common.world.generic.GenericTile; +import ru.windcorp.progressia.common.world.generic.GenericROTileReference; +import ru.windcorp.progressia.common.world.generic.GenericROTileStack; +import ru.windcorp.progressia.common.world.rels.BlockFace; + +/** + * A {@link Context} referencing a world with a block location specified. The + * location may or may not be loaded. + */ +//@formatter:off +public interface GenericROBlockContext< + B extends GenericBlock, + T extends GenericTile, + TS extends GenericROTileStack , + TR extends GenericROTileReference , + C extends GenericROChunk , + E extends GenericEntity +> extends GenericROWorldContext { +//@formatter:on + + /** + * Returns the location of the block. + *

    + * The coordinate system in use is not specified, but it is consistent + * across all methods of this context. + *

    + * The object returned by this method must not be modified. It is only valid + * while the context is {@linkplain valid}. + * + * @return a vector describing the block's position + */ + Vec3i getLocation(); + + /** + * Determines whether the location relevant to this context is currently + * loaded. + * + * @return {@code true} iff the location is loaded + */ + default boolean isLoaded() { + return isBlockLoaded(getLocation()); + } + + /** + * Gets the block relevant in this context. + * + * @return the block or {@code null} if the location is not loaded + */ + default B getBlock() { + return getBlock(getLocation()); + } + + /** + * Gets the tile stack at the specified position; block location is implied + * by the context. + * + * @return the specified tile stack or {@code null} if the location is not + * loaded or the tile stack does not exist + */ + default TS getTilesOrNull(BlockFace face) { + return getTilesOrNull(getLocation(), face); + } + + /** + * Determines whether the location relevant to this context has a tile stack + * at the specified side. + * + * @return {@code true} iff the tile stack exists + */ + default boolean hasTiles(BlockFace face) { + return hasTiles(getLocation(), face); + } + + /** + * Determines whether the specified position has a tile; block location is + * implied by the context. + * + * @return {@code true} iff the tile exists + */ + default boolean hasTile(BlockFace face, int layer) { + return hasTile(getLocation(), face, layer); + } + + /** + * Gets the tile at the specified position; block location is implied by the + * context. + * + * @return the specified tile or {@code null} if the location is not loaded + * or the tile does not exist + */ + default T getTile(BlockFace face, int layer) { + return getTile(getLocation(), face, layer); + } + +} diff --git a/src/main/java/ru/windcorp/progressia/common/world/generic/context/GenericROBlockFaceContext.java b/src/main/java/ru/windcorp/progressia/common/world/generic/context/GenericROBlockFaceContext.java new file mode 100644 index 0000000..430a4a3 --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/common/world/generic/context/GenericROBlockFaceContext.java @@ -0,0 +1,93 @@ +/* + * 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.common.world.generic.context; + +import ru.windcorp.progressia.common.world.context.Context; +import ru.windcorp.progressia.common.world.generic.GenericBlock; +import ru.windcorp.progressia.common.world.generic.GenericROChunk; +import ru.windcorp.progressia.common.world.generic.GenericEntity; +import ru.windcorp.progressia.common.world.generic.GenericTile; +import ru.windcorp.progressia.common.world.generic.GenericROTileReference; +import ru.windcorp.progressia.common.world.generic.GenericROTileStack; +import ru.windcorp.progressia.common.world.rels.RelFace; + +/** + * A {@link Context} referencing a world with a block location and a block face + * specified, effectively pointing to a tile stack. The tile stack may or may + * not actually exist. + */ +//@formatter:off +public interface GenericROBlockFaceContext< + B extends GenericBlock, + T extends GenericTile, + TS extends GenericROTileStack , + TR extends GenericROTileReference , + C extends GenericROChunk , + E extends GenericEntity +> extends GenericROBlockContext { +//@formatter:on + + /** + * Returns the face relevant to this context. + * + * @return the block face + */ + RelFace getFace(); + + /** + * Gets the tile stack at the relevant position. + * + * @return the specified tile stack or {@code null} if the location is not + * loaded or the tile stack does not exist + */ + default TS getTilesOrNull() { + return getTilesOrNull(getLocation(), getFace()); + } + + /** + * Determines whether the location relevant to this context has a tile + * stack. + * + * @return {@code true} iff the tile stack exists + */ + default boolean hasTiles() { + return hasTiles(getLocation(), getFace()); + } + + /** + * Determines whether the specified position has a tile; block location and + * face are implied by the context. + * + * @return {@code true} iff the tile exists + */ + default boolean hasTile(int layer) { + return hasTile(getLocation(), getFace(), layer); + } + + /** + * Gets the tile at the specified position; block location and face are + * implied by the context. + * + * @return the specified tile or {@code null} if the location is not loaded + * or the tile does not exist + */ + default T getTile(int layer) { + return getTile(getLocation(), getFace(), layer); + } + +} diff --git a/src/main/java/ru/windcorp/progressia/common/world/generic/context/GenericROTileContext.java b/src/main/java/ru/windcorp/progressia/common/world/generic/context/GenericROTileContext.java new file mode 100644 index 0000000..0ebc768 --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/common/world/generic/context/GenericROTileContext.java @@ -0,0 +1,85 @@ +/* + * 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.common.world.generic.context; + +import ru.windcorp.progressia.common.world.context.Context; +import ru.windcorp.progressia.common.world.generic.GenericBlock; +import ru.windcorp.progressia.common.world.generic.GenericROChunk; +import ru.windcorp.progressia.common.world.generic.GenericEntity; +import ru.windcorp.progressia.common.world.generic.GenericTile; +import ru.windcorp.progressia.common.world.generic.GenericROTileReference; +import ru.windcorp.progressia.common.world.generic.GenericROTileStack; + +/** + * A {@link Context} referencing a world with a block location, a block face and + * a tile layer specified, effectively pointing to a single tile. The tile may + * or may not actually exist. + */ +//@formatter:off +public interface GenericROTileContext< + B extends GenericBlock, + T extends GenericTile, + TS extends GenericROTileStack , + TR extends GenericROTileReference , + C extends GenericROChunk , + E extends GenericEntity +> extends GenericROBlockFaceContext { +//@formatter:on + + /** + * Returns the tile layer relevant to this context. + * + * @return the tile layer + */ + int getLayer(); + + /** + * Determines whether the location relevant to this context has a tile. + * + * @return {@code true} iff the tile exists + */ + default boolean hasTile() { + return hasTile(getLocation(), getFace(), getLayer()); + } + + /** + * Gets the tile at the relevant position. + * + * @return the specified tile or {@code null} if the location is not loaded + * or the tile does not exist + */ + default T getTile() { + return getTile(getLocation(), getFace(), getLayer()); + } + + /** + * Gets the tag of the tile at the relevant position. + * + * @return the tag of the tile or {@code -1} if the location is not loaded + * or the tile does not exist + */ + default int getTag() { + TS tileStack = getTilesOrNull(); + if (tileStack == null) { + return -1; + } + + return tileStack.getTagByIndex(getLayer()); + } + +} diff --git a/src/main/java/ru/windcorp/progressia/common/world/generic/context/GenericROWorldContext.java b/src/main/java/ru/windcorp/progressia/common/world/generic/context/GenericROWorldContext.java new file mode 100644 index 0000000..09629da --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/common/world/generic/context/GenericROWorldContext.java @@ -0,0 +1,45 @@ +/* + * 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.common.world.generic.context; + +import ru.windcorp.progressia.common.world.context.Context; +import ru.windcorp.progressia.common.world.generic.GenericBlock; +import ru.windcorp.progressia.common.world.generic.GenericROChunk; +import ru.windcorp.progressia.common.world.generic.GenericEntity; +import ru.windcorp.progressia.common.world.generic.GenericTile; +import ru.windcorp.progressia.common.world.generic.GenericROTileReference; +import ru.windcorp.progressia.common.world.generic.GenericROTileStack; +import ru.windcorp.progressia.common.world.generic.GenericROWorld; + +/** + * A {@link Context} with a world instance. + */ +// @formatter:off +public interface GenericROWorldContext< + B extends GenericBlock, + T extends GenericTile, + TS extends GenericROTileStack , + TR extends GenericROTileReference , + C extends GenericROChunk , + E extends GenericEntity +> extends Context, GenericROWorld { +// @formatter:on + + // currently empty + +} diff --git a/src/main/java/ru/windcorp/progressia/common/world/generic/context/GenericRWBlockContext.java b/src/main/java/ru/windcorp/progressia/common/world/generic/context/GenericRWBlockContext.java new file mode 100644 index 0000000..23fb6fe --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/common/world/generic/context/GenericRWBlockContext.java @@ -0,0 +1,92 @@ +/* + * 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.common.world.generic.context; + +import ru.windcorp.progressia.common.world.context.Context; +import ru.windcorp.progressia.common.world.generic.*; +import ru.windcorp.progressia.common.world.rels.BlockFace; + +/** + * A writable {@link Context} referencing a world with a block location + * specified. This context provides methods for affecting the world. The + * application of requested changes may or may not be immediate, see + * {@link #isImmediate()}. The location may or may not be loaded. + */ +//@formatter:off +public interface GenericRWBlockContext< + B extends GenericBlock, + T extends GenericTile, + TS extends GenericRWTileStack , + TR extends GenericROTileReference , + C extends GenericRWChunk , + E extends GenericEntity +> extends GenericRWWorldContext, GenericROBlockContext { +//@formatter:on + + /** + * Requests that a block is changed. The object provided may be stored until + * the change is applied. The location of the block is implied by the + * context. + * + * @param block the new block + * @see #isImmediate() + */ + default void setBlock(B block) { + setBlock(getLocation(), block); + } + + /** + * Requests that a tile is added to the top of the tile stack at the given + * location. The object provided may be stored until the change is applied. + * If the tile could not be added at the time of application this method + * fails silently. The location of the block is implied by the context. + * + * @param face the face of the block to add the tile to + * @param tile the tile to add + */ + default void addTile(BlockFace face, T tile) { + addTile(getLocation(), face, tile); + } + + /** + * Requests that a tile identified by its tag is removed from the specified + * tile stack. If the tile could not be found at the time of application + * this method fails silently. The location of the block is implied by the + * context. + * + * @param face the of the block to remove the tile from + * @param tag the tag of the tile to remove + */ + default void removeTile(BlockFace face, int tag) { + removeTile(getLocation(), face, tag); + } + + /** + * Requests that the referenced tile is removed from the specified tile + * stack. If the tile could not be found at the time of application this + * method fails silently. The location of the block is implied by the + * context. + * + * @param face the of the block to remove the tile from + * @param tileReference a reference to the tile + */ + default void removeTile(BlockFace face, TR tileReference) { + removeTile(getLocation(), face, tileReference.getTag()); + } + +} diff --git a/src/main/java/ru/windcorp/progressia/common/world/generic/context/GenericRWBlockFaceContext.java b/src/main/java/ru/windcorp/progressia/common/world/generic/context/GenericRWBlockFaceContext.java new file mode 100644 index 0000000..b2152f8 --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/common/world/generic/context/GenericRWBlockFaceContext.java @@ -0,0 +1,78 @@ +/* + * 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.common.world.generic.context; + +import ru.windcorp.progressia.common.world.context.Context; +import ru.windcorp.progressia.common.world.generic.*; + +/** + * A writable {@link Context} referencing a world with a block location and a + * block face specified, effectively pointing to a tile stack. This context + * provides methods for affecting the world. The application of requested + * changes may or may not be immediate, see {@link #isImmediate()}. The tile + * stack may or may not actually exist. + */ +//@formatter:off +public interface GenericRWBlockFaceContext< + B extends GenericBlock, + T extends GenericTile, + TS extends GenericRWTileStack , + TR extends GenericROTileReference , + C extends GenericRWChunk , + E extends GenericEntity +> extends GenericRWBlockContext, GenericROBlockFaceContext { +//@formatter:on + + /** + * Requests that a tile is added to the top of the tile stack at the given + * location. The object provided may be stored until the change is applied. + * If the tile could not be added at the time of application this method + * fails silently. The location and the face of the block are implied by the + * context. + * + * @param tile the tile to add + */ + default void addTile(T tile) { + addTile(getLocation(), getFace(), tile); + } + + /** + * Requests that a tile identified by its tag is removed from the specified + * tile stack. If the tile could not be found at the time of application + * this method fails silently. The location and the face of the block are + * implied by the context. + * + * @param tag the tag of the tile to remove + */ + default void removeTile(int tag) { + removeTile(getLocation(), getFace(), tag); + } + + /** + * Requests that the referenced tile is removed from the specified tile + * stack. If the tile could not be found at the time of application this + * method fails silently. The location and the face of the block are implied + * by the context. + * + * @param tileReference a reference to the tile + */ + default void removeTile(TR tileReference) { + removeTile(getLocation(), getFace(), tileReference.getTag()); + } + +} diff --git a/src/main/java/ru/windcorp/progressia/common/world/generic/context/GenericRWTileContext.java b/src/main/java/ru/windcorp/progressia/common/world/generic/context/GenericRWTileContext.java new file mode 100644 index 0000000..c7c0d5c --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/common/world/generic/context/GenericRWTileContext.java @@ -0,0 +1,50 @@ +/* + * 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.common.world.generic.context; + +import ru.windcorp.progressia.common.world.context.Context; +import ru.windcorp.progressia.common.world.generic.*; + +/** + * A writable {@link Context} referencing a world with a block location, a block + * face and a tile layer specified, effectively pointing to a single tile. This + * context provides methods for affecting the world. The application of + * requested changes may or may not be immediate, see {@link #isImmediate()}. + * The tile may or may not actually exist. + */ +//@formatter:off +public interface GenericRWTileContext< + B extends GenericBlock, + T extends GenericTile, + TS extends GenericRWTileStack , + TR extends GenericROTileReference , + C extends GenericRWChunk , + E extends GenericEntity +> extends GenericRWBlockFaceContext, GenericROTileContext { +//@formatter:on + + /** + * Requests that the tile relevant to this context be removed from its tile + * stack. If the tile could not be found at the time of application this + * method fails silently. + */ + default void removeTile() { + removeTile(getLocation(), getFace(), getTag()); + } + +} diff --git a/src/main/java/ru/windcorp/progressia/common/world/generic/context/GenericRWWorldContext.java b/src/main/java/ru/windcorp/progressia/common/world/generic/context/GenericRWWorldContext.java new file mode 100644 index 0000000..55d83ff --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/common/world/generic/context/GenericRWWorldContext.java @@ -0,0 +1,151 @@ +/* + * 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.common.world.generic.context; + +import glm.vec._3.i.Vec3i; +import ru.windcorp.progressia.common.state.StateChange; +import ru.windcorp.progressia.common.state.StatefulObject; +import ru.windcorp.progressia.common.world.context.Context; +import ru.windcorp.progressia.common.world.generic.*; +import ru.windcorp.progressia.common.world.rels.BlockFace; + +/** + * A writable {@link Context} with a world instance. This context provides + * methods for affecting the world. The application of requested changes may or + * may not be immediate, see {@link #isImmediate()}. + */ +// @formatter:off +public interface GenericRWWorldContext< + B extends GenericBlock, + T extends GenericTile, + TS extends GenericRWTileStack , + TR extends GenericROTileReference , + C extends GenericRWChunk , + E extends GenericEntity +> extends GenericROWorldContext, GenericRWWorld { +// @formatter:on + + /** + * Queries whether changes requested with this context are guaranteed to be + * applied immediately. + *

    + * When the changes are applied immediately, all subsequent queries will + * reflect the change. When the changes are not applied immediately, none of + * the subsequent queries will be affected by the requests while the context + * is {@linkplain Context#validity valid}. Immediate mode does not change + * while the context is valid. + * + * @return {@code true} iff changes are visible immediately + */ + boolean isImmediate(); + + /** + * Requests that a block is changed. The object provided may be stored until + * the change is applied. + * + * @param location the location of the change + * @param block the new block + * @see #isImmediate() + */ + default void setBlock(Vec3i location, B block) { + setBlock(location, block); + } + + /** + * Requests that a tile is added to the top of the tile stack at the given + * location. The object provided may be stored until the change is applied. + * If the tile could not be added at the time of application this method + * fails silently. + * + * @param location the location of the block to which the tile is to be + * added + * @param face the face of the block to add the tile to + * @param tile the tile to add + */ + void addTile(Vec3i location, BlockFace face, T tile); + + /** + * Requests that a tile identified by its tag is removed from the specified + * tile stack. If the tile could not be found at the time of application + * this method fails silently. + * + * @param location the location of the block from which the tile is to be + * removed + * @param face the of the block to remove the tile from + * @param tag the tag of the tile to remove + */ + void removeTile(Vec3i location, BlockFace face, int tag); + + /** + * Requests that the referenced tile is removed from the specified tile + * stack. If the tile could not be found at the time of application this + * method fails silently. + * + * @param location the location of the block from which the tile is to + * be removed + * @param face the of the block to remove the tile from + * @param tileReference a reference to the tile + */ + default void removeTile(Vec3i location, BlockFace face, TR tileReference) { + removeTile(location, face, tileReference.getTag()); + } + + /** + * Requests that an entity is added to the world. The object provided may be + * stored until the change is applied. If the entity was already added to + * the world at the time of application this method does nothing. + * + * @param entity the entity to add + * @see #isImmediate() + */ + @Override + void addEntity(E entity); + + /** + * Requests that an entity with the given entity ID is removed from the + * world. If the entity did not exist at the time of application this method + * fails silently. + * + * @param entityId the ID of the entity to remove + * @see #isImmediate() + * @see #removeEntity(GenericEntity) + */ + @Override + void removeEntity(long entityId); + + /** + * Requests that the entity is removed from the world. If the entity did not + * exist at the time of application this method fails silently. + * + * @param entity the entity to remove + * @see #isImmediate() + * @see #removeEntity(long) + */ + @Override + void removeEntity(E entity); + + /** + * Requests that the specified change is applied to the given entity. The {@code change} object provided may be stored until the change is applied. + * + * @param entity the entity to change + * @param change the change to apply + */ + @Override + void changeEntity(SE entity, StateChange change); + +} diff --git a/src/main/java/ru/windcorp/progressia/server/world/context/ServerContext.java b/src/main/java/ru/windcorp/progressia/server/world/context/ServerContext.java new file mode 100644 index 0000000..bb218ab --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/server/world/context/ServerContext.java @@ -0,0 +1,84 @@ +/* + * 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.server.world.context; + +import java.util.Random; + +import ru.windcorp.progressia.common.world.context.Context; +import ru.windcorp.progressia.server.Server; +import ru.windcorp.progressia.server.ServerState; + +/** + * A server-side {@link Context}. This context has a {@link Server} instance. + */ +public interface ServerContext extends Context { + + /** + * Gets the {@link Server} instance relevant to this context. This method + * should always be preferred to {@link ServerState#getInstance()} when + * possible. + * + * @return the server instance + */ + Server getServer(); + + /** + * Retrieves a context-appropriate source of randomness. This source should + * always be preferred to any other when possible. + * + * @return an intended {@link Random} instance + */ + Random getRandom(); + + /** + * Returns the duration of the last server tick. Server logic should assume + * that this much in-world time has passed. + * + * @return the length of the last server tick + */ + default double getTickLength() { + return getServer().getTickLength(); + } + + /** + * Adjusts the provided value according to tick length assuming the value + * scales linearly. The call {@code ctxt.adjustValue(x)} is equivalent to + * {@code ((float) ctxt.getTickLength()) * x}. + * + * @param valueForOneSecond the value to adjust, normalized to one second + * @return the value adjust to account for the actual tick length + * @see #getTickLength() + */ + default float adjustTime(float valueForOneSecond) { + return ((float) getTickLength()) * valueForOneSecond; + } + + /** + * Adjusts the provided value according to tick length assuming the value + * scales linearly. The call {@code ctxt.adjustValue(x)} is equivalent to + * {@code ctxt.getTickLength() * x}. + * + * @param valueForOneSecond the value to adjust, normalized to one second + * @return the value adjust to account for the actual tick length + * @see #getTickLength() + */ + default double adjustTime(double valueForOneSecond) { + return getTickLength() * valueForOneSecond; + } + +} From 9a326603cd9e4cb8d1f9a130d7cde62f861a0cd9 Mon Sep 17 00:00:00 2001 From: OLEGSHA Date: Fri, 23 Jul 2021 22:46:49 +0300 Subject: [PATCH 31/55] Still working on Contexts. Introduced a billion interfaces. WIP. *takes a deep breath - Renamed Generic world structure interfaces to the following scheme: {Block,Tile,Chunk,World}Generic{,Stack,Reference}{RO,WO} (e.g. GenericWritableChunk -> ChunkGenericWO) - RO is Read Only, WO is Write Only - Generic writable interfaces no longer extend their read-only counterparts (thus Write Only) - TileGenericStack{RO,WO} are now interfaces; AbstractList is only introduced by final implementations - TileGenericReferenceRO now has a WO counterpart - Fixed compilation issues with the previous commit - Declared some additional functionality for Generic interfaces - Old ChunkData and WorldData renamed to DefaultChunkData and DefaultWorldData - Now considered to be an implementation detail; references will be minimized - Introduced TileDataStack{,RO}, TileDataReference{,RO}, ChunkData{,RO}, WorldData{,RO} interfaces - Suffix -RO indicates Read Only, no suffix means read-write - To be used in place of DefaultChunk and DefaultWorld - Designed to support wrappers and "fake" implementations - May need some refinement (fix return/parameter types, ...) - Surface world generator is now implemented poorly (WIP) - Should compile. May work fine. Unless Java inheritance rules have screwed me over. --- .../ru/windcorp/progressia/client/Client.java | 4 +- .../progressia/client/ClientState.java | 4 +- .../progressia/client/world/ChunkRender.java | 16 +- .../client/world/ChunkRenderModel.java | 10 +- .../client/world/ChunkUpdateListener.java | 14 +- .../progressia/client/world/WorldRender.java | 26 +- .../client/world/block/BlockRender.java | 8 +- .../client/world/block/BlockRenderNone.java | 4 +- .../world/block/BlockRenderTexturedCube.java | 8 +- .../cro/ChunkRenderOptimizerSurface.java | 8 +- .../client/world/entity/EntityRenderable.java | 4 +- .../client/world/tile/TileRender.java | 8 +- .../client/world/tile/TileRenderNone.java | 4 +- .../world/tile/TileRenderReference.java | 4 +- .../client/world/tile/TileRenderStack.java | 10 +- .../client/world/tile/TileRenderSurface.java | 8 +- .../collision/WorldCollisionHelper.java | 4 +- .../common/collision/colliders/Collider.java | 14 +- .../StateChange.java} | 11 +- .../progressia/common/world/ChunkData.java | 525 +----------------- .../common/world/ChunkDataListener.java | 10 +- .../common/world/ChunkDataListeners.java | 2 +- .../progressia/common/world/ChunkDataRO.java | 12 + .../progressia/common/world/Coordinates.java | 2 +- .../common/world/DefaultChunkData.java | 525 ++++++++++++++++++ .../common/world/DefaultWorldData.java | 262 +++++++++ .../common/world/PacketAffectWorld.java | 2 +- .../common/world/PacketRevokeChunk.java | 4 +- .../common/world/PacketSendChunk.java | 4 +- .../common/world/PacketSetGravityModel.java | 2 +- .../common/world/TileDataReference.java | 10 + .../common/world/TileDataReferenceRO.java | 12 + .../common/world/TileDataStack.java | 25 + .../common/world/TileDataStackRO.java | 12 + .../progressia/common/world/WorldData.java | 257 ++------- .../common/world/WorldDataListener.java | 14 +- .../progressia/common/world/WorldDataRO.java | 29 + .../common/world/block/BlockData.java | 4 +- .../common/world/block/PacketSetBlock.java | 4 +- .../common/world/entity/EntityData.java | 4 +- .../world/entity/PacketAffectEntity.java | 4 +- .../world/entity/PacketChangeEntity.java | 4 +- .../world/entity/PacketRevokeEntity.java | 4 +- .../common/world/entity/PacketSendEntity.java | 4 +- .../{GenericBlock.java => BlockGeneric.java} | 2 +- ...{GenericChunk.java => ChunkGenericRO.java} | 24 +- .../common/world/generic/ChunkGenericWO.java | 37 ++ .../common/world/generic/ChunkMap.java | 16 +- .../common/world/generic/ChunkMaps.java | 16 +- .../common/world/generic/ChunkSet.java | 18 +- .../common/world/generic/ChunkSets.java | 18 +- ...{GenericEntity.java => EntityGeneric.java} | 2 +- .../common/world/generic/GenericChunks.java | 18 +- .../world/generic/GenericWritableChunk.java | 43 -- .../world/generic/LongBasedChunkSet.java | 2 +- .../{GenericTile.java => TileGeneric.java} | 2 +- .../world/generic/TileGenericReferenceRO.java | 50 ++ ...rence.java => TileGenericReferenceWO.java} | 24 +- ...TileStack.java => TileGenericStackRO.java} | 48 +- ...TileStack.java => TileGenericStackWO.java} | 49 +- ...{GenericWorld.java => WorldGenericRO.java} | 25 +- ...WritableWorld.java => WorldGenericWO.java} | 34 +- ...xt.java => BlockFaceGenericContextRO.java} | 31 +- ...xt.java => BlockFaceGenericContextWO.java} | 28 +- ...ontext.java => BlockGenericContextRO.java} | 37 +- ...ontext.java => BlockGenericContextWO.java} | 29 +- ...Context.java => TileGenericContextRO.java} | 56 +- ...Context.java => TileGenericContextWO.java} | 16 +- .../world/generic/context/WorldContexts.java | 127 +++++ ...ontext.java => WorldGenericContextRO.java} | 24 +- ...ontext.java => WorldGenericContextWO.java} | 42 +- .../common/world/io/ChunkCodec.java | 10 +- .../progressia/common/world/io/ChunkIO.java | 10 +- .../common/world/tile/PacketAddTile.java | 4 +- .../common/world/tile/PacketRemoveTile.java | 5 +- .../common/world/tile/TileData.java | 4 +- .../common/world/tile/TileDataStack.java | 28 - .../ru/windcorp/progressia/server/Player.java | 4 +- .../ru/windcorp/progressia/server/Server.java | 4 +- .../progressia/server/ServerState.java | 4 +- .../server/management/load/ChunkManager.java | 16 +- .../progressia/server/world/ChunkLogic.java | 16 +- .../server/world/ChunkTickContext.java | 4 +- .../progressia/server/world/TickContext.java | 4 +- .../server/world/TickContextMutable.java | 16 +- .../server/world/UpdateTriggerer.java | 6 +- .../progressia/server/world/WorldLogic.java | 26 +- .../server/world/block/BlockLogic.java | 4 +- .../generation/AbstractWorldGenerator.java | 10 +- .../world/generation/WorldGenerator.java | 8 +- .../server/world/tasks/TickChunk.java | 12 +- .../world/ticking/TickerCoordinator.java | 4 +- .../server/world/tile/TSTickContext.java | 6 +- .../server/world/tile/TileLogic.java | 4 +- .../server/world/tile/TileLogicReference.java | 4 +- .../server/world/tile/TileLogicStack.java | 9 +- .../server/world/tile/TileTickContext.java | 4 +- .../progressia/test/TestChunkCodec.java | 24 +- .../progressia/test/TestWorldDiskIO.java | 18 +- .../progressia/test/gen/TerrainLayer.java | 4 +- .../test/gen/TestWorldGenerator.java | 42 +- .../progressia/test/gen/planet/Planet.java | 6 +- .../gen/planet/PlanetFeatureGenerator.java | 8 +- .../gen/planet/PlanetTerrainGenerator.java | 14 +- .../test/gen/planet/TestPlanetGenerator.java | 8 +- .../gen/planet/TestPlanetGravityModel.java | 8 +- .../test/gen/surface/SurfaceFeature.java | 8 +- .../gen/surface/SurfaceFeatureGenerator.java | 4 +- .../gen/surface/SurfaceTerrainGenerator.java | 19 +- .../test/gen/surface/SurfaceWorld.java | 39 +- 110 files changed, 1733 insertions(+), 1419 deletions(-) rename src/main/java/ru/windcorp/progressia/common/{world/tile/TileDataReference.java => state/StateChange.java} (66%) create mode 100644 src/main/java/ru/windcorp/progressia/common/world/ChunkDataRO.java create mode 100644 src/main/java/ru/windcorp/progressia/common/world/DefaultChunkData.java create mode 100644 src/main/java/ru/windcorp/progressia/common/world/DefaultWorldData.java create mode 100644 src/main/java/ru/windcorp/progressia/common/world/TileDataReference.java create mode 100644 src/main/java/ru/windcorp/progressia/common/world/TileDataReferenceRO.java create mode 100644 src/main/java/ru/windcorp/progressia/common/world/TileDataStack.java create mode 100644 src/main/java/ru/windcorp/progressia/common/world/TileDataStackRO.java create mode 100644 src/main/java/ru/windcorp/progressia/common/world/WorldDataRO.java rename src/main/java/ru/windcorp/progressia/common/world/generic/{GenericBlock.java => BlockGeneric.java} (96%) rename src/main/java/ru/windcorp/progressia/common/world/generic/{GenericChunk.java => ChunkGenericRO.java} (92%) create mode 100644 src/main/java/ru/windcorp/progressia/common/world/generic/ChunkGenericWO.java rename src/main/java/ru/windcorp/progressia/common/world/generic/{GenericEntity.java => EntityGeneric.java} (97%) delete mode 100644 src/main/java/ru/windcorp/progressia/common/world/generic/GenericWritableChunk.java rename src/main/java/ru/windcorp/progressia/common/world/generic/{GenericTile.java => TileGeneric.java} (96%) create mode 100644 src/main/java/ru/windcorp/progressia/common/world/generic/TileGenericReferenceRO.java rename src/main/java/ru/windcorp/progressia/common/world/generic/{GenericTileReference.java => TileGenericReferenceWO.java} (70%) rename src/main/java/ru/windcorp/progressia/common/world/generic/{GenericTileStack.java => TileGenericStackRO.java} (68%) rename src/main/java/ru/windcorp/progressia/common/world/generic/{GenericWritableTileStack.java => TileGenericStackWO.java} (80%) rename src/main/java/ru/windcorp/progressia/common/world/generic/{GenericWorld.java => WorldGenericRO.java} (90%) rename src/main/java/ru/windcorp/progressia/common/world/generic/{GenericWritableWorld.java => WorldGenericWO.java} (52%) rename src/main/java/ru/windcorp/progressia/common/world/generic/context/{GenericROBlockFaceContext.java => BlockFaceGenericContextRO.java} (70%) rename src/main/java/ru/windcorp/progressia/common/world/generic/context/{GenericRWBlockFaceContext.java => BlockFaceGenericContextWO.java} (72%) rename src/main/java/ru/windcorp/progressia/common/world/generic/context/{GenericROBlockContext.java => BlockGenericContextRO.java} (69%) rename src/main/java/ru/windcorp/progressia/common/world/generic/context/{GenericRWBlockContext.java => BlockGenericContextWO.java} (74%) rename src/main/java/ru/windcorp/progressia/common/world/generic/context/{GenericROTileContext.java => TileGenericContextRO.java} (62%) rename src/main/java/ru/windcorp/progressia/common/world/generic/context/{GenericRWTileContext.java => TileGenericContextWO.java} (80%) create mode 100644 src/main/java/ru/windcorp/progressia/common/world/generic/context/WorldContexts.java rename src/main/java/ru/windcorp/progressia/common/world/generic/context/{GenericROWorldContext.java => WorldGenericContextRO.java} (54%) rename src/main/java/ru/windcorp/progressia/common/world/generic/context/{GenericRWWorldContext.java => WorldGenericContextWO.java} (80%) delete mode 100644 src/main/java/ru/windcorp/progressia/common/world/tile/TileDataStack.java diff --git a/src/main/java/ru/windcorp/progressia/client/Client.java b/src/main/java/ru/windcorp/progressia/client/Client.java index d8800c7..f356954 100644 --- a/src/main/java/ru/windcorp/progressia/client/Client.java +++ b/src/main/java/ru/windcorp/progressia/client/Client.java @@ -24,7 +24,7 @@ import ru.windcorp.progressia.client.graphics.world.Camera; import ru.windcorp.progressia.client.graphics.world.EntityAnchor; import ru.windcorp.progressia.client.graphics.world.LocalPlayer; import ru.windcorp.progressia.client.world.WorldRender; -import ru.windcorp.progressia.common.world.WorldData; +import ru.windcorp.progressia.common.world.DefaultWorldData; import ru.windcorp.progressia.common.world.entity.EntityData; public class Client { @@ -36,7 +36,7 @@ public class Client { private final ServerCommsChannel comms; - public Client(WorldData world, ServerCommsChannel comms) { + public Client(DefaultWorldData world, ServerCommsChannel comms) { this.world = new WorldRender(world, this); this.comms = comms; diff --git a/src/main/java/ru/windcorp/progressia/client/ClientState.java b/src/main/java/ru/windcorp/progressia/client/ClientState.java index 75f0f07..31c366e 100644 --- a/src/main/java/ru/windcorp/progressia/client/ClientState.java +++ b/src/main/java/ru/windcorp/progressia/client/ClientState.java @@ -21,7 +21,7 @@ package ru.windcorp.progressia.client; import ru.windcorp.progressia.client.comms.localhost.LocalServerCommsChannel; import ru.windcorp.progressia.client.graphics.GUI; import ru.windcorp.progressia.client.graphics.world.LayerWorld; -import ru.windcorp.progressia.common.world.WorldData; +import ru.windcorp.progressia.common.world.DefaultWorldData; import ru.windcorp.progressia.server.ServerState; import ru.windcorp.progressia.test.LayerAbout; import ru.windcorp.progressia.test.LayerTestUI; @@ -41,7 +41,7 @@ public class ClientState { public static void connectToLocalServer() { - WorldData world = new WorldData(); + DefaultWorldData world = new DefaultWorldData(); LocalServerCommsChannel channel = new LocalServerCommsChannel( ServerState.getInstance() diff --git a/src/main/java/ru/windcorp/progressia/client/world/ChunkRender.java b/src/main/java/ru/windcorp/progressia/client/world/ChunkRender.java index c69fcf3..e96166d 100644 --- a/src/main/java/ru/windcorp/progressia/client/world/ChunkRender.java +++ b/src/main/java/ru/windcorp/progressia/client/world/ChunkRender.java @@ -30,26 +30,26 @@ import ru.windcorp.progressia.client.world.tile.TileRender; import ru.windcorp.progressia.client.world.tile.TileRenderReference; import ru.windcorp.progressia.client.world.tile.TileRenderRegistry; import ru.windcorp.progressia.client.world.tile.TileRenderStack; -import ru.windcorp.progressia.common.world.ChunkData; -import ru.windcorp.progressia.common.world.generic.GenericChunk; +import ru.windcorp.progressia.common.world.DefaultChunkData; +import ru.windcorp.progressia.common.world.TileDataReference; +import ru.windcorp.progressia.common.world.TileDataStack; +import ru.windcorp.progressia.common.world.generic.ChunkGenericRO; import ru.windcorp.progressia.common.world.rels.AbsFace; import ru.windcorp.progressia.common.world.rels.BlockFace; import ru.windcorp.progressia.common.world.rels.RelFace; -import ru.windcorp.progressia.common.world.tile.TileDataReference; -import ru.windcorp.progressia.common.world.tile.TileDataStack; public class ChunkRender - implements GenericChunk { + implements ChunkGenericRO { private final WorldRender world; - private final ChunkData data; + private final DefaultChunkData data; private final ChunkRenderModel model; private final Map tileRenderLists = Collections .synchronizedMap(new WeakHashMap<>()); - public ChunkRender(WorldRender world, ChunkData data) { + public ChunkRender(WorldRender world, DefaultChunkData data) { this.world = world; this.data = data; this.model = new ChunkRenderModel(this); @@ -93,7 +93,7 @@ public class ChunkRender return world; } - public ChunkData getData() { + public DefaultChunkData getData() { return data; } diff --git a/src/main/java/ru/windcorp/progressia/client/world/ChunkRenderModel.java b/src/main/java/ru/windcorp/progressia/client/world/ChunkRenderModel.java index 832a7ee..cd8a1d8 100644 --- a/src/main/java/ru/windcorp/progressia/client/world/ChunkRenderModel.java +++ b/src/main/java/ru/windcorp/progressia/client/world/ChunkRenderModel.java @@ -35,7 +35,7 @@ import ru.windcorp.progressia.client.world.cro.ChunkRenderOptimizerRegistry; import ru.windcorp.progressia.client.world.tile.TileRender; import ru.windcorp.progressia.client.world.tile.TileRenderNone; import ru.windcorp.progressia.client.world.tile.TileRenderStack; -import ru.windcorp.progressia.common.world.ChunkData; +import ru.windcorp.progressia.common.world.DefaultChunkData; import ru.windcorp.progressia.common.world.generic.GenericChunks; import ru.windcorp.progressia.common.world.rels.AxisRotations; import ru.windcorp.progressia.common.world.rels.RelFace; @@ -55,12 +55,12 @@ public class ChunkRenderModel implements Renderable { public void render(ShapeRenderHelper renderer) { if (model == null) return; - float offset = ChunkData.BLOCKS_PER_CHUNK / 2 - 0.5f; + float offset = DefaultChunkData.BLOCKS_PER_CHUNK / 2 - 0.5f; renderer.pushTransform().translate( - chunk.getX() * ChunkData.BLOCKS_PER_CHUNK, - chunk.getY() * ChunkData.BLOCKS_PER_CHUNK, - chunk.getZ() * ChunkData.BLOCKS_PER_CHUNK + chunk.getX() * DefaultChunkData.BLOCKS_PER_CHUNK, + chunk.getY() * DefaultChunkData.BLOCKS_PER_CHUNK, + chunk.getZ() * DefaultChunkData.BLOCKS_PER_CHUNK ).translate(offset, offset, offset) .mul(AxisRotations.getResolutionMatrix4(chunk.getUp())) .translate(-offset, -offset, -offset); diff --git a/src/main/java/ru/windcorp/progressia/client/world/ChunkUpdateListener.java b/src/main/java/ru/windcorp/progressia/client/world/ChunkUpdateListener.java index da3d10d..1e854f2 100644 --- a/src/main/java/ru/windcorp/progressia/client/world/ChunkUpdateListener.java +++ b/src/main/java/ru/windcorp/progressia/client/world/ChunkUpdateListener.java @@ -21,7 +21,7 @@ package ru.windcorp.progressia.client.world; 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.world.ChunkData; +import ru.windcorp.progressia.common.world.DefaultChunkData; import ru.windcorp.progressia.common.world.ChunkDataListener; import ru.windcorp.progressia.common.world.block.BlockData; import ru.windcorp.progressia.common.world.rels.AbsFace; @@ -37,12 +37,12 @@ class ChunkUpdateListener implements ChunkDataListener { } @Override - public void onChunkChanged(ChunkData chunk) { + public void onChunkChanged(DefaultChunkData chunk) { world.getChunk(chunk).markForUpdate(); } @Override - public void onChunkLoaded(ChunkData chunk) { + public void onChunkLoaded(DefaultChunkData chunk) { Vec3i cursor = new Vec3i(); for (AbsFace face : AbsFace.getFaces()) { cursor.set(chunk.getX(), chunk.getY(), chunk.getZ()); @@ -52,13 +52,13 @@ class ChunkUpdateListener implements ChunkDataListener { } @Override - public void onChunkBlockChanged(ChunkData chunk, Vec3i blockInChunk, BlockData previous, BlockData current) { + public void onChunkBlockChanged(DefaultChunkData chunk, Vec3i blockInChunk, BlockData previous, BlockData current) { onLocationChanged(chunk, blockInChunk); } @Override public void onChunkTilesChanged( - ChunkData chunk, + DefaultChunkData chunk, Vec3i blockInChunk, RelFace face, TileData tile, @@ -67,7 +67,7 @@ class ChunkUpdateListener implements ChunkDataListener { onLocationChanged(chunk, blockInChunk); } - private void onLocationChanged(ChunkData chunk, Vec3i blockInChunk) { + private void onLocationChanged(DefaultChunkData chunk, Vec3i blockInChunk) { Vec3i chunkPos = Vectors.grab3i().set(chunk.getX(), chunk.getY(), chunk.getZ()); checkCoordinate(blockInChunk, chunkPos, VectorUtil.Axis.X); @@ -83,7 +83,7 @@ class ChunkUpdateListener implements ChunkDataListener { if (block == 0) { diff = -1; - } else if (block == ChunkData.BLOCKS_PER_CHUNK - 1) { + } else if (block == DefaultChunkData.BLOCKS_PER_CHUNK - 1) { diff = +1; } else { return; diff --git a/src/main/java/ru/windcorp/progressia/client/world/WorldRender.java b/src/main/java/ru/windcorp/progressia/client/world/WorldRender.java index 7ff4df6..2ab9e7d 100644 --- a/src/main/java/ru/windcorp/progressia/client/world/WorldRender.java +++ b/src/main/java/ru/windcorp/progressia/client/world/WorldRender.java @@ -38,54 +38,54 @@ import ru.windcorp.progressia.client.world.tile.TileRenderReference; import ru.windcorp.progressia.client.world.tile.TileRenderStack; import ru.windcorp.progressia.common.util.VectorUtil; import ru.windcorp.progressia.common.util.Vectors; -import ru.windcorp.progressia.common.world.ChunkData; +import ru.windcorp.progressia.common.world.DefaultChunkData; import ru.windcorp.progressia.common.world.ChunkDataListeners; -import ru.windcorp.progressia.common.world.WorldData; +import ru.windcorp.progressia.common.world.DefaultWorldData; import ru.windcorp.progressia.common.world.WorldDataListener; import ru.windcorp.progressia.common.world.entity.EntityData; import ru.windcorp.progressia.common.world.generic.ChunkSet; import ru.windcorp.progressia.common.world.generic.ChunkSets; -import ru.windcorp.progressia.common.world.generic.GenericWorld; +import ru.windcorp.progressia.common.world.generic.WorldGenericRO; public class WorldRender - implements GenericWorld { + implements WorldGenericRO { - private final WorldData data; + private final DefaultWorldData data; private final Client client; - private final Map chunks = Collections.synchronizedMap(new HashMap<>()); + private final Map chunks = Collections.synchronizedMap(new HashMap<>()); private final Map entityModels = Collections.synchronizedMap(new WeakHashMap<>()); private final ChunkSet chunksToUpdate = ChunkSets.newSyncHashSet(); - public WorldRender(WorldData data, Client client) { + public WorldRender(DefaultWorldData data, Client client) { this.data = data; this.client = client; data.addListener(ChunkDataListeners.createAdder(new ChunkUpdateListener(this))); data.addListener(new WorldDataListener() { @Override - public void onChunkLoaded(WorldData world, ChunkData chunk) { + public void onChunkLoaded(DefaultWorldData world, DefaultChunkData chunk) { addChunk(chunk); } @Override - public void beforeChunkUnloaded(WorldData world, ChunkData chunk) { + public void beforeChunkUnloaded(DefaultWorldData world, DefaultChunkData chunk) { removeChunk(chunk); } }); } - protected void addChunk(ChunkData chunk) { + protected void addChunk(DefaultChunkData chunk) { chunks.put(chunk, new ChunkRender(WorldRender.this, chunk)); markChunkForUpdate(chunk.getPosition()); } - protected void removeChunk(ChunkData chunk) { + protected void removeChunk(DefaultChunkData chunk) { chunks.remove(chunk); } - public WorldData getData() { + public DefaultWorldData getData() { return data; } @@ -93,7 +93,7 @@ public class WorldRender return client; } - public ChunkRender getChunk(ChunkData chunkData) { + public ChunkRender getChunk(DefaultChunkData chunkData) { return chunks.get(chunkData); } diff --git a/src/main/java/ru/windcorp/progressia/client/world/block/BlockRender.java b/src/main/java/ru/windcorp/progressia/client/world/block/BlockRender.java index 2a3c8e1..6adbfde 100644 --- a/src/main/java/ru/windcorp/progressia/client/world/block/BlockRender.java +++ b/src/main/java/ru/windcorp/progressia/client/world/block/BlockRender.java @@ -19,18 +19,18 @@ package ru.windcorp.progressia.client.world.block; import ru.windcorp.progressia.common.util.namespaces.Namespaced; -import ru.windcorp.progressia.common.world.ChunkData; -import ru.windcorp.progressia.common.world.generic.GenericBlock; +import ru.windcorp.progressia.common.world.DefaultChunkData; +import ru.windcorp.progressia.common.world.generic.BlockGeneric; import glm.vec._3.i.Vec3i; import ru.windcorp.progressia.client.graphics.model.Renderable; -public abstract class BlockRender extends Namespaced implements GenericBlock { +public abstract class BlockRender extends Namespaced implements BlockGeneric { public BlockRender(String id) { super(id); } - public Renderable createRenderable(ChunkData chunk, Vec3i relBlockInChunk) { + public Renderable createRenderable(DefaultChunkData chunk, Vec3i relBlockInChunk) { return null; } diff --git a/src/main/java/ru/windcorp/progressia/client/world/block/BlockRenderNone.java b/src/main/java/ru/windcorp/progressia/client/world/block/BlockRenderNone.java index 84a2c4b..e9c10a8 100644 --- a/src/main/java/ru/windcorp/progressia/client/world/block/BlockRenderNone.java +++ b/src/main/java/ru/windcorp/progressia/client/world/block/BlockRenderNone.java @@ -21,7 +21,7 @@ package ru.windcorp.progressia.client.world.block; import glm.vec._3.i.Vec3i; import ru.windcorp.progressia.client.graphics.model.EmptyModel; import ru.windcorp.progressia.client.graphics.model.Renderable; -import ru.windcorp.progressia.common.world.ChunkData; +import ru.windcorp.progressia.common.world.DefaultChunkData; public class BlockRenderNone extends BlockRender { @@ -30,7 +30,7 @@ public class BlockRenderNone extends BlockRender { } @Override - public Renderable createRenderable(ChunkData chunk, Vec3i blockInChunk) { + public Renderable createRenderable(DefaultChunkData chunk, Vec3i blockInChunk) { return EmptyModel.getInstance(); } diff --git a/src/main/java/ru/windcorp/progressia/client/world/block/BlockRenderTexturedCube.java b/src/main/java/ru/windcorp/progressia/client/world/block/BlockRenderTexturedCube.java index 6ed7ef7..91d05e1 100644 --- a/src/main/java/ru/windcorp/progressia/client/world/block/BlockRenderTexturedCube.java +++ b/src/main/java/ru/windcorp/progressia/client/world/block/BlockRenderTexturedCube.java @@ -36,7 +36,7 @@ import ru.windcorp.progressia.client.graphics.texture.Texture; import ru.windcorp.progressia.client.graphics.world.WorldRenderProgram; import ru.windcorp.progressia.client.world.cro.ChunkRenderOptimizerSurface.BlockOptimizedSurface; import ru.windcorp.progressia.common.util.Vectors; -import ru.windcorp.progressia.common.world.ChunkData; +import ru.windcorp.progressia.common.world.DefaultChunkData; import ru.windcorp.progressia.common.world.rels.AbsFace; import ru.windcorp.progressia.common.world.rels.RelFace; @@ -69,7 +69,7 @@ public abstract class BlockRenderTexturedCube @Override public final void getShapeParts( - ChunkData chunk, Vec3i blockInChunk, RelFace blockFace, + DefaultChunkData chunk, Vec3i blockInChunk, RelFace blockFace, boolean inner, Consumer output, Vec3 offset @@ -78,7 +78,7 @@ public abstract class BlockRenderTexturedCube } private ShapePart createFace( - ChunkData chunk, Vec3i blockInChunk, RelFace blockFace, + DefaultChunkData chunk, Vec3i blockInChunk, RelFace blockFace, boolean inner, Vec3 offset ) { @@ -93,7 +93,7 @@ public abstract class BlockRenderTexturedCube } @Override - public Renderable createRenderable(ChunkData chunk, Vec3i blockInChunk) { + public Renderable createRenderable(DefaultChunkData chunk, Vec3i blockInChunk) { boolean opaque = isBlockOpaque(); ShapePart[] faces = new ShapePart[BLOCK_FACE_COUNT + (opaque ? BLOCK_FACE_COUNT : 0)]; diff --git a/src/main/java/ru/windcorp/progressia/client/world/cro/ChunkRenderOptimizerSurface.java b/src/main/java/ru/windcorp/progressia/client/world/cro/ChunkRenderOptimizerSurface.java index 26ee23c..296e7b8 100644 --- a/src/main/java/ru/windcorp/progressia/client/world/cro/ChunkRenderOptimizerSurface.java +++ b/src/main/java/ru/windcorp/progressia/client/world/cro/ChunkRenderOptimizerSurface.java @@ -18,8 +18,8 @@ package ru.windcorp.progressia.client.world.cro; -import static ru.windcorp.progressia.common.world.ChunkData.BLOCKS_PER_CHUNK; -import static ru.windcorp.progressia.common.world.generic.GenericTileStack.TILES_PER_FACE; +import static ru.windcorp.progressia.common.world.DefaultChunkData.BLOCKS_PER_CHUNK; +import static ru.windcorp.progressia.common.world.generic.TileGenericStackRO.TILES_PER_FACE; import static ru.windcorp.progressia.common.world.rels.AbsFace.BLOCK_FACE_COUNT; import java.util.ArrayList; @@ -37,7 +37,7 @@ import ru.windcorp.progressia.client.world.ChunkRender; import ru.windcorp.progressia.client.world.block.BlockRender; import ru.windcorp.progressia.client.world.tile.TileRender; import ru.windcorp.progressia.common.util.Vectors; -import ru.windcorp.progressia.common.world.ChunkData; +import ru.windcorp.progressia.common.world.DefaultChunkData; import ru.windcorp.progressia.common.world.generic.GenericChunks; import ru.windcorp.progressia.common.world.rels.RelFace; @@ -71,7 +71,7 @@ public class ChunkRenderOptimizerSurface extends ChunkRenderOptimizer { * vertices */ void getShapeParts( - ChunkData chunk, + DefaultChunkData chunk, Vec3i relBlockInChunk, RelFace blockFace, boolean inner, diff --git a/src/main/java/ru/windcorp/progressia/client/world/entity/EntityRenderable.java b/src/main/java/ru/windcorp/progressia/client/world/entity/EntityRenderable.java index fcd50f6..1749ffb 100644 --- a/src/main/java/ru/windcorp/progressia/client/world/entity/EntityRenderable.java +++ b/src/main/java/ru/windcorp/progressia/client/world/entity/EntityRenderable.java @@ -23,9 +23,9 @@ import ru.windcorp.progressia.client.graphics.backend.GraphicsInterface; import ru.windcorp.progressia.client.graphics.model.Renderable; import ru.windcorp.progressia.client.graphics.model.ShapeRenderHelper; import ru.windcorp.progressia.common.world.entity.EntityData; -import ru.windcorp.progressia.common.world.generic.GenericEntity; +import ru.windcorp.progressia.common.world.generic.EntityGeneric; -public abstract class EntityRenderable implements Renderable, GenericEntity { +public abstract class EntityRenderable implements Renderable, EntityGeneric { private final EntityData data; diff --git a/src/main/java/ru/windcorp/progressia/client/world/tile/TileRender.java b/src/main/java/ru/windcorp/progressia/client/world/tile/TileRender.java index 38c4ae9..dcb6c54 100644 --- a/src/main/java/ru/windcorp/progressia/client/world/tile/TileRender.java +++ b/src/main/java/ru/windcorp/progressia/client/world/tile/TileRender.java @@ -22,17 +22,17 @@ import glm.vec._3.i.Vec3i; import ru.windcorp.progressia.client.graphics.model.Renderable; import ru.windcorp.progressia.client.world.cro.ChunkRenderOptimizer; import ru.windcorp.progressia.common.util.namespaces.Namespaced; -import ru.windcorp.progressia.common.world.ChunkData; -import ru.windcorp.progressia.common.world.generic.GenericTile; +import ru.windcorp.progressia.common.world.DefaultChunkData; +import ru.windcorp.progressia.common.world.generic.TileGeneric; import ru.windcorp.progressia.common.world.rels.RelFace; -public class TileRender extends Namespaced implements GenericTile { +public class TileRender extends Namespaced implements TileGeneric { public TileRender(String id) { super(id); } - public Renderable createRenderable(ChunkData chunk, Vec3i blockInChunk, RelFace face) { + public Renderable createRenderable(DefaultChunkData chunk, Vec3i blockInChunk, RelFace face) { return null; } diff --git a/src/main/java/ru/windcorp/progressia/client/world/tile/TileRenderNone.java b/src/main/java/ru/windcorp/progressia/client/world/tile/TileRenderNone.java index f8ad55b..894a42d 100644 --- a/src/main/java/ru/windcorp/progressia/client/world/tile/TileRenderNone.java +++ b/src/main/java/ru/windcorp/progressia/client/world/tile/TileRenderNone.java @@ -20,7 +20,7 @@ package ru.windcorp.progressia.client.world.tile; import glm.vec._3.i.Vec3i; import ru.windcorp.progressia.client.graphics.model.EmptyModel; import ru.windcorp.progressia.client.graphics.model.Renderable; -import ru.windcorp.progressia.common.world.ChunkData; +import ru.windcorp.progressia.common.world.DefaultChunkData; import ru.windcorp.progressia.common.world.rels.RelFace; public class TileRenderNone extends TileRender { @@ -30,7 +30,7 @@ public class TileRenderNone extends TileRender { } @Override - public Renderable createRenderable(ChunkData chunk, Vec3i blockInChunk, RelFace face) { + public Renderable createRenderable(DefaultChunkData chunk, Vec3i blockInChunk, RelFace face) { return EmptyModel.getInstance(); } diff --git a/src/main/java/ru/windcorp/progressia/client/world/tile/TileRenderReference.java b/src/main/java/ru/windcorp/progressia/client/world/tile/TileRenderReference.java index 3def556..9ec5194 100644 --- a/src/main/java/ru/windcorp/progressia/client/world/tile/TileRenderReference.java +++ b/src/main/java/ru/windcorp/progressia/client/world/tile/TileRenderReference.java @@ -19,9 +19,9 @@ package ru.windcorp.progressia.client.world.tile; import ru.windcorp.progressia.client.world.ChunkRender; import ru.windcorp.progressia.client.world.block.BlockRender; -import ru.windcorp.progressia.common.world.generic.GenericTileReference; +import ru.windcorp.progressia.common.world.generic.TileGenericReferenceRO; public interface TileRenderReference - extends GenericTileReference { + extends TileGenericReferenceRO { } diff --git a/src/main/java/ru/windcorp/progressia/client/world/tile/TileRenderStack.java b/src/main/java/ru/windcorp/progressia/client/world/tile/TileRenderStack.java index ca95cd2..b0c6b65 100644 --- a/src/main/java/ru/windcorp/progressia/client/world/tile/TileRenderStack.java +++ b/src/main/java/ru/windcorp/progressia/client/world/tile/TileRenderStack.java @@ -18,13 +18,15 @@ package ru.windcorp.progressia.client.world.tile; +import java.util.AbstractList; + import ru.windcorp.progressia.client.world.ChunkRender; import ru.windcorp.progressia.client.world.block.BlockRender; -import ru.windcorp.progressia.common.world.generic.GenericTileStack; -import ru.windcorp.progressia.common.world.tile.TileDataStack; - +import ru.windcorp.progressia.common.world.TileDataStack; +import ru.windcorp.progressia.common.world.generic.TileGenericStackRO; public abstract class TileRenderStack - extends GenericTileStack { + extends AbstractList + implements TileGenericStackRO { public abstract TileDataStack getData(); diff --git a/src/main/java/ru/windcorp/progressia/client/world/tile/TileRenderSurface.java b/src/main/java/ru/windcorp/progressia/client/world/tile/TileRenderSurface.java index 91eeb00..604bf69 100644 --- a/src/main/java/ru/windcorp/progressia/client/world/tile/TileRenderSurface.java +++ b/src/main/java/ru/windcorp/progressia/client/world/tile/TileRenderSurface.java @@ -33,7 +33,7 @@ import ru.windcorp.progressia.client.graphics.texture.Texture; import ru.windcorp.progressia.client.graphics.world.WorldRenderProgram; import ru.windcorp.progressia.client.world.cro.ChunkRenderOptimizerSurface.TileOptimizedSurface; import ru.windcorp.progressia.common.util.Vectors; -import ru.windcorp.progressia.common.world.ChunkData; +import ru.windcorp.progressia.common.world.DefaultChunkData; import ru.windcorp.progressia.common.world.rels.AbsFace; import ru.windcorp.progressia.common.world.rels.RelFace; @@ -60,7 +60,7 @@ public abstract class TileRenderSurface extends TileRender implements TileOptimi @Override public final void getShapeParts( - ChunkData chunk, Vec3i relBlockInChunk, RelFace blockFace, + DefaultChunkData chunk, Vec3i relBlockInChunk, RelFace blockFace, boolean inner, Consumer output, Vec3 offset @@ -69,7 +69,7 @@ public abstract class TileRenderSurface extends TileRender implements TileOptimi } private ShapePart createFace( - ChunkData chunk, Vec3i blockInChunk, RelFace blockFace, + DefaultChunkData chunk, Vec3i blockInChunk, RelFace blockFace, boolean inner, Vec3 offset ) { @@ -84,7 +84,7 @@ public abstract class TileRenderSurface extends TileRender implements TileOptimi } @Override - public Renderable createRenderable(ChunkData chunk, Vec3i blockInChunk, RelFace blockFace) { + public Renderable createRenderable(DefaultChunkData chunk, Vec3i blockInChunk, RelFace blockFace) { return new Shape( Usage.STATIC, WorldRenderProgram.getDefault(), diff --git a/src/main/java/ru/windcorp/progressia/common/collision/WorldCollisionHelper.java b/src/main/java/ru/windcorp/progressia/common/collision/WorldCollisionHelper.java index 69d2d4a..69b157d 100644 --- a/src/main/java/ru/windcorp/progressia/common/collision/WorldCollisionHelper.java +++ b/src/main/java/ru/windcorp/progressia/common/collision/WorldCollisionHelper.java @@ -24,7 +24,7 @@ import java.util.Collection; import glm.vec._3.Vec3; import glm.vec._3.i.Vec3i; import ru.windcorp.progressia.common.util.LowOverheadCache; -import ru.windcorp.progressia.common.world.WorldData; +import ru.windcorp.progressia.common.world.DefaultWorldData; public class WorldCollisionHelper { @@ -79,7 +79,7 @@ public class WorldCollisionHelper { * checked against * @param maxTime maximum collision time */ - public void tuneToCollideable(WorldData world, Collideable collideable, float maxTime) { + public void tuneToCollideable(DefaultWorldData world, Collideable collideable, float maxTime) { activeBlockModels.forEach(blockModelCache::release); activeBlockModels.clear(); CollisionPathComputer.forEveryBlockInCollisionPath( diff --git a/src/main/java/ru/windcorp/progressia/common/collision/colliders/Collider.java b/src/main/java/ru/windcorp/progressia/common/collision/colliders/Collider.java index 62a7808..9b97e40 100644 --- a/src/main/java/ru/windcorp/progressia/common/collision/colliders/Collider.java +++ b/src/main/java/ru/windcorp/progressia/common/collision/colliders/Collider.java @@ -27,7 +27,7 @@ import glm.vec._3.Vec3; import ru.windcorp.progressia.common.collision.*; import ru.windcorp.progressia.common.util.LowOverheadCache; import ru.windcorp.progressia.common.util.Vectors; -import ru.windcorp.progressia.common.world.WorldData; +import ru.windcorp.progressia.common.world.DefaultWorldData; public class Collider { @@ -36,7 +36,7 @@ public class Collider { /** * Dear Princess Celestia, *

    - * When {@linkplain #advanceTime(Collection, Collision, WorldData, float) + * When {@linkplain #advanceTime(Collection, Collision, DefaultWorldData, float) * advancing time}, * time step for all entities except currently colliding bodies is * the current @@ -61,7 +61,7 @@ public class Collider { public static void performCollisions( List colls, - WorldData world, + DefaultWorldData world, float tickLength, ColliderWorkspace workspace ) { @@ -96,7 +96,7 @@ public class Collider { private static Collision getFirstCollision( List colls, float tickLength, - WorldData world, + DefaultWorldData world, ColliderWorkspace workspace ) { Collision result = null; @@ -126,7 +126,7 @@ public class Collider { private static void tuneWorldCollisionHelper( Collideable coll, float tickLength, - WorldData world, + DefaultWorldData world, ColliderWorkspace workspace ) { WorldCollisionHelper wch = workspace.worldCollisionHelper; @@ -194,7 +194,7 @@ public class Collider { Collision collision, Collection colls, - WorldData world, + DefaultWorldData world, float tickLength, ColliderWorkspace workspace ) { @@ -361,7 +361,7 @@ public class Collider { private static void advanceTime( Collection colls, Collision exceptions, - WorldData world, + DefaultWorldData world, float step ) { world.advanceTime(step); diff --git a/src/main/java/ru/windcorp/progressia/common/world/tile/TileDataReference.java b/src/main/java/ru/windcorp/progressia/common/state/StateChange.java similarity index 66% rename from src/main/java/ru/windcorp/progressia/common/world/tile/TileDataReference.java rename to src/main/java/ru/windcorp/progressia/common/state/StateChange.java index b9699c2..38638a7 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/tile/TileDataReference.java +++ b/src/main/java/ru/windcorp/progressia/common/state/StateChange.java @@ -16,12 +16,9 @@ * along with this program. If not, see . */ -package ru.windcorp.progressia.common.world.tile; - -import ru.windcorp.progressia.common.world.ChunkData; -import ru.windcorp.progressia.common.world.block.BlockData; -import ru.windcorp.progressia.common.world.generic.GenericTileReference; - -public interface TileDataReference extends GenericTileReference { +package ru.windcorp.progressia.common.state; +@FunctionalInterface +public interface StateChange { + void change(T object); } diff --git a/src/main/java/ru/windcorp/progressia/common/world/ChunkData.java b/src/main/java/ru/windcorp/progressia/common/world/ChunkData.java index 728bc80..ab55863 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/ChunkData.java +++ b/src/main/java/ru/windcorp/progressia/common/world/ChunkData.java @@ -1,527 +1,14 @@ -/* - * 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.common.world; -import static ru.windcorp.progressia.common.world.rels.BlockFace.BLOCK_FACE_COUNT; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; -import java.util.Objects; - -import glm.vec._3.i.Vec3i; - import ru.windcorp.progressia.common.world.block.BlockData; -import ru.windcorp.progressia.common.world.generic.GenericChunks; -import ru.windcorp.progressia.common.world.generic.GenericWritableChunk; -import ru.windcorp.progressia.common.world.rels.AbsFace; -import ru.windcorp.progressia.common.world.rels.BlockFace; -import ru.windcorp.progressia.common.world.rels.RelFace; +import ru.windcorp.progressia.common.world.generic.ChunkGenericWO; import ru.windcorp.progressia.common.world.tile.TileData; -import ru.windcorp.progressia.common.world.tile.TileDataReference; -import ru.windcorp.progressia.common.world.tile.TileDataStack; -import ru.windcorp.progressia.common.world.tile.TileStackIsFullException; -public class ChunkData - implements GenericWritableChunk { - - public static final int BLOCKS_PER_CHUNK = Coordinates.CHUNK_SIZE; - public static final int CHUNK_RADIUS = BLOCKS_PER_CHUNK / 2; - - private final Vec3i position = new Vec3i(); - private final WorldData world; - - private final BlockData[] blocks = new BlockData[BLOCKS_PER_CHUNK * BLOCKS_PER_CHUNK * BLOCKS_PER_CHUNK]; - - private final TileDataStack[] tiles = new TileDataStack[ - BLOCKS_PER_CHUNK * BLOCKS_PER_CHUNK * BLOCKS_PER_CHUNK * BLOCK_FACE_COUNT - ]; +public interface ChunkData extends ChunkDataRO, ChunkGenericWO { - private final AbsFace up; - - private Object generationHint = null; - - private final Collection listeners = Collections.synchronizedCollection(new ArrayList<>()); - - public ChunkData(Vec3i position, WorldData world) { - this.position.set(position.x, position.y, position.z); - this.world = world; - this.up = world.getGravityModel().getDiscreteUp(position); - } - - @Override - public Vec3i getPosition() { - return position; - } - - @Override - public AbsFace getUp() { - return up; - } - - @Override - public BlockData getBlock(Vec3i posInChunk) { - return blocks[getBlockIndex(posInChunk)]; - } - - @Override - public void setBlock(Vec3i posInChunk, BlockData block, boolean notify) { - BlockData previous = blocks[getBlockIndex(posInChunk)]; - blocks[getBlockIndex(posInChunk)] = block; - - if (notify) { - getListeners().forEach(l -> { - l.onChunkBlockChanged(this, posInChunk, previous, block); - l.onChunkChanged(this); - }); - } - } - - @Override - public TileDataStack getTilesOrNull(Vec3i blockInChunk, BlockFace face) { - return tiles[getTileIndex(blockInChunk, face)]; - } - - /** - * Internal use only. Modify a list returned by - * {@link #getTiles(Vec3i, BlockFace)} or - * {@link #getTilesOrNull(Vec3i, BlockFace)} - * to change tiles. - */ - protected void setTiles( - Vec3i blockInChunk, - BlockFace face, - TileDataStack tiles - ) { - this.tiles[getTileIndex(blockInChunk, face)] = tiles; - } - - @Override - public boolean hasTiles(Vec3i blockInChunk, BlockFace face) { - return getTilesOrNull(blockInChunk, face) != null; - } - - @Override - public TileDataStack getTiles(Vec3i blockInChunk, BlockFace face) { - int index = getTileIndex(blockInChunk, face); - - if (tiles[index] == null) { - createTileStack(blockInChunk, face); - } - - return tiles[index]; - } - - private void createTileStack(Vec3i blockInChunk, BlockFace face) { - Vec3i independentBlockInChunk = conjureIndependentBlockInChunkVec3i(blockInChunk); - TileDataStackImpl stack = new TileDataStackImpl(independentBlockInChunk, face); - setTiles(blockInChunk, face, stack); - } - - private Vec3i conjureIndependentBlockInChunkVec3i(Vec3i blockInChunk) { - for (int i = 0; i < AbsFace.BLOCK_FACE_COUNT; ++i) { - TileDataStack stack = getTilesOrNull(blockInChunk, AbsFace.getFaces().get(i)); - if (stack instanceof TileDataStackImpl) { - return ((TileDataStackImpl) stack).blockInChunk; - } - } - - return new Vec3i(blockInChunk); - } - - private static int getBlockIndex(Vec3i posInChunk) { - checkLocalCoordinates(posInChunk); - - return posInChunk.z * BLOCKS_PER_CHUNK * BLOCKS_PER_CHUNK + - posInChunk.y * BLOCKS_PER_CHUNK + - posInChunk.x; - } - - private int getTileIndex(Vec3i posInChunk, BlockFace face) { - return getBlockIndex(posInChunk) * BLOCK_FACE_COUNT + - face.resolve(getUp()).getId(); - } - - private static void checkLocalCoordinates(Vec3i posInChunk) { - if (!GenericChunks.containsBiC(posInChunk)) { - throw new IllegalCoordinatesException( - "Coordinates (" + posInChunk.x + "; " + posInChunk.y + "; " + posInChunk.z + ") " - + "are not legal chunk coordinates" - ); - } - } - - public WorldData getWorld() { - return world; - } - - public Collection getListeners() { - return listeners; - } - - public void addListener(ChunkDataListener listener) { - this.listeners.add(listener); - } - - public void removeListener(ChunkDataListener listener) { - this.listeners.remove(listener); - } - - protected void onLoaded() { - getListeners().forEach(l -> l.onChunkLoaded(this)); - } - - protected void beforeUnloaded() { - getListeners().forEach(l -> l.beforeChunkUnloaded(this)); - } - - public Object getGenerationHint() { - return generationHint; - } - - public void setGenerationHint(Object generationHint) { - this.generationHint = generationHint; - } - - /** - * Implementation of {@link TileDataStack} used internally by - * {@link ChunkData} to - * actually store the tiles. This is basically an array wrapper with - * reporting - * capabilities. - * - * @author javapony - */ - private class TileDataStackImpl extends TileDataStack { - private class TileDataReferenceImpl implements TileDataReference { - private int index; - - public TileDataReferenceImpl(int index) { - this.index = index; - } - - public void incrementIndex() { - this.index++; - } - - public void decrementIndex() { - this.index--; - } - - public void invalidate() { - this.index = 0; - } - - @Override - public TileData get() { - if (!isValid()) - return null; - return TileDataStackImpl.this.get(this.index); - } - - @Override - public int getIndex() { - return index; - } - - @Override - public TileDataStack getStack() { - return TileDataStackImpl.this; - } - - @Override - public boolean isValid() { - return this.index >= 0; - } - } - - private final TileData[] tiles = new TileData[TILES_PER_FACE]; - private int size = 0; - - private final TileDataReferenceImpl[] references = new TileDataReferenceImpl[tiles.length]; - private final int[] indicesByTag = new int[tiles.length]; - private final int[] tagsByIndex = new int[tiles.length]; - - { - Arrays.fill(indicesByTag, -1); - Arrays.fill(tagsByIndex, -1); - } - - /* - * Potentially shared - */ - private final Vec3i blockInChunk; - private final RelFace face; - - public TileDataStackImpl(Vec3i blockInChunk, BlockFace face) { - this.blockInChunk = blockInChunk; - this.face = face.relativize(getUp()); - } - - @Override - public Vec3i getBlockInChunk(Vec3i output) { - if (output == null) - output = new Vec3i(); - output.set(blockInChunk.x, blockInChunk.y, blockInChunk.z); - return output; - } - - @Override - public RelFace getFace() { - return face; - } - - @Override - public ChunkData getChunk() { - return ChunkData.this; - } - - @Override - public int size() { - return size; - } - - @Override - public TileData get(int index) { - checkIndex(index, false); - - return tiles[index]; - } - - @Override - public TileData set(int index, TileData tile) { - Objects.requireNonNull(tile, "tile"); - TileData previous = get(index); // checks index - - tiles[index] = tile; - - if (references[index] != null) { - references[index].invalidate(); - references[index] = null; - } - - assert checkConsistency(); - - report(previous, tile); - return previous; - } - - @Override - public void add(int index, TileData tile) { - Objects.requireNonNull(tile, "tile"); - checkIndex(index, true); - - if (index != size()) { - System.arraycopy(tiles, index + 1, tiles, index + 2, size - index); - - for (int i = index; i < size; ++i) { - if (references[i] != null) { - references[i].incrementIndex(); - } - - indicesByTag[tagsByIndex[i]]++; - } - - System.arraycopy(references, index + 1, references, index + 2, size - index); - System.arraycopy(tagsByIndex, index + 1, tagsByIndex, index + 2, size - index); - } - - size++; - tiles[index] = tile; - references[index] = null; - - for (int tag = 0; tag < indicesByTag.length; ++tag) { - if (indicesByTag[tag] == -1) { - indicesByTag[tag] = index; - tagsByIndex[index] = tag; - break; - } - } - - modCount++; - assert checkConsistency(); - - report(null, tile); - } - - @Override - public void load(TileData tile, int tag) { - addFarthest(tile); - - int assignedIndex = size() - 1; - - // Skip if we already have the correct tag - int assignedTag = getTagByIndex(assignedIndex); - if (assignedTag == tag) { - return; - } - assert assignedTag != -1 : "Adding farthest tile resulted in -1 tag"; - - // Make sure we aren't trying to assign a tag already in use - int tileWithRequestedTag = getIndexByTag(tag); - if (tileWithRequestedTag != -1) { - throw new IllegalArgumentException( - "Tag " + tag + " already used by tile at index " + tileWithRequestedTag - ); - } - assert tileWithRequestedTag != assignedIndex : "tag == assignedTag yet tileWithRequestedTag != assignedIndex"; - - // Do the tag editing - indicesByTag[assignedTag] = -1; // Release assigned tag - tagsByIndex[assignedIndex] = tag; // Reroute assigned index to requested tag - indicesByTag[tag] = assignedIndex; // Claim requested tag - assert checkConsistency(); - } - - @Override - public TileData remove(int index) { - TileData previous = get(index); // checks index - - if (references[index] != null) { - references[index].invalidate(); - } - - indicesByTag[tagsByIndex[index]] = -1; - - if (index != size() - 1) { - System.arraycopy(tiles, index + 1, tiles, index, size - index - 1); - - for (int i = index + 1; i < size; ++i) { - if (references[i] != null) { - references[i].decrementIndex(); - } - - indicesByTag[tagsByIndex[i]]--; - } - - System.arraycopy(references, index + 1, references, index, size - index - 1); - System.arraycopy(tagsByIndex, index + 1, tagsByIndex, index, size - index - 1); - } - - size--; - tiles[size] = null; - references[size] = null; - tagsByIndex[size] = -1; - - modCount++; - assert checkConsistency(); - - report(previous, null); - return previous; - } - - @Override - public TileDataReference getReference(int index) { - checkIndex(index, false); - - if (references[index] == null) { - references[index] = new TileDataReferenceImpl(index); - } - - return references[index]; - } - - @Override - public int getIndexByTag(int tag) { - return indicesByTag[tag]; - } - - @Override - public int getTagByIndex(int index) { - checkIndex(index, false); - return tagsByIndex[index]; - } - - @Override - public void clear() { - while (!isEmpty()) { - removeFarthest(); - } - } - - private void checkIndex(int index, boolean isSizeAllowed) { - if (isSizeAllowed ? (index > size()) : (index >= size())) - throw new IndexOutOfBoundsException("Index " + index + " is out of bounds: size is " + size); - - if (index < 0) - throw new IndexOutOfBoundsException("Index " + index + " is out of bounds: index cannot be negative"); - - if (index >= TILES_PER_FACE) - throw new TileStackIsFullException( - "Index " + index + " is out of bounds: maximum tile stack size is " + TILES_PER_FACE - ); - } - - private void report(TileData previous, TileData current) { - ChunkData.this.getListeners().forEach(l -> { - if (previous != null) { - l.onChunkTilesChanged(ChunkData.this, blockInChunk, face, previous, false); - } - - if (current != null) { - l.onChunkTilesChanged(ChunkData.this, blockInChunk, face, current, true); - } - - l.onChunkChanged(ChunkData.this); - }); - } - - private boolean checkConsistency() { - int index; - - for (index = 0; index < size(); ++index) { - if (get(index) == null) - throw new AssertionError("get(index) is null"); - - if (references[index] != null) { - TileDataReference ref = getReference(index); - if (ref == null) - throw new AssertionError("references[index] is not null but getReference(index) is"); - if (!ref.isValid()) - throw new AssertionError("Reference is not valid"); - if (ref.get() != get(index)) - throw new AssertionError("Reference points to " + (ref.get() == null ? "null" : "wrong tile")); - if (ref.getIndex() != index) - throw new AssertionError("Reference has invalid index"); - if (ref.getStack() != this) - throw new AssertionError("Reference has invalid TDS"); - } - - if (index != indicesByTag[tagsByIndex[index]]) - throw new AssertionError("Tag mapping is inconsistent"); - if (index != getIndexByTag(getTagByIndex(index))) - throw new AssertionError("Tag methods are inconsistent with tag mapping"); - } - - for (; index < tiles.length; ++index) { - if (tiles[index] != null) - throw new AssertionError("Leftover tile detected"); - if (references[index] != null) - throw new AssertionError("Leftover reference detected"); - if (tagsByIndex[index] != -1) - throw new AssertionError("Leftover tags detected"); - } - - return true; - } - - } +// @Override +// default TileDataStack getTiles(Vec3i blockInChunk, BlockFace face) { +// return null; +// } } diff --git a/src/main/java/ru/windcorp/progressia/common/world/ChunkDataListener.java b/src/main/java/ru/windcorp/progressia/common/world/ChunkDataListener.java index 0dc7088..22b4fb3 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/ChunkDataListener.java +++ b/src/main/java/ru/windcorp/progressia/common/world/ChunkDataListener.java @@ -36,7 +36,7 @@ public interface ChunkDataListener { * @param previous the previous occupant of {@code blockInChunk} * @param current the current (new) occupant of {@code blockInChunk} */ - default void onChunkBlockChanged(ChunkData chunk, Vec3i blockInChunk, BlockData previous, BlockData current) { + default void onChunkBlockChanged(DefaultChunkData chunk, Vec3i blockInChunk, BlockData previous, BlockData current) { } /** @@ -53,7 +53,7 @@ public interface ChunkDataListener { * {@code false} iff the tile has been removed */ default void onChunkTilesChanged( - ChunkData chunk, + DefaultChunkData chunk, Vec3i blockInChunk, RelFace face, TileData tile, @@ -70,7 +70,7 @@ public interface ChunkDataListener { * * @param chunk the chunk that has changed */ - default void onChunkChanged(ChunkData chunk) { + default void onChunkChanged(DefaultChunkData chunk) { } /** @@ -78,7 +78,7 @@ public interface ChunkDataListener { * * @param chunk the chunk that has loaded */ - default void onChunkLoaded(ChunkData chunk) { + default void onChunkLoaded(DefaultChunkData chunk) { } /** @@ -86,7 +86,7 @@ public interface ChunkDataListener { * * @param chunk the chunk that is going to be loaded */ - default void beforeChunkUnloaded(ChunkData chunk) { + default void beforeChunkUnloaded(DefaultChunkData chunk) { } } diff --git a/src/main/java/ru/windcorp/progressia/common/world/ChunkDataListeners.java b/src/main/java/ru/windcorp/progressia/common/world/ChunkDataListeners.java index b39437c..a9a4168 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/ChunkDataListeners.java +++ b/src/main/java/ru/windcorp/progressia/common/world/ChunkDataListeners.java @@ -28,7 +28,7 @@ public class ChunkDataListeners { public static WorldDataListener createAdder(Supplier listenerSupplier) { return new WorldDataListener() { @Override - public void getChunkListeners(WorldData world, Vec3i chunk, Consumer chunkListenerSink) { + public void getChunkListeners(DefaultWorldData world, Vec3i chunk, Consumer chunkListenerSink) { chunkListenerSink.accept(listenerSupplier.get()); } }; diff --git a/src/main/java/ru/windcorp/progressia/common/world/ChunkDataRO.java b/src/main/java/ru/windcorp/progressia/common/world/ChunkDataRO.java new file mode 100644 index 0000000..08ce159 --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/common/world/ChunkDataRO.java @@ -0,0 +1,12 @@ +package ru.windcorp.progressia.common.world; + +import ru.windcorp.progressia.common.world.block.BlockData; +import ru.windcorp.progressia.common.world.generic.ChunkGenericRO; +import ru.windcorp.progressia.common.world.tile.TileData; + +public interface ChunkDataRO + extends ChunkGenericRO { + + // currently empty + +} diff --git a/src/main/java/ru/windcorp/progressia/common/world/Coordinates.java b/src/main/java/ru/windcorp/progressia/common/world/Coordinates.java index 55f2076..b43231b 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/Coordinates.java +++ b/src/main/java/ru/windcorp/progressia/common/world/Coordinates.java @@ -18,7 +18,7 @@ package ru.windcorp.progressia.common.world; -import static ru.windcorp.progressia.common.world.ChunkData.BLOCKS_PER_CHUNK; +import static ru.windcorp.progressia.common.world.DefaultChunkData.BLOCKS_PER_CHUNK; import glm.vec._3.i.Vec3i; diff --git a/src/main/java/ru/windcorp/progressia/common/world/DefaultChunkData.java b/src/main/java/ru/windcorp/progressia/common/world/DefaultChunkData.java new file mode 100644 index 0000000..5c1cd08 --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/common/world/DefaultChunkData.java @@ -0,0 +1,525 @@ +/* + * 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.common.world; + +import static ru.windcorp.progressia.common.world.rels.BlockFace.BLOCK_FACE_COUNT; + +import java.util.AbstractList; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.Objects; + +import glm.vec._3.i.Vec3i; + +import ru.windcorp.progressia.common.world.block.BlockData; +import ru.windcorp.progressia.common.world.generic.GenericChunks; +import ru.windcorp.progressia.common.world.rels.AbsFace; +import ru.windcorp.progressia.common.world.rels.BlockFace; +import ru.windcorp.progressia.common.world.rels.RelFace; +import ru.windcorp.progressia.common.world.tile.TileData; +import ru.windcorp.progressia.common.world.tile.TileStackIsFullException; + +public class DefaultChunkData implements ChunkData { + + public static final int BLOCKS_PER_CHUNK = Coordinates.CHUNK_SIZE; + public static final int CHUNK_RADIUS = BLOCKS_PER_CHUNK / 2; + + private final Vec3i position = new Vec3i(); + private final DefaultWorldData world; + + private final BlockData[] blocks = new BlockData[BLOCKS_PER_CHUNK * BLOCKS_PER_CHUNK * BLOCKS_PER_CHUNK]; + + private final TileDataStack[] tiles = new TileDataStack[BLOCKS_PER_CHUNK * BLOCKS_PER_CHUNK * BLOCKS_PER_CHUNK + * BLOCK_FACE_COUNT]; + + private final AbsFace up; + + private Object generationHint = null; + + private final Collection listeners = Collections.synchronizedCollection(new ArrayList<>()); + + public DefaultChunkData(Vec3i position, DefaultWorldData world) { + this.position.set(position.x, position.y, position.z); + this.world = world; + this.up = world.getGravityModel().getDiscreteUp(position); + } + + @Override + public Vec3i getPosition() { + return position; + } + + @Override + public AbsFace getUp() { + return up; + } + + @Override + public BlockData getBlock(Vec3i posInChunk) { + return blocks[getBlockIndex(posInChunk)]; + } + + @Override + public void setBlock(Vec3i posInChunk, BlockData block, boolean notify) { + BlockData previous = blocks[getBlockIndex(posInChunk)]; + blocks[getBlockIndex(posInChunk)] = block; + + if (notify) { + getListeners().forEach(l -> { + l.onChunkBlockChanged(this, posInChunk, previous, block); + l.onChunkChanged(this); + }); + } + } + + @Override + public TileDataStack getTilesOrNull(Vec3i blockInChunk, BlockFace face) { + return tiles[getTileIndex(blockInChunk, face)]; + } + + /** + * Internal use only. Modify a list returned by + * {@link #getTiles(Vec3i, BlockFace)} or + * {@link #getTilesOrNull(Vec3i, BlockFace)} + * to change tiles. + */ + protected void setTiles( + Vec3i blockInChunk, + BlockFace face, + TileDataStack tiles + ) { + this.tiles[getTileIndex(blockInChunk, face)] = tiles; + } + + @Override + public boolean hasTiles(Vec3i blockInChunk, BlockFace face) { + return getTilesOrNull(blockInChunk, face) != null; + } + + @Override + public TileDataStack getTiles(Vec3i blockInChunk, BlockFace face) { + int index = getTileIndex(blockInChunk, face); + + if (tiles[index] == null) { + createTileStack(blockInChunk, face); + } + + return tiles[index]; + } + + private void createTileStack(Vec3i blockInChunk, BlockFace face) { + Vec3i independentBlockInChunk = conjureIndependentBlockInChunkVec3i(blockInChunk); + TileDataStackImpl stack = new TileDataStackImpl(independentBlockInChunk, face); + setTiles(blockInChunk, face, stack); + } + + private Vec3i conjureIndependentBlockInChunkVec3i(Vec3i blockInChunk) { + for (int i = 0; i < AbsFace.BLOCK_FACE_COUNT; ++i) { + TileDataStack stack = getTilesOrNull(blockInChunk, AbsFace.getFaces().get(i)); + if (stack instanceof TileDataStackImpl) { + return ((TileDataStackImpl) stack).blockInChunk; + } + } + + return new Vec3i(blockInChunk); + } + + private static int getBlockIndex(Vec3i posInChunk) { + checkLocalCoordinates(posInChunk); + + return posInChunk.z * BLOCKS_PER_CHUNK * BLOCKS_PER_CHUNK + + posInChunk.y * BLOCKS_PER_CHUNK + + posInChunk.x; + } + + private int getTileIndex(Vec3i posInChunk, BlockFace face) { + return getBlockIndex(posInChunk) * BLOCK_FACE_COUNT + + face.resolve(getUp()).getId(); + } + + private static void checkLocalCoordinates(Vec3i posInChunk) { + if (!GenericChunks.containsBiC(posInChunk)) { + throw new IllegalCoordinatesException( + "Coordinates (" + posInChunk.x + "; " + posInChunk.y + "; " + posInChunk.z + ") " + + "are not legal chunk coordinates" + ); + } + } + + public DefaultWorldData getWorld() { + return world; + } + + public Collection getListeners() { + return listeners; + } + + public void addListener(ChunkDataListener listener) { + this.listeners.add(listener); + } + + public void removeListener(ChunkDataListener listener) { + this.listeners.remove(listener); + } + + protected void onLoaded() { + getListeners().forEach(l -> l.onChunkLoaded(this)); + } + + protected void beforeUnloaded() { + getListeners().forEach(l -> l.beforeChunkUnloaded(this)); + } + + public Object getGenerationHint() { + return generationHint; + } + + public void setGenerationHint(Object generationHint) { + this.generationHint = generationHint; + } + + /** + * Implementation of {@link TileDataStack} used internally by + * {@link DefaultChunkData} to + * actually store the tiles. This is basically an array wrapper with + * reporting + * capabilities. + * + * @author javapony + */ + private class TileDataStackImpl extends AbstractList implements TileDataStack { + private class TileDataReferenceImpl implements TileDataReference { + private int index; + + public TileDataReferenceImpl(int index) { + this.index = index; + } + + public void incrementIndex() { + this.index++; + } + + public void decrementIndex() { + this.index--; + } + + public void invalidate() { + this.index = 0; + } + + @Override + public TileData get() { + if (!isValid()) + return null; + return TileDataStackImpl.this.get(this.index); + } + + @Override + public int getIndex() { + return index; + } + + @Override + public TileDataStack getStack() { + return TileDataStackImpl.this; + } + + @Override + public boolean isValid() { + return this.index >= 0; + } + } + + private final TileData[] tiles = new TileData[TILES_PER_FACE]; + private int size = 0; + + private final TileDataReferenceImpl[] references = new TileDataReferenceImpl[tiles.length]; + private final int[] indicesByTag = new int[tiles.length]; + private final int[] tagsByIndex = new int[tiles.length]; + + { + Arrays.fill(indicesByTag, -1); + Arrays.fill(tagsByIndex, -1); + } + + /* + * Potentially shared + */ + private final Vec3i blockInChunk; + private final RelFace face; + + public TileDataStackImpl(Vec3i blockInChunk, BlockFace face) { + this.blockInChunk = blockInChunk; + this.face = face.relativize(getUp()); + } + + @Override + public Vec3i getBlockInChunk(Vec3i output) { + if (output == null) + output = new Vec3i(); + output.set(blockInChunk.x, blockInChunk.y, blockInChunk.z); + return output; + } + + @Override + public RelFace getFace() { + return face; + } + + @Override + public DefaultChunkData getChunk() { + return DefaultChunkData.this; + } + + @Override + public int size() { + return size; + } + + @Override + public TileData get(int index) { + checkIndex(index, false); + + return tiles[index]; + } + + @Override + public TileData set(int index, TileData tile) { + Objects.requireNonNull(tile, "tile"); + TileData previous = get(index); // checks index + + tiles[index] = tile; + + if (references[index] != null) { + references[index].invalidate(); + references[index] = null; + } + + assert checkConsistency(); + + report(previous, tile); + return previous; + } + + @Override + public void add(int index, TileData tile) { + Objects.requireNonNull(tile, "tile"); + checkIndex(index, true); + + if (index != size()) { + System.arraycopy(tiles, index + 1, tiles, index + 2, size - index); + + for (int i = index; i < size; ++i) { + if (references[i] != null) { + references[i].incrementIndex(); + } + + indicesByTag[tagsByIndex[i]]++; + } + + System.arraycopy(references, index + 1, references, index + 2, size - index); + System.arraycopy(tagsByIndex, index + 1, tagsByIndex, index + 2, size - index); + } + + size++; + tiles[index] = tile; + references[index] = null; + + for (int tag = 0; tag < indicesByTag.length; ++tag) { + if (indicesByTag[tag] == -1) { + indicesByTag[tag] = index; + tagsByIndex[index] = tag; + break; + } + } + + modCount++; + assert checkConsistency(); + + report(null, tile); + } + + @Override + public void load(TileData tile, int tag) { + addFarthest(tile); + + int assignedIndex = size() - 1; + + // Skip if we already have the correct tag + int assignedTag = getTagByIndex(assignedIndex); + if (assignedTag == tag) { + return; + } + assert assignedTag != -1 : "Adding farthest tile resulted in -1 tag"; + + // Make sure we aren't trying to assign a tag already in use + int tileWithRequestedTag = getIndexByTag(tag); + if (tileWithRequestedTag != -1) { + throw new IllegalArgumentException( + "Tag " + tag + " already used by tile at index " + tileWithRequestedTag + ); + } + assert tileWithRequestedTag != assignedIndex + : "tag == assignedTag yet tileWithRequestedTag != assignedIndex"; + + // Do the tag editing + indicesByTag[assignedTag] = -1; // Release assigned tag + tagsByIndex[assignedIndex] = tag; // Reroute assigned index to + // requested tag + indicesByTag[tag] = assignedIndex; // Claim requested tag + assert checkConsistency(); + } + + @Override + public TileData remove(int index) { + TileData previous = get(index); // checks index + + if (references[index] != null) { + references[index].invalidate(); + } + + indicesByTag[tagsByIndex[index]] = -1; + + if (index != size() - 1) { + System.arraycopy(tiles, index + 1, tiles, index, size - index - 1); + + for (int i = index + 1; i < size; ++i) { + if (references[i] != null) { + references[i].decrementIndex(); + } + + indicesByTag[tagsByIndex[i]]--; + } + + System.arraycopy(references, index + 1, references, index, size - index - 1); + System.arraycopy(tagsByIndex, index + 1, tagsByIndex, index, size - index - 1); + } + + size--; + tiles[size] = null; + references[size] = null; + tagsByIndex[size] = -1; + + modCount++; + assert checkConsistency(); + + report(previous, null); + return previous; + } + + @Override + public TileDataReference getReference(int index) { + checkIndex(index, false); + + if (references[index] == null) { + references[index] = new TileDataReferenceImpl(index); + } + + return references[index]; + } + + @Override + public int getIndexByTag(int tag) { + return indicesByTag[tag]; + } + + @Override + public int getTagByIndex(int index) { + checkIndex(index, false); + return tagsByIndex[index]; + } + + @Override + public void clear() { + while (!isEmpty()) { + removeFarthest(); + } + } + + private void checkIndex(int index, boolean isSizeAllowed) { + if (isSizeAllowed ? (index > size()) : (index >= size())) + throw new IndexOutOfBoundsException("Index " + index + " is out of bounds: size is " + size); + + if (index < 0) + throw new IndexOutOfBoundsException("Index " + index + " is out of bounds: index cannot be negative"); + + if (index >= TILES_PER_FACE) + throw new TileStackIsFullException( + "Index " + index + " is out of bounds: maximum tile stack size is " + TILES_PER_FACE + ); + } + + private void report(TileData previous, TileData current) { + DefaultChunkData.this.getListeners().forEach(l -> { + if (previous != null) { + l.onChunkTilesChanged(DefaultChunkData.this, blockInChunk, face, previous, false); + } + + if (current != null) { + l.onChunkTilesChanged(DefaultChunkData.this, blockInChunk, face, current, true); + } + + l.onChunkChanged(DefaultChunkData.this); + }); + } + + private boolean checkConsistency() { + int index; + + for (index = 0; index < size(); ++index) { + if (get(index) == null) + throw new AssertionError("get(index) is null"); + + if (references[index] != null) { + TileDataReference ref = getReference(index); + if (ref == null) + throw new AssertionError("references[index] is not null but getReference(index) is"); + if (!ref.isValid()) + throw new AssertionError("Reference is not valid"); + if (ref.get() != get(index)) + throw new AssertionError("Reference points to " + (ref.get() == null ? "null" : "wrong tile")); + if (ref.getIndex() != index) + throw new AssertionError("Reference has invalid index"); + if (ref.getStack() != this) + throw new AssertionError("Reference has invalid TDS"); + } + + if (index != indicesByTag[tagsByIndex[index]]) + throw new AssertionError("Tag mapping is inconsistent"); + if (index != getIndexByTag(getTagByIndex(index))) + throw new AssertionError("Tag methods are inconsistent with tag mapping"); + } + + for (; index < tiles.length; ++index) { + if (tiles[index] != null) + throw new AssertionError("Leftover tile detected"); + if (references[index] != null) + throw new AssertionError("Leftover reference detected"); + if (tagsByIndex[index] != -1) + throw new AssertionError("Leftover tags detected"); + } + + return true; + } + + } + +} diff --git a/src/main/java/ru/windcorp/progressia/common/world/DefaultWorldData.java b/src/main/java/ru/windcorp/progressia/common/world/DefaultWorldData.java new file mode 100644 index 0000000..1de79a6 --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/common/world/DefaultWorldData.java @@ -0,0 +1,262 @@ +/* + * 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.common.world; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Objects; +import java.util.function.Consumer; + +import glm.vec._3.i.Vec3i; +import gnu.trove.TCollections; +import gnu.trove.map.TLongObjectMap; +import gnu.trove.map.hash.TLongObjectHashMap; +import gnu.trove.set.TLongSet; +import ru.windcorp.progressia.common.collision.CollisionModel; +import ru.windcorp.progressia.common.state.StateChange; +import ru.windcorp.progressia.common.state.StatefulObject; +import ru.windcorp.progressia.common.world.block.BlockData; +import ru.windcorp.progressia.common.world.entity.EntityData; +import ru.windcorp.progressia.common.world.generic.ChunkMap; +import ru.windcorp.progressia.common.world.generic.ChunkSet; +import ru.windcorp.progressia.common.world.generic.EntityGeneric; +import ru.windcorp.progressia.common.world.rels.BlockFace; +import ru.windcorp.progressia.common.world.generic.LongBasedChunkMap; + +public class DefaultWorldData implements WorldData { + + private final ChunkMap chunksByPos = new LongBasedChunkMap<>( + TCollections.synchronizedMap(new TLongObjectHashMap<>()) + ); + + private final Collection chunks = Collections.unmodifiableCollection(chunksByPos.values()); + + private final TLongObjectMap entitiesById = TCollections.synchronizedMap(new TLongObjectHashMap<>()); + + private final Collection entities = Collections.unmodifiableCollection(entitiesById.valueCollection()); + + private GravityModel gravityModel = null; + + private float time = 0; + + private final Collection listeners = Collections.synchronizedCollection(new ArrayList<>()); + + public DefaultWorldData() { + + } + + @Override + public DefaultChunkData getChunk(Vec3i pos) { + return chunksByPos.get(pos); + } + + @Override + public DefaultChunkData getChunkByBlock(Vec3i blockInWorld) { + return (DefaultChunkData) WorldData.super.getChunkByBlock(blockInWorld); + } + + @Override + public Collection getChunks() { + return chunks; + } + + public ChunkSet getLoadedChunks() { + return chunksByPos.keys(); + } + + @Override + public Collection getEntities() { + return entities; + } + + @Override + public void forEachEntity(Consumer action) { + synchronized (entitiesById) { // TODO HORRIBLY MUTILATE THE CORPSE OF + // TROVE4J so that + // gnu.trove.impl.sync.SynchronizedCollection.forEach + // is synchronized + getEntities().forEach(action); + } + } + + public TLongSet getLoadedEntities() { + return entitiesById.keySet(); + } + + private void addChunkListeners(DefaultChunkData chunk) { + getListeners().forEach(l -> l.getChunkListeners(this, chunk.getPosition(), chunk::addListener)); + } + + public synchronized void addChunk(DefaultChunkData chunk) { + addChunkListeners(chunk); + + DefaultChunkData previous = chunksByPos.get(chunk); + if (previous != null) { + throw new IllegalArgumentException( + String.format( + "Chunk at (%d; %d; %d) already exists", + chunk.getPosition().x, + chunk.getPosition().y, + chunk.getPosition().z + ) + ); + } + + chunksByPos.put(chunk, chunk); + + chunk.onLoaded(); + getListeners().forEach(l -> l.onChunkLoaded(this, chunk)); + } + + public synchronized void removeChunk(DefaultChunkData chunk) { + getListeners().forEach(l -> l.beforeChunkUnloaded(this, chunk)); + chunk.beforeUnloaded(); + + chunksByPos.remove(chunk); + } + + @Override + public void setBlock(Vec3i blockInWorld, BlockData block, boolean notify) { + DefaultChunkData chunk = getChunkByBlock(blockInWorld); + if (chunk == null) + throw new IllegalCoordinatesException( + "Coordinates " + + "(" + blockInWorld.x + "; " + blockInWorld.y + "; " + blockInWorld.z + ") " + + "do not belong to a loaded chunk" + ); + + chunk.setBlock(Coordinates.convertInWorldToInChunk(blockInWorld, null), block, notify); + } + + @Override + public TileDataStack getTiles(Vec3i blockInWorld, BlockFace face) { + return WorldData.super.getTiles(blockInWorld, face); + } + + @Override + public EntityData getEntity(long entityId) { + return entitiesById.get(entityId); + } + + @Override + public void addEntity(EntityData entity) { + Objects.requireNonNull(entity, "entity"); + + EntityData previous = entitiesById.putIfAbsent(entity.getEntityId(), entity); + + if (previous != null) { + String message = "Cannot add entity " + entity + ": "; + + if (previous == entity) { + message += "already present"; + } else { + message += "entity with the same EntityID already present (" + previous + ")"; + } + + throw new IllegalStateException(message); + } + + getListeners().forEach(l -> l.onEntityAdded(this, entity)); + } + + @Override + public void removeEntity(long entityId) { + synchronized (entitiesById) { + EntityData entity = entitiesById.get(entityId); + + if (entity == null) { + throw new IllegalArgumentException( + "Entity with EntityID " + EntityData.formatEntityId(entityId) + " not present" + ); + } else { + removeEntity(entity); + } + } + } + + @Override + public void removeEntity(EntityData entity) { + Objects.requireNonNull(entity, "entity"); + + getListeners().forEach(l -> l.beforeEntityRemoved(this, entity)); + entitiesById.remove(entity.getEntityId()); + } + + @Override + public void changeEntity(SE entity, StateChange change) { + change.change(entity); + } + + @Override + public float getTime() { + return time; + } + + @Override + public void advanceTime(float change) { + this.time += change; + } + + public CollisionModel getCollisionModelOfBlock(Vec3i blockInWorld) { + DefaultChunkData chunk = getChunkByBlock(blockInWorld); + if (chunk == null) + return null; + + BlockData block = chunk.getBlock(Coordinates.convertInWorldToInChunk(blockInWorld, null)); + if (block == null) + return null; + return block.getCollisionModel(); + } + + /** + * @return the gravity model + */ + @Override + public GravityModel getGravityModel() { + return gravityModel; + } + + /** + * @param gravityModel the gravity model to set + */ + public void setGravityModel(GravityModel gravityModel) { + if (!chunks.isEmpty()) { + throw new IllegalStateException( + "Attempted to change gravity model to " + gravityModel + " while " + chunks.size() + + " chunks were loaded" + ); + } + + this.gravityModel = gravityModel; + } + + public Collection getListeners() { + return listeners; + } + + public void addListener(WorldDataListener e) { + listeners.add(e); + } + + public void removeListener(WorldDataListener o) { + listeners.remove(o); + } + +} diff --git a/src/main/java/ru/windcorp/progressia/common/world/PacketAffectWorld.java b/src/main/java/ru/windcorp/progressia/common/world/PacketAffectWorld.java index 8433b9b..27731ab 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/PacketAffectWorld.java +++ b/src/main/java/ru/windcorp/progressia/common/world/PacketAffectWorld.java @@ -26,6 +26,6 @@ public abstract class PacketAffectWorld extends Packet { super(id); } - public abstract void apply(WorldData world); + public abstract void apply(DefaultWorldData world); } diff --git a/src/main/java/ru/windcorp/progressia/common/world/PacketRevokeChunk.java b/src/main/java/ru/windcorp/progressia/common/world/PacketRevokeChunk.java index c65b045..4849876 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/PacketRevokeChunk.java +++ b/src/main/java/ru/windcorp/progressia/common/world/PacketRevokeChunk.java @@ -53,9 +53,9 @@ public class PacketRevokeChunk extends PacketAffectChunk { } @Override - public void apply(WorldData world) { + public void apply(DefaultWorldData world) { synchronized (world) { - ChunkData chunk = world.getChunk(position); + DefaultChunkData chunk = world.getChunk(position); if (chunk != null) { world.removeChunk(chunk); } diff --git a/src/main/java/ru/windcorp/progressia/common/world/PacketSendChunk.java b/src/main/java/ru/windcorp/progressia/common/world/PacketSendChunk.java index ca079ff..71f2de6 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/PacketSendChunk.java +++ b/src/main/java/ru/windcorp/progressia/common/world/PacketSendChunk.java @@ -41,7 +41,7 @@ public class PacketSendChunk extends PacketAffectChunk { super(id); } - public void set(ChunkData chunk) { + public void set(DefaultChunkData chunk) { this.position.set(chunk.getX(), chunk.getY(), chunk.getZ()); try { @@ -67,7 +67,7 @@ public class PacketSendChunk extends PacketAffectChunk { } @Override - public void apply(WorldData world) { + public void apply(DefaultWorldData world) { try { world.addChunk(ChunkIO.load(world, position, data.getReader(), IOContext.COMMS)); } catch (DecodingException | IOException e) { 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 2fd30a6..454a1fa 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/PacketSetGravityModel.java +++ b/src/main/java/ru/windcorp/progressia/common/world/PacketSetGravityModel.java @@ -61,7 +61,7 @@ public class PacketSetGravityModel extends PacketAffectWorld { } @Override - public void apply(WorldData world) { + public void apply(DefaultWorldData world) { GravityModel model = GravityModelRegistry.getInstance().create(gravityModelId); world.setGravityModel(model); try { diff --git a/src/main/java/ru/windcorp/progressia/common/world/TileDataReference.java b/src/main/java/ru/windcorp/progressia/common/world/TileDataReference.java new file mode 100644 index 0000000..ccc118b --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/common/world/TileDataReference.java @@ -0,0 +1,10 @@ +package ru.windcorp.progressia.common.world; + +import ru.windcorp.progressia.common.world.block.BlockData; +import ru.windcorp.progressia.common.world.generic.TileGenericReferenceWO; +import ru.windcorp.progressia.common.world.tile.TileData; + +public interface TileDataReference extends TileDataReferenceRO, + TileGenericReferenceWO { + +} diff --git a/src/main/java/ru/windcorp/progressia/common/world/TileDataReferenceRO.java b/src/main/java/ru/windcorp/progressia/common/world/TileDataReferenceRO.java new file mode 100644 index 0000000..59257ec --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/common/world/TileDataReferenceRO.java @@ -0,0 +1,12 @@ +package ru.windcorp.progressia.common.world; + +import ru.windcorp.progressia.common.world.block.BlockData; +import ru.windcorp.progressia.common.world.generic.TileGenericReferenceRO; +import ru.windcorp.progressia.common.world.tile.TileData; + +public interface TileDataReferenceRO + extends TileGenericReferenceRO { + + // currently empty + +} diff --git a/src/main/java/ru/windcorp/progressia/common/world/TileDataStack.java b/src/main/java/ru/windcorp/progressia/common/world/TileDataStack.java new file mode 100644 index 0000000..0c17ae4 --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/common/world/TileDataStack.java @@ -0,0 +1,25 @@ +package ru.windcorp.progressia.common.world; + +import ru.windcorp.progressia.common.world.block.BlockData; +import ru.windcorp.progressia.common.world.generic.TileGenericStackWO; +import ru.windcorp.progressia.common.world.tile.TileData; + +public interface TileDataStack + extends TileDataStackRO, TileGenericStackWO { + + @Override + default boolean isFull() { + return TileDataStackRO.super.isFull(); + } + + /* + * Method specialization + */ + + @Override + TileDataReference getReference(int index); + + @Override + ChunkData getChunk(); + +} diff --git a/src/main/java/ru/windcorp/progressia/common/world/TileDataStackRO.java b/src/main/java/ru/windcorp/progressia/common/world/TileDataStackRO.java new file mode 100644 index 0000000..ca74bc4 --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/common/world/TileDataStackRO.java @@ -0,0 +1,12 @@ +package ru.windcorp.progressia.common.world; + +import ru.windcorp.progressia.common.world.block.BlockData; +import ru.windcorp.progressia.common.world.generic.TileGenericStackRO; +import ru.windcorp.progressia.common.world.tile.TileData; + +public interface TileDataStackRO + extends TileGenericStackRO { + + // currently empty + +} diff --git a/src/main/java/ru/windcorp/progressia/common/world/WorldData.java b/src/main/java/ru/windcorp/progressia/common/world/WorldData.java index 13138c5..65f13be 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/WorldData.java +++ b/src/main/java/ru/windcorp/progressia/common/world/WorldData.java @@ -1,245 +1,52 @@ -/* - * 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.common.world; -import java.util.ArrayList; import java.util.Collection; -import java.util.Collections; -import java.util.Objects; -import java.util.function.Consumer; import glm.vec._3.i.Vec3i; -import gnu.trove.TCollections; -import gnu.trove.map.TLongObjectMap; -import gnu.trove.map.hash.TLongObjectHashMap; -import gnu.trove.set.TLongSet; -import ru.windcorp.progressia.common.collision.CollisionModel; import ru.windcorp.progressia.common.world.block.BlockData; import ru.windcorp.progressia.common.world.entity.EntityData; -import ru.windcorp.progressia.common.world.generic.ChunkMap; -import ru.windcorp.progressia.common.world.generic.ChunkSet; -import ru.windcorp.progressia.common.world.generic.GenericWritableWorld; -import ru.windcorp.progressia.common.world.generic.LongBasedChunkMap; +import ru.windcorp.progressia.common.world.generic.WorldGenericWO; +import ru.windcorp.progressia.common.world.rels.BlockFace; import ru.windcorp.progressia.common.world.tile.TileData; -import ru.windcorp.progressia.common.world.tile.TileDataStack; -import ru.windcorp.progressia.common.world.tile.TileDataReference; -public class WorldData - implements GenericWritableWorld { - - private final ChunkMap chunksByPos = new LongBasedChunkMap<>( - TCollections.synchronizedMap(new TLongObjectHashMap<>()) - ); - - private final Collection chunks = Collections.unmodifiableCollection(chunksByPos.values()); - - private final TLongObjectMap entitiesById = TCollections.synchronizedMap(new TLongObjectHashMap<>()); - - private final Collection entities = Collections.unmodifiableCollection(entitiesById.valueCollection()); - - private GravityModel gravityModel = null; - - private float time = 0; - - private final Collection listeners = Collections.synchronizedCollection(new ArrayList<>()); - - public WorldData() { - - } +public interface WorldData + extends WorldDataRO, WorldGenericWO { @Override - public ChunkData getChunk(Vec3i pos) { - return chunksByPos.get(pos); - } - - @Override - public Collection getChunks() { - return chunks; - } - - public ChunkSet getLoadedChunks() { - return chunksByPos.keys(); - } - - @Override - public Collection getEntities() { - return entities; - } - - @Override - public void forEachEntity(Consumer action) { - synchronized (entitiesById) { // TODO HORRIBLY MUTILATE THE CORPSE OF - // TROVE4J so that - // gnu.trove.impl.sync.SynchronizedCollection.forEach - // is synchronized - getEntities().forEach(action); - } - } - - public TLongSet getLoadedEntities() { - return entitiesById.keySet(); - } - - private void addChunkListeners(ChunkData chunk) { - getListeners().forEach(l -> l.getChunkListeners(this, chunk.getPosition(), chunk::addListener)); - } - - public synchronized void addChunk(ChunkData chunk) { - addChunkListeners(chunk); - - ChunkData previous = chunksByPos.get(chunk); - if (previous != null) { - throw new IllegalArgumentException( - String.format( - "Chunk at (%d; %d; %d) already exists", - chunk.getPosition().x, - chunk.getPosition().y, - chunk.getPosition().z - ) - ); - } - - chunksByPos.put(chunk, chunk); - - chunk.onLoaded(); - getListeners().forEach(l -> l.onChunkLoaded(this, chunk)); - } - - public synchronized void removeChunk(ChunkData chunk) { - getListeners().forEach(l -> l.beforeChunkUnloaded(this, chunk)); - chunk.beforeUnloaded(); - - chunksByPos.remove(chunk); - } - - @Override - public void setBlock(Vec3i blockInWorld, BlockData block, boolean notify) { - ChunkData chunk = getChunkByBlock(blockInWorld); - if (chunk == null) - throw new IllegalCoordinatesException( - "Coordinates " - + "(" + blockInWorld.x + "; " + blockInWorld.y + "; " + blockInWorld.z + ") " - + "do not belong to a loaded chunk" - ); - - chunk.setBlock(Coordinates.convertInWorldToInChunk(blockInWorld, null), block, notify); - } - - @Override - public EntityData getEntity(long entityId) { - return entitiesById.get(entityId); - } - - @Override - public void addEntity(EntityData entity) { - Objects.requireNonNull(entity, "entity"); - - EntityData previous = entitiesById.putIfAbsent(entity.getEntityId(), entity); - - if (previous != null) { - String message = "Cannot add entity " + entity + ": "; - - if (previous == entity) { - message += "already present"; - } else { - message += "entity with the same EntityID already present (" + previous + ")"; - } - - throw new IllegalStateException(message); - } - - getListeners().forEach(l -> l.onEntityAdded(this, entity)); - } - - @Override - public void removeEntity(long entityId) { - synchronized (entitiesById) { - EntityData entity = entitiesById.get(entityId); - - if (entity == null) { - throw new IllegalArgumentException( - "Entity with EntityID " + EntityData.formatEntityId(entityId) + " not present" - ); - } else { - removeEntity(entity); - } - } - } - - @Override - public void removeEntity(EntityData entity) { - Objects.requireNonNull(entity, "entity"); - - getListeners().forEach(l -> l.beforeEntityRemoved(this, entity)); - entitiesById.remove(entity.getEntityId()); - } - - public float getTime() { - return time; - } - - public void advanceTime(float change) { - this.time += change; - } - - public CollisionModel getCollisionModelOfBlock(Vec3i blockInWorld) { - ChunkData chunk = getChunkByBlock(blockInWorld); - if (chunk == null) - return null; - - BlockData block = chunk.getBlock(Coordinates.convertInWorldToInChunk(blockInWorld, null)); - if (block == null) - return null; - return block.getCollisionModel(); + default TileDataStack getTiles(Vec3i blockInWorld, BlockFace face) { + return (TileDataStack) WorldDataRO.super.getTiles(blockInWorld, face); } /** - * @return the gravity model + * Increases in-game time of this world by {@code change}. Total time is + * decreased when {@code change} is negative. + * + * @param change the amount of time to add to current world time. May be + * negative. + * @see #getTime() */ - public GravityModel getGravityModel() { - return gravityModel; - } - - /** - * @param gravityModel the gravity model to set + void advanceTime(float change); + + /* + * Method specialization */ - public void setGravityModel(GravityModel gravityModel) { - if (!chunks.isEmpty()) { - throw new IllegalStateException( - "Attempted to change gravity model to " + gravityModel + " while " + chunks.size() - + " chunks were loaded" - ); - } - - this.gravityModel = gravityModel; + + @Override + ChunkData getChunk(Vec3i pos); + + @Override + Collection getChunks(); + + // TODO: rename WGRO.forEachChunk -> forEachChunkRO and define WGWO.forEachChunk + + @Override + default ChunkData getChunkByBlock(Vec3i blockInWorld) { + return (ChunkData) WorldDataRO.super.getChunkByBlock(blockInWorld); } - - public Collection getListeners() { - return listeners; - } - - public void addListener(WorldDataListener e) { - listeners.add(e); - } - - public void removeListener(WorldDataListener o) { - listeners.remove(o); + + @Override + default TileDataStack getTilesOrNull(Vec3i blockInWorld, BlockFace face) { + return (TileDataStack) WorldDataRO.super.getTilesOrNull(blockInWorld, face); } } diff --git a/src/main/java/ru/windcorp/progressia/common/world/WorldDataListener.java b/src/main/java/ru/windcorp/progressia/common/world/WorldDataListener.java index 9211efd..0949566 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/WorldDataListener.java +++ b/src/main/java/ru/windcorp/progressia/common/world/WorldDataListener.java @@ -26,11 +26,11 @@ import ru.windcorp.progressia.common.world.entity.EntityData; public interface WorldDataListener { /** - * Invoked when a new {@link ChunkData} instance is created. This method + * Invoked when a new {@link DefaultChunkData} instance is created. This method * should be used to add * {@link ChunkDataListener}s to a new chunk. When listeners are added with * this method, - * their {@link ChunkDataListener#onChunkLoaded(ChunkData) onChunkLoaded} + * their {@link ChunkDataListener#onChunkLoaded(DefaultChunkData) onChunkLoaded} * methods will be invoked. * * @param world the world instance @@ -41,7 +41,7 @@ public interface WorldDataListener { * {@link Consumer#accept(Object) accept} method * will be added to the chunk. */ - default void getChunkListeners(WorldData world, Vec3i chunk, Consumer chunkListenerSink) { + default void getChunkListeners(DefaultWorldData world, Vec3i chunk, Consumer chunkListenerSink) { } /** @@ -50,7 +50,7 @@ public interface WorldDataListener { * @param world the world instance * @param chunk the chunk that has loaded */ - default void onChunkLoaded(WorldData world, ChunkData chunk) { + default void onChunkLoaded(DefaultWorldData world, DefaultChunkData chunk) { } /** @@ -59,7 +59,7 @@ public interface WorldDataListener { * @param world the world instance * @param chunk the chunk that is going to be unloaded */ - default void beforeChunkUnloaded(WorldData world, ChunkData chunk) { + default void beforeChunkUnloaded(DefaultWorldData world, DefaultChunkData chunk) { } /** @@ -68,7 +68,7 @@ public interface WorldDataListener { * @param world the world instance * @param entity the entity that has been added */ - default void onEntityAdded(WorldData world, EntityData entity) { + default void onEntityAdded(DefaultWorldData world, EntityData entity) { } /** @@ -77,7 +77,7 @@ public interface WorldDataListener { * @param world the world instance * @param entity the entity that is going to be removed */ - default void beforeEntityRemoved(WorldData world, EntityData entity) { + default void beforeEntityRemoved(DefaultWorldData world, EntityData entity) { } } diff --git a/src/main/java/ru/windcorp/progressia/common/world/WorldDataRO.java b/src/main/java/ru/windcorp/progressia/common/world/WorldDataRO.java new file mode 100644 index 0000000..0fdfcbc --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/common/world/WorldDataRO.java @@ -0,0 +1,29 @@ +package ru.windcorp.progressia.common.world; + +import ru.windcorp.progressia.common.world.block.BlockData; +import ru.windcorp.progressia.common.world.entity.EntityData; +import ru.windcorp.progressia.common.world.generic.WorldGenericRO; +import ru.windcorp.progressia.common.world.tile.TileData; + +public interface WorldDataRO + extends WorldGenericRO { + + /** + * Returns in-world time since creation. World time is zero before and + * during first tick. + *

    + * Game logic should assume that this value mostly increases uniformly. + * However, it is not guaranteed that in-world time always increments. + * + * @return time, in in-game seconds, since the world was created + */ + float getTime(); + + /** + * Gets the {@link GravityModel} used by this world. + * + * @return the gravity model + */ + GravityModel getGravityModel(); + +} diff --git a/src/main/java/ru/windcorp/progressia/common/world/block/BlockData.java b/src/main/java/ru/windcorp/progressia/common/world/block/BlockData.java index e94f838..e2337c5 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/block/BlockData.java +++ b/src/main/java/ru/windcorp/progressia/common/world/block/BlockData.java @@ -21,9 +21,9 @@ package ru.windcorp.progressia.common.world.block; import ru.windcorp.progressia.common.collision.AABB; import ru.windcorp.progressia.common.collision.CollisionModel; import ru.windcorp.progressia.common.util.namespaces.Namespaced; -import ru.windcorp.progressia.common.world.generic.GenericBlock; +import ru.windcorp.progressia.common.world.generic.BlockGeneric; -public class BlockData extends Namespaced implements GenericBlock { +public class BlockData extends Namespaced implements BlockGeneric { public BlockData(String id) { super(id); diff --git a/src/main/java/ru/windcorp/progressia/common/world/block/PacketSetBlock.java b/src/main/java/ru/windcorp/progressia/common/world/block/PacketSetBlock.java index 55d0eb2..eec2c46 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/block/PacketSetBlock.java +++ b/src/main/java/ru/windcorp/progressia/common/world/block/PacketSetBlock.java @@ -24,7 +24,7 @@ import java.io.IOException; import glm.vec._3.i.Vec3i; import ru.windcorp.progressia.common.world.DecodingException; -import ru.windcorp.progressia.common.world.WorldData; +import ru.windcorp.progressia.common.world.DefaultWorldData; public class PacketSetBlock extends PacketAffectBlock { @@ -60,7 +60,7 @@ public class PacketSetBlock extends PacketAffectBlock { } @Override - public void apply(WorldData world) { + public void apply(DefaultWorldData world) { BlockData block = BlockDataRegistry.getInstance().get(getBlockId()); world.setBlock(getBlockInWorld(), block, true); } diff --git a/src/main/java/ru/windcorp/progressia/common/world/entity/EntityData.java b/src/main/java/ru/windcorp/progressia/common/world/entity/EntityData.java index ed6876d..bc00974 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/entity/EntityData.java +++ b/src/main/java/ru/windcorp/progressia/common/world/entity/EntityData.java @@ -32,10 +32,10 @@ import ru.windcorp.progressia.common.collision.CollisionModel; import ru.windcorp.progressia.common.state.IOContext; import ru.windcorp.progressia.common.state.StatefulObject; import ru.windcorp.progressia.common.util.Matrices; -import ru.windcorp.progressia.common.world.generic.GenericEntity; +import ru.windcorp.progressia.common.world.generic.EntityGeneric; import ru.windcorp.progressia.common.world.rels.AbsFace; -public class EntityData extends StatefulObject implements Collideable, GenericEntity { +public class EntityData extends StatefulObject implements Collideable, EntityGeneric { private final Vec3 position = new Vec3(); private final Vec3 velocity = new Vec3(); diff --git a/src/main/java/ru/windcorp/progressia/common/world/entity/PacketAffectEntity.java b/src/main/java/ru/windcorp/progressia/common/world/entity/PacketAffectEntity.java index f3bf792..252ca6c 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/entity/PacketAffectEntity.java +++ b/src/main/java/ru/windcorp/progressia/common/world/entity/PacketAffectEntity.java @@ -24,7 +24,7 @@ import java.io.IOException; import ru.windcorp.progressia.common.world.DecodingException; import ru.windcorp.progressia.common.world.PacketAffectWorld; -import ru.windcorp.progressia.common.world.WorldData; +import ru.windcorp.progressia.common.world.DefaultWorldData; public class PacketAffectEntity extends PacketAffectWorld { @@ -53,7 +53,7 @@ public class PacketAffectEntity extends PacketAffectWorld { } @Override - public void apply(WorldData world) { + public void apply(DefaultWorldData world) { world.removeEntity(this.entityId); } diff --git a/src/main/java/ru/windcorp/progressia/common/world/entity/PacketChangeEntity.java b/src/main/java/ru/windcorp/progressia/common/world/entity/PacketChangeEntity.java index d09b0f3..25eb94f 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/entity/PacketChangeEntity.java +++ b/src/main/java/ru/windcorp/progressia/common/world/entity/PacketChangeEntity.java @@ -26,7 +26,7 @@ import ru.windcorp.progressia.common.state.IOContext; import ru.windcorp.progressia.common.util.DataBuffer; import ru.windcorp.progressia.common.util.crash.CrashReports; import ru.windcorp.progressia.common.world.DecodingException; -import ru.windcorp.progressia.common.world.WorldData; +import ru.windcorp.progressia.common.world.DefaultWorldData; public class PacketChangeEntity extends PacketAffectEntity { @@ -68,7 +68,7 @@ public class PacketChangeEntity extends PacketAffectEntity { } @Override - public void apply(WorldData world) { + public void apply(DefaultWorldData world) { EntityData entity = world.getEntity(getEntityId()); if (entity == null) { diff --git a/src/main/java/ru/windcorp/progressia/common/world/entity/PacketRevokeEntity.java b/src/main/java/ru/windcorp/progressia/common/world/entity/PacketRevokeEntity.java index 06dfc12..b006abf 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/entity/PacketRevokeEntity.java +++ b/src/main/java/ru/windcorp/progressia/common/world/entity/PacketRevokeEntity.java @@ -23,7 +23,7 @@ import java.io.DataOutput; import java.io.IOException; import ru.windcorp.progressia.common.world.DecodingException; -import ru.windcorp.progressia.common.world.WorldData; +import ru.windcorp.progressia.common.world.DefaultWorldData; public class PacketRevokeEntity extends PacketAffectEntity { @@ -51,7 +51,7 @@ public class PacketRevokeEntity extends PacketAffectEntity { } @Override - public void apply(WorldData world) { + public void apply(DefaultWorldData world) { world.removeEntity(getEntityId()); } diff --git a/src/main/java/ru/windcorp/progressia/common/world/entity/PacketSendEntity.java b/src/main/java/ru/windcorp/progressia/common/world/entity/PacketSendEntity.java index 6604d4a..1d1c792 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/entity/PacketSendEntity.java +++ b/src/main/java/ru/windcorp/progressia/common/world/entity/PacketSendEntity.java @@ -26,7 +26,7 @@ import ru.windcorp.progressia.common.state.IOContext; import ru.windcorp.progressia.common.util.DataBuffer; import ru.windcorp.progressia.common.util.crash.CrashReports; import ru.windcorp.progressia.common.world.DecodingException; -import ru.windcorp.progressia.common.world.WorldData; +import ru.windcorp.progressia.common.world.DefaultWorldData; public class PacketSendEntity extends PacketAffectEntity { @@ -85,7 +85,7 @@ public class PacketSendEntity extends PacketAffectEntity { } @Override - public void apply(WorldData world) { + public void apply(DefaultWorldData world) { EntityData entity = EntityDataRegistry.getInstance().create(getEntityTypeId()); entity.setEntityId(getEntityId()); diff --git a/src/main/java/ru/windcorp/progressia/common/world/generic/GenericBlock.java b/src/main/java/ru/windcorp/progressia/common/world/generic/BlockGeneric.java similarity index 96% rename from src/main/java/ru/windcorp/progressia/common/world/generic/GenericBlock.java rename to src/main/java/ru/windcorp/progressia/common/world/generic/BlockGeneric.java index d669b07..b8b05b2 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/generic/GenericBlock.java +++ b/src/main/java/ru/windcorp/progressia/common/world/generic/BlockGeneric.java @@ -18,7 +18,7 @@ package ru.windcorp.progressia.common.world.generic; -public interface GenericBlock { +public interface BlockGeneric { String getId(); diff --git a/src/main/java/ru/windcorp/progressia/common/world/generic/GenericChunk.java b/src/main/java/ru/windcorp/progressia/common/world/generic/ChunkGenericRO.java similarity index 92% rename from src/main/java/ru/windcorp/progressia/common/world/generic/GenericChunk.java rename to src/main/java/ru/windcorp/progressia/common/world/generic/ChunkGenericRO.java index 3643564..56482b5 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/generic/GenericChunk.java +++ b/src/main/java/ru/windcorp/progressia/common/world/generic/ChunkGenericRO.java @@ -32,37 +32,37 @@ import ru.windcorp.progressia.common.world.rels.BlockFace; /** * An unmodifiable chunk representation. Per default, it is usually one of - * {@link ru.windcorp.progressia.common.world.ChunkData ChunkData}, + * {@link ru.windcorp.progressia.common.world.DefaultChunkData ChunkData}, * {@link ru.windcorp.progressia.client.world.ChunkRender ChunkRender} or * {@link ru.windcorp.progressia.server.world.ChunkLogic ChunkLogic}, but this * interface may be implemented differently for various reasons. *

    - * A generic chunk contains {@linkplain GenericBlock blocks} and - * {@linkplain GenericTileStack tile stacks} and is characterized by its + * A generic chunk contains {@linkplain BlockGeneric blocks} and + * {@linkplain TileGenericStackRO tile stacks} and is characterized by its * location. It also bears a discrete up direction. Note that no - * {@linkplain GenericWorld world} object is directly accessible through this + * {@linkplain WorldGenericRO world} object is directly accessible through this * interface. *

    * This interface defines the most common methods for examining a chunk and * implements many of them as default methods. It also contains several static * methods useful when dealing with chunks. {@code GenericChunk} does not - * provide a way to modify a chunk; use {@link GenericWritableChunk} methods + * provide a way to modify a chunk; use {@link ChunkGenericWO} methods * when applicable. * * @param a reference to itself (required to properly reference a - * {@link GenericTileStack}) + * {@link TileGenericStackRO}) * @param block type * @param tile type * @param tile stack type * @author javapony */ // @formatter:off -public interface GenericChunk< - B extends GenericBlock, - T extends GenericTile, - TS extends GenericTileStack , - TR extends GenericTileReference , - C extends GenericChunk +public interface ChunkGenericRO< + B extends BlockGeneric, + T extends TileGeneric, + TS extends TileGenericStackRO , + TR extends TileGenericReferenceRO , + C extends ChunkGenericRO > { // @formatter:on diff --git a/src/main/java/ru/windcorp/progressia/common/world/generic/ChunkGenericWO.java b/src/main/java/ru/windcorp/progressia/common/world/generic/ChunkGenericWO.java new file mode 100644 index 0000000..1005454 --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/common/world/generic/ChunkGenericWO.java @@ -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 . + */ +package ru.windcorp.progressia.common.world.generic; + +import glm.vec._3.i.Vec3i; +import ru.windcorp.progressia.common.world.rels.BlockFace; + +// @formatter:off +public interface ChunkGenericWO< + B extends BlockGeneric, + T extends TileGeneric, + TS extends TileGenericStackWO , + TR extends TileGenericReferenceWO , + C extends ChunkGenericWO +> { +// @formatter:on + + void setBlock(Vec3i posInChunk, B block, boolean notify); + + TS getTiles(Vec3i blockInChunk, BlockFace face); + +} diff --git a/src/main/java/ru/windcorp/progressia/common/world/generic/ChunkMap.java b/src/main/java/ru/windcorp/progressia/common/world/generic/ChunkMap.java index 5b4f6f6..695ba91 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/generic/ChunkMap.java +++ b/src/main/java/ru/windcorp/progressia/common/world/generic/ChunkMap.java @@ -77,27 +77,27 @@ public interface ChunkMap { // TODO implement (int, int, int) and GenericChunk versions of all of the // above - default boolean containsChunk(GenericChunk chunk) { + default boolean containsChunk(ChunkGenericRO chunk) { return containsKey(chunk.getPosition()); } - default V get(GenericChunk chunk) { + default V get(ChunkGenericRO chunk) { return get(chunk.getPosition()); } - default V put(GenericChunk chunk, V obj) { + default V put(ChunkGenericRO chunk, V obj) { return put(chunk.getPosition(), obj); } - default V remove(GenericChunk chunk) { + default V remove(ChunkGenericRO chunk) { return remove(chunk.getPosition()); } - default V getOrDefault(GenericChunk chunk, V def) { + default V getOrDefault(ChunkGenericRO chunk, V def) { return containsChunk(chunk) ? def : get(chunk); } - default > V compute( + default > V compute( C chunk, BiFunction remappingFunction ) { @@ -128,8 +128,8 @@ public interface ChunkMap { void forEach(BiConsumer action); - default > void forEachIn( - GenericWorld world, + default > void forEachIn( + WorldGenericRO world, BiConsumer action ) { forEach((pos, value) -> { diff --git a/src/main/java/ru/windcorp/progressia/common/world/generic/ChunkMaps.java b/src/main/java/ru/windcorp/progressia/common/world/generic/ChunkMaps.java index c194351..658f9ea 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/generic/ChunkMaps.java +++ b/src/main/java/ru/windcorp/progressia/common/world/generic/ChunkMaps.java @@ -174,42 +174,42 @@ public class ChunkMaps { } @Override - public boolean containsChunk(GenericChunk chunk) { + public boolean containsChunk(ChunkGenericRO chunk) { synchronized (mutex) { return parent.containsChunk(chunk); } } @Override - public V get(GenericChunk chunk) { + public V get(ChunkGenericRO chunk) { synchronized (mutex) { return parent.get(chunk); } } @Override - public V put(GenericChunk chunk, V obj) { + public V put(ChunkGenericRO chunk, V obj) { synchronized (mutex) { return parent.put(chunk, obj); } } @Override - public V remove(GenericChunk chunk) { + public V remove(ChunkGenericRO chunk) { synchronized (mutex) { return parent.remove(chunk); } } @Override - public V getOrDefault(GenericChunk chunk, V def) { + public V getOrDefault(ChunkGenericRO chunk, V def) { synchronized (mutex) { return parent.getOrDefault(chunk, def); } } @Override - public > V compute( + public > V compute( C chunk, BiFunction remappingFunction ) { @@ -247,8 +247,8 @@ public class ChunkMaps { } @Override - public > void forEachIn( - GenericWorld world, + public > void forEachIn( + WorldGenericRO world, BiConsumer action ) { synchronized (mutex) { diff --git a/src/main/java/ru/windcorp/progressia/common/world/generic/ChunkSet.java b/src/main/java/ru/windcorp/progressia/common/world/generic/ChunkSet.java index 199e780..9b75d3c 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/generic/ChunkSet.java +++ b/src/main/java/ru/windcorp/progressia/common/world/generic/ChunkSet.java @@ -78,20 +78,20 @@ public interface ChunkSet extends Iterable { return result; } - default boolean contains(GenericChunk chunk) { + default boolean contains(ChunkGenericRO chunk) { return contains(chunk.getPosition()); } - default boolean add(GenericChunk chunk) { + default boolean add(ChunkGenericRO chunk) { return add(chunk.getPosition()); } - default boolean remove(GenericChunk chunk) { + default boolean remove(ChunkGenericRO chunk) { return remove(chunk.getPosition()); } - default > void forEachIn( - GenericWorld world, + default > void forEachIn( + WorldGenericRO world, Consumer action ) { forEach(position -> { @@ -210,7 +210,7 @@ public interface ChunkSet extends Iterable { } } - default boolean containsAllChunks(Iterable> chunks) { + default boolean containsAllChunks(Iterable> chunks) { boolean[] hasMissing = new boolean[] { false }; chunks.forEach(c -> { @@ -222,7 +222,7 @@ public interface ChunkSet extends Iterable { return hasMissing[0]; } - default boolean containsAnyChunks(Iterable> chunks) { + default boolean containsAnyChunks(Iterable> chunks) { boolean[] hasPresent = new boolean[] { false }; chunks.forEach(c -> { @@ -234,11 +234,11 @@ public interface ChunkSet extends Iterable { return hasPresent[0]; } - default void addAllChunks(Iterable> chunks) { + default void addAllChunks(Iterable> chunks) { chunks.forEach(this::add); } - default void removeAllChunks(Iterable> chunks) { + default void removeAllChunks(Iterable> chunks) { chunks.forEach(this::remove); } diff --git a/src/main/java/ru/windcorp/progressia/common/world/generic/ChunkSets.java b/src/main/java/ru/windcorp/progressia/common/world/generic/ChunkSets.java index 4ee643b..8123cbc 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/generic/ChunkSets.java +++ b/src/main/java/ru/windcorp/progressia/common/world/generic/ChunkSets.java @@ -198,29 +198,29 @@ public class ChunkSets { } @Override - public boolean contains(GenericChunk chunk) { + public boolean contains(ChunkGenericRO chunk) { synchronized (mutex) { return parent.contains(chunk); } } @Override - public boolean add(GenericChunk chunk) { + public boolean add(ChunkGenericRO chunk) { synchronized (mutex) { return parent.add(chunk); } } @Override - public boolean remove(GenericChunk chunk) { + public boolean remove(ChunkGenericRO chunk) { synchronized (mutex) { return parent.remove(chunk); } } @Override - public > void forEachIn( - GenericWorld world, + public > void forEachIn( + WorldGenericRO world, Consumer action ) { synchronized (mutex) { @@ -320,28 +320,28 @@ public class ChunkSets { } @Override - public boolean containsAllChunks(Iterable> chunks) { + public boolean containsAllChunks(Iterable> chunks) { synchronized (mutex) { return parent.containsAllChunks(chunks); } } @Override - public boolean containsAnyChunks(Iterable> chunks) { + public boolean containsAnyChunks(Iterable> chunks) { synchronized (mutex) { return parent.containsAnyChunks(chunks); } } @Override - public void addAllChunks(Iterable> chunks) { + public void addAllChunks(Iterable> chunks) { synchronized (mutex) { parent.addAllChunks(chunks); } } @Override - public void removeAllChunks(Iterable> chunks) { + public void removeAllChunks(Iterable> chunks) { synchronized (mutex) { parent.removeAllChunks(chunks); } diff --git a/src/main/java/ru/windcorp/progressia/common/world/generic/GenericEntity.java b/src/main/java/ru/windcorp/progressia/common/world/generic/EntityGeneric.java similarity index 97% rename from src/main/java/ru/windcorp/progressia/common/world/generic/GenericEntity.java rename to src/main/java/ru/windcorp/progressia/common/world/generic/EntityGeneric.java index 3acfc23..481191f 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/generic/GenericEntity.java +++ b/src/main/java/ru/windcorp/progressia/common/world/generic/EntityGeneric.java @@ -22,7 +22,7 @@ import glm.vec._3.Vec3; import glm.vec._3.i.Vec3i; import ru.windcorp.progressia.common.world.Coordinates; -public interface GenericEntity { +public interface EntityGeneric { String getId(); diff --git a/src/main/java/ru/windcorp/progressia/common/world/generic/GenericChunks.java b/src/main/java/ru/windcorp/progressia/common/world/generic/GenericChunks.java index 3d65785..83ba89a 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/generic/GenericChunks.java +++ b/src/main/java/ru/windcorp/progressia/common/world/generic/GenericChunks.java @@ -34,7 +34,7 @@ public class GenericChunks { output = new Vec3i(); } - final int offset = GenericChunk.BLOCKS_PER_CHUNK - 1; + final int offset = ChunkGenericRO.BLOCKS_PER_CHUNK - 1; output.set(relativeCoords.x, relativeCoords.y, relativeCoords.z); output.mul(2).sub(offset); @@ -51,7 +51,7 @@ public class GenericChunks { output = new Vec3i(); } - final int offset = GenericChunk.BLOCKS_PER_CHUNK - 1; + final int offset = ChunkGenericRO.BLOCKS_PER_CHUNK - 1; output.set(absoluteCoords.x, absoluteCoords.y, absoluteCoords.z); output.mul(2).sub(offset); @@ -73,7 +73,7 @@ public class GenericChunks { return hits; } - static boolean testBiC(Vec3i blockInWorld, GenericChunk chunk, Predicate test) { + static boolean testBiC(Vec3i blockInWorld, ChunkGenericRO chunk, Predicate test) { Vec3i v = Vectors.grab3i(); v = Coordinates.getInWorld(chunk.getPosition(), Vectors.ZERO_3i, v); @@ -87,9 +87,9 @@ public class GenericChunks { } public static boolean containsBiC(Vec3i blockInChunk) { - return blockInChunk.x >= 0 && blockInChunk.x < GenericChunk.BLOCKS_PER_CHUNK && - blockInChunk.y >= 0 && blockInChunk.y < GenericChunk.BLOCKS_PER_CHUNK && - blockInChunk.z >= 0 && blockInChunk.z < GenericChunk.BLOCKS_PER_CHUNK; + return blockInChunk.x >= 0 && blockInChunk.x < ChunkGenericRO.BLOCKS_PER_CHUNK && + blockInChunk.y >= 0 && blockInChunk.y < ChunkGenericRO.BLOCKS_PER_CHUNK && + blockInChunk.z >= 0 && blockInChunk.z < ChunkGenericRO.BLOCKS_PER_CHUNK; } public static boolean isSurfaceBiC(Vec3i blockInChunk) { @@ -109,9 +109,9 @@ public class GenericChunks { 0, 0, 0, - GenericChunk.BLOCKS_PER_CHUNK, - GenericChunk.BLOCKS_PER_CHUNK, - GenericChunk.BLOCKS_PER_CHUNK, + ChunkGenericRO.BLOCKS_PER_CHUNK, + ChunkGenericRO.BLOCKS_PER_CHUNK, + ChunkGenericRO.BLOCKS_PER_CHUNK, action ); } diff --git a/src/main/java/ru/windcorp/progressia/common/world/generic/GenericWritableChunk.java b/src/main/java/ru/windcorp/progressia/common/world/generic/GenericWritableChunk.java deleted file mode 100644 index 40fb010..0000000 --- a/src/main/java/ru/windcorp/progressia/common/world/generic/GenericWritableChunk.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * 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.common.world.generic; - -import glm.vec._3.i.Vec3i; -import ru.windcorp.progressia.common.util.Vectors; - -// @formatter:off -public interface GenericWritableChunk< - B extends GenericBlock, - T extends GenericTile, - TS extends GenericWritableTileStack , - TR extends GenericTileReference , - C extends GenericWritableChunk -> - extends GenericChunk { -// @formatter:on - - void setBlock(Vec3i posInChunk, B block, boolean notify); - - default void setBlockRel(Vec3i relativeBlockInChunk, B block, boolean notify) { - Vec3i absoluteBlockInChunk = Vectors.grab3i(); - resolve(relativeBlockInChunk, absoluteBlockInChunk); - setBlock(absoluteBlockInChunk, block, notify); - Vectors.release(absoluteBlockInChunk); - } - -} diff --git a/src/main/java/ru/windcorp/progressia/common/world/generic/LongBasedChunkSet.java b/src/main/java/ru/windcorp/progressia/common/world/generic/LongBasedChunkSet.java index 11559ca..bed628e 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/generic/LongBasedChunkSet.java +++ b/src/main/java/ru/windcorp/progressia/common/world/generic/LongBasedChunkSet.java @@ -45,7 +45,7 @@ public class LongBasedChunkSet implements ChunkSet { addAll(copyFrom); } - public LongBasedChunkSet(TLongSet impl, GenericWorld copyFrom) { + public LongBasedChunkSet(TLongSet impl, WorldGenericRO copyFrom) { this(impl); addAllChunks(copyFrom.getChunks()); } diff --git a/src/main/java/ru/windcorp/progressia/common/world/generic/GenericTile.java b/src/main/java/ru/windcorp/progressia/common/world/generic/TileGeneric.java similarity index 96% rename from src/main/java/ru/windcorp/progressia/common/world/generic/GenericTile.java rename to src/main/java/ru/windcorp/progressia/common/world/generic/TileGeneric.java index e35aec2..4a2b2e3 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/generic/GenericTile.java +++ b/src/main/java/ru/windcorp/progressia/common/world/generic/TileGeneric.java @@ -18,7 +18,7 @@ package ru.windcorp.progressia.common.world.generic; -public interface GenericTile { +public interface TileGeneric { String getId(); diff --git a/src/main/java/ru/windcorp/progressia/common/world/generic/TileGenericReferenceRO.java b/src/main/java/ru/windcorp/progressia/common/world/generic/TileGenericReferenceRO.java new file mode 100644 index 0000000..64f7cfb --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/common/world/generic/TileGenericReferenceRO.java @@ -0,0 +1,50 @@ +/* + * 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.common.world.generic; + +// @formatter:off +public interface TileGenericReferenceRO< + B extends BlockGeneric, + T extends TileGeneric, + TS extends TileGenericStackRO , + TR extends TileGenericReferenceRO , + C extends ChunkGenericRO +> { +// @formatter:on + + T get(); + + int getIndex(); + + TS getStack(); + + default boolean isValid() { + return get() != null; + } + + default int getTag() { + TS tileStack = getStack(); + if (tileStack == null) { + return -1; + } else { + return tileStack.getTagByIndex(getIndex()); + } + } + +} diff --git a/src/main/java/ru/windcorp/progressia/common/world/generic/GenericTileReference.java b/src/main/java/ru/windcorp/progressia/common/world/generic/TileGenericReferenceWO.java similarity index 70% rename from src/main/java/ru/windcorp/progressia/common/world/generic/GenericTileReference.java rename to src/main/java/ru/windcorp/progressia/common/world/generic/TileGenericReferenceWO.java index b3e7289..f31eca8 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/generic/GenericTileReference.java +++ b/src/main/java/ru/windcorp/progressia/common/world/generic/TileGenericReferenceWO.java @@ -19,23 +19,15 @@ package ru.windcorp.progressia.common.world.generic; // @formatter:off -public interface GenericTileReference< - B extends GenericBlock, - T extends GenericTile, - TS extends GenericTileStack , - TR extends GenericTileReference , - C extends GenericChunk +public interface TileGenericReferenceWO< + B extends BlockGeneric, + T extends TileGeneric, + TS extends TileGenericStackWO , + TR extends TileGenericReferenceWO , + C extends ChunkGenericWO > { // @formatter:on - - T get(); - - int getIndex(); - - TS getStack(); - - default boolean isValid() { - return get() != null; - } + + // currently empty } diff --git a/src/main/java/ru/windcorp/progressia/common/world/generic/GenericTileStack.java b/src/main/java/ru/windcorp/progressia/common/world/generic/TileGenericStackRO.java similarity index 68% rename from src/main/java/ru/windcorp/progressia/common/world/generic/GenericTileStack.java rename to src/main/java/ru/windcorp/progressia/common/world/generic/TileGenericStackRO.java index ddf7e00..0a08fac 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/generic/GenericTileStack.java +++ b/src/main/java/ru/windcorp/progressia/common/world/generic/TileGenericStackRO.java @@ -18,7 +18,7 @@ package ru.windcorp.progressia.common.world.generic; -import java.util.AbstractList; +import java.util.List; import java.util.Objects; import java.util.RandomAccess; import java.util.function.Consumer; @@ -28,13 +28,13 @@ import ru.windcorp.progressia.common.world.Coordinates; import ru.windcorp.progressia.common.world.rels.RelFace; // @formatter:off -public abstract class GenericTileStack< - B extends GenericBlock, - T extends GenericTile, - TS extends GenericTileStack , - TR extends GenericTileReference , - C extends GenericChunk -> extends AbstractList implements RandomAccess { +public interface TileGenericStackRO< + B extends BlockGeneric, + T extends TileGeneric, + TS extends TileGenericStackRO , + TR extends TileGenericReferenceRO , + C extends ChunkGenericRO +> extends List, RandomAccess { // @formatter:on public static interface TSConsumer { @@ -43,36 +43,36 @@ public abstract class GenericTileStack< public static final int TILES_PER_FACE = 8; - public abstract Vec3i getBlockInChunk(Vec3i output); + Vec3i getBlockInChunk(Vec3i output); - public abstract C getChunk(); + C getChunk(); - public abstract RelFace getFace(); + RelFace getFace(); - public abstract TR getReference(int index); + TR getReference(int index); - public abstract int getIndexByTag(int tag); + int getIndexByTag(int tag); - public abstract int getTagByIndex(int index); + int getTagByIndex(int index); - public Vec3i getBlockInWorld(Vec3i output) { + default Vec3i getBlockInWorld(Vec3i output) { // This is safe return Coordinates.getInWorld(getChunk().getPosition(), getBlockInChunk(output), output); } - public boolean isFull() { + default boolean isFull() { return size() >= TILES_PER_FACE; } - public T getClosest() { + default T getClosest() { return get(0); } - public T getFarthest() { + default T getFarthest() { return get(size() - 1); } - public void forEach(TSConsumer action) { + default void forEach(TSConsumer action) { Objects.requireNonNull(action, "action"); for (int i = 0; i < size(); ++i) { action.accept(i, get(i)); @@ -80,14 +80,14 @@ public abstract class GenericTileStack< } @Override - public void forEach(Consumer action) { + default void forEach(Consumer action) { Objects.requireNonNull(action, "action"); for (int i = 0; i < size(); ++i) { action.accept(get(i)); } } - public T findClosest(String id) { + default T findClosest(String id) { Objects.requireNonNull(id, "id"); for (int i = 0; i < size(); ++i) { @@ -100,7 +100,7 @@ public abstract class GenericTileStack< return null; } - public T findFarthest(String id) { + default T findFarthest(String id) { Objects.requireNonNull(id, "id"); for (int i = 0; i < size(); ++i) { @@ -113,11 +113,11 @@ public abstract class GenericTileStack< return null; } - public boolean contains(String id) { + default boolean contains(String id) { return findClosest(id) != null; } - public B getHost() { + default B getHost() { return getChunk().getBlock(getBlockInChunk(null)); } diff --git a/src/main/java/ru/windcorp/progressia/common/world/generic/GenericWritableTileStack.java b/src/main/java/ru/windcorp/progressia/common/world/generic/TileGenericStackWO.java similarity index 80% rename from src/main/java/ru/windcorp/progressia/common/world/generic/GenericWritableTileStack.java rename to src/main/java/ru/windcorp/progressia/common/world/generic/TileGenericStackWO.java index b2363e3..ec5073e 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/generic/GenericWritableTileStack.java +++ b/src/main/java/ru/windcorp/progressia/common/world/generic/TileGenericStackWO.java @@ -18,15 +18,18 @@ package ru.windcorp.progressia.common.world.generic; +import java.util.List; +import java.util.RandomAccess; + // @formatter:off -public abstract class GenericWritableTileStack< - B extends GenericBlock, - T extends GenericTile, - TS extends GenericWritableTileStack, - TR extends GenericTileReference, - C extends GenericWritableChunk +public interface TileGenericStackWO< + B extends BlockGeneric, + T extends TileGeneric, + TS extends TileGenericStackWO , + TR extends TileGenericReferenceWO , + C extends ChunkGenericWO > - extends GenericTileStack { + extends List, RandomAccess { // @formatter:on /** @@ -45,7 +48,7 @@ public abstract class GenericWritableTileStack< * make sure to override it in subclass */ @Override - public abstract void add(int index, T tile); + void add(int index, T tile); /** * Adds the specified tile at the end of this stack assigning it the @@ -59,7 +62,7 @@ public abstract class GenericWritableTileStack< * with the * provided tag */ - public abstract void load(T tile, int tag); + void load(T tile, int tag); /** * Replaces the tile at the specified position in this stack with the @@ -74,7 +77,7 @@ public abstract class GenericWritableTileStack< * make sure to override it in subclass */ @Override - public abstract T set(int index, T tile); + T set(int index, T tile); /** * Removes the tile at the specified position in this list. Shifts any @@ -91,19 +94,21 @@ public abstract class GenericWritableTileStack< * make sure to override it in subclass */ @Override - public abstract T remove(int index); + T remove(int index); /* * Aliases and overloads */ - public void addClosest(T tile) { + default void addClosest(T tile) { add(0, tile); } - public void addFarthest(T tile) { + default void addFarthest(T tile) { add(size(), tile); } + + boolean isFull(); /** * Attempts to {@link #add(int, TileData) add} the provided {@code tile} @@ -114,45 +119,45 @@ public abstract class GenericWritableTileStack< * @param tile the tile to try to add * @return {@code true} iff this stack has changed */ - public boolean offer(int index, T tile) { + default boolean offer(int index, T tile) { if (isFull()) return false; add(index, tile); return true; } - public boolean offerClosest(T tile) { + default boolean offerClosest(T tile) { return offer(0, tile); } - public boolean offerFarthest(T tile) { + default boolean offerFarthest(T tile) { return offer(size(), tile); } - public T removeClosest() { + default T removeClosest() { return remove(0); } - public T removeFarthest() { + default T removeFarthest() { return remove(size() - 1); } - public T poll(int index) { + default T poll(int index) { if (size() <= index) return null; return remove(index); } - public T pollClosest() { + default T pollClosest() { return poll(0); } - public T pollFarthest() { + default T pollFarthest() { return poll(size() - 1); } @Override - public boolean add(T tile) { + default boolean add(T tile) { addFarthest(tile); return true; } diff --git a/src/main/java/ru/windcorp/progressia/common/world/generic/GenericWorld.java b/src/main/java/ru/windcorp/progressia/common/world/generic/WorldGenericRO.java similarity index 90% rename from src/main/java/ru/windcorp/progressia/common/world/generic/GenericWorld.java rename to src/main/java/ru/windcorp/progressia/common/world/generic/WorldGenericRO.java index e17cf66..75ad1c3 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/generic/GenericWorld.java +++ b/src/main/java/ru/windcorp/progressia/common/world/generic/WorldGenericRO.java @@ -30,17 +30,17 @@ import ru.windcorp.progressia.common.world.rels.AbsFace; import ru.windcorp.progressia.common.world.rels.BlockFace; // @formatter:off -public interface GenericWorld< - B extends GenericBlock, - T extends GenericTile, - TS extends GenericTileStack , - TR extends GenericTileReference , - C extends GenericChunk , - E extends GenericEntity +public interface WorldGenericRO< + B extends BlockGeneric, + T extends TileGeneric, + TS extends TileGenericStackRO , + TR extends TileGenericReferenceRO , + C extends ChunkGenericRO , + E extends EntityGeneric > { // @formatter:on - Collection getChunks(); + Collection getChunks(); C getChunk(Vec3i pos); @@ -131,6 +131,15 @@ public interface GenericWorld< return stack.get(layer); } + /** + * Determines whether the specified position has a tile. + * + * @return {@code true} iff the tile exists + */ + default boolean hasTile(Vec3i location, BlockFace face, int layer) { + return hasTile(location, face, layer); + } + default boolean isChunkLoaded(Vec3i chunkPos) { return getChunk(chunkPos) != null; } diff --git a/src/main/java/ru/windcorp/progressia/common/world/generic/GenericWritableWorld.java b/src/main/java/ru/windcorp/progressia/common/world/generic/WorldGenericWO.java similarity index 52% rename from src/main/java/ru/windcorp/progressia/common/world/generic/GenericWritableWorld.java rename to src/main/java/ru/windcorp/progressia/common/world/generic/WorldGenericWO.java index b970f89..3b9a81b 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/generic/GenericWritableWorld.java +++ b/src/main/java/ru/windcorp/progressia/common/world/generic/WorldGenericWO.java @@ -18,21 +18,24 @@ package ru.windcorp.progressia.common.world.generic; import glm.vec._3.i.Vec3i; -import ru.windcorp.progressia.common.world.block.BlockData; +import ru.windcorp.progressia.common.state.StateChange; +import ru.windcorp.progressia.common.state.StatefulObject; +import ru.windcorp.progressia.common.world.rels.BlockFace; //@formatter:off -public interface GenericWritableWorld< - B extends GenericBlock, - T extends GenericTile, - TS extends GenericWritableTileStack , - TR extends GenericTileReference , - C extends GenericWritableChunk , - E extends GenericEntity -> - extends GenericWorld { +public interface WorldGenericWO< + B extends BlockGeneric, + T extends TileGeneric, + TS extends TileGenericStackWO , + TR extends TileGenericReferenceWO , + C extends ChunkGenericWO , + E extends EntityGeneric +> { //@formatter:on - void setBlock(Vec3i blockInWorld, BlockData block, boolean notify); + void setBlock(Vec3i blockInWorld, B block, boolean notify); + + TS getTiles(Vec3i blockInWorld, BlockFace face); void addEntity(E entity); @@ -42,4 +45,13 @@ public interface GenericWritableWorld< removeEntity(entity.getEntityId()); } + /** + * Requests that the specified change is applied to the given entity. The + * {@code change} object provided may be stored until the change is applied. + * + * @param entity the entity to change + * @param change the change to apply + */ + void changeEntity(SE entity, StateChange change); + } diff --git a/src/main/java/ru/windcorp/progressia/common/world/generic/context/GenericROBlockFaceContext.java b/src/main/java/ru/windcorp/progressia/common/world/generic/context/BlockFaceGenericContextRO.java similarity index 70% rename from src/main/java/ru/windcorp/progressia/common/world/generic/context/GenericROBlockFaceContext.java rename to src/main/java/ru/windcorp/progressia/common/world/generic/context/BlockFaceGenericContextRO.java index 430a4a3..212cc9b 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/generic/context/GenericROBlockFaceContext.java +++ b/src/main/java/ru/windcorp/progressia/common/world/generic/context/BlockFaceGenericContextRO.java @@ -18,13 +18,7 @@ package ru.windcorp.progressia.common.world.generic.context; import ru.windcorp.progressia.common.world.context.Context; -import ru.windcorp.progressia.common.world.generic.GenericBlock; -import ru.windcorp.progressia.common.world.generic.GenericROChunk; -import ru.windcorp.progressia.common.world.generic.GenericEntity; -import ru.windcorp.progressia.common.world.generic.GenericTile; -import ru.windcorp.progressia.common.world.generic.GenericROTileReference; -import ru.windcorp.progressia.common.world.generic.GenericROTileStack; -import ru.windcorp.progressia.common.world.rels.RelFace; +import ru.windcorp.progressia.common.world.generic.*; /** * A {@link Context} referencing a world with a block location and a block face @@ -32,23 +26,16 @@ import ru.windcorp.progressia.common.world.rels.RelFace; * not actually exist. */ //@formatter:off -public interface GenericROBlockFaceContext< - B extends GenericBlock, - T extends GenericTile, - TS extends GenericROTileStack , - TR extends GenericROTileReference , - C extends GenericROChunk , - E extends GenericEntity -> extends GenericROBlockContext { +public interface BlockFaceGenericContextRO< + B extends BlockGeneric, + T extends TileGeneric, + TS extends TileGenericStackRO , + TR extends TileGenericReferenceRO , + C extends ChunkGenericRO , + E extends EntityGeneric +> extends WorldContexts.BlockFace, BlockGenericContextRO { //@formatter:on - /** - * Returns the face relevant to this context. - * - * @return the block face - */ - RelFace getFace(); - /** * Gets the tile stack at the relevant position. * diff --git a/src/main/java/ru/windcorp/progressia/common/world/generic/context/GenericRWBlockFaceContext.java b/src/main/java/ru/windcorp/progressia/common/world/generic/context/BlockFaceGenericContextWO.java similarity index 72% rename from src/main/java/ru/windcorp/progressia/common/world/generic/context/GenericRWBlockFaceContext.java rename to src/main/java/ru/windcorp/progressia/common/world/generic/context/BlockFaceGenericContextWO.java index b2152f8..bcaa226 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/generic/context/GenericRWBlockFaceContext.java +++ b/src/main/java/ru/windcorp/progressia/common/world/generic/context/BlockFaceGenericContextWO.java @@ -28,14 +28,14 @@ import ru.windcorp.progressia.common.world.generic.*; * stack may or may not actually exist. */ //@formatter:off -public interface GenericRWBlockFaceContext< - B extends GenericBlock, - T extends GenericTile, - TS extends GenericRWTileStack , - TR extends GenericROTileReference , - C extends GenericRWChunk , - E extends GenericEntity -> extends GenericRWBlockContext, GenericROBlockFaceContext { +public interface BlockFaceGenericContextWO< + B extends BlockGeneric, + T extends TileGeneric, + TS extends TileGenericStackWO , + TR extends TileGenericReferenceWO , + C extends ChunkGenericWO , + E extends EntityGeneric +> extends WorldContexts.BlockFace, BlockGenericContextWO { //@formatter:on /** @@ -63,16 +63,4 @@ public interface GenericRWBlockFaceContext< removeTile(getLocation(), getFace(), tag); } - /** - * Requests that the referenced tile is removed from the specified tile - * stack. If the tile could not be found at the time of application this - * method fails silently. The location and the face of the block are implied - * by the context. - * - * @param tileReference a reference to the tile - */ - default void removeTile(TR tileReference) { - removeTile(getLocation(), getFace(), tileReference.getTag()); - } - } diff --git a/src/main/java/ru/windcorp/progressia/common/world/generic/context/GenericROBlockContext.java b/src/main/java/ru/windcorp/progressia/common/world/generic/context/BlockGenericContextRO.java similarity index 69% rename from src/main/java/ru/windcorp/progressia/common/world/generic/context/GenericROBlockContext.java rename to src/main/java/ru/windcorp/progressia/common/world/generic/context/BlockGenericContextRO.java index 4411407..91ac3d3 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/generic/context/GenericROBlockContext.java +++ b/src/main/java/ru/windcorp/progressia/common/world/generic/context/BlockGenericContextRO.java @@ -17,14 +17,8 @@ */ package ru.windcorp.progressia.common.world.generic.context; -import glm.vec._3.i.Vec3i; import ru.windcorp.progressia.common.world.context.Context; -import ru.windcorp.progressia.common.world.generic.GenericBlock; -import ru.windcorp.progressia.common.world.generic.GenericROChunk; -import ru.windcorp.progressia.common.world.generic.GenericEntity; -import ru.windcorp.progressia.common.world.generic.GenericTile; -import ru.windcorp.progressia.common.world.generic.GenericROTileReference; -import ru.windcorp.progressia.common.world.generic.GenericROTileStack; +import ru.windcorp.progressia.common.world.generic.*; import ru.windcorp.progressia.common.world.rels.BlockFace; /** @@ -32,29 +26,16 @@ import ru.windcorp.progressia.common.world.rels.BlockFace; * location may or may not be loaded. */ //@formatter:off -public interface GenericROBlockContext< - B extends GenericBlock, - T extends GenericTile, - TS extends GenericROTileStack , - TR extends GenericROTileReference , - C extends GenericROChunk , - E extends GenericEntity -> extends GenericROWorldContext { +public interface BlockGenericContextRO< + B extends BlockGeneric, + T extends TileGeneric, + TS extends TileGenericStackRO , + TR extends TileGenericReferenceRO , + C extends ChunkGenericRO , + E extends EntityGeneric +> extends WorldContexts.Block, WorldGenericContextRO { //@formatter:on - /** - * Returns the location of the block. - *

    - * The coordinate system in use is not specified, but it is consistent - * across all methods of this context. - *

    - * The object returned by this method must not be modified. It is only valid - * while the context is {@linkplain valid}. - * - * @return a vector describing the block's position - */ - Vec3i getLocation(); - /** * Determines whether the location relevant to this context is currently * loaded. diff --git a/src/main/java/ru/windcorp/progressia/common/world/generic/context/GenericRWBlockContext.java b/src/main/java/ru/windcorp/progressia/common/world/generic/context/BlockGenericContextWO.java similarity index 74% rename from src/main/java/ru/windcorp/progressia/common/world/generic/context/GenericRWBlockContext.java rename to src/main/java/ru/windcorp/progressia/common/world/generic/context/BlockGenericContextWO.java index 23fb6fe..f7a0eea 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/generic/context/GenericRWBlockContext.java +++ b/src/main/java/ru/windcorp/progressia/common/world/generic/context/BlockGenericContextWO.java @@ -28,14 +28,14 @@ import ru.windcorp.progressia.common.world.rels.BlockFace; * {@link #isImmediate()}. The location may or may not be loaded. */ //@formatter:off -public interface GenericRWBlockContext< - B extends GenericBlock, - T extends GenericTile, - TS extends GenericRWTileStack , - TR extends GenericROTileReference , - C extends GenericRWChunk , - E extends GenericEntity -> extends GenericRWWorldContext, GenericROBlockContext { +public interface BlockGenericContextWO< + B extends BlockGeneric, + T extends TileGeneric, + TS extends TileGenericStackWO , + TR extends TileGenericReferenceWO , + C extends ChunkGenericWO , + E extends EntityGeneric +> extends WorldContexts.Block, WorldGenericContextWO { //@formatter:on /** @@ -76,17 +76,4 @@ public interface GenericRWBlockContext< removeTile(getLocation(), face, tag); } - /** - * Requests that the referenced tile is removed from the specified tile - * stack. If the tile could not be found at the time of application this - * method fails silently. The location of the block is implied by the - * context. - * - * @param face the of the block to remove the tile from - * @param tileReference a reference to the tile - */ - default void removeTile(BlockFace face, TR tileReference) { - removeTile(getLocation(), face, tileReference.getTag()); - } - } diff --git a/src/main/java/ru/windcorp/progressia/common/world/generic/context/GenericROTileContext.java b/src/main/java/ru/windcorp/progressia/common/world/generic/context/TileGenericContextRO.java similarity index 62% rename from src/main/java/ru/windcorp/progressia/common/world/generic/context/GenericROTileContext.java rename to src/main/java/ru/windcorp/progressia/common/world/generic/context/TileGenericContextRO.java index 0ebc768..0bc04d0 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/generic/context/GenericROTileContext.java +++ b/src/main/java/ru/windcorp/progressia/common/world/generic/context/TileGenericContextRO.java @@ -18,12 +18,7 @@ package ru.windcorp.progressia.common.world.generic.context; import ru.windcorp.progressia.common.world.context.Context; -import ru.windcorp.progressia.common.world.generic.GenericBlock; -import ru.windcorp.progressia.common.world.generic.GenericROChunk; -import ru.windcorp.progressia.common.world.generic.GenericEntity; -import ru.windcorp.progressia.common.world.generic.GenericTile; -import ru.windcorp.progressia.common.world.generic.GenericROTileReference; -import ru.windcorp.progressia.common.world.generic.GenericROTileStack; +import ru.windcorp.progressia.common.world.generic.*; /** * A {@link Context} referencing a world with a block location, a block face and @@ -31,23 +26,16 @@ import ru.windcorp.progressia.common.world.generic.GenericROTileStack; * or may not actually exist. */ //@formatter:off -public interface GenericROTileContext< - B extends GenericBlock, - T extends GenericTile, - TS extends GenericROTileStack , - TR extends GenericROTileReference , - C extends GenericROChunk , - E extends GenericEntity -> extends GenericROBlockFaceContext { +public interface TileGenericContextRO< + B extends BlockGeneric, + T extends TileGeneric, + TS extends TileGenericStackRO , + TR extends TileGenericReferenceRO , + C extends ChunkGenericRO , + E extends EntityGeneric +> extends WorldContexts.Tile, BlockFaceGenericContextRO { //@formatter:on - /** - * Returns the tile layer relevant to this context. - * - * @return the tile layer - */ - int getLayer(); - /** * Determines whether the location relevant to this context has a tile. * @@ -67,12 +55,7 @@ public interface GenericROTileContext< return getTile(getLocation(), getFace(), getLayer()); } - /** - * Gets the tag of the tile at the relevant position. - * - * @return the tag of the tile or {@code -1} if the location is not loaded - * or the tile does not exist - */ + @Override default int getTag() { TS tileStack = getTilesOrNull(); if (tileStack == null) { @@ -82,4 +65,23 @@ public interface GenericROTileContext< return tileStack.getTagByIndex(getLayer()); } + /** + * Gets the {@link TileGenericReferenceRO TileReference} to the relevant + * tile. + * + * @return the reference to the tile relevant to this context or + * {@code null} if the location is not loaded or the tile does not + * exist + * + * @see TileGenericStackRO#getReference(int) + */ + default TR getTileReference() { + TS tileStack = getTilesOrNull(); + if (tileStack == null) { + return null; + } + + return tileStack.getReference(getLayer()); + } + } diff --git a/src/main/java/ru/windcorp/progressia/common/world/generic/context/GenericRWTileContext.java b/src/main/java/ru/windcorp/progressia/common/world/generic/context/TileGenericContextWO.java similarity index 80% rename from src/main/java/ru/windcorp/progressia/common/world/generic/context/GenericRWTileContext.java rename to src/main/java/ru/windcorp/progressia/common/world/generic/context/TileGenericContextWO.java index c7c0d5c..01a27d1 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/generic/context/GenericRWTileContext.java +++ b/src/main/java/ru/windcorp/progressia/common/world/generic/context/TileGenericContextWO.java @@ -28,14 +28,14 @@ import ru.windcorp.progressia.common.world.generic.*; * The tile may or may not actually exist. */ //@formatter:off -public interface GenericRWTileContext< - B extends GenericBlock, - T extends GenericTile, - TS extends GenericRWTileStack , - TR extends GenericROTileReference , - C extends GenericRWChunk , - E extends GenericEntity -> extends GenericRWBlockFaceContext, GenericROTileContext { +public interface TileGenericContextWO< + B extends BlockGeneric, + T extends TileGeneric, + TS extends TileGenericStackWO , + TR extends TileGenericReferenceWO , + C extends ChunkGenericWO , + E extends EntityGeneric +> extends WorldContexts.Tile, BlockFaceGenericContextWO { //@formatter:on /** diff --git a/src/main/java/ru/windcorp/progressia/common/world/generic/context/WorldContexts.java b/src/main/java/ru/windcorp/progressia/common/world/generic/context/WorldContexts.java new file mode 100644 index 0000000..69c5f94 --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/common/world/generic/context/WorldContexts.java @@ -0,0 +1,127 @@ +/* + * 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.common.world.generic.context; + +import glm.vec._3.i.Vec3i; +import ru.windcorp.progressia.common.world.context.Context; +import ru.windcorp.progressia.common.world.rels.RelFace; + +/** + * This class defines several {@link Context} subinterfaces that are further + * extended by Generic contexts. These interfaces declare methods for + * determining which location is "relevant" to the context. Since they are not + * Java generics they can safely be extended more than once. + *

    + * Do not reuse these interfaces outside the Generic contexts' package; consider + * them to be an implementation detail. + * + * @author javapony + * + */ +class WorldContexts { + + /** + * A {@link Context} with a world instance. This interface should not be + * implemented directly; see {@link WorldGenericContextRO} or + * {@link WorldGenericContextWO}. + * + * @author javapony + * + */ + public static interface World extends Context { + + // currently empty + + } + + /** + * A {@link Context} with a world instance and a block location. This interface + * should not be implemented directly; see {@link BlockGenericContextRO} or + * {@link BlockGenericContextWO}. + * + * @author javapony + * + */ + public static interface Block extends World { + + /** + * Returns the location of the block. + *

    + * The coordinate system in use is not specified, but it is consistent across + * all methods of this context. + *

    + * The object returned by this method must not be modified. It is only valid + * while the context is {@linkplain valid}. + * + * @return a vector describing the block's position + */ + Vec3i getLocation(); + + } + + /** + * A {@link Context} with a world instance, a block location and a block face + * (block side). This interface should not be implemented directly; see + * {@link BlockFaceGenericContextRO} or {@link BlockFaceGenericContextWO}. + * + * @author javapony + * + */ + public static interface BlockFace extends Block { + + /** + * Returns the face relevant to this context. + * + * @return the block face + */ + RelFace getFace(); + + } + + /** + * A {@link Context} with a world instance, a block location, a block face + * (block side) and a tile layer. This interface should not be implemented + * directly; see {@link TileGenericContextRO} or {@link TileGenericContextWO}. + * + * @author javapony + * + */ + public static interface Tile extends BlockFace { + + /** + * Returns the tile layer relevant to this context. + * + * @return the tile layer + */ + int getLayer(); + + /** + * Gets the tag of the tile at the relevant position. + * + * @return the tag of the tile or {@code -1} if the location is not loaded + * or the tile does not exist + */ + int getTag(); + + } + + WorldContexts() { + } + +} diff --git a/src/main/java/ru/windcorp/progressia/common/world/generic/context/GenericROWorldContext.java b/src/main/java/ru/windcorp/progressia/common/world/generic/context/WorldGenericContextRO.java similarity index 54% rename from src/main/java/ru/windcorp/progressia/common/world/generic/context/GenericROWorldContext.java rename to src/main/java/ru/windcorp/progressia/common/world/generic/context/WorldGenericContextRO.java index 09629da..588c98f 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/generic/context/GenericROWorldContext.java +++ b/src/main/java/ru/windcorp/progressia/common/world/generic/context/WorldGenericContextRO.java @@ -18,26 +18,20 @@ package ru.windcorp.progressia.common.world.generic.context; import ru.windcorp.progressia.common.world.context.Context; -import ru.windcorp.progressia.common.world.generic.GenericBlock; -import ru.windcorp.progressia.common.world.generic.GenericROChunk; -import ru.windcorp.progressia.common.world.generic.GenericEntity; -import ru.windcorp.progressia.common.world.generic.GenericTile; -import ru.windcorp.progressia.common.world.generic.GenericROTileReference; -import ru.windcorp.progressia.common.world.generic.GenericROTileStack; -import ru.windcorp.progressia.common.world.generic.GenericROWorld; +import ru.windcorp.progressia.common.world.generic.*; /** * A {@link Context} with a world instance. */ // @formatter:off -public interface GenericROWorldContext< - B extends GenericBlock, - T extends GenericTile, - TS extends GenericROTileStack , - TR extends GenericROTileReference , - C extends GenericROChunk , - E extends GenericEntity -> extends Context, GenericROWorld { +public interface WorldGenericContextRO< + B extends BlockGeneric, + T extends TileGeneric, + TS extends TileGenericStackRO , + TR extends TileGenericReferenceRO , + C extends ChunkGenericRO , + E extends EntityGeneric +> extends WorldContexts.World, WorldGenericRO { // @formatter:on // currently empty diff --git a/src/main/java/ru/windcorp/progressia/common/world/generic/context/GenericRWWorldContext.java b/src/main/java/ru/windcorp/progressia/common/world/generic/context/WorldGenericContextWO.java similarity index 80% rename from src/main/java/ru/windcorp/progressia/common/world/generic/context/GenericRWWorldContext.java rename to src/main/java/ru/windcorp/progressia/common/world/generic/context/WorldGenericContextWO.java index 55d83ff..ddac83d 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/generic/context/GenericRWWorldContext.java +++ b/src/main/java/ru/windcorp/progressia/common/world/generic/context/WorldGenericContextWO.java @@ -30,14 +30,14 @@ import ru.windcorp.progressia.common.world.rels.BlockFace; * may not be immediate, see {@link #isImmediate()}. */ // @formatter:off -public interface GenericRWWorldContext< - B extends GenericBlock, - T extends GenericTile, - TS extends GenericRWTileStack , - TR extends GenericROTileReference , - C extends GenericRWChunk , - E extends GenericEntity -> extends GenericROWorldContext, GenericRWWorld { +public interface WorldGenericContextWO< + B extends BlockGeneric, + T extends TileGeneric, + TS extends TileGenericStackWO , + TR extends TileGenericReferenceWO , + C extends ChunkGenericWO , + E extends EntityGeneric +> extends WorldContexts.World, WorldGenericWO { // @formatter:on /** @@ -92,17 +92,20 @@ public interface GenericRWWorldContext< void removeTile(Vec3i location, BlockFace face, int tag); /** - * Requests that the referenced tile is removed from the specified tile - * stack. If the tile could not be found at the time of application this - * method fails silently. + * Requests that the referenced tile is removed from its tile stack. If the + * tile could not be found at the time of application this method fails + * silently. * - * @param location the location of the block from which the tile is to - * be removed - * @param face the of the block to remove the tile from * @param tileReference a reference to the tile */ - default void removeTile(Vec3i location, BlockFace face, TR tileReference) { - removeTile(location, face, tileReference.getTag()); + default void removeTile(TileGenericReferenceRO tileReference) { + TileGenericStackRO tileStack = tileReference.getStack(); + + if (tileStack == null) { + return; + } + + removeTile(tileStack.getBlockInWorld(null), tileStack.getFace(), tileReference.getTag()); } /** @@ -123,7 +126,7 @@ public interface GenericRWWorldContext< * * @param entityId the ID of the entity to remove * @see #isImmediate() - * @see #removeEntity(GenericEntity) + * @see #removeEntity(EntityGeneric) */ @Override void removeEntity(long entityId); @@ -140,12 +143,13 @@ public interface GenericRWWorldContext< void removeEntity(E entity); /** - * Requests that the specified change is applied to the given entity. The {@code change} object provided may be stored until the change is applied. + * Requests that the specified change is applied to the given entity. The + * {@code change} object provided may be stored until the change is applied. * * @param entity the entity to change * @param change the change to apply */ @Override - void changeEntity(SE entity, StateChange change); + void changeEntity(SE entity, StateChange change); } diff --git a/src/main/java/ru/windcorp/progressia/common/world/io/ChunkCodec.java b/src/main/java/ru/windcorp/progressia/common/world/io/ChunkCodec.java index 7c2a35c..df47640 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/io/ChunkCodec.java +++ b/src/main/java/ru/windcorp/progressia/common/world/io/ChunkCodec.java @@ -25,9 +25,9 @@ import java.io.IOException; import glm.vec._3.i.Vec3i; import ru.windcorp.progressia.common.state.IOContext; import ru.windcorp.progressia.common.util.namespaces.Namespaced; -import ru.windcorp.progressia.common.world.ChunkData; +import ru.windcorp.progressia.common.world.DefaultChunkData; import ru.windcorp.progressia.common.world.DecodingException; -import ru.windcorp.progressia.common.world.WorldData; +import ru.windcorp.progressia.common.world.DefaultWorldData; public abstract class ChunkCodec extends Namespaced { @@ -46,12 +46,12 @@ public abstract class ChunkCodec extends Namespaced { return signature; } - public abstract ChunkData decode(WorldData world, Vec3i position, DataInputStream input, IOContext context) + public abstract DefaultChunkData decode(DefaultWorldData world, Vec3i position, DataInputStream input, IOContext context) throws DecodingException, IOException; - public abstract boolean shouldEncode(ChunkData chunk, IOContext context); + public abstract boolean shouldEncode(DefaultChunkData chunk, IOContext context); - public abstract void encode(ChunkData chunk, DataOutputStream output, IOContext context) throws IOException; + public abstract void encode(DefaultChunkData chunk, DataOutputStream output, IOContext context) throws IOException; } diff --git a/src/main/java/ru/windcorp/progressia/common/world/io/ChunkIO.java b/src/main/java/ru/windcorp/progressia/common/world/io/ChunkIO.java index 025738f..b2a1cd2 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/io/ChunkIO.java +++ b/src/main/java/ru/windcorp/progressia/common/world/io/ChunkIO.java @@ -31,16 +31,16 @@ import gnu.trove.map.TByteObjectMap; import gnu.trove.map.hash.TByteObjectHashMap; import ru.windcorp.progressia.common.state.IOContext; import ru.windcorp.progressia.common.util.crash.CrashReports; -import ru.windcorp.progressia.common.world.ChunkData; +import ru.windcorp.progressia.common.world.DefaultChunkData; import ru.windcorp.progressia.common.world.DecodingException; -import ru.windcorp.progressia.common.world.WorldData; +import ru.windcorp.progressia.common.world.DefaultWorldData; public class ChunkIO { private static final TByteObjectMap CODECS_BY_ID = new TByteObjectHashMap<>(); private static final List CODECS_BY_PRIORITY = new ArrayList<>(); - public static ChunkData load(WorldData world, Vec3i position, DataInputStream data, IOContext context) + public static DefaultChunkData load(DefaultWorldData world, Vec3i position, DataInputStream data, IOContext context) throws DecodingException, IOException { if (CODECS_BY_ID.isEmpty()) @@ -73,7 +73,7 @@ public class ChunkIO { } } - public static void save(ChunkData chunk, DataOutputStream output, IOContext context) + public static void save(DefaultChunkData chunk, DataOutputStream output, IOContext context) throws IOException { ChunkCodec codec = getCodec(chunk, context); @@ -100,7 +100,7 @@ public class ChunkIO { return CODECS_BY_ID.get(signature); } - public static ChunkCodec getCodec(ChunkData chunk, IOContext context) { + public static ChunkCodec getCodec(DefaultChunkData chunk, IOContext context) { for (ChunkCodec codec : CODECS_BY_PRIORITY) { if (codec.shouldEncode(chunk, context)) { return codec; diff --git a/src/main/java/ru/windcorp/progressia/common/world/tile/PacketAddTile.java b/src/main/java/ru/windcorp/progressia/common/world/tile/PacketAddTile.java index 4a1e7a0..1655446 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/tile/PacketAddTile.java +++ b/src/main/java/ru/windcorp/progressia/common/world/tile/PacketAddTile.java @@ -24,7 +24,7 @@ import java.io.IOException; import glm.vec._3.i.Vec3i; import ru.windcorp.progressia.common.world.DecodingException; -import ru.windcorp.progressia.common.world.WorldData; +import ru.windcorp.progressia.common.world.DefaultWorldData; import ru.windcorp.progressia.common.world.rels.AbsFace; public class PacketAddTile extends PacketAffectTile { @@ -61,7 +61,7 @@ public class PacketAddTile extends PacketAffectTile { } @Override - public void apply(WorldData world) { + public void apply(DefaultWorldData world) { TileData tile = TileDataRegistry.getInstance().get(getTileId()); world.getTiles(getBlockInWorld(), getFace()).add(tile); } diff --git a/src/main/java/ru/windcorp/progressia/common/world/tile/PacketRemoveTile.java b/src/main/java/ru/windcorp/progressia/common/world/tile/PacketRemoveTile.java index 9bb66af..6935368 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/tile/PacketRemoveTile.java +++ b/src/main/java/ru/windcorp/progressia/common/world/tile/PacketRemoveTile.java @@ -25,7 +25,8 @@ import java.io.IOException; import glm.vec._3.i.Vec3i; import ru.windcorp.progressia.common.util.crash.CrashReports; import ru.windcorp.progressia.common.world.DecodingException; -import ru.windcorp.progressia.common.world.WorldData; +import ru.windcorp.progressia.common.world.DefaultWorldData; +import ru.windcorp.progressia.common.world.TileDataStack; import ru.windcorp.progressia.common.world.rels.AbsFace; public class PacketRemoveTile extends PacketAffectTile { @@ -54,7 +55,7 @@ public class PacketRemoveTile extends PacketAffectTile { } @Override - public void apply(WorldData world) { + public void apply(DefaultWorldData world) { TileDataStack stack = world.getTiles(getBlockInWorld(), getFace()); int index = stack.getIndexByTag(getTag()); diff --git a/src/main/java/ru/windcorp/progressia/common/world/tile/TileData.java b/src/main/java/ru/windcorp/progressia/common/world/tile/TileData.java index d314445..54f09a9 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/tile/TileData.java +++ b/src/main/java/ru/windcorp/progressia/common/world/tile/TileData.java @@ -19,9 +19,9 @@ package ru.windcorp.progressia.common.world.tile; import ru.windcorp.progressia.common.util.namespaces.Namespaced; -import ru.windcorp.progressia.common.world.generic.GenericTile; +import ru.windcorp.progressia.common.world.generic.TileGeneric; -public class TileData extends Namespaced implements GenericTile { +public class TileData extends Namespaced implements TileGeneric { public TileData(String id) { super(id); diff --git a/src/main/java/ru/windcorp/progressia/common/world/tile/TileDataStack.java b/src/main/java/ru/windcorp/progressia/common/world/tile/TileDataStack.java deleted file mode 100644 index 7e88402..0000000 --- a/src/main/java/ru/windcorp/progressia/common/world/tile/TileDataStack.java +++ /dev/null @@ -1,28 +0,0 @@ -/* - * 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.common.world.tile; - -import ru.windcorp.progressia.common.world.ChunkData; -import ru.windcorp.progressia.common.world.block.BlockData; -import ru.windcorp.progressia.common.world.generic.GenericWritableTileStack; - -public abstract class TileDataStack - extends GenericWritableTileStack { - -} diff --git a/src/main/java/ru/windcorp/progressia/server/Player.java b/src/main/java/ru/windcorp/progressia/server/Player.java index 734783f..008c000 100644 --- a/src/main/java/ru/windcorp/progressia/server/Player.java +++ b/src/main/java/ru/windcorp/progressia/server/Player.java @@ -22,7 +22,7 @@ import java.util.function.Consumer; 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.DefaultChunkData; import ru.windcorp.progressia.common.world.Coordinates; import ru.windcorp.progressia.common.world.PlayerData; import ru.windcorp.progressia.common.world.entity.EntityData; @@ -55,7 +55,7 @@ public class Player extends PlayerData implements ChunkLoader { Coordinates.convertInWorldToChunk(start, start); Vec3i cursor = new Vec3i(); - float radius = getServer().getLoadDistance(this) / Units.get(ChunkData.BLOCKS_PER_CHUNK, "m"); + float radius = getServer().getLoadDistance(this) / Units.get(DefaultChunkData.BLOCKS_PER_CHUNK, "m"); float radiusSq = radius * radius; int iRadius = (int) Math.ceil(radius); diff --git a/src/main/java/ru/windcorp/progressia/server/Server.java b/src/main/java/ru/windcorp/progressia/server/Server.java index a0febbf..9da227f 100644 --- a/src/main/java/ru/windcorp/progressia/server/Server.java +++ b/src/main/java/ru/windcorp/progressia/server/Server.java @@ -28,7 +28,7 @@ import ru.windcorp.jputil.functions.ThrowingRunnable; import ru.windcorp.progressia.common.Units; import ru.windcorp.progressia.common.util.TaskQueue; import ru.windcorp.progressia.common.util.crash.ReportingEventBus; -import ru.windcorp.progressia.common.world.WorldData; +import ru.windcorp.progressia.common.world.DefaultWorldData; import ru.windcorp.progressia.server.comms.ClientManager; import ru.windcorp.progressia.server.events.ServerEvent; import ru.windcorp.progressia.server.management.load.ChunkRequestDaemon; @@ -68,7 +68,7 @@ public class Server { private final TickingSettings tickingSettings = new TickingSettings(); - public Server(WorldData world) { + public Server(DefaultWorldData world) { this.world = new WorldLogic( world, this, diff --git a/src/main/java/ru/windcorp/progressia/server/ServerState.java b/src/main/java/ru/windcorp/progressia/server/ServerState.java index 774f17d..de505f5 100644 --- a/src/main/java/ru/windcorp/progressia/server/ServerState.java +++ b/src/main/java/ru/windcorp/progressia/server/ServerState.java @@ -18,7 +18,7 @@ package ru.windcorp.progressia.server; -import ru.windcorp.progressia.common.world.WorldData; +import ru.windcorp.progressia.common.world.DefaultWorldData; public class ServerState { @@ -33,7 +33,7 @@ public class ServerState { } public static void startServer() { - Server server = new Server(new WorldData()); + Server server = new Server(new DefaultWorldData()); setInstance(server); server.start(); } diff --git a/src/main/java/ru/windcorp/progressia/server/management/load/ChunkManager.java b/src/main/java/ru/windcorp/progressia/server/management/load/ChunkManager.java index baf68f6..3071530 100644 --- a/src/main/java/ru/windcorp/progressia/server/management/load/ChunkManager.java +++ b/src/main/java/ru/windcorp/progressia/server/management/load/ChunkManager.java @@ -18,10 +18,10 @@ package ru.windcorp.progressia.server.management.load; import glm.vec._3.i.Vec3i; -import ru.windcorp.progressia.common.world.ChunkData; +import ru.windcorp.progressia.common.world.DefaultChunkData; import ru.windcorp.progressia.common.world.PacketRevokeChunk; import ru.windcorp.progressia.common.world.PacketSendChunk; -import ru.windcorp.progressia.common.world.WorldData; +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; @@ -113,9 +113,9 @@ public class ChunkManager { return LoadResult.ALREADY_LOADED; } - WorldData world = getServer().getWorld().getData(); + DefaultWorldData world = getServer().getWorld().getData(); - ChunkData chunk = TestWorldDiskIO.tryToLoad(chunkPos, world, getServer()); + DefaultChunkData chunk = TestWorldDiskIO.tryToLoad(chunkPos, world, getServer()); if (chunk != null) { world.addChunk(chunk); return LoadResult.LOADED_FROM_DISK; @@ -133,8 +133,8 @@ public class ChunkManager { * this method */ public boolean unloadChunk(Vec3i chunkPos) { - WorldData world = getServer().getWorld().getData(); - ChunkData chunk = world.getChunk(chunkPos); + DefaultWorldData world = getServer().getWorld().getData(); + DefaultChunkData chunk = world.getChunk(chunkPos); if (chunk == null) { return false; @@ -147,7 +147,7 @@ public class ChunkManager { } public void sendChunk(Player player, Vec3i chunkPos) { - ChunkData chunk = getServer().getWorld().getData().getChunk(chunkPos); + DefaultChunkData chunk = getServer().getWorld().getData().getChunk(chunkPos); if (chunk == null) { throw new IllegalStateException( @@ -180,7 +180,7 @@ public class ChunkManager { /** * Checks whether or not the chunk at the specified location is loaded. A - * loaded chunk is accessible through the server's {@link WorldData} object. + * loaded chunk is accessible through the server's {@link DefaultWorldData} object. * * @param chunkPos the position of the chunk * @return {@code true} iff the chunk is loaded diff --git a/src/main/java/ru/windcorp/progressia/server/world/ChunkLogic.java b/src/main/java/ru/windcorp/progressia/server/world/ChunkLogic.java index a5177fe..f633179 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/ChunkLogic.java +++ b/src/main/java/ru/windcorp/progressia/server/world/ChunkLogic.java @@ -26,14 +26,14 @@ import java.util.WeakHashMap; import java.util.function.BiConsumer; import glm.vec._3.i.Vec3i; -import ru.windcorp.progressia.common.world.ChunkData; +import ru.windcorp.progressia.common.world.DefaultChunkData; import ru.windcorp.progressia.common.world.Coordinates; -import ru.windcorp.progressia.common.world.generic.GenericChunk; +import ru.windcorp.progressia.common.world.generic.ChunkGenericRO; import ru.windcorp.progressia.common.world.rels.AbsFace; import ru.windcorp.progressia.common.world.rels.BlockFace; import ru.windcorp.progressia.common.world.rels.RelFace; -import ru.windcorp.progressia.common.world.tile.TileDataStack; -import ru.windcorp.progressia.common.world.tile.TileDataReference; +import ru.windcorp.progressia.common.world.TileDataStack; +import ru.windcorp.progressia.common.world.TileDataReference; import ru.windcorp.progressia.server.world.block.BlockLogic; import ru.windcorp.progressia.server.world.block.BlockLogicRegistry; import ru.windcorp.progressia.server.world.block.TickableBlock; @@ -45,10 +45,10 @@ import ru.windcorp.progressia.server.world.tile.TileLogicReference; import ru.windcorp.progressia.server.world.tile.TileLogicRegistry; import ru.windcorp.progressia.server.world.tile.TileLogicStack; -public class ChunkLogic implements GenericChunk { +public class ChunkLogic implements ChunkGenericRO { private final WorldLogic world; - private final ChunkData data; + private final DefaultChunkData data; private final Collection tickingBlocks = new ArrayList<>(); private final Collection tickingTiles = new ArrayList<>(); @@ -58,7 +58,7 @@ public class ChunkLogic implements GenericChunk tileLogicLists = Collections .synchronizedMap(new WeakHashMap<>()); - public ChunkLogic(WorldLogic world, ChunkData data) { + public ChunkLogic(WorldLogic world, DefaultChunkData data) { this.world = world; this.data = data; @@ -103,7 +103,7 @@ public class ChunkLogic implements GenericChunk tileStack); + TileStack withTS(TileGenericStackRO tileStack); - default Builder.Chunk withChunk(ChunkData chunk) { + default Builder.Chunk withChunk(DefaultChunkData chunk) { Objects.requireNonNull(chunk, "chunk"); return withChunk(chunk.getPosition()); } @@ -259,7 +259,7 @@ public abstract class TickContextMutable implements BlockTickContext, TSTickCont } @Override - public TileStack withTS(GenericTileStack tileStack) { + public TileStack withTS(TileGenericStackRO tileStack) { Objects.requireNonNull(tileStack, "tileStack"); return withBlock( @@ -324,7 +324,7 @@ public abstract class TickContextMutable implements BlockTickContext, TSTickCont final int minX = Coordinates.getInWorld(chunk.x, 0); final int minY = Coordinates.getInWorld(chunk.y, 0); final int minZ = Coordinates.getInWorld(chunk.z, 0); - final int size = ChunkData.BLOCKS_PER_CHUNK; + final int size = DefaultChunkData.BLOCKS_PER_CHUNK; for (v.x = minX; v.x < minX + size; ++v.x) { for (v.y = minY; v.y < minY + size; ++v.y) { diff --git a/src/main/java/ru/windcorp/progressia/server/world/UpdateTriggerer.java b/src/main/java/ru/windcorp/progressia/server/world/UpdateTriggerer.java index d0b9562..fc22047 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/UpdateTriggerer.java +++ b/src/main/java/ru/windcorp/progressia/server/world/UpdateTriggerer.java @@ -19,7 +19,7 @@ package ru.windcorp.progressia.server.world; import glm.vec._3.i.Vec3i; -import ru.windcorp.progressia.common.world.ChunkData; +import ru.windcorp.progressia.common.world.DefaultChunkData; import ru.windcorp.progressia.common.world.ChunkDataListener; import ru.windcorp.progressia.common.world.Coordinates; import ru.windcorp.progressia.common.world.block.BlockData; @@ -37,7 +37,7 @@ public class UpdateTriggerer implements ChunkDataListener { @Override public void onChunkBlockChanged( - ChunkData chunk, + DefaultChunkData chunk, Vec3i blockInChunk, BlockData previous, BlockData current @@ -47,7 +47,7 @@ public class UpdateTriggerer implements ChunkDataListener { @Override public void onChunkTilesChanged( - ChunkData chunk, + DefaultChunkData chunk, Vec3i blockInChunk, RelFace face, TileData tile, diff --git a/src/main/java/ru/windcorp/progressia/server/world/WorldLogic.java b/src/main/java/ru/windcorp/progressia/server/world/WorldLogic.java index d080551..7028573 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/WorldLogic.java +++ b/src/main/java/ru/windcorp/progressia/server/world/WorldLogic.java @@ -25,12 +25,12 @@ import java.util.Map; import glm.Glm; import glm.vec._3.i.Vec3i; import ru.windcorp.progressia.common.util.crash.CrashReports; -import ru.windcorp.progressia.common.world.ChunkData; +import ru.windcorp.progressia.common.world.DefaultChunkData; import ru.windcorp.progressia.common.world.ChunkDataListeners; -import ru.windcorp.progressia.common.world.WorldData; +import ru.windcorp.progressia.common.world.DefaultWorldData; import ru.windcorp.progressia.common.world.WorldDataListener; import ru.windcorp.progressia.common.world.entity.EntityData; -import ru.windcorp.progressia.common.world.generic.GenericWorld; +import ru.windcorp.progressia.common.world.generic.WorldGenericRO; import ru.windcorp.progressia.server.Server; import ru.windcorp.progressia.server.world.block.BlockLogic; import ru.windcorp.progressia.server.world.generation.WorldGenerator; @@ -41,20 +41,20 @@ import ru.windcorp.progressia.server.world.tile.TileLogicReference; import ru.windcorp.progressia.server.world.tile.TileLogicStack; public class WorldLogic - implements GenericWorld { - private final WorldData data; + private final DefaultWorldData data; private final Server server; private final WorldGenerator generator; - private final Map chunks = new HashMap<>(); + private final Map chunks = new HashMap<>(); private final Evaluation tickEntitiesTask = new TickEntitiesTask(); - public WorldLogic(WorldData data, Server server, WorldGenerator generator) { + public WorldLogic(DefaultWorldData data, Server server, WorldGenerator generator) { this.data = data; this.server = server; @@ -63,12 +63,12 @@ public class WorldLogic data.addListener(new WorldDataListener() { @Override - public void onChunkLoaded(WorldData world, ChunkData chunk) { + public void onChunkLoaded(DefaultWorldData world, DefaultChunkData chunk) { chunks.put(chunk, new ChunkLogic(WorldLogic.this, chunk)); } @Override - public void beforeChunkUnloaded(WorldData world, ChunkData chunk) { + public void beforeChunkUnloaded(DefaultWorldData world, DefaultChunkData chunk) { chunks.remove(chunk); } }); @@ -104,7 +104,7 @@ public class WorldLogic return server; } - public WorldData getData() { + public DefaultWorldData getData() { return data; } @@ -112,8 +112,8 @@ public class WorldLogic return generator; } - public ChunkData generate(Vec3i chunkPos) { - ChunkData chunk = getGenerator().generate(chunkPos); + public DefaultChunkData generate(Vec3i chunkPos) { + DefaultChunkData 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)", @@ -147,7 +147,7 @@ public class WorldLogic return chunk; } - public ChunkLogic getChunk(ChunkData chunkData) { + public ChunkLogic getChunk(DefaultChunkData chunkData) { return chunks.get(chunkData); } diff --git a/src/main/java/ru/windcorp/progressia/server/world/block/BlockLogic.java b/src/main/java/ru/windcorp/progressia/server/world/block/BlockLogic.java index fdc35e2..1d08194 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/block/BlockLogic.java +++ b/src/main/java/ru/windcorp/progressia/server/world/block/BlockLogic.java @@ -19,10 +19,10 @@ package ru.windcorp.progressia.server.world.block; import ru.windcorp.progressia.common.util.namespaces.Namespaced; -import ru.windcorp.progressia.common.world.generic.GenericBlock; +import ru.windcorp.progressia.common.world.generic.BlockGeneric; import ru.windcorp.progressia.common.world.rels.RelFace; -public class BlockLogic extends Namespaced implements GenericBlock { +public class BlockLogic extends Namespaced implements BlockGeneric { public BlockLogic(String id) { super(id); 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 e765d85..bd244a0 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 @@ -23,11 +23,11 @@ import java.io.DataOutputStream; import java.io.IOException; import java.util.Objects; -import ru.windcorp.progressia.common.world.ChunkData; +import ru.windcorp.progressia.common.world.DefaultChunkData; import ru.windcorp.progressia.common.world.DecodingException; import ru.windcorp.progressia.common.world.GravityModel; import ru.windcorp.progressia.common.world.GravityModelRegistry; -import ru.windcorp.progressia.common.world.WorldData; +import ru.windcorp.progressia.common.world.DefaultWorldData; import ru.windcorp.progressia.server.Server; import ru.windcorp.progressia.server.world.WorldLogic; @@ -71,11 +71,11 @@ public abstract class AbstractWorldGenerator extends WorldGenerator { protected abstract boolean checkIsChunkReady(H hint); - protected H getHint(ChunkData chunk) { + protected H getHint(DefaultChunkData chunk) { return hintClass.cast(chunk.getGenerationHint()); } - protected void setHint(ChunkData chunk, H hint) { + protected void setHint(DefaultChunkData chunk, H hint) { chunk.setGenerationHint(hint); } @@ -95,7 +95,7 @@ public abstract class AbstractWorldGenerator extends WorldGenerator { } @Override - public WorldData getWorldData() { + public DefaultWorldData getWorldData() { return server.getWorld().getData(); } diff --git a/src/main/java/ru/windcorp/progressia/server/world/generation/WorldGenerator.java b/src/main/java/ru/windcorp/progressia/server/world/generation/WorldGenerator.java index f05674d..a7c9753 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/generation/WorldGenerator.java +++ b/src/main/java/ru/windcorp/progressia/server/world/generation/WorldGenerator.java @@ -25,10 +25,10 @@ import java.io.IOException; import glm.vec._3.Vec3; import glm.vec._3.i.Vec3i; import ru.windcorp.progressia.common.util.namespaces.Namespaced; -import ru.windcorp.progressia.common.world.ChunkData; +import ru.windcorp.progressia.common.world.DefaultChunkData; import ru.windcorp.progressia.common.world.DecodingException; import ru.windcorp.progressia.common.world.GravityModel; -import ru.windcorp.progressia.common.world.WorldData; +import ru.windcorp.progressia.common.world.DefaultWorldData; import ru.windcorp.progressia.server.Server; import ru.windcorp.progressia.server.world.WorldLogic; @@ -39,7 +39,7 @@ public abstract class WorldGenerator extends Namespaced { // package-private constructor; extend AbstractWorldGeneration } - public abstract ChunkData generate(Vec3i chunkPos); + public abstract DefaultChunkData generate(Vec3i chunkPos); public abstract Object readGenerationHint(DataInputStream input) throws IOException, DecodingException; @@ -53,6 +53,6 @@ public abstract class WorldGenerator extends Namespaced { public abstract Server getServer(); public abstract WorldLogic getWorldLogic(); - public abstract WorldData getWorldData(); + public abstract DefaultWorldData getWorldData(); } diff --git a/src/main/java/ru/windcorp/progressia/server/world/tasks/TickChunk.java b/src/main/java/ru/windcorp/progressia/server/world/tasks/TickChunk.java index 186fa55..df92442 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/tasks/TickChunk.java +++ b/src/main/java/ru/windcorp/progressia/server/world/tasks/TickChunk.java @@ -27,9 +27,9 @@ import com.google.common.collect.ImmutableList; import glm.vec._3.i.Vec3i; import ru.windcorp.progressia.common.util.FloatMathUtil; -import ru.windcorp.progressia.common.world.ChunkData; +import ru.windcorp.progressia.common.world.DefaultChunkData; import ru.windcorp.progressia.common.world.rels.AbsFace; -import ru.windcorp.progressia.common.world.tile.TileDataStack; +import ru.windcorp.progressia.common.world.TileDataStack; import ru.windcorp.progressia.server.Server; import ru.windcorp.progressia.server.world.ChunkLogic; import ru.windcorp.progressia.server.world.TickContextMutable; @@ -40,13 +40,13 @@ import ru.windcorp.progressia.server.world.ticking.TickingPolicy; import ru.windcorp.progressia.server.world.tile.TSTickContext; import ru.windcorp.progressia.server.world.tile.TickableTile; import ru.windcorp.progressia.server.world.tile.TileLogic; -import static ru.windcorp.progressia.common.world.ChunkData.BLOCKS_PER_CHUNK; +import static ru.windcorp.progressia.common.world.DefaultChunkData.BLOCKS_PER_CHUNK; public class TickChunk extends Evaluation { - private static final int CHUNK_VOLUME = ChunkData.BLOCKS_PER_CHUNK * - ChunkData.BLOCKS_PER_CHUNK * - ChunkData.BLOCKS_PER_CHUNK; + private static final int CHUNK_VOLUME = DefaultChunkData.BLOCKS_PER_CHUNK * + DefaultChunkData.BLOCKS_PER_CHUNK * + DefaultChunkData.BLOCKS_PER_CHUNK; private final List> randomTickMethods; 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 7d58d6d..25dc4db 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 @@ -34,7 +34,7 @@ import com.google.common.collect.ImmutableList; import ru.windcorp.progressia.common.Units; import ru.windcorp.progressia.common.util.crash.CrashReports; -import ru.windcorp.progressia.common.world.ChunkData; +import ru.windcorp.progressia.common.world.DefaultChunkData; import ru.windcorp.progressia.common.world.ChunkDataListener; import ru.windcorp.progressia.common.world.ChunkDataListeners; import ru.windcorp.progressia.server.Server; @@ -105,7 +105,7 @@ public class TickerCoordinator { server.getWorld().getData().addListener(ChunkDataListeners.createAdder(new ChunkDataListener() { @Override - public void onChunkChanged(ChunkData chunk) { + public void onChunkChanged(DefaultChunkData chunk) { if (!canChange.get()) { throw CrashReports.report(null, "A change has been detected during evaluation phase"); } diff --git a/src/main/java/ru/windcorp/progressia/server/world/tile/TSTickContext.java b/src/main/java/ru/windcorp/progressia/server/world/tile/TSTickContext.java index e965ffb..4272919 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/tile/TSTickContext.java +++ b/src/main/java/ru/windcorp/progressia/server/world/tile/TSTickContext.java @@ -22,9 +22,9 @@ import java.util.Objects; import java.util.function.Consumer; import java.util.function.Function; -import ru.windcorp.progressia.common.world.ChunkData; +import ru.windcorp.progressia.common.world.DefaultChunkData; import ru.windcorp.progressia.common.world.rels.RelFace; -import ru.windcorp.progressia.common.world.tile.TileDataStack; +import ru.windcorp.progressia.common.world.TileDataStack; import ru.windcorp.progressia.server.world.ChunkLogic; import ru.windcorp.progressia.server.world.TickContextMutable; import ru.windcorp.progressia.server.world.block.BlockTickContext; @@ -54,7 +54,7 @@ public interface TSTickContext extends BlockTickContext { } default TileDataStack getTDSOrNull() { - ChunkData chunkData = getChunkData(); + DefaultChunkData chunkData = getChunkData(); if (chunkData == null) return null; diff --git a/src/main/java/ru/windcorp/progressia/server/world/tile/TileLogic.java b/src/main/java/ru/windcorp/progressia/server/world/tile/TileLogic.java index 2bd43f5..67466b5 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/tile/TileLogic.java +++ b/src/main/java/ru/windcorp/progressia/server/world/tile/TileLogic.java @@ -19,10 +19,10 @@ package ru.windcorp.progressia.server.world.tile; import ru.windcorp.progressia.common.util.namespaces.Namespaced; -import ru.windcorp.progressia.common.world.generic.GenericTile; +import ru.windcorp.progressia.common.world.generic.TileGeneric; import ru.windcorp.progressia.common.world.rels.RelFace; -public class TileLogic extends Namespaced implements GenericTile { +public class TileLogic extends Namespaced implements TileGeneric { public TileLogic(String id) { super(id); diff --git a/src/main/java/ru/windcorp/progressia/server/world/tile/TileLogicReference.java b/src/main/java/ru/windcorp/progressia/server/world/tile/TileLogicReference.java index 97bf35c..36d4c2d 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/tile/TileLogicReference.java +++ b/src/main/java/ru/windcorp/progressia/server/world/tile/TileLogicReference.java @@ -17,11 +17,11 @@ */ package ru.windcorp.progressia.server.world.tile; -import ru.windcorp.progressia.common.world.generic.GenericTileReference; +import ru.windcorp.progressia.common.world.generic.TileGenericReferenceRO; import ru.windcorp.progressia.server.world.ChunkLogic; import ru.windcorp.progressia.server.world.block.BlockLogic; public interface TileLogicReference - extends GenericTileReference { + extends TileGenericReferenceRO { } diff --git a/src/main/java/ru/windcorp/progressia/server/world/tile/TileLogicStack.java b/src/main/java/ru/windcorp/progressia/server/world/tile/TileLogicStack.java index b38a6f6..83d7d9a 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/tile/TileLogicStack.java +++ b/src/main/java/ru/windcorp/progressia/server/world/tile/TileLogicStack.java @@ -18,13 +18,16 @@ package ru.windcorp.progressia.server.world.tile; -import ru.windcorp.progressia.common.world.generic.GenericTileStack; -import ru.windcorp.progressia.common.world.tile.TileDataStack; +import java.util.AbstractList; + +import ru.windcorp.progressia.common.world.TileDataStack; +import ru.windcorp.progressia.common.world.generic.TileGenericStackRO; import ru.windcorp.progressia.server.world.ChunkLogic; import ru.windcorp.progressia.server.world.block.BlockLogic; public abstract class TileLogicStack - extends GenericTileStack { + extends AbstractList + implements TileGenericStackRO { public abstract TileDataStack getData(); diff --git a/src/main/java/ru/windcorp/progressia/server/world/tile/TileTickContext.java b/src/main/java/ru/windcorp/progressia/server/world/tile/TileTickContext.java index 7e7ae88..c3003d8 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/tile/TileTickContext.java +++ b/src/main/java/ru/windcorp/progressia/server/world/tile/TileTickContext.java @@ -19,8 +19,8 @@ package ru.windcorp.progressia.server.world.tile; import ru.windcorp.progressia.common.world.tile.TileData; -import ru.windcorp.progressia.common.world.tile.TileDataStack; -import ru.windcorp.progressia.common.world.tile.TileDataReference; +import ru.windcorp.progressia.common.world.TileDataStack; +import ru.windcorp.progressia.common.world.TileDataReference; public interface TileTickContext extends TSTickContext { diff --git a/src/main/java/ru/windcorp/progressia/test/TestChunkCodec.java b/src/main/java/ru/windcorp/progressia/test/TestChunkCodec.java index caba6ea..f4e81c5 100644 --- a/src/main/java/ru/windcorp/progressia/test/TestChunkCodec.java +++ b/src/main/java/ru/windcorp/progressia/test/TestChunkCodec.java @@ -33,9 +33,9 @@ import gnu.trove.map.TObjectIntMap; import gnu.trove.map.hash.TObjectIntHashMap; import ru.windcorp.jputil.functions.ThrowingConsumer; import ru.windcorp.progressia.common.state.IOContext; -import ru.windcorp.progressia.common.world.ChunkData; +import ru.windcorp.progressia.common.world.DefaultChunkData; import ru.windcorp.progressia.common.world.DecodingException; -import ru.windcorp.progressia.common.world.WorldData; +import ru.windcorp.progressia.common.world.DefaultWorldData; import ru.windcorp.progressia.common.world.block.BlockData; import ru.windcorp.progressia.common.world.block.BlockDataRegistry; import ru.windcorp.progressia.common.world.generic.GenericChunks; @@ -76,7 +76,7 @@ public class TestChunkCodec extends ChunkCodec { } @Override - public boolean shouldEncode(ChunkData chunk, IOContext context) { + public boolean shouldEncode(DefaultChunkData chunk, IOContext context) { return true; } @@ -85,13 +85,13 @@ public class TestChunkCodec extends ChunkCodec { */ @Override - public ChunkData decode(WorldData world, Vec3i position, DataInputStream input, IOContext context) + public DefaultChunkData decode(DefaultWorldData world, Vec3i position, DataInputStream input, IOContext context) throws DecodingException, IOException { BlockData[] blockPalette = readBlockPalette(input); TileData[] tilePalette = readTilePalette(input); - ChunkData chunk = new ChunkData(position, world); + DefaultChunkData chunk = new DefaultChunkData(position, world); readBlocks(input, blockPalette, chunk); readTiles(input, tilePalette, chunk); @@ -121,7 +121,7 @@ public class TestChunkCodec extends ChunkCodec { return palette; } - private void readBlocks(DataInput input, BlockData[] blockPalette, ChunkData chunk) throws IOException { + private void readBlocks(DataInput input, BlockData[] blockPalette, DefaultChunkData chunk) throws IOException { try { GenericChunks.forEachBiC(guard(v -> { chunk.setBlock(v, blockPalette[input.readInt()], false); @@ -131,7 +131,7 @@ public class TestChunkCodec extends ChunkCodec { } } - private void readTiles(DataInput input, TileData[] tilePalette, ChunkData chunk) throws IOException { + private void readTiles(DataInput input, TileData[] tilePalette, DefaultChunkData chunk) throws IOException { Vec3i bic = new Vec3i(); while (true) { @@ -157,7 +157,7 @@ public class TestChunkCodec extends ChunkCodec { */ @Override - public void encode(ChunkData chunk, DataOutputStream output, IOContext context) throws IOException { + public void encode(DefaultChunkData chunk, DataOutputStream output, IOContext context) throws IOException { Palette blockPalette = createBlockPalette(chunk); Palette tilePalette = createTilePalette(chunk); @@ -168,13 +168,13 @@ public class TestChunkCodec extends ChunkCodec { writeTiles(chunk, tilePalette, output); } - private Palette createBlockPalette(ChunkData chunk) { + private Palette createBlockPalette(DefaultChunkData chunk) { Palette blockPalette = new Palette<>(); GenericChunks.forEachBiC(v -> blockPalette.add(chunk.getBlock(v))); return blockPalette; } - private Palette createTilePalette(ChunkData chunk) { + private Palette createTilePalette(DefaultChunkData chunk) { Palette tilePalette = new Palette<>(); chunk.forEachTile((ts, t) -> tilePalette.add(t)); return tilePalette; @@ -196,7 +196,7 @@ public class TestChunkCodec extends ChunkCodec { } } - private void writeBlocks(ChunkData chunk, Palette blockPalette, DataOutput output) throws IOException { + private void writeBlocks(DefaultChunkData chunk, Palette blockPalette, DataOutput output) throws IOException { try { GenericChunks.forEachBiC(guard(v -> { output.writeInt(blockPalette.getNid(chunk.getBlock(v))); @@ -206,7 +206,7 @@ public class TestChunkCodec extends ChunkCodec { } } - private void writeTiles(ChunkData chunk, Palette tilePalette, DataOutput output) throws IOException { + private void writeTiles(DefaultChunkData chunk, Palette tilePalette, DataOutput output) throws IOException { Vec3i bic = new Vec3i(); try { diff --git a/src/main/java/ru/windcorp/progressia/test/TestWorldDiskIO.java b/src/main/java/ru/windcorp/progressia/test/TestWorldDiskIO.java index 97a0d99..ebfafde 100644 --- a/src/main/java/ru/windcorp/progressia/test/TestWorldDiskIO.java +++ b/src/main/java/ru/windcorp/progressia/test/TestWorldDiskIO.java @@ -34,9 +34,9 @@ import org.apache.logging.log4j.Logger; import glm.vec._3.i.Vec3i; import ru.windcorp.progressia.common.state.IOContext; -import ru.windcorp.progressia.common.world.ChunkData; +import ru.windcorp.progressia.common.world.DefaultChunkData; import ru.windcorp.progressia.common.world.DecodingException; -import ru.windcorp.progressia.common.world.WorldData; +import ru.windcorp.progressia.common.world.DefaultWorldData; import ru.windcorp.progressia.common.world.io.ChunkIO; import ru.windcorp.progressia.server.Server; @@ -47,7 +47,7 @@ public class TestWorldDiskIO { private static final boolean ENABLE = false; - public static void saveChunk(ChunkData chunk, Server server) { + public static void saveChunk(DefaultChunkData chunk, Server server) { if (!ENABLE) return; @@ -83,12 +83,12 @@ public class TestWorldDiskIO { } } - private static void writeGenerationHint(ChunkData chunk, DataOutputStream output, Server server) + private static void writeGenerationHint(DefaultChunkData chunk, DataOutputStream output, Server server) throws IOException { server.getWorld().getGenerator().writeGenerationHint(output, chunk.getGenerationHint()); } - public static ChunkData tryToLoad(Vec3i chunkPos, WorldData world, Server server) { + public static DefaultChunkData tryToLoad(Vec3i chunkPos, DefaultWorldData world, Server server) { if (!ENABLE) return null; @@ -113,7 +113,7 @@ public class TestWorldDiskIO { } try { - ChunkData result = load(path, chunkPos, world, server); + DefaultChunkData result = load(path, chunkPos, world, server); LOG.debug( "Loaded {} {} {}", @@ -135,7 +135,7 @@ public class TestWorldDiskIO { } } - private static ChunkData load(Path path, Vec3i chunkPos, WorldData world, Server server) + private static DefaultChunkData load(Path path, Vec3i chunkPos, DefaultWorldData world, Server server) throws IOException, DecodingException { try ( @@ -143,13 +143,13 @@ public class TestWorldDiskIO { new InflaterInputStream(new BufferedInputStream(Files.newInputStream(path))) ) ) { - ChunkData chunk = ChunkIO.load(world, chunkPos, input, IOContext.SAVE); + DefaultChunkData chunk = ChunkIO.load(world, chunkPos, input, IOContext.SAVE); readGenerationHint(chunk, input, server); return chunk; } } - private static void readGenerationHint(ChunkData chunk, DataInputStream input, Server server) + private static void readGenerationHint(DefaultChunkData chunk, DataInputStream input, Server server) throws IOException, DecodingException { chunk.setGenerationHint(server.getWorld().getGenerator().readGenerationHint(input)); diff --git a/src/main/java/ru/windcorp/progressia/test/gen/TerrainLayer.java b/src/main/java/ru/windcorp/progressia/test/gen/TerrainLayer.java index 74e3335..21c1809 100644 --- a/src/main/java/ru/windcorp/progressia/test/gen/TerrainLayer.java +++ b/src/main/java/ru/windcorp/progressia/test/gen/TerrainLayer.java @@ -19,12 +19,12 @@ package ru.windcorp.progressia.test.gen; import java.util.Random; -import ru.windcorp.progressia.common.world.ChunkData; +import ru.windcorp.progressia.common.world.DefaultChunkData; import ru.windcorp.progressia.common.world.block.BlockData; @FunctionalInterface public interface TerrainLayer { - BlockData get(float north, float west, float depth, Random random, ChunkData chunk); + BlockData get(float north, float west, float depth, Random random, DefaultChunkData chunk); } diff --git a/src/main/java/ru/windcorp/progressia/test/gen/TestWorldGenerator.java b/src/main/java/ru/windcorp/progressia/test/gen/TestWorldGenerator.java index e8c8641..75d4eb0 100644 --- a/src/main/java/ru/windcorp/progressia/test/gen/TestWorldGenerator.java +++ b/src/main/java/ru/windcorp/progressia/test/gen/TestWorldGenerator.java @@ -27,10 +27,10 @@ import glm.vec._3.Vec3; 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.world.ChunkData; +import ru.windcorp.progressia.common.world.DefaultChunkData; import ru.windcorp.progressia.common.world.Coordinates; import ru.windcorp.progressia.common.world.DecodingException; -import ru.windcorp.progressia.common.world.WorldData; +import ru.windcorp.progressia.common.world.DefaultWorldData; import ru.windcorp.progressia.common.world.WorldDataListener; import ru.windcorp.progressia.common.world.block.BlockData; import ru.windcorp.progressia.common.world.block.BlockDataRegistry; @@ -50,7 +50,7 @@ public class TestWorldGenerator extends AbstractWorldGenerator { getWorldData().addListener(new WorldDataListener() { @Override - public void onChunkLoaded(WorldData world, ChunkData chunk) { + public void onChunkLoaded(DefaultWorldData world, DefaultChunkData chunk) { findAndPopulate(chunk.getPosition(), world); } }); @@ -77,17 +77,17 @@ public class TestWorldGenerator extends AbstractWorldGenerator { } @Override - public ChunkData generate(Vec3i chunkPos) { - ChunkData chunk = generateUnpopulated(chunkPos, getWorldData()); + public DefaultChunkData generate(Vec3i chunkPos) { + DefaultChunkData chunk = generateUnpopulated(chunkPos, getWorldData()); getWorldData().addChunk(chunk); return chunk; } - private ChunkData generateUnpopulated(Vec3i chunkPos, WorldData world) { - ChunkData chunk = new ChunkData(chunkPos, world); + private DefaultChunkData generateUnpopulated(Vec3i chunkPos, DefaultWorldData world) { + DefaultChunkData chunk = new DefaultChunkData(chunkPos, world); chunk.setGenerationHint(false); - final int bpc = ChunkData.BLOCKS_PER_CHUNK; + final int bpc = DefaultChunkData.BLOCKS_PER_CHUNK; Random random = new Random(chunkPos.x + chunkPos.y + chunkPos.z); BlockData dirt = BlockDataRegistry.getInstance().get("Test:Dirt"); @@ -130,7 +130,7 @@ public class TestWorldGenerator extends AbstractWorldGenerator { return chunk; } - private void findAndPopulate(Vec3i changePos, WorldData world) { + private void findAndPopulate(Vec3i changePos, DefaultWorldData world) { VectorUtil.iterateCuboidAround(changePos, 3, candidatePos -> { if (canBePopulated(candidatePos, world)) { populate(candidatePos, world); @@ -138,10 +138,10 @@ public class TestWorldGenerator extends AbstractWorldGenerator { }); } - private boolean canBePopulated(Vec3i candidatePos, WorldData world) { + private boolean canBePopulated(Vec3i candidatePos, DefaultWorldData world) { Vec3i cursor = Vectors.grab3i(); - ChunkData candidate = world.getChunk(candidatePos); + DefaultChunkData candidate = world.getChunk(candidatePos); if (candidate == null || isChunkReady(candidate.getGenerationHint())) return false; @@ -156,7 +156,7 @@ public class TestWorldGenerator extends AbstractWorldGenerator { cursor.z = candidatePos.z + dz; - ChunkData chunk = world.getChunk(cursor); + DefaultChunkData chunk = world.getChunk(cursor); if (chunk == null) { return false; } @@ -169,10 +169,10 @@ public class TestWorldGenerator extends AbstractWorldGenerator { return true; } - private void populate(Vec3i chunkPos, WorldData world) { + private void populate(Vec3i chunkPos, DefaultWorldData world) { Random random = new Random(chunkPos.x + chunkPos.y + chunkPos.z); - ChunkData chunk = world.getChunk(chunkPos); + DefaultChunkData chunk = world.getChunk(chunkPos); assert chunk != null : "Something went wrong when populating chunk at (" + chunkPos.x + "; " + chunkPos.y + "; " + chunkPos.z + ")"; @@ -188,7 +188,7 @@ public class TestWorldGenerator extends AbstractWorldGenerator { int minZ = chunk.getMinZ(); int maxZ = chunk.getMaxZ() + 1; - final int bpc = ChunkData.BLOCKS_PER_CHUNK; + final int bpc = DefaultChunkData.BLOCKS_PER_CHUNK; double[][] heightMap = new double[bpc][bpc]; double[][] gradMap = new double[bpc][bpc]; @@ -226,9 +226,9 @@ public class TestWorldGenerator extends AbstractWorldGenerator { } private void addTiles( - ChunkData chunk, + DefaultChunkData chunk, Vec3i biw, - WorldData world, + DefaultWorldData world, Random random, boolean isDirt, double height, @@ -240,7 +240,7 @@ public class TestWorldGenerator extends AbstractWorldGenerator { addSnow(chunk, biw, world, random, isDirt, height, grad); } - private void addGrass(ChunkData chunk, Vec3i biw, WorldData world, Random random) { + private void addGrass(DefaultChunkData chunk, Vec3i biw, DefaultWorldData world, Random random) { BlockData air = BlockDataRegistry.getInstance().get("Test:Air"); TileData grass = TileDataRegistry.getInstance().get("Test:Grass"); @@ -260,7 +260,7 @@ public class TestWorldGenerator extends AbstractWorldGenerator { } } - private void addDecor(ChunkData chunk, Vec3i biw, WorldData world, Random random, boolean isDirt) { + private void addDecor(DefaultChunkData chunk, Vec3i biw, DefaultWorldData world, Random random, boolean isDirt) { if (isDirt) { if (random.nextInt(8) == 0) { world.getTiles(biw, AbsFace.POS_Z).addFarthest( @@ -289,9 +289,9 @@ public class TestWorldGenerator extends AbstractWorldGenerator { } private void addSnow( - ChunkData chunk, + DefaultChunkData chunk, Vec3i biw, - WorldData world, + DefaultWorldData world, Random random, boolean isDirt, double height, 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 38b9d94..3637078 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 @@ -17,7 +17,7 @@ */ package ru.windcorp.progressia.test.gen.planet; -import ru.windcorp.progressia.common.world.ChunkData; +import ru.windcorp.progressia.common.world.DefaultChunkData; public class Planet { @@ -47,7 +47,7 @@ public class Planet { } public float getRadius() { - return radiusInChunks * ChunkData.BLOCKS_PER_CHUNK + ChunkData.CHUNK_RADIUS; + return radiusInChunks * DefaultChunkData.BLOCKS_PER_CHUNK + DefaultChunkData.CHUNK_RADIUS; } public int getDiameterInChunks() { @@ -55,7 +55,7 @@ public class Planet { } public float getDiameter() { - return getDiameterInChunks() * ChunkData.BLOCKS_PER_CHUNK; + return getDiameterInChunks() * DefaultChunkData.BLOCKS_PER_CHUNK; } /** 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 6c14a2b..a33cb87 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 @@ -23,7 +23,7 @@ import java.util.Map; import glm.vec._3.i.Vec3i; import ru.windcorp.progressia.common.util.VectorUtil; -import ru.windcorp.progressia.common.world.ChunkData; +import ru.windcorp.progressia.common.world.DefaultChunkData; import ru.windcorp.progressia.common.world.rels.AbsFace; import ru.windcorp.progressia.test.TestBushFeature; import ru.windcorp.progressia.test.TestGrassFeature; @@ -57,7 +57,7 @@ public class PlanetFeatureGenerator { return parent; } - public void generateFeatures(ChunkData chunk) { + public void generateFeatures(DefaultChunkData chunk) { if (isOrdinaryChunk(chunk.getPosition())) { generateOrdinaryFeatures(chunk); } else { @@ -72,11 +72,11 @@ public class PlanetFeatureGenerator { return sorted.x != sorted.y; } - private void generateOrdinaryFeatures(ChunkData chunk) { + private void generateOrdinaryFeatures(DefaultChunkData chunk) { surfaceGenerators.get(chunk.getUp()).generateFeatures(chunk); } - private void generateBorderFeatures(ChunkData chunk) { + private void generateBorderFeatures(DefaultChunkData chunk) { // Do nothing } diff --git a/src/main/java/ru/windcorp/progressia/test/gen/planet/PlanetTerrainGenerator.java b/src/main/java/ru/windcorp/progressia/test/gen/planet/PlanetTerrainGenerator.java index e8307cb..227187d 100644 --- a/src/main/java/ru/windcorp/progressia/test/gen/planet/PlanetTerrainGenerator.java +++ b/src/main/java/ru/windcorp/progressia/test/gen/planet/PlanetTerrainGenerator.java @@ -22,7 +22,7 @@ import glm.vec._3.i.Vec3i; import ru.windcorp.progressia.common.util.ArrayFloatRangeMap; import ru.windcorp.progressia.common.util.FloatRangeMap; import ru.windcorp.progressia.common.util.VectorUtil; -import ru.windcorp.progressia.common.world.ChunkData; +import ru.windcorp.progressia.common.world.DefaultChunkData; import ru.windcorp.progressia.common.world.Coordinates; import ru.windcorp.progressia.common.world.block.BlockData; import ru.windcorp.progressia.common.world.block.BlockDataRegistry; @@ -40,7 +40,7 @@ class PlanetTerrainGenerator { this.parent = generator; SurfaceFloatField heightMap = new TestHeightMap( - generator.getPlanet().getRadius() - ChunkData.BLOCKS_PER_CHUNK, + generator.getPlanet().getRadius() - DefaultChunkData.BLOCKS_PER_CHUNK, generator.getPlanet().getRadius() / 4, 5, 6 @@ -61,8 +61,8 @@ class PlanetTerrainGenerator { return parent; } - public ChunkData generateTerrain(Vec3i chunkPos) { - ChunkData chunk = new ChunkData(chunkPos, getGenerator().getWorldData()); + public DefaultChunkData generateTerrain(Vec3i chunkPos) { + DefaultChunkData chunk = new DefaultChunkData(chunkPos, getGenerator().getWorldData()); if (isOrdinaryChunk(chunkPos)) { generateOrdinaryTerrain(chunk); @@ -80,11 +80,11 @@ class PlanetTerrainGenerator { return sorted.x != sorted.y; } - private void generateOrdinaryTerrain(ChunkData chunk) { + private void generateOrdinaryTerrain(DefaultChunkData chunk) { surfaceGenerator.generateTerrain(chunk); } - private void generateBorderTerrain(ChunkData chunk) { + private void generateBorderTerrain(DefaultChunkData chunk) { BlockData stone = BlockDataRegistry.getInstance().get("Test:Stone"); BlockData air = BlockDataRegistry.getInstance().get("Test:Air"); @@ -100,7 +100,7 @@ class PlanetTerrainGenerator { Coordinates.getInWorld(chunk.getZ(), bic.z) ); - biw.sub(ChunkData.CHUNK_RADIUS - 0.5f); + biw.sub(DefaultChunkData.CHUNK_RADIUS - 0.5f); VectorUtil.sortAfterAbs(biw, biw); chunk.setBlock(bic, biw.x <= radius ? stone : air, false); 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 1dbd5b8..8b92470 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 @@ -24,7 +24,7 @@ import java.io.IOException; import glm.vec._3.Vec3; import glm.vec._3.i.Vec3i; import ru.windcorp.progressia.common.util.VectorUtil; -import ru.windcorp.progressia.common.world.ChunkData; +import ru.windcorp.progressia.common.world.DefaultChunkData; import ru.windcorp.progressia.common.world.DecodingException; import ru.windcorp.progressia.server.Server; import ru.windcorp.progressia.server.world.generation.AbstractWorldGenerator; @@ -76,9 +76,9 @@ public class TestPlanetGenerator extends AbstractWorldGenerator { } @Override - public ChunkData generate(Vec3i chunkPos) { + public DefaultChunkData generate(Vec3i chunkPos) { VectorUtil.iterateCuboidAround(chunkPos, 3, r -> conjureTerrain(r)); - ChunkData chunk = getWorldData().getChunk(chunkPos); + DefaultChunkData chunk = getWorldData().getChunk(chunkPos); if (!isChunkReady(chunk.getGenerationHint())) { featureGenerator.generateFeatures(chunk); @@ -88,7 +88,7 @@ public class TestPlanetGenerator extends AbstractWorldGenerator { } private void conjureTerrain(Vec3i chunkPos) { - ChunkData chunk = getWorldData().getChunk(chunkPos); + DefaultChunkData chunk = getWorldData().getChunk(chunkPos); if (chunk == null) { chunk = getWorldData().getChunk(chunkPos); 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 cb5fc34..a7fb334 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,7 +19,7 @@ package ru.windcorp.progressia.test.gen.planet; import glm.vec._3.Vec3; import glm.vec._3.i.Vec3i; -import ru.windcorp.progressia.common.world.ChunkData; +import ru.windcorp.progressia.common.world.DefaultChunkData; import ru.windcorp.progressia.common.world.DecodingException; import ru.windcorp.progressia.common.world.GravityModel; import ru.windcorp.progressia.common.world.rels.AbsFace; @@ -93,9 +93,9 @@ public class TestPlanetGravityModel extends GravityModel { 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; + float px = pos.x - DefaultChunkData.CHUNK_RADIUS + 0.5f; + float py = pos.y - DefaultChunkData.CHUNK_RADIUS + 0.5f; + float pz = pos.z - DefaultChunkData.CHUNK_RADIUS + 0.5f; // Assume weightlessness when too close to center if ((px*px + py*py + pz*pz) < r*r) { 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 69e6d8b..0510d98 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 @@ -25,7 +25,7 @@ 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.ChunkData; +import ru.windcorp.progressia.common.world.DefaultChunkData; import ru.windcorp.progressia.common.world.generic.GenericChunks; public abstract class SurfaceFeature extends Namespaced { @@ -33,13 +33,13 @@ public abstract class SurfaceFeature extends Namespaced { public static class Request { private final SurfaceWorld world; - private final ChunkData chunk; + private final DefaultChunkData chunk; private final Vec3i minSfc = new Vec3i(); private final Vec3i maxSfc = new Vec3i(); private final Random random; - public Request(SurfaceWorld world, ChunkData chunk, Random random) { + public Request(SurfaceWorld world, DefaultChunkData chunk, Random random) { this.world = world; this.chunk = chunk; this.random = random; @@ -57,7 +57,7 @@ public abstract class SurfaceFeature extends Namespaced { maxSfc.z -= world.getSurface().getSeaLevel(); } - public ChunkData getChunk() { + public DefaultChunkData getChunk() { return chunk; } 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 9a3c909..54b582e 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 @@ -22,7 +22,7 @@ import java.util.Collection; import java.util.Random; import ru.windcorp.progressia.common.util.CoordinatePacker; -import ru.windcorp.progressia.common.world.ChunkData; +import ru.windcorp.progressia.common.world.DefaultChunkData; public class SurfaceFeatureGenerator { @@ -42,7 +42,7 @@ public class SurfaceFeatureGenerator { return surface; } - public void generateFeatures(ChunkData chunk) { + public void generateFeatures(DefaultChunkData chunk) { SurfaceWorld world = new SurfaceWorld(surface, chunk.getWorld()); Random random = new Random(CoordinatePacker.pack3IntsIntoLong(chunk.getPosition()) /* ^ seed*/); diff --git a/src/main/java/ru/windcorp/progressia/test/gen/surface/SurfaceTerrainGenerator.java b/src/main/java/ru/windcorp/progressia/test/gen/surface/SurfaceTerrainGenerator.java index b05df5a..ec93d58 100644 --- a/src/main/java/ru/windcorp/progressia/test/gen/surface/SurfaceTerrainGenerator.java +++ b/src/main/java/ru/windcorp/progressia/test/gen/surface/SurfaceTerrainGenerator.java @@ -23,7 +23,7 @@ import glm.vec._3.Vec3; import glm.vec._3.i.Vec3i; import ru.windcorp.progressia.common.util.CoordinatePacker; import ru.windcorp.progressia.common.util.FloatRangeMap; -import ru.windcorp.progressia.common.world.ChunkData; +import ru.windcorp.progressia.common.world.DefaultChunkData; import ru.windcorp.progressia.common.world.block.BlockData; import ru.windcorp.progressia.common.world.rels.AxisRotations; import ru.windcorp.progressia.test.gen.TerrainLayer; @@ -38,35 +38,38 @@ public class SurfaceTerrainGenerator { this.layers = layers; } - public void generateTerrain(ChunkData chunk) { + public void generateTerrain(DefaultChunkData chunk) { Vec3i relBIC = new Vec3i(); Vec3 offset = new Vec3(chunk.getMinX(), chunk.getMinY(), chunk.getMinZ()); AxisRotations.relativize(offset, chunk.getUp(), offset); - offset.sub(ChunkData.CHUNK_RADIUS - 0.5f); + offset.sub(DefaultChunkData.CHUNK_RADIUS - 0.5f); Random random = new Random(CoordinatePacker.pack3IntsIntoLong(chunk.getPosition()) /* ^ seed*/); - for (relBIC.x = 0; relBIC.x < ChunkData.BLOCKS_PER_CHUNK; ++relBIC.x) { - for (relBIC.y = 0; relBIC.y < ChunkData.BLOCKS_PER_CHUNK; ++relBIC.y) { + for (relBIC.x = 0; relBIC.x < DefaultChunkData.BLOCKS_PER_CHUNK; ++relBIC.x) { + for (relBIC.y = 0; relBIC.y < DefaultChunkData.BLOCKS_PER_CHUNK; ++relBIC.y) { generateColumn(chunk, relBIC, offset, random); } } } - public void generateColumn(ChunkData chunk, Vec3i relBIC, Vec3 offset, Random random) { + public void generateColumn(DefaultChunkData chunk, Vec3i relBIC, Vec3 offset, Random random) { float north = relBIC.x + offset.x; float west = relBIC.y + offset.y; float relSurface = heightMap.get(chunk.getUp(), north, west) - offset.z; - for (relBIC.z = 0; relBIC.z < ChunkData.BLOCKS_PER_CHUNK; ++relBIC.z) { + for (relBIC.z = 0; relBIC.z < DefaultChunkData.BLOCKS_PER_CHUNK; ++relBIC.z) { float depth = relSurface - relBIC.z; BlockData block = layers.get(depth).get(north, west, depth, random, chunk); - chunk.setBlockRel(relBIC, block, false); + + chunk.resolve(relBIC, relBIC); + chunk.setBlock(relBIC, block, false); + chunk.relativize(relBIC, relBIC); } } diff --git a/src/main/java/ru/windcorp/progressia/test/gen/surface/SurfaceWorld.java b/src/main/java/ru/windcorp/progressia/test/gen/surface/SurfaceWorld.java index 12ff59a..7d3ec10 100644 --- a/src/main/java/ru/windcorp/progressia/test/gen/surface/SurfaceWorld.java +++ b/src/main/java/ru/windcorp/progressia/test/gen/surface/SurfaceWorld.java @@ -20,26 +20,29 @@ package ru.windcorp.progressia.test.gen.surface; import java.util.Collection; import glm.vec._3.i.Vec3i; +import ru.windcorp.progressia.common.state.StateChange; +import ru.windcorp.progressia.common.state.StatefulObject; import ru.windcorp.progressia.common.util.Vectors; import ru.windcorp.progressia.common.world.ChunkData; +import ru.windcorp.progressia.common.world.GravityModel; import ru.windcorp.progressia.common.world.block.BlockData; import ru.windcorp.progressia.common.world.entity.EntityData; +import ru.windcorp.progressia.common.world.generic.EntityGeneric; import ru.windcorp.progressia.common.world.generic.GenericChunks; -import ru.windcorp.progressia.common.world.generic.GenericWritableWorld; import ru.windcorp.progressia.common.world.rels.BlockFace; import ru.windcorp.progressia.common.world.tile.TileData; -import ru.windcorp.progressia.common.world.tile.TileDataReference; -import ru.windcorp.progressia.common.world.tile.TileDataStack; +import ru.windcorp.progressia.common.world.TileDataStack; +import ru.windcorp.progressia.common.world.WorldData; public class SurfaceWorld - implements GenericWritableWorld { + implements WorldData { private final Surface surface; - private final GenericWritableWorld parent; + private final WorldData parent; public SurfaceWorld( Surface surface, - GenericWritableWorld parent + WorldData parent ) { this.surface = surface; this.parent = parent; @@ -55,7 +58,7 @@ public class SurfaceWorld /** * @return the parent */ - public GenericWritableWorld getParent() { + public WorldData getParent() { return parent; } @@ -64,7 +67,7 @@ public class SurfaceWorld */ @Override - public Collection getChunks() { + public Collection getChunks() { return parent.getChunks(); } @@ -179,4 +182,24 @@ public class SurfaceWorld return result; } + @Override + public float getTime() { + return parent.getTime(); + } + + @Override + public GravityModel getGravityModel() { + return parent.getGravityModel(); + } + + @Override + public void changeEntity(SE entity, StateChange change) { + parent.changeEntity(entity, change); + } + + @Override + public void advanceTime(float change) { + parent.advanceTime(change); + } + } From a338a00f1d83c1ec36130ac5a80bcf72f168d046 Mon Sep 17 00:00:00 2001 From: OLEGSHA Date: Sat, 31 Jul 2021 16:01:25 +0300 Subject: [PATCH 32/55] A change to the class hierarchy of WorldLogic similar to prev commit - Renamed ChunkLogic -> DefaultChunkLogic, WorldLogic -> DefaultWorldLogic - Created/rewritten TileLogicReference{,RO}, TileLogicStack{,RO}, ChunkLogic{,RO} - Drafted up something for ServerWorldContext & friends, WIP (see commit 9a32660 for more details) --- .../progressia/common/world/ChunkData.java | 8 +- .../common/world/DefaultChunkData.java | 6 +- .../common/world/generic/ChunkGenericRO.java | 2 +- .../world/generic/TileGenericReferenceRO.java | 49 +++- .../ru/windcorp/progressia/server/Server.java | 10 +- .../progressia/server/world/ChunkLogic.java | 225 +--------------- .../progressia/server/world/ChunkLogicRO.java | 15 ++ .../server/world/ChunkTickContext.java | 4 +- .../server/world/DefaultChunkLogic.java | 249 ++++++++++++++++++ .../server/world/DefaultWorldLogic.java | 146 ++++++++++ .../server/world/TickAndUpdateUtil.java | 12 +- .../progressia/server/world/TickContext.java | 2 +- .../server/world/TickContextMutable.java | 4 +- .../server/world/TileLogicReference.java | 44 ++++ .../server/world/TileLogicReferenceRO.java | 82 ++++++ .../server/world/TileLogicStack.java | 37 +++ ...eLogicStack.java => TileLogicStackRO.java} | 15 +- .../progressia/server/world/WorldLogic.java | 134 ++-------- ...eLogicReference.java => WorldLogicRO.java} | 11 +- .../world/context/ServerWorldContext.java | 35 +++ .../world/context/ServerWorldContextRO.java | 16 ++ .../generation/AbstractWorldGenerator.java | 4 +- .../world/generation/WorldGenerator.java | 4 +- .../world/tasks/BlockTriggeredUpdate.java | 4 +- .../server/world/tasks/TickChunk.java | 6 +- .../world/tasks/TileTriggeredUpdate.java | 4 +- .../server/world/tile/TSTickContext.java | 9 +- .../server/world/tile/TileTickContext.java | 3 +- .../test/gen/TestTerrainGenerator.java | 4 +- 29 files changed, 754 insertions(+), 390 deletions(-) create mode 100644 src/main/java/ru/windcorp/progressia/server/world/ChunkLogicRO.java create mode 100644 src/main/java/ru/windcorp/progressia/server/world/DefaultChunkLogic.java create mode 100644 src/main/java/ru/windcorp/progressia/server/world/DefaultWorldLogic.java create mode 100644 src/main/java/ru/windcorp/progressia/server/world/TileLogicReference.java create mode 100644 src/main/java/ru/windcorp/progressia/server/world/TileLogicReferenceRO.java create mode 100644 src/main/java/ru/windcorp/progressia/server/world/TileLogicStack.java rename src/main/java/ru/windcorp/progressia/server/world/{tile/TileLogicStack.java => TileLogicStackRO.java} (67%) rename src/main/java/ru/windcorp/progressia/server/world/{tile/TileLogicReference.java => WorldLogicRO.java} (67%) create mode 100644 src/main/java/ru/windcorp/progressia/server/world/context/ServerWorldContext.java create mode 100644 src/main/java/ru/windcorp/progressia/server/world/context/ServerWorldContextRO.java diff --git a/src/main/java/ru/windcorp/progressia/common/world/ChunkData.java b/src/main/java/ru/windcorp/progressia/common/world/ChunkData.java index ab55863..fe84518 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/ChunkData.java +++ b/src/main/java/ru/windcorp/progressia/common/world/ChunkData.java @@ -4,11 +4,9 @@ import ru.windcorp.progressia.common.world.block.BlockData; import ru.windcorp.progressia.common.world.generic.ChunkGenericWO; import ru.windcorp.progressia.common.world.tile.TileData; -public interface ChunkData extends ChunkDataRO, ChunkGenericWO { +public interface ChunkData + extends ChunkDataRO, ChunkGenericWO { -// @Override -// default TileDataStack getTiles(Vec3i blockInChunk, BlockFace face) { -// return null; -// } + // currently empty } diff --git a/src/main/java/ru/windcorp/progressia/common/world/DefaultChunkData.java b/src/main/java/ru/windcorp/progressia/common/world/DefaultChunkData.java index 5c1cd08..e11509b 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/DefaultChunkData.java +++ b/src/main/java/ru/windcorp/progressia/common/world/DefaultChunkData.java @@ -37,6 +37,10 @@ import ru.windcorp.progressia.common.world.rels.RelFace; import ru.windcorp.progressia.common.world.tile.TileData; import ru.windcorp.progressia.common.world.tile.TileStackIsFullException; +/** + * The implementation of {@link ChunkData} used to store the actual game world. + * This class should be considered an implementation detail. + */ public class DefaultChunkData implements ChunkData { public static final int BLOCKS_PER_CHUNK = Coordinates.CHUNK_SIZE; @@ -222,7 +226,7 @@ public class DefaultChunkData implements ChunkData { } public void invalidate() { - this.index = 0; + this.index = -1; } @Override diff --git a/src/main/java/ru/windcorp/progressia/common/world/generic/ChunkGenericRO.java b/src/main/java/ru/windcorp/progressia/common/world/generic/ChunkGenericRO.java index 56482b5..cd648c5 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/generic/ChunkGenericRO.java +++ b/src/main/java/ru/windcorp/progressia/common/world/generic/ChunkGenericRO.java @@ -34,7 +34,7 @@ import ru.windcorp.progressia.common.world.rels.BlockFace; * An unmodifiable chunk representation. Per default, it is usually one of * {@link ru.windcorp.progressia.common.world.DefaultChunkData ChunkData}, * {@link ru.windcorp.progressia.client.world.ChunkRender ChunkRender} or - * {@link ru.windcorp.progressia.server.world.ChunkLogic ChunkLogic}, but this + * {@link ru.windcorp.progressia.server.world.DefaultChunkLogic ChunkLogic}, but this * interface may be implemented differently for various reasons. *

    * A generic chunk contains {@linkplain BlockGeneric blocks} and diff --git a/src/main/java/ru/windcorp/progressia/common/world/generic/TileGenericReferenceRO.java b/src/main/java/ru/windcorp/progressia/common/world/generic/TileGenericReferenceRO.java index 64f7cfb..6f49630 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/generic/TileGenericReferenceRO.java +++ b/src/main/java/ru/windcorp/progressia/common/world/generic/TileGenericReferenceRO.java @@ -18,6 +18,16 @@ package ru.windcorp.progressia.common.world.generic; +/** + * A reference to a single tile in a tile stack. A {@code TileReference} remains + * valid until the tile is removed from its stack. + *

    + * Tile reference objects may be reused for other tiles; {@link #isValid()} only + * shows if there exists some tile that this object references; it may + * or may not be the tile this reference was acquired for. It is the + * responsibility of the programmer to discard references when the tile is + * removed. + */ // @formatter:off public interface TileGenericReferenceRO< B extends BlockGeneric, @@ -28,16 +38,49 @@ public interface TileGenericReferenceRO< > { // @formatter:on - T get(); - + /** + * Gets the index that the referenced tile currently occupies. This value + * may change as tiles are added to or removed from the stack. + * + * @return the index of the tile or {@code -1} if this reference is invalid + */ int getIndex(); + /** + * Gets the tile stack that contains the referenced tile. + * + * @return the tile stack of the relevant tile or {@code null} if this + * reference is invalid. + */ TS getStack(); + /** + * Gets the tile that this object references. + * + * @return the relevant tile or {@code null} if this reference is invalid + */ + default T get() { + return getStack().get(getIndex()); + } + + /** + * Checks whether this reference is valid. A reference is valid if it points + * to some tile; it may or may not be the tile that this reference + * was acquired for. (A tile reference can only change the referenced tile + * after the previous tile is removed from the stack.) + * + * @return {@code true} iff there exists a tile that this reference points + * to. + */ default boolean isValid() { return get() != null; } - + + /** + * Gets the tag of the referenced tile. + * + * @return the tag or {@code -1} iff this reference is invalid. + */ default int getTag() { TS tileStack = getStack(); if (tileStack == null) { diff --git a/src/main/java/ru/windcorp/progressia/server/Server.java b/src/main/java/ru/windcorp/progressia/server/Server.java index 9da227f..0896caa 100644 --- a/src/main/java/ru/windcorp/progressia/server/Server.java +++ b/src/main/java/ru/windcorp/progressia/server/Server.java @@ -34,7 +34,7 @@ import ru.windcorp.progressia.server.events.ServerEvent; import ru.windcorp.progressia.server.management.load.ChunkRequestDaemon; import ru.windcorp.progressia.server.management.load.EntityRequestDaemon; import ru.windcorp.progressia.server.management.load.LoadManager; -import ru.windcorp.progressia.server.world.WorldLogic; +import ru.windcorp.progressia.server.world.DefaultWorldLogic; import ru.windcorp.progressia.server.world.tasks.WorldAccessor; import ru.windcorp.progressia.server.world.ticking.Change; import ru.windcorp.progressia.server.world.ticking.Evaluation; @@ -53,7 +53,7 @@ public class Server { return ServerThread.getCurrentServer(); } - private final WorldLogic world; + private final DefaultWorldLogic world; private final WorldAccessor worldAccessor = new WorldAccessor(this); private final ServerThread serverThread; @@ -69,7 +69,7 @@ public class Server { private final TickingSettings tickingSettings = new TickingSettings(); public Server(DefaultWorldData world) { - this.world = new WorldLogic( + this.world = new DefaultWorldLogic( world, this, new TestPlanetGenerator("Test:PlanetGenerator", this, new Planet(4, 9.8f, 16f, 16f)) @@ -91,9 +91,9 @@ public class Server { /** * Returns this server's world. * - * @return this server's {@link WorldLogic} + * @return this server's {@link DefaultWorldLogic} */ - public WorldLogic getWorld() { + public DefaultWorldLogic getWorld() { return world; } diff --git a/src/main/java/ru/windcorp/progressia/server/world/ChunkLogic.java b/src/main/java/ru/windcorp/progressia/server/world/ChunkLogic.java index f633179..a9c3392 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/ChunkLogic.java +++ b/src/main/java/ru/windcorp/progressia/server/world/ChunkLogic.java @@ -15,230 +15,27 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - package ru.windcorp.progressia.server.world; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.Map; -import java.util.WeakHashMap; -import java.util.function.BiConsumer; - import glm.vec._3.i.Vec3i; -import ru.windcorp.progressia.common.world.DefaultChunkData; -import ru.windcorp.progressia.common.world.Coordinates; -import ru.windcorp.progressia.common.world.generic.ChunkGenericRO; -import ru.windcorp.progressia.common.world.rels.AbsFace; +import ru.windcorp.progressia.common.world.ChunkData; import ru.windcorp.progressia.common.world.rels.BlockFace; -import ru.windcorp.progressia.common.world.rels.RelFace; -import ru.windcorp.progressia.common.world.TileDataStack; -import ru.windcorp.progressia.common.world.TileDataReference; -import ru.windcorp.progressia.server.world.block.BlockLogic; -import ru.windcorp.progressia.server.world.block.BlockLogicRegistry; -import ru.windcorp.progressia.server.world.block.TickableBlock; -import ru.windcorp.progressia.server.world.tasks.TickChunk; -import ru.windcorp.progressia.server.world.ticking.TickingPolicy; -import ru.windcorp.progressia.server.world.tile.TickableTile; -import ru.windcorp.progressia.server.world.tile.TileLogic; -import ru.windcorp.progressia.server.world.tile.TileLogicReference; -import ru.windcorp.progressia.server.world.tile.TileLogicRegistry; -import ru.windcorp.progressia.server.world.tile.TileLogicStack; -public class ChunkLogic implements ChunkGenericRO { +public interface ChunkLogic extends ChunkLogicRO { - private final WorldLogic world; - private final DefaultChunkData data; - - private final Collection tickingBlocks = new ArrayList<>(); - private final Collection tickingTiles = new ArrayList<>(); - - private final TickChunk tickTask = new TickChunk(this); - - private final Map tileLogicLists = Collections - .synchronizedMap(new WeakHashMap<>()); - - public ChunkLogic(WorldLogic world, DefaultChunkData data) { - this.world = world; - this.data = data; - - tmp_generateTickLists(); - } - - @Override - public Vec3i getPosition() { - return getData().getPosition(); - } + /* + * Override return type + */ @Override - public AbsFace getUp() { - return getData().getUp(); + ChunkData getData(); + + @Override + default TileLogicStack getTilesOrNull(Vec3i blockInChunk, BlockFace face) { + return (TileLogicStack) ChunkLogicRO.super.getTilesOrNull(blockInChunk, face); } @Override - public BlockLogic getBlock(Vec3i blockInChunk) { - return BlockLogicRegistry.getInstance().get( - getData().getBlock(blockInChunk).getId() - ); - } - - @Override - public TileLogicStack getTiles(Vec3i blockInChunk, BlockFace face) { - return getTileStackWrapper(getData().getTiles(blockInChunk, face)); - } - - @Override - public boolean hasTiles(Vec3i blockInChunk, BlockFace face) { - return getData().hasTiles(blockInChunk, face); - } - - private TileLogicStack getTileStackWrapper(TileDataStack tileDataList) { - return tileLogicLists.computeIfAbsent( - tileDataList, - TileLogicStackImpl::new - ); - } - - public WorldLogic getWorld() { - return world; - } - - public DefaultChunkData getData() { - return data; - } - - public boolean isReady() { - return getWorld().getGenerator().isChunkReady(getData().getGenerationHint()); - } - - public boolean hasTickingBlocks() { - return !tickingBlocks.isEmpty(); - } - - public boolean hasTickingTiles() { - return !tickingTiles.isEmpty(); - } - - public void forEachTickingBlock(BiConsumer action) { - tickingBlocks.forEach(blockInChunk -> { - action.accept(blockInChunk, getBlock(blockInChunk)); - }); - } - - public void forEachTickingTile(BiConsumer action) { - tickingTiles.forEach(ref -> { - action.accept( - ref, - TileLogicRegistry.getInstance().get(ref.get().getId()) - ); - }); - } - - public TickChunk getTickTask() { - return tickTask; - } - - private class TileLogicStackImpl extends TileLogicStack { - private class TileLogicReferenceImpl implements TileLogicReference { - private final TileDataReference parent; - - public TileLogicReferenceImpl (TileDataReference parent) { - this.parent = parent; - } - - @Override - public TileLogic get() { - return TileLogicRegistry.getInstance().get(parent.get().getId()); - } - - @Override - public int getIndex() { - return parent.getIndex(); - } - - @Override - public TileLogicStack getStack() { - return TileLogicStackImpl.this; - } - } - - private final TileDataStack parent; - - public TileLogicStackImpl(TileDataStack parent) { - this.parent = parent; - } - - @Override - public Vec3i getBlockInChunk(Vec3i output) { - return parent.getBlockInChunk(output); - } - - @Override - public ChunkLogic getChunk() { - return ChunkLogic.this; - } - - @Override - public RelFace getFace() { - return parent.getFace(); - } - - @Override - public TileLogicReference getReference(int index) { - return new TileLogicReferenceImpl(parent.getReference(index)); - } - - @Override - public int getIndexByTag(int tag) { - return parent.getIndexByTag(tag); - } - - @Override - public int getTagByIndex(int index) { - return parent.getTagByIndex(index); - } - - @Override - public TileLogic get(int index) { - return TileLogicRegistry.getInstance().get(parent.get(index).getId()); - } - - @Override - public int size() { - return parent.size(); - } - - @Override - public TileDataStack getData() { - return parent; - } - - } - - private void tmp_generateTickLists() { - ChunkTickContext context = TickContextMutable.start().withChunk(this).build(); - - context.forEachBlock(bctxt -> { - BlockLogic block = bctxt.getBlock(); - - if (!(block instanceof TickableBlock)) - return; - - if (((TickableBlock) block).getTickingPolicy(bctxt) == TickingPolicy.REGULAR) { - tickingBlocks.add(Coordinates.convertInWorldToInChunk(bctxt.getBlockInWorld(), null)); - } - - bctxt.forEachFace(fctxt -> fctxt.forEachTile(tctxt -> { - TileLogic tile = tctxt.getTile(); - - if (!(tile instanceof TickableTile)) - return; - - if (((TickableTile) tile).getTickingPolicy(tctxt) == TickingPolicy.REGULAR) { - tickingTiles.add(tctxt.getReference()); - } - })); - }); - } + TileLogicStack getTiles(Vec3i blockInChunk, BlockFace face); } diff --git a/src/main/java/ru/windcorp/progressia/server/world/ChunkLogicRO.java b/src/main/java/ru/windcorp/progressia/server/world/ChunkLogicRO.java new file mode 100644 index 0000000..5631027 --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/server/world/ChunkLogicRO.java @@ -0,0 +1,15 @@ +package ru.windcorp.progressia.server.world; + +import ru.windcorp.progressia.common.world.ChunkDataRO; +import ru.windcorp.progressia.common.world.generic.ChunkGenericRO; +import ru.windcorp.progressia.server.world.block.BlockLogic; +import ru.windcorp.progressia.server.world.tile.TileLogic; + +public interface ChunkLogicRO + extends ChunkGenericRO { + + ChunkDataRO getData(); + + boolean isReady(); + +} diff --git a/src/main/java/ru/windcorp/progressia/server/world/ChunkTickContext.java b/src/main/java/ru/windcorp/progressia/server/world/ChunkTickContext.java index 09cf0e6..aec68fe 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/ChunkTickContext.java +++ b/src/main/java/ru/windcorp/progressia/server/world/ChunkTickContext.java @@ -30,12 +30,12 @@ public interface ChunkTickContext extends TickContext { Vec3i getChunk(); - default ChunkLogic getChunkLogic() { + default DefaultChunkLogic getChunkLogic() { return getWorld().getChunk(getChunk()); } default DefaultChunkData getChunkData() { - ChunkLogic chunkLogic = getChunkLogic(); + DefaultChunkLogic chunkLogic = getChunkLogic(); return chunkLogic == null ? null : chunkLogic.getData(); } diff --git a/src/main/java/ru/windcorp/progressia/server/world/DefaultChunkLogic.java b/src/main/java/ru/windcorp/progressia/server/world/DefaultChunkLogic.java new file mode 100644 index 0000000..69fed5e --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/server/world/DefaultChunkLogic.java @@ -0,0 +1,249 @@ +/* + * 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.server.world; + +import java.util.AbstractList; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Map; +import java.util.WeakHashMap; +import java.util.function.BiConsumer; + +import glm.vec._3.i.Vec3i; +import ru.windcorp.progressia.common.world.DefaultChunkData; +import ru.windcorp.progressia.common.world.Coordinates; +import ru.windcorp.progressia.common.world.rels.AbsFace; +import ru.windcorp.progressia.common.world.rels.BlockFace; +import ru.windcorp.progressia.common.world.rels.RelFace; +import ru.windcorp.progressia.common.world.TileDataStack; +import ru.windcorp.progressia.common.world.TileDataReference; +import ru.windcorp.progressia.server.world.block.BlockLogic; +import ru.windcorp.progressia.server.world.block.BlockLogicRegistry; +import ru.windcorp.progressia.server.world.block.TickableBlock; +import ru.windcorp.progressia.server.world.tasks.TickChunk; +import ru.windcorp.progressia.server.world.ticking.TickingPolicy; +import ru.windcorp.progressia.server.world.tile.TickableTile; +import ru.windcorp.progressia.server.world.tile.TileLogic; +import ru.windcorp.progressia.server.world.tile.TileLogicRegistry; + +public class DefaultChunkLogic implements ChunkLogic { + + private final DefaultWorldLogic world; + private final DefaultChunkData data; + + private final Collection tickingBlocks = new ArrayList<>(); + private final Collection tickingTiles = new ArrayList<>(); + + private final TickChunk tickTask = new TickChunk(this); + + private final Map tileLogicLists = Collections + .synchronizedMap(new WeakHashMap<>()); + + public DefaultChunkLogic(DefaultWorldLogic world, DefaultChunkData data) { + this.world = world; + this.data = data; + + tmp_generateTickLists(); + } + + @Override + public Vec3i getPosition() { + return getData().getPosition(); + } + + @Override + public AbsFace getUp() { + return getData().getUp(); + } + + @Override + public BlockLogic getBlock(Vec3i blockInChunk) { + return BlockLogicRegistry.getInstance().get( + getData().getBlock(blockInChunk).getId() + ); + } + + @Override + public TileLogicStack getTiles(Vec3i blockInChunk, BlockFace face) { + return getTileStackWrapper(getData().getTiles(blockInChunk, face)); + } + + @Override + public boolean hasTiles(Vec3i blockInChunk, BlockFace face) { + return getData().hasTiles(blockInChunk, face); + } + + private TileLogicStack getTileStackWrapper(TileDataStack tileDataList) { + return tileLogicLists.computeIfAbsent( + tileDataList, + TileLogicStackImpl::new + ); + } + + public DefaultWorldLogic getWorld() { + return world; + } + + @Override + public DefaultChunkData getData() { + return data; + } + + @Override + public boolean isReady() { + return getWorld().getGenerator().isChunkReady(getData().getGenerationHint()); + } + + public boolean hasTickingBlocks() { + return !tickingBlocks.isEmpty(); + } + + public boolean hasTickingTiles() { + return !tickingTiles.isEmpty(); + } + + public void forEachTickingBlock(BiConsumer action) { + tickingBlocks.forEach(blockInChunk -> { + action.accept(blockInChunk, getBlock(blockInChunk)); + }); + } + + public void forEachTickingTile(BiConsumer action) { + tickingTiles.forEach(ref -> { + action.accept( + ref, + TileLogicRegistry.getInstance().get(ref.get().getId()) + ); + }); + } + + public TickChunk getTickTask() { + return tickTask; + } + + private class TileLogicStackImpl extends AbstractList implements TileLogicStack { + private class TileLogicReferenceImpl implements TileLogicReference { + private final TileDataReference parent; + + public TileLogicReferenceImpl (TileDataReference parent) { + this.parent = parent; + } + + @Override + public TileDataReference getDataReference() { + return parent; + } + + @Override + public TileLogic get() { + return TileLogicRegistry.getInstance().get(parent.get().getId()); + } + + @Override + public int getIndex() { + return parent.getIndex(); + } + + @Override + public TileLogicStack getStack() { + return TileLogicStackImpl.this; + } + } + + private final TileDataStack parent; + + public TileLogicStackImpl(TileDataStack parent) { + this.parent = parent; + } + + @Override + public Vec3i getBlockInChunk(Vec3i output) { + return parent.getBlockInChunk(output); + } + + @Override + public DefaultChunkLogic getChunk() { + return DefaultChunkLogic.this; + } + + @Override + public RelFace getFace() { + return parent.getFace(); + } + + @Override + public TileLogicReference getReference(int index) { + return new TileLogicReferenceImpl(parent.getReference(index)); + } + + @Override + public int getIndexByTag(int tag) { + return parent.getIndexByTag(tag); + } + + @Override + public int getTagByIndex(int index) { + return parent.getTagByIndex(index); + } + + @Override + public TileLogic get(int index) { + return TileLogicRegistry.getInstance().get(parent.get(index).getId()); + } + + @Override + public int size() { + return parent.size(); + } + + @Override + public TileDataStack getData() { + return parent; + } + + } + + private void tmp_generateTickLists() { + ChunkTickContext context = TickContextMutable.start().withChunk(this).build(); + + context.forEachBlock(bctxt -> { + BlockLogic block = bctxt.getBlock(); + + if (!(block instanceof TickableBlock)) + return; + + if (((TickableBlock) block).getTickingPolicy(bctxt) == TickingPolicy.REGULAR) { + tickingBlocks.add(Coordinates.convertInWorldToInChunk(bctxt.getBlockInWorld(), null)); + } + + bctxt.forEachFace(fctxt -> fctxt.forEachTile(tctxt -> { + TileLogic tile = tctxt.getTile(); + + if (!(tile instanceof TickableTile)) + return; + + if (((TickableTile) tile).getTickingPolicy(tctxt) == TickingPolicy.REGULAR) { + tickingTiles.add(tctxt.getReference()); + } + })); + }); + } + +} diff --git a/src/main/java/ru/windcorp/progressia/server/world/DefaultWorldLogic.java b/src/main/java/ru/windcorp/progressia/server/world/DefaultWorldLogic.java new file mode 100644 index 0000000..e38559d --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/server/world/DefaultWorldLogic.java @@ -0,0 +1,146 @@ +/* + * 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.server.world; + +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; + +import glm.Glm; +import glm.vec._3.i.Vec3i; +import ru.windcorp.progressia.common.util.crash.CrashReports; +import ru.windcorp.progressia.common.world.DefaultChunkData; +import ru.windcorp.progressia.common.world.ChunkDataListeners; +import ru.windcorp.progressia.common.world.DefaultWorldData; +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.tasks.TickEntitiesTask; +import ru.windcorp.progressia.server.world.ticking.Evaluation; + +public class DefaultWorldLogic implements WorldLogic { + + private final DefaultWorldData data; + private final Server server; + + private final WorldGenerator generator; + + private final Map chunks = new HashMap<>(); + + private final Evaluation tickEntitiesTask = new TickEntitiesTask(); + + public DefaultWorldLogic(DefaultWorldData data, Server server, WorldGenerator generator) { + this.data = data; + this.server = server; + + this.generator = generator; + data.setGravityModel(getGenerator().getGravityModel()); + + data.addListener(new WorldDataListener() { + @Override + public void onChunkLoaded(DefaultWorldData world, DefaultChunkData chunk) { + chunks.put(chunk, new DefaultChunkLogic(DefaultWorldLogic.this, chunk)); + } + + @Override + public void beforeChunkUnloaded(DefaultWorldData world, DefaultChunkData chunk) { + chunks.remove(chunk); + } + }); + + data.addListener(ChunkDataListeners.createAdder(new UpdateTriggerer(server))); + } + + @Override + public DefaultChunkLogic getChunk(Vec3i pos) { + return chunks.get(getData().getChunk(pos)); + } + + @Override + public Collection getChunks() { + return chunks.values(); + } + + @Override + public Collection getEntities() { + return getData().getEntities(); + } + + @Override + public EntityData getEntity(long entityId) { + return getData().getEntity(entityId); + } + + public Evaluation getTickEntitiesTask() { + return tickEntitiesTask; + } + + public Server getServer() { + return server; + } + + public DefaultWorldData getData() { + return data; + } + + public WorldGenerator getGenerator() { + return generator; + } + + public DefaultChunkData generate(Vec3i chunkPos) { + DefaultChunkData 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 DefaultChunkLogic getChunk(DefaultChunkData chunkData) { + return chunks.get(chunkData); + } + +} diff --git a/src/main/java/ru/windcorp/progressia/server/world/TickAndUpdateUtil.java b/src/main/java/ru/windcorp/progressia/server/world/TickAndUpdateUtil.java index 9f8f265..fd3e0ec 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/TickAndUpdateUtil.java +++ b/src/main/java/ru/windcorp/progressia/server/world/TickAndUpdateUtil.java @@ -44,7 +44,7 @@ public class TickAndUpdateUtil { } } - public static void tickBlock(WorldLogic world, Vec3i blockInWorld) { + public static void tickBlock(DefaultWorldLogic world, Vec3i blockInWorld) { BlockLogic block = world.getBlock(blockInWorld); if (!(block instanceof TickableBlock)) return; // also checks nulls @@ -61,7 +61,7 @@ public class TickAndUpdateUtil { } } - public static void tickTile(WorldLogic world, Vec3i blockInWorld, BlockFace face, int layer) { + public static void tickTile(DefaultWorldLogic world, Vec3i blockInWorld, BlockFace face, int layer) { TileLogic tile = world.getTile(blockInWorld, face, layer); if (!(tile instanceof TickableTile)) { return; @@ -72,7 +72,7 @@ public class TickAndUpdateUtil { tickTile((TickableTile) tile, tickContext); } - public static void tickTiles(WorldLogic world, Vec3i blockInWorld, BlockFace face) { + public static void tickTiles(DefaultWorldLogic world, Vec3i blockInWorld, BlockFace face) { if (!world.isBlockLoaded(blockInWorld)) { return; } @@ -94,7 +94,7 @@ public class TickAndUpdateUtil { } } - public static void updateBlock(WorldLogic world, Vec3i blockInWorld) { + public static void updateBlock(DefaultWorldLogic world, Vec3i blockInWorld) { BlockLogic block = world.getBlock(blockInWorld); if (!(block instanceof UpdateableBlock)) return; // also checks nulls @@ -111,7 +111,7 @@ public class TickAndUpdateUtil { } } - public static void updateTile(WorldLogic world, Vec3i blockInWorld, BlockFace face, int layer) { + public static void updateTile(DefaultWorldLogic world, Vec3i blockInWorld, BlockFace face, int layer) { TileLogic tile = world.getTile(blockInWorld, face, layer); if (!(tile instanceof UpdateableTile)) { return; @@ -122,7 +122,7 @@ public class TickAndUpdateUtil { updateTile((UpdateableTile) tile, tickContext); } - public static void updateTiles(WorldLogic world, Vec3i blockInWorld, BlockFace face) { + public static void updateTiles(DefaultWorldLogic world, Vec3i blockInWorld, BlockFace face) { if (!world.isBlockLoaded(blockInWorld)) { return; } diff --git a/src/main/java/ru/windcorp/progressia/server/world/TickContext.java b/src/main/java/ru/windcorp/progressia/server/world/TickContext.java index 9d59699..5d92f4a 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/TickContext.java +++ b/src/main/java/ru/windcorp/progressia/server/world/TickContext.java @@ -30,7 +30,7 @@ public interface TickContext { Server getServer(); - default WorldLogic getWorld() { + default DefaultWorldLogic getWorld() { return getServer().getWorld(); } diff --git a/src/main/java/ru/windcorp/progressia/server/world/TickContextMutable.java b/src/main/java/ru/windcorp/progressia/server/world/TickContextMutable.java index d8ba535..a5eb592 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/TickContextMutable.java +++ b/src/main/java/ru/windcorp/progressia/server/world/TickContextMutable.java @@ -93,12 +93,12 @@ public abstract class TickContextMutable implements BlockTickContext, TSTickCont public static interface Empty /* does not extend Builder */ { World withServer(Server server); - default Builder.World withWorld(WorldLogic world) { + default Builder.World withWorld(DefaultWorldLogic world) { Objects.requireNonNull(world, "world"); return withServer(world.getServer()); } - default Builder.Chunk withChunk(ChunkLogic chunk) { + default Builder.Chunk withChunk(DefaultChunkLogic chunk) { Objects.requireNonNull(chunk, "chunk"); return withWorld(chunk.getWorld()).withChunk(chunk.getPosition()); } diff --git a/src/main/java/ru/windcorp/progressia/server/world/TileLogicReference.java b/src/main/java/ru/windcorp/progressia/server/world/TileLogicReference.java new file mode 100644 index 0000000..e56cffb --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/server/world/TileLogicReference.java @@ -0,0 +1,44 @@ +/* + * 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.server.world; + +import ru.windcorp.progressia.common.world.TileDataReference; +import ru.windcorp.progressia.common.world.generic.TileGenericReferenceRO; +import ru.windcorp.progressia.common.world.tile.TileData; +import ru.windcorp.progressia.server.world.tile.TileLogic; + +/** + * A read-only {@link TileGenericReferenceRO TileReference} for a + * {@link TileData} that provides convenient read-write access to the matching + * {@link TileLogic} instance. + *

    + * For all methods other than {@link #get()}, {@link #getStack()} and + * {@link #getDataReference()}, + * logicRef.method() == logicRef.getDataReference().method(). + */ +public interface TileLogicReference + extends TileLogicReferenceRO { + + /* + * Override return type + */ + + @Override + TileDataReference getDataReference(); + +} diff --git a/src/main/java/ru/windcorp/progressia/server/world/TileLogicReferenceRO.java b/src/main/java/ru/windcorp/progressia/server/world/TileLogicReferenceRO.java new file mode 100644 index 0000000..2a92764 --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/server/world/TileLogicReferenceRO.java @@ -0,0 +1,82 @@ +/* + * 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.server.world; + +import ru.windcorp.progressia.common.world.TileDataReference; +import ru.windcorp.progressia.common.world.TileDataReferenceRO; +import ru.windcorp.progressia.common.world.generic.TileGenericReferenceRO; +import ru.windcorp.progressia.common.world.tile.TileData; +import ru.windcorp.progressia.server.world.block.BlockLogic; +import ru.windcorp.progressia.server.world.tile.TileLogic; + +/** + * A {@link TileGenericReferenceRO TileReference} for a {@link TileData} that + * provides convenient access to the matching {@link TileLogic} instance. + *

    + * For all methods other than {@link #get()}, {@link #getStack()} and + * {@link #getDataReference()}, + * logicRef.method() == logicRef.getDataReference().method(). + */ +public interface TileLogicReferenceRO + extends TileGenericReferenceRO { + + /** + * Returns a reference to the {@link TileData} that this object references. + * + * @return a {@link TileDataReference} equivalent to this object + */ + TileDataReferenceRO getDataReference(); + + /** + * Returns the {@link TileData} that is referenced by this object, or + * {@code null} if the tile does not exist. + * + * @return the relevant {@link TileData} + */ + default TileData getData() { + return getDataReference().get(); + } + + /** + * {@inheritDoc} + * + * @see #getData() + */ + @Override + TileLogic get(); + + /* + * Refer to #getDataReference() by default + */ + + @Override + default int getIndex() { + return getDataReference().getIndex(); + } + + @Override + default int getTag() { + return getDataReference().getTag(); + } + + @Override + default boolean isValid() { + return getDataReference().isValid(); + } + +} diff --git a/src/main/java/ru/windcorp/progressia/server/world/TileLogicStack.java b/src/main/java/ru/windcorp/progressia/server/world/TileLogicStack.java new file mode 100644 index 0000000..3b8ef2f --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/server/world/TileLogicStack.java @@ -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 . + */ +package ru.windcorp.progressia.server.world; + +import ru.windcorp.progressia.common.world.TileDataStack; + +public interface TileLogicStack extends TileLogicStackRO { + + /* + * Override return types + */ + + @Override + TileDataStack getData(); + + @Override + ChunkLogic getChunk(); + + @Override + TileLogicReference getReference(int index); + +} diff --git a/src/main/java/ru/windcorp/progressia/server/world/tile/TileLogicStack.java b/src/main/java/ru/windcorp/progressia/server/world/TileLogicStackRO.java similarity index 67% rename from src/main/java/ru/windcorp/progressia/server/world/tile/TileLogicStack.java rename to src/main/java/ru/windcorp/progressia/server/world/TileLogicStackRO.java index 83d7d9a..3561663 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/tile/TileLogicStack.java +++ b/src/main/java/ru/windcorp/progressia/server/world/TileLogicStackRO.java @@ -15,20 +15,17 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - -package ru.windcorp.progressia.server.world.tile; -import java.util.AbstractList; +package ru.windcorp.progressia.server.world; -import ru.windcorp.progressia.common.world.TileDataStack; +import ru.windcorp.progressia.common.world.TileDataStackRO; import ru.windcorp.progressia.common.world.generic.TileGenericStackRO; -import ru.windcorp.progressia.server.world.ChunkLogic; import ru.windcorp.progressia.server.world.block.BlockLogic; +import ru.windcorp.progressia.server.world.tile.TileLogic; -public abstract class TileLogicStack - extends AbstractList - implements TileGenericStackRO { +public interface TileLogicStackRO + extends TileGenericStackRO { - public abstract TileDataStack getData(); + public abstract TileDataStackRO getData(); } diff --git a/src/main/java/ru/windcorp/progressia/server/world/WorldLogic.java b/src/main/java/ru/windcorp/progressia/server/world/WorldLogic.java index 7028573..0995ce4 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/WorldLogic.java +++ b/src/main/java/ru/windcorp/progressia/server/world/WorldLogic.java @@ -15,140 +15,38 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - package ru.windcorp.progressia.server.world; import java.util.Collection; -import java.util.HashMap; -import java.util.Map; -import glm.Glm; import glm.vec._3.i.Vec3i; -import ru.windcorp.progressia.common.util.crash.CrashReports; -import ru.windcorp.progressia.common.world.DefaultChunkData; -import ru.windcorp.progressia.common.world.ChunkDataListeners; -import ru.windcorp.progressia.common.world.DefaultWorldData; -import ru.windcorp.progressia.common.world.WorldDataListener; -import ru.windcorp.progressia.common.world.entity.EntityData; -import ru.windcorp.progressia.common.world.generic.WorldGenericRO; -import ru.windcorp.progressia.server.Server; -import ru.windcorp.progressia.server.world.block.BlockLogic; -import ru.windcorp.progressia.server.world.generation.WorldGenerator; -import ru.windcorp.progressia.server.world.tasks.TickEntitiesTask; -import ru.windcorp.progressia.server.world.ticking.Evaluation; -import ru.windcorp.progressia.server.world.tile.TileLogic; -import ru.windcorp.progressia.server.world.tile.TileLogicReference; -import ru.windcorp.progressia.server.world.tile.TileLogicStack; +import ru.windcorp.progressia.common.world.rels.BlockFace; -public class WorldLogic - implements WorldGenericRO { +public interface WorldLogic extends WorldLogicRO { - private final DefaultWorldData data; - private final Server server; + /* + * Override return types + */ - private final WorldGenerator generator; + @Override + ChunkLogic getChunk(Vec3i pos); - private final Map chunks = new HashMap<>(); + @Override + Collection getChunks(); - private final Evaluation tickEntitiesTask = new TickEntitiesTask(); - - public WorldLogic(DefaultWorldData data, Server server, WorldGenerator generator) { - this.data = data; - this.server = server; - - this.generator = generator; - data.setGravityModel(getGenerator().getGravityModel()); - - data.addListener(new WorldDataListener() { - @Override - public void onChunkLoaded(DefaultWorldData world, DefaultChunkData chunk) { - chunks.put(chunk, new ChunkLogic(WorldLogic.this, chunk)); - } - - @Override - public void beforeChunkUnloaded(DefaultWorldData world, DefaultChunkData chunk) { - chunks.remove(chunk); - } - }); - - data.addListener(ChunkDataListeners.createAdder(new UpdateTriggerer(server))); + @Override + default ChunkLogic getChunkByBlock(Vec3i blockInWorld) { + return (ChunkLogic) WorldLogicRO.super.getChunkByBlock(blockInWorld); } @Override - public ChunkLogic getChunk(Vec3i pos) { - return chunks.get(getData().getChunk(pos)); + default TileLogicStack getTiles(Vec3i blockInWorld, BlockFace face) { + return (TileLogicStack) WorldLogicRO.super.getTiles(blockInWorld, face); } @Override - public Collection getChunks() { - return chunks.values(); - } - - @Override - public Collection getEntities() { - return getData().getEntities(); - } - - @Override - public EntityData getEntity(long entityId) { - return getData().getEntity(entityId); - } - - public Evaluation getTickEntitiesTask() { - return tickEntitiesTask; - } - - public Server getServer() { - return server; - } - - public DefaultWorldData getData() { - return data; - } - - public WorldGenerator getGenerator() { - return generator; - } - - public DefaultChunkData generate(Vec3i chunkPos) { - DefaultChunkData 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(DefaultChunkData chunkData) { - return chunks.get(chunkData); + default TileLogicStack getTilesOrNull(Vec3i blockInWorld, BlockFace face) { + return (TileLogicStack) WorldLogicRO.super.getTilesOrNull(blockInWorld, face); } } diff --git a/src/main/java/ru/windcorp/progressia/server/world/tile/TileLogicReference.java b/src/main/java/ru/windcorp/progressia/server/world/WorldLogicRO.java similarity index 67% rename from src/main/java/ru/windcorp/progressia/server/world/tile/TileLogicReference.java rename to src/main/java/ru/windcorp/progressia/server/world/WorldLogicRO.java index 36d4c2d..1fc1549 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/tile/TileLogicReference.java +++ b/src/main/java/ru/windcorp/progressia/server/world/WorldLogicRO.java @@ -15,13 +15,14 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ -package ru.windcorp.progressia.server.world.tile; +package ru.windcorp.progressia.server.world; -import ru.windcorp.progressia.common.world.generic.TileGenericReferenceRO; -import ru.windcorp.progressia.server.world.ChunkLogic; +import ru.windcorp.progressia.common.world.entity.EntityData; +import ru.windcorp.progressia.common.world.generic.WorldGenericRO; import ru.windcorp.progressia.server.world.block.BlockLogic; +import ru.windcorp.progressia.server.world.tile.TileLogic; -public interface TileLogicReference - extends TileGenericReferenceRO { +public interface WorldLogicRO + extends WorldGenericRO { } diff --git a/src/main/java/ru/windcorp/progressia/server/world/context/ServerWorldContext.java b/src/main/java/ru/windcorp/progressia/server/world/context/ServerWorldContext.java new file mode 100644 index 0000000..1b281c9 --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/server/world/context/ServerWorldContext.java @@ -0,0 +1,35 @@ +/* + * 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.server.world.context; + +import ru.windcorp.progressia.common.world.WorldData; +import ru.windcorp.progressia.server.world.WorldLogic; + +public interface ServerWorldContext extends WorldData, ServerWorldContextRO { + + public interface Logic extends ServerWorldContextRO.Logic, WorldLogic { + + @Override + ServerWorldContext data(); + + } + + @Override + ServerWorldContext.Logic logic(); + +} \ No newline at end of file diff --git a/src/main/java/ru/windcorp/progressia/server/world/context/ServerWorldContextRO.java b/src/main/java/ru/windcorp/progressia/server/world/context/ServerWorldContextRO.java new file mode 100644 index 0000000..7672a12 --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/server/world/context/ServerWorldContextRO.java @@ -0,0 +1,16 @@ +package ru.windcorp.progressia.server.world.context; + +import ru.windcorp.progressia.common.world.WorldDataRO; +import ru.windcorp.progressia.server.world.WorldLogicRO; + +public interface ServerWorldContextRO extends WorldDataRO, ServerContext { + + public interface Logic extends WorldLogicRO { + + ServerWorldContextRO data(); + + } + + ServerWorldContextRO.Logic logic(); + +} 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 bd244a0..d52e6a2 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 @@ -29,7 +29,7 @@ import ru.windcorp.progressia.common.world.GravityModel; import ru.windcorp.progressia.common.world.GravityModelRegistry; import ru.windcorp.progressia.common.world.DefaultWorldData; import ru.windcorp.progressia.server.Server; -import ru.windcorp.progressia.server.world.WorldLogic; +import ru.windcorp.progressia.server.world.DefaultWorldLogic; public abstract class AbstractWorldGenerator extends WorldGenerator { @@ -90,7 +90,7 @@ public abstract class AbstractWorldGenerator extends WorldGenerator { } @Override - public WorldLogic getWorldLogic() { + public DefaultWorldLogic getWorldLogic() { return server.getWorld(); } diff --git a/src/main/java/ru/windcorp/progressia/server/world/generation/WorldGenerator.java b/src/main/java/ru/windcorp/progressia/server/world/generation/WorldGenerator.java index a7c9753..05dc4ea 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/generation/WorldGenerator.java +++ b/src/main/java/ru/windcorp/progressia/server/world/generation/WorldGenerator.java @@ -30,7 +30,7 @@ import ru.windcorp.progressia.common.world.DecodingException; import ru.windcorp.progressia.common.world.GravityModel; import ru.windcorp.progressia.common.world.DefaultWorldData; import ru.windcorp.progressia.server.Server; -import ru.windcorp.progressia.server.world.WorldLogic; +import ru.windcorp.progressia.server.world.DefaultWorldLogic; public abstract class WorldGenerator extends Namespaced { @@ -52,7 +52,7 @@ public abstract class WorldGenerator extends Namespaced { public abstract Vec3 suggestSpawnLocation(); public abstract Server getServer(); - public abstract WorldLogic getWorldLogic(); + public abstract DefaultWorldLogic getWorldLogic(); public abstract DefaultWorldData getWorldData(); } diff --git a/src/main/java/ru/windcorp/progressia/server/world/tasks/BlockTriggeredUpdate.java b/src/main/java/ru/windcorp/progressia/server/world/tasks/BlockTriggeredUpdate.java index 5ddd08f..120cd22 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/tasks/BlockTriggeredUpdate.java +++ b/src/main/java/ru/windcorp/progressia/server/world/tasks/BlockTriggeredUpdate.java @@ -25,7 +25,7 @@ import ru.windcorp.progressia.common.world.Coordinates; import ru.windcorp.progressia.common.world.rels.AbsFace; import ru.windcorp.progressia.server.Server; import ru.windcorp.progressia.server.world.TickAndUpdateUtil; -import ru.windcorp.progressia.server.world.WorldLogic; +import ru.windcorp.progressia.server.world.DefaultWorldLogic; class BlockTriggeredUpdate extends CachedEvaluation { @@ -39,7 +39,7 @@ class BlockTriggeredUpdate extends CachedEvaluation { public void evaluate(Server server) { Vec3i cursor = new Vec3i(blockInWorld.x, blockInWorld.y, blockInWorld.z); - WorldLogic world = server.getWorld(); + DefaultWorldLogic world = server.getWorld(); for (AbsFace face : AbsFace.getFaces()) { TickAndUpdateUtil.updateTiles(world, cursor, face); diff --git a/src/main/java/ru/windcorp/progressia/server/world/tasks/TickChunk.java b/src/main/java/ru/windcorp/progressia/server/world/tasks/TickChunk.java index df92442..336f166 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/tasks/TickChunk.java +++ b/src/main/java/ru/windcorp/progressia/server/world/tasks/TickChunk.java @@ -31,7 +31,7 @@ import ru.windcorp.progressia.common.world.DefaultChunkData; import ru.windcorp.progressia.common.world.rels.AbsFace; import ru.windcorp.progressia.common.world.TileDataStack; import ru.windcorp.progressia.server.Server; -import ru.windcorp.progressia.server.world.ChunkLogic; +import ru.windcorp.progressia.server.world.DefaultChunkLogic; import ru.windcorp.progressia.server.world.TickContextMutable; import ru.windcorp.progressia.server.world.block.BlockLogic; import ru.windcorp.progressia.server.world.block.TickableBlock; @@ -61,9 +61,9 @@ public class TickChunk extends Evaluation { this.randomTickMethods = ImmutableList.copyOf(randomTickMethods); } - private final ChunkLogic chunk; + private final DefaultChunkLogic chunk; - public TickChunk(ChunkLogic chunk) { + public TickChunk(DefaultChunkLogic chunk) { this.chunk = chunk; } diff --git a/src/main/java/ru/windcorp/progressia/server/world/tasks/TileTriggeredUpdate.java b/src/main/java/ru/windcorp/progressia/server/world/tasks/TileTriggeredUpdate.java index bb9d480..66e95a1 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/tasks/TileTriggeredUpdate.java +++ b/src/main/java/ru/windcorp/progressia/server/world/tasks/TileTriggeredUpdate.java @@ -25,7 +25,7 @@ import ru.windcorp.progressia.common.world.Coordinates; import ru.windcorp.progressia.common.world.rels.AbsFace; import ru.windcorp.progressia.server.Server; import ru.windcorp.progressia.server.world.TickAndUpdateUtil; -import ru.windcorp.progressia.server.world.WorldLogic; +import ru.windcorp.progressia.server.world.DefaultWorldLogic; class TileTriggeredUpdate extends CachedEvaluation { @@ -40,7 +40,7 @@ class TileTriggeredUpdate extends CachedEvaluation { public void evaluate(Server server) { Vec3i cursor = new Vec3i(blockInWorld.x, blockInWorld.y, blockInWorld.z); - WorldLogic world = server.getWorld(); + DefaultWorldLogic world = server.getWorld(); TickAndUpdateUtil.updateTiles(world, cursor, face); // Update facemates // (also self) diff --git a/src/main/java/ru/windcorp/progressia/server/world/tile/TSTickContext.java b/src/main/java/ru/windcorp/progressia/server/world/tile/TSTickContext.java index 4272919..d805607 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/tile/TSTickContext.java +++ b/src/main/java/ru/windcorp/progressia/server/world/tile/TSTickContext.java @@ -25,8 +25,9 @@ import java.util.function.Function; import ru.windcorp.progressia.common.world.DefaultChunkData; import ru.windcorp.progressia.common.world.rels.RelFace; import ru.windcorp.progressia.common.world.TileDataStack; -import ru.windcorp.progressia.server.world.ChunkLogic; +import ru.windcorp.progressia.server.world.DefaultChunkLogic; import ru.windcorp.progressia.server.world.TickContextMutable; +import ru.windcorp.progressia.server.world.TileLogicStackRO; import ru.windcorp.progressia.server.world.block.BlockTickContext; public interface TSTickContext extends BlockTickContext { @@ -41,15 +42,15 @@ public interface TSTickContext extends BlockTickContext { * Getters */ - default TileLogicStack getTLSOrNull() { - ChunkLogic chunkLogic = getChunkLogic(); + default TileLogicStackRO getTLSOrNull() { + DefaultChunkLogic chunkLogic = getChunkLogic(); if (chunkLogic == null) return null; return chunkLogic.getTilesOrNull(getBlockInChunk(), getFace()); } - default TileLogicStack getTLS() { + default TileLogicStackRO getTLS() { return getChunkLogic().getTiles(getBlockInChunk(), getFace()); } diff --git a/src/main/java/ru/windcorp/progressia/server/world/tile/TileTickContext.java b/src/main/java/ru/windcorp/progressia/server/world/tile/TileTickContext.java index c3003d8..597291a 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/tile/TileTickContext.java +++ b/src/main/java/ru/windcorp/progressia/server/world/tile/TileTickContext.java @@ -19,6 +19,7 @@ package ru.windcorp.progressia.server.world.tile; import ru.windcorp.progressia.common.world.tile.TileData; +import ru.windcorp.progressia.server.world.TileLogicStackRO; import ru.windcorp.progressia.common.world.TileDataStack; import ru.windcorp.progressia.common.world.TileDataReference; @@ -40,7 +41,7 @@ public interface TileTickContext extends TSTickContext { */ default TileLogic getTile() { - TileLogicStack stack = getTLSOrNull(); + TileLogicStackRO stack = getTLSOrNull(); if (stack == null) return null; return stack.get(getLayer()); diff --git a/src/main/java/ru/windcorp/progressia/test/gen/TestTerrainGenerator.java b/src/main/java/ru/windcorp/progressia/test/gen/TestTerrainGenerator.java index c4f5ec7..8112105 100644 --- a/src/main/java/ru/windcorp/progressia/test/gen/TestTerrainGenerator.java +++ b/src/main/java/ru/windcorp/progressia/test/gen/TestTerrainGenerator.java @@ -19,7 +19,7 @@ package ru.windcorp.progressia.test.gen; import kdotjpg.opensimplex2.areagen.OpenSimplex2S; -import ru.windcorp.progressia.server.world.WorldLogic; +import ru.windcorp.progressia.server.world.DefaultWorldLogic; class TestTerrainGenerator { @@ -31,7 +31,7 @@ class TestTerrainGenerator { private final OpenSimplex2S noise; private final Func2D shape; - public TestTerrainGenerator(TestWorldGenerator testWorldGenerator, WorldLogic world) { + public TestTerrainGenerator(TestWorldGenerator testWorldGenerator, DefaultWorldLogic world) { this.noise = new OpenSimplex2S("We're getting somewhere".hashCode()); Func2D plainsHeight = tweak( From 1ee9a55d19d6be50bda073c5b5f4d4b437faf2ba Mon Sep 17 00:00:00 2001 From: OLEGSHA Date: Sat, 31 Jul 2021 20:47:23 +0300 Subject: [PATCH 33/55] Defined Data and Server context interfaces Server read-write (not RO) interfaces do not extend the complimentary *GenericContextWO interfaces by design. It makes no sense to set a BlockLogic, but it makes plenty of sense to refer to a ChunkData rather than a ChunkDataRO. --- .../world/context/BlockDataContext.java | 35 ++++++++++++++++ .../world/context/BlockDataContextRO.java | 34 +++++++++++++++ .../world/context/BlockFaceDataContext.java | 35 ++++++++++++++++ .../world/context/BlockFaceDataContextRO.java | 34 +++++++++++++++ .../common/world/context/TileDataContext.java | 35 ++++++++++++++++ .../world/context/TileDataContextRO.java | 34 +++++++++++++++ .../world/context/WorldDataContext.java | 36 ++++++++++++++++ .../world/context/WorldDataContextRO.java | 36 ++++++++++++++++ .../world/context/ServerBlockContext.java | 41 ++++++++++++++++++ .../world/context/ServerBlockContextRO.java | 42 +++++++++++++++++++ .../world/context/ServerBlockFaceContext.java | 40 ++++++++++++++++++ .../context/ServerBlockFaceContextRO.java | 42 +++++++++++++++++++ .../world/context/ServerTileContext.java | 40 ++++++++++++++++++ .../world/context/ServerTileContextRO.java | 42 +++++++++++++++++++ .../world/context/ServerWorldContext.java | 21 ++++++---- .../world/context/ServerWorldContextRO.java | 31 ++++++++++++-- 16 files changed, 568 insertions(+), 10 deletions(-) create mode 100644 src/main/java/ru/windcorp/progressia/common/world/context/BlockDataContext.java create mode 100644 src/main/java/ru/windcorp/progressia/common/world/context/BlockDataContextRO.java create mode 100644 src/main/java/ru/windcorp/progressia/common/world/context/BlockFaceDataContext.java create mode 100644 src/main/java/ru/windcorp/progressia/common/world/context/BlockFaceDataContextRO.java create mode 100644 src/main/java/ru/windcorp/progressia/common/world/context/TileDataContext.java create mode 100644 src/main/java/ru/windcorp/progressia/common/world/context/TileDataContextRO.java create mode 100644 src/main/java/ru/windcorp/progressia/common/world/context/WorldDataContext.java create mode 100644 src/main/java/ru/windcorp/progressia/common/world/context/WorldDataContextRO.java create mode 100644 src/main/java/ru/windcorp/progressia/server/world/context/ServerBlockContext.java create mode 100644 src/main/java/ru/windcorp/progressia/server/world/context/ServerBlockContextRO.java create mode 100644 src/main/java/ru/windcorp/progressia/server/world/context/ServerBlockFaceContext.java create mode 100644 src/main/java/ru/windcorp/progressia/server/world/context/ServerBlockFaceContextRO.java create mode 100644 src/main/java/ru/windcorp/progressia/server/world/context/ServerTileContext.java create mode 100644 src/main/java/ru/windcorp/progressia/server/world/context/ServerTileContextRO.java diff --git a/src/main/java/ru/windcorp/progressia/common/world/context/BlockDataContext.java b/src/main/java/ru/windcorp/progressia/common/world/context/BlockDataContext.java new file mode 100644 index 0000000..4ebb85a --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/common/world/context/BlockDataContext.java @@ -0,0 +1,35 @@ +/* + * 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.common.world.context; + +import ru.windcorp.progressia.common.world.ChunkData; +import ru.windcorp.progressia.common.world.TileDataReference; +import ru.windcorp.progressia.common.world.TileDataStack; +import ru.windcorp.progressia.common.world.block.BlockData; +import ru.windcorp.progressia.common.world.entity.EntityData; +import ru.windcorp.progressia.common.world.generic.context.BlockGenericContextWO; +import ru.windcorp.progressia.common.world.tile.TileData; + +public interface BlockDataContext + extends BlockGenericContextWO, + WorldDataContext, + BlockDataContextRO { + + // currently empty + +} diff --git a/src/main/java/ru/windcorp/progressia/common/world/context/BlockDataContextRO.java b/src/main/java/ru/windcorp/progressia/common/world/context/BlockDataContextRO.java new file mode 100644 index 0000000..f910fa1 --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/common/world/context/BlockDataContextRO.java @@ -0,0 +1,34 @@ +/* + * 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.common.world.context; + +import ru.windcorp.progressia.common.world.ChunkDataRO; +import ru.windcorp.progressia.common.world.TileDataReferenceRO; +import ru.windcorp.progressia.common.world.TileDataStackRO; +import ru.windcorp.progressia.common.world.block.BlockData; +import ru.windcorp.progressia.common.world.entity.EntityData; +import ru.windcorp.progressia.common.world.generic.context.BlockGenericContextRO; +import ru.windcorp.progressia.common.world.tile.TileData; + +public interface BlockDataContextRO + extends BlockGenericContextRO, + WorldDataContextRO { + + // currently empty + +} diff --git a/src/main/java/ru/windcorp/progressia/common/world/context/BlockFaceDataContext.java b/src/main/java/ru/windcorp/progressia/common/world/context/BlockFaceDataContext.java new file mode 100644 index 0000000..45ce045 --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/common/world/context/BlockFaceDataContext.java @@ -0,0 +1,35 @@ +/* + * 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.common.world.context; + +import ru.windcorp.progressia.common.world.ChunkData; +import ru.windcorp.progressia.common.world.TileDataReference; +import ru.windcorp.progressia.common.world.TileDataStack; +import ru.windcorp.progressia.common.world.block.BlockData; +import ru.windcorp.progressia.common.world.entity.EntityData; +import ru.windcorp.progressia.common.world.generic.context.BlockFaceGenericContextWO; +import ru.windcorp.progressia.common.world.tile.TileData; + +public interface BlockFaceDataContext + extends BlockFaceGenericContextWO, + BlockDataContext, + BlockFaceDataContextRO { + + // currently empty + +} diff --git a/src/main/java/ru/windcorp/progressia/common/world/context/BlockFaceDataContextRO.java b/src/main/java/ru/windcorp/progressia/common/world/context/BlockFaceDataContextRO.java new file mode 100644 index 0000000..ddf7089 --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/common/world/context/BlockFaceDataContextRO.java @@ -0,0 +1,34 @@ +/* + * 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.common.world.context; + +import ru.windcorp.progressia.common.world.ChunkDataRO; +import ru.windcorp.progressia.common.world.TileDataReferenceRO; +import ru.windcorp.progressia.common.world.TileDataStackRO; +import ru.windcorp.progressia.common.world.block.BlockData; +import ru.windcorp.progressia.common.world.entity.EntityData; +import ru.windcorp.progressia.common.world.generic.context.BlockFaceGenericContextRO; +import ru.windcorp.progressia.common.world.tile.TileData; + +public interface BlockFaceDataContextRO + extends BlockFaceGenericContextRO, + BlockDataContext { + + // currently empty + +} diff --git a/src/main/java/ru/windcorp/progressia/common/world/context/TileDataContext.java b/src/main/java/ru/windcorp/progressia/common/world/context/TileDataContext.java new file mode 100644 index 0000000..c3e1321 --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/common/world/context/TileDataContext.java @@ -0,0 +1,35 @@ +/* + * 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.common.world.context; + +import ru.windcorp.progressia.common.world.ChunkData; +import ru.windcorp.progressia.common.world.TileDataReference; +import ru.windcorp.progressia.common.world.TileDataStack; +import ru.windcorp.progressia.common.world.block.BlockData; +import ru.windcorp.progressia.common.world.entity.EntityData; +import ru.windcorp.progressia.common.world.generic.context.TileGenericContextWO; +import ru.windcorp.progressia.common.world.tile.TileData; + +public interface TileDataContext + extends TileGenericContextWO, + BlockFaceDataContext, + TileDataContextRO { + + // currently empty + +} diff --git a/src/main/java/ru/windcorp/progressia/common/world/context/TileDataContextRO.java b/src/main/java/ru/windcorp/progressia/common/world/context/TileDataContextRO.java new file mode 100644 index 0000000..b7f2b4d --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/common/world/context/TileDataContextRO.java @@ -0,0 +1,34 @@ +/* + * 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.common.world.context; + +import ru.windcorp.progressia.common.world.ChunkDataRO; +import ru.windcorp.progressia.common.world.TileDataReferenceRO; +import ru.windcorp.progressia.common.world.TileDataStackRO; +import ru.windcorp.progressia.common.world.block.BlockData; +import ru.windcorp.progressia.common.world.entity.EntityData; +import ru.windcorp.progressia.common.world.generic.context.TileGenericContextRO; +import ru.windcorp.progressia.common.world.tile.TileData; + +public interface TileDataContextRO + extends TileGenericContextRO, + BlockFaceDataContextRO { + + // currently empty + +} diff --git a/src/main/java/ru/windcorp/progressia/common/world/context/WorldDataContext.java b/src/main/java/ru/windcorp/progressia/common/world/context/WorldDataContext.java new file mode 100644 index 0000000..31dbef1 --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/common/world/context/WorldDataContext.java @@ -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 . + */ +package ru.windcorp.progressia.common.world.context; + +import ru.windcorp.progressia.common.world.ChunkData; +import ru.windcorp.progressia.common.world.TileDataReference; +import ru.windcorp.progressia.common.world.TileDataStack; +import ru.windcorp.progressia.common.world.WorldData; +import ru.windcorp.progressia.common.world.block.BlockData; +import ru.windcorp.progressia.common.world.entity.EntityData; +import ru.windcorp.progressia.common.world.generic.context.WorldGenericContextWO; +import ru.windcorp.progressia.common.world.tile.TileData; + +public interface WorldDataContext + extends WorldGenericContextWO, + WorldDataContextRO, + WorldData { + + // currently empty + +} diff --git a/src/main/java/ru/windcorp/progressia/common/world/context/WorldDataContextRO.java b/src/main/java/ru/windcorp/progressia/common/world/context/WorldDataContextRO.java new file mode 100644 index 0000000..c474ea4 --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/common/world/context/WorldDataContextRO.java @@ -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 . + */ + +package ru.windcorp.progressia.common.world.context; + +import ru.windcorp.progressia.common.world.ChunkDataRO; +import ru.windcorp.progressia.common.world.TileDataReferenceRO; +import ru.windcorp.progressia.common.world.TileDataStackRO; +import ru.windcorp.progressia.common.world.WorldDataRO; +import ru.windcorp.progressia.common.world.block.BlockData; +import ru.windcorp.progressia.common.world.entity.EntityData; +import ru.windcorp.progressia.common.world.generic.context.WorldGenericContextRO; +import ru.windcorp.progressia.common.world.tile.TileData; + +public interface WorldDataContextRO + extends WorldGenericContextRO, + WorldDataRO { + + // currently empty + +} diff --git a/src/main/java/ru/windcorp/progressia/server/world/context/ServerBlockContext.java b/src/main/java/ru/windcorp/progressia/server/world/context/ServerBlockContext.java new file mode 100644 index 0000000..a1fbbf5 --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/server/world/context/ServerBlockContext.java @@ -0,0 +1,41 @@ +/* + * 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.server.world.context; + +import ru.windcorp.progressia.common.world.context.BlockDataContext; +import ru.windcorp.progressia.common.world.rels.BlockFace; +import ru.windcorp.progressia.server.world.TileLogicStack; + +public interface ServerBlockContext extends BlockDataContext, ServerWorldContext, ServerBlockContextRO { + + public interface Logic extends ServerBlockContextRO.Logic, ServerWorldContext.Logic { + + @Override + ServerBlockContext data(); + + @Override + default TileLogicStack getTilesOrNull(BlockFace face) { + return (TileLogicStack) ServerBlockContextRO.Logic.super.getTilesOrNull(face); + } + + } + + @Override + ServerBlockContext.Logic logic(); + +} diff --git a/src/main/java/ru/windcorp/progressia/server/world/context/ServerBlockContextRO.java b/src/main/java/ru/windcorp/progressia/server/world/context/ServerBlockContextRO.java new file mode 100644 index 0000000..1ffb30d --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/server/world/context/ServerBlockContextRO.java @@ -0,0 +1,42 @@ +/* + * 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.server.world.context; + +import ru.windcorp.progressia.common.world.context.BlockDataContextRO; +import ru.windcorp.progressia.common.world.entity.EntityData; +import ru.windcorp.progressia.common.world.generic.context.BlockGenericContextRO; +import ru.windcorp.progressia.server.world.ChunkLogicRO; +import ru.windcorp.progressia.server.world.TileLogicReferenceRO; +import ru.windcorp.progressia.server.world.TileLogicStackRO; +import ru.windcorp.progressia.server.world.block.BlockLogic; +import ru.windcorp.progressia.server.world.tile.TileLogic; + +public interface ServerBlockContextRO extends ServerWorldContextRO, BlockDataContextRO { + + public interface Logic extends ServerWorldContextRO.Logic, + BlockGenericContextRO { + + @Override + ServerBlockContextRO data(); + + } + + @Override + ServerBlockContextRO.Logic logic(); + +} diff --git a/src/main/java/ru/windcorp/progressia/server/world/context/ServerBlockFaceContext.java b/src/main/java/ru/windcorp/progressia/server/world/context/ServerBlockFaceContext.java new file mode 100644 index 0000000..335e15f --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/server/world/context/ServerBlockFaceContext.java @@ -0,0 +1,40 @@ +/* + * 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.server.world.context; + +import ru.windcorp.progressia.common.world.context.BlockFaceDataContext; +import ru.windcorp.progressia.server.world.TileLogicStack; + +public interface ServerBlockFaceContext extends BlockFaceDataContext, ServerBlockContext, ServerBlockFaceContextRO { + + public interface Logic extends ServerBlockFaceContextRO.Logic, ServerBlockContext.Logic { + + @Override + ServerBlockFaceContext data(); + + @Override + default TileLogicStack getTilesOrNull() { + return (TileLogicStack) ServerBlockFaceContextRO.Logic.super.getTilesOrNull(); + } + + } + + @Override + ServerBlockFaceContext.Logic logic(); + +} diff --git a/src/main/java/ru/windcorp/progressia/server/world/context/ServerBlockFaceContextRO.java b/src/main/java/ru/windcorp/progressia/server/world/context/ServerBlockFaceContextRO.java new file mode 100644 index 0000000..7fca1db --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/server/world/context/ServerBlockFaceContextRO.java @@ -0,0 +1,42 @@ +/* + * 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.server.world.context; + +import ru.windcorp.progressia.common.world.context.BlockFaceDataContextRO; +import ru.windcorp.progressia.common.world.entity.EntityData; +import ru.windcorp.progressia.common.world.generic.context.BlockFaceGenericContextRO; +import ru.windcorp.progressia.server.world.ChunkLogicRO; +import ru.windcorp.progressia.server.world.TileLogicReferenceRO; +import ru.windcorp.progressia.server.world.TileLogicStackRO; +import ru.windcorp.progressia.server.world.block.BlockLogic; +import ru.windcorp.progressia.server.world.tile.TileLogic; + +public interface ServerBlockFaceContextRO extends ServerBlockContextRO, BlockFaceDataContextRO { + + public interface Logic extends ServerBlockContextRO.Logic, + BlockFaceGenericContextRO { + + @Override + ServerBlockFaceContextRO data(); + + } + + @Override + ServerBlockFaceContextRO.Logic logic(); + +} diff --git a/src/main/java/ru/windcorp/progressia/server/world/context/ServerTileContext.java b/src/main/java/ru/windcorp/progressia/server/world/context/ServerTileContext.java new file mode 100644 index 0000000..5d5a3c0 --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/server/world/context/ServerTileContext.java @@ -0,0 +1,40 @@ +/* + * 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.server.world.context; + +import ru.windcorp.progressia.common.world.context.TileDataContext; +import ru.windcorp.progressia.server.world.TileLogicReference; + +public interface ServerTileContext extends TileDataContext, ServerBlockFaceContext, ServerTileContextRO { + + public interface Logic extends ServerTileContextRO.Logic, ServerBlockFaceContext.Logic { + + @Override + ServerTileContext data(); + + @Override + default TileLogicReference getTileReference() { + return (TileLogicReference) ServerTileContextRO.Logic.super.getTileReference(); + } + + } + + @Override + ServerTileContext.Logic logic(); + +} diff --git a/src/main/java/ru/windcorp/progressia/server/world/context/ServerTileContextRO.java b/src/main/java/ru/windcorp/progressia/server/world/context/ServerTileContextRO.java new file mode 100644 index 0000000..73b8d2c --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/server/world/context/ServerTileContextRO.java @@ -0,0 +1,42 @@ +/* + * 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.server.world.context; + +import ru.windcorp.progressia.common.world.context.TileDataContextRO; +import ru.windcorp.progressia.common.world.entity.EntityData; +import ru.windcorp.progressia.common.world.generic.context.TileGenericContextRO; +import ru.windcorp.progressia.server.world.ChunkLogicRO; +import ru.windcorp.progressia.server.world.TileLogicReferenceRO; +import ru.windcorp.progressia.server.world.TileLogicStackRO; +import ru.windcorp.progressia.server.world.block.BlockLogic; +import ru.windcorp.progressia.server.world.tile.TileLogic; + +public interface ServerTileContextRO extends ServerBlockFaceContextRO, TileDataContextRO { + + public interface Logic extends ServerBlockFaceContextRO.Logic, + TileGenericContextRO { + + @Override + ServerTileContextRO data(); + + } + + @Override + ServerTileContextRO.Logic logic(); + +} diff --git a/src/main/java/ru/windcorp/progressia/server/world/context/ServerWorldContext.java b/src/main/java/ru/windcorp/progressia/server/world/context/ServerWorldContext.java index 1b281c9..ee04242 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/context/ServerWorldContext.java +++ b/src/main/java/ru/windcorp/progressia/server/world/context/ServerWorldContext.java @@ -17,19 +17,26 @@ */ package ru.windcorp.progressia.server.world.context; -import ru.windcorp.progressia.common.world.WorldData; +import glm.vec._3.i.Vec3i; +import ru.windcorp.progressia.common.world.context.WorldDataContext; +import ru.windcorp.progressia.common.world.rels.BlockFace; +import ru.windcorp.progressia.server.world.TileLogicStack; import ru.windcorp.progressia.server.world.WorldLogic; -public interface ServerWorldContext extends WorldData, ServerWorldContextRO { - - public interface Logic extends ServerWorldContextRO.Logic, WorldLogic { - +public interface ServerWorldContext extends WorldDataContext, ServerWorldContextRO { + + public interface Logic extends ServerWorldContextRO.Logic, + WorldLogic { + @Override ServerWorldContext data(); + @Override + TileLogicStack getTiles(Vec3i blockInWorld, BlockFace face); + } - + @Override ServerWorldContext.Logic logic(); - + } \ No newline at end of file diff --git a/src/main/java/ru/windcorp/progressia/server/world/context/ServerWorldContextRO.java b/src/main/java/ru/windcorp/progressia/server/world/context/ServerWorldContextRO.java index 7672a12..43eeedc 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/context/ServerWorldContextRO.java +++ b/src/main/java/ru/windcorp/progressia/server/world/context/ServerWorldContextRO.java @@ -1,16 +1,41 @@ package ru.windcorp.progressia.server.world.context; -import ru.windcorp.progressia.common.world.WorldDataRO; +import ru.windcorp.progressia.common.world.context.WorldDataContextRO; +import ru.windcorp.progressia.common.world.entity.EntityData; +import ru.windcorp.progressia.common.world.generic.context.WorldGenericContextRO; +import ru.windcorp.progressia.server.world.ChunkLogicRO; +import ru.windcorp.progressia.server.world.TileLogicReferenceRO; +import ru.windcorp.progressia.server.world.TileLogicStackRO; import ru.windcorp.progressia.server.world.WorldLogicRO; +import ru.windcorp.progressia.server.world.block.BlockLogic; +import ru.windcorp.progressia.server.world.tile.TileLogic; -public interface ServerWorldContextRO extends WorldDataRO, ServerContext { +public interface ServerWorldContextRO extends WorldDataContextRO, ServerContext { - public interface Logic extends WorldLogicRO { + public interface Logic + extends + WorldGenericContextRO, + WorldLogicRO, + ServerContext { + /** + * Acquires the data view of this context. Use this method to + * conveniently access data content. The returned object is linked to + * this context and operates on the same data. + * + * @return a view of this context that returns data objects + */ ServerWorldContextRO data(); } + /** + * Acquires the logic view of this context. Use this method to conveniently + * access logic content. The returned object is linked to this context and + * operates on the same data. + * + * @return a view of this context that returns appropriate logic objects + */ ServerWorldContextRO.Logic logic(); } From fbc803d6e27d911970ac15aa29a9f19c06504062 Mon Sep 17 00:00:00 2001 From: OLEGSHA Date: Wed, 4 Aug 2021 18:42:16 +0300 Subject: [PATCH 34/55] Laid some groundwork for context implementation; rewrite incoming - ReusableServerContext will be the default context implementation. It is sort of implemented, but not really - WorldLogic{,RO} now declare getData() method - WorldGenericContextWO.removeEntity(EntityGeneric) received a default implementation - TileDataContext.getTag() received a default implementation --- .../common/world/context/TileDataContext.java | 7 +- .../context/WorldGenericContextWO.java | 4 +- .../server/world/DefaultWorldLogic.java | 1 + .../progressia/server/world/WorldLogic.java | 4 + .../progressia/server/world/WorldLogicRO.java | 3 + .../context/impl/ReusableServerContext.java | 122 ++++ .../impl/ReusableServerContextBuilders.java | 87 +++ .../impl/ReusableServerContextImpl.java | 519 ++++++++++++++++++ 8 files changed, 744 insertions(+), 3 deletions(-) create mode 100644 src/main/java/ru/windcorp/progressia/server/world/context/impl/ReusableServerContext.java create mode 100644 src/main/java/ru/windcorp/progressia/server/world/context/impl/ReusableServerContextBuilders.java create mode 100644 src/main/java/ru/windcorp/progressia/server/world/context/impl/ReusableServerContextImpl.java diff --git a/src/main/java/ru/windcorp/progressia/common/world/context/TileDataContext.java b/src/main/java/ru/windcorp/progressia/common/world/context/TileDataContext.java index c3e1321..79e8d51 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/context/TileDataContext.java +++ b/src/main/java/ru/windcorp/progressia/common/world/context/TileDataContext.java @@ -29,7 +29,10 @@ public interface TileDataContext extends TileGenericContextWO, BlockFaceDataContext, TileDataContextRO { - - // currently empty + + @Override + default int getTag() { + return getTileReference().getTag(); + } } diff --git a/src/main/java/ru/windcorp/progressia/common/world/generic/context/WorldGenericContextWO.java b/src/main/java/ru/windcorp/progressia/common/world/generic/context/WorldGenericContextWO.java index ddac83d..27bbb1a 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/generic/context/WorldGenericContextWO.java +++ b/src/main/java/ru/windcorp/progressia/common/world/generic/context/WorldGenericContextWO.java @@ -140,7 +140,9 @@ public interface WorldGenericContextWO< * @see #removeEntity(long) */ @Override - void removeEntity(E entity); + default void removeEntity(E entity) { + removeEntity(entity.getEntityId()); + } /** * Requests that the specified change is applied to the given entity. The diff --git a/src/main/java/ru/windcorp/progressia/server/world/DefaultWorldLogic.java b/src/main/java/ru/windcorp/progressia/server/world/DefaultWorldLogic.java index e38559d..d578fa7 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/DefaultWorldLogic.java +++ b/src/main/java/ru/windcorp/progressia/server/world/DefaultWorldLogic.java @@ -96,6 +96,7 @@ public class DefaultWorldLogic implements WorldLogic { return server; } + @Override public DefaultWorldData getData() { return data; } diff --git a/src/main/java/ru/windcorp/progressia/server/world/WorldLogic.java b/src/main/java/ru/windcorp/progressia/server/world/WorldLogic.java index 0995ce4..f0cdb0a 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/WorldLogic.java +++ b/src/main/java/ru/windcorp/progressia/server/world/WorldLogic.java @@ -20,6 +20,7 @@ package ru.windcorp.progressia.server.world; import java.util.Collection; import glm.vec._3.i.Vec3i; +import ru.windcorp.progressia.common.world.WorldData; import ru.windcorp.progressia.common.world.rels.BlockFace; public interface WorldLogic extends WorldLogicRO { @@ -27,6 +28,9 @@ public interface WorldLogic extends WorldLogicRO { /* * Override return types */ + + @Override + WorldData getData(); @Override ChunkLogic getChunk(Vec3i pos); diff --git a/src/main/java/ru/windcorp/progressia/server/world/WorldLogicRO.java b/src/main/java/ru/windcorp/progressia/server/world/WorldLogicRO.java index 1fc1549..7f98ef9 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/WorldLogicRO.java +++ b/src/main/java/ru/windcorp/progressia/server/world/WorldLogicRO.java @@ -17,6 +17,7 @@ */ package ru.windcorp.progressia.server.world; +import ru.windcorp.progressia.common.world.WorldDataRO; import ru.windcorp.progressia.common.world.entity.EntityData; import ru.windcorp.progressia.common.world.generic.WorldGenericRO; import ru.windcorp.progressia.server.world.block.BlockLogic; @@ -24,5 +25,7 @@ import ru.windcorp.progressia.server.world.tile.TileLogic; public interface WorldLogicRO extends WorldGenericRO { + + WorldDataRO getData(); } diff --git a/src/main/java/ru/windcorp/progressia/server/world/context/impl/ReusableServerContext.java b/src/main/java/ru/windcorp/progressia/server/world/context/impl/ReusableServerContext.java new file mode 100644 index 0000000..fdffd22 --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/server/world/context/impl/ReusableServerContext.java @@ -0,0 +1,122 @@ +/* + * 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.server.world.context.impl; + +import ru.windcorp.progressia.common.world.context.Context; +import ru.windcorp.progressia.server.world.WorldLogic; +import ru.windcorp.progressia.server.world.WorldLogicRO; +import ru.windcorp.progressia.server.world.context.ServerBlockContext; +import ru.windcorp.progressia.server.world.context.ServerBlockContextRO; +import ru.windcorp.progressia.server.world.context.ServerBlockFaceContext; +import ru.windcorp.progressia.server.world.context.ServerBlockFaceContextRO; +import ru.windcorp.progressia.server.world.context.ServerContext; +import ru.windcorp.progressia.server.world.context.ServerTileContext; +import ru.windcorp.progressia.server.world.context.ServerTileContextRO; +import ru.windcorp.progressia.server.world.context.ServerWorldContext; +import ru.windcorp.progressia.server.world.context.ServerWorldContextRO; + +/** + * An implementation of the entire {@link ServerContext} tree. The objects of + * this class are designed to be highly reusable, including reusability in + * {@linkplain Context#subcontexting subcontexting}. Use this implementation + * when a {@link WorldLogic} (or a {@link WorldLogicRO}) instance requires a + * context wrapper. + *

    + * Use other unutilized instances of {@link ReusableServerContext} or + * {@link #empty()} static method to acquire a usable instance. + *

    + * This class defines the outward-facing safe interface of the actual + * implementation located in {@link ReusableServerContextImpl}. The reasoning + * for creating a subclass is to allow a single instance to implement both + * {@linkplain ReusableServerContextBuilders builder interfaces} and the context + * interface without causing confusion around object states. + * + * @author javapony + */ +public abstract class ReusableServerContext implements ServerTileContext { + + /** + * An RSC can conform to a variety of different {@link Context} interfaces. + * Each compliance mode is identified by a Role. + */ + public enum Role { + /** + * This object has not been configured yet. + */ + NONE, + /** + * This object conforms to {@link ServerWorldContext} or + * {@link ServerWorldContextRO}. + */ + WORLD, + /** + * This object conforms to {@link ServerBlockContext} or + * {@link ServerBlockContextRO}. + */ + LOCATION, + /** + * This object conforms to {@link ServerBlockFaceContext} or + * {@link ServerBlockFaceContextRO}. + */ + TILE_STACK, + /** + * This object conforms to {@link ServerTileContext} or + * {@link ServerTileContextRO}. + */ + TILE + } + + /** + * Do not extend ReusableServerContext directly. Use + * {@link ReusableServerContextImpl} if this is truly necessary. + */ + ReusableServerContext() { + // do nothing + } + + /** + * Resets this object to its uninitialized state and returns a builder to + * reinitialize it. + * + * @return a {@link ReusableServerContextBuilders.Empty} instance that may + * be used to reinitialize this object + * @throws IllegalStateException if active subcontexting is detected. + * Detection is done on a best-effort basis; + * do not rely this exception + */ + public abstract ReusableServerContextBuilders.Empty reuse() throws IllegalStateException; + + /** + * Returns the {@link Role} currently assumed by this object. + * + * @return the role + */ + public abstract Role getRole(); + + /** + * Instantiates a new {@link ReusableServerContext} using an appropriate + * implementation. + * + * @return a {@link ReusableServerContextBuilders.Empty} instance that can + * be used to initialize this object + */ + public static ReusableServerContextBuilders.Empty empty() { + return new ReusableServerContextImpl(); + } + +} diff --git a/src/main/java/ru/windcorp/progressia/server/world/context/impl/ReusableServerContextBuilders.java b/src/main/java/ru/windcorp/progressia/server/world/context/impl/ReusableServerContextBuilders.java new file mode 100644 index 0000000..349c66a --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/server/world/context/impl/ReusableServerContextBuilders.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.server.world.context.impl; + +import glm.vec._3.i.Vec3i; +import ru.windcorp.progressia.common.world.generic.TileGenericReferenceRO; +import ru.windcorp.progressia.common.world.generic.TileGenericStackRO; +import ru.windcorp.progressia.common.world.rels.BlockFace; +import ru.windcorp.progressia.common.world.rels.RelFace; +import ru.windcorp.progressia.server.Server; +import ru.windcorp.progressia.server.world.WorldLogic; + +public interface ReusableServerContextBuilders { + + ReusableServerContext build(); + + public interface Empty /* does not extend RSCB */ { + + WithWorld in(Server server, WorldLogic world); + + default WithWorld inRealWorldOf(Server server) { + return in(server, server.getWorld()); + } + + } + + public interface WithWorld extends ReusableServerContextBuilders { + + WithLocation at(Vec3i location); + + default ReusableServerContext at(TileGenericReferenceRO reference) { + if (!reference.isValid()) { + throw new IllegalArgumentException("Reference " + reference + " is invalid"); + } + + TileGenericStackRO stack = reference.getStack(); + return at(stack.getBlockInWorld(null)).on(stack.getFace()).index(reference.getIndex()); + } + + } + + public interface WithLocation extends ReusableServerContextBuilders { + + WithTileStack on(RelFace side); + WithTileStack on(BlockFace side); + + default ReusableServerContext on(TileGenericReferenceRO reference) { + if (!reference.isValid()) { + throw new IllegalArgumentException("Reference " + reference + " is invalid"); + } + + TileGenericStackRO stack = reference.getStack(); + return on(stack.getFace()).index(reference.getIndex()); + } + + } + + public interface WithTileStack extends ReusableServerContextBuilders { + + ReusableServerContext index(int index); + + default ReusableServerContext index(TileGenericReferenceRO reference) { + if (!reference.isValid()) { + throw new IllegalArgumentException("Reference " + reference + " is invalid"); + } + + return index(reference.getIndex()); + } + + } + +} diff --git a/src/main/java/ru/windcorp/progressia/server/world/context/impl/ReusableServerContextImpl.java b/src/main/java/ru/windcorp/progressia/server/world/context/impl/ReusableServerContextImpl.java new file mode 100644 index 0000000..2336937 --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/server/world/context/impl/ReusableServerContextImpl.java @@ -0,0 +1,519 @@ +/* + * 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.server.world.context.impl; + +import java.util.Collection; +import java.util.Random; + +import glm.vec._3.i.Vec3i; +import ru.windcorp.progressia.common.state.StateChange; +import ru.windcorp.progressia.common.state.StatefulObject; +import ru.windcorp.progressia.common.world.ChunkData; +import ru.windcorp.progressia.common.world.GravityModel; +import ru.windcorp.progressia.common.world.TileDataStack; +import ru.windcorp.progressia.common.world.WorldData; +import ru.windcorp.progressia.common.world.block.BlockData; +import ru.windcorp.progressia.common.world.entity.EntityData; +import ru.windcorp.progressia.common.world.generic.EntityGeneric; +import ru.windcorp.progressia.common.world.rels.BlockFace; +import ru.windcorp.progressia.common.world.rels.RelFace; +import ru.windcorp.progressia.common.world.tile.TileData; +import ru.windcorp.progressia.server.Server; +import ru.windcorp.progressia.server.world.ChunkLogic; +import ru.windcorp.progressia.server.world.TileLogicStack; +import ru.windcorp.progressia.server.world.WorldLogic; +import ru.windcorp.progressia.server.world.context.ServerTileContext; + +class ReusableServerContextImpl extends ReusableServerContext + implements ReusableServerContextBuilders.Empty, ReusableServerContextBuilders.WithWorld, + ReusableServerContextBuilders.WithLocation, ReusableServerContextBuilders.WithTileStack { + + /* + * STATE MANAGEMENT & UTIL + */ + + public ReusableServerContextImpl() { + reuse(); + } + + /** + * The relevant {@link Server} instance. If this is {@code null}, the role + * is {@link Role#NONE}. + */ + protected Server server; + + /** + * The relevant {@link WorldLogic} instance. If this is {@code null}, the + * role is {@link Role#NONE}. + */ + protected WorldLogic world; + + /** + * The relevant location. If this is {@code null}, the role is + * {@link Role#WORLD} or {@link Role#NONE}. + */ + protected Vec3i location; + + /** + * A {@code final} reference to the {@link Vec3i} instance used by + * {@link #location}. + */ + protected final Vec3i locationVectorContainer = new Vec3i(); + + /** + * The relevant {@link RelFace}. If the role is {@link Role#TILE_STACK} or + * {@link Role#TILE}, this is not {@code null}. + */ + protected RelFace blockFace; + + /** + * The index of the relevant tile. This value is {@code -1} unless the role + * is {@link Role#TILE}. + */ + protected int index; + + /** + * Determines whether this object currently acts as a builder or a context. + */ + protected boolean isBuilder; + + /** + * Counts the instances of subcontexting that are currently active. This + * value increases by 1 when subcontexting begins and decreases by 1 when it + * ends. This is always 0 when the object is a builder. + */ + protected int subcontextDepth = 0; + + /** + * The Logic view returned by {@link #logic()}. + */ + protected final ReusableServerContextImpl.Logic logic = new Logic(); + + /** + * Returns the Role currently assumed by this object. + * + * @return the role + */ + @Override + public Role getRole() { + if (server == null) + return Role.NONE; + if (location == null) + return Role.WORLD; + if (blockFace == null) + return Role.LOCATION; + if (index == -1) + return Role.TILE_STACK; + return Role.TILE; + } + + /** + * Throws an {@link IllegalStateException} iff this object does not conform + * to the specified role. The object must not be a builder to pass the + * check. + * + * @param role the required role + * @return {@code true} (for convenience with {@code assert}) + * @throws IllegalStateException when the check fails + */ + public boolean requireContextRole(Role role) throws IllegalStateException { + + boolean ok = !isBuilder && getRole().compareTo(role) <= 0; + if (!ok) { + complainAboutIllegalState(role, false); + } + return true; + + } + + /** + * Throws an {@link IllegalStateException} iff this object does not conform + * to the specified role. The object must be a builder to pass the check. If + * {@code role} is {@code null}, any role except {@link Role#NONE} passes. + * + * @param role the required role or {@code null}, see above + * @return {@code true} (for convenience with {@code assert}) + * @throws IllegalStateException when the check fails + */ + public boolean requireBuilderRole(Role role) { + + boolean ok = isBuilder && role == null ? (getRole() != Role.NONE) : (getRole() == role); + if (!ok) { + complainAboutIllegalState(role, true); + } + return true; + + } + + private void complainAboutIllegalState(Role role, boolean builder) { + throw new IllegalStateException( + "Required " + (builder ? "builder for" : "context") + " " + role + + ", but I am currently " + this + ); + } + + @Override + public String toString() { + String result; + + switch (getRole()) { + case TILE: + result = String.format( + "ServerTileContext[x=%d, y=%d, z=%d, %s, index=%d]", + location.x, + location.y, + location.z, + blockFace, + index + ); + break; + case TILE_STACK: + result = String + .format("ServerBlockFaceContext[x=%d, y=%d, z=%d, %s]", location.x, location.y, location.z, blockFace); + break; + case LOCATION: + result = String.format("ServerBlockContext[x=%d, y=%d, z=%d]", location.x, location.y, location.z); + break; + case WORLD: + result = String.format("ServerWorldContext"); + break; + default: + result = "Uninitialized ReusableServerContext"; + break; + } + + if (isBuilder) { + result = "Builder for " + result; + } + + return result; + } + + /* + * RSC INTERFACE + */ + + @Override + public Empty reuse() { + + if (subcontextDepth != 0) { + throw new IllegalStateException("Resetting is not allowed when subcontexting"); + } + + server = null; + world = null; + location = null; + blockFace = null; + index = -1; + + isBuilder = true; + + return this; + + } + + /* + * BUILDER INTERFACE + */ + + @Override + public ReusableServerContext build() { + assert requireBuilderRole(null); + isBuilder = false; + return this; + } + + /* + * Empty + */ + + @Override + public WithWorld in(Server server, WorldLogic world) { + requireBuilderRole(Role.NONE); + this.server = server; + this.world = world; + return this; + } + + /* + * WithWorld + */ + + @Override + public WithLocation at(Vec3i location) { + requireBuilderRole(Role.WORLD); + this.location = this.locationVectorContainer; + this.location.set(location.x, location.y, location.z); + return this; + } + + /* + * WithLocation + */ + + @Override + public WithTileStack on(RelFace side) { + requireBuilderRole(Role.LOCATION); + this.blockFace = side; + return this; + } + + @Override + public WithTileStack on(BlockFace side) { + requireBuilderRole(Role.LOCATION); + this.blockFace = side.relativize(world.getData().getUp(location)); + return this; + } + + /* + * WithTileStack + */ + + @Override + public ReusableServerContext index(int index) { + requireBuilderRole(Role.TILE_STACK); + this.index = index; + return build(); + } + + /* + * ServerWorldContext.Logic STUFF + */ + + private class Logic implements ServerTileContext.Logic { + @Override + public boolean isReal() { + return ReusableServerContextImpl.this.isReal(); + } + + @Override + public Collection getChunks() { + return world.getChunks(); + } + + @Override + public Collection getEntities() { + return ReusableServerContextImpl.this.getEntities(); + } + + @Override + public EntityData getEntity(long entityId) { + return ReusableServerContextImpl.this.getEntity(entityId); + } + + @Override + public Server getServer() { + return ReusableServerContextImpl.this.getServer(); + } + + @Override + public Random getRandom() { + return ReusableServerContextImpl.this.getRandom(); + } + + @Override + public Vec3i getLocation() { + return ReusableServerContextImpl.this.getLocation(); + } + + @Override + public RelFace getFace() { + return ReusableServerContextImpl.this.getFace(); + } + + @Override + public int getLayer() { + return ReusableServerContextImpl.this.getLayer(); + } + + @Override + public TileLogicStack getTiles(Vec3i blockInWorld, BlockFace face) { + return world.getTiles(blockInWorld, face); + } + + @Override + public ChunkLogic getChunk(Vec3i pos) { + return world.getChunk(pos); + } + + @Override + public WorldData getData() { + return world.getData(); + } + + @Override + public ServerTileContext data() { + return ReusableServerContextImpl.this; + } + + @Override + public String toString() { + return ReusableServerContextImpl.this + ".Logic"; + } + } + + @Override + public Logic logic() { + return logic; + } + + /* + * LOCATION GETTERS + */ + + @Override + public Server getServer() { + assert requireContextRole(Role.WORLD); + return server; + } + + @Override + public Vec3i getLocation() { + assert requireContextRole(Role.LOCATION); + return location; + } + + @Override + public RelFace getFace() { + assert requireContextRole(Role.TILE_STACK); + return blockFace; + } + + @Override + public int getLayer() { + assert requireContextRole(Role.TILE); + return index; + } + + /* + * RO CONTEXT INTERFACE + */ + + @Override + public boolean isReal() { + assert requireContextRole(Role.WORLD); + return true; + } + + @Override + public Random getRandom() { + assert requireContextRole(Role.WORLD); + return server.getAdHocRandom(); + } + + @Override + public ChunkData getChunk(Vec3i pos) { + assert requireContextRole(Role.WORLD); + return world.getData().getChunk(pos); + } + + @Override + public Collection getChunks() { + assert requireContextRole(Role.WORLD); + return world.getData().getChunks(); + } + + @Override + public Collection getEntities() { + assert requireContextRole(Role.WORLD); + return world.getEntities(); + } + + @Override + public EntityData getEntity(long entityId) { + assert requireContextRole(Role.WORLD); + return world.getEntity(entityId); + } + + @Override + public GravityModel getGravityModel() { + assert requireContextRole(Role.WORLD); + return world.getData().getGravityModel(); + } + + @Override + public float getTime() { + assert requireContextRole(Role.WORLD); + return world.getData().getTime(); + } + + /* + * RO CONTEXT OPTIMIZATIONS + */ + + /* + * RW CONTEXT INTERFACE + */ + + @Override + public boolean isImmediate() { + assert requireContextRole(Role.WORLD); + return true; + } + + @Override + public void setBlock(Vec3i blockInWorld, BlockData block, boolean notify) { + assert requireContextRole(Role.WORLD); + world.getData().setBlock(blockInWorld, block, notify); + } + + @Override + public void addTile(Vec3i location, BlockFace face, TileData tile) { + assert requireContextRole(Role.WORLD); + world.getData().getTiles(location, face).addFarthest(tile); + } + + @Override + public void removeTile(Vec3i location, BlockFace face, int tag) { + assert requireContextRole(Role.WORLD); + TileDataStack stack = world.getData().getTilesOrNull(location, face); + if (stack == null) return; + int index = stack.getIndexByTag(tag); + if (index == -1) return; + stack.remove(index); + } + + @Override + public void addEntity(EntityData entity) { + assert requireContextRole(Role.WORLD); + world.getData().addEntity(entity); + } + + @Override + public void removeEntity(long entityId) { + assert requireContextRole(Role.WORLD); + world.getData().removeEntity(entityId); + } + + @Override + public void changeEntity(SE entity, StateChange change) { + assert requireContextRole(Role.WORLD); + world.getData().changeEntity(entity, change); + } + + @Override + public void advanceTime(float change) { + assert requireContextRole(Role.WORLD); + world.getData().advanceTime(change); + } + + /* + * RW CONTEXT OPTIMIZATIONS + */ + +} From 0f60d45ffa547fe9e196f216ccc60b912158164e Mon Sep 17 00:00:00 2001 From: OLEGSHA Date: Thu, 5 Aug 2021 16:42:21 +0300 Subject: [PATCH 35/55] Contexts no longer expose to World, Chunks, TileStacks or TileReferences The intention is to bottleneck all read queries and write requests through context objects without the need to create practically useless Chunk, TileStack and TileRef wrappers. - WorldGenericContext{RO,WO} no longer extend WorldGeneric{RO,WO} - Added tag access for tiles to contexts - Documented almost all context methods - Renamed isBlockLoaded() to isLocationLoaded() - I found some inner peace --- .../world/context/BlockDataContext.java | 7 +- .../world/context/BlockDataContextRO.java | 5 +- .../world/context/BlockFaceDataContext.java | 7 +- .../world/context/BlockFaceDataContextRO.java | 5 +- .../common/world/context/TileDataContext.java | 10 +- .../world/context/TileDataContextRO.java | 5 +- .../world/context/WorldDataContext.java | 21 +- .../world/context/WorldDataContextRO.java | 27 +- .../common/world/generic/WorldGenericRO.java | 2 +- .../context/BlockFaceGenericContextRO.java | 84 ++-- .../context/BlockFaceGenericContextWO.java | 5 +- .../context/BlockGenericContextRO.java | 97 +++-- .../context/BlockGenericContextWO.java | 5 +- .../generic/context/TileGenericContextRO.java | 47 +-- .../generic/context/TileGenericContextWO.java | 5 +- .../context/WorldGenericContextRO.java | 166 +++++++- .../context/WorldGenericContextWO.java | 12 +- .../server/world/TickAndUpdateUtil.java | 4 +- .../world/context/ServerBlockContext.java | 7 - .../world/context/ServerBlockContextRO.java | 7 +- .../world/context/ServerBlockFaceContext.java | 6 - .../context/ServerBlockFaceContextRO.java | 7 +- .../server/world/context/ServerContext.java | 4 +- .../world/context/ServerTileContext.java | 6 - .../world/context/ServerTileContextRO.java | 7 +- .../world/context/ServerWorldContext.java | 10 +- .../world/context/ServerWorldContextRO.java | 10 +- .../context/impl/ReusableServerContext.java | 7 +- .../impl/ReusableServerContextImpl.java | 399 ++++++++++++------ .../test/gen/surface/SurfaceWorld.java | 2 +- 30 files changed, 613 insertions(+), 373 deletions(-) diff --git a/src/main/java/ru/windcorp/progressia/common/world/context/BlockDataContext.java b/src/main/java/ru/windcorp/progressia/common/world/context/BlockDataContext.java index 4ebb85a..3462048 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/context/BlockDataContext.java +++ b/src/main/java/ru/windcorp/progressia/common/world/context/BlockDataContext.java @@ -17,19 +17,16 @@ */ package ru.windcorp.progressia.common.world.context; -import ru.windcorp.progressia.common.world.ChunkData; -import ru.windcorp.progressia.common.world.TileDataReference; -import ru.windcorp.progressia.common.world.TileDataStack; import ru.windcorp.progressia.common.world.block.BlockData; import ru.windcorp.progressia.common.world.entity.EntityData; import ru.windcorp.progressia.common.world.generic.context.BlockGenericContextWO; import ru.windcorp.progressia.common.world.tile.TileData; public interface BlockDataContext - extends BlockGenericContextWO, + extends BlockGenericContextWO, WorldDataContext, BlockDataContextRO { - + // currently empty } diff --git a/src/main/java/ru/windcorp/progressia/common/world/context/BlockDataContextRO.java b/src/main/java/ru/windcorp/progressia/common/world/context/BlockDataContextRO.java index f910fa1..70ad8f4 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/context/BlockDataContextRO.java +++ b/src/main/java/ru/windcorp/progressia/common/world/context/BlockDataContextRO.java @@ -17,16 +17,13 @@ */ package ru.windcorp.progressia.common.world.context; -import ru.windcorp.progressia.common.world.ChunkDataRO; -import ru.windcorp.progressia.common.world.TileDataReferenceRO; -import ru.windcorp.progressia.common.world.TileDataStackRO; import ru.windcorp.progressia.common.world.block.BlockData; import ru.windcorp.progressia.common.world.entity.EntityData; import ru.windcorp.progressia.common.world.generic.context.BlockGenericContextRO; import ru.windcorp.progressia.common.world.tile.TileData; public interface BlockDataContextRO - extends BlockGenericContextRO, + extends BlockGenericContextRO, WorldDataContextRO { // currently empty diff --git a/src/main/java/ru/windcorp/progressia/common/world/context/BlockFaceDataContext.java b/src/main/java/ru/windcorp/progressia/common/world/context/BlockFaceDataContext.java index 45ce045..b12c36c 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/context/BlockFaceDataContext.java +++ b/src/main/java/ru/windcorp/progressia/common/world/context/BlockFaceDataContext.java @@ -17,19 +17,16 @@ */ package ru.windcorp.progressia.common.world.context; -import ru.windcorp.progressia.common.world.ChunkData; -import ru.windcorp.progressia.common.world.TileDataReference; -import ru.windcorp.progressia.common.world.TileDataStack; import ru.windcorp.progressia.common.world.block.BlockData; import ru.windcorp.progressia.common.world.entity.EntityData; import ru.windcorp.progressia.common.world.generic.context.BlockFaceGenericContextWO; import ru.windcorp.progressia.common.world.tile.TileData; public interface BlockFaceDataContext - extends BlockFaceGenericContextWO, + extends BlockFaceGenericContextWO, BlockDataContext, BlockFaceDataContextRO { - + // currently empty } diff --git a/src/main/java/ru/windcorp/progressia/common/world/context/BlockFaceDataContextRO.java b/src/main/java/ru/windcorp/progressia/common/world/context/BlockFaceDataContextRO.java index ddf7089..a20355a 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/context/BlockFaceDataContextRO.java +++ b/src/main/java/ru/windcorp/progressia/common/world/context/BlockFaceDataContextRO.java @@ -17,16 +17,13 @@ */ package ru.windcorp.progressia.common.world.context; -import ru.windcorp.progressia.common.world.ChunkDataRO; -import ru.windcorp.progressia.common.world.TileDataReferenceRO; -import ru.windcorp.progressia.common.world.TileDataStackRO; import ru.windcorp.progressia.common.world.block.BlockData; import ru.windcorp.progressia.common.world.entity.EntityData; import ru.windcorp.progressia.common.world.generic.context.BlockFaceGenericContextRO; import ru.windcorp.progressia.common.world.tile.TileData; public interface BlockFaceDataContextRO - extends BlockFaceGenericContextRO, + extends BlockFaceGenericContextRO, BlockDataContext { // currently empty diff --git a/src/main/java/ru/windcorp/progressia/common/world/context/TileDataContext.java b/src/main/java/ru/windcorp/progressia/common/world/context/TileDataContext.java index 79e8d51..3f4a0d6 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/context/TileDataContext.java +++ b/src/main/java/ru/windcorp/progressia/common/world/context/TileDataContext.java @@ -17,22 +17,16 @@ */ package ru.windcorp.progressia.common.world.context; -import ru.windcorp.progressia.common.world.ChunkData; -import ru.windcorp.progressia.common.world.TileDataReference; -import ru.windcorp.progressia.common.world.TileDataStack; import ru.windcorp.progressia.common.world.block.BlockData; import ru.windcorp.progressia.common.world.entity.EntityData; import ru.windcorp.progressia.common.world.generic.context.TileGenericContextWO; import ru.windcorp.progressia.common.world.tile.TileData; public interface TileDataContext - extends TileGenericContextWO, + extends TileGenericContextWO, BlockFaceDataContext, TileDataContextRO { - @Override - default int getTag() { - return getTileReference().getTag(); - } + // currently empty } diff --git a/src/main/java/ru/windcorp/progressia/common/world/context/TileDataContextRO.java b/src/main/java/ru/windcorp/progressia/common/world/context/TileDataContextRO.java index b7f2b4d..e143e03 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/context/TileDataContextRO.java +++ b/src/main/java/ru/windcorp/progressia/common/world/context/TileDataContextRO.java @@ -17,16 +17,13 @@ */ package ru.windcorp.progressia.common.world.context; -import ru.windcorp.progressia.common.world.ChunkDataRO; -import ru.windcorp.progressia.common.world.TileDataReferenceRO; -import ru.windcorp.progressia.common.world.TileDataStackRO; import ru.windcorp.progressia.common.world.block.BlockData; import ru.windcorp.progressia.common.world.entity.EntityData; import ru.windcorp.progressia.common.world.generic.context.TileGenericContextRO; import ru.windcorp.progressia.common.world.tile.TileData; public interface TileDataContextRO - extends TileGenericContextRO, + extends TileGenericContextRO, BlockFaceDataContextRO { // currently empty diff --git a/src/main/java/ru/windcorp/progressia/common/world/context/WorldDataContext.java b/src/main/java/ru/windcorp/progressia/common/world/context/WorldDataContext.java index 31dbef1..68965b5 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/context/WorldDataContext.java +++ b/src/main/java/ru/windcorp/progressia/common/world/context/WorldDataContext.java @@ -17,20 +17,23 @@ */ package ru.windcorp.progressia.common.world.context; -import ru.windcorp.progressia.common.world.ChunkData; -import ru.windcorp.progressia.common.world.TileDataReference; -import ru.windcorp.progressia.common.world.TileDataStack; -import ru.windcorp.progressia.common.world.WorldData; import ru.windcorp.progressia.common.world.block.BlockData; import ru.windcorp.progressia.common.world.entity.EntityData; import ru.windcorp.progressia.common.world.generic.context.WorldGenericContextWO; import ru.windcorp.progressia.common.world.tile.TileData; public interface WorldDataContext - extends WorldGenericContextWO, - WorldDataContextRO, - WorldData { - - // currently empty + extends WorldGenericContextWO, + WorldDataContextRO { + + /** + * Increases in-game time of this world by {@code change}. Total time is + * decreased when {@code change} is negative. + * + * @param change the amount of time to add to current world time. May be + * negative. + * @see #getTime() + */ + void advanceTime(float change); } diff --git a/src/main/java/ru/windcorp/progressia/common/world/context/WorldDataContextRO.java b/src/main/java/ru/windcorp/progressia/common/world/context/WorldDataContextRO.java index c474ea4..8201738 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/context/WorldDataContextRO.java +++ b/src/main/java/ru/windcorp/progressia/common/world/context/WorldDataContextRO.java @@ -18,19 +18,30 @@ package ru.windcorp.progressia.common.world.context; -import ru.windcorp.progressia.common.world.ChunkDataRO; -import ru.windcorp.progressia.common.world.TileDataReferenceRO; -import ru.windcorp.progressia.common.world.TileDataStackRO; -import ru.windcorp.progressia.common.world.WorldDataRO; +import ru.windcorp.progressia.common.world.GravityModel; import ru.windcorp.progressia.common.world.block.BlockData; import ru.windcorp.progressia.common.world.entity.EntityData; import ru.windcorp.progressia.common.world.generic.context.WorldGenericContextRO; import ru.windcorp.progressia.common.world.tile.TileData; -public interface WorldDataContextRO - extends WorldGenericContextRO, - WorldDataRO { +public interface WorldDataContextRO extends WorldGenericContextRO { - // currently empty + /** + * Returns in-world time since creation. World time is zero before and + * during first tick. + *

    + * Game logic should assume that this value mostly increases uniformly. + * However, it is not guaranteed that in-world time always increments. + * + * @return time, in in-game seconds, since the world was created + */ + float getTime(); + + /** + * Gets the {@link GravityModel} used by this world. + * + * @return the gravity model + */ + GravityModel getGravityModel(); } diff --git a/src/main/java/ru/windcorp/progressia/common/world/generic/WorldGenericRO.java b/src/main/java/ru/windcorp/progressia/common/world/generic/WorldGenericRO.java index 75ad1c3..eac2a0c 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/generic/WorldGenericRO.java +++ b/src/main/java/ru/windcorp/progressia/common/world/generic/WorldGenericRO.java @@ -144,7 +144,7 @@ public interface WorldGenericRO< return getChunk(chunkPos) != null; } - default boolean isBlockLoaded(Vec3i blockInWorld) { + default boolean isLocationLoaded(Vec3i blockInWorld) { return getChunkByBlock(blockInWorld) != null; } diff --git a/src/main/java/ru/windcorp/progressia/common/world/generic/context/BlockFaceGenericContextRO.java b/src/main/java/ru/windcorp/progressia/common/world/generic/context/BlockFaceGenericContextRO.java index 212cc9b..0ca350a 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/generic/context/BlockFaceGenericContextRO.java +++ b/src/main/java/ru/windcorp/progressia/common/world/generic/context/BlockFaceGenericContextRO.java @@ -29,37 +29,15 @@ import ru.windcorp.progressia.common.world.generic.*; public interface BlockFaceGenericContextRO< B extends BlockGeneric, T extends TileGeneric, - TS extends TileGenericStackRO , - TR extends TileGenericReferenceRO , - C extends ChunkGenericRO , E extends EntityGeneric -> extends WorldContexts.BlockFace, BlockGenericContextRO { +> extends WorldContexts.BlockFace, BlockGenericContextRO { //@formatter:on /** - * Gets the tile stack at the relevant position. - * - * @return the specified tile stack or {@code null} if the location is not - * loaded or the tile stack does not exist - */ - default TS getTilesOrNull() { - return getTilesOrNull(getLocation(), getFace()); - } - - /** - * Determines whether the location relevant to this context has a tile - * stack. - * - * @return {@code true} iff the tile stack exists - */ - default boolean hasTiles() { - return hasTiles(getLocation(), getFace()); - } - - /** - * Determines whether the specified position has a tile; block location and - * face are implied by the context. + * Determines whether the specified position has a tile. Block location and + * block face are implied by the context. * + * @param layer the layer of the tile * @return {@code true} iff the tile exists */ default boolean hasTile(int layer) { @@ -67,14 +45,60 @@ public interface BlockFaceGenericContextRO< } /** - * Gets the tile at the specified position; block location and face are - * implied by the context. + * Determines whether the specified position has a tile with the given tag. + * Block location and block face are implied by the context. * - * @return the specified tile or {@code null} if the location is not loaded - * or the tile does not exist + * @param tag the tag of the tile + * @return {@code true} iff the tile exists + */ + default boolean isTagValid(int tag) { + return isTagValid(getLocation(), getFace(), tag); + } + + /** + * Retrieves the tile at the specified position. Block location and block + * face are implied by the context. This method may return {@code null} in + * one of three cases: + *

      + *
    • the location is not loaded, + *
    • there is no tile stack on the relevant face, or + *
    • {@code layer} is not less than the amount of tiles in the tile stack. + *
    + * + * @return the tile or {@code null} if the position does not contain a tile */ default T getTile(int layer) { return getTile(getLocation(), getFace(), layer); } + /** + * Retrieves the tile at the specified position and the tile's tag. Block + * location and block face are implied by the context. This + * method may return {@code null} in one of three cases: + *
      + *
    • the location is not loaded, + *
    • there is no tile stack on the relevant face, or + *
    • there is no tile with the specified tag in the tile stack. + *
    + * + * @param tag the tag of the tile + * @return the tile or {@code null} if the position does not contain a tile + */ + default T getTileByTag(int tag) { + return getTileByTag(getLocation(), getFace(), tag); + } + + /** + * Counts the amount of tiles in the specified tile stack. Block location + * and block face are implied by the context. + *

    + * This method returns {@code 0} in case the location is not loaded. + * + * @return the count of tiles in the tile stack or {@code -1} if the tile + * stack could not exist + */ + default int getTileCount() { + return getTileCount(getLocation(), getFace()); + } + } diff --git a/src/main/java/ru/windcorp/progressia/common/world/generic/context/BlockFaceGenericContextWO.java b/src/main/java/ru/windcorp/progressia/common/world/generic/context/BlockFaceGenericContextWO.java index bcaa226..dd6c5ad 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/generic/context/BlockFaceGenericContextWO.java +++ b/src/main/java/ru/windcorp/progressia/common/world/generic/context/BlockFaceGenericContextWO.java @@ -31,11 +31,8 @@ import ru.windcorp.progressia.common.world.generic.*; public interface BlockFaceGenericContextWO< B extends BlockGeneric, T extends TileGeneric, - TS extends TileGenericStackWO , - TR extends TileGenericReferenceWO , - C extends ChunkGenericWO , E extends EntityGeneric -> extends WorldContexts.BlockFace, BlockGenericContextWO { +> extends WorldContexts.BlockFace, BlockGenericContextWO { //@formatter:on /** diff --git a/src/main/java/ru/windcorp/progressia/common/world/generic/context/BlockGenericContextRO.java b/src/main/java/ru/windcorp/progressia/common/world/generic/context/BlockGenericContextRO.java index 91ac3d3..239a02e 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/generic/context/BlockGenericContextRO.java +++ b/src/main/java/ru/windcorp/progressia/common/world/generic/context/BlockGenericContextRO.java @@ -29,11 +29,8 @@ import ru.windcorp.progressia.common.world.rels.BlockFace; public interface BlockGenericContextRO< B extends BlockGeneric, T extends TileGeneric, - TS extends TileGenericStackRO , - TR extends TileGenericReferenceRO , - C extends ChunkGenericRO , E extends EntityGeneric -> extends WorldContexts.Block, WorldGenericContextRO { +> extends WorldContexts.Block, WorldGenericContextRO { //@formatter:on /** @@ -43,11 +40,16 @@ public interface BlockGenericContextRO< * @return {@code true} iff the location is loaded */ default boolean isLoaded() { - return isBlockLoaded(getLocation()); + return isLocationLoaded(getLocation()); } /** - * Gets the block relevant in this context. + * Retrieves the block at the relevant location. This method may return + * {@code null} in one of two cases: + *

      + *
    • the location that the block would occupy is not loaded, or + *
    • the corresponding chunk's terrain has not yet generated. + *
    * * @return the block or {@code null} if the location is not loaded */ @@ -56,30 +58,11 @@ public interface BlockGenericContextRO< } /** - * Gets the tile stack at the specified position; block location is implied - * by the context. - * - * @return the specified tile stack or {@code null} if the location is not - * loaded or the tile stack does not exist - */ - default TS getTilesOrNull(BlockFace face) { - return getTilesOrNull(getLocation(), face); - } - - /** - * Determines whether the location relevant to this context has a tile stack - * at the specified side. - * - * @return {@code true} iff the tile stack exists - */ - default boolean hasTiles(BlockFace face) { - return hasTiles(getLocation(), face); - } - - /** - * Determines whether the specified position has a tile; block location is + * Determines whether the specified position has a tile. Block location is * implied by the context. * + * @param face the face of the block that the tile occupies + * @param layer the layer of the tile * @return {@code true} iff the tile exists */ default boolean hasTile(BlockFace face, int layer) { @@ -87,14 +70,64 @@ public interface BlockGenericContextRO< } /** - * Gets the tile at the specified position; block location is implied by the - * context. + * Determines whether the specified position has a tile with the given tag. + * Block location is implied by context. * - * @return the specified tile or {@code null} if the location is not loaded - * or the tile does not exist + * @param face the face of the block that the tile occupies + * @param tag the tag of the tile + * @return {@code true} iff the tile exists + */ + default boolean isTagValid(BlockFace face, int tag) { + return isTagValid(getLocation(), face, tag); + } + + /** + * Retrieves the tile at the specified position. Block location is implied + * by context. This method may return {@code null} in one of three cases: + *
      + *
    • the location is not loaded, + *
    • there is no tile stack on the specified face, or + *
    • {@code layer} is not less than the amount of tiles in the tile stack. + *
    + * + * @param face the face of the block that the tile occupies + * @param layer the layer of the tile stack that the tile occupies + * @return the tile or {@code null} if the position does not contain a tile */ default T getTile(BlockFace face, int layer) { return getTile(getLocation(), face, layer); } + /** + * Retrieves the tile at the specified position and the tile's tag. Block + * location is implied by the context. This + * method may return {@code null} in one of three cases: + *
      + *
    • the location is not loaded, + *
    • there is no tile stack on the specified face, or + *
    • there is no tile with the specified tag in the tile stack. + *
    + * + * @param face the face of the block that the tile occupies + * @param tag the tag of the tile + * @return the tile or {@code null} if the position does not contain a tile + */ + default T getTileByTag(BlockFace face, int tag) { + return getTileByTag(getLocation(), face, tag); + } + + /** + * Counts the amount of tiles in the specified tile stack. Block location is + * implied by the context + *

    + * This method returns {@code 0} in case the location is not loaded. + * + * @param face the face of the block that the tile stack occupies + * @return the count of tiles in the tile stack or {@code -1} if the tile + * stack could not exist + */ + default int getTileCount(BlockFace face) { + return getTileCount(face); + } + } diff --git a/src/main/java/ru/windcorp/progressia/common/world/generic/context/BlockGenericContextWO.java b/src/main/java/ru/windcorp/progressia/common/world/generic/context/BlockGenericContextWO.java index f7a0eea..ffdb969 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/generic/context/BlockGenericContextWO.java +++ b/src/main/java/ru/windcorp/progressia/common/world/generic/context/BlockGenericContextWO.java @@ -31,11 +31,8 @@ import ru.windcorp.progressia.common.world.rels.BlockFace; public interface BlockGenericContextWO< B extends BlockGeneric, T extends TileGeneric, - TS extends TileGenericStackWO , - TR extends TileGenericReferenceWO , - C extends ChunkGenericWO , E extends EntityGeneric -> extends WorldContexts.Block, WorldGenericContextWO { +> extends WorldContexts.Block, WorldGenericContextWO { //@formatter:on /** diff --git a/src/main/java/ru/windcorp/progressia/common/world/generic/context/TileGenericContextRO.java b/src/main/java/ru/windcorp/progressia/common/world/generic/context/TileGenericContextRO.java index 0bc04d0..daf7fb8 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/generic/context/TileGenericContextRO.java +++ b/src/main/java/ru/windcorp/progressia/common/world/generic/context/TileGenericContextRO.java @@ -29,15 +29,12 @@ import ru.windcorp.progressia.common.world.generic.*; public interface TileGenericContextRO< B extends BlockGeneric, T extends TileGeneric, - TS extends TileGenericStackRO , - TR extends TileGenericReferenceRO , - C extends ChunkGenericRO , E extends EntityGeneric -> extends WorldContexts.Tile, BlockFaceGenericContextRO { +> extends WorldContexts.Tile, BlockFaceGenericContextRO { //@formatter:on /** - * Determines whether the location relevant to this context has a tile. + * Determines whether the relevant position has a tile. * * @return {@code true} iff the tile exists */ @@ -46,42 +43,18 @@ public interface TileGenericContextRO< } /** - * Gets the tile at the relevant position. + * Retrieves the tile at the relevant position. This method may return + * {@code null} in one of three cases: + *

      + *
    • the location is not loaded, + *
    • there is no tile stack on the relevant face, or + *
    • {@code layer} is not less than the amount of tiles in the tile stack. + *
    * - * @return the specified tile or {@code null} if the location is not loaded - * or the tile does not exist + * @return the tile or {@code null} if the position does not contain a tile */ default T getTile() { return getTile(getLocation(), getFace(), getLayer()); } - @Override - default int getTag() { - TS tileStack = getTilesOrNull(); - if (tileStack == null) { - return -1; - } - - return tileStack.getTagByIndex(getLayer()); - } - - /** - * Gets the {@link TileGenericReferenceRO TileReference} to the relevant - * tile. - * - * @return the reference to the tile relevant to this context or - * {@code null} if the location is not loaded or the tile does not - * exist - * - * @see TileGenericStackRO#getReference(int) - */ - default TR getTileReference() { - TS tileStack = getTilesOrNull(); - if (tileStack == null) { - return null; - } - - return tileStack.getReference(getLayer()); - } - } diff --git a/src/main/java/ru/windcorp/progressia/common/world/generic/context/TileGenericContextWO.java b/src/main/java/ru/windcorp/progressia/common/world/generic/context/TileGenericContextWO.java index 01a27d1..4c2b4dd 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/generic/context/TileGenericContextWO.java +++ b/src/main/java/ru/windcorp/progressia/common/world/generic/context/TileGenericContextWO.java @@ -31,11 +31,8 @@ import ru.windcorp.progressia.common.world.generic.*; public interface TileGenericContextWO< B extends BlockGeneric, T extends TileGeneric, - TS extends TileGenericStackWO , - TR extends TileGenericReferenceWO , - C extends ChunkGenericWO , E extends EntityGeneric -> extends WorldContexts.Tile, BlockFaceGenericContextWO { +> extends WorldContexts.Tile, BlockFaceGenericContextWO { //@formatter:on /** diff --git a/src/main/java/ru/windcorp/progressia/common/world/generic/context/WorldGenericContextRO.java b/src/main/java/ru/windcorp/progressia/common/world/generic/context/WorldGenericContextRO.java index 588c98f..d604d62 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/generic/context/WorldGenericContextRO.java +++ b/src/main/java/ru/windcorp/progressia/common/world/generic/context/WorldGenericContextRO.java @@ -17,23 +17,175 @@ */ package ru.windcorp.progressia.common.world.generic.context; +import java.util.Collection; +import java.util.function.Consumer; + +import glm.vec._3.Vec3; +import glm.vec._3.i.Vec3i; import ru.windcorp.progressia.common.world.context.Context; import ru.windcorp.progressia.common.world.generic.*; +import ru.windcorp.progressia.common.world.rels.BlockFace; /** * A {@link Context} with a world instance. + *

    + * This interfaces defines the entirety of world query methods supported by the + * default contexts. */ // @formatter:off public interface WorldGenericContextRO< B extends BlockGeneric, T extends TileGeneric, - TS extends TileGenericStackRO , - TR extends TileGenericReferenceRO , - C extends ChunkGenericRO , E extends EntityGeneric -> extends WorldContexts.World, WorldGenericRO { +> extends WorldContexts.World { // @formatter:on - - // currently empty - + + /** + * Retrieves the block at the specified location. This method may return + * {@code null} in one of two cases: + *

      + *
    • the location that the block would occupy is not loaded, or + *
    • the corresponding chunk's terrain has not yet generated. + *
    + * + * @param location the location to query + * @return the block or {@code null} if the location is not loaded + */ + B getBlock(Vec3i location); + + /** + * Determines whether the specified location is loaded. + * + * @param location the location to query + * @return {@code true} iff the location is loaded + */ + boolean isLocationLoaded(Vec3i location); + + /** + * Retrieves the tile at the specified position. This method may return + * {@code null} in one of three cases: + *
      + *
    • the location is not loaded, + *
    • there is no tile stack on the specified face, or + *
    • {@code layer} is not less than the amount of tiles in the tile stack. + *
    + * + * @param location location of the host block + * @param face the face of the block that the tile occupies + * @param layer the layer of the tile stack that the tile occupies + * @return the tile or {@code null} if the position does not contain a tile + */ + T getTile(Vec3i location, BlockFace face, int layer); + + /** + * Retrieves the tile at the specified position and the tile's tag. This + * method may return {@code null} in one of three cases: + *
      + *
    • the location is not loaded, + *
    • there is no tile stack on the specified face, or + *
    • there is no tile with the specified tag in the tile stack. + *
    + * + * @param location location of the host block + * @param face the face of the block that the tile occupies + * @param tag the tag of the tile + * @return the tile or {@code null} if the position does not contain a tile + */ + T getTileByTag(Vec3i location, BlockFace face, int tag); + + /** + * Determines whether the specified position has a tile. + * + * @param location location of the host block + * @param face the face of the block that the tile occupies + * @param layer the layer of the tile + * @return {@code true} iff the tile exists + */ + boolean hasTile(Vec3i location, BlockFace face, int layer); + + /** + * Determines whether the specified position has a tile with the given tag. + * + * @param location location of the host block + * @param face the face of the block that the tile occupies + * @param tag the tag of the tile + * @return {@code true} iff the tile exists + */ + boolean isTagValid(Vec3i location, BlockFace face, int tag); + + /** + * Counts the amount of tiles in the specified tile stack. + *

    + * This method returns {@code 0} in case the location is not loaded. + * + * @param location location of the host block + * @param face the face of the block that the tile stack occupies + * @return the count of tiles in the tile stack or {@code -1} if the tile + * stack could not exist + */ + int getTileCount(Vec3i location, BlockFace face); + + /** + * Retrieves a listing of all entities. {@link #forEachEntity(Consumer)} + * should be used to iterate the collection. The collection is not + * modifiable. + * + * @return all loaded entities + */ + Collection getEntities(); + + /** + * Retrieves the entity with the specified entity ID. + * + * @param entityId the entity ID to look up + * @return the entity found or {@code null} + */ + E getEntity(long entityId); + + /* + * Convenience methods + */ + + /** + * Iterates all entities safely + */ + default void forEachEntity(Consumer action) { + getEntities().forEach(action); + } + + /** + * Iterates all entities in cuboid safely + */ + default void forEachEntityIn(Vec3i min, Vec3i max, Consumer action) { + forEachEntity(e -> { + Vec3 pos = e.getPosition(); + if (pos.x < min.x || pos.y < min.y || pos.z < min.z || pos.x > max.x || pos.y > max.y || pos.z > max.z) { + action.accept(e); + } + }); + } + + /** + * Iterates all entities in cuboid safely + */ + default void forEachEntityIn(Vec3 min, Vec3 max, Consumer action) { + forEachEntity(e -> { + Vec3 pos = e.getPosition(); + if (pos.x < min.x || pos.y < min.y || pos.z < min.z || pos.x > max.x || pos.y > max.y || pos.z > max.z) { + action.accept(e); + } + }); + } + + /** + * Iterates all entities with ID safely + */ + default void forEachEntityWithId(String id, Consumer action) { + forEachEntity(e -> { + if (id.equals(e.getId())) { + action.accept(e); + } + }); + } + } diff --git a/src/main/java/ru/windcorp/progressia/common/world/generic/context/WorldGenericContextWO.java b/src/main/java/ru/windcorp/progressia/common/world/generic/context/WorldGenericContextWO.java index 27bbb1a..ad1291e 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/generic/context/WorldGenericContextWO.java +++ b/src/main/java/ru/windcorp/progressia/common/world/generic/context/WorldGenericContextWO.java @@ -28,16 +28,16 @@ import ru.windcorp.progressia.common.world.rels.BlockFace; * A writable {@link Context} with a world instance. This context provides * methods for affecting the world. The application of requested changes may or * may not be immediate, see {@link #isImmediate()}. + *

    + * This interfaces defines the entirety of world modification methods supported + * by the default contexts. */ // @formatter:off public interface WorldGenericContextWO< B extends BlockGeneric, T extends TileGeneric, - TS extends TileGenericStackWO , - TR extends TileGenericReferenceWO , - C extends ChunkGenericWO , E extends EntityGeneric -> extends WorldContexts.World, WorldGenericWO { +> extends WorldContexts.World { // @formatter:on /** @@ -116,7 +116,6 @@ public interface WorldGenericContextWO< * @param entity the entity to add * @see #isImmediate() */ - @Override void addEntity(E entity); /** @@ -128,7 +127,6 @@ public interface WorldGenericContextWO< * @see #isImmediate() * @see #removeEntity(EntityGeneric) */ - @Override void removeEntity(long entityId); /** @@ -139,7 +137,6 @@ public interface WorldGenericContextWO< * @see #isImmediate() * @see #removeEntity(long) */ - @Override default void removeEntity(E entity) { removeEntity(entity.getEntityId()); } @@ -151,7 +148,6 @@ public interface WorldGenericContextWO< * @param entity the entity to change * @param change the change to apply */ - @Override void changeEntity(SE entity, StateChange change); } diff --git a/src/main/java/ru/windcorp/progressia/server/world/TickAndUpdateUtil.java b/src/main/java/ru/windcorp/progressia/server/world/TickAndUpdateUtil.java index fd3e0ec..112d722 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/TickAndUpdateUtil.java +++ b/src/main/java/ru/windcorp/progressia/server/world/TickAndUpdateUtil.java @@ -73,7 +73,7 @@ public class TickAndUpdateUtil { } public static void tickTiles(DefaultWorldLogic world, Vec3i blockInWorld, BlockFace face) { - if (!world.isBlockLoaded(blockInWorld)) { + if (!world.isLocationLoaded(blockInWorld)) { return; } @@ -123,7 +123,7 @@ public class TickAndUpdateUtil { } public static void updateTiles(DefaultWorldLogic world, Vec3i blockInWorld, BlockFace face) { - if (!world.isBlockLoaded(blockInWorld)) { + if (!world.isLocationLoaded(blockInWorld)) { return; } diff --git a/src/main/java/ru/windcorp/progressia/server/world/context/ServerBlockContext.java b/src/main/java/ru/windcorp/progressia/server/world/context/ServerBlockContext.java index a1fbbf5..4130b50 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/context/ServerBlockContext.java +++ b/src/main/java/ru/windcorp/progressia/server/world/context/ServerBlockContext.java @@ -18,8 +18,6 @@ package ru.windcorp.progressia.server.world.context; import ru.windcorp.progressia.common.world.context.BlockDataContext; -import ru.windcorp.progressia.common.world.rels.BlockFace; -import ru.windcorp.progressia.server.world.TileLogicStack; public interface ServerBlockContext extends BlockDataContext, ServerWorldContext, ServerBlockContextRO { @@ -28,11 +26,6 @@ public interface ServerBlockContext extends BlockDataContext, ServerWorldContext @Override ServerBlockContext data(); - @Override - default TileLogicStack getTilesOrNull(BlockFace face) { - return (TileLogicStack) ServerBlockContextRO.Logic.super.getTilesOrNull(face); - } - } @Override diff --git a/src/main/java/ru/windcorp/progressia/server/world/context/ServerBlockContextRO.java b/src/main/java/ru/windcorp/progressia/server/world/context/ServerBlockContextRO.java index 1ffb30d..ca2e09f 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/context/ServerBlockContextRO.java +++ b/src/main/java/ru/windcorp/progressia/server/world/context/ServerBlockContextRO.java @@ -20,16 +20,13 @@ package ru.windcorp.progressia.server.world.context; import ru.windcorp.progressia.common.world.context.BlockDataContextRO; import ru.windcorp.progressia.common.world.entity.EntityData; import ru.windcorp.progressia.common.world.generic.context.BlockGenericContextRO; -import ru.windcorp.progressia.server.world.ChunkLogicRO; -import ru.windcorp.progressia.server.world.TileLogicReferenceRO; -import ru.windcorp.progressia.server.world.TileLogicStackRO; import ru.windcorp.progressia.server.world.block.BlockLogic; import ru.windcorp.progressia.server.world.tile.TileLogic; public interface ServerBlockContextRO extends ServerWorldContextRO, BlockDataContextRO { - public interface Logic extends ServerWorldContextRO.Logic, - BlockGenericContextRO { + public interface Logic + extends ServerWorldContextRO.Logic, BlockGenericContextRO { @Override ServerBlockContextRO data(); diff --git a/src/main/java/ru/windcorp/progressia/server/world/context/ServerBlockFaceContext.java b/src/main/java/ru/windcorp/progressia/server/world/context/ServerBlockFaceContext.java index 335e15f..499408d 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/context/ServerBlockFaceContext.java +++ b/src/main/java/ru/windcorp/progressia/server/world/context/ServerBlockFaceContext.java @@ -18,7 +18,6 @@ package ru.windcorp.progressia.server.world.context; import ru.windcorp.progressia.common.world.context.BlockFaceDataContext; -import ru.windcorp.progressia.server.world.TileLogicStack; public interface ServerBlockFaceContext extends BlockFaceDataContext, ServerBlockContext, ServerBlockFaceContextRO { @@ -27,11 +26,6 @@ public interface ServerBlockFaceContext extends BlockFaceDataContext, ServerBloc @Override ServerBlockFaceContext data(); - @Override - default TileLogicStack getTilesOrNull() { - return (TileLogicStack) ServerBlockFaceContextRO.Logic.super.getTilesOrNull(); - } - } @Override diff --git a/src/main/java/ru/windcorp/progressia/server/world/context/ServerBlockFaceContextRO.java b/src/main/java/ru/windcorp/progressia/server/world/context/ServerBlockFaceContextRO.java index 7fca1db..b1a3f05 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/context/ServerBlockFaceContextRO.java +++ b/src/main/java/ru/windcorp/progressia/server/world/context/ServerBlockFaceContextRO.java @@ -20,16 +20,13 @@ package ru.windcorp.progressia.server.world.context; import ru.windcorp.progressia.common.world.context.BlockFaceDataContextRO; import ru.windcorp.progressia.common.world.entity.EntityData; import ru.windcorp.progressia.common.world.generic.context.BlockFaceGenericContextRO; -import ru.windcorp.progressia.server.world.ChunkLogicRO; -import ru.windcorp.progressia.server.world.TileLogicReferenceRO; -import ru.windcorp.progressia.server.world.TileLogicStackRO; import ru.windcorp.progressia.server.world.block.BlockLogic; import ru.windcorp.progressia.server.world.tile.TileLogic; public interface ServerBlockFaceContextRO extends ServerBlockContextRO, BlockFaceDataContextRO { - public interface Logic extends ServerBlockContextRO.Logic, - BlockFaceGenericContextRO { + public interface Logic + extends ServerBlockContextRO.Logic, BlockFaceGenericContextRO { @Override ServerBlockFaceContextRO data(); diff --git a/src/main/java/ru/windcorp/progressia/server/world/context/ServerContext.java b/src/main/java/ru/windcorp/progressia/server/world/context/ServerContext.java index bb218ab..052718f 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/context/ServerContext.java +++ b/src/main/java/ru/windcorp/progressia/server/world/context/ServerContext.java @@ -51,9 +51,7 @@ public interface ServerContext extends Context { * * @return the length of the last server tick */ - default double getTickLength() { - return getServer().getTickLength(); - } + double getTickLength(); /** * Adjusts the provided value according to tick length assuming the value diff --git a/src/main/java/ru/windcorp/progressia/server/world/context/ServerTileContext.java b/src/main/java/ru/windcorp/progressia/server/world/context/ServerTileContext.java index 5d5a3c0..7682287 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/context/ServerTileContext.java +++ b/src/main/java/ru/windcorp/progressia/server/world/context/ServerTileContext.java @@ -18,7 +18,6 @@ package ru.windcorp.progressia.server.world.context; import ru.windcorp.progressia.common.world.context.TileDataContext; -import ru.windcorp.progressia.server.world.TileLogicReference; public interface ServerTileContext extends TileDataContext, ServerBlockFaceContext, ServerTileContextRO { @@ -27,11 +26,6 @@ public interface ServerTileContext extends TileDataContext, ServerBlockFaceConte @Override ServerTileContext data(); - @Override - default TileLogicReference getTileReference() { - return (TileLogicReference) ServerTileContextRO.Logic.super.getTileReference(); - } - } @Override diff --git a/src/main/java/ru/windcorp/progressia/server/world/context/ServerTileContextRO.java b/src/main/java/ru/windcorp/progressia/server/world/context/ServerTileContextRO.java index 73b8d2c..b5a42df 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/context/ServerTileContextRO.java +++ b/src/main/java/ru/windcorp/progressia/server/world/context/ServerTileContextRO.java @@ -20,16 +20,13 @@ package ru.windcorp.progressia.server.world.context; import ru.windcorp.progressia.common.world.context.TileDataContextRO; import ru.windcorp.progressia.common.world.entity.EntityData; import ru.windcorp.progressia.common.world.generic.context.TileGenericContextRO; -import ru.windcorp.progressia.server.world.ChunkLogicRO; -import ru.windcorp.progressia.server.world.TileLogicReferenceRO; -import ru.windcorp.progressia.server.world.TileLogicStackRO; import ru.windcorp.progressia.server.world.block.BlockLogic; import ru.windcorp.progressia.server.world.tile.TileLogic; public interface ServerTileContextRO extends ServerBlockFaceContextRO, TileDataContextRO { - public interface Logic extends ServerBlockFaceContextRO.Logic, - TileGenericContextRO { + public interface Logic + extends ServerBlockFaceContextRO.Logic, TileGenericContextRO { @Override ServerTileContextRO data(); diff --git a/src/main/java/ru/windcorp/progressia/server/world/context/ServerWorldContext.java b/src/main/java/ru/windcorp/progressia/server/world/context/ServerWorldContext.java index ee04242..b8504c4 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/context/ServerWorldContext.java +++ b/src/main/java/ru/windcorp/progressia/server/world/context/ServerWorldContext.java @@ -17,22 +17,14 @@ */ package ru.windcorp.progressia.server.world.context; -import glm.vec._3.i.Vec3i; import ru.windcorp.progressia.common.world.context.WorldDataContext; -import ru.windcorp.progressia.common.world.rels.BlockFace; -import ru.windcorp.progressia.server.world.TileLogicStack; -import ru.windcorp.progressia.server.world.WorldLogic; public interface ServerWorldContext extends WorldDataContext, ServerWorldContextRO { - public interface Logic extends ServerWorldContextRO.Logic, - WorldLogic { + public interface Logic extends ServerWorldContextRO.Logic { @Override ServerWorldContext data(); - - @Override - TileLogicStack getTiles(Vec3i blockInWorld, BlockFace face); } diff --git a/src/main/java/ru/windcorp/progressia/server/world/context/ServerWorldContextRO.java b/src/main/java/ru/windcorp/progressia/server/world/context/ServerWorldContextRO.java index 43eeedc..0202024 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/context/ServerWorldContextRO.java +++ b/src/main/java/ru/windcorp/progressia/server/world/context/ServerWorldContextRO.java @@ -3,20 +3,12 @@ package ru.windcorp.progressia.server.world.context; import ru.windcorp.progressia.common.world.context.WorldDataContextRO; import ru.windcorp.progressia.common.world.entity.EntityData; import ru.windcorp.progressia.common.world.generic.context.WorldGenericContextRO; -import ru.windcorp.progressia.server.world.ChunkLogicRO; -import ru.windcorp.progressia.server.world.TileLogicReferenceRO; -import ru.windcorp.progressia.server.world.TileLogicStackRO; -import ru.windcorp.progressia.server.world.WorldLogicRO; import ru.windcorp.progressia.server.world.block.BlockLogic; import ru.windcorp.progressia.server.world.tile.TileLogic; public interface ServerWorldContextRO extends WorldDataContextRO, ServerContext { - public interface Logic - extends - WorldGenericContextRO, - WorldLogicRO, - ServerContext { + public interface Logic extends WorldGenericContextRO, ServerContext { /** * Acquires the data view of this context. Use this method to diff --git a/src/main/java/ru/windcorp/progressia/server/world/context/impl/ReusableServerContext.java b/src/main/java/ru/windcorp/progressia/server/world/context/impl/ReusableServerContext.java index fdffd22..6131776 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/context/impl/ReusableServerContext.java +++ b/src/main/java/ru/windcorp/progressia/server/world/context/impl/ReusableServerContext.java @@ -37,9 +37,14 @@ import ru.windcorp.progressia.server.world.context.ServerWorldContextRO; * when a {@link WorldLogic} (or a {@link WorldLogicRO}) instance requires a * context wrapper. *

    - * Use other unutilized instances of {@link ReusableServerContext} or + * Use other unutilized instances of {@code ReusableServerContext} or * {@link #empty()} static method to acquire a usable instance. *

    + * {@code ReusableServerContext} asserts that is it {@linkplain #isReal() real} + * and {@linkplain #isImmediate() immediate}. It creates and provides an + * independent randomness source. The tick length is consulted with the server. + * Use wrappers to alter these properties. + *

    * This class defines the outward-facing safe interface of the actual * implementation located in {@link ReusableServerContextImpl}. The reasoning * for creating a subclass is to allow a single instance to implement both diff --git a/src/main/java/ru/windcorp/progressia/server/world/context/impl/ReusableServerContextImpl.java b/src/main/java/ru/windcorp/progressia/server/world/context/impl/ReusableServerContextImpl.java index 2336937..7e4545d 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/context/impl/ReusableServerContextImpl.java +++ b/src/main/java/ru/windcorp/progressia/server/world/context/impl/ReusableServerContextImpl.java @@ -23,7 +23,6 @@ import java.util.Random; import glm.vec._3.i.Vec3i; import ru.windcorp.progressia.common.state.StateChange; import ru.windcorp.progressia.common.state.StatefulObject; -import ru.windcorp.progressia.common.world.ChunkData; import ru.windcorp.progressia.common.world.GravityModel; import ru.windcorp.progressia.common.world.TileDataStack; import ru.windcorp.progressia.common.world.WorldData; @@ -34,10 +33,11 @@ import ru.windcorp.progressia.common.world.rels.BlockFace; import ru.windcorp.progressia.common.world.rels.RelFace; import ru.windcorp.progressia.common.world.tile.TileData; import ru.windcorp.progressia.server.Server; -import ru.windcorp.progressia.server.world.ChunkLogic; import ru.windcorp.progressia.server.world.TileLogicStack; import ru.windcorp.progressia.server.world.WorldLogic; +import ru.windcorp.progressia.server.world.block.BlockLogic; import ru.windcorp.progressia.server.world.context.ServerTileContext; +import ru.windcorp.progressia.server.world.tile.TileLogic; class ReusableServerContextImpl extends ReusableServerContext implements ReusableServerContextBuilders.Empty, ReusableServerContextBuilders.WithWorld, @@ -61,7 +61,13 @@ class ReusableServerContextImpl extends ReusableServerContext * The relevant {@link WorldLogic} instance. If this is {@code null}, the * role is {@link Role#NONE}. */ - protected WorldLogic world; + protected WorldLogic worldLogic; + + /** + * The {@link WorldData} accessible through {@link #worldLogic}. This field + * is kept always in sync with {@link #worldLogic}. + */ + protected WorldData worldData; /** * The relevant location. If this is {@code null}, the role is @@ -85,7 +91,12 @@ class ReusableServerContextImpl extends ReusableServerContext * The index of the relevant tile. This value is {@code -1} unless the role * is {@link Role#TILE}. */ - protected int index; + protected int layer; + + /** + * The {@link Random} instance exposed with {@link #getRandom()}. + */ + protected final Random random = new Random(); /** * Determines whether this object currently acts as a builder or a context. @@ -98,7 +109,7 @@ class ReusableServerContextImpl extends ReusableServerContext * ends. This is always 0 when the object is a builder. */ protected int subcontextDepth = 0; - + /** * The Logic view returned by {@link #logic()}. */ @@ -117,7 +128,7 @@ class ReusableServerContextImpl extends ReusableServerContext return Role.WORLD; if (blockFace == null) return Role.LOCATION; - if (index == -1) + if (layer == -1) return Role.TILE_STACK; return Role.TILE; } @@ -179,7 +190,7 @@ class ReusableServerContextImpl extends ReusableServerContext location.y, location.z, blockFace, - index + layer ); break; case TILE_STACK: @@ -216,10 +227,11 @@ class ReusableServerContextImpl extends ReusableServerContext } server = null; - world = null; + worldLogic = null; + worldData = null; location = null; blockFace = null; - index = -1; + layer = -1; isBuilder = true; @@ -246,7 +258,8 @@ class ReusableServerContextImpl extends ReusableServerContext public WithWorld in(Server server, WorldLogic world) { requireBuilderRole(Role.NONE); this.server = server; - this.world = world; + this.worldLogic = world; + this.worldData = world.getData(); return this; } @@ -272,11 +285,11 @@ class ReusableServerContextImpl extends ReusableServerContext this.blockFace = side; return this; } - + @Override public WithTileStack on(BlockFace side) { requireBuilderRole(Role.LOCATION); - this.blockFace = side.relativize(world.getData().getUp(location)); + this.blockFace = side.relativize(worldLogic.getData().getUp(location)); return this; } @@ -287,91 +300,10 @@ class ReusableServerContextImpl extends ReusableServerContext @Override public ReusableServerContext index(int index) { requireBuilderRole(Role.TILE_STACK); - this.index = index; + this.layer = index; return build(); } - /* - * ServerWorldContext.Logic STUFF - */ - - private class Logic implements ServerTileContext.Logic { - @Override - public boolean isReal() { - return ReusableServerContextImpl.this.isReal(); - } - - @Override - public Collection getChunks() { - return world.getChunks(); - } - - @Override - public Collection getEntities() { - return ReusableServerContextImpl.this.getEntities(); - } - - @Override - public EntityData getEntity(long entityId) { - return ReusableServerContextImpl.this.getEntity(entityId); - } - - @Override - public Server getServer() { - return ReusableServerContextImpl.this.getServer(); - } - - @Override - public Random getRandom() { - return ReusableServerContextImpl.this.getRandom(); - } - - @Override - public Vec3i getLocation() { - return ReusableServerContextImpl.this.getLocation(); - } - - @Override - public RelFace getFace() { - return ReusableServerContextImpl.this.getFace(); - } - - @Override - public int getLayer() { - return ReusableServerContextImpl.this.getLayer(); - } - - @Override - public TileLogicStack getTiles(Vec3i blockInWorld, BlockFace face) { - return world.getTiles(blockInWorld, face); - } - - @Override - public ChunkLogic getChunk(Vec3i pos) { - return world.getChunk(pos); - } - - @Override - public WorldData getData() { - return world.getData(); - } - - @Override - public ServerTileContext data() { - return ReusableServerContextImpl.this; - } - - @Override - public String toString() { - return ReusableServerContextImpl.this + ".Logic"; - } - } - - @Override - public Logic logic() { - return logic; - } - /* * LOCATION GETTERS */ @@ -381,139 +313,326 @@ class ReusableServerContextImpl extends ReusableServerContext assert requireContextRole(Role.WORLD); return server; } - + @Override public Vec3i getLocation() { assert requireContextRole(Role.LOCATION); return location; } - + @Override public RelFace getFace() { assert requireContextRole(Role.TILE_STACK); return blockFace; } - + @Override public int getLayer() { assert requireContextRole(Role.TILE); - return index; + return layer; } /* * RO CONTEXT INTERFACE */ - + @Override public boolean isReal() { assert requireContextRole(Role.WORLD); return true; } - + @Override public Random getRandom() { assert requireContextRole(Role.WORLD); - return server.getAdHocRandom(); + return random; } - + @Override - public ChunkData getChunk(Vec3i pos) { + public double getTickLength() { assert requireContextRole(Role.WORLD); - return world.getData().getChunk(pos); + return server.getTickLength(); } - + @Override - public Collection getChunks() { + public BlockData getBlock(Vec3i location) { assert requireContextRole(Role.WORLD); - return world.getData().getChunks(); + return worldData.getBlock(location); } - + + @Override + public boolean isLocationLoaded(Vec3i location) { + assert requireContextRole(Role.WORLD); + return worldData.isLocationLoaded(location); + } + + @Override + public TileData getTile(Vec3i location, BlockFace face, int layer) { + assert requireContextRole(Role.WORLD); + return worldData.getTile(location, face, layer); + } + + @Override + public boolean hasTile(Vec3i location, BlockFace face, int layer) { + assert requireContextRole(Role.WORLD); + return worldData.hasTile(location, face, layer); + } + + @Override + public TileData getTileByTag(Vec3i location, BlockFace face, int tag) { + assert requireContextRole(Role.WORLD); + TileDataStack stack = worldData.getTilesOrNull(location, face); + if (stack == null) + return null; + int layer = stack.getIndexByTag(tag); + if (layer == -1) + return null; + return stack.get(layer); + } + + @Override + public boolean isTagValid(Vec3i location, BlockFace face, int tag) { + assert requireContextRole(Role.WORLD); + TileDataStack stack = worldData.getTilesOrNull(location, face); + if (stack == null) + return false; + return stack.getIndexByTag(tag) != -1; + } + + @Override + public int getTag() { + assert requireContextRole(Role.TILE); + TileDataStack stack = worldData.getTilesOrNull(location, blockFace); + if (stack == null) + return -1; + return stack.getTagByIndex(layer); + } + + @Override + public int getTileCount(Vec3i location, BlockFace face) { + assert requireContextRole(Role.TILE_STACK); + TileDataStack stack = worldData.getTilesOrNull(location, blockFace); + if (stack == null) + return 0; + return stack.size(); + } + @Override public Collection getEntities() { assert requireContextRole(Role.WORLD); - return world.getEntities(); + return worldData.getEntities(); } - + @Override public EntityData getEntity(long entityId) { assert requireContextRole(Role.WORLD); - return world.getEntity(entityId); + return worldData.getEntity(entityId); } - + @Override public GravityModel getGravityModel() { assert requireContextRole(Role.WORLD); - return world.getData().getGravityModel(); + return worldData.getGravityModel(); } - + @Override public float getTime() { assert requireContextRole(Role.WORLD); - return world.getData().getTime(); + return worldData.getTime(); } - /* - * RO CONTEXT OPTIMIZATIONS - */ - /* * RW CONTEXT INTERFACE */ - + @Override public boolean isImmediate() { assert requireContextRole(Role.WORLD); return true; } - + @Override - public void setBlock(Vec3i blockInWorld, BlockData block, boolean notify) { + public void setBlock(Vec3i blockInWorld, BlockData block) { assert requireContextRole(Role.WORLD); - world.getData().setBlock(blockInWorld, block, notify); + worldData.setBlock(blockInWorld, block, true); } - + @Override public void addTile(Vec3i location, BlockFace face, TileData tile) { assert requireContextRole(Role.WORLD); - world.getData().getTiles(location, face).addFarthest(tile); + worldData.getTiles(location, face).addFarthest(tile); } - + @Override public void removeTile(Vec3i location, BlockFace face, int tag) { assert requireContextRole(Role.WORLD); - TileDataStack stack = world.getData().getTilesOrNull(location, face); - if (stack == null) return; - int index = stack.getIndexByTag(tag); - if (index == -1) return; - stack.remove(index); + TileDataStack stack = worldData.getTilesOrNull(location, face); + if (stack == null) + return; + int layer = stack.getIndexByTag(tag); + if (layer == -1) + return; + stack.remove(layer); } - + @Override public void addEntity(EntityData entity) { assert requireContextRole(Role.WORLD); - world.getData().addEntity(entity); + worldData.addEntity(entity); } - + @Override public void removeEntity(long entityId) { assert requireContextRole(Role.WORLD); - world.getData().removeEntity(entityId); + worldData.removeEntity(entityId); } - + @Override public void changeEntity(SE entity, StateChange change) { assert requireContextRole(Role.WORLD); - world.getData().changeEntity(entity, change); + worldData.changeEntity(entity, change); } - + @Override public void advanceTime(float change) { assert requireContextRole(Role.WORLD); - world.getData().advanceTime(change); + worldData.advanceTime(change); } /* - * RW CONTEXT OPTIMIZATIONS + * ServerWorldContext.Logic STUFF */ + private class Logic implements ServerTileContext.Logic { + + /* + * LOCATION GETTERS + */ + + @Override + public Server getServer() { + return server; + } + + @Override + public Vec3i getLocation() { + return location; + } + + @Override + public RelFace getFace() { + return blockFace; + } + + @Override + public int getLayer() { + return layer; + } + + /* + * RO CONTEXT INTERFACE + */ + + @Override + public boolean isReal() { + return true; + } + + @Override + public Random getRandom() { + return random; + } + + @Override + public double getTickLength() { + return server.getTickLength(); + } + + @Override + public BlockLogic getBlock(Vec3i location) { + assert requireContextRole(Role.WORLD); + return worldLogic.getBlock(location); + } + + @Override + public boolean isLocationLoaded(Vec3i location) { + return worldData.isLocationLoaded(location); + } + + @Override + public boolean hasTile(Vec3i location, BlockFace face, int layer) { + return worldData.hasTile(location, face, layer); + } + + @Override + public boolean isTagValid(Vec3i location, BlockFace face, int tag) { + return ReusableServerContextImpl.this.isTagValid(location, face, tag); + } + + @Override + public TileLogic getTile(Vec3i location, BlockFace face, int layer) { + assert requireContextRole(Role.WORLD); + return worldLogic.getTile(location, face, layer); + } + + @Override + public TileLogic getTileByTag(Vec3i location, BlockFace face, int tag) { + assert requireContextRole(Role.WORLD); + TileLogicStack stack = worldLogic.getTilesOrNull(location, face); + if (stack == null) { + return null; + } + int layer = stack.getIndexByTag(tag); + if (layer == -1) { + return null; + } + return stack.get(layer); + } + + @Override + public int getTileCount(Vec3i location, BlockFace face) { + assert requireContextRole(Role.WORLD); + TileLogicStack stack = worldLogic.getTilesOrNull(location, face); + if (stack == null) { + return 0; + } + return stack.size(); + } + + @Override + public int getTag() { + return ReusableServerContextImpl.this.getTag(); + } + + @Override + public Collection getEntities() { + return worldLogic.getEntities(); + } + + @Override + public EntityData getEntity(long entityId) { + return worldLogic.getEntity(entityId); + } + + /* + * MISC + */ + + @Override + public ReusableServerContext data() { + return ReusableServerContextImpl.this; + } + + @Override + public String toString() { + return ReusableServerContextImpl.this + ".Logic"; + } + } + + @Override + public Logic logic() { + assert requireContextRole(Role.WORLD); + return logic; + } + } diff --git a/src/main/java/ru/windcorp/progressia/test/gen/surface/SurfaceWorld.java b/src/main/java/ru/windcorp/progressia/test/gen/surface/SurfaceWorld.java index 7d3ec10..43a218e 100644 --- a/src/main/java/ru/windcorp/progressia/test/gen/surface/SurfaceWorld.java +++ b/src/main/java/ru/windcorp/progressia/test/gen/surface/SurfaceWorld.java @@ -177,7 +177,7 @@ public class SurfaceWorld public boolean isBlockLoadedSfc(Vec3i surfaceBlockInWorld) { Vec3i blockInWorld = Vectors.grab3i(); resolve(surfaceBlockInWorld, blockInWorld); - boolean result = parent.isBlockLoaded(blockInWorld); + boolean result = parent.isLocationLoaded(blockInWorld); Vectors.release(blockInWorld); return result; } From 80541eafc3f5a415b95cd057afea5e8b9141cfe5 Mon Sep 17 00:00:00 2001 From: OLEGSHA Date: Thu, 5 Aug 2021 19:39:39 +0300 Subject: [PATCH 36/55] Renamed BlockFace contexts into TileStack contexts --- .../common/world/context/TileDataContext.java | 2 +- .../common/world/context/TileDataContextRO.java | 2 +- ...eDataContext.java => TileStackDataContext.java} | 8 ++++---- ...aContextRO.java => TileStackDataContextRO.java} | 6 +++--- .../generic/context/TileGenericContextRO.java | 2 +- .../generic/context/TileGenericContextWO.java | 2 +- ...ntextRO.java => TileStackGenericContextRO.java} | 2 +- ...ntextWO.java => TileStackGenericContextWO.java} | 2 +- .../world/generic/context/WorldContexts.java | 2 +- .../server/world/context/ServerTileContext.java | 4 ++-- .../server/world/context/ServerTileContextRO.java | 4 ++-- ...aceContext.java => ServerTileStackContext.java} | 10 +++++----- ...ontextRO.java => ServerTileStackContextRO.java} | 12 ++++++------ .../world/context/impl/ReusableServerContext.java | 14 +++----------- 14 files changed, 32 insertions(+), 40 deletions(-) rename src/main/java/ru/windcorp/progressia/common/world/context/{BlockFaceDataContext.java => TileStackDataContext.java} (82%) rename src/main/java/ru/windcorp/progressia/common/world/context/{BlockFaceDataContextRO.java => TileStackDataContextRO.java} (84%) rename src/main/java/ru/windcorp/progressia/common/world/generic/context/{BlockFaceGenericContextRO.java => TileStackGenericContextRO.java} (98%) rename src/main/java/ru/windcorp/progressia/common/world/generic/context/{BlockFaceGenericContextWO.java => TileStackGenericContextWO.java} (98%) rename src/main/java/ru/windcorp/progressia/server/world/context/{ServerBlockFaceContext.java => ServerTileStackContext.java} (73%) rename src/main/java/ru/windcorp/progressia/server/world/context/{ServerBlockFaceContextRO.java => ServerTileStackContextRO.java} (73%) diff --git a/src/main/java/ru/windcorp/progressia/common/world/context/TileDataContext.java b/src/main/java/ru/windcorp/progressia/common/world/context/TileDataContext.java index 3f4a0d6..78538c4 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/context/TileDataContext.java +++ b/src/main/java/ru/windcorp/progressia/common/world/context/TileDataContext.java @@ -24,7 +24,7 @@ import ru.windcorp.progressia.common.world.tile.TileData; public interface TileDataContext extends TileGenericContextWO, - BlockFaceDataContext, + TileStackDataContext, TileDataContextRO { // currently empty diff --git a/src/main/java/ru/windcorp/progressia/common/world/context/TileDataContextRO.java b/src/main/java/ru/windcorp/progressia/common/world/context/TileDataContextRO.java index e143e03..e9f2d41 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/context/TileDataContextRO.java +++ b/src/main/java/ru/windcorp/progressia/common/world/context/TileDataContextRO.java @@ -24,7 +24,7 @@ import ru.windcorp.progressia.common.world.tile.TileData; public interface TileDataContextRO extends TileGenericContextRO, - BlockFaceDataContextRO { + TileStackDataContextRO { // currently empty diff --git a/src/main/java/ru/windcorp/progressia/common/world/context/BlockFaceDataContext.java b/src/main/java/ru/windcorp/progressia/common/world/context/TileStackDataContext.java similarity index 82% rename from src/main/java/ru/windcorp/progressia/common/world/context/BlockFaceDataContext.java rename to src/main/java/ru/windcorp/progressia/common/world/context/TileStackDataContext.java index b12c36c..12ded3c 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/context/BlockFaceDataContext.java +++ b/src/main/java/ru/windcorp/progressia/common/world/context/TileStackDataContext.java @@ -19,13 +19,13 @@ package ru.windcorp.progressia.common.world.context; import ru.windcorp.progressia.common.world.block.BlockData; import ru.windcorp.progressia.common.world.entity.EntityData; -import ru.windcorp.progressia.common.world.generic.context.BlockFaceGenericContextWO; +import ru.windcorp.progressia.common.world.generic.context.TileStackGenericContextWO; import ru.windcorp.progressia.common.world.tile.TileData; -public interface BlockFaceDataContext - extends BlockFaceGenericContextWO, +public interface TileStackDataContext + extends TileStackGenericContextWO, BlockDataContext, - BlockFaceDataContextRO { + TileStackDataContextRO { // currently empty diff --git a/src/main/java/ru/windcorp/progressia/common/world/context/BlockFaceDataContextRO.java b/src/main/java/ru/windcorp/progressia/common/world/context/TileStackDataContextRO.java similarity index 84% rename from src/main/java/ru/windcorp/progressia/common/world/context/BlockFaceDataContextRO.java rename to src/main/java/ru/windcorp/progressia/common/world/context/TileStackDataContextRO.java index a20355a..1e3a46d 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/context/BlockFaceDataContextRO.java +++ b/src/main/java/ru/windcorp/progressia/common/world/context/TileStackDataContextRO.java @@ -19,11 +19,11 @@ package ru.windcorp.progressia.common.world.context; import ru.windcorp.progressia.common.world.block.BlockData; import ru.windcorp.progressia.common.world.entity.EntityData; -import ru.windcorp.progressia.common.world.generic.context.BlockFaceGenericContextRO; +import ru.windcorp.progressia.common.world.generic.context.TileStackGenericContextRO; import ru.windcorp.progressia.common.world.tile.TileData; -public interface BlockFaceDataContextRO - extends BlockFaceGenericContextRO, +public interface TileStackDataContextRO + extends TileStackGenericContextRO, BlockDataContext { // currently empty diff --git a/src/main/java/ru/windcorp/progressia/common/world/generic/context/TileGenericContextRO.java b/src/main/java/ru/windcorp/progressia/common/world/generic/context/TileGenericContextRO.java index daf7fb8..bdc5b69 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/generic/context/TileGenericContextRO.java +++ b/src/main/java/ru/windcorp/progressia/common/world/generic/context/TileGenericContextRO.java @@ -30,7 +30,7 @@ public interface TileGenericContextRO< B extends BlockGeneric, T extends TileGeneric, E extends EntityGeneric -> extends WorldContexts.Tile, BlockFaceGenericContextRO { +> extends WorldContexts.Tile, TileStackGenericContextRO { //@formatter:on /** diff --git a/src/main/java/ru/windcorp/progressia/common/world/generic/context/TileGenericContextWO.java b/src/main/java/ru/windcorp/progressia/common/world/generic/context/TileGenericContextWO.java index 4c2b4dd..ae8a2ff 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/generic/context/TileGenericContextWO.java +++ b/src/main/java/ru/windcorp/progressia/common/world/generic/context/TileGenericContextWO.java @@ -32,7 +32,7 @@ public interface TileGenericContextWO< B extends BlockGeneric, T extends TileGeneric, E extends EntityGeneric -> extends WorldContexts.Tile, BlockFaceGenericContextWO { +> extends WorldContexts.Tile, TileStackGenericContextWO { //@formatter:on /** diff --git a/src/main/java/ru/windcorp/progressia/common/world/generic/context/BlockFaceGenericContextRO.java b/src/main/java/ru/windcorp/progressia/common/world/generic/context/TileStackGenericContextRO.java similarity index 98% rename from src/main/java/ru/windcorp/progressia/common/world/generic/context/BlockFaceGenericContextRO.java rename to src/main/java/ru/windcorp/progressia/common/world/generic/context/TileStackGenericContextRO.java index 0ca350a..082788b 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/generic/context/BlockFaceGenericContextRO.java +++ b/src/main/java/ru/windcorp/progressia/common/world/generic/context/TileStackGenericContextRO.java @@ -26,7 +26,7 @@ import ru.windcorp.progressia.common.world.generic.*; * not actually exist. */ //@formatter:off -public interface BlockFaceGenericContextRO< +public interface TileStackGenericContextRO< B extends BlockGeneric, T extends TileGeneric, E extends EntityGeneric diff --git a/src/main/java/ru/windcorp/progressia/common/world/generic/context/BlockFaceGenericContextWO.java b/src/main/java/ru/windcorp/progressia/common/world/generic/context/TileStackGenericContextWO.java similarity index 98% rename from src/main/java/ru/windcorp/progressia/common/world/generic/context/BlockFaceGenericContextWO.java rename to src/main/java/ru/windcorp/progressia/common/world/generic/context/TileStackGenericContextWO.java index dd6c5ad..28c87ee 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/generic/context/BlockFaceGenericContextWO.java +++ b/src/main/java/ru/windcorp/progressia/common/world/generic/context/TileStackGenericContextWO.java @@ -28,7 +28,7 @@ import ru.windcorp.progressia.common.world.generic.*; * stack may or may not actually exist. */ //@formatter:off -public interface BlockFaceGenericContextWO< +public interface TileStackGenericContextWO< B extends BlockGeneric, T extends TileGeneric, E extends EntityGeneric diff --git a/src/main/java/ru/windcorp/progressia/common/world/generic/context/WorldContexts.java b/src/main/java/ru/windcorp/progressia/common/world/generic/context/WorldContexts.java index 69c5f94..4dd8c19 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/generic/context/WorldContexts.java +++ b/src/main/java/ru/windcorp/progressia/common/world/generic/context/WorldContexts.java @@ -78,7 +78,7 @@ class WorldContexts { /** * A {@link Context} with a world instance, a block location and a block face * (block side). This interface should not be implemented directly; see - * {@link BlockFaceGenericContextRO} or {@link BlockFaceGenericContextWO}. + * {@link TileStackGenericContextRO} or {@link TileStackGenericContextWO}. * * @author javapony * diff --git a/src/main/java/ru/windcorp/progressia/server/world/context/ServerTileContext.java b/src/main/java/ru/windcorp/progressia/server/world/context/ServerTileContext.java index 7682287..bc5fe6c 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/context/ServerTileContext.java +++ b/src/main/java/ru/windcorp/progressia/server/world/context/ServerTileContext.java @@ -19,9 +19,9 @@ package ru.windcorp.progressia.server.world.context; import ru.windcorp.progressia.common.world.context.TileDataContext; -public interface ServerTileContext extends TileDataContext, ServerBlockFaceContext, ServerTileContextRO { +public interface ServerTileContext extends TileDataContext, ServerTileStackContext, ServerTileContextRO { - public interface Logic extends ServerTileContextRO.Logic, ServerBlockFaceContext.Logic { + public interface Logic extends ServerTileContextRO.Logic, ServerTileStackContext.Logic { @Override ServerTileContext data(); diff --git a/src/main/java/ru/windcorp/progressia/server/world/context/ServerTileContextRO.java b/src/main/java/ru/windcorp/progressia/server/world/context/ServerTileContextRO.java index b5a42df..87faf0c 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/context/ServerTileContextRO.java +++ b/src/main/java/ru/windcorp/progressia/server/world/context/ServerTileContextRO.java @@ -23,10 +23,10 @@ import ru.windcorp.progressia.common.world.generic.context.TileGenericContextRO; import ru.windcorp.progressia.server.world.block.BlockLogic; import ru.windcorp.progressia.server.world.tile.TileLogic; -public interface ServerTileContextRO extends ServerBlockFaceContextRO, TileDataContextRO { +public interface ServerTileContextRO extends ServerTileStackContextRO, TileDataContextRO { public interface Logic - extends ServerBlockFaceContextRO.Logic, TileGenericContextRO { + extends ServerTileStackContextRO.Logic, TileGenericContextRO { @Override ServerTileContextRO data(); diff --git a/src/main/java/ru/windcorp/progressia/server/world/context/ServerBlockFaceContext.java b/src/main/java/ru/windcorp/progressia/server/world/context/ServerTileStackContext.java similarity index 73% rename from src/main/java/ru/windcorp/progressia/server/world/context/ServerBlockFaceContext.java rename to src/main/java/ru/windcorp/progressia/server/world/context/ServerTileStackContext.java index 499408d..938271b 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/context/ServerBlockFaceContext.java +++ b/src/main/java/ru/windcorp/progressia/server/world/context/ServerTileStackContext.java @@ -17,18 +17,18 @@ */ package ru.windcorp.progressia.server.world.context; -import ru.windcorp.progressia.common.world.context.BlockFaceDataContext; +import ru.windcorp.progressia.common.world.context.TileStackDataContext; -public interface ServerBlockFaceContext extends BlockFaceDataContext, ServerBlockContext, ServerBlockFaceContextRO { +public interface ServerTileStackContext extends TileStackDataContext, ServerBlockContext, ServerTileStackContextRO { - public interface Logic extends ServerBlockFaceContextRO.Logic, ServerBlockContext.Logic { + public interface Logic extends ServerTileStackContextRO.Logic, ServerBlockContext.Logic { @Override - ServerBlockFaceContext data(); + ServerTileStackContext data(); } @Override - ServerBlockFaceContext.Logic logic(); + ServerTileStackContext.Logic logic(); } diff --git a/src/main/java/ru/windcorp/progressia/server/world/context/ServerBlockFaceContextRO.java b/src/main/java/ru/windcorp/progressia/server/world/context/ServerTileStackContextRO.java similarity index 73% rename from src/main/java/ru/windcorp/progressia/server/world/context/ServerBlockFaceContextRO.java rename to src/main/java/ru/windcorp/progressia/server/world/context/ServerTileStackContextRO.java index b1a3f05..0b33933 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/context/ServerBlockFaceContextRO.java +++ b/src/main/java/ru/windcorp/progressia/server/world/context/ServerTileStackContextRO.java @@ -17,23 +17,23 @@ */ package ru.windcorp.progressia.server.world.context; -import ru.windcorp.progressia.common.world.context.BlockFaceDataContextRO; +import ru.windcorp.progressia.common.world.context.TileStackDataContextRO; import ru.windcorp.progressia.common.world.entity.EntityData; -import ru.windcorp.progressia.common.world.generic.context.BlockFaceGenericContextRO; +import ru.windcorp.progressia.common.world.generic.context.TileStackGenericContextRO; import ru.windcorp.progressia.server.world.block.BlockLogic; import ru.windcorp.progressia.server.world.tile.TileLogic; -public interface ServerBlockFaceContextRO extends ServerBlockContextRO, BlockFaceDataContextRO { +public interface ServerTileStackContextRO extends ServerBlockContextRO, TileStackDataContextRO { public interface Logic - extends ServerBlockContextRO.Logic, BlockFaceGenericContextRO { + extends ServerBlockContextRO.Logic, TileStackGenericContextRO { @Override - ServerBlockFaceContextRO data(); + ServerTileStackContextRO data(); } @Override - ServerBlockFaceContextRO.Logic logic(); + ServerTileStackContextRO.Logic logic(); } diff --git a/src/main/java/ru/windcorp/progressia/server/world/context/impl/ReusableServerContext.java b/src/main/java/ru/windcorp/progressia/server/world/context/impl/ReusableServerContext.java index 6131776..345ff37 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/context/impl/ReusableServerContext.java +++ b/src/main/java/ru/windcorp/progressia/server/world/context/impl/ReusableServerContext.java @@ -20,15 +20,7 @@ package ru.windcorp.progressia.server.world.context.impl; import ru.windcorp.progressia.common.world.context.Context; import ru.windcorp.progressia.server.world.WorldLogic; import ru.windcorp.progressia.server.world.WorldLogicRO; -import ru.windcorp.progressia.server.world.context.ServerBlockContext; -import ru.windcorp.progressia.server.world.context.ServerBlockContextRO; -import ru.windcorp.progressia.server.world.context.ServerBlockFaceContext; -import ru.windcorp.progressia.server.world.context.ServerBlockFaceContextRO; -import ru.windcorp.progressia.server.world.context.ServerContext; -import ru.windcorp.progressia.server.world.context.ServerTileContext; -import ru.windcorp.progressia.server.world.context.ServerTileContextRO; -import ru.windcorp.progressia.server.world.context.ServerWorldContext; -import ru.windcorp.progressia.server.world.context.ServerWorldContextRO; +import ru.windcorp.progressia.server.world.context.*; /** * An implementation of the entire {@link ServerContext} tree. The objects of @@ -75,8 +67,8 @@ public abstract class ReusableServerContext implements ServerTileContext { */ LOCATION, /** - * This object conforms to {@link ServerBlockFaceContext} or - * {@link ServerBlockFaceContextRO}. + * This object conforms to {@link ServerTileStackContext} or + * {@link ServerTileStackContextRO}. */ TILE_STACK, /** From 15f741bc04bb4e3a792e61cae158f48c0a6a4db0 Mon Sep 17 00:00:00 2001 From: OLEGSHA Date: Fri, 6 Aug 2021 10:49:40 +0300 Subject: [PATCH 37/55] Added subcontexting. Context#subcontexting. --- .../world/context/BlockDataContext.java | 32 ++- .../world/context/BlockDataContextRO.java | 32 ++- .../common/world/context/Context.java | 84 +++++--- .../common/world/context/TileDataContext.java | 14 +- .../world/context/TileDataContextRO.java | 14 +- .../world/context/TileStackDataContext.java | 21 +- .../world/context/TileStackDataContextRO.java | 21 +- .../world/context/WorldDataContext.java | 15 ++ .../world/context/WorldDataContextRO.java | 15 ++ .../generic/context/AbstractContextRO.java | 95 +++++++++ .../context/BlockGenericContextRO.java | 32 +++ .../context/BlockGenericContextWO.java | 32 +++ .../generic/context/TileGenericContextRO.java | 14 ++ .../generic/context/TileGenericContextWO.java | 14 ++ .../context/TileStackGenericContextRO.java | 21 +- .../context/TileStackGenericContextWO.java | 21 +- .../world/generic/context/WorldContexts.java | 197 ++++++++++++++++-- .../context/WorldGenericContextRO.java | 14 ++ .../context/WorldGenericContextWO.java | 14 ++ .../world/context/ServerBlockContext.java | 53 +++++ .../world/context/ServerBlockContextRO.java | 53 +++++ .../world/context/ServerTileContext.java | 20 ++ .../world/context/ServerTileContextRO.java | 20 ++ .../world/context/ServerTileStackContext.java | 30 +++ .../context/ServerTileStackContextRO.java | 30 +++ .../world/context/ServerWorldContext.java | 20 ++ .../world/context/ServerWorldContextRO.java | 20 ++ .../context/impl/ReusableServerContext.java | 31 ++- .../impl/ReusableServerContextImpl.java | 109 +++++----- 29 files changed, 978 insertions(+), 110 deletions(-) create mode 100644 src/main/java/ru/windcorp/progressia/common/world/generic/context/AbstractContextRO.java diff --git a/src/main/java/ru/windcorp/progressia/common/world/context/BlockDataContext.java b/src/main/java/ru/windcorp/progressia/common/world/context/BlockDataContext.java index 3462048..9667eac 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/context/BlockDataContext.java +++ b/src/main/java/ru/windcorp/progressia/common/world/context/BlockDataContext.java @@ -17,9 +17,12 @@ */ package ru.windcorp.progressia.common.world.context; +import glm.vec._3.i.Vec3i; import ru.windcorp.progressia.common.world.block.BlockData; import ru.windcorp.progressia.common.world.entity.EntityData; import ru.windcorp.progressia.common.world.generic.context.BlockGenericContextWO; +import ru.windcorp.progressia.common.world.rels.AbsRelation; +import ru.windcorp.progressia.common.world.rels.RelFace; import ru.windcorp.progressia.common.world.tile.TileData; public interface BlockDataContext @@ -27,6 +30,33 @@ public interface BlockDataContext WorldDataContext, BlockDataContextRO { - // currently empty + /* + * Subcontexting + */ + + @Override + default BlockDataContext pushRelative(int dx, int dy, int dz) { + return push(getLocation().add_(dx, dy, dz)); + } + + @Override + default BlockDataContext pushRelative(Vec3i direction) { + return push(getLocation().add_(direction)); + } + + @Override + default BlockDataContext pushRelative(AbsRelation direction) { + return push(direction.getVector()); + } + + @Override + default TileStackDataContext push(RelFace face) { + return push(getLocation(), face); + } + + @Override + default TileDataContext push(RelFace face, int layer) { + return push(getLocation(), face, layer); + } } diff --git a/src/main/java/ru/windcorp/progressia/common/world/context/BlockDataContextRO.java b/src/main/java/ru/windcorp/progressia/common/world/context/BlockDataContextRO.java index 70ad8f4..7d35ec3 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/context/BlockDataContextRO.java +++ b/src/main/java/ru/windcorp/progressia/common/world/context/BlockDataContextRO.java @@ -17,15 +17,45 @@ */ package ru.windcorp.progressia.common.world.context; +import glm.vec._3.i.Vec3i; import ru.windcorp.progressia.common.world.block.BlockData; import ru.windcorp.progressia.common.world.entity.EntityData; import ru.windcorp.progressia.common.world.generic.context.BlockGenericContextRO; +import ru.windcorp.progressia.common.world.rels.AbsRelation; +import ru.windcorp.progressia.common.world.rels.RelFace; import ru.windcorp.progressia.common.world.tile.TileData; public interface BlockDataContextRO extends BlockGenericContextRO, WorldDataContextRO { - // currently empty + /* + * Subcontexting + */ + + @Override + default BlockDataContextRO pushRelative(int dx, int dy, int dz) { + return push(getLocation().add_(dx, dy, dz)); + } + + @Override + default BlockDataContextRO pushRelative(Vec3i direction) { + return push(getLocation().add_(direction)); + } + + @Override + default BlockDataContextRO pushRelative(AbsRelation direction) { + return push(direction.getVector()); + } + + @Override + default TileStackDataContextRO push(RelFace face) { + return push(getLocation(), face); + } + + @Override + default TileDataContextRO push(RelFace face, int layer) { + return push(getLocation(), face, layer); + } } diff --git a/src/main/java/ru/windcorp/progressia/common/world/context/Context.java b/src/main/java/ru/windcorp/progressia/common/world/context/Context.java index bfbd164..73644ea 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/context/Context.java +++ b/src/main/java/ru/windcorp/progressia/common/world/context/Context.java @@ -17,11 +17,15 @@ */ package ru.windcorp.progressia.common.world.context; +import ru.windcorp.progressia.common.world.generic.context.AbstractContextRO; + /** * A cursor-like object for retrieving information about an in-game environment. * A context object typically holds a reference to some sort of data structure * and a cursor pointing to a location in that data structure. The exact meaning - * of "environment" and "location" is defined by extending interfaces. + * of "environment" and "location" is defined by extending interfaces. The terms + * relevant and implied should be understood to refer to the + * aforementioned location. *

    * Context objects are intended to be the primary way of interacting for in-game * content. Wherever possible, context objects should be preferred over other @@ -41,37 +45,48 @@ package ru.windcorp.progressia.common.world.context; * thread-safe and are often pooled and reused. *

    *

    Subcontexting

    - * Subcontexting is the invocation of user-provided code with a context - * object derived from an existing one. For example, block context provides a - * convenience method for referencing the block's neighbor: + * Context objects allow subcontexting. Subcontexting is the temporary + * modification of the context object. Contexts use a stack approach to + * modification: all modifications must be reverted in the reversed order they + * were applied. + *

    + * Modification methods are usually named {@code pushXXX}. To revert + * the most recent non-reverted modification, use {@link #pop()}. As a general + * rule, a method that is given a context must always {@link #pop()} every + * change it has pushed. Failure to abide by this contract results in bugs that + * is difficult to trace. + *

    + * Although various push methods declare differing result types, the same object + * is always returned: * *

    - * blockContextA.forNeighbor(RelFace.UP, blockContextB -> {
    - * 	foo(blockContextA); // undefined behavior!
    - * 	foo(blockContextB); // correct
    - * });
    + * someContext.pushXXX() == someContext
      * 
    * - * In this example, {@code forNeighbor} is a subcontexting method, - * {@code blockContextA} is the parent context, {@code blockContextB} is the - * subcontext, and the lambda is the context consumer. - *

    - * Parent contexts are invalid while the subcontexting method is - * running. Referencing {@code blockContextA} from inside the lambda - * creates undefined behavior. - *

    - * This restriction exists because some implementations of contexts may - * implement subcontexting by simply modifying the parent context for the - * duration of the call and presenting the temporarily modified parent context - * as the subcontext: + * Therefore invoking {@link #pop()} is valid using both the original reference + * and the obtained reference. + *

    Subcontexting example

    + * Given a {@link ru.windcorp.progressia.common.world.context.BlockDataContext + * BlockDataContext} {@code a} one can process the tile stack on the top of the + * relevant block by using * *
    - * public void forNeighbor(BlockFace face, Consumer<BlockContext> action) {
    - * 	this.position.add(face);
    - * 	action.accept(this);
    - * 	this.position.sub(face);
    - * }
    + * TileStackDataContext b = a.push(RelFace.TOP);
    + * processTileStack(b);
    + * b.pop();
      * 
    + * + * One can improve readability by eliminating the temporary variable: + * + *
    + * processTileStack(a.push(RelFace.TOP));
    + * a.pop();
    + * 
    + * + * Notice that {@code a.pop()} and {@code b.pop()} are interchangeable. + * + * @see AbstractContextRO + * @author javapony */ public interface Context { @@ -102,4 +117,23 @@ public interface Context { */ boolean isReal(); + /** + * Reverts the more recent modification to this object that has not been + * reverted yet. + *

    + * Context objects may be modified temporarily with various push methods + * (see subcontexting). To revert the most + * recent non-reverted modification, use {@link #pop()}. As a general rule, + * a method that is given a context must always {@link #pop()} every change + * it has pushed. Failure to abide by this contract results in bugs that is + * difficult to trace. + *

    + * This method may be invoked using either the original reference or the + * reference provided by push method. + *

    + * This method fails with an {@link IllegalStateException} when there are no + * modifications to revert. + */ + void pop(); + } diff --git a/src/main/java/ru/windcorp/progressia/common/world/context/TileDataContext.java b/src/main/java/ru/windcorp/progressia/common/world/context/TileDataContext.java index 78538c4..b424b2f 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/context/TileDataContext.java +++ b/src/main/java/ru/windcorp/progressia/common/world/context/TileDataContext.java @@ -27,6 +27,18 @@ public interface TileDataContext TileStackDataContext, TileDataContextRO { - // currently empty + /* + * Subcontexting + */ + + @Override + default TileDataContext pushCloser() { + return push(getLocation(), getFace(), getLayer() - 1); + } + + @Override + default TileDataContext pushFarther() { + return push(getLocation(), getFace(), getLayer() + 1); + } } diff --git a/src/main/java/ru/windcorp/progressia/common/world/context/TileDataContextRO.java b/src/main/java/ru/windcorp/progressia/common/world/context/TileDataContextRO.java index e9f2d41..f6979e2 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/context/TileDataContextRO.java +++ b/src/main/java/ru/windcorp/progressia/common/world/context/TileDataContextRO.java @@ -26,6 +26,18 @@ public interface TileDataContextRO extends TileGenericContextRO, TileStackDataContextRO { - // currently empty + /* + * Subcontexting + */ + + @Override + default TileDataContextRO pushCloser() { + return push(getLocation(), getFace(), getLayer() - 1); + } + + @Override + default TileDataContextRO pushFarther() { + return push(getLocation(), getFace(), getLayer() + 1); + } } diff --git a/src/main/java/ru/windcorp/progressia/common/world/context/TileStackDataContext.java b/src/main/java/ru/windcorp/progressia/common/world/context/TileStackDataContext.java index 12ded3c..1751a50 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/context/TileStackDataContext.java +++ b/src/main/java/ru/windcorp/progressia/common/world/context/TileStackDataContext.java @@ -26,7 +26,24 @@ public interface TileStackDataContext extends TileStackGenericContextWO, BlockDataContext, TileStackDataContextRO { - - // currently empty + + /* + * Subcontexting + */ + + @Override + default TileDataContext push(int layer) { + return push(getLocation(), getFace(), layer); + } + + @Override + default TileStackDataContext pushCounter() { + return push(getFace().getCounter()); + } + + @Override + default TileStackDataContext pushOpposite() { + return push(getLocation().add_(getFace().getRelVector()), getFace().getCounter()); + } } diff --git a/src/main/java/ru/windcorp/progressia/common/world/context/TileStackDataContextRO.java b/src/main/java/ru/windcorp/progressia/common/world/context/TileStackDataContextRO.java index 1e3a46d..bcdb948 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/context/TileStackDataContextRO.java +++ b/src/main/java/ru/windcorp/progressia/common/world/context/TileStackDataContextRO.java @@ -24,8 +24,25 @@ import ru.windcorp.progressia.common.world.tile.TileData; public interface TileStackDataContextRO extends TileStackGenericContextRO, - BlockDataContext { + BlockDataContextRO { - // currently empty + /* + * Subcontexting + */ + + @Override + default TileDataContextRO push(int layer) { + return push(getLocation(), getFace(), layer); + } + + @Override + default TileStackDataContextRO pushCounter() { + return push(getFace().getCounter()); + } + + @Override + default TileStackDataContextRO pushOpposite() { + return push(getLocation().add_(getFace().getRelVector()), getFace().getCounter()); + } } diff --git a/src/main/java/ru/windcorp/progressia/common/world/context/WorldDataContext.java b/src/main/java/ru/windcorp/progressia/common/world/context/WorldDataContext.java index 68965b5..9dcb0ae 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/context/WorldDataContext.java +++ b/src/main/java/ru/windcorp/progressia/common/world/context/WorldDataContext.java @@ -17,9 +17,11 @@ */ package ru.windcorp.progressia.common.world.context; +import glm.vec._3.i.Vec3i; import ru.windcorp.progressia.common.world.block.BlockData; import ru.windcorp.progressia.common.world.entity.EntityData; import ru.windcorp.progressia.common.world.generic.context.WorldGenericContextWO; +import ru.windcorp.progressia.common.world.rels.RelFace; import ru.windcorp.progressia.common.world.tile.TileData; public interface WorldDataContext @@ -35,5 +37,18 @@ public interface WorldDataContext * @see #getTime() */ void advanceTime(float change); + + /* + * Subcontexting + */ + + @Override + BlockDataContext push(Vec3i location); + + @Override + TileStackDataContext push(Vec3i location, RelFace face); + + @Override + TileDataContext push(Vec3i location, RelFace face, int layer); } diff --git a/src/main/java/ru/windcorp/progressia/common/world/context/WorldDataContextRO.java b/src/main/java/ru/windcorp/progressia/common/world/context/WorldDataContextRO.java index 8201738..be037bf 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/context/WorldDataContextRO.java +++ b/src/main/java/ru/windcorp/progressia/common/world/context/WorldDataContextRO.java @@ -18,10 +18,12 @@ package ru.windcorp.progressia.common.world.context; +import glm.vec._3.i.Vec3i; import ru.windcorp.progressia.common.world.GravityModel; import ru.windcorp.progressia.common.world.block.BlockData; import ru.windcorp.progressia.common.world.entity.EntityData; import ru.windcorp.progressia.common.world.generic.context.WorldGenericContextRO; +import ru.windcorp.progressia.common.world.rels.RelFace; import ru.windcorp.progressia.common.world.tile.TileData; public interface WorldDataContextRO extends WorldGenericContextRO { @@ -43,5 +45,18 @@ public interface WorldDataContextRO extends WorldGenericContextRO. + */ +package ru.windcorp.progressia.common.world.generic.context; + +import glm.vec._3.i.Vec3i; +import ru.windcorp.progressia.common.util.StashingStack; +import ru.windcorp.progressia.common.world.generic.BlockGeneric; +import ru.windcorp.progressia.common.world.generic.EntityGeneric; +import ru.windcorp.progressia.common.world.generic.TileGeneric; +import ru.windcorp.progressia.common.world.rels.RelFace; + +//@formatter:off +public abstract class AbstractContextRO< + B extends BlockGeneric, + T extends TileGeneric, + E extends EntityGeneric +> implements TileGenericContextRO { +//@formatter:on + + public static final int MAX_SUBCONTEXTS = 64; + + protected class Frame { + + public final Vec3i location = new Vec3i(); + public RelFace face; + public int layer; + + } + + protected Frame frame = null; + + private final StashingStack frameStack = new StashingStack<>(MAX_SUBCONTEXTS, Frame::new); + + @Override + public void pop() { + if (!isSubcontexting()) { + throw new IllegalStateException("Cannot pop(): already top frame"); + } + + frame = frameStack.pop(); + } + + @Override + public BlockGenericContextRO push(Vec3i location) { + frame = frameStack.push(); + + frame.location.set(location.x, location.y, location.z); + frame.face = null; + frame.layer = -1; + + return this; + } + + @Override + public TileStackGenericContextRO push(Vec3i location, RelFace face) { + frame = frameStack.push(); + + frame.location.set(location.x, location.y, location.z); + frame.face = face; + frame.layer = -1; + + return this; + } + + @Override + public TileGenericContextRO push(Vec3i location, RelFace face, int layer) { + frame = frameStack.push(); + + frame.location.set(location.x, location.y, location.z); + frame.face = face; + frame.layer = layer; + + return this; + } + + public boolean isSubcontexting() { + return frameStack.isEmpty(); + } + +} diff --git a/src/main/java/ru/windcorp/progressia/common/world/generic/context/BlockGenericContextRO.java b/src/main/java/ru/windcorp/progressia/common/world/generic/context/BlockGenericContextRO.java index 239a02e..842fd0a 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/generic/context/BlockGenericContextRO.java +++ b/src/main/java/ru/windcorp/progressia/common/world/generic/context/BlockGenericContextRO.java @@ -17,9 +17,12 @@ */ package ru.windcorp.progressia.common.world.generic.context; +import glm.vec._3.i.Vec3i; import ru.windcorp.progressia.common.world.context.Context; import ru.windcorp.progressia.common.world.generic.*; +import ru.windcorp.progressia.common.world.rels.AbsRelation; import ru.windcorp.progressia.common.world.rels.BlockFace; +import ru.windcorp.progressia.common.world.rels.RelFace; /** * A {@link Context} referencing a world with a block location specified. The @@ -129,5 +132,34 @@ public interface BlockGenericContextRO< default int getTileCount(BlockFace face) { return getTileCount(face); } + + /* + * Subcontexting + */ + + @Override + default BlockGenericContextRO pushRelative(int dx, int dy, int dz) { + return push(getLocation().add_(dx, dy, dz)); + } + + @Override + default BlockGenericContextRO pushRelative(Vec3i direction) { + return push(getLocation().add_(direction)); + } + + @Override + default BlockGenericContextRO pushRelative(AbsRelation direction) { + return push(direction.getVector()); + } + + @Override + default TileStackGenericContextRO push(RelFace face) { + return push(getLocation(), face); + } + + @Override + default TileGenericContextRO push(RelFace face, int layer) { + return push(getLocation(), face, layer); + } } diff --git a/src/main/java/ru/windcorp/progressia/common/world/generic/context/BlockGenericContextWO.java b/src/main/java/ru/windcorp/progressia/common/world/generic/context/BlockGenericContextWO.java index ffdb969..97ec62d 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/generic/context/BlockGenericContextWO.java +++ b/src/main/java/ru/windcorp/progressia/common/world/generic/context/BlockGenericContextWO.java @@ -17,9 +17,12 @@ */ package ru.windcorp.progressia.common.world.generic.context; +import glm.vec._3.i.Vec3i; import ru.windcorp.progressia.common.world.context.Context; import ru.windcorp.progressia.common.world.generic.*; +import ru.windcorp.progressia.common.world.rels.AbsRelation; import ru.windcorp.progressia.common.world.rels.BlockFace; +import ru.windcorp.progressia.common.world.rels.RelFace; /** * A writable {@link Context} referencing a world with a block location @@ -72,5 +75,34 @@ public interface BlockGenericContextWO< default void removeTile(BlockFace face, int tag) { removeTile(getLocation(), face, tag); } + + /* + * Subcontexting + */ + + @Override + default BlockGenericContextWO pushRelative(int dx, int dy, int dz) { + return push(getLocation().add_(dx, dy, dz)); + } + + @Override + default BlockGenericContextWO pushRelative(Vec3i direction) { + return push(getLocation().add_(direction)); + } + + @Override + default BlockGenericContextWO pushRelative(AbsRelation direction) { + return push(direction.getVector()); + } + + @Override + default TileStackGenericContextWO push(RelFace face) { + return push(getLocation(), face); + } + + @Override + default TileGenericContextWO push(RelFace face, int layer) { + return push(getLocation(), face, layer); + } } diff --git a/src/main/java/ru/windcorp/progressia/common/world/generic/context/TileGenericContextRO.java b/src/main/java/ru/windcorp/progressia/common/world/generic/context/TileGenericContextRO.java index bdc5b69..1088a16 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/generic/context/TileGenericContextRO.java +++ b/src/main/java/ru/windcorp/progressia/common/world/generic/context/TileGenericContextRO.java @@ -56,5 +56,19 @@ public interface TileGenericContextRO< default T getTile() { return getTile(getLocation(), getFace(), getLayer()); } + + /* + * Subcontexting + */ + + @Override + default TileGenericContextRO pushCloser() { + return push(getLocation(), getFace(), getLayer() - 1); + } + + @Override + default TileGenericContextRO pushFarther() { + return push(getLocation(), getFace(), getLayer() + 1); + } } diff --git a/src/main/java/ru/windcorp/progressia/common/world/generic/context/TileGenericContextWO.java b/src/main/java/ru/windcorp/progressia/common/world/generic/context/TileGenericContextWO.java index ae8a2ff..1193f51 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/generic/context/TileGenericContextWO.java +++ b/src/main/java/ru/windcorp/progressia/common/world/generic/context/TileGenericContextWO.java @@ -43,5 +43,19 @@ public interface TileGenericContextWO< default void removeTile() { removeTile(getLocation(), getFace(), getTag()); } + + /* + * Subcontexting + */ + + @Override + default TileGenericContextWO pushCloser() { + return push(getLocation(), getFace(), getLayer() - 1); + } + + @Override + default TileGenericContextWO pushFarther() { + return push(getLocation(), getFace(), getLayer() + 1); + } } diff --git a/src/main/java/ru/windcorp/progressia/common/world/generic/context/TileStackGenericContextRO.java b/src/main/java/ru/windcorp/progressia/common/world/generic/context/TileStackGenericContextRO.java index 082788b..2a5cd3c 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/generic/context/TileStackGenericContextRO.java +++ b/src/main/java/ru/windcorp/progressia/common/world/generic/context/TileStackGenericContextRO.java @@ -30,7 +30,7 @@ public interface TileStackGenericContextRO< B extends BlockGeneric, T extends TileGeneric, E extends EntityGeneric -> extends WorldContexts.BlockFace, BlockGenericContextRO { +> extends WorldContexts.TileStack, BlockGenericContextRO { //@formatter:on /** @@ -100,5 +100,24 @@ public interface TileStackGenericContextRO< default int getTileCount() { return getTileCount(getLocation(), getFace()); } + + /* + * Subcontexting + */ + + @Override + default TileGenericContextRO push(int layer) { + return push(getLocation(), getFace(), layer); + } + + @Override + default TileStackGenericContextRO pushCounter() { + return push(getFace().getCounter()); + } + + @Override + default TileStackGenericContextRO pushOpposite() { + return push(getLocation().add_(getFace().getRelVector()), getFace().getCounter()); + } } diff --git a/src/main/java/ru/windcorp/progressia/common/world/generic/context/TileStackGenericContextWO.java b/src/main/java/ru/windcorp/progressia/common/world/generic/context/TileStackGenericContextWO.java index 28c87ee..7a618b9 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/generic/context/TileStackGenericContextWO.java +++ b/src/main/java/ru/windcorp/progressia/common/world/generic/context/TileStackGenericContextWO.java @@ -32,7 +32,7 @@ public interface TileStackGenericContextWO< B extends BlockGeneric, T extends TileGeneric, E extends EntityGeneric -> extends WorldContexts.BlockFace, BlockGenericContextWO { +> extends WorldContexts.TileStack, BlockGenericContextWO { //@formatter:on /** @@ -59,5 +59,24 @@ public interface TileStackGenericContextWO< default void removeTile(int tag) { removeTile(getLocation(), getFace(), tag); } + + /* + * Subcontexting + */ + + @Override + default TileGenericContextWO push(int layer) { + return push(getLocation(), getFace(), layer); + } + + @Override + default TileStackGenericContextWO pushCounter() { + return push(getFace().getCounter()); + } + + @Override + default TileStackGenericContextWO pushOpposite() { + return push(getLocation().add_(getFace().getRelVector()), getFace().getCounter()); + } } diff --git a/src/main/java/ru/windcorp/progressia/common/world/generic/context/WorldContexts.java b/src/main/java/ru/windcorp/progressia/common/world/generic/context/WorldContexts.java index 4dd8c19..bfc85bb 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/generic/context/WorldContexts.java +++ b/src/main/java/ru/windcorp/progressia/common/world/generic/context/WorldContexts.java @@ -20,19 +20,20 @@ package ru.windcorp.progressia.common.world.generic.context; import glm.vec._3.i.Vec3i; import ru.windcorp.progressia.common.world.context.Context; +import ru.windcorp.progressia.common.world.rels.AbsRelation; import ru.windcorp.progressia.common.world.rels.RelFace; /** * This class defines several {@link Context} subinterfaces that are further * extended by Generic contexts. These interfaces declare methods for - * determining which location is "relevant" to the context. Since they are not - * Java generics they can safely be extended more than once. + * determining which location is "relevant" to the context and the basic + * subcontexting methods. Since they are not Java generics they can safely be + * extended more than once. *

    * Do not reuse these interfaces outside the Generic contexts' package; consider * them to be an implementation detail. * * @author javapony - * */ class WorldContexts { @@ -42,48 +43,149 @@ class WorldContexts { * {@link WorldGenericContextWO}. * * @author javapony - * */ public static interface World extends Context { - // currently empty + /** + * Assigns the specified location to this context. Block face and tile + * layer information is discarded if it was present. See + * {@linkplain Context#subcontexting subcontexting} for more details. + * + * @param location the new location to use + * @return this object + * @see #pop() + */ + Block push(Vec3i location); + + /** + * Assigns the specified location and block face to this context. Tile + * layer information is discarded if it was present. See + * {@linkplain Context#subcontexting subcontexting} for more details. + * + * @param location the new location to use + * @param face the new block face to use + * @return this object + * @see #pop() + */ + TileStack push(Vec3i location, RelFace face); + + /** + * Assigns the specified position to this context. See + * {@linkplain Context#subcontexting subcontexting} for more details. + * + * @param location the new location to use + * @param face the new block face to use + * @param layer the new tile layer to use + * @return this object + * @see #pop() + */ + Tile push(Vec3i location, RelFace face, int layer); } /** - * A {@link Context} with a world instance and a block location. This interface + * A {@link Context} with a world instance and a block location. This + * interface * should not be implemented directly; see {@link BlockGenericContextRO} or * {@link BlockGenericContextWO}. * * @author javapony - * */ public static interface Block extends World { /** * Returns the location of the block. *

    - * The coordinate system in use is not specified, but it is consistent across + * The coordinate system in use is not specified, but it is consistent + * across * all methods of this context. *

    - * The object returned by this method must not be modified. It is only valid + * The object returned by this method must not be modified. It is only + * valid * while the context is {@linkplain valid}. * * @return a vector describing the block's position */ Vec3i getLocation(); + /** + * Shifts the location in the specified direction. Block face and tile + * layer information is discarded if it was present. See + * {@linkplain Context#subcontexting subcontexting} for more details. + * + * @param dx the change of the x component + * @param dy the change of the y component + * @param dz the change of the z component + * @return this object + * @see #pop() + */ + default Block pushRelative(int dx, int dy, int dz) { + return push(getLocation().add_(dx, dy, dz)); + } + + /** + * Shifts the location in the specified direction. Block face and tile + * layer information is discarded if it was present. See + * {@linkplain Context#subcontexting subcontexting} for more details. + * + * @param direction the change added to the current location + * @return this object + * @see #pop() + */ + default Block pushRelative(Vec3i direction) { + return push(getLocation().add_(direction)); + } + + /** + * Shifts the location in the specified direction. Block face and tile + * layer information is discarded if it was present. See + * {@linkplain Context#subcontexting subcontexting} for more details. + * + * @param direction the change added to the current location + * @return this object + * @see #pop() + */ + default Block pushRelative(AbsRelation direction) { + return push(direction.getVector()); + } + + /** + * Assigns the specified block face to this context. Tile layer + * information is discarded if it was present. See + * {@linkplain Context#subcontexting subcontexting} for more details. + * + * @param face the new block face to use + * @return this object + * @see #pop() + */ + default TileStack push(RelFace face) { + return push(getLocation(), face); + } + + /** + * Assigns the specified block face and tile layer to this context. See + * {@linkplain Context#subcontexting subcontexting} for more details. + * + * @param face the new block face to use + * @param layer the new tile layer to use + * @return this object + * @see #pop() + */ + default Tile push(RelFace face, int layer) { + return push(getLocation(), face, layer); + } + } /** - * A {@link Context} with a world instance, a block location and a block face + * A {@link Context} with a world instance, a block location and a block + * face * (block side). This interface should not be implemented directly; see * {@link TileStackGenericContextRO} or {@link TileStackGenericContextWO}. * * @author javapony - * */ - public static interface BlockFace extends Block { + public static interface TileStack extends Block { /** * Returns the face relevant to this context. @@ -92,17 +194,57 @@ class WorldContexts { */ RelFace getFace(); + /** + * Assigns the specified tile layer to this context. See + * {@linkplain Context#subcontexting subcontexting} for more details. + * + * @param layer the new tile layer to use + * @return this object + * @see #pop() + */ + default Tile push(int layer) { + return push(getLocation(), getFace(), layer); + } + + /** + * Assigns the counter face (the face on the opposite side of this + * block) to this context. Tile layer information is discarded if it was + * present. See {@linkplain Context#subcontexting subcontexting} for + * more details. + * + * @return this object + * @see #pop() + */ + default TileStack pushCounter() { + return push(getFace().getCounter()); + } + + /** + * Assigns the face opposite to the current face to this context. The + * current face and its opposite are the only two tile stacks occupying + * the gap between the two respective blocks. Tile layer information is + * discarded if it was present. See {@linkplain Context#subcontexting + * subcontexting} for + * more details. + * + * @return this object + * @see #pop() + */ + default TileStack pushOpposite() { + return push(getLocation().add_(getFace().getRelVector()), getFace().getCounter()); + } + } /** * A {@link Context} with a world instance, a block location, a block face * (block side) and a tile layer. This interface should not be implemented - * directly; see {@link TileGenericContextRO} or {@link TileGenericContextWO}. + * directly; see {@link TileGenericContextRO} or + * {@link TileGenericContextWO}. * * @author javapony - * */ - public static interface Tile extends BlockFace { + public static interface Tile extends TileStack { /** * Returns the tile layer relevant to this context. @@ -114,11 +256,34 @@ class WorldContexts { /** * Gets the tag of the tile at the relevant position. * - * @return the tag of the tile or {@code -1} if the location is not loaded + * @return the tag of the tile or {@code -1} if the location is not + * loaded * or the tile does not exist */ int getTag(); + /** + * Assigns the tile layer closer to the host block to this context. See + * {@linkplain Context#subcontexting subcontexting} for more details. + * + * @return this object + * @see #pop() + */ + default Tile pushCloser() { + return push(getLocation(), getFace(), getLayer() - 1); + } + + /** + * Assigns the tile layer farther to the host block to this context. See + * {@linkplain Context#subcontexting subcontexting} for more details. + * + * @return this object + * @see #pop() + */ + default Tile pushFarther() { + return push(getLocation(), getFace(), getLayer() + 1); + } + } WorldContexts() { diff --git a/src/main/java/ru/windcorp/progressia/common/world/generic/context/WorldGenericContextRO.java b/src/main/java/ru/windcorp/progressia/common/world/generic/context/WorldGenericContextRO.java index d604d62..59707e9 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/generic/context/WorldGenericContextRO.java +++ b/src/main/java/ru/windcorp/progressia/common/world/generic/context/WorldGenericContextRO.java @@ -25,6 +25,7 @@ import glm.vec._3.i.Vec3i; import ru.windcorp.progressia.common.world.context.Context; import ru.windcorp.progressia.common.world.generic.*; import ru.windcorp.progressia.common.world.rels.BlockFace; +import ru.windcorp.progressia.common.world.rels.RelFace; /** * A {@link Context} with a world instance. @@ -188,4 +189,17 @@ public interface WorldGenericContextRO< }); } + /* + * Subcontexting + */ + + @Override + BlockGenericContextRO push(Vec3i location); + + @Override + TileStackGenericContextRO push(Vec3i location, RelFace face); + + @Override + TileGenericContextRO push(Vec3i location, RelFace face, int layer); + } diff --git a/src/main/java/ru/windcorp/progressia/common/world/generic/context/WorldGenericContextWO.java b/src/main/java/ru/windcorp/progressia/common/world/generic/context/WorldGenericContextWO.java index ad1291e..0a465a0 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/generic/context/WorldGenericContextWO.java +++ b/src/main/java/ru/windcorp/progressia/common/world/generic/context/WorldGenericContextWO.java @@ -23,6 +23,7 @@ import ru.windcorp.progressia.common.state.StatefulObject; import ru.windcorp.progressia.common.world.context.Context; import ru.windcorp.progressia.common.world.generic.*; import ru.windcorp.progressia.common.world.rels.BlockFace; +import ru.windcorp.progressia.common.world.rels.RelFace; /** * A writable {@link Context} with a world instance. This context provides @@ -149,5 +150,18 @@ public interface WorldGenericContextWO< * @param change the change to apply */ void changeEntity(SE entity, StateChange change); + + /* + * Subcontexting + */ + + @Override + BlockGenericContextWO push(Vec3i location); + + @Override + TileStackGenericContextWO push(Vec3i location, RelFace face); + + @Override + TileGenericContextWO push(Vec3i location, RelFace face, int layer); } diff --git a/src/main/java/ru/windcorp/progressia/server/world/context/ServerBlockContext.java b/src/main/java/ru/windcorp/progressia/server/world/context/ServerBlockContext.java index 4130b50..c8bdf0b 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/context/ServerBlockContext.java +++ b/src/main/java/ru/windcorp/progressia/server/world/context/ServerBlockContext.java @@ -17,7 +17,10 @@ */ package ru.windcorp.progressia.server.world.context; +import glm.vec._3.i.Vec3i; import ru.windcorp.progressia.common.world.context.BlockDataContext; +import ru.windcorp.progressia.common.world.rels.AbsRelation; +import ru.windcorp.progressia.common.world.rels.RelFace; public interface ServerBlockContext extends BlockDataContext, ServerWorldContext, ServerBlockContextRO { @@ -25,10 +28,60 @@ public interface ServerBlockContext extends BlockDataContext, ServerWorldContext @Override ServerBlockContext data(); + + @Override + default ServerBlockContext.Logic pushRelative(int dx, int dy, int dz) { + return push(getLocation().add_(dx, dy, dz)); + } + + @Override + default ServerBlockContext.Logic pushRelative(Vec3i direction) { + return push(getLocation().add_(direction)); + } + + @Override + default ServerBlockContext.Logic pushRelative(AbsRelation direction) { + return push(direction.getVector()); + } + + @Override + default ServerTileStackContext.Logic push(RelFace face) { + return push(getLocation(), face); + } + + @Override + default ServerTileContext.Logic push(RelFace face, int layer) { + return push(getLocation(), face, layer); + } } @Override ServerBlockContext.Logic logic(); + + @Override + default ServerBlockContext pushRelative(int dx, int dy, int dz) { + return push(getLocation().add_(dx, dy, dz)); + } + + @Override + default ServerBlockContext pushRelative(Vec3i direction) { + return push(getLocation().add_(direction)); + } + + @Override + default ServerBlockContext pushRelative(AbsRelation direction) { + return push(direction.getVector()); + } + + @Override + default ServerTileStackContext push(RelFace face) { + return push(getLocation(), face); + } + + @Override + default ServerTileContext push(RelFace face, int layer) { + return push(getLocation(), face, layer); + } } diff --git a/src/main/java/ru/windcorp/progressia/server/world/context/ServerBlockContextRO.java b/src/main/java/ru/windcorp/progressia/server/world/context/ServerBlockContextRO.java index ca2e09f..eefa195 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/context/ServerBlockContextRO.java +++ b/src/main/java/ru/windcorp/progressia/server/world/context/ServerBlockContextRO.java @@ -17,9 +17,12 @@ */ package ru.windcorp.progressia.server.world.context; +import glm.vec._3.i.Vec3i; import ru.windcorp.progressia.common.world.context.BlockDataContextRO; import ru.windcorp.progressia.common.world.entity.EntityData; import ru.windcorp.progressia.common.world.generic.context.BlockGenericContextRO; +import ru.windcorp.progressia.common.world.rels.AbsRelation; +import ru.windcorp.progressia.common.world.rels.RelFace; import ru.windcorp.progressia.server.world.block.BlockLogic; import ru.windcorp.progressia.server.world.tile.TileLogic; @@ -30,10 +33,60 @@ public interface ServerBlockContextRO extends ServerWorldContextRO, BlockDataCon @Override ServerBlockContextRO data(); + + @Override + default ServerBlockContextRO.Logic pushRelative(int dx, int dy, int dz) { + return push(getLocation().add_(dx, dy, dz)); + } + + @Override + default ServerBlockContextRO.Logic pushRelative(Vec3i direction) { + return push(getLocation().add_(direction)); + } + + @Override + default ServerBlockContextRO.Logic pushRelative(AbsRelation direction) { + return push(direction.getVector()); + } + + @Override + default ServerTileStackContextRO.Logic push(RelFace face) { + return push(getLocation(), face); + } + + @Override + default ServerTileContextRO.Logic push(RelFace face, int layer) { + return push(getLocation(), face, layer); + } } @Override ServerBlockContextRO.Logic logic(); + + @Override + default ServerBlockContextRO pushRelative(int dx, int dy, int dz) { + return push(getLocation().add_(dx, dy, dz)); + } + + @Override + default ServerBlockContextRO pushRelative(Vec3i direction) { + return push(getLocation().add_(direction)); + } + + @Override + default ServerBlockContextRO pushRelative(AbsRelation direction) { + return push(direction.getVector()); + } + + @Override + default ServerTileStackContextRO push(RelFace face) { + return push(getLocation(), face); + } + + @Override + default ServerTileContextRO push(RelFace face, int layer) { + return push(getLocation(), face, layer); + } } diff --git a/src/main/java/ru/windcorp/progressia/server/world/context/ServerTileContext.java b/src/main/java/ru/windcorp/progressia/server/world/context/ServerTileContext.java index bc5fe6c..6850f43 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/context/ServerTileContext.java +++ b/src/main/java/ru/windcorp/progressia/server/world/context/ServerTileContext.java @@ -25,10 +25,30 @@ public interface ServerTileContext extends TileDataContext, ServerTileStackConte @Override ServerTileContext data(); + + @Override + default ServerTileContext.Logic pushCloser() { + return push(getLocation(), getFace(), getLayer() - 1); + } + + @Override + default ServerTileContext.Logic pushFarther() { + return push(getLocation(), getFace(), getLayer() + 1); + } } @Override ServerTileContext.Logic logic(); + + @Override + default ServerTileContext pushCloser() { + return push(getLocation(), getFace(), getLayer() - 1); + } + + @Override + default ServerTileContext pushFarther() { + return push(getLocation(), getFace(), getLayer() + 1); + } } diff --git a/src/main/java/ru/windcorp/progressia/server/world/context/ServerTileContextRO.java b/src/main/java/ru/windcorp/progressia/server/world/context/ServerTileContextRO.java index 87faf0c..18382bd 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/context/ServerTileContextRO.java +++ b/src/main/java/ru/windcorp/progressia/server/world/context/ServerTileContextRO.java @@ -30,10 +30,30 @@ public interface ServerTileContextRO extends ServerTileStackContextRO, TileDataC @Override ServerTileContextRO data(); + + @Override + default ServerTileContextRO.Logic pushCloser() { + return push(getLocation(), getFace(), getLayer() - 1); + } + + @Override + default ServerTileContextRO.Logic pushFarther() { + return push(getLocation(), getFace(), getLayer() + 1); + } } @Override ServerTileContextRO.Logic logic(); + + @Override + default ServerTileContextRO pushCloser() { + return push(getLocation(), getFace(), getLayer() - 1); + } + + @Override + default ServerTileContextRO pushFarther() { + return push(getLocation(), getFace(), getLayer() + 1); + } } diff --git a/src/main/java/ru/windcorp/progressia/server/world/context/ServerTileStackContext.java b/src/main/java/ru/windcorp/progressia/server/world/context/ServerTileStackContext.java index 938271b..7454f26 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/context/ServerTileStackContext.java +++ b/src/main/java/ru/windcorp/progressia/server/world/context/ServerTileStackContext.java @@ -25,10 +25,40 @@ public interface ServerTileStackContext extends TileStackDataContext, ServerBloc @Override ServerTileStackContext data(); + + @Override + default ServerTileContext.Logic push(int layer) { + return push(getLocation(), getFace(), layer); + } + + @Override + default ServerTileStackContext.Logic pushCounter() { + return push(getFace().getCounter()); + } + + @Override + default ServerTileStackContext.Logic pushOpposite() { + return push(getLocation().add_(getFace().getRelVector()), getFace().getCounter()); + } } @Override ServerTileStackContext.Logic logic(); + + @Override + default ServerTileContext push(int layer) { + return push(getLocation(), getFace(), layer); + } + + @Override + default ServerTileStackContext pushCounter() { + return push(getFace().getCounter()); + } + + @Override + default ServerTileStackContext pushOpposite() { + return push(getLocation().add_(getFace().getRelVector()), getFace().getCounter()); + } } diff --git a/src/main/java/ru/windcorp/progressia/server/world/context/ServerTileStackContextRO.java b/src/main/java/ru/windcorp/progressia/server/world/context/ServerTileStackContextRO.java index 0b33933..ef2d476 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/context/ServerTileStackContextRO.java +++ b/src/main/java/ru/windcorp/progressia/server/world/context/ServerTileStackContextRO.java @@ -30,10 +30,40 @@ public interface ServerTileStackContextRO extends ServerBlockContextRO, TileStac @Override ServerTileStackContextRO data(); + + @Override + default ServerTileContextRO.Logic push(int layer) { + return push(getLocation(), getFace(), layer); + } + + @Override + default ServerTileStackContextRO.Logic pushCounter() { + return push(getFace().getCounter()); + } + + @Override + default ServerTileStackContextRO.Logic pushOpposite() { + return push(getLocation().add_(getFace().getRelVector()), getFace().getCounter()); + } } @Override ServerTileStackContextRO.Logic logic(); + + @Override + default ServerTileContextRO push(int layer) { + return push(getLocation(), getFace(), layer); + } + + @Override + default ServerTileStackContextRO pushCounter() { + return push(getFace().getCounter()); + } + + @Override + default ServerTileStackContextRO pushOpposite() { + return push(getLocation().add_(getFace().getRelVector()), getFace().getCounter()); + } } diff --git a/src/main/java/ru/windcorp/progressia/server/world/context/ServerWorldContext.java b/src/main/java/ru/windcorp/progressia/server/world/context/ServerWorldContext.java index b8504c4..3de8038 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/context/ServerWorldContext.java +++ b/src/main/java/ru/windcorp/progressia/server/world/context/ServerWorldContext.java @@ -17,7 +17,9 @@ */ package ru.windcorp.progressia.server.world.context; +import glm.vec._3.i.Vec3i; import ru.windcorp.progressia.common.world.context.WorldDataContext; +import ru.windcorp.progressia.common.world.rels.RelFace; public interface ServerWorldContext extends WorldDataContext, ServerWorldContextRO { @@ -25,10 +27,28 @@ public interface ServerWorldContext extends WorldDataContext, ServerWorldContext @Override ServerWorldContext data(); + + @Override + ServerBlockContext.Logic push(Vec3i location); + + @Override + ServerTileStackContext.Logic push(Vec3i location, RelFace face); + + @Override + ServerTileContext.Logic push(Vec3i location, RelFace face, int layer); } @Override ServerWorldContext.Logic logic(); + + @Override + ServerBlockContext push(Vec3i location); + + @Override + ServerTileStackContext push(Vec3i location, RelFace face); + + @Override + ServerTileContext push(Vec3i location, RelFace face, int layer); } \ No newline at end of file diff --git a/src/main/java/ru/windcorp/progressia/server/world/context/ServerWorldContextRO.java b/src/main/java/ru/windcorp/progressia/server/world/context/ServerWorldContextRO.java index 0202024..ff849c1 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/context/ServerWorldContextRO.java +++ b/src/main/java/ru/windcorp/progressia/server/world/context/ServerWorldContextRO.java @@ -1,8 +1,10 @@ package ru.windcorp.progressia.server.world.context; +import glm.vec._3.i.Vec3i; import ru.windcorp.progressia.common.world.context.WorldDataContextRO; import ru.windcorp.progressia.common.world.entity.EntityData; import ru.windcorp.progressia.common.world.generic.context.WorldGenericContextRO; +import ru.windcorp.progressia.common.world.rels.RelFace; import ru.windcorp.progressia.server.world.block.BlockLogic; import ru.windcorp.progressia.server.world.tile.TileLogic; @@ -18,6 +20,15 @@ public interface ServerWorldContextRO extends WorldDataContextRO, ServerContext * @return a view of this context that returns data objects */ ServerWorldContextRO data(); + + @Override + ServerBlockContextRO.Logic push(Vec3i location); + + @Override + ServerTileStackContextRO.Logic push(Vec3i location, RelFace face); + + @Override + ServerTileContextRO.Logic push(Vec3i location, RelFace face, int layer); } @@ -29,5 +40,14 @@ public interface ServerWorldContextRO extends WorldDataContextRO, ServerContext * @return a view of this context that returns appropriate logic objects */ ServerWorldContextRO.Logic logic(); + + @Override + ServerBlockContextRO push(Vec3i location); + + @Override + ServerTileStackContextRO push(Vec3i location, RelFace face); + + @Override + ServerTileContextRO push(Vec3i location, RelFace face, int layer); } diff --git a/src/main/java/ru/windcorp/progressia/server/world/context/impl/ReusableServerContext.java b/src/main/java/ru/windcorp/progressia/server/world/context/impl/ReusableServerContext.java index 345ff37..d32974c 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/context/impl/ReusableServerContext.java +++ b/src/main/java/ru/windcorp/progressia/server/world/context/impl/ReusableServerContext.java @@ -17,7 +17,13 @@ */ package ru.windcorp.progressia.server.world.context.impl; +import glm.vec._3.i.Vec3i; +import ru.windcorp.progressia.common.world.block.BlockData; import ru.windcorp.progressia.common.world.context.Context; +import ru.windcorp.progressia.common.world.entity.EntityData; +import ru.windcorp.progressia.common.world.generic.context.AbstractContextRO; +import ru.windcorp.progressia.common.world.rels.RelFace; +import ru.windcorp.progressia.common.world.tile.TileData; import ru.windcorp.progressia.server.world.WorldLogic; import ru.windcorp.progressia.server.world.WorldLogicRO; import ru.windcorp.progressia.server.world.context.*; @@ -45,7 +51,8 @@ import ru.windcorp.progressia.server.world.context.*; * * @author javapony */ -public abstract class ReusableServerContext implements ServerTileContext { +public abstract class ReusableServerContext extends AbstractContextRO + implements ServerTileContext { /** * An RSC can conform to a variety of different {@link Context} interfaces. @@ -92,9 +99,7 @@ public abstract class ReusableServerContext implements ServerTileContext { * * @return a {@link ReusableServerContextBuilders.Empty} instance that may * be used to reinitialize this object - * @throws IllegalStateException if active subcontexting is detected. - * Detection is done on a best-effort basis; - * do not rely this exception + * @throws IllegalStateException if active subcontexting is detected */ public abstract ReusableServerContextBuilders.Empty reuse() throws IllegalStateException; @@ -115,5 +120,23 @@ public abstract class ReusableServerContext implements ServerTileContext { public static ReusableServerContextBuilders.Empty empty() { return new ReusableServerContextImpl(); } + + @Override + public ReusableServerContext push(Vec3i location) { + super.push(location); + return this; + } + + @Override + public ReusableServerContext push(Vec3i location, RelFace face) { + super.push(location, face); + return this; + } + + @Override + public ReusableServerContext push(Vec3i location, RelFace face, int layer) { + super.push(location, face, layer); + return this; + } } diff --git a/src/main/java/ru/windcorp/progressia/server/world/context/impl/ReusableServerContextImpl.java b/src/main/java/ru/windcorp/progressia/server/world/context/impl/ReusableServerContextImpl.java index 7e4545d..2994205 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/context/impl/ReusableServerContextImpl.java +++ b/src/main/java/ru/windcorp/progressia/server/world/context/impl/ReusableServerContextImpl.java @@ -69,30 +69,6 @@ class ReusableServerContextImpl extends ReusableServerContext */ protected WorldData worldData; - /** - * The relevant location. If this is {@code null}, the role is - * {@link Role#WORLD} or {@link Role#NONE}. - */ - protected Vec3i location; - - /** - * A {@code final} reference to the {@link Vec3i} instance used by - * {@link #location}. - */ - protected final Vec3i locationVectorContainer = new Vec3i(); - - /** - * The relevant {@link RelFace}. If the role is {@link Role#TILE_STACK} or - * {@link Role#TILE}, this is not {@code null}. - */ - protected RelFace blockFace; - - /** - * The index of the relevant tile. This value is {@code -1} unless the role - * is {@link Role#TILE}. - */ - protected int layer; - /** * The {@link Random} instance exposed with {@link #getRandom()}. */ @@ -124,11 +100,11 @@ class ReusableServerContextImpl extends ReusableServerContext public Role getRole() { if (server == null) return Role.NONE; - if (location == null) + if (frame == null) return Role.WORLD; - if (blockFace == null) + if (frame.face == null) return Role.LOCATION; - if (layer == -1) + if (frame.layer == -1) return Role.TILE_STACK; return Role.TILE; } @@ -186,19 +162,19 @@ class ReusableServerContextImpl extends ReusableServerContext case TILE: result = String.format( "ServerTileContext[x=%d, y=%d, z=%d, %s, index=%d]", - location.x, - location.y, - location.z, - blockFace, - layer + frame.location.x, + frame.location.y, + frame.location.z, + frame.face, + frame.layer ); break; case TILE_STACK: result = String - .format("ServerBlockFaceContext[x=%d, y=%d, z=%d, %s]", location.x, location.y, location.z, blockFace); + .format("ServerBlockFaceContext[x=%d, y=%d, z=%d, %s]", frame.location.x, frame.location.y, frame.location.z, frame.face); break; case LOCATION: - result = String.format("ServerBlockContext[x=%d, y=%d, z=%d]", location.x, location.y, location.z); + result = String.format("ServerBlockContext[x=%d, y=%d, z=%d]", frame.location.x, frame.location.y, frame.location.z); break; case WORLD: result = String.format("ServerWorldContext"); @@ -222,16 +198,13 @@ class ReusableServerContextImpl extends ReusableServerContext @Override public Empty reuse() { - if (subcontextDepth != 0) { - throw new IllegalStateException("Resetting is not allowed when subcontexting"); - } - server = null; worldLogic = null; worldData = null; - location = null; - blockFace = null; - layer = -1; + + while (isSubcontexting()) { + pop(); + } isBuilder = true; @@ -270,8 +243,7 @@ class ReusableServerContextImpl extends ReusableServerContext @Override public WithLocation at(Vec3i location) { requireBuilderRole(Role.WORLD); - this.location = this.locationVectorContainer; - this.location.set(location.x, location.y, location.z); + push(location); return this; } @@ -282,14 +254,14 @@ class ReusableServerContextImpl extends ReusableServerContext @Override public WithTileStack on(RelFace side) { requireBuilderRole(Role.LOCATION); - this.blockFace = side; + frame.face = side; return this; } @Override public WithTileStack on(BlockFace side) { requireBuilderRole(Role.LOCATION); - this.blockFace = side.relativize(worldLogic.getData().getUp(location)); + frame.face = side.relativize(worldLogic.getData().getUp(frame.location)); return this; } @@ -300,7 +272,7 @@ class ReusableServerContextImpl extends ReusableServerContext @Override public ReusableServerContext index(int index) { requireBuilderRole(Role.TILE_STACK); - this.layer = index; + frame.layer = index; return build(); } @@ -317,19 +289,19 @@ class ReusableServerContextImpl extends ReusableServerContext @Override public Vec3i getLocation() { assert requireContextRole(Role.LOCATION); - return location; + return frame.location; } @Override public RelFace getFace() { assert requireContextRole(Role.TILE_STACK); - return blockFace; + return frame.face; } @Override public int getLayer() { assert requireContextRole(Role.TILE); - return layer; + return frame.layer; } /* @@ -402,16 +374,16 @@ class ReusableServerContextImpl extends ReusableServerContext @Override public int getTag() { assert requireContextRole(Role.TILE); - TileDataStack stack = worldData.getTilesOrNull(location, blockFace); + TileDataStack stack = worldData.getTilesOrNull(frame.location, frame.face); if (stack == null) return -1; - return stack.getTagByIndex(layer); + return stack.getTagByIndex(frame.layer); } @Override public int getTileCount(Vec3i location, BlockFace face) { assert requireContextRole(Role.TILE_STACK); - TileDataStack stack = worldData.getTilesOrNull(location, blockFace); + TileDataStack stack = worldData.getTilesOrNull(frame.location, frame.face); if (stack == null) return 0; return stack.size(); @@ -516,17 +488,17 @@ class ReusableServerContextImpl extends ReusableServerContext @Override public Vec3i getLocation() { - return location; + return frame.location; } @Override public RelFace getFace() { - return blockFace; + return frame.face; } @Override public int getLayer() { - return layer; + return frame.layer; } /* @@ -614,6 +586,33 @@ class ReusableServerContextImpl extends ReusableServerContext return worldLogic.getEntity(entityId); } + /* + * Subcontexting + */ + + @Override + public Logic push(Vec3i location) { + ReusableServerContextImpl.this.push(location); + return this; + } + + @Override + public Logic push(Vec3i location, RelFace face) { + ReusableServerContextImpl.this.push(location, face); + return this; + } + + @Override + public Logic push(Vec3i location, RelFace face, int layer) { + ReusableServerContextImpl.this.push(location, face, layer); + return this; + } + + @Override + public void pop() { + ReusableServerContextImpl.this.pop(); + } + /* * MISC */ From 0f909039fe4c8dd67104e8024651ed487784bbce Mon Sep 17 00:00:00 2001 From: OLEGSHA Date: Fri, 6 Aug 2021 11:02:43 +0300 Subject: [PATCH 38/55] Renamed ReusableServerContext to DefaultServerContext --- ...Context.java => DefaultServerContext.java} | 28 ++++++++-------- ...java => DefaultServerContextBuilders.java} | 18 +++++------ ...mpl.java => DefaultServerContextImpl.java} | 32 +++++++++---------- 3 files changed, 39 insertions(+), 39 deletions(-) rename src/main/java/ru/windcorp/progressia/server/world/context/impl/{ReusableServerContext.java => DefaultServerContext.java} (79%) rename src/main/java/ru/windcorp/progressia/server/world/context/impl/{ReusableServerContextBuilders.java => DefaultServerContextBuilders.java} (79%) rename src/main/java/ru/windcorp/progressia/server/world/context/impl/{ReusableServerContextImpl.java => DefaultServerContextImpl.java} (93%) diff --git a/src/main/java/ru/windcorp/progressia/server/world/context/impl/ReusableServerContext.java b/src/main/java/ru/windcorp/progressia/server/world/context/impl/DefaultServerContext.java similarity index 79% rename from src/main/java/ru/windcorp/progressia/server/world/context/impl/ReusableServerContext.java rename to src/main/java/ru/windcorp/progressia/server/world/context/impl/DefaultServerContext.java index d32974c..afeadea 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/context/impl/ReusableServerContext.java +++ b/src/main/java/ru/windcorp/progressia/server/world/context/impl/DefaultServerContext.java @@ -44,14 +44,14 @@ import ru.windcorp.progressia.server.world.context.*; * Use wrappers to alter these properties. *

    * This class defines the outward-facing safe interface of the actual - * implementation located in {@link ReusableServerContextImpl}. The reasoning + * implementation located in {@link DefaultServerContextImpl}. The reasoning * for creating a subclass is to allow a single instance to implement both - * {@linkplain ReusableServerContextBuilders builder interfaces} and the context + * {@linkplain DefaultServerContextBuilders builder interfaces} and the context * interface without causing confusion around object states. * * @author javapony */ -public abstract class ReusableServerContext extends AbstractContextRO +public abstract class DefaultServerContext extends AbstractContextRO implements ServerTileContext { /** @@ -87,9 +87,9 @@ public abstract class ReusableServerContext extends AbstractContextRO reference) { + default DefaultServerContext at(TileGenericReferenceRO reference) { if (!reference.isValid()) { throw new IllegalArgumentException("Reference " + reference + " is invalid"); } @@ -54,12 +54,12 @@ public interface ReusableServerContextBuilders { } - public interface WithLocation extends ReusableServerContextBuilders { + public interface WithLocation extends DefaultServerContextBuilders { WithTileStack on(RelFace side); WithTileStack on(BlockFace side); - default ReusableServerContext on(TileGenericReferenceRO reference) { + default DefaultServerContext on(TileGenericReferenceRO reference) { if (!reference.isValid()) { throw new IllegalArgumentException("Reference " + reference + " is invalid"); } @@ -70,11 +70,11 @@ public interface ReusableServerContextBuilders { } - public interface WithTileStack extends ReusableServerContextBuilders { + public interface WithTileStack extends DefaultServerContextBuilders { - ReusableServerContext index(int index); + DefaultServerContext index(int index); - default ReusableServerContext index(TileGenericReferenceRO reference) { + default DefaultServerContext index(TileGenericReferenceRO reference) { if (!reference.isValid()) { throw new IllegalArgumentException("Reference " + reference + " is invalid"); } diff --git a/src/main/java/ru/windcorp/progressia/server/world/context/impl/ReusableServerContextImpl.java b/src/main/java/ru/windcorp/progressia/server/world/context/impl/DefaultServerContextImpl.java similarity index 93% rename from src/main/java/ru/windcorp/progressia/server/world/context/impl/ReusableServerContextImpl.java rename to src/main/java/ru/windcorp/progressia/server/world/context/impl/DefaultServerContextImpl.java index 2994205..a391dd0 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/context/impl/ReusableServerContextImpl.java +++ b/src/main/java/ru/windcorp/progressia/server/world/context/impl/DefaultServerContextImpl.java @@ -39,15 +39,15 @@ import ru.windcorp.progressia.server.world.block.BlockLogic; import ru.windcorp.progressia.server.world.context.ServerTileContext; import ru.windcorp.progressia.server.world.tile.TileLogic; -class ReusableServerContextImpl extends ReusableServerContext - implements ReusableServerContextBuilders.Empty, ReusableServerContextBuilders.WithWorld, - ReusableServerContextBuilders.WithLocation, ReusableServerContextBuilders.WithTileStack { +class DefaultServerContextImpl extends DefaultServerContext + implements DefaultServerContextBuilders.Empty, DefaultServerContextBuilders.WithWorld, + DefaultServerContextBuilders.WithLocation, DefaultServerContextBuilders.WithTileStack { /* * STATE MANAGEMENT & UTIL */ - public ReusableServerContextImpl() { + public DefaultServerContextImpl() { reuse(); } @@ -89,7 +89,7 @@ class ReusableServerContextImpl extends ReusableServerContext /** * The Logic view returned by {@link #logic()}. */ - protected final ReusableServerContextImpl.Logic logic = new Logic(); + protected final DefaultServerContextImpl.Logic logic = new Logic(); /** * Returns the Role currently assumed by this object. @@ -217,7 +217,7 @@ class ReusableServerContextImpl extends ReusableServerContext */ @Override - public ReusableServerContext build() { + public DefaultServerContext build() { assert requireBuilderRole(null); isBuilder = false; return this; @@ -270,7 +270,7 @@ class ReusableServerContextImpl extends ReusableServerContext */ @Override - public ReusableServerContext index(int index) { + public DefaultServerContext index(int index) { requireBuilderRole(Role.TILE_STACK); frame.layer = index; return build(); @@ -538,7 +538,7 @@ class ReusableServerContextImpl extends ReusableServerContext @Override public boolean isTagValid(Vec3i location, BlockFace face, int tag) { - return ReusableServerContextImpl.this.isTagValid(location, face, tag); + return DefaultServerContextImpl.this.isTagValid(location, face, tag); } @Override @@ -573,7 +573,7 @@ class ReusableServerContextImpl extends ReusableServerContext @Override public int getTag() { - return ReusableServerContextImpl.this.getTag(); + return DefaultServerContextImpl.this.getTag(); } @Override @@ -592,25 +592,25 @@ class ReusableServerContextImpl extends ReusableServerContext @Override public Logic push(Vec3i location) { - ReusableServerContextImpl.this.push(location); + DefaultServerContextImpl.this.push(location); return this; } @Override public Logic push(Vec3i location, RelFace face) { - ReusableServerContextImpl.this.push(location, face); + DefaultServerContextImpl.this.push(location, face); return this; } @Override public Logic push(Vec3i location, RelFace face, int layer) { - ReusableServerContextImpl.this.push(location, face, layer); + DefaultServerContextImpl.this.push(location, face, layer); return this; } @Override public void pop() { - ReusableServerContextImpl.this.pop(); + DefaultServerContextImpl.this.pop(); } /* @@ -618,13 +618,13 @@ class ReusableServerContextImpl extends ReusableServerContext */ @Override - public ReusableServerContext data() { - return ReusableServerContextImpl.this; + public DefaultServerContext data() { + return DefaultServerContextImpl.this; } @Override public String toString() { - return ReusableServerContextImpl.this + ".Logic"; + return DefaultServerContextImpl.this + ".Logic"; } } From 020802a89c32c35f19d140f780dbc7adc0f1d935 Mon Sep 17 00:00:00 2001 From: OLEGSHA Date: Sun, 8 Aug 2021 12:19:31 +0300 Subject: [PATCH 39/55] Added FilterServerContext and DefaultServerContextLogic - Added DefaultServerContextLogic - A standard implementation of ServerTileContext.Logic that delegates all methods to a ServerTileContext instance - Now used by DefaultServerContextImpl - Added FilterServerContext - A base for creating context wrappers --- .../impl/DefaultServerContextBuilders.java | 6 +- .../impl/DefaultServerContextImpl.java | 219 +++--------------- .../impl/DefaultServerContextLogic.java | 165 +++++++++++++ .../context/impl/FilterServerContext.java | 210 +++++++++++++++++ 4 files changed, 405 insertions(+), 195 deletions(-) create mode 100644 src/main/java/ru/windcorp/progressia/server/world/context/impl/DefaultServerContextLogic.java create mode 100644 src/main/java/ru/windcorp/progressia/server/world/context/impl/FilterServerContext.java diff --git a/src/main/java/ru/windcorp/progressia/server/world/context/impl/DefaultServerContextBuilders.java b/src/main/java/ru/windcorp/progressia/server/world/context/impl/DefaultServerContextBuilders.java index 6c10747..8069db8 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/context/impl/DefaultServerContextBuilders.java +++ b/src/main/java/ru/windcorp/progressia/server/world/context/impl/DefaultServerContextBuilders.java @@ -18,12 +18,12 @@ package ru.windcorp.progressia.server.world.context.impl; import glm.vec._3.i.Vec3i; +import ru.windcorp.progressia.common.world.WorldData; import ru.windcorp.progressia.common.world.generic.TileGenericReferenceRO; import ru.windcorp.progressia.common.world.generic.TileGenericStackRO; import ru.windcorp.progressia.common.world.rels.BlockFace; import ru.windcorp.progressia.common.world.rels.RelFace; import ru.windcorp.progressia.server.Server; -import ru.windcorp.progressia.server.world.WorldLogic; public interface DefaultServerContextBuilders { @@ -31,10 +31,10 @@ public interface DefaultServerContextBuilders { public interface Empty /* does not extend RSCB */ { - WithWorld in(Server server, WorldLogic world); + WithWorld in(Server server, WorldData world); default WithWorld inRealWorldOf(Server server) { - return in(server, server.getWorld()); + return in(server, server.getWorld().getData()); } } diff --git a/src/main/java/ru/windcorp/progressia/server/world/context/impl/DefaultServerContextImpl.java b/src/main/java/ru/windcorp/progressia/server/world/context/impl/DefaultServerContextImpl.java index a391dd0..1fa1178 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/context/impl/DefaultServerContextImpl.java +++ b/src/main/java/ru/windcorp/progressia/server/world/context/impl/DefaultServerContextImpl.java @@ -33,11 +33,6 @@ import ru.windcorp.progressia.common.world.rels.BlockFace; import ru.windcorp.progressia.common.world.rels.RelFace; import ru.windcorp.progressia.common.world.tile.TileData; import ru.windcorp.progressia.server.Server; -import ru.windcorp.progressia.server.world.TileLogicStack; -import ru.windcorp.progressia.server.world.WorldLogic; -import ru.windcorp.progressia.server.world.block.BlockLogic; -import ru.windcorp.progressia.server.world.context.ServerTileContext; -import ru.windcorp.progressia.server.world.tile.TileLogic; class DefaultServerContextImpl extends DefaultServerContext implements DefaultServerContextBuilders.Empty, DefaultServerContextBuilders.WithWorld, @@ -58,16 +53,10 @@ class DefaultServerContextImpl extends DefaultServerContext protected Server server; /** - * The relevant {@link WorldLogic} instance. If this is {@code null}, the + * The relevant {@link WorldData} instance. If this is {@code null}, the * role is {@link Role#NONE}. */ - protected WorldLogic worldLogic; - - /** - * The {@link WorldData} accessible through {@link #worldLogic}. This field - * is kept always in sync with {@link #worldLogic}. - */ - protected WorldData worldData; + protected WorldData world; /** * The {@link Random} instance exposed with {@link #getRandom()}. @@ -89,7 +78,7 @@ class DefaultServerContextImpl extends DefaultServerContext /** * The Logic view returned by {@link #logic()}. */ - protected final DefaultServerContextImpl.Logic logic = new Logic(); + protected final DefaultServerContextImpl.Logic logic = new DefaultServerContextLogic(this); /** * Returns the Role currently assumed by this object. @@ -199,8 +188,8 @@ class DefaultServerContextImpl extends DefaultServerContext public Empty reuse() { server = null; - worldLogic = null; - worldData = null; +// worldLogic = null; + world = null; while (isSubcontexting()) { pop(); @@ -228,11 +217,10 @@ class DefaultServerContextImpl extends DefaultServerContext */ @Override - public WithWorld in(Server server, WorldLogic world) { + public WithWorld in(Server server, WorldData world) { requireBuilderRole(Role.NONE); this.server = server; - this.worldLogic = world; - this.worldData = world.getData(); + this.world = world; return this; } @@ -261,7 +249,7 @@ class DefaultServerContextImpl extends DefaultServerContext @Override public WithTileStack on(BlockFace side) { requireBuilderRole(Role.LOCATION); - frame.face = side.relativize(worldLogic.getData().getUp(frame.location)); + frame.face = side.relativize(world.getUp(frame.location)); return this; } @@ -329,31 +317,31 @@ class DefaultServerContextImpl extends DefaultServerContext @Override public BlockData getBlock(Vec3i location) { assert requireContextRole(Role.WORLD); - return worldData.getBlock(location); + return world.getBlock(location); } @Override public boolean isLocationLoaded(Vec3i location) { assert requireContextRole(Role.WORLD); - return worldData.isLocationLoaded(location); + return world.isLocationLoaded(location); } @Override public TileData getTile(Vec3i location, BlockFace face, int layer) { assert requireContextRole(Role.WORLD); - return worldData.getTile(location, face, layer); + return world.getTile(location, face, layer); } @Override public boolean hasTile(Vec3i location, BlockFace face, int layer) { assert requireContextRole(Role.WORLD); - return worldData.hasTile(location, face, layer); + return world.hasTile(location, face, layer); } @Override public TileData getTileByTag(Vec3i location, BlockFace face, int tag) { assert requireContextRole(Role.WORLD); - TileDataStack stack = worldData.getTilesOrNull(location, face); + TileDataStack stack = world.getTilesOrNull(location, face); if (stack == null) return null; int layer = stack.getIndexByTag(tag); @@ -365,7 +353,7 @@ class DefaultServerContextImpl extends DefaultServerContext @Override public boolean isTagValid(Vec3i location, BlockFace face, int tag) { assert requireContextRole(Role.WORLD); - TileDataStack stack = worldData.getTilesOrNull(location, face); + TileDataStack stack = world.getTilesOrNull(location, face); if (stack == null) return false; return stack.getIndexByTag(tag) != -1; @@ -374,7 +362,7 @@ class DefaultServerContextImpl extends DefaultServerContext @Override public int getTag() { assert requireContextRole(Role.TILE); - TileDataStack stack = worldData.getTilesOrNull(frame.location, frame.face); + TileDataStack stack = world.getTilesOrNull(frame.location, frame.face); if (stack == null) return -1; return stack.getTagByIndex(frame.layer); @@ -383,7 +371,7 @@ class DefaultServerContextImpl extends DefaultServerContext @Override public int getTileCount(Vec3i location, BlockFace face) { assert requireContextRole(Role.TILE_STACK); - TileDataStack stack = worldData.getTilesOrNull(frame.location, frame.face); + TileDataStack stack = world.getTilesOrNull(frame.location, frame.face); if (stack == null) return 0; return stack.size(); @@ -392,25 +380,25 @@ class DefaultServerContextImpl extends DefaultServerContext @Override public Collection getEntities() { assert requireContextRole(Role.WORLD); - return worldData.getEntities(); + return world.getEntities(); } @Override public EntityData getEntity(long entityId) { assert requireContextRole(Role.WORLD); - return worldData.getEntity(entityId); + return world.getEntity(entityId); } @Override public GravityModel getGravityModel() { assert requireContextRole(Role.WORLD); - return worldData.getGravityModel(); + return world.getGravityModel(); } @Override public float getTime() { assert requireContextRole(Role.WORLD); - return worldData.getTime(); + return world.getTime(); } /* @@ -426,19 +414,19 @@ class DefaultServerContextImpl extends DefaultServerContext @Override public void setBlock(Vec3i blockInWorld, BlockData block) { assert requireContextRole(Role.WORLD); - worldData.setBlock(blockInWorld, block, true); + world.setBlock(blockInWorld, block, true); } @Override public void addTile(Vec3i location, BlockFace face, TileData tile) { assert requireContextRole(Role.WORLD); - worldData.getTiles(location, face).addFarthest(tile); + world.getTiles(location, face).addFarthest(tile); } @Override public void removeTile(Vec3i location, BlockFace face, int tag) { assert requireContextRole(Role.WORLD); - TileDataStack stack = worldData.getTilesOrNull(location, face); + TileDataStack stack = world.getTilesOrNull(location, face); if (stack == null) return; int layer = stack.getIndexByTag(tag); @@ -450,184 +438,31 @@ class DefaultServerContextImpl extends DefaultServerContext @Override public void addEntity(EntityData entity) { assert requireContextRole(Role.WORLD); - worldData.addEntity(entity); + world.addEntity(entity); } @Override public void removeEntity(long entityId) { assert requireContextRole(Role.WORLD); - worldData.removeEntity(entityId); + world.removeEntity(entityId); } @Override public void changeEntity(SE entity, StateChange change) { assert requireContextRole(Role.WORLD); - worldData.changeEntity(entity, change); + world.changeEntity(entity, change); } @Override public void advanceTime(float change) { assert requireContextRole(Role.WORLD); - worldData.advanceTime(change); + world.advanceTime(change); } /* * ServerWorldContext.Logic STUFF */ - private class Logic implements ServerTileContext.Logic { - - /* - * LOCATION GETTERS - */ - - @Override - public Server getServer() { - return server; - } - - @Override - public Vec3i getLocation() { - return frame.location; - } - - @Override - public RelFace getFace() { - return frame.face; - } - - @Override - public int getLayer() { - return frame.layer; - } - - /* - * RO CONTEXT INTERFACE - */ - - @Override - public boolean isReal() { - return true; - } - - @Override - public Random getRandom() { - return random; - } - - @Override - public double getTickLength() { - return server.getTickLength(); - } - - @Override - public BlockLogic getBlock(Vec3i location) { - assert requireContextRole(Role.WORLD); - return worldLogic.getBlock(location); - } - - @Override - public boolean isLocationLoaded(Vec3i location) { - return worldData.isLocationLoaded(location); - } - - @Override - public boolean hasTile(Vec3i location, BlockFace face, int layer) { - return worldData.hasTile(location, face, layer); - } - - @Override - public boolean isTagValid(Vec3i location, BlockFace face, int tag) { - return DefaultServerContextImpl.this.isTagValid(location, face, tag); - } - - @Override - public TileLogic getTile(Vec3i location, BlockFace face, int layer) { - assert requireContextRole(Role.WORLD); - return worldLogic.getTile(location, face, layer); - } - - @Override - public TileLogic getTileByTag(Vec3i location, BlockFace face, int tag) { - assert requireContextRole(Role.WORLD); - TileLogicStack stack = worldLogic.getTilesOrNull(location, face); - if (stack == null) { - return null; - } - int layer = stack.getIndexByTag(tag); - if (layer == -1) { - return null; - } - return stack.get(layer); - } - - @Override - public int getTileCount(Vec3i location, BlockFace face) { - assert requireContextRole(Role.WORLD); - TileLogicStack stack = worldLogic.getTilesOrNull(location, face); - if (stack == null) { - return 0; - } - return stack.size(); - } - - @Override - public int getTag() { - return DefaultServerContextImpl.this.getTag(); - } - - @Override - public Collection getEntities() { - return worldLogic.getEntities(); - } - - @Override - public EntityData getEntity(long entityId) { - return worldLogic.getEntity(entityId); - } - - /* - * Subcontexting - */ - - @Override - public Logic push(Vec3i location) { - DefaultServerContextImpl.this.push(location); - return this; - } - - @Override - public Logic push(Vec3i location, RelFace face) { - DefaultServerContextImpl.this.push(location, face); - return this; - } - - @Override - public Logic push(Vec3i location, RelFace face, int layer) { - DefaultServerContextImpl.this.push(location, face, layer); - return this; - } - - @Override - public void pop() { - DefaultServerContextImpl.this.pop(); - } - - /* - * MISC - */ - - @Override - public DefaultServerContext data() { - return DefaultServerContextImpl.this; - } - - @Override - public String toString() { - return DefaultServerContextImpl.this + ".Logic"; - } - } - @Override public Logic logic() { assert requireContextRole(Role.WORLD); diff --git a/src/main/java/ru/windcorp/progressia/server/world/context/impl/DefaultServerContextLogic.java b/src/main/java/ru/windcorp/progressia/server/world/context/impl/DefaultServerContextLogic.java new file mode 100644 index 0000000..4461d23 --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/server/world/context/impl/DefaultServerContextLogic.java @@ -0,0 +1,165 @@ +/* + * 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.server.world.context.impl; + +import java.util.Collection; +import java.util.Random; + +import glm.vec._3.i.Vec3i; +import ru.windcorp.progressia.common.world.block.BlockData; +import ru.windcorp.progressia.common.world.entity.EntityData; +import ru.windcorp.progressia.common.world.rels.BlockFace; +import ru.windcorp.progressia.common.world.rels.RelFace; +import ru.windcorp.progressia.common.world.tile.TileData; +import ru.windcorp.progressia.server.Server; +import ru.windcorp.progressia.server.world.block.BlockLogic; +import ru.windcorp.progressia.server.world.block.BlockLogicRegistry; +import ru.windcorp.progressia.server.world.context.ServerTileContext; +import ru.windcorp.progressia.server.world.tile.TileLogic; +import ru.windcorp.progressia.server.world.tile.TileLogicRegistry; + +public class DefaultServerContextLogic implements ServerTileContext.Logic { + + private final ServerTileContext parent; + + public DefaultServerContextLogic(ServerTileContext parent) { + this.parent = parent; + } + + @Override + public ServerTileContext data() { + return parent; + } + + @Override + public Server getServer() { + return parent.getServer(); + } + + @Override + public Random getRandom() { + return parent.getRandom(); + } + + @Override + public BlockLogic getBlock(Vec3i location) { + BlockData data = parent.getBlock(location); + return data == null ? null : BlockLogicRegistry.getInstance().get(data.getId()); + } + + @Override + public boolean isLocationLoaded(Vec3i location) { + return parent.isLocationLoaded(location); + } + + @Override + public ServerTileContext.Logic push(Vec3i location) { + parent.push(location); + return this; + } + + @Override + public ServerTileContext.Logic push(Vec3i location, RelFace face) { + parent.push(location, face); + return this; + } + + @Override + public ServerTileContext.Logic push(Vec3i location, RelFace face, int layer) { + parent.push(location, face, layer); + return this; + } + + @Override + public double getTickLength() { + return parent.getTickLength(); + } + + @Override + public TileLogic getTile(Vec3i location, BlockFace face, int layer) { + TileData data = parent.getTile(location, face, layer); + return data == null ? null : TileLogicRegistry.getInstance().get(data.getId()); + } + + @Override + public TileLogic getTileByTag(Vec3i location, BlockFace face, int tag) { + TileData data = parent.getTileByTag(location, face, tag); + return data == null ? null : TileLogicRegistry.getInstance().get(data.getId()); + } + + @Override + public Vec3i getLocation() { + return parent.getLocation(); + } + + @Override + public boolean hasTile(Vec3i location, BlockFace face, int layer) { + return parent.hasTile(location, face, layer); + } + + @Override + public boolean isTagValid(Vec3i location, BlockFace face, int tag) { + return parent.isTagValid(location, face, tag); + } + + @Override + public boolean isReal() { + return parent.isReal(); + } + + @Override + public int getTileCount(Vec3i location, BlockFace face) { + return parent.getTileCount(location, face); + } + + @Override + public Collection getEntities() { + return parent.getEntities(); + } + + @Override + public EntityData getEntity(long entityId) { + return parent.getEntity(entityId); + } + + @Override + public void pop() { + parent.pop(); + } + + @Override + public RelFace getFace() { + return parent.getFace(); + } + + @Override + public int getLayer() { + return parent.getLayer(); + } + + @Override + public int getTag() { + return parent.getTag(); + } + + @Override + public String toString() { + return parent + ".Logic"; + } + +} diff --git a/src/main/java/ru/windcorp/progressia/server/world/context/impl/FilterServerContext.java b/src/main/java/ru/windcorp/progressia/server/world/context/impl/FilterServerContext.java new file mode 100644 index 0000000..67e9a79 --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/server/world/context/impl/FilterServerContext.java @@ -0,0 +1,210 @@ +/* + * 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.server.world.context.impl; + +import java.util.Collection; +import java.util.Random; + +import glm.vec._3.i.Vec3i; +import ru.windcorp.progressia.common.state.StateChange; +import ru.windcorp.progressia.common.state.StatefulObject; +import ru.windcorp.progressia.common.world.GravityModel; +import ru.windcorp.progressia.common.world.block.BlockData; +import ru.windcorp.progressia.common.world.entity.EntityData; +import ru.windcorp.progressia.common.world.generic.EntityGeneric; +import ru.windcorp.progressia.common.world.rels.BlockFace; +import ru.windcorp.progressia.common.world.rels.RelFace; +import ru.windcorp.progressia.common.world.tile.TileData; +import ru.windcorp.progressia.server.Server; +import ru.windcorp.progressia.server.world.context.ServerBlockContext; +import ru.windcorp.progressia.server.world.context.ServerTileContext; +import ru.windcorp.progressia.server.world.context.ServerTileStackContext; + +/** + * This is an implementation of the server context tree that delegates all calls + * to a provided instance of {@link ServerTileContext}. + */ +public abstract class FilterServerContext implements ServerTileContext { + + protected final ServerTileContext parent; + protected final DefaultServerContextLogic logic = new DefaultServerContextLogic(this); + + public FilterServerContext(ServerTileContext parent) { + this.parent = parent; + } + + public ServerTileContext getParent() { + return parent; + } + + @Override + public int getLayer() { + return parent.getLayer(); + } + + @Override + public int getTag() { + return parent.getTag(); + } + + @Override + public RelFace getFace() { + return parent.getFace(); + } + + @Override + public Vec3i getLocation() { + return parent.getLocation(); + } + + @Override + public boolean isReal() { + return parent.isReal(); + } + + @Override + public void pop() { + parent.pop(); + } + + @Override + public boolean isImmediate() { + return parent.isImmediate(); + } + + @Override + public void addTile(Vec3i location, BlockFace face, TileData tile) { + parent.addTile(location, face, tile); + } + + @Override + public void removeTile(Vec3i location, BlockFace face, int tag) { + parent.removeTile(location, face, tag); + } + + @Override + public void addEntity(EntityData entity) { + parent.addEntity(entity); + } + + @Override + public void removeEntity(long entityId) { + parent.removeEntity(entityId); + } + + @Override + public void changeEntity(SE entity, StateChange change) { + parent.changeEntity(entity, change); + } + + @Override + public void advanceTime(float change) { + parent.advanceTime(change); + } + + @Override + public float getTime() { + return parent.getTime(); + } + + @Override + public GravityModel getGravityModel() { + return parent.getGravityModel(); + } + + @Override + public BlockData getBlock(Vec3i location) { + return parent.getBlock(location); + } + + @Override + public boolean isLocationLoaded(Vec3i location) { + return parent.isLocationLoaded(location); + } + + @Override + public TileData getTile(Vec3i location, BlockFace face, int layer) { + return parent.getTile(location, face, layer); + } + + @Override + public TileData getTileByTag(Vec3i location, BlockFace face, int tag) { + return parent.getTileByTag(location, face, tag); + } + + @Override + public boolean hasTile(Vec3i location, BlockFace face, int layer) { + return parent.hasTile(location, face, layer); + } + + @Override + public boolean isTagValid(Vec3i location, BlockFace face, int tag) { + return parent.isTagValid(location, face, tag); + } + + @Override + public int getTileCount(Vec3i location, BlockFace face) { + return parent.getTileCount(location, face); + } + + @Override + public Collection getEntities() { + return parent.getEntities(); + } + + @Override + public EntityData getEntity(long entityId) { + return parent.getEntity(entityId); + } + + @Override + public ServerBlockContext push(Vec3i location) { + return parent.push(location); + } + + @Override + public ServerTileStackContext push(Vec3i location, RelFace face) { + return parent.push(location, face); + } + + @Override + public ServerTileContext push(Vec3i location, RelFace face, int layer) { + return parent.push(location, face, layer); + } + + @Override + public Server getServer() { + return parent.getServer(); + } + + @Override + public Random getRandom() { + return parent.getRandom(); + } + + @Override + public double getTickLength() { + return parent.getTickLength(); + } + + @Override + public ServerTileContext.Logic logic() { + return logic; + } + +} From 5fb4c601fffdc7c978a77202fcd3e0743f91f91e Mon Sep 17 00:00:00 2001 From: OLEGSHA Date: Sun, 8 Aug 2021 14:07:07 +0300 Subject: [PATCH 40/55] Added ReportingServerContext - Added ReportingServerContext to listen for write events in contexts - Fixed method WorldGenericContextWO.setBlock(Vec3i, B) --- .../context/WorldGenericContextWO.java | 4 +- .../context/impl/FilterServerContext.java | 5 + .../context/impl/ReportingServerContext.java | 145 ++++++++++++++++++ 3 files changed, 151 insertions(+), 3 deletions(-) create mode 100644 src/main/java/ru/windcorp/progressia/server/world/context/impl/ReportingServerContext.java diff --git a/src/main/java/ru/windcorp/progressia/common/world/generic/context/WorldGenericContextWO.java b/src/main/java/ru/windcorp/progressia/common/world/generic/context/WorldGenericContextWO.java index 0a465a0..3f27b17 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/generic/context/WorldGenericContextWO.java +++ b/src/main/java/ru/windcorp/progressia/common/world/generic/context/WorldGenericContextWO.java @@ -63,9 +63,7 @@ public interface WorldGenericContextWO< * @param block the new block * @see #isImmediate() */ - default void setBlock(Vec3i location, B block) { - setBlock(location, block); - } + void setBlock(Vec3i location, B block); /** * Requests that a tile is added to the top of the tile stack at the given diff --git a/src/main/java/ru/windcorp/progressia/server/world/context/impl/FilterServerContext.java b/src/main/java/ru/windcorp/progressia/server/world/context/impl/FilterServerContext.java index 67e9a79..4896b84 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/context/impl/FilterServerContext.java +++ b/src/main/java/ru/windcorp/progressia/server/world/context/impl/FilterServerContext.java @@ -86,6 +86,11 @@ public abstract class FilterServerContext implements ServerTileContext { public boolean isImmediate() { return parent.isImmediate(); } + + @Override + public void setBlock(Vec3i location, BlockData block) { + parent.setBlock(location, block); + } @Override public void addTile(Vec3i location, BlockFace face, TileData tile) { diff --git a/src/main/java/ru/windcorp/progressia/server/world/context/impl/ReportingServerContext.java b/src/main/java/ru/windcorp/progressia/server/world/context/impl/ReportingServerContext.java new file mode 100644 index 0000000..302a47f --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/server/world/context/impl/ReportingServerContext.java @@ -0,0 +1,145 @@ +/* + * 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.server.world.context.impl; + +import glm.vec._3.i.Vec3i; +import ru.windcorp.progressia.common.state.StateChange; +import ru.windcorp.progressia.common.state.StatefulObject; +import ru.windcorp.progressia.common.world.block.BlockData; +import ru.windcorp.progressia.common.world.entity.EntityData; +import ru.windcorp.progressia.common.world.generic.EntityGeneric; +import ru.windcorp.progressia.common.world.rels.BlockFace; +import ru.windcorp.progressia.common.world.tile.TileData; +import ru.windcorp.progressia.server.world.context.ServerTileContext; + +public class ReportingServerContext extends FilterServerContext { + + public static interface ChangeListener { + + void onBlockSet(Vec3i location, BlockData block); + + void onTileAdded(Vec3i location, BlockFace face, TileData tile); + + void onTileRemoved(Vec3i location, BlockFace face, int tag); + + void onEntityAdded(EntityData entity); + + void onEntityRemoved(long entityId); + + void onEntityChanged(SE entity, StateChange change); + + void onTimeChanged(float change); + + } + + private ChangeListener listener = null; + private boolean passToParent = true; + + /** + * Creates a new {@link ReportingServerContext} instance that delegates + * method calls to the specified parent context. Write methods are always + * passed, disable with {@link #setPassToParent(boolean)}. No listener is + * set, set a listener with {@link #withListener(ChangeListener)}. + * + * @param parent the parent context + */ + public ReportingServerContext(ServerTileContext parent) { + super(parent); + } + + public ReportingServerContext withListener(ChangeListener listener) { + this.listener = listener; + return this; + } + + public ReportingServerContext setPassToParent(boolean pass) { + this.passToParent = pass; + return this; + } + + @Override + public void setBlock(Vec3i location, BlockData block) { + if (passToParent) { + super.setBlock(location, block); + } + if (listener != null) { + listener.onBlockSet(location, block); + } + } + + @Override + public void addTile(Vec3i location, BlockFace face, TileData tile) { + if (passToParent) { + super.addTile(location, face, tile); + } + if (listener != null) { + listener.onTileAdded(location, face, tile); + } + } + + @Override + public void removeTile(Vec3i location, BlockFace face, int tag) { + if (passToParent) { + super.removeTile(location, face, tag); + } + if (listener != null) { + listener.onTileRemoved(location, face, tag); + } + } + + @Override + public void addEntity(EntityData entity) { + if (passToParent) { + super.addEntity(entity); + } + if (listener != null) { + listener.onEntityAdded(entity); + } + } + + @Override + public void removeEntity(long entityId) { + if (passToParent) { + super.removeEntity(entityId); + } + if (listener != null) { + listener.onEntityRemoved(entityId); + } + } + + @Override + public void changeEntity(SE entity, StateChange change) { + if (passToParent) { + super.changeEntity(entity, change); + } + if (listener != null) { + listener.onEntityChanged(entity, change); + } + } + + @Override + public void advanceTime(float change) { + if (passToParent) { + super.advanceTime(change); + } + if (listener != null) { + listener.onTimeChanged(change); + } + } + +} From 0a45613e454debc137b7ac974de960a3ea946a9f Mon Sep 17 00:00:00 2001 From: OLEGSHA Date: Mon, 9 Aug 2021 20:32:15 +0300 Subject: [PATCH 41/55] Began work on integrating the new Contexts. Compiles but does not work - All TickContexts including TickContextMutable are deleted - Previous occurrences of TickContexts are replaced by appropriate ServerContexts - Added Context.popAndReturn methods for convenience Current known problems: - World does not generate properly on startup - No bulk methods in the new API (the likes of forEachTile, etc.) - AbsFace/RelFace ambiguity in the new API (see TestTileLogicGrass.java:68) - TestTileLogicGrass.java:53 is disabled for some reason --- .../common/world/context/Context.java | 20 + .../ru/windcorp/progressia/server/Server.java | 40 +- .../server/world/ChunkTickContext.java | 55 -- .../server/world/DefaultChunkLogic.java | 47 +- .../server/world/DefaultWorldLogic.java | 2 +- .../server/world/TickAndUpdateUtil.java | 132 +++-- .../progressia/server/world/TickContext.java | 49 -- .../server/world/TickContextMutable.java | 497 ------------------ .../server/world/UpdateTriggerer.java | 14 +- .../server/world/block/BlockLogic.java | 5 +- .../server/world/block/BlockTickContext.java | 114 ---- .../server/world/block/TickableBlock.java | 6 +- .../server/world/block/UpdateableBlock.java | 12 +- .../server/world/entity/EntityLogic.java | 4 +- .../world/tasks/BlockTriggeredUpdate.java | 9 +- .../server/world/tasks/ChangeEntity.java | 3 +- .../server/world/tasks/StateChange.java | 24 - .../server/world/tasks/TickChunk.java | 56 +- .../world/tasks/TileTriggeredUpdate.java | 19 +- .../server/world/tasks/WorldAccessor.java | 52 +- .../server/world/tile/HangingTileLogic.java | 21 +- .../server/world/tile/TSTickContext.java | 113 ---- .../server/world/tile/TickableTile.java | 6 +- .../server/world/tile/TileLogic.java | 5 +- .../server/world/tile/TileTickContext.java | 77 --- .../server/world/tile/UpdateableTile.java | 4 +- .../windcorp/progressia/test/TestContent.java | 6 +- .../test/TestEntityLogicStatie.java | 6 +- .../progressia/test/TestTileLogicGrass.java | 27 +- 29 files changed, 305 insertions(+), 1120 deletions(-) delete mode 100644 src/main/java/ru/windcorp/progressia/server/world/ChunkTickContext.java delete mode 100644 src/main/java/ru/windcorp/progressia/server/world/TickContext.java delete mode 100644 src/main/java/ru/windcorp/progressia/server/world/TickContextMutable.java delete mode 100644 src/main/java/ru/windcorp/progressia/server/world/block/BlockTickContext.java delete mode 100644 src/main/java/ru/windcorp/progressia/server/world/tasks/StateChange.java delete mode 100644 src/main/java/ru/windcorp/progressia/server/world/tile/TSTickContext.java delete mode 100644 src/main/java/ru/windcorp/progressia/server/world/tile/TileTickContext.java diff --git a/src/main/java/ru/windcorp/progressia/common/world/context/Context.java b/src/main/java/ru/windcorp/progressia/common/world/context/Context.java index 73644ea..786e1eb 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/context/Context.java +++ b/src/main/java/ru/windcorp/progressia/common/world/context/Context.java @@ -135,5 +135,25 @@ public interface Context { * modifications to revert. */ void pop(); + + default T popAndReturn(T result) { + pop(); + return result; + } + + default boolean popAndReturn(boolean result) { + pop(); + return result; + } + + default int popAndReturn(int result) { + pop(); + return result; + } + + default float popAndReturn(float result) { + pop(); + return result; + } } diff --git a/src/main/java/ru/windcorp/progressia/server/Server.java b/src/main/java/ru/windcorp/progressia/server/Server.java index 0896caa..a57ce2f 100644 --- a/src/main/java/ru/windcorp/progressia/server/Server.java +++ b/src/main/java/ru/windcorp/progressia/server/Server.java @@ -35,6 +35,9 @@ import ru.windcorp.progressia.server.management.load.ChunkRequestDaemon; import ru.windcorp.progressia.server.management.load.EntityRequestDaemon; import ru.windcorp.progressia.server.management.load.LoadManager; import ru.windcorp.progressia.server.world.DefaultWorldLogic; +import ru.windcorp.progressia.server.world.context.ServerWorldContext; +import ru.windcorp.progressia.server.world.context.impl.DefaultServerContext; +import ru.windcorp.progressia.server.world.context.impl.ReportingServerContext; import ru.windcorp.progressia.server.world.tasks.WorldAccessor; import ru.windcorp.progressia.server.world.ticking.Change; import ru.windcorp.progressia.server.world.ticking.Evaluation; @@ -97,6 +100,19 @@ public class Server { return world; } + /** + * Instantiates and returns an new {@link ServerWorldContext} instance + * suitable for read and write access to the server's world. This is the + * preferred way to query or change the world. + * + * @return the context + */ + public ServerWorldContext createContext() { + + return new ReportingServerContext(DefaultServerContext.empty().inRealWorldOf(this).build()).withListener(worldAccessor); + + } + /** * Returns this server's {@link ClientManager}. Use this to deal with * communications, e.g. send packets. @@ -219,16 +235,20 @@ public class Server { 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() { +// /** +// * 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; } diff --git a/src/main/java/ru/windcorp/progressia/server/world/ChunkTickContext.java b/src/main/java/ru/windcorp/progressia/server/world/ChunkTickContext.java deleted file mode 100644 index aec68fe..0000000 --- a/src/main/java/ru/windcorp/progressia/server/world/ChunkTickContext.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * 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.server.world; - -import java.util.function.Consumer; - -import glm.vec._3.i.Vec3i; -import ru.windcorp.progressia.common.world.DefaultChunkData; -import ru.windcorp.progressia.common.world.generic.GenericChunks; -import ru.windcorp.progressia.common.world.rels.AbsFace; -import ru.windcorp.progressia.server.world.block.BlockTickContext; - -public interface ChunkTickContext extends TickContext { - - Vec3i getChunk(); - - default DefaultChunkLogic getChunkLogic() { - return getWorld().getChunk(getChunk()); - } - - default DefaultChunkData getChunkData() { - DefaultChunkLogic chunkLogic = getChunkLogic(); - return chunkLogic == null ? null : chunkLogic.getData(); - } - - default AbsFace getUp() { - return getChunkData().getUp(); - } - - default void forEachBlock(Consumer action) { - TickContextMutable context = TickContextMutable.uninitialized(); - - GenericChunks.forEachBiC(blockInChunk -> { - context.rebuild().withServer(getServer()).withChunk(getChunk()).withBlockInChunk(blockInChunk).build(); - action.accept(context); - }); - } - -} diff --git a/src/main/java/ru/windcorp/progressia/server/world/DefaultChunkLogic.java b/src/main/java/ru/windcorp/progressia/server/world/DefaultChunkLogic.java index 69fed5e..0e2dbbe 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/DefaultChunkLogic.java +++ b/src/main/java/ru/windcorp/progressia/server/world/DefaultChunkLogic.java @@ -34,9 +34,13 @@ import ru.windcorp.progressia.common.world.rels.BlockFace; import ru.windcorp.progressia.common.world.rels.RelFace; import ru.windcorp.progressia.common.world.TileDataStack; import ru.windcorp.progressia.common.world.TileDataReference; +import ru.windcorp.progressia.server.Server; import ru.windcorp.progressia.server.world.block.BlockLogic; import ru.windcorp.progressia.server.world.block.BlockLogicRegistry; import ru.windcorp.progressia.server.world.block.TickableBlock; +import ru.windcorp.progressia.server.world.context.ServerBlockContextRO; +import ru.windcorp.progressia.server.world.context.ServerTileContextRO; +import ru.windcorp.progressia.server.world.context.ServerWorldContextRO; import ru.windcorp.progressia.server.world.tasks.TickChunk; import ru.windcorp.progressia.server.world.ticking.TickingPolicy; import ru.windcorp.progressia.server.world.tile.TickableTile; @@ -221,28 +225,45 @@ public class DefaultChunkLogic implements ChunkLogic { } private void tmp_generateTickLists() { - ChunkTickContext context = TickContextMutable.start().withChunk(this).build(); - - context.forEachBlock(bctxt -> { - BlockLogic block = bctxt.getBlock(); + ServerWorldContextRO context = Server.getCurrentServer().createContext(); + Vec3i blockInChunk = new Vec3i(); + + forEachBiW(location -> { + + ServerBlockContextRO blockContext = context.push(location); + + BlockLogic block = blockContext.logic().getBlock(); + Coordinates.convertInWorldToInChunk(location, blockInChunk); if (!(block instanceof TickableBlock)) return; - if (((TickableBlock) block).getTickingPolicy(bctxt) == TickingPolicy.REGULAR) { - tickingBlocks.add(Coordinates.convertInWorldToInChunk(bctxt.getBlockInWorld(), null)); + if (((TickableBlock) block).getTickingPolicy(blockContext) == TickingPolicy.REGULAR) { + tickingBlocks.add(blockInChunk); } - bctxt.forEachFace(fctxt -> fctxt.forEachTile(tctxt -> { - TileLogic tile = tctxt.getTile(); + for (RelFace face : RelFace.getFaces()) { + TileLogicStack stack = getTilesOrNull(blockInChunk, face); + if (stack == null || stack.isEmpty()) continue; + + for (int i = 0; i < stack.size(); ++i) { + ServerTileContextRO tileContext = blockContext.push(face, i); + + TileLogic tile = stack.get(i); - if (!(tile instanceof TickableTile)) - return; + if (!(tile instanceof TickableTile)) + return; - if (((TickableTile) tile).getTickingPolicy(tctxt) == TickingPolicy.REGULAR) { - tickingTiles.add(tctxt.getReference()); + if (((TickableTile) tile).getTickingPolicy(tileContext) == TickingPolicy.REGULAR) { + tickingTiles.add(stack.getData().getReference(i)); + } + + tileContext.pop(); } - })); + } + + blockContext.pop(); + }); } diff --git a/src/main/java/ru/windcorp/progressia/server/world/DefaultWorldLogic.java b/src/main/java/ru/windcorp/progressia/server/world/DefaultWorldLogic.java index d578fa7..f2b1883 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/DefaultWorldLogic.java +++ b/src/main/java/ru/windcorp/progressia/server/world/DefaultWorldLogic.java @@ -65,7 +65,7 @@ public class DefaultWorldLogic implements WorldLogic { } }); - data.addListener(ChunkDataListeners.createAdder(new UpdateTriggerer(server))); + data.addListener(ChunkDataListeners.createAdder(new UpdateTriggerer(server.getWorldAccessor___really_bad_dont_use()))); } @Override diff --git a/src/main/java/ru/windcorp/progressia/server/world/TickAndUpdateUtil.java b/src/main/java/ru/windcorp/progressia/server/world/TickAndUpdateUtil.java index 112d722..286a557 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/TickAndUpdateUtil.java +++ b/src/main/java/ru/windcorp/progressia/server/world/TickAndUpdateUtil.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.server.world; import glm.vec._3.i.Vec3i; @@ -24,19 +24,26 @@ import ru.windcorp.progressia.common.world.entity.EntityData; import ru.windcorp.progressia.common.world.rels.BlockFace; import ru.windcorp.progressia.server.Server; import ru.windcorp.progressia.server.world.block.BlockLogic; -import ru.windcorp.progressia.server.world.block.BlockTickContext; import ru.windcorp.progressia.server.world.block.TickableBlock; import ru.windcorp.progressia.server.world.block.UpdateableBlock; +import ru.windcorp.progressia.server.world.context.ServerBlockContext; +import ru.windcorp.progressia.server.world.context.ServerTileContext; +import ru.windcorp.progressia.server.world.context.ServerTileStackContext; +import ru.windcorp.progressia.server.world.context.ServerWorldContext; import ru.windcorp.progressia.server.world.entity.EntityLogic; import ru.windcorp.progressia.server.world.entity.EntityLogicRegistry; import ru.windcorp.progressia.server.world.tile.TickableTile; import ru.windcorp.progressia.server.world.tile.TileLogic; -import ru.windcorp.progressia.server.world.tile.TileTickContext; import ru.windcorp.progressia.server.world.tile.UpdateableTile; public class TickAndUpdateUtil { - public static void tickBlock(TickableBlock block, BlockTickContext context) { + public static void tickBlock(ServerBlockContext context) { + BlockLogic uncheckedBlock = context.logic().getBlock(); + if (!(uncheckedBlock instanceof BlockLogic)) { + return; + } + TickableBlock block = (TickableBlock) uncheckedBlock; try { block.tick(context); } catch (Exception e) { @@ -44,16 +51,21 @@ public class TickAndUpdateUtil { } } - public static void tickBlock(DefaultWorldLogic world, Vec3i blockInWorld) { - BlockLogic block = world.getBlock(blockInWorld); - if (!(block instanceof TickableBlock)) - return; // also checks nulls - - BlockTickContext tickContext = TickContextMutable.start().withWorld(world).withBlock(blockInWorld).build(); - tickBlock((TickableBlock) block, tickContext); + public static void tickBlock(Server server, Vec3i blockInWorld) { + BlockLogic block = server.getWorld().getBlock(blockInWorld); + if (!(block instanceof TickableBlock)) { + return; + } + ServerBlockContext context = server.createContext().push(blockInWorld); + tickBlock(context); } - public static void tickTile(TickableTile tile, TileTickContext context) { + public static void tickTile(ServerTileContext context) { + TileLogic uncheckedTile = context.logic().getTile(); + if (!(uncheckedTile instanceof TickableTile)) { + return; + } + TickableTile tile = (TickableTile) uncheckedTile; try { tile.tick(context); } catch (Exception e) { @@ -61,82 +73,88 @@ public class TickAndUpdateUtil { } } - public static void tickTile(DefaultWorldLogic world, Vec3i blockInWorld, BlockFace face, int layer) { - TileLogic tile = world.getTile(blockInWorld, face, layer); + public static void tickTile(Server server, Vec3i blockInWorld, BlockFace face, int layer) { + TileLogic tile = server.getWorld().getTile(blockInWorld, face, layer); if (!(tile instanceof TickableTile)) { return; } - - TileTickContext tickContext = TickContextMutable.start().withWorld(world).withBlock(blockInWorld).withFace(face) - .withLayer(layer); - tickTile((TickableTile) tile, tickContext); + ServerTileContext context = server.createContext() + .push(blockInWorld, face.relativize(server.getWorld().getUp(blockInWorld)), layer); + tickTile(context); } - public static void tickTiles(DefaultWorldLogic world, Vec3i blockInWorld, BlockFace face) { - if (!world.isLocationLoaded(blockInWorld)) { + public static void tickTiles(Server server, Vec3i blockInWorld, BlockFace face) { + if (!server.getWorld().hasTiles(blockInWorld, face)) { return; } - - TickContextMutable.start().withWorld(world).withBlock(blockInWorld).withFace(face).build() - .forEachTile(context -> { - TileLogic tile = context.getTile(); - if (tile instanceof TickableTile) { - tickTile((TickableTile) tile, context); - } - }); + + ServerTileStackContext context = server.createContext() + .push(blockInWorld, face.relativize(server.getWorld().getUp(blockInWorld))); + for (int i = 0; i < context.getTileCount(); ++i) { + tickTile(context.push(i)); + context.pop(); + } } - public static void updateBlock(UpdateableBlock block, BlockTickContext context) { + public static void updateBlock(ServerBlockContext context) { + BlockLogic uncheckedBlock = context.logic().getBlock(); + if (!(uncheckedBlock instanceof BlockLogic)) { + return; + } + UpdateableBlock block = (UpdateableBlock) uncheckedBlock; try { block.update(context); } catch (Exception e) { - throw CrashReports.report(e, "Could not update block {}", block); + throw CrashReports.report(e, "Could not update block %s", block); } } - public static void updateBlock(DefaultWorldLogic world, Vec3i blockInWorld) { - BlockLogic block = world.getBlock(blockInWorld); - if (!(block instanceof UpdateableBlock)) - return; // also checks nulls - - BlockTickContext tickContext = TickContextMutable.start().withWorld(world).withBlock(blockInWorld).build(); - updateBlock((UpdateableBlock) block, tickContext); + public static void updateBlock(Server server, Vec3i blockInWorld) { + BlockLogic block = server.getWorld().getBlock(blockInWorld); + if (!(block instanceof UpdateableBlock)) { + return; + } + ServerBlockContext context = server.createContext().push(blockInWorld); + updateBlock(context); } - public static void updateTile(UpdateableTile tile, TileTickContext context) { + public static void updateTile(ServerTileContext context) { + TileLogic uncheckedTile = context.logic().getTile(); + if (!(uncheckedTile instanceof UpdateableTile)) { + return; + } + UpdateableTile tile = (UpdateableTile) uncheckedTile; try { tile.update(context); } catch (Exception e) { - throw CrashReports.report(e, "Could not update tile {}", tile); + throw CrashReports.report(e, "Could not tick tile %s", tile); } } - public static void updateTile(DefaultWorldLogic world, Vec3i blockInWorld, BlockFace face, int layer) { - TileLogic tile = world.getTile(blockInWorld, face, layer); + public static void updateTile(Server server, Vec3i blockInWorld, BlockFace face, int layer) { + TileLogic tile = server.getWorld().getTile(blockInWorld, face, layer); if (!(tile instanceof UpdateableTile)) { return; } - - TileTickContext tickContext = TickContextMutable.start().withWorld(world).withBlock(blockInWorld).withFace(face) - .withLayer(layer); - updateTile((UpdateableTile) tile, tickContext); + ServerTileContext context = server.createContext() + .push(blockInWorld, face.relativize(server.getWorld().getUp(blockInWorld)), layer); + updateTile(context); } - public static void updateTiles(DefaultWorldLogic world, Vec3i blockInWorld, BlockFace face) { - if (!world.isLocationLoaded(blockInWorld)) { + public static void updateTiles(Server server, Vec3i blockInWorld, BlockFace face) { + if (!server.getWorld().hasTiles(blockInWorld, face)) { return; } - - TickContextMutable.start().withWorld(world).withBlock(blockInWorld).withFace(face).build() - .forEachTile(context -> { - TileLogic tile = context.getTile(); - if (tile instanceof UpdateableTile) { - updateTile((UpdateableTile) tile, context); - } - }); + + ServerTileStackContext context = server.createContext() + .push(blockInWorld, face.relativize(server.getWorld().getUp(blockInWorld))); + for (int i = 0; i < context.getTileCount(); ++i) { + updateTile(context.push(i)); + context.pop(); + } } - public static void tickEntity(EntityLogic logic, EntityData data, TickContext context) { + public static void tickEntity(EntityLogic logic, EntityData data, ServerWorldContext context) { try { logic.tick(data, context); } catch (Exception e) { @@ -148,7 +166,7 @@ public class TickAndUpdateUtil { tickEntity( EntityLogicRegistry.getInstance().get(data.getId()), data, - TickContextMutable.start().withServer(server).build() + server.createContext() ); } diff --git a/src/main/java/ru/windcorp/progressia/server/world/TickContext.java b/src/main/java/ru/windcorp/progressia/server/world/TickContext.java deleted file mode 100644 index 5d92f4a..0000000 --- a/src/main/java/ru/windcorp/progressia/server/world/TickContext.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * 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.server.world; - -import java.util.Random; - -import ru.windcorp.progressia.common.world.DefaultWorldData; -import ru.windcorp.progressia.server.Server; -import ru.windcorp.progressia.server.world.tasks.WorldAccessor; - -public interface TickContext { - - float getTickLength(); - - Server getServer(); - - default DefaultWorldLogic getWorld() { - return getServer().getWorld(); - } - - default WorldAccessor getAccessor() { - return getServer().getWorldAccessor(); - } - - default Random getRandom() { - return getServer().getAdHocRandom(); - } - - default DefaultWorldData getWorldData() { - return getWorld().getData(); - } - -} diff --git a/src/main/java/ru/windcorp/progressia/server/world/TickContextMutable.java b/src/main/java/ru/windcorp/progressia/server/world/TickContextMutable.java deleted file mode 100644 index a5eb592..0000000 --- a/src/main/java/ru/windcorp/progressia/server/world/TickContextMutable.java +++ /dev/null @@ -1,497 +0,0 @@ -/* - * 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.server.world; - -import java.util.Objects; -import java.util.function.Consumer; -import java.util.function.Function; - -import glm.vec._3.i.Vec3i; -import ru.windcorp.progressia.common.world.DefaultChunkData; -import ru.windcorp.progressia.common.world.Coordinates; -import ru.windcorp.progressia.common.world.generic.TileGenericStackRO; -import ru.windcorp.progressia.common.world.rels.BlockFace; -import ru.windcorp.progressia.common.world.rels.RelFace; -import ru.windcorp.progressia.common.world.TileDataStack; -import ru.windcorp.progressia.common.world.TileDataReference; -import ru.windcorp.progressia.server.Server; -import ru.windcorp.progressia.server.world.block.BlockTickContext; -import ru.windcorp.progressia.server.world.tile.TSTickContext; -import ru.windcorp.progressia.server.world.tile.TileTickContext; - -public abstract class TickContextMutable implements BlockTickContext, TSTickContext, TileTickContext { - - private static enum Role { - NONE, WORLD, CHUNK, BLOCK, TILE_STACK, TILE; - } - - /* - * TickContextMutable interface - */ - - // Only TickContextMutable.Impl can extend; extend Impl if need be - private TickContextMutable() { - } - - public abstract Builder.Empty rebuild(); - - /* - * Static methods - */ - - public static TickContextMutable uninitialized() { - return new Impl(); - } - - public static Builder.Empty start() { - return uninitialized().rebuild(); - } - - public static Builder.World copyWorld(TickContext context) { - return start().withServer(context.getServer()); - } - - public static Builder.Chunk copyChunk(ChunkTickContext context) { - return start().withChunk(context.getChunkLogic()); - } - - public static Builder.Block copyBlock(BlockTickContext context) { - return copyWorld(context).withBlock(context.getBlockInWorld()); - } - - public static Builder.TileStack copyTS(TSTickContext context) { - return copyBlock(context).withFace(context.getFace()); - } - - public static TileTickContext copyTile(TileTickContext context) { - return copyTS(context).withLayer(context.getLayer()); - } - - /* - * Builder interfaces - */ - - public static interface Builder { - TickContextMutable build(); - - public static interface Empty /* does not extend Builder */ { - World withServer(Server server); - - default Builder.World withWorld(DefaultWorldLogic world) { - Objects.requireNonNull(world, "world"); - return withServer(world.getServer()); - } - - default Builder.Chunk withChunk(DefaultChunkLogic chunk) { - Objects.requireNonNull(chunk, "chunk"); - return withWorld(chunk.getWorld()).withChunk(chunk.getPosition()); - } - } - - public static interface World extends Builder { - Chunk withChunk(Vec3i chunk); - - Block withBlock(Vec3i blockInWorld); - - TileStack withTS(TileGenericStackRO tileStack); - - default Builder.Chunk withChunk(DefaultChunkData chunk) { - Objects.requireNonNull(chunk, "chunk"); - return withChunk(chunk.getPosition()); - } - - default TileTickContext withTile(TileDataReference ref) { - Objects.requireNonNull(ref, "ref"); - return withTS(ref.getStack()).withLayer(ref.getIndex()); - } - } - - public static interface Chunk extends Builder { - Builder.Block withBlockInChunk(Vec3i blockInChunk); - } - - public static interface Block extends Builder { - Builder.TileStack withFace(BlockFace face); - } - - public static interface TileStack extends Builder { - TickContextMutable withLayer(int layer); - } - } - - /* - * Impl - */ - - public static class Impl - extends TickContextMutable - implements Builder.Empty, Builder.World, Builder.Chunk, Builder.Block, Builder.TileStack { - - protected Impl() { - } - - protected Server server; - protected final Vec3i chunk = new Vec3i(); - protected final Vec3i blockInWorld = new Vec3i(); - protected RelFace face; - protected int layer; - - protected Role role = Role.NONE; - protected boolean isBeingBuilt = false; - - /** - * Updated lazily - */ - protected final Vec3i blockInChunk = new Vec3i(); - - /* - * TickContextMutable - */ - - @Override - public Server getServer() { - checkContextState(Role.WORLD); - return this.server; - } - - @Override - public float getTickLength() { - checkContextState(Role.WORLD); - return (float) this.server.getTickLength(); - } - - @Override - public Vec3i getChunk() { - checkContextState(Role.CHUNK); - return this.chunk; - } - - @Override - public Vec3i getBlockInWorld() { - checkContextState(Role.BLOCK); - return this.blockInWorld; - } - - @Override - public RelFace getFace() { - checkContextState(Role.TILE_STACK); - return this.face; - } - - @Override - public int getLayer() { - checkContextState(Role.TILE); - return this.layer; - } - - @Override - public Builder.Empty rebuild() { - this.role = Role.NONE; - this.isBeingBuilt = true; - - this.server = null; - this.chunk.set(0); - this.blockInWorld.set(0); - this.face = null; - this.layer = -1; - - return this; - } - - /* - * Builder - * memo: do NOT use Context getters, they throw ISEs - */ - - @Override - public TickContextMutable build() { - checkBuilderState(null); - this.isBeingBuilt = false; - return this; - } - - @Override - public World withServer(Server server) { - Objects.requireNonNull(server, "server"); - checkBuilderState(Role.NONE); - this.server = server; - this.role = Role.WORLD; - return this; - } - - @Override - public Chunk withChunk(Vec3i chunk) { - Objects.requireNonNull(chunk, "chunk"); - checkBuilderState(Role.WORLD); - - this.chunk.set(chunk.x, chunk.y, chunk.z); - - this.role = Role.CHUNK; - return this; - } - - @Override - public Block withBlock(Vec3i blockInWorld) { - Objects.requireNonNull(blockInWorld, "blockInWorld"); - checkBuilderState(Role.WORLD); - - this.blockInWorld.set(blockInWorld.x, blockInWorld.y, blockInWorld.z); - Coordinates.convertInWorldToChunk(blockInWorld, this.chunk); - - this.role = Role.BLOCK; - return this; - } - - @Override - public TileStack withTS(TileGenericStackRO tileStack) { - Objects.requireNonNull(tileStack, "tileStack"); - - return withBlock( - tileStack.getBlockInWorld(this.blockInWorld) // This is safe - ).withFace(tileStack.getFace()); - } - - @Override - public Block withBlockInChunk(Vec3i blockInChunk) { - Objects.requireNonNull(blockInChunk, "blockInChunk"); - checkBuilderState(Role.CHUNK); - - Coordinates.getInWorld(this.chunk, blockInChunk, this.blockInWorld); - - this.role = Role.BLOCK; - return this; - } - - @Override - public TileStack withFace(BlockFace face) { - Objects.requireNonNull(face, "face"); - checkBuilderState(Role.BLOCK); - - this.face = face.relativize(server.getWorld().getChunk(chunk).getUp()); - - this.role = Role.TILE_STACK; - return this; - } - - @Override - public TickContextMutable withLayer(int layer) { - checkBuilderState(Role.TILE); - - this.layer = layer; - - this.role = Role.TILE; - return build(); - } - - /* - * Optimization - */ - - @Override - public Vec3i getBlockInChunk() { - return Coordinates.convertInWorldToInChunk(getBlockInWorld(), this.blockInChunk); - } - - @Override - public void forEachBlock(Consumer action) { - checkContextState(Role.CHUNK); - - Vec3i v = this.blockInWorld; - - int previousX = v.x; - int previousY = v.y; - int previousZ = v.z; - Role previousRole = this.role; - - this.role = Role.BLOCK; - - final int minX = Coordinates.getInWorld(chunk.x, 0); - final int minY = Coordinates.getInWorld(chunk.y, 0); - final int minZ = Coordinates.getInWorld(chunk.z, 0); - final int size = DefaultChunkData.BLOCKS_PER_CHUNK; - - for (v.x = minX; v.x < minX + size; ++v.x) { - for (v.y = minY; v.y < minY + size; ++v.y) { - for (v.z = minZ; v.z < minZ + size; ++v.z) { - action.accept(this); - } - } - } - - this.role = previousRole; - blockInWorld.set(previousX, previousY, previousZ); - } - - @Override - public void forEachFace(Consumer action) { - checkContextState(Role.BLOCK); - RelFace previousFace = this.face; - Role previousRole = this.role; - - this.role = Role.TILE_STACK; - for (int i = 0; i < BlockFace.BLOCK_FACE_COUNT; ++i) { - this.face = RelFace.getFaces().get(i); - action.accept(this); - } - - this.role = previousRole; - this.face = previousFace; - } - - @Override - public R evalNeighbor(Vec3i direction, Function action) { - this.blockInWorld.add(direction); - R result = action.apply(this); - this.blockInWorld.sub(direction); - - return result; - } - - @Override - public void forNeighbor(Vec3i direction, Consumer action) { - this.blockInWorld.add(direction); - action.accept(this); - this.blockInWorld.sub(direction); - } - - @Override - public boolean forEachTile(Consumer action) { - checkContextState(Role.TILE_STACK); - int previousLayer = this.layer; - Role previousRole = this.role; - - this.role = Role.TILE; - TileDataStack stack = getTDSOrNull(); - if (stack == null || stack.isEmpty()) - return false; - - for (this.layer = 0; this.layer < stack.size(); ++this.layer) { - action.accept(this); - } - - this.role = previousRole; - this.layer = previousLayer; - return true; - } - - @Override - public R evalComplementary(Function action) { - Objects.requireNonNull(action, "action"); - checkContextState(Role.TILE_STACK); - - Vec3i vector = this.face.getVector(getUp()); - - this.blockInWorld.add(vector); - this.face = this.face.getCounter(); - R result = action.apply(this); - this.face = this.face.getCounter(); - this.blockInWorld.sub(vector); - - return result; - } - - @Override - public void forComplementary(Consumer action) { - Objects.requireNonNull(action, "action"); - checkContextState(Role.TILE_STACK); - - Vec3i vector = this.face.getVector(getUp()); - - this.blockInWorld.add(vector); - this.face = this.face.getCounter(); - action.accept(this); - this.face = this.face.getCounter(); - this.blockInWorld.sub(vector); - } - - /* - * Misc - */ - - protected void checkContextState(Role requiredRole) { - if (isBeingBuilt) { - throw new IllegalStateException("This context is still being built"); - } - - if ((role == null) || (requiredRole.compareTo(role) > 0)) { - throw new IllegalStateException( - "This context is currently initialized as " + role + "; requested " + requiredRole - ); - } - } - - protected void checkBuilderState(Role requiredRole) { - if (!isBeingBuilt) { - throw new IllegalStateException("This context is already built"); - } - - if (requiredRole == null) { - if (role == Role.NONE) { - throw new IllegalStateException("This context is currently not initialized"); - } - } else { - if (role != requiredRole) { - throw new IllegalStateException( - "This context is currently initialized as " + role + "; requested " + requiredRole - ); - } - } - } - - @Override - public String toString() { - final String format; - - switch (this.role) { - case WORLD: - format = "TickContext"; - break; - case CHUNK: - format = "(%2$d; %3$d; %4$d)"; - break; - case BLOCK: - format = "(%5$d; %6$d; %7$d)"; - break; - case TILE_STACK: - format = "((%5$d; %6$d; %7$d); %8$6s)"; - break; - case TILE: - format = "((%5$d; %6$d; %7$d); %8$6s; %9$d)"; - break; - case NONE: - default: - format = "Uninitialized TickContextMutable"; - break; - } - - return String.format( - format, - this.chunk.x, - this.chunk.y, - this.chunk.z, - this.blockInWorld.x, - this.blockInWorld.y, - this.blockInWorld.z, - this.face, - this.layer - ); - } - } - -} diff --git a/src/main/java/ru/windcorp/progressia/server/world/UpdateTriggerer.java b/src/main/java/ru/windcorp/progressia/server/world/UpdateTriggerer.java index fc22047..8175937 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/UpdateTriggerer.java +++ b/src/main/java/ru/windcorp/progressia/server/world/UpdateTriggerer.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.server.world; import glm.vec._3.i.Vec3i; @@ -25,14 +25,14 @@ import ru.windcorp.progressia.common.world.Coordinates; import ru.windcorp.progressia.common.world.block.BlockData; import ru.windcorp.progressia.common.world.rels.RelFace; import ru.windcorp.progressia.common.world.tile.TileData; -import ru.windcorp.progressia.server.Server; +import ru.windcorp.progressia.server.world.tasks.WorldAccessor; public class UpdateTriggerer implements ChunkDataListener { - private final Server server; + private final WorldAccessor worldAccessor; - public UpdateTriggerer(Server server) { - this.server = server; + public UpdateTriggerer(WorldAccessor worldAccessor) { + this.worldAccessor = worldAccessor; } @Override @@ -42,7 +42,7 @@ public class UpdateTriggerer implements ChunkDataListener { BlockData previous, BlockData current ) { - server.getWorldAccessor().triggerUpdates(Coordinates.getInWorld(chunk.getPosition(), blockInChunk, null)); + worldAccessor.triggerUpdates(Coordinates.getInWorld(chunk.getPosition(), blockInChunk, null)); } @Override @@ -53,7 +53,7 @@ public class UpdateTriggerer implements ChunkDataListener { TileData tile, boolean wasAdded ) { - server.getWorldAccessor().triggerUpdates(Coordinates.getInWorld(chunk.getPosition(), blockInChunk, null), face); + worldAccessor.triggerUpdates(Coordinates.getInWorld(chunk.getPosition(), blockInChunk, null), face); } } diff --git a/src/main/java/ru/windcorp/progressia/server/world/block/BlockLogic.java b/src/main/java/ru/windcorp/progressia/server/world/block/BlockLogic.java index 1d08194..7b2204f 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/block/BlockLogic.java +++ b/src/main/java/ru/windcorp/progressia/server/world/block/BlockLogic.java @@ -21,6 +21,7 @@ package ru.windcorp.progressia.server.world.block; import ru.windcorp.progressia.common.util.namespaces.Namespaced; import ru.windcorp.progressia.common.world.generic.BlockGeneric; import ru.windcorp.progressia.common.world.rels.RelFace; +import ru.windcorp.progressia.server.world.context.ServerBlockContextRO; public class BlockLogic extends Namespaced implements BlockGeneric { @@ -28,7 +29,7 @@ public class BlockLogic extends Namespaced implements BlockGeneric { super(id); } - public boolean isSolid(BlockTickContext context, RelFace face) { + public boolean isSolid(ServerBlockContextRO context, RelFace face) { return isSolid(face); } @@ -36,7 +37,7 @@ public class BlockLogic extends Namespaced implements BlockGeneric { return true; } - public boolean isTransparent(BlockTickContext context) { + public boolean isTransparent(ServerBlockContextRO context) { return isTransparent(); } diff --git a/src/main/java/ru/windcorp/progressia/server/world/block/BlockTickContext.java b/src/main/java/ru/windcorp/progressia/server/world/block/BlockTickContext.java deleted file mode 100644 index 7069aa9..0000000 --- a/src/main/java/ru/windcorp/progressia/server/world/block/BlockTickContext.java +++ /dev/null @@ -1,114 +0,0 @@ -/* - * 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.server.world.block; - -import java.util.Objects; -import java.util.function.Consumer; -import java.util.function.Function; - -import glm.vec._3.i.Vec3i; -import ru.windcorp.progressia.common.world.Coordinates; -import ru.windcorp.progressia.common.world.block.BlockData; -import ru.windcorp.progressia.common.world.rels.AbsFace; -import ru.windcorp.progressia.common.world.rels.BlockRelation; -import ru.windcorp.progressia.server.world.ChunkTickContext; -import ru.windcorp.progressia.server.world.TickContextMutable; -import ru.windcorp.progressia.server.world.tile.TSTickContext; - -public interface BlockTickContext extends ChunkTickContext { - - /** - * Returns the current world coordinates. - * - * @return the world coordinates of the block being ticked - */ - Vec3i getBlockInWorld(); - - default Vec3i getBlockInChunk() { - return Coordinates.convertInWorldToInChunk(getBlockInWorld(), null); - } - - default BlockLogic getBlock() { - return getWorld().getBlock(getBlockInWorld()); - } - - default BlockData getBlockData() { - return getWorldData().getBlock(getBlockInWorld()); - } - - default void forEachFace(Consumer action) { - Objects.requireNonNull(action, "action"); - TickContextMutable context = TickContextMutable.uninitialized(); - - for (AbsFace face : AbsFace.getFaces()) { - context.rebuild().withServer(getServer()).withBlock(getBlockInWorld()).withFace(face).build(); - action.accept(context); - } - } - - default BlockTickContext getNeighbor(Vec3i direction) { - Objects.requireNonNull(direction, "direction"); - return TickContextMutable.copyWorld(this).withBlock(getBlockInWorld().add_(direction)).build(); - } - - default BlockTickContext getNeighbor(BlockRelation relation) { - Objects.requireNonNull(relation, "relation"); - return getNeighbor(relation.getVector(getChunkData().getUp())); - } - - default R evalNeighbor(Vec3i direction, Function action) { - Objects.requireNonNull(action, "action"); - Objects.requireNonNull(direction, "direction"); - return action.apply(getNeighbor(direction)); - } - - default R evalNeighbor(BlockRelation relation, Function action) { - Objects.requireNonNull(action, "action"); - Objects.requireNonNull(relation, "relation"); - return evalNeighbor(relation.getVector(getChunkData().getUp()), action); - } - - default void forNeighbor(Vec3i direction, Consumer action) { - Objects.requireNonNull(action, "action"); - Objects.requireNonNull(direction, "direction"); - evalNeighbor(direction, (Function) ctxt -> { - action.accept(ctxt); - return null; - }); - } - - default void forNeighbor(BlockRelation relation, Consumer action) { - Objects.requireNonNull(action, "action"); - Objects.requireNonNull(relation, "relation"); - forNeighbor(relation.getVector(getChunkData().getUp()), action); - } - - /* - * Convenience methods - changes - */ - - default void setThisBlock(BlockData block) { - getAccessor().setBlock(getBlockInWorld(), block); - } - - default void setThisBlock(String id) { - getAccessor().setBlock(getBlockInWorld(), id); - } - -} diff --git a/src/main/java/ru/windcorp/progressia/server/world/block/TickableBlock.java b/src/main/java/ru/windcorp/progressia/server/world/block/TickableBlock.java index 56ba938..bc4569b 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/block/TickableBlock.java +++ b/src/main/java/ru/windcorp/progressia/server/world/block/TickableBlock.java @@ -18,12 +18,14 @@ package ru.windcorp.progressia.server.world.block; +import ru.windcorp.progressia.server.world.context.ServerBlockContext; +import ru.windcorp.progressia.server.world.context.ServerBlockContextRO; import ru.windcorp.progressia.server.world.ticking.TickingPolicy; public interface TickableBlock { - void tick(BlockTickContext context); + void tick(ServerBlockContext context); - TickingPolicy getTickingPolicy(BlockTickContext context); + TickingPolicy getTickingPolicy(ServerBlockContextRO context); } diff --git a/src/main/java/ru/windcorp/progressia/server/world/block/UpdateableBlock.java b/src/main/java/ru/windcorp/progressia/server/world/block/UpdateableBlock.java index 1497c92..757e972 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/block/UpdateableBlock.java +++ b/src/main/java/ru/windcorp/progressia/server/world/block/UpdateableBlock.java @@ -18,18 +18,10 @@ package ru.windcorp.progressia.server.world.block; -import org.apache.logging.log4j.LogManager; +import ru.windcorp.progressia.server.world.context.ServerBlockContext; public interface UpdateableBlock { - default void update(BlockTickContext context) { - LogManager.getLogger().info( - "Updating block {} @ ({}; {}; {})", - context.getBlock(), - context.getBlockInWorld().x, - context.getBlockInWorld().y, - context.getBlockInWorld().z - ); - } + void update(ServerBlockContext context); } diff --git a/src/main/java/ru/windcorp/progressia/server/world/entity/EntityLogic.java b/src/main/java/ru/windcorp/progressia/server/world/entity/EntityLogic.java index 7725612..2ebd2d6 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/entity/EntityLogic.java +++ b/src/main/java/ru/windcorp/progressia/server/world/entity/EntityLogic.java @@ -20,7 +20,7 @@ package ru.windcorp.progressia.server.world.entity; import ru.windcorp.progressia.common.util.namespaces.Namespaced; import ru.windcorp.progressia.common.world.entity.EntityData; -import ru.windcorp.progressia.server.world.TickContext; +import ru.windcorp.progressia.server.world.context.ServerWorldContext; public class EntityLogic extends Namespaced { @@ -28,7 +28,7 @@ public class EntityLogic extends Namespaced { super(id); } - public void tick(EntityData entity, TickContext context) { + public void tick(EntityData entity, ServerWorldContext context) { entity.incrementAge(context.getTickLength()); } diff --git a/src/main/java/ru/windcorp/progressia/server/world/tasks/BlockTriggeredUpdate.java b/src/main/java/ru/windcorp/progressia/server/world/tasks/BlockTriggeredUpdate.java index 120cd22..57d2c67 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/tasks/BlockTriggeredUpdate.java +++ b/src/main/java/ru/windcorp/progressia/server/world/tasks/BlockTriggeredUpdate.java @@ -25,7 +25,6 @@ import ru.windcorp.progressia.common.world.Coordinates; import ru.windcorp.progressia.common.world.rels.AbsFace; import ru.windcorp.progressia.server.Server; import ru.windcorp.progressia.server.world.TickAndUpdateUtil; -import ru.windcorp.progressia.server.world.DefaultWorldLogic; class BlockTriggeredUpdate extends CachedEvaluation { @@ -39,13 +38,11 @@ class BlockTriggeredUpdate extends CachedEvaluation { public void evaluate(Server server) { Vec3i cursor = new Vec3i(blockInWorld.x, blockInWorld.y, blockInWorld.z); - DefaultWorldLogic world = server.getWorld(); - for (AbsFace face : AbsFace.getFaces()) { - TickAndUpdateUtil.updateTiles(world, cursor, face); + TickAndUpdateUtil.updateTiles(server, cursor, face); cursor.add(face.getVector()); - TickAndUpdateUtil.updateBlock(world, cursor); - TickAndUpdateUtil.updateTiles(world, cursor, face.getCounter()); + TickAndUpdateUtil.updateBlock(server, cursor); + TickAndUpdateUtil.updateTiles(server, cursor, face.getCounter()); cursor.sub(face.getVector()); } } diff --git a/src/main/java/ru/windcorp/progressia/server/world/tasks/ChangeEntity.java b/src/main/java/ru/windcorp/progressia/server/world/tasks/ChangeEntity.java index 08f1212..8760460 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/tasks/ChangeEntity.java +++ b/src/main/java/ru/windcorp/progressia/server/world/tasks/ChangeEntity.java @@ -21,6 +21,7 @@ package ru.windcorp.progressia.server.world.tasks; import java.util.function.Consumer; import glm.vec._3.i.Vec3i; +import ru.windcorp.progressia.common.state.StateChange; import ru.windcorp.progressia.common.world.entity.EntityData; import ru.windcorp.progressia.common.world.entity.PacketChangeEntity; import ru.windcorp.progressia.server.Server; @@ -36,7 +37,7 @@ class ChangeEntity extends CachedChange { super(disposer); } - public void set(T entity, StateChange change) { + public void set(EntityData entity, StateChange change) { if (this.entity != null) throw new IllegalStateException("Entity is not null. Current: " + this.entity + "; requested: " + entity); diff --git a/src/main/java/ru/windcorp/progressia/server/world/tasks/StateChange.java b/src/main/java/ru/windcorp/progressia/server/world/tasks/StateChange.java deleted file mode 100644 index 93d5f08..0000000 --- a/src/main/java/ru/windcorp/progressia/server/world/tasks/StateChange.java +++ /dev/null @@ -1,24 +0,0 @@ -/* - * 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.server.world.tasks; - -@FunctionalInterface -public interface StateChange { - void change(T object); -} diff --git a/src/main/java/ru/windcorp/progressia/server/world/tasks/TickChunk.java b/src/main/java/ru/windcorp/progressia/server/world/tasks/TickChunk.java index 336f166..d7fabc1 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/tasks/TickChunk.java +++ b/src/main/java/ru/windcorp/progressia/server/world/tasks/TickChunk.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.server.world.tasks; import java.util.ArrayList; @@ -27,17 +27,22 @@ import com.google.common.collect.ImmutableList; import glm.vec._3.i.Vec3i; import ru.windcorp.progressia.common.util.FloatMathUtil; +import ru.windcorp.progressia.common.util.Vectors; +import ru.windcorp.progressia.common.world.Coordinates; import ru.windcorp.progressia.common.world.DefaultChunkData; import ru.windcorp.progressia.common.world.rels.AbsFace; import ru.windcorp.progressia.common.world.TileDataStack; +import ru.windcorp.progressia.common.world.generic.ChunkGenericRO; import ru.windcorp.progressia.server.Server; import ru.windcorp.progressia.server.world.DefaultChunkLogic; -import ru.windcorp.progressia.server.world.TickContextMutable; import ru.windcorp.progressia.server.world.block.BlockLogic; import ru.windcorp.progressia.server.world.block.TickableBlock; +import ru.windcorp.progressia.server.world.context.ServerBlockContext; +import ru.windcorp.progressia.server.world.context.ServerTileContext; +import ru.windcorp.progressia.server.world.context.ServerTileStackContext; +import ru.windcorp.progressia.server.world.context.ServerWorldContext; import ru.windcorp.progressia.server.world.ticking.Evaluation; import ru.windcorp.progressia.server.world.ticking.TickingPolicy; -import ru.windcorp.progressia.server.world.tile.TSTickContext; import ru.windcorp.progressia.server.world.tile.TickableTile; import ru.windcorp.progressia.server.world.tile.TileLogic; import static ru.windcorp.progressia.common.world.DefaultChunkData.BLOCKS_PER_CHUNK; @@ -82,11 +87,11 @@ public class TickChunk extends Evaluation { if (!chunk.hasTickingBlocks()) return; - TickContextMutable context = TickContextMutable.uninitialized(); + ServerWorldContext context = server.createContext(); chunk.forEachTickingBlock((blockInChunk, block) -> { - context.rebuild().withChunk(chunk).withBlockInChunk(blockInChunk).build(); - ((TickableBlock) block).tick(context); + ((TickableBlock) block).tick(contextPushBiC(context, chunk, blockInChunk)); + context.pop(); }); } @@ -94,11 +99,14 @@ public class TickChunk extends Evaluation { if (!chunk.hasTickingTiles()) return; - TickContextMutable context = TickContextMutable.uninitialized(); + ServerWorldContext context = server.createContext(); + Vec3i blockInWorld = new Vec3i(); chunk.forEachTickingTile((ref, tile) -> { - context.rebuild().withServer(server).withTile(ref); - ((TickableTile) tile).tick(context); + ((TickableTile) tile).tick( + context.push(ref.getStack().getBlockInWorld(blockInWorld), ref.getStack().getFace(), ref.getIndex()) + ); + context.pop(); }); } @@ -144,7 +152,7 @@ public class TickChunk extends Evaluation { return; TickableBlock tickable = (TickableBlock) block; - TickContextMutable context = TickContextMutable.start().withChunk(chunk).withBlockInChunk(blockInChunk).build(); + ServerBlockContext context = contextPushBiC(server.createContext(), chunk, blockInChunk); if (tickable.getTickingPolicy(context) != TickingPolicy.RANDOM) return; @@ -164,18 +172,22 @@ public class TickChunk extends Evaluation { if (tiles == null || tiles.isEmpty()) return; - TSTickContext context = TickContextMutable.start().withServer(server).withTS(tiles).build(); + ServerTileStackContext context = contextPushBiC(server.createContext(), chunk, blockInChunk).push(face.relativize(chunk.getUp())); - context.forEachTile(tctxt -> { - TileLogic logic = tctxt.getTile(); + for (int i = 0; i < tiles.size(); ++i) { + ServerTileContext tileContext = context.push(i); + + TileLogic logic = tileContext.logic().getTile(); if (!(logic instanceof TickableTile)) return; TickableTile tickable = (TickableTile) logic; - if (tickable.getTickingPolicy(tctxt) != TickingPolicy.RANDOM) + if (tickable.getTickingPolicy(tileContext) != TickingPolicy.RANDOM) return; - tickable.tick(tctxt); - }); + tickable.tick(tileContext); + + tileContext.pop(); + } } private float computeRandomTicks(Server server) { @@ -184,6 +196,18 @@ public class TickChunk extends Evaluation { server.getTickLength()); } + private ServerBlockContext contextPushBiC( + ServerWorldContext context, + ChunkGenericRO chunk, + Vec3i blockInChunk + ) { + Vec3i blockInWorld = Vectors.grab3i(); + Coordinates.getInWorld(chunk.getPosition(), blockInChunk, blockInWorld); + ServerBlockContext blockContext = context.push(blockInWorld); + Vectors.release(blockInWorld); + return blockContext; + } + @Override public void getRelevantChunk(Vec3i output) { Vec3i p = chunk.getData().getPosition(); diff --git a/src/main/java/ru/windcorp/progressia/server/world/tasks/TileTriggeredUpdate.java b/src/main/java/ru/windcorp/progressia/server/world/tasks/TileTriggeredUpdate.java index 66e95a1..c052108 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/tasks/TileTriggeredUpdate.java +++ b/src/main/java/ru/windcorp/progressia/server/world/tasks/TileTriggeredUpdate.java @@ -25,7 +25,6 @@ import ru.windcorp.progressia.common.world.Coordinates; import ru.windcorp.progressia.common.world.rels.AbsFace; import ru.windcorp.progressia.server.Server; import ru.windcorp.progressia.server.world.TickAndUpdateUtil; -import ru.windcorp.progressia.server.world.DefaultWorldLogic; class TileTriggeredUpdate extends CachedEvaluation { @@ -40,17 +39,15 @@ class TileTriggeredUpdate extends CachedEvaluation { public void evaluate(Server server) { Vec3i cursor = new Vec3i(blockInWorld.x, blockInWorld.y, blockInWorld.z); - DefaultWorldLogic world = server.getWorld(); - - TickAndUpdateUtil.updateTiles(world, cursor, face); // Update facemates - // (also self) - TickAndUpdateUtil.updateBlock(world, cursor); // Update block on one - // side + // Update facemates (also self) + TickAndUpdateUtil.updateTiles(server, cursor, face); + // Update block on one side + TickAndUpdateUtil.updateBlock(server, cursor); cursor.add(face.getVector()); - TickAndUpdateUtil.updateBlock(world, cursor); // Update block on the - // other side - TickAndUpdateUtil.updateTiles(world, cursor, face.getCounter()); // Update - // complement + // Update block on the other side + TickAndUpdateUtil.updateBlock(server, cursor); + // Update complement + TickAndUpdateUtil.updateTiles(server, cursor, face.getCounter()); } public void init(Vec3i blockInWorld, AbsFace face) { diff --git a/src/main/java/ru/windcorp/progressia/server/world/tasks/WorldAccessor.java b/src/main/java/ru/windcorp/progressia/server/world/tasks/WorldAccessor.java index 15ab504..cb95063 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/tasks/WorldAccessor.java +++ b/src/main/java/ru/windcorp/progressia/server/world/tasks/WorldAccessor.java @@ -21,17 +21,19 @@ package ru.windcorp.progressia.server.world.tasks; import java.util.function.Consumer; import glm.vec._3.i.Vec3i; +import ru.windcorp.progressia.common.state.StateChange; +import ru.windcorp.progressia.common.state.StatefulObject; import ru.windcorp.progressia.common.util.MultiLOC; import ru.windcorp.progressia.common.world.block.BlockData; -import ru.windcorp.progressia.common.world.block.BlockDataRegistry; import ru.windcorp.progressia.common.world.entity.EntityData; +import ru.windcorp.progressia.common.world.generic.EntityGeneric; import ru.windcorp.progressia.common.world.rels.BlockFace; import ru.windcorp.progressia.common.world.tile.TileData; -import ru.windcorp.progressia.common.world.tile.TileDataRegistry; import ru.windcorp.progressia.server.Server; +import ru.windcorp.progressia.server.world.context.impl.ReportingServerContext; import ru.windcorp.progressia.server.world.ticking.TickerTask; -public class WorldAccessor { +public class WorldAccessor implements ReportingServerContext.ChangeListener { private final MultiLOC cache; { @@ -54,38 +56,52 @@ public class WorldAccessor { this.server = server; } - public void setBlock(Vec3i blockInWorld, BlockData block) { + @Override + public void onBlockSet(Vec3i blockInWorld, BlockData block) { SetBlock change = cache.grab(SetBlock.class); change.getPacket().set(block, blockInWorld); server.requestChange(change); } - public void setBlock(Vec3i blockInWorld, String id) { - setBlock(blockInWorld, BlockDataRegistry.getInstance().get(id)); - } - - public void addTile(Vec3i blockInWorld, BlockFace face, TileData tile) { + @Override + public void onTileAdded(Vec3i blockInWorld, BlockFace face, TileData tile) { AddTile change = cache.grab(AddTile.class); change.getPacket().set(tile, blockInWorld, face.resolve(server.getWorld().getUp(blockInWorld))); server.requestChange(change); } - public void addTile(Vec3i blockInWorld, BlockFace face, String id) { - addTile(blockInWorld, face, TileDataRegistry.getInstance().get(id)); - } - - public void removeTile(Vec3i blockInWorld, BlockFace face, int tag) { + @Override + public void onTileRemoved(Vec3i blockInWorld, BlockFace face, int tag) { RemoveTile change = cache.grab(RemoveTile.class); change.getPacket().set(blockInWorld, face.resolve(server.getWorld().getUp(blockInWorld)), tag); server.requestChange(change); } + + @Override + public void onEntityAdded(EntityData entity) { + // TODO Auto-generated method stub + + } + + @Override + public void onEntityRemoved(long entityId) { + // TODO Auto-generated method stub + + } + + @Override + public void onTimeChanged(float change) { + // TODO Auto-generated method stub + System.err.println("WorldAccessor.onTimeChanged() NYI!"); + } - public void changeEntity( - T entity, - StateChange stateChange + @Override + public void onEntityChanged( + SE entity, + StateChange stateChange ) { ChangeEntity change = cache.grab(ChangeEntity.class); - change.set(entity, stateChange); + change.set((EntityData) entity, stateChange); server.requestChange(change); } diff --git a/src/main/java/ru/windcorp/progressia/server/world/tile/HangingTileLogic.java b/src/main/java/ru/windcorp/progressia/server/world/tile/HangingTileLogic.java index 745f289..f916a24 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/tile/HangingTileLogic.java +++ b/src/main/java/ru/windcorp/progressia/server/world/tile/HangingTileLogic.java @@ -19,6 +19,8 @@ package ru.windcorp.progressia.server.world.tile; import ru.windcorp.progressia.server.world.block.BlockLogic; +import ru.windcorp.progressia.server.world.context.ServerTileContext; +import ru.windcorp.progressia.server.world.context.ServerTileContextRO; public class HangingTileLogic extends TileLogic implements UpdateableTile { @@ -27,15 +29,15 @@ public class HangingTileLogic extends TileLogic implements UpdateableTile { } @Override - public void update(TileTickContext context) { + public void update(ServerTileContext context) { if (!canOccupyFace(context)) { - context.removeThisTile(); + context.removeTile(); } } @Override - public boolean canOccupyFace(TileTickContext context) { - BlockLogic host = context.getBlock(); + public boolean canOccupyFace(ServerTileContextRO context) { + BlockLogic host = context.logic().getBlock(); if (host == null) return false; @@ -45,13 +47,14 @@ public class HangingTileLogic extends TileLogic implements UpdateableTile { if (canBeSquashed(context)) return true; - return context.evalComplementary(ctxt -> { - BlockLogic complHost = ctxt.getBlock(); - return complHost == null || !complHost.isSolid(ctxt, context.getFace()); - }); + context.pushOpposite(); + BlockLogic complHost = context.logic().getBlock(); + boolean result = complHost == null || !complHost.isSolid(context, context.getFace()); + context.pop(); + return result; } - public boolean canBeSquashed(TileTickContext context) { + public boolean canBeSquashed(ServerTileContextRO context) { return false; } diff --git a/src/main/java/ru/windcorp/progressia/server/world/tile/TSTickContext.java b/src/main/java/ru/windcorp/progressia/server/world/tile/TSTickContext.java deleted file mode 100644 index d805607..0000000 --- a/src/main/java/ru/windcorp/progressia/server/world/tile/TSTickContext.java +++ /dev/null @@ -1,113 +0,0 @@ -/* - * 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.server.world.tile; - -import java.util.Objects; -import java.util.function.Consumer; -import java.util.function.Function; - -import ru.windcorp.progressia.common.world.DefaultChunkData; -import ru.windcorp.progressia.common.world.rels.RelFace; -import ru.windcorp.progressia.common.world.TileDataStack; -import ru.windcorp.progressia.server.world.DefaultChunkLogic; -import ru.windcorp.progressia.server.world.TickContextMutable; -import ru.windcorp.progressia.server.world.TileLogicStackRO; -import ru.windcorp.progressia.server.world.block.BlockTickContext; - -public interface TSTickContext extends BlockTickContext { - - /* - * Specifications - */ - - RelFace getFace(); - - /* - * Getters - */ - - default TileLogicStackRO getTLSOrNull() { - DefaultChunkLogic chunkLogic = getChunkLogic(); - if (chunkLogic == null) - return null; - - return chunkLogic.getTilesOrNull(getBlockInChunk(), getFace()); - } - - default TileLogicStackRO getTLS() { - return getChunkLogic().getTiles(getBlockInChunk(), getFace()); - } - - default TileDataStack getTDSOrNull() { - DefaultChunkData chunkData = getChunkData(); - if (chunkData == null) - return null; - - return chunkData.getTilesOrNull(getBlockInChunk(), getFace()); - } - - default TileDataStack getTDS() { - return getChunkData().getTiles(getBlockInChunk(), getFace()); - } - - /* - * Contexts - */ - - default TileTickContext forLayer(int layer) { - return TickContextMutable.start().withServer(getServer()).withBlock(getBlockInWorld()).withFace(getFace()) - .withLayer(layer); - } - - default boolean forEachTile(Consumer action) { - TickContextMutable context = TickContextMutable.uninitialized(); - - TileDataStack stack = getTDSOrNull(); - if (stack == null || stack.isEmpty()) - return false; - - for (int layer = 0; layer < stack.size(); ++layer) { - context.rebuild().withServer(getServer()).withBlock(getBlockInWorld()).withFace(getFace()).withLayer(layer); - action.accept(context); - } - - return true; - } - - default TSTickContext getComplementary() { - return TickContextMutable.copyWorld(this) - .withBlock(getBlockInWorld().add_(getFace().getVector(getUp()))) - .withFace(getFace().getCounter()) - .build(); - } - - default R evalComplementary(Function action) { - Objects.requireNonNull(action, "action"); - return action.apply(getComplementary()); - } - - default void forComplementary(Consumer action) { - Objects.requireNonNull(action, "action"); - evalComplementary((Function) ctxt -> { - action.accept(ctxt); - return null; - }); - } - -} diff --git a/src/main/java/ru/windcorp/progressia/server/world/tile/TickableTile.java b/src/main/java/ru/windcorp/progressia/server/world/tile/TickableTile.java index 4def3b0..ce2487d 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/tile/TickableTile.java +++ b/src/main/java/ru/windcorp/progressia/server/world/tile/TickableTile.java @@ -18,12 +18,14 @@ package ru.windcorp.progressia.server.world.tile; +import ru.windcorp.progressia.server.world.context.ServerTileContext; +import ru.windcorp.progressia.server.world.context.ServerTileContextRO; import ru.windcorp.progressia.server.world.ticking.TickingPolicy; public interface TickableTile { - void tick(TileTickContext context); + void tick(ServerTileContext context); - TickingPolicy getTickingPolicy(TileTickContext context); + TickingPolicy getTickingPolicy(ServerTileContextRO context); } diff --git a/src/main/java/ru/windcorp/progressia/server/world/tile/TileLogic.java b/src/main/java/ru/windcorp/progressia/server/world/tile/TileLogic.java index 67466b5..229d7e3 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/tile/TileLogic.java +++ b/src/main/java/ru/windcorp/progressia/server/world/tile/TileLogic.java @@ -21,6 +21,7 @@ package ru.windcorp.progressia.server.world.tile; import ru.windcorp.progressia.common.util.namespaces.Namespaced; import ru.windcorp.progressia.common.world.generic.TileGeneric; import ru.windcorp.progressia.common.world.rels.RelFace; +import ru.windcorp.progressia.server.world.context.ServerTileContextRO; public class TileLogic extends Namespaced implements TileGeneric { @@ -28,7 +29,7 @@ public class TileLogic extends Namespaced implements TileGeneric { super(id); } - public boolean canOccupyFace(TileTickContext context) { + public boolean canOccupyFace(ServerTileContextRO context) { return canOccupyFace(context.getFace()); } @@ -36,7 +37,7 @@ public class TileLogic extends Namespaced implements TileGeneric { return true; } - public boolean isSolid(TileTickContext context) { + public boolean isSolid(ServerTileContextRO context) { return isSolid(); } diff --git a/src/main/java/ru/windcorp/progressia/server/world/tile/TileTickContext.java b/src/main/java/ru/windcorp/progressia/server/world/tile/TileTickContext.java deleted file mode 100644 index 597291a..0000000 --- a/src/main/java/ru/windcorp/progressia/server/world/tile/TileTickContext.java +++ /dev/null @@ -1,77 +0,0 @@ -/* - * 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.server.world.tile; - -import ru.windcorp.progressia.common.world.tile.TileData; -import ru.windcorp.progressia.server.world.TileLogicStackRO; -import ru.windcorp.progressia.common.world.TileDataStack; -import ru.windcorp.progressia.common.world.TileDataReference; - -public interface TileTickContext extends TSTickContext { - - /* - * Specifications - */ - - /** - * Returns the current layer. - * - * @return the layer that the tile being ticked occupies in the tile stack - */ - int getLayer(); - - /* - * Getters - */ - - default TileLogic getTile() { - TileLogicStackRO stack = getTLSOrNull(); - if (stack == null) - return null; - return stack.get(getLayer()); - } - - default TileData getTileData() { - TileDataStack stack = getTDSOrNull(); - if (stack == null) - return null; - return stack.get(getLayer()); - } - - default TileDataReference getReference() { - return getTDS().getReference(getLayer()); - } - - default int getTag() { - return getTDS().getTagByIndex(getLayer()); - } - - /* - * Contexts - */ - - /* - * Convenience methods - changes - */ - - default void removeThisTile() { - getAccessor().removeTile(getBlockInWorld(), getFace(), getTag()); - } - -} diff --git a/src/main/java/ru/windcorp/progressia/server/world/tile/UpdateableTile.java b/src/main/java/ru/windcorp/progressia/server/world/tile/UpdateableTile.java index bf114fa..3d63585 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/tile/UpdateableTile.java +++ b/src/main/java/ru/windcorp/progressia/server/world/tile/UpdateableTile.java @@ -18,8 +18,10 @@ package ru.windcorp.progressia.server.world.tile; +import ru.windcorp.progressia.server.world.context.ServerTileContext; + public interface UpdateableTile { - void update(TileTickContext context); + void update(ServerTileContext context); } diff --git a/src/main/java/ru/windcorp/progressia/test/TestContent.java b/src/main/java/ru/windcorp/progressia/test/TestContent.java index 46bf460..0ddc3e5 100644 --- a/src/main/java/ru/windcorp/progressia/test/TestContent.java +++ b/src/main/java/ru/windcorp/progressia/test/TestContent.java @@ -383,7 +383,7 @@ public class TestContent { ru.windcorp.progressia.server.comms.Client client ) { Vec3i blockInWorld = ((ControlBreakBlockData) packet.getControl()).getBlockInWorld(); - server.getWorldAccessor().setBlock(blockInWorld, BlockDataRegistry.getInstance().get("Test:Air")); + server.createContext().setBlock(blockInWorld, BlockDataRegistry.getInstance().get("Test:Air")); } private static void onBlockPlaceTrigger(ControlData control) { @@ -403,7 +403,7 @@ public class TestContent { Vec3i blockInWorld = controlData.getBlockInWorld(); if (server.getWorld().getData().getChunkByBlock(blockInWorld) == null) return; - server.getWorldAccessor().setBlock(blockInWorld, block); + server.createContext().setBlock(blockInWorld, block); } private static void onTilePlaceTrigger(ControlData control) { @@ -428,7 +428,7 @@ public class TestContent { return; if (server.getWorld().getData().getTiles(blockInWorld, face).isFull()) return; - server.getWorldAccessor().addTile(blockInWorld, face, tile); + server.createContext().addTile(blockInWorld, face, tile); } private static void registerMisc() { diff --git a/src/main/java/ru/windcorp/progressia/test/TestEntityLogicStatie.java b/src/main/java/ru/windcorp/progressia/test/TestEntityLogicStatie.java index 5fa66fb..ac49fc9 100644 --- a/src/main/java/ru/windcorp/progressia/test/TestEntityLogicStatie.java +++ b/src/main/java/ru/windcorp/progressia/test/TestEntityLogicStatie.java @@ -19,7 +19,7 @@ package ru.windcorp.progressia.test; import ru.windcorp.progressia.common.world.entity.EntityData; -import ru.windcorp.progressia.server.world.TickContext; +import ru.windcorp.progressia.server.world.context.ServerWorldContext; import ru.windcorp.progressia.server.world.entity.EntityLogic; public class TestEntityLogicStatie extends EntityLogic { @@ -29,13 +29,13 @@ public class TestEntityLogicStatie extends EntityLogic { } @Override - public void tick(EntityData entity, TickContext context) { + public void tick(EntityData entity, ServerWorldContext context) { super.tick(entity, context); TestEntityDataStatie statie = (TestEntityDataStatie) entity; int size = (int) (18 + 6 * Math.sin(entity.getAge())); - context.getServer().getWorldAccessor().changeEntity(statie, e -> e.setSizeNow(size)); + context.changeEntity(statie, e -> e.setSizeNow(size)); } } diff --git a/src/main/java/ru/windcorp/progressia/test/TestTileLogicGrass.java b/src/main/java/ru/windcorp/progressia/test/TestTileLogicGrass.java index 246c882..b41f5a7 100644 --- a/src/main/java/ru/windcorp/progressia/test/TestTileLogicGrass.java +++ b/src/main/java/ru/windcorp/progressia/test/TestTileLogicGrass.java @@ -20,11 +20,11 @@ package ru.windcorp.progressia.test; import ru.windcorp.progressia.common.world.rels.RelFace; import ru.windcorp.progressia.server.world.block.BlockLogic; -import ru.windcorp.progressia.server.world.block.BlockTickContext; +import ru.windcorp.progressia.server.world.context.ServerTileContext; +import ru.windcorp.progressia.server.world.context.ServerTileContextRO; import ru.windcorp.progressia.server.world.ticking.TickingPolicy; import ru.windcorp.progressia.server.world.tile.HangingTileLogic; import ru.windcorp.progressia.server.world.tile.TickableTile; -import ru.windcorp.progressia.server.world.tile.TileTickContext; public class TestTileLogicGrass extends HangingTileLogic implements TickableTile { @@ -33,7 +33,7 @@ public class TestTileLogicGrass extends HangingTileLogic implements TickableTile } @Override - public boolean canOccupyFace(TileTickContext context) { + public boolean canOccupyFace(ServerTileContextRO context) { return context.getFace() != RelFace.DOWN && super.canOccupyFace(context); } @@ -43,34 +43,31 @@ public class TestTileLogicGrass extends HangingTileLogic implements TickableTile } @Override - public TickingPolicy getTickingPolicy(TileTickContext context) { + public TickingPolicy getTickingPolicy(ServerTileContextRO context) { return TickingPolicy.RANDOM; } @Override - public void tick(TileTickContext context) { + public void tick(ServerTileContext context) { if (!isLocationSuitable(context)) { // context.removeThisTile(); } } @Override - public boolean canBeSquashed(TileTickContext context) { + public boolean canBeSquashed(ServerTileContextRO context) { return true; } - private boolean isLocationSuitable(TileTickContext context) { + private boolean isLocationSuitable(ServerTileContextRO context) { return canOccupyFace(context) && isBlockAboveTransparent(context); } - private boolean isBlockAboveTransparent(BlockTickContext context) { - return context.evalNeighbor(RelFace.UP, bctxt -> { - BlockLogic block = bctxt.getBlock(); - if (block == null) - return true; - - return block.isTransparent(bctxt); - }); + private boolean isBlockAboveTransparent(ServerTileContextRO context) { + // TODO rework + context.pushRelative(RelFace.UP.resolve(context.getServer().getWorld().getUp(context.getLocation()))); + BlockLogic block = context.logic().getBlock(); + return context.popAndReturn(block == null || block.isTransparent(context)); } } From a03c783fc9080b03c3dfbd6534b9a9d3ffd43453 Mon Sep 17 00:00:00 2001 From: OLEGSHA Date: Wed, 11 Aug 2021 13:02:18 +0300 Subject: [PATCH 42/55] Fixing bugs introduced in previous commit - Fixed AbstractContextRO.isSubcontexting() - Fixed push(...) overrides in FilterServerContext - Fixed DefaultChunkLogic.tmp_generateTickLists() - Debug screen now also lists visible and loaded chunks - AbstractContextRO.Frame now has a toString() --- .../generic/context/AbstractContextRO.java | 44 +++++++++++-------- .../ru/windcorp/progressia/server/Server.java | 2 +- .../server/world/DefaultChunkLogic.java | 13 +++--- .../impl/DefaultServerContextImpl.java | 2 +- .../context/impl/FilterServerContext.java | 9 ++-- .../progressia/test/LayerTestGUI.java | 32 ++++++++++++-- .../resources/assets/languages/en-US.lang | 2 +- .../resources/assets/languages/ru-RU.lang | 2 +- 8 files changed, 71 insertions(+), 35 deletions(-) diff --git a/src/main/java/ru/windcorp/progressia/common/world/generic/context/AbstractContextRO.java b/src/main/java/ru/windcorp/progressia/common/world/generic/context/AbstractContextRO.java index db4770f..29e3127 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/generic/context/AbstractContextRO.java +++ b/src/main/java/ru/windcorp/progressia/common/world/generic/context/AbstractContextRO.java @@ -31,65 +31,71 @@ public abstract class AbstractContextRO< E extends EntityGeneric > implements TileGenericContextRO { //@formatter:on - + public static final int MAX_SUBCONTEXTS = 64; - + protected class Frame { - + public final Vec3i location = new Vec3i(); public RelFace face; public int layer; - + + @Override + public String toString() { + return "Frame [x=" + location.x + ", y=" + location.y + ", z=" + location.z + ", face=" + face + ", layer=" + + layer + "]"; + } + } - + protected Frame frame = null; - + private final StashingStack frameStack = new StashingStack<>(MAX_SUBCONTEXTS, Frame::new); - + @Override public void pop() { if (!isSubcontexting()) { throw new IllegalStateException("Cannot pop(): already top frame"); } - + frame = frameStack.pop(); } - + @Override public BlockGenericContextRO push(Vec3i location) { frame = frameStack.push(); - + frame.location.set(location.x, location.y, location.z); frame.face = null; frame.layer = -1; - + return this; } - + @Override public TileStackGenericContextRO push(Vec3i location, RelFace face) { frame = frameStack.push(); - + frame.location.set(location.x, location.y, location.z); frame.face = face; frame.layer = -1; - + return this; } - + @Override public TileGenericContextRO push(Vec3i location, RelFace face, int layer) { frame = frameStack.push(); - + frame.location.set(location.x, location.y, location.z); frame.face = face; frame.layer = layer; - + return this; } - + public boolean isSubcontexting() { - return frameStack.isEmpty(); + return !frameStack.isEmpty(); } } diff --git a/src/main/java/ru/windcorp/progressia/server/Server.java b/src/main/java/ru/windcorp/progressia/server/Server.java index a57ce2f..0efc551 100644 --- a/src/main/java/ru/windcorp/progressia/server/Server.java +++ b/src/main/java/ru/windcorp/progressia/server/Server.java @@ -109,7 +109,7 @@ public class Server { */ public ServerWorldContext createContext() { - return new ReportingServerContext(DefaultServerContext.empty().inRealWorldOf(this).build()).withListener(worldAccessor); + return new ReportingServerContext(DefaultServerContext.empty().inRealWorldOf(this).build()).withListener(worldAccessor).setPassToParent(false); } diff --git a/src/main/java/ru/windcorp/progressia/server/world/DefaultChunkLogic.java b/src/main/java/ru/windcorp/progressia/server/world/DefaultChunkLogic.java index 0e2dbbe..978fae3 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/DefaultChunkLogic.java +++ b/src/main/java/ru/windcorp/progressia/server/world/DefaultChunkLogic.java @@ -235,8 +235,10 @@ public class DefaultChunkLogic implements ChunkLogic { BlockLogic block = blockContext.logic().getBlock(); Coordinates.convertInWorldToInChunk(location, blockInChunk); - if (!(block instanceof TickableBlock)) + if (!(block instanceof TickableBlock)) { + blockContext.pop(); return; + } if (((TickableBlock) block).getTickingPolicy(blockContext) == TickingPolicy.REGULAR) { tickingBlocks.add(blockInChunk); @@ -248,16 +250,17 @@ public class DefaultChunkLogic implements ChunkLogic { for (int i = 0; i < stack.size(); ++i) { ServerTileContextRO tileContext = blockContext.push(face, i); - TileLogic tile = stack.get(i); - if (!(tile instanceof TickableTile)) - return; + if (!(tile instanceof TickableTile)) { + tileContext.pop(); + continue; + } if (((TickableTile) tile).getTickingPolicy(tileContext) == TickingPolicy.REGULAR) { tickingTiles.add(stack.getData().getReference(i)); } - + tileContext.pop(); } } diff --git a/src/main/java/ru/windcorp/progressia/server/world/context/impl/DefaultServerContextImpl.java b/src/main/java/ru/windcorp/progressia/server/world/context/impl/DefaultServerContextImpl.java index 1fa1178..77e5551 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/context/impl/DefaultServerContextImpl.java +++ b/src/main/java/ru/windcorp/progressia/server/world/context/impl/DefaultServerContextImpl.java @@ -109,7 +109,7 @@ class DefaultServerContextImpl extends DefaultServerContext */ public boolean requireContextRole(Role role) throws IllegalStateException { - boolean ok = !isBuilder && getRole().compareTo(role) <= 0; + boolean ok = !isBuilder && getRole().compareTo(role) >= 0; if (!ok) { complainAboutIllegalState(role, false); } diff --git a/src/main/java/ru/windcorp/progressia/server/world/context/impl/FilterServerContext.java b/src/main/java/ru/windcorp/progressia/server/world/context/impl/FilterServerContext.java index 4896b84..40927c3 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/context/impl/FilterServerContext.java +++ b/src/main/java/ru/windcorp/progressia/server/world/context/impl/FilterServerContext.java @@ -179,17 +179,20 @@ public abstract class FilterServerContext implements ServerTileContext { @Override public ServerBlockContext push(Vec3i location) { - return parent.push(location); + parent.push(location); + return this; } @Override public ServerTileStackContext push(Vec3i location, RelFace face) { - return parent.push(location, face); + parent.push(location, face); + return this; } @Override public ServerTileContext push(Vec3i location, RelFace face, int layer) { - return parent.push(location, face, layer); + parent.push(location, face, layer); + return this; } @Override diff --git a/src/main/java/ru/windcorp/progressia/test/LayerTestGUI.java b/src/main/java/ru/windcorp/progressia/test/LayerTestGUI.java index fcdc1ac..65913d2 100755 --- a/src/main/java/ru/windcorp/progressia/test/LayerTestGUI.java +++ b/src/main/java/ru/windcorp/progressia/test/LayerTestGUI.java @@ -35,6 +35,7 @@ import ru.windcorp.progressia.client.graphics.gui.layout.LayoutVertical; import ru.windcorp.progressia.client.localization.Localizer; import ru.windcorp.progressia.client.localization.MutableString; import ru.windcorp.progressia.client.localization.MutableStringLocalized; +import ru.windcorp.progressia.client.world.WorldRender; import ru.windcorp.progressia.common.Units; import ru.windcorp.progressia.common.util.dynstr.DynamicStrings; import ru.windcorp.progressia.server.Server; @@ -128,14 +129,37 @@ public class LayerTestGUI extends GUILayer { 128 ) ); - + group.addChild( new DynamicLabel( - "ChunkUpdatesDisplay", + "ChunkStatsDisplay", font, DynamicStrings.builder() - .addDyn(new MutableStringLocalized("LayerTestGUI.ChunkUpdatesDisplay")) - .addDyn(ClientState.getInstance().getWorld()::getPendingChunkUpdates) + .addDyn(new MutableStringLocalized("LayerTestGUI.ChunkStatsDisplay")) + .addDyn(() -> { + if (ClientState.getInstance() == null) { + return -1; + } else { + WorldRender world = ClientState.getInstance().getWorld(); + return world.getChunks().size() - world.getPendingChunkUpdates(); + } + }, 4) + .add('/') + .addDyn(() -> { + if (ClientState.getInstance() == null) { + return -1; + } else { + return ClientState.getInstance().getWorld().getPendingChunkUpdates(); + } + }, 4) + .add('/') + .addDyn(() -> { + if (ServerState.getInstance() == null) { + return -1; + } else { + return ServerState.getInstance().getWorld().getChunks().size(); + } + }, 4) .buildSupplier(), 128 ) diff --git a/src/main/resources/assets/languages/en-US.lang b/src/main/resources/assets/languages/en-US.lang index e4b69de..e2ff70b 100644 --- a/src/main/resources/assets/languages/en-US.lang +++ b/src/main/resources/assets/languages/en-US.lang @@ -11,7 +11,7 @@ LayerTestGUI.LanguageDisplay = Language: %5s (L) LayerTestGUI.FPSDisplay = FPS: LayerTestGUI.TPSDisplay = TPS: LayerTestGUI.TPSDisplay.NA = TPS: n/a -LayerTestGUI.ChunkUpdatesDisplay = Pending updates: +LayerTestGUI.ChunkStatsDisplay = Chunks vis/pnd/load: LayerTestGUI.PosDisplay = Pos: LayerTestGUI.PosDisplay.NA.Client = Pos: client n/a LayerTestGUI.PosDisplay.NA.Entity = Pos: entity n/a diff --git a/src/main/resources/assets/languages/ru-RU.lang b/src/main/resources/assets/languages/ru-RU.lang index a01e6ad..97935d6 100644 --- a/src/main/resources/assets/languages/ru-RU.lang +++ b/src/main/resources/assets/languages/ru-RU.lang @@ -11,7 +11,7 @@ LayerTestGUI.LanguageDisplay = Язык: %5s (L) LayerTestGUI.FPSDisplay = FPS: LayerTestGUI.TPSDisplay = TPS: LayerTestGUI.TPSDisplay.NA = TPS: н/д -LayerTestGUI.ChunkUpdatesDisplay = Обновления в очереди: +LayerTestGUI.ChunkStatsDisplay = Чанки вид/очр/загр: LayerTestGUI.PosDisplay = Поз: LayerTestGUI.PosDisplay.NA.Client = Поз: клиент н/д LayerTestGUI.PosDisplay.NA.Entity = Поз: сущность н/д From 78a1c25554e033c999d611287c1614d39ebb807b Mon Sep 17 00:00:00 2001 From: OLEGSHA Date: Wed, 11 Aug 2021 13:45:47 +0300 Subject: [PATCH 43/55] Grass tiles have regained the ability to disappear under blocks - Test:Grass now (again) randomly disappears under opaque blocks - Fixed a truly egregious bug in AbstractContextRO.pop() - Fixed BlockContext.pushRelative(AbsRelation) - Some changes in toString methods in contexts --- .../common/world/context/BlockDataContext.java | 2 +- .../common/world/context/BlockDataContextRO.java | 2 +- .../world/generic/context/AbstractContextRO.java | 3 ++- .../world/generic/context/BlockGenericContextRO.java | 2 +- .../world/generic/context/BlockGenericContextWO.java | 2 +- .../common/world/generic/context/WorldContexts.java | 2 +- .../server/world/context/ServerBlockContext.java | 4 ++-- .../server/world/context/ServerBlockContextRO.java | 4 ++-- .../context/impl/DefaultServerContextBuilders.java | 2 +- .../world/context/impl/DefaultServerContextImpl.java | 11 +++++------ .../world/context/impl/FilterServerContext.java | 5 +++++ .../progressia/server/world/tasks/TickChunk.java | 12 ++++++++---- .../server/world/tile/HangingTileLogic.java | 4 +--- .../windcorp/progressia/test/TestTileLogicGrass.java | 2 +- 14 files changed, 32 insertions(+), 25 deletions(-) diff --git a/src/main/java/ru/windcorp/progressia/common/world/context/BlockDataContext.java b/src/main/java/ru/windcorp/progressia/common/world/context/BlockDataContext.java index 9667eac..36e7dbe 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/context/BlockDataContext.java +++ b/src/main/java/ru/windcorp/progressia/common/world/context/BlockDataContext.java @@ -46,7 +46,7 @@ public interface BlockDataContext @Override default BlockDataContext pushRelative(AbsRelation direction) { - return push(direction.getVector()); + return push(getLocation().add_(direction.getVector())); } @Override diff --git a/src/main/java/ru/windcorp/progressia/common/world/context/BlockDataContextRO.java b/src/main/java/ru/windcorp/progressia/common/world/context/BlockDataContextRO.java index 7d35ec3..8d75845 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/context/BlockDataContextRO.java +++ b/src/main/java/ru/windcorp/progressia/common/world/context/BlockDataContextRO.java @@ -45,7 +45,7 @@ public interface BlockDataContextRO @Override default BlockDataContextRO pushRelative(AbsRelation direction) { - return push(direction.getVector()); + return push(getLocation().add_(direction.getVector())); } @Override diff --git a/src/main/java/ru/windcorp/progressia/common/world/generic/context/AbstractContextRO.java b/src/main/java/ru/windcorp/progressia/common/world/generic/context/AbstractContextRO.java index 29e3127..0657a3e 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/generic/context/AbstractContextRO.java +++ b/src/main/java/ru/windcorp/progressia/common/world/generic/context/AbstractContextRO.java @@ -58,7 +58,8 @@ public abstract class AbstractContextRO< throw new IllegalStateException("Cannot pop(): already top frame"); } - frame = frameStack.pop(); + frameStack.pop(); + frame = frameStack.peek(); } @Override diff --git a/src/main/java/ru/windcorp/progressia/common/world/generic/context/BlockGenericContextRO.java b/src/main/java/ru/windcorp/progressia/common/world/generic/context/BlockGenericContextRO.java index 842fd0a..cacbe45 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/generic/context/BlockGenericContextRO.java +++ b/src/main/java/ru/windcorp/progressia/common/world/generic/context/BlockGenericContextRO.java @@ -149,7 +149,7 @@ public interface BlockGenericContextRO< @Override default BlockGenericContextRO pushRelative(AbsRelation direction) { - return push(direction.getVector()); + return push(getLocation().add_(direction.getVector())); } @Override diff --git a/src/main/java/ru/windcorp/progressia/common/world/generic/context/BlockGenericContextWO.java b/src/main/java/ru/windcorp/progressia/common/world/generic/context/BlockGenericContextWO.java index 97ec62d..c1fa216 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/generic/context/BlockGenericContextWO.java +++ b/src/main/java/ru/windcorp/progressia/common/world/generic/context/BlockGenericContextWO.java @@ -92,7 +92,7 @@ public interface BlockGenericContextWO< @Override default BlockGenericContextWO pushRelative(AbsRelation direction) { - return push(direction.getVector()); + return push(getLocation().add_(direction.getVector())); } @Override diff --git a/src/main/java/ru/windcorp/progressia/common/world/generic/context/WorldContexts.java b/src/main/java/ru/windcorp/progressia/common/world/generic/context/WorldContexts.java index bfc85bb..30b85ce 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/generic/context/WorldContexts.java +++ b/src/main/java/ru/windcorp/progressia/common/world/generic/context/WorldContexts.java @@ -146,7 +146,7 @@ class WorldContexts { * @see #pop() */ default Block pushRelative(AbsRelation direction) { - return push(direction.getVector()); + return push(getLocation().add_(direction.getVector())); } /** diff --git a/src/main/java/ru/windcorp/progressia/server/world/context/ServerBlockContext.java b/src/main/java/ru/windcorp/progressia/server/world/context/ServerBlockContext.java index c8bdf0b..6b66ba0 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/context/ServerBlockContext.java +++ b/src/main/java/ru/windcorp/progressia/server/world/context/ServerBlockContext.java @@ -41,7 +41,7 @@ public interface ServerBlockContext extends BlockDataContext, ServerWorldContext @Override default ServerBlockContext.Logic pushRelative(AbsRelation direction) { - return push(direction.getVector()); + return push(getLocation().add_(direction.getVector())); } @Override @@ -71,7 +71,7 @@ public interface ServerBlockContext extends BlockDataContext, ServerWorldContext @Override default ServerBlockContext pushRelative(AbsRelation direction) { - return push(direction.getVector()); + return push(getLocation().add_(direction.getVector())); } @Override diff --git a/src/main/java/ru/windcorp/progressia/server/world/context/ServerBlockContextRO.java b/src/main/java/ru/windcorp/progressia/server/world/context/ServerBlockContextRO.java index eefa195..8ef355e 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/context/ServerBlockContextRO.java +++ b/src/main/java/ru/windcorp/progressia/server/world/context/ServerBlockContextRO.java @@ -46,7 +46,7 @@ public interface ServerBlockContextRO extends ServerWorldContextRO, BlockDataCon @Override default ServerBlockContextRO.Logic pushRelative(AbsRelation direction) { - return push(direction.getVector()); + return push(getLocation().add_(direction.getVector())); } @Override @@ -76,7 +76,7 @@ public interface ServerBlockContextRO extends ServerWorldContextRO, BlockDataCon @Override default ServerBlockContextRO pushRelative(AbsRelation direction) { - return push(direction.getVector()); + return push(getLocation().add_(direction.getVector())); } @Override diff --git a/src/main/java/ru/windcorp/progressia/server/world/context/impl/DefaultServerContextBuilders.java b/src/main/java/ru/windcorp/progressia/server/world/context/impl/DefaultServerContextBuilders.java index 8069db8..cb182ce 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/context/impl/DefaultServerContextBuilders.java +++ b/src/main/java/ru/windcorp/progressia/server/world/context/impl/DefaultServerContextBuilders.java @@ -29,7 +29,7 @@ public interface DefaultServerContextBuilders { DefaultServerContext build(); - public interface Empty /* does not extend RSCB */ { + public interface Empty /* does not extend DSCB */ { WithWorld in(Server server, WorldData world); diff --git a/src/main/java/ru/windcorp/progressia/server/world/context/impl/DefaultServerContextImpl.java b/src/main/java/ru/windcorp/progressia/server/world/context/impl/DefaultServerContextImpl.java index 77e5551..ec89e47 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/context/impl/DefaultServerContextImpl.java +++ b/src/main/java/ru/windcorp/progressia/server/world/context/impl/DefaultServerContextImpl.java @@ -150,7 +150,7 @@ class DefaultServerContextImpl extends DefaultServerContext switch (getRole()) { case TILE: result = String.format( - "ServerTileContext[x=%d, y=%d, z=%d, %s, index=%d]", + "ServerTileContext [x=%+4d, y=%+4d, z=%+4d, %s, index=%d]", frame.location.x, frame.location.y, frame.location.z, @@ -160,16 +160,16 @@ class DefaultServerContextImpl extends DefaultServerContext break; case TILE_STACK: result = String - .format("ServerBlockFaceContext[x=%d, y=%d, z=%d, %s]", frame.location.x, frame.location.y, frame.location.z, frame.face); + .format("ServerBlockFaceContext [x=%+4d, y=%+4d, z=%+4d, %s]", frame.location.x, frame.location.y, frame.location.z, frame.face); break; case LOCATION: - result = String.format("ServerBlockContext[x=%d, y=%d, z=%d]", frame.location.x, frame.location.y, frame.location.z); + result = String.format("ServerBlockContext [x=%+4d, y=%+4d, z=%+4d]", frame.location.x, frame.location.y, frame.location.z); break; case WORLD: - result = String.format("ServerWorldContext"); + result = "ServerWorldContext"; break; default: - result = "Uninitialized ReusableServerContext"; + result = "Uninitialized DefaultServerContext"; break; } @@ -188,7 +188,6 @@ class DefaultServerContextImpl extends DefaultServerContext public Empty reuse() { server = null; -// worldLogic = null; world = null; while (isSubcontexting()) { diff --git a/src/main/java/ru/windcorp/progressia/server/world/context/impl/FilterServerContext.java b/src/main/java/ru/windcorp/progressia/server/world/context/impl/FilterServerContext.java index 40927c3..b7b5ff5 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/context/impl/FilterServerContext.java +++ b/src/main/java/ru/windcorp/progressia/server/world/context/impl/FilterServerContext.java @@ -51,6 +51,11 @@ public abstract class FilterServerContext implements ServerTileContext { public ServerTileContext getParent() { return parent; } + + @Override + public String toString() { + return getClass().getSimpleName() + " [" + parent + "]"; + } @Override public int getLayer() { diff --git a/src/main/java/ru/windcorp/progressia/server/world/tasks/TickChunk.java b/src/main/java/ru/windcorp/progressia/server/world/tasks/TickChunk.java index d7fabc1..4ed21f1 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/tasks/TickChunk.java +++ b/src/main/java/ru/windcorp/progressia/server/world/tasks/TickChunk.java @@ -178,12 +178,16 @@ public class TickChunk extends Evaluation { ServerTileContext tileContext = context.push(i); TileLogic logic = tileContext.logic().getTile(); - if (!(logic instanceof TickableTile)) - return; + if (!(logic instanceof TickableTile)) { + tileContext.pop(); + continue; + } TickableTile tickable = (TickableTile) logic; - if (tickable.getTickingPolicy(tileContext) != TickingPolicy.RANDOM) - return; + if (tickable.getTickingPolicy(tileContext) != TickingPolicy.RANDOM) { + tileContext.pop(); + continue; + } tickable.tick(tileContext); tileContext.pop(); diff --git a/src/main/java/ru/windcorp/progressia/server/world/tile/HangingTileLogic.java b/src/main/java/ru/windcorp/progressia/server/world/tile/HangingTileLogic.java index f916a24..87a5c07 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/tile/HangingTileLogic.java +++ b/src/main/java/ru/windcorp/progressia/server/world/tile/HangingTileLogic.java @@ -49,9 +49,7 @@ public class HangingTileLogic extends TileLogic implements UpdateableTile { context.pushOpposite(); BlockLogic complHost = context.logic().getBlock(); - boolean result = complHost == null || !complHost.isSolid(context, context.getFace()); - context.pop(); - return result; + return context.popAndReturn(complHost == null || !complHost.isSolid(context, context.getFace())); } public boolean canBeSquashed(ServerTileContextRO context) { diff --git a/src/main/java/ru/windcorp/progressia/test/TestTileLogicGrass.java b/src/main/java/ru/windcorp/progressia/test/TestTileLogicGrass.java index b41f5a7..bfe438f 100644 --- a/src/main/java/ru/windcorp/progressia/test/TestTileLogicGrass.java +++ b/src/main/java/ru/windcorp/progressia/test/TestTileLogicGrass.java @@ -50,7 +50,7 @@ public class TestTileLogicGrass extends HangingTileLogic implements TickableTile @Override public void tick(ServerTileContext context) { if (!isLocationSuitable(context)) { -// context.removeThisTile(); + context.removeTile(); } } From 54c66d28d6579bad0d4973a741a8b8c343908af4 Mon Sep 17 00:00:00 2001 From: OLEGSHA Date: Fri, 13 Aug 2021 16:11:46 +0300 Subject: [PATCH 44/55] Added TransformingServerContext and RotatingServerContext. WIP There is a problem with faces in contexts when up != POS_Z, world crashes soon after startup - Added TransformingServerContext - a common basis for context wrappers that alter the coordinate space - Added RotatingServerContext - a context wrapper that rotates the coordinate space - Used to ensure positive Z is up - PacketAffectTile now checks the provided tile tag for validity - This causes a crash when the invalid action is requested, not executed - TickChunk task reuses contexts --- .../world/generic/context/WorldContexts.java | 76 +++++ .../common/world/tile/PacketAffectTile.java | 4 + .../ru/windcorp/progressia/server/Server.java | 57 +++- .../server/world/DefaultChunkLogic.java | 30 +- .../server/world/TickAndUpdateUtil.java | 31 +- .../server/world/context/ServerContexts.java | 141 +++++++++ .../impl/DefaultServerContextImpl.java | 36 +++ .../impl/DefaultServerContextLogic.java | 21 ++ .../context/impl/FilterServerContext.java | 21 ++ .../context/impl/RotatingServerContext.java | 54 ++++ .../impl/TransformingServerContext.java | 273 ++++++++++++++++++ .../server/world/tasks/TickChunk.java | 90 +++--- .../windcorp/progressia/test/TestContent.java | 6 +- .../progressia/test/TestTileLogicGrass.java | 3 +- 14 files changed, 749 insertions(+), 94 deletions(-) create mode 100644 src/main/java/ru/windcorp/progressia/server/world/context/ServerContexts.java create mode 100644 src/main/java/ru/windcorp/progressia/server/world/context/impl/RotatingServerContext.java create mode 100644 src/main/java/ru/windcorp/progressia/server/world/context/impl/TransformingServerContext.java diff --git a/src/main/java/ru/windcorp/progressia/common/world/generic/context/WorldContexts.java b/src/main/java/ru/windcorp/progressia/common/world/generic/context/WorldContexts.java index 30b85ce..5cf9f44 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/generic/context/WorldContexts.java +++ b/src/main/java/ru/windcorp/progressia/common/world/generic/context/WorldContexts.java @@ -20,7 +20,9 @@ package ru.windcorp.progressia.common.world.generic.context; import glm.vec._3.i.Vec3i; import ru.windcorp.progressia.common.world.context.Context; +import ru.windcorp.progressia.common.world.rels.AbsFace; import ru.windcorp.progressia.common.world.rels.AbsRelation; +import ru.windcorp.progressia.common.world.rels.BlockFace; import ru.windcorp.progressia.common.world.rels.RelFace; /** @@ -81,6 +83,80 @@ class WorldContexts { */ Tile push(Vec3i location, RelFace face, int layer); + /** + * Converts the provided location given in the context's coordinate + * space to the underlying absolute coordinate space. + *

    + * The definition of "absolute coordinate space" for contexts that are + * not {@linkplain #isReal() real} may be arbitrary, but methods + * {@link #toAbsolute(Vec3i, Vec3i)}, {@link #toAbsolute(BlockFace)}, + * {@link #toContext(Vec3i, Vec3i)} and {@link #toContext(AbsFace)} are + * guaranteed to be consistent for all contexts. + * + * @param contextLocation the location expressed in context coordinate + * system + * @param output the {@link Vec3i} object to output the result + * into, or {@code null} + * @return The location expressed in absolute coordinate system. If + * {@code output} is not {@code null}, {@code output} is + * returned; otherwise, a new {@link Vec3i} is instantiated and + * returned + */ + Vec3i toAbsolute(Vec3i contextLocation, Vec3i output); + + /** + * Converts the provided location given in the absolute coordinate + * space to the context coordinate space. + *

    + * The definition of "absolute coordinate space" for contexts that are + * not {@linkplain #isReal() real} may be arbitrary, but methods + * {@link #toAbsolute(Vec3i, Vec3i)}, {@link #toAbsolute(BlockFace)}, + * {@link #toContext(Vec3i, Vec3i)} and {@link #toContext(AbsFace)} are + * guaranteed to be consistent for all contexts. + * + * @param contextLocation the location expressed in absolute coordinate + * system + * @param output the {@link Vec3i} object to output the result + * into, or {@code null} + * @return The location expressed in context coordinate system. If + * {@code output} is not {@code null}, {@code output} is + * returned; otherwise, a new {@link Vec3i} is instantiated and + * returned + */ + Vec3i toContext(Vec3i absoluteLocation, Vec3i output); + + /** + * Converts the provided face given in the context's coordinate + * space to the underlying absolute coordinate space. + *

    + * The definition of "absolute coordinate space" for contexts that are + * not {@linkplain #isReal() real} may be arbitrary, but methods + * {@link #toAbsolute(Vec3i, Vec3i)}, {@link #toAbsolute(BlockFace)}, + * {@link #toContext(Vec3i, Vec3i)} and {@link #toContext(AbsFace)} are + * guaranteed to be consistent for all contexts. + * + * @param contextLocation the face expressed in context coordinate + * system + * @return the face expressed in absolute coordinate system + */ + AbsFace toAbsolute(BlockFace contextFace); + + /** + * Converts the provided face given in the absolute coordinate + * space to the context coordinate space. + *

    + * The definition of "absolute coordinate space" for contexts that are + * not {@linkplain #isReal() real} may be arbitrary, but methods + * {@link #toAbsolute(Vec3i, Vec3i)}, {@link #toAbsolute(BlockFace)}, + * {@link #toContext(Vec3i, Vec3i)} and {@link #toContext(AbsFace)} are + * guaranteed to be consistent for all contexts. + * + * @param contextLocation the face expressed in absolute coordinate + * system + * @return the face expressed in context coordinate system + */ + RelFace toContext(AbsFace absoluteFace); + } /** diff --git a/src/main/java/ru/windcorp/progressia/common/world/tile/PacketAffectTile.java b/src/main/java/ru/windcorp/progressia/common/world/tile/PacketAffectTile.java index 9be01e2..41cffef 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/tile/PacketAffectTile.java +++ b/src/main/java/ru/windcorp/progressia/common/world/tile/PacketAffectTile.java @@ -51,6 +51,10 @@ public abstract class PacketAffectTile extends PacketAffectChunk { } public void set(Vec3i blockInWorld, AbsFace face, int tag) { + if (tag < 0) { + throw new IllegalArgumentException("Cannot affect tile with tag -1"); + } + this.blockInWorld.set(blockInWorld.x, blockInWorld.y, blockInWorld.z); this.face = face; this.tag = tag; diff --git a/src/main/java/ru/windcorp/progressia/server/Server.java b/src/main/java/ru/windcorp/progressia/server/Server.java index 0efc551..915c262 100644 --- a/src/main/java/ru/windcorp/progressia/server/Server.java +++ b/src/main/java/ru/windcorp/progressia/server/Server.java @@ -24,20 +24,26 @@ import org.apache.logging.log4j.LogManager; import com.google.common.eventbus.EventBus; +import glm.vec._3.i.Vec3i; import ru.windcorp.jputil.functions.ThrowingRunnable; import ru.windcorp.progressia.common.Units; import ru.windcorp.progressia.common.util.TaskQueue; import ru.windcorp.progressia.common.util.crash.ReportingEventBus; import ru.windcorp.progressia.common.world.DefaultWorldData; +import ru.windcorp.progressia.common.world.rels.AbsFace; +import ru.windcorp.progressia.common.world.rels.AxisRotations; import ru.windcorp.progressia.server.comms.ClientManager; import ru.windcorp.progressia.server.events.ServerEvent; import ru.windcorp.progressia.server.management.load.ChunkRequestDaemon; import ru.windcorp.progressia.server.management.load.EntityRequestDaemon; import ru.windcorp.progressia.server.management.load.LoadManager; import ru.windcorp.progressia.server.world.DefaultWorldLogic; +import ru.windcorp.progressia.server.world.context.ServerBlockContext; +import ru.windcorp.progressia.server.world.context.ServerTileContext; import ru.windcorp.progressia.server.world.context.ServerWorldContext; 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.tasks.WorldAccessor; import ru.windcorp.progressia.server.world.ticking.Change; import ru.windcorp.progressia.server.world.ticking.Evaluation; @@ -102,15 +108,54 @@ public class Server { /** * Instantiates and returns an new {@link ServerWorldContext} instance - * suitable for read and write access to the server's world. This is the - * preferred way to query or change the world. + * suitable for read and write access to the server's world. This context + * uses the absolute coordinate space (not rotated to match positive Z = + * up). * * @return the context + * @see #createContext(AbsFace) */ - public ServerWorldContext createContext() { + public ServerWorldContext createAbsoluteContext() { + return doCreateAbsoluteContext(); + } - return new ReportingServerContext(DefaultServerContext.empty().inRealWorldOf(this).build()).withListener(worldAccessor).setPassToParent(false); - + private ServerTileContext doCreateAbsoluteContext() { + return new ReportingServerContext(DefaultServerContext.empty().inRealWorldOf(this).build()) + .withListener(worldAccessor).setPassToParent(false); + } + + /** + * Instantiates and returns an new {@link ServerWorldContext} instance + * suitable for read and write access to the server's world. This is the + * preferred way to query or change the world. This context uses the + * coordinate space in which positive Z = {@code up}. + * + * @param up the desired up direction + * @return the context + * @see #createContext(Vec3i) + * @see #createAbsoluteContext() + */ + public ServerWorldContext createContext(AbsFace up) { + return new RotatingServerContext(doCreateAbsoluteContext(), up); + } + + /** + * Instantiates and returns an new {@link ServerBlockContext} instance + * suitable for read and write access to the server's world. The context is + * initialized to point to the provided block. This is the preferred way to + * query or change the world. This context uses the coordinate space in + * which positive Z matches the discrete up direction of the provided + * location. + * + * @param up the desired up direction + * @return the context + * @see #createContext(AbsFace) + * @see #createAbsoluteContext() + */ + public ServerBlockContext createContext(Vec3i blockInWorld) { + AbsFace up = getWorld().getUp(blockInWorld); + Vec3i relativeBlockInWorld = AxisRotations.relativize(blockInWorld, up, null); + return new RotatingServerContext(doCreateAbsoluteContext(), up).push(relativeBlockInWorld); } /** @@ -247,7 +292,7 @@ public class Server { // public WorldAccessor getWorldAccessor() { // return worldAccessor; // } - + public WorldAccessor getWorldAccessor___really_bad_dont_use() { return worldAccessor; } diff --git a/src/main/java/ru/windcorp/progressia/server/world/DefaultChunkLogic.java b/src/main/java/ru/windcorp/progressia/server/world/DefaultChunkLogic.java index 978fae3..d18ff11 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/DefaultChunkLogic.java +++ b/src/main/java/ru/windcorp/progressia/server/world/DefaultChunkLogic.java @@ -28,17 +28,18 @@ import java.util.function.BiConsumer; import glm.vec._3.i.Vec3i; import ru.windcorp.progressia.common.world.DefaultChunkData; -import ru.windcorp.progressia.common.world.Coordinates; import ru.windcorp.progressia.common.world.rels.AbsFace; import ru.windcorp.progressia.common.world.rels.BlockFace; import ru.windcorp.progressia.common.world.rels.RelFace; import ru.windcorp.progressia.common.world.TileDataStack; +import ru.windcorp.progressia.common.world.generic.GenericChunks; import ru.windcorp.progressia.common.world.TileDataReference; import ru.windcorp.progressia.server.Server; import ru.windcorp.progressia.server.world.block.BlockLogic; import ru.windcorp.progressia.server.world.block.BlockLogicRegistry; import ru.windcorp.progressia.server.world.block.TickableBlock; import ru.windcorp.progressia.server.world.context.ServerBlockContextRO; +import ru.windcorp.progressia.server.world.context.ServerContexts; import ru.windcorp.progressia.server.world.context.ServerTileContextRO; import ru.windcorp.progressia.server.world.context.ServerWorldContextRO; import ru.windcorp.progressia.server.world.tasks.TickChunk; @@ -225,15 +226,12 @@ public class DefaultChunkLogic implements ChunkLogic { } private void tmp_generateTickLists() { - ServerWorldContextRO context = Server.getCurrentServer().createContext(); - Vec3i blockInChunk = new Vec3i(); + ServerWorldContextRO context = Server.getCurrentServer().createContext(getUp()); - forEachBiW(location -> { + GenericChunks.forEachBiC(blockInChunk -> { - ServerBlockContextRO blockContext = context.push(location); - - BlockLogic block = blockContext.logic().getBlock(); - Coordinates.convertInWorldToInChunk(location, blockInChunk); + ServerBlockContextRO blockContext = ServerContexts.pushAbs(context, this, blockInChunk); + BlockLogic block = getBlock(blockInChunk); if (!(block instanceof TickableBlock)) { blockContext.pop(); @@ -241,7 +239,7 @@ public class DefaultChunkLogic implements ChunkLogic { } if (((TickableBlock) block).getTickingPolicy(blockContext) == TickingPolicy.REGULAR) { - tickingBlocks.add(blockInChunk); + tickingBlocks.add(blockInChunk.add_(0)); } for (RelFace face : RelFace.getFaces()) { @@ -249,16 +247,14 @@ public class DefaultChunkLogic implements ChunkLogic { if (stack == null || stack.isEmpty()) continue; for (int i = 0; i < stack.size(); ++i) { - ServerTileContextRO tileContext = blockContext.push(face, i); + ServerTileContextRO tileContext = blockContext.push(context.toContext(face.resolve(getUp())), i); TileLogic tile = stack.get(i); - if (!(tile instanceof TickableTile)) { - tileContext.pop(); - continue; - } - - if (((TickableTile) tile).getTickingPolicy(tileContext) == TickingPolicy.REGULAR) { - tickingTiles.add(stack.getData().getReference(i)); + if (tile instanceof TickableTile) { + TickingPolicy policy = ((TickableTile) tile).getTickingPolicy(tileContext); + if (policy == TickingPolicy.REGULAR) { + tickingTiles.add(stack.getData().getReference(i)); + } } tileContext.pop(); diff --git a/src/main/java/ru/windcorp/progressia/server/world/TickAndUpdateUtil.java b/src/main/java/ru/windcorp/progressia/server/world/TickAndUpdateUtil.java index 286a557..9e21c63 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/TickAndUpdateUtil.java +++ b/src/main/java/ru/windcorp/progressia/server/world/TickAndUpdateUtil.java @@ -21,12 +21,13 @@ package ru.windcorp.progressia.server.world; import glm.vec._3.i.Vec3i; import ru.windcorp.progressia.common.util.crash.CrashReports; import ru.windcorp.progressia.common.world.entity.EntityData; -import ru.windcorp.progressia.common.world.rels.BlockFace; +import ru.windcorp.progressia.common.world.rels.AbsFace; import ru.windcorp.progressia.server.Server; import ru.windcorp.progressia.server.world.block.BlockLogic; import ru.windcorp.progressia.server.world.block.TickableBlock; import ru.windcorp.progressia.server.world.block.UpdateableBlock; import ru.windcorp.progressia.server.world.context.ServerBlockContext; +import ru.windcorp.progressia.server.world.context.ServerContexts; import ru.windcorp.progressia.server.world.context.ServerTileContext; import ru.windcorp.progressia.server.world.context.ServerTileStackContext; import ru.windcorp.progressia.server.world.context.ServerWorldContext; @@ -56,7 +57,7 @@ public class TickAndUpdateUtil { if (!(block instanceof TickableBlock)) { return; } - ServerBlockContext context = server.createContext().push(blockInWorld); + ServerBlockContext context = server.createContext(blockInWorld); tickBlock(context); } @@ -73,23 +74,22 @@ public class TickAndUpdateUtil { } } - public static void tickTile(Server server, Vec3i blockInWorld, BlockFace face, int layer) { + public static void tickTile(Server server, Vec3i blockInWorld, AbsFace face, int layer) { TileLogic tile = server.getWorld().getTile(blockInWorld, face, layer); if (!(tile instanceof TickableTile)) { return; } - ServerTileContext context = server.createContext() - .push(blockInWorld, face.relativize(server.getWorld().getUp(blockInWorld)), layer); + ServerTileContext context = ServerContexts.pushAbs(server.createContext(blockInWorld), blockInWorld, face) + .push(layer); tickTile(context); } - public static void tickTiles(Server server, Vec3i blockInWorld, BlockFace face) { + public static void tickTiles(Server server, Vec3i blockInWorld, AbsFace face) { if (!server.getWorld().hasTiles(blockInWorld, face)) { return; } - ServerTileStackContext context = server.createContext() - .push(blockInWorld, face.relativize(server.getWorld().getUp(blockInWorld))); + ServerTileStackContext context = ServerContexts.pushAbs(server.createContext(blockInWorld), blockInWorld, face); for (int i = 0; i < context.getTileCount(); ++i) { tickTile(context.push(i)); context.pop(); @@ -114,7 +114,7 @@ public class TickAndUpdateUtil { if (!(block instanceof UpdateableBlock)) { return; } - ServerBlockContext context = server.createContext().push(blockInWorld); + ServerBlockContext context = server.createContext(blockInWorld); updateBlock(context); } @@ -131,23 +131,22 @@ public class TickAndUpdateUtil { } } - public static void updateTile(Server server, Vec3i blockInWorld, BlockFace face, int layer) { + public static void updateTile(Server server, Vec3i blockInWorld, AbsFace face, int layer) { TileLogic tile = server.getWorld().getTile(blockInWorld, face, layer); if (!(tile instanceof UpdateableTile)) { return; } - ServerTileContext context = server.createContext() - .push(blockInWorld, face.relativize(server.getWorld().getUp(blockInWorld)), layer); + ServerTileContext context = ServerContexts.pushAbs(server.createContext(blockInWorld), blockInWorld, face) + .push(layer); updateTile(context); } - public static void updateTiles(Server server, Vec3i blockInWorld, BlockFace face) { + public static void updateTiles(Server server, Vec3i blockInWorld, AbsFace face) { if (!server.getWorld().hasTiles(blockInWorld, face)) { return; } - ServerTileStackContext context = server.createContext() - .push(blockInWorld, face.relativize(server.getWorld().getUp(blockInWorld))); + ServerTileStackContext context = ServerContexts.pushAbs(server.createContext(blockInWorld), blockInWorld, face); for (int i = 0; i < context.getTileCount(); ++i) { updateTile(context.push(i)); context.pop(); @@ -166,7 +165,7 @@ public class TickAndUpdateUtil { tickEntity( EntityLogicRegistry.getInstance().get(data.getId()), data, - server.createContext() + server.createContext(data.getUpFace()) ); } diff --git a/src/main/java/ru/windcorp/progressia/server/world/context/ServerContexts.java b/src/main/java/ru/windcorp/progressia/server/world/context/ServerContexts.java new file mode 100644 index 0000000..b0cf996 --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/server/world/context/ServerContexts.java @@ -0,0 +1,141 @@ +/* + * 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.server.world.context; + +import glm.vec._3.i.Vec3i; +import ru.windcorp.progressia.common.util.Vectors; +import ru.windcorp.progressia.common.world.Coordinates; +import ru.windcorp.progressia.common.world.generic.ChunkGenericRO; +import ru.windcorp.progressia.common.world.generic.TileGenericReferenceRO; +import ru.windcorp.progressia.common.world.rels.AbsFace; +import ru.windcorp.progressia.common.world.rels.RelFace; + +public class ServerContexts { + + /* + * RW + */ + + public static ServerBlockContext pushAbs(ServerWorldContext context, Vec3i blockInWorld) { + Vec3i contextLocation = Vectors.grab3i(); + context.toContext(blockInWorld, contextLocation); + ServerBlockContext blockContext = context.push(contextLocation); + Vectors.release(contextLocation); + return blockContext; + } + + public static ServerBlockContext pushAbs(ServerWorldContext context, ChunkGenericRO chunk, Vec3i blockInChunk) { + Vec3i contextLocation = Vectors.grab3i(); + Coordinates.getInWorld(chunk.getPosition(), blockInChunk, contextLocation); + context.toContext(contextLocation, contextLocation); + ServerBlockContext blockContext = context.push(contextLocation); + Vectors.release(contextLocation); + return blockContext; + } + + public static ServerTileStackContext pushAbs(ServerWorldContext context, Vec3i blockInWorld, AbsFace face) { + Vec3i contextLocation = Vectors.grab3i(); + context.toContext(blockInWorld, contextLocation); + RelFace contextFace = context.toContext(face); + ServerTileStackContext tileStackContext = context.push(contextLocation, contextFace); + Vectors.release(contextLocation); + return tileStackContext; + } + + public static ServerTileStackContext pushAbs(ServerWorldContext context, ChunkGenericRO chunk, Vec3i blockInChunk, AbsFace face) { + Vec3i contextLocation = Vectors.grab3i(); + Coordinates.getInWorld(chunk.getPosition(), blockInChunk, contextLocation); + context.toContext(contextLocation, contextLocation); + RelFace contextFace = context.toContext(face); + ServerTileStackContext tileStackContext = context.push(contextLocation, contextFace); + Vectors.release(contextLocation); + return tileStackContext; + } + + public static ServerTileStackContext pushAbs(ServerBlockContext context, AbsFace face) { + return context.push(context.toContext(face)); + } + + public static ServerTileContext pushAbs(ServerWorldContext context, AbsFace up, TileGenericReferenceRO ref) { + Vec3i contextLocation = Vectors.grab3i(); + ref.getStack().getBlockInWorld(contextLocation); + context.toContext(contextLocation, contextLocation); + RelFace contextFace = context.toContext(ref.getStack().getFace().resolve(up)); + ServerTileContext tileContext = context.push(contextLocation, contextFace, ref.getIndex()); + Vectors.release(contextLocation); + return tileContext; + } + + /* + * RO + */ + + public static ServerBlockContextRO pushAbs(ServerWorldContextRO context, Vec3i blockInWorld) { + Vec3i contextLocation = Vectors.grab3i(); + context.toContext(blockInWorld, contextLocation); + ServerBlockContextRO blockContextRO = context.push(contextLocation); + Vectors.release(contextLocation); + return blockContextRO; + } + + public static ServerBlockContextRO pushAbs(ServerWorldContextRO context, ChunkGenericRO chunk, Vec3i blockInChunk) { + Vec3i contextLocation = Vectors.grab3i(); + Coordinates.getInWorld(chunk.getPosition(), blockInChunk, contextLocation); + context.toContext(contextLocation, contextLocation); + ServerBlockContextRO blockContextRO = context.push(contextLocation); + Vectors.release(contextLocation); + return blockContextRO; + } + + public static ServerTileStackContextRO pushAbs(ServerWorldContextRO context, Vec3i blockInWorld, AbsFace face) { + Vec3i contextLocation = Vectors.grab3i(); + context.toContext(blockInWorld, contextLocation); + RelFace contextFace = context.toContext(face); + ServerTileStackContextRO tileStackContextRO = context.push(contextLocation, contextFace); + Vectors.release(contextLocation); + return tileStackContextRO; + } + + public static ServerTileStackContextRO pushAbs(ServerWorldContextRO context, ChunkGenericRO chunk, Vec3i blockInChunk, AbsFace face) { + Vec3i contextLocation = Vectors.grab3i(); + Coordinates.getInWorld(chunk.getPosition(), blockInChunk, contextLocation); + context.toContext(contextLocation, contextLocation); + RelFace contextFace = context.toContext(face); + ServerTileStackContextRO tileStackContextRO = context.push(contextLocation, contextFace); + Vectors.release(contextLocation); + return tileStackContextRO; + } + + public static ServerTileStackContextRO pushAbs(ServerBlockContextRO context, AbsFace face) { + return context.push(context.toContext(face)); + } + + public static ServerTileContextRO pushAbs(ServerWorldContextRO context, AbsFace up, TileGenericReferenceRO ref) { + Vec3i contextLocation = Vectors.grab3i(); + ref.getStack().getBlockInWorld(contextLocation); + context.toContext(contextLocation, contextLocation); + RelFace contextFace = context.toContext(ref.getStack().getFace().resolve(up)); + ServerTileContextRO tileContextRO = context.push(contextLocation, contextFace, ref.getIndex()); + Vectors.release(contextLocation); + return tileContextRO; + } + + private ServerContexts() { + } + +} diff --git a/src/main/java/ru/windcorp/progressia/server/world/context/impl/DefaultServerContextImpl.java b/src/main/java/ru/windcorp/progressia/server/world/context/impl/DefaultServerContextImpl.java index ec89e47..aeda6e8 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/context/impl/DefaultServerContextImpl.java +++ b/src/main/java/ru/windcorp/progressia/server/world/context/impl/DefaultServerContextImpl.java @@ -29,6 +29,7 @@ import ru.windcorp.progressia.common.world.WorldData; import ru.windcorp.progressia.common.world.block.BlockData; import ru.windcorp.progressia.common.world.entity.EntityData; import ru.windcorp.progressia.common.world.generic.EntityGeneric; +import ru.windcorp.progressia.common.world.rels.AbsFace; import ru.windcorp.progressia.common.world.rels.BlockFace; import ru.windcorp.progressia.common.world.rels.RelFace; import ru.windcorp.progressia.common.world.tile.TileData; @@ -290,6 +291,41 @@ class DefaultServerContextImpl extends DefaultServerContext assert requireContextRole(Role.TILE); return frame.layer; } + + /* + * ABSOLUTE COORDINATE CONVERSIONS + * (or lack thereof) + */ + + @Override + public Vec3i toAbsolute(Vec3i contextLocation, Vec3i output) { + if (output == null) { + output = new Vec3i(); + } + + output.set(contextLocation.x, contextLocation.y, contextLocation.z); + return output; + } + + @Override + public Vec3i toContext(Vec3i absoluteLocation, Vec3i output) { + if (output == null) { + output = new Vec3i(); + } + + output.set(absoluteLocation.x, absoluteLocation.y, absoluteLocation.z); + return output; + } + + @Override + public AbsFace toAbsolute(BlockFace contextFace) { + return contextFace.resolve(AbsFace.POS_Z); + } + + @Override + public RelFace toContext(AbsFace absoluteFace) { + return absoluteFace.relativize(AbsFace.POS_Z); + } /* * RO CONTEXT INTERFACE diff --git a/src/main/java/ru/windcorp/progressia/server/world/context/impl/DefaultServerContextLogic.java b/src/main/java/ru/windcorp/progressia/server/world/context/impl/DefaultServerContextLogic.java index 4461d23..640a475 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/context/impl/DefaultServerContextLogic.java +++ b/src/main/java/ru/windcorp/progressia/server/world/context/impl/DefaultServerContextLogic.java @@ -23,6 +23,7 @@ import java.util.Random; import glm.vec._3.i.Vec3i; import ru.windcorp.progressia.common.world.block.BlockData; import ru.windcorp.progressia.common.world.entity.EntityData; +import ru.windcorp.progressia.common.world.rels.AbsFace; import ru.windcorp.progressia.common.world.rels.BlockFace; import ru.windcorp.progressia.common.world.rels.RelFace; import ru.windcorp.progressia.common.world.tile.TileData; @@ -84,6 +85,26 @@ public class DefaultServerContextLogic implements ServerTileContext.Logic { parent.push(location, face, layer); return this; } + + @Override + public Vec3i toAbsolute(Vec3i contextLocation, Vec3i output) { + return parent.toAbsolute(contextLocation, output); + } + + @Override + public Vec3i toContext(Vec3i absoluteLocation, Vec3i output) { + return parent.toContext(absoluteLocation, output); + } + + @Override + public AbsFace toAbsolute(BlockFace contextFace) { + return parent.toAbsolute(contextFace); + } + + @Override + public RelFace toContext(AbsFace absoluteFace) { + return parent.toContext(absoluteFace); + } @Override public double getTickLength() { diff --git a/src/main/java/ru/windcorp/progressia/server/world/context/impl/FilterServerContext.java b/src/main/java/ru/windcorp/progressia/server/world/context/impl/FilterServerContext.java index b7b5ff5..677f9d3 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/context/impl/FilterServerContext.java +++ b/src/main/java/ru/windcorp/progressia/server/world/context/impl/FilterServerContext.java @@ -27,6 +27,7 @@ import ru.windcorp.progressia.common.world.GravityModel; import ru.windcorp.progressia.common.world.block.BlockData; import ru.windcorp.progressia.common.world.entity.EntityData; import ru.windcorp.progressia.common.world.generic.EntityGeneric; +import ru.windcorp.progressia.common.world.rels.AbsFace; import ru.windcorp.progressia.common.world.rels.BlockFace; import ru.windcorp.progressia.common.world.rels.RelFace; import ru.windcorp.progressia.common.world.tile.TileData; @@ -199,6 +200,26 @@ public abstract class FilterServerContext implements ServerTileContext { parent.push(location, face, layer); return this; } + + @Override + public Vec3i toAbsolute(Vec3i contextLocation, Vec3i output) { + return parent.toAbsolute(contextLocation, output); + } + + @Override + public Vec3i toContext(Vec3i absoluteLocation, Vec3i output) { + return parent.toContext(absoluteLocation, output); + } + + @Override + public AbsFace toAbsolute(BlockFace contextFace) { + return parent.toAbsolute(contextFace); + } + + @Override + public RelFace toContext(AbsFace absoluteFace) { + return parent.toContext(absoluteFace); + } @Override public Server getServer() { diff --git a/src/main/java/ru/windcorp/progressia/server/world/context/impl/RotatingServerContext.java b/src/main/java/ru/windcorp/progressia/server/world/context/impl/RotatingServerContext.java new file mode 100644 index 0000000..2ccc86c --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/server/world/context/impl/RotatingServerContext.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.server.world.context.impl; + +import glm.vec._3.i.Vec3i; +import ru.windcorp.progressia.common.world.rels.AbsFace; +import ru.windcorp.progressia.common.world.rels.RelFace; +import ru.windcorp.progressia.server.world.context.ServerTileContext; + +public class RotatingServerContext extends TransformingServerContext { + + private final AbsFace up; + + public RotatingServerContext(ServerTileContext parent, AbsFace up) { + super(parent); + this.up = up; + } + + @Override + protected void transform(Vec3i userLocation, Vec3i output) { + output.set(userLocation.x, userLocation.y, userLocation.z); + } + + @Override + protected void untransform(Vec3i parentLocation, Vec3i output) { + output.set(parentLocation.x, parentLocation.y, parentLocation.z); + } + + @Override + protected RelFace transform(RelFace userFace) { + return userFace.resolve(up).relativize(AbsFace.POS_Z); + } + + @Override + protected RelFace untransform(RelFace parentFace) { + return parentFace.resolve(AbsFace.POS_Z).relativize(up); + } + +} diff --git a/src/main/java/ru/windcorp/progressia/server/world/context/impl/TransformingServerContext.java b/src/main/java/ru/windcorp/progressia/server/world/context/impl/TransformingServerContext.java new file mode 100644 index 0000000..7305876 --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/server/world/context/impl/TransformingServerContext.java @@ -0,0 +1,273 @@ +/* + * 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.server.world.context.impl; + +import java.util.ArrayList; +import java.util.List; + +import glm.vec._3.i.Vec3i; +import ru.windcorp.progressia.common.world.block.BlockData; +import ru.windcorp.progressia.common.world.rels.AbsFace; +import ru.windcorp.progressia.common.world.rels.BlockFace; +import ru.windcorp.progressia.common.world.rels.RelFace; +import ru.windcorp.progressia.common.world.tile.TileData; +import ru.windcorp.progressia.server.world.context.ServerBlockContext; +import ru.windcorp.progressia.server.world.context.ServerTileContext; +import ru.windcorp.progressia.server.world.context.ServerTileStackContext; + +public abstract class TransformingServerContext extends FilterServerContext { + + private final Vec3i location = new Vec3i(); + private boolean isLocationValid = false; + + private RelFace face; + + private final List vectorCache = new ArrayList<>(1); + + public TransformingServerContext(ServerTileContext parent) { + super(parent); + } + + protected abstract void transform(Vec3i userLocation, Vec3i output); + + protected abstract void untransform(Vec3i parentLocation, Vec3i output); + + protected abstract RelFace transform(RelFace userFace); + + protected abstract RelFace untransform(RelFace parentFace); + + protected void invalidateCache() { + isLocationValid = false; + face = null; + } + + private Vec3i grabVector(Vec3i userVector) { + Vec3i parentVector; + + if (vectorCache.isEmpty()) { + parentVector = new Vec3i(); + } else { + parentVector = vectorCache.remove(vectorCache.size() - 1); + } + + transform(userVector, parentVector); + + return parentVector; + } + + private void releaseVector(Vec3i parentVector) { + vectorCache.add(parentVector); + } + + @Override + public Vec3i getLocation() { + // Always invoke parent method to allow parent to determine validity + Vec3i parentLocation = super.getLocation(); + + if (!isLocationValid) { + untransform(parentLocation, location); + isLocationValid = true; + } + + return location; + } + + @Override + public RelFace getFace() { + // Always invoke parent method to allow parent to determine validity + RelFace parentFace = super.getFace(); + + if (face == null) { + face = untransform(parentFace); + } + + return face; + } + + @Override + public void pop() { + super.pop(); + invalidateCache(); + } + + @Override + public ServerBlockContext push(Vec3i userLocation) { + transform(userLocation, location); + isLocationValid = true; + super.push(location); + face = null; + return this; + } + + @Override + public ServerTileStackContext push(Vec3i userLocation, RelFace userFace) { + transform(userLocation, location); + isLocationValid = true; + face = transform(userFace); + super.push(location, face); + return this; + } + + @Override + public ServerTileContext push(Vec3i userLocation, RelFace userFace, int layer) { + transform(userLocation, location); + isLocationValid = true; + face = transform(userFace); + super.push(location, face, layer); + return this; + } + + @Override + public Vec3i toAbsolute(Vec3i contextLocation, Vec3i output) { + if (output == null) { + output = new Vec3i(); + } + + transform(contextLocation, output); + + return super.toAbsolute(output, output); + } + + @Override + public Vec3i toContext(Vec3i absoluteLocation, Vec3i output) { + output = super.toContext(absoluteLocation, output); + untransform(output, output); + return output; + } + + @Override + public AbsFace toAbsolute(BlockFace contextFace) { + return super.toAbsolute(transform(contextFace.relativize(AbsFace.POS_Z))); + } + + @Override + public RelFace toContext(AbsFace absoluteFace) { + return untransform(super.toContext(absoluteFace)); + } + + @Override + public boolean isLocationLoaded(Vec3i userLocation) { + Vec3i parentLocation = grabVector(userLocation); + + try { + return super.isLocationLoaded(parentLocation); + } finally { + releaseVector(parentLocation); + } + } + + @Override + public BlockData getBlock(Vec3i userLocation) { + Vec3i parentLocation = grabVector(userLocation); + + try { + return super.getBlock(parentLocation); + } finally { + releaseVector(parentLocation); + } + } + + @Override + public void setBlock(Vec3i userLocation, BlockData block) { + Vec3i parentLocation = grabVector(userLocation); + + try { + super.setBlock(parentLocation, block); + } finally { + releaseVector(parentLocation); + } + } + + @Override + public boolean hasTile(Vec3i userLocation, BlockFace userFace, int layer) { + Vec3i parentLocation = grabVector(userLocation); + + try { + return super.hasTile(parentLocation, transform(userFace.relativize(AbsFace.POS_Z)), layer); + } finally { + releaseVector(parentLocation); + } + } + + @Override + public TileData getTile(Vec3i userLocation, BlockFace userFace, int layer) { + Vec3i parentLocation = grabVector(userLocation); + + try { + return super.getTile(parentLocation, transform(userFace.relativize(AbsFace.POS_Z)), layer); + } finally { + releaseVector(parentLocation); + } + } + + @Override + public boolean isTagValid(Vec3i userLocation, BlockFace userFace, int tag) { + Vec3i parentLocation = grabVector(userLocation); + + try { + return super.isTagValid(parentLocation, transform(userFace.relativize(AbsFace.POS_Z)), tag); + } finally { + releaseVector(parentLocation); + } + } + + @Override + public TileData getTileByTag(Vec3i userLocation, BlockFace userFace, int tag) { + Vec3i parentLocation = grabVector(userLocation); + + try { + return super.getTileByTag(parentLocation, transform(userFace.relativize(AbsFace.POS_Z)), tag); + } finally { + releaseVector(parentLocation); + } + } + + @Override + public int getTileCount(Vec3i userLocation, BlockFace userFace) { + Vec3i parentLocation = grabVector(userLocation); + + try { + return super.getTileCount(parentLocation, transform(userFace.relativize(AbsFace.POS_Z))); + } finally { + releaseVector(parentLocation); + } + } + + @Override + public void addTile(Vec3i userLocation, BlockFace userFace, TileData tile) { + Vec3i parentLocation = grabVector(userLocation); + + try { + super.addTile(parentLocation, transform(userFace.relativize(AbsFace.POS_Z)), tile); + } finally { + releaseVector(parentLocation); + } + } + + @Override + public void removeTile(Vec3i userLocation, BlockFace userFace, int tag) { + Vec3i parentLocation = grabVector(userLocation); + + try { + super.removeTile(parentLocation, transform(userFace.relativize(AbsFace.POS_Z)), tag); + } finally { + releaseVector(parentLocation); + } + } + +} diff --git a/src/main/java/ru/windcorp/progressia/server/world/tasks/TickChunk.java b/src/main/java/ru/windcorp/progressia/server/world/tasks/TickChunk.java index 4ed21f1..a2a59f9 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/tasks/TickChunk.java +++ b/src/main/java/ru/windcorp/progressia/server/world/tasks/TickChunk.java @@ -27,17 +27,15 @@ import com.google.common.collect.ImmutableList; import glm.vec._3.i.Vec3i; import ru.windcorp.progressia.common.util.FloatMathUtil; -import ru.windcorp.progressia.common.util.Vectors; -import ru.windcorp.progressia.common.world.Coordinates; import ru.windcorp.progressia.common.world.DefaultChunkData; import ru.windcorp.progressia.common.world.rels.AbsFace; import ru.windcorp.progressia.common.world.TileDataStack; -import ru.windcorp.progressia.common.world.generic.ChunkGenericRO; import ru.windcorp.progressia.server.Server; import ru.windcorp.progressia.server.world.DefaultChunkLogic; import ru.windcorp.progressia.server.world.block.BlockLogic; import ru.windcorp.progressia.server.world.block.TickableBlock; import ru.windcorp.progressia.server.world.context.ServerBlockContext; +import ru.windcorp.progressia.server.world.context.ServerContexts; import ru.windcorp.progressia.server.world.context.ServerTileContext; import ru.windcorp.progressia.server.world.context.ServerTileStackContext; import ru.windcorp.progressia.server.world.context.ServerWorldContext; @@ -53,20 +51,21 @@ public class TickChunk extends Evaluation { DefaultChunkData.BLOCKS_PER_CHUNK * DefaultChunkData.BLOCKS_PER_CHUNK; - private final List> randomTickMethods; + private final List> randomTickMethods; { - List> randomTickMethods = new ArrayList<>(); + List> randomTickMethods = new ArrayList<>(); randomTickMethods.add(this::tickRandomBlock); for (AbsFace face : AbsFace.getFaces()) { - randomTickMethods.add(s -> this.tickRandomTile(s, face)); + randomTickMethods.add(context -> this.tickRandomTile(face, context)); } this.randomTickMethods = ImmutableList.copyOf(randomTickMethods); } private final DefaultChunkLogic chunk; + private ServerWorldContext context; public TickChunk(DefaultChunkLogic chunk) { this.chunk = chunk; @@ -74,44 +73,41 @@ public class TickChunk extends Evaluation { @Override public void evaluate(Server server) { - tickRegulars(server); - tickRandom(server); + if (context == null || context.getServer() != server) { + context = server.createContext(chunk.getUp()); + } + + tickRegulars(context); + tickRandom(context); } - private void tickRegulars(Server server) { - tickRegularBlocks(server); - tickRegularTiles(server); + private void tickRegulars(ServerWorldContext context) { + tickRegularBlocks(context); + tickRegularTiles(context); } - private void tickRegularBlocks(Server server) { + private void tickRegularBlocks(ServerWorldContext context) { if (!chunk.hasTickingBlocks()) return; - ServerWorldContext context = server.createContext(); - chunk.forEachTickingBlock((blockInChunk, block) -> { - ((TickableBlock) block).tick(contextPushBiC(context, chunk, blockInChunk)); + ((TickableBlock) block).tick(ServerContexts.pushAbs(context, chunk, blockInChunk)); context.pop(); }); } - private void tickRegularTiles(Server server) { + private void tickRegularTiles(ServerWorldContext context) { if (!chunk.hasTickingTiles()) return; - ServerWorldContext context = server.createContext(); - Vec3i blockInWorld = new Vec3i(); - chunk.forEachTickingTile((ref, tile) -> { - ((TickableTile) tile).tick( - context.push(ref.getStack().getBlockInWorld(blockInWorld), ref.getStack().getFace(), ref.getIndex()) - ); + ((TickableTile) tile).tick(ServerContexts.pushAbs(context, chunk.getUp(), ref)); context.pop(); }); } - private void tickRandom(Server server) { - float ticks = computeRandomTicks(server); + private void tickRandom(ServerWorldContext context) { + float ticks = computeRandomTicks(context.getServer()); /* * If we are expected to run 3.25 random ticks per tick @@ -122,23 +118,23 @@ public class TickChunk extends Evaluation { float extraTickChance = ticks - unconditionalTicks; for (int i = 0; i < unconditionalTicks; ++i) { - tickRandomOnce(server); + tickRandomOnce(context); } - if (server.getAdHocRandom().nextFloat() < extraTickChance) { - tickRandomOnce(server); + if (context.getRandom().nextFloat() < extraTickChance) { + tickRandomOnce(context); } } - private void tickRandomOnce(Server server) { + private void tickRandomOnce(ServerWorldContext context) { // Pick a target at random: a block or one of 3 primary block faces randomTickMethods.get( - server.getAdHocRandom().nextInt(randomTickMethods.size()) - ).accept(server); + context.getRandom().nextInt(randomTickMethods.size()) + ).accept(context); } - private void tickRandomBlock(Server server) { - Random random = server.getAdHocRandom(); + private void tickRandomBlock(ServerWorldContext context) { + Random random = context.getRandom(); Vec3i blockInChunk = new Vec3i( random.nextInt(BLOCKS_PER_CHUNK), @@ -152,15 +148,17 @@ public class TickChunk extends Evaluation { return; TickableBlock tickable = (TickableBlock) block; - ServerBlockContext context = contextPushBiC(server.createContext(), chunk, blockInChunk); + ServerBlockContext blockContext = ServerContexts.pushAbs(context, chunk, blockInChunk); - if (tickable.getTickingPolicy(context) != TickingPolicy.RANDOM) + if (tickable.getTickingPolicy(blockContext) != TickingPolicy.RANDOM) return; - tickable.tick(context); + tickable.tick(blockContext); + + blockContext.pop(); } - private void tickRandomTile(Server server, AbsFace face) { - Random random = server.getAdHocRandom(); + private void tickRandomTile(AbsFace face, ServerWorldContext context) { + Random random = context.getRandom(); Vec3i blockInChunk = new Vec3i( random.nextInt(BLOCKS_PER_CHUNK), @@ -172,10 +170,10 @@ public class TickChunk extends Evaluation { if (tiles == null || tiles.isEmpty()) return; - ServerTileStackContext context = contextPushBiC(server.createContext(), chunk, blockInChunk).push(face.relativize(chunk.getUp())); + ServerTileStackContext tsContext = ServerContexts.pushAbs(context, chunk, blockInChunk, face); for (int i = 0; i < tiles.size(); ++i) { - ServerTileContext tileContext = context.push(i); + ServerTileContext tileContext = tsContext.push(i); TileLogic logic = tileContext.logic().getTile(); if (!(logic instanceof TickableTile)) { @@ -192,6 +190,8 @@ public class TickChunk extends Evaluation { tileContext.pop(); } + + tsContext.pop(); } private float computeRandomTicks(Server server) { @@ -200,18 +200,6 @@ public class TickChunk extends Evaluation { server.getTickLength()); } - private ServerBlockContext contextPushBiC( - ServerWorldContext context, - ChunkGenericRO chunk, - Vec3i blockInChunk - ) { - Vec3i blockInWorld = Vectors.grab3i(); - Coordinates.getInWorld(chunk.getPosition(), blockInChunk, blockInWorld); - ServerBlockContext blockContext = context.push(blockInWorld); - Vectors.release(blockInWorld); - return blockContext; - } - @Override public void getRelevantChunk(Vec3i output) { Vec3i p = chunk.getData().getPosition(); diff --git a/src/main/java/ru/windcorp/progressia/test/TestContent.java b/src/main/java/ru/windcorp/progressia/test/TestContent.java index 0ddc3e5..7b9122f 100644 --- a/src/main/java/ru/windcorp/progressia/test/TestContent.java +++ b/src/main/java/ru/windcorp/progressia/test/TestContent.java @@ -383,7 +383,7 @@ public class TestContent { ru.windcorp.progressia.server.comms.Client client ) { Vec3i blockInWorld = ((ControlBreakBlockData) packet.getControl()).getBlockInWorld(); - server.createContext().setBlock(blockInWorld, BlockDataRegistry.getInstance().get("Test:Air")); + server.createAbsoluteContext().setBlock(blockInWorld, BlockDataRegistry.getInstance().get("Test:Air")); } private static void onBlockPlaceTrigger(ControlData control) { @@ -403,7 +403,7 @@ public class TestContent { Vec3i blockInWorld = controlData.getBlockInWorld(); if (server.getWorld().getData().getChunkByBlock(blockInWorld) == null) return; - server.createContext().setBlock(blockInWorld, block); + server.createAbsoluteContext().setBlock(blockInWorld, block); } private static void onTilePlaceTrigger(ControlData control) { @@ -428,7 +428,7 @@ public class TestContent { return; if (server.getWorld().getData().getTiles(blockInWorld, face).isFull()) return; - server.createContext().addTile(blockInWorld, face, tile); + server.createAbsoluteContext().addTile(blockInWorld, face, tile); } private static void registerMisc() { diff --git a/src/main/java/ru/windcorp/progressia/test/TestTileLogicGrass.java b/src/main/java/ru/windcorp/progressia/test/TestTileLogicGrass.java index bfe438f..c197ce1 100644 --- a/src/main/java/ru/windcorp/progressia/test/TestTileLogicGrass.java +++ b/src/main/java/ru/windcorp/progressia/test/TestTileLogicGrass.java @@ -18,6 +18,7 @@ package ru.windcorp.progressia.test; +import ru.windcorp.progressia.common.world.rels.AbsFace; import ru.windcorp.progressia.common.world.rels.RelFace; import ru.windcorp.progressia.server.world.block.BlockLogic; import ru.windcorp.progressia.server.world.context.ServerTileContext; @@ -65,7 +66,7 @@ public class TestTileLogicGrass extends HangingTileLogic implements TickableTile private boolean isBlockAboveTransparent(ServerTileContextRO context) { // TODO rework - context.pushRelative(RelFace.UP.resolve(context.getServer().getWorld().getUp(context.getLocation()))); + context.pushRelative(RelFace.UP.resolve(AbsFace.POS_Z)); BlockLogic block = context.logic().getBlock(); return context.popAndReturn(block == null || block.isTransparent(context)); } From 82872c7cf3e1f1a5730b083b26df8987700468fa Mon Sep 17 00:00:00 2001 From: OLEGSHA Date: Sun, 15 Aug 2021 23:54:25 +0300 Subject: [PATCH 45/55] Fixed RotatingServerContext - RotatingServerContext now rotates coordinates, too - Fixed a bug caused by the implementation of push methods by TransformingServerContext - Fixed unbounded recursion in WorldGenericRO.hasTile(Vec3i, BlockFace, int) --- .../common/world/generic/WorldGenericRO.java | 3 +- .../context/impl/RotatingServerContext.java | 9 ++++-- .../impl/TransformingServerContext.java | 30 +++++++++++++------ 3 files changed, 30 insertions(+), 12 deletions(-) diff --git a/src/main/java/ru/windcorp/progressia/common/world/generic/WorldGenericRO.java b/src/main/java/ru/windcorp/progressia/common/world/generic/WorldGenericRO.java index eac2a0c..826396f 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/generic/WorldGenericRO.java +++ b/src/main/java/ru/windcorp/progressia/common/world/generic/WorldGenericRO.java @@ -137,7 +137,8 @@ public interface WorldGenericRO< * @return {@code true} iff the tile exists */ default boolean hasTile(Vec3i location, BlockFace face, int layer) { - return hasTile(location, face, layer); + TS stack = getTilesOrNull(location, face); + return stack != null && stack.size() > layer; } default boolean isChunkLoaded(Vec3i chunkPos) { diff --git a/src/main/java/ru/windcorp/progressia/server/world/context/impl/RotatingServerContext.java b/src/main/java/ru/windcorp/progressia/server/world/context/impl/RotatingServerContext.java index 2ccc86c..c6459c4 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/context/impl/RotatingServerContext.java +++ b/src/main/java/ru/windcorp/progressia/server/world/context/impl/RotatingServerContext.java @@ -19,6 +19,7 @@ package ru.windcorp.progressia.server.world.context.impl; import glm.vec._3.i.Vec3i; import ru.windcorp.progressia.common.world.rels.AbsFace; +import ru.windcorp.progressia.common.world.rels.AxisRotations; import ru.windcorp.progressia.common.world.rels.RelFace; import ru.windcorp.progressia.server.world.context.ServerTileContext; @@ -30,15 +31,19 @@ public class RotatingServerContext extends TransformingServerContext { super(parent); this.up = up; } + + public AbsFace getUp() { + return up; + } @Override protected void transform(Vec3i userLocation, Vec3i output) { - output.set(userLocation.x, userLocation.y, userLocation.z); + AxisRotations.resolve(userLocation, up, output); } @Override protected void untransform(Vec3i parentLocation, Vec3i output) { - output.set(parentLocation.x, parentLocation.y, parentLocation.z); + AxisRotations.relativize(parentLocation, up, output); } @Override diff --git a/src/main/java/ru/windcorp/progressia/server/world/context/impl/TransformingServerContext.java b/src/main/java/ru/windcorp/progressia/server/world/context/impl/TransformingServerContext.java index 7305876..1fb387e 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/context/impl/TransformingServerContext.java +++ b/src/main/java/ru/windcorp/progressia/server/world/context/impl/TransformingServerContext.java @@ -35,7 +35,7 @@ public abstract class TransformingServerContext extends FilterServerContext { private final Vec3i location = new Vec3i(); private boolean isLocationValid = false; - private RelFace face; + private RelFace face = null; private final List vectorCache = new ArrayList<>(1); @@ -107,28 +107,40 @@ public abstract class TransformingServerContext extends FilterServerContext { @Override public ServerBlockContext push(Vec3i userLocation) { - transform(userLocation, location); + Vec3i parentLocation = grabVector(userLocation); + super.push(parentLocation); + releaseVector(parentLocation); + + location.set(userLocation.x, userLocation.y, userLocation.z); isLocationValid = true; - super.push(location); face = null; + return this; } @Override public ServerTileStackContext push(Vec3i userLocation, RelFace userFace) { - transform(userLocation, location); + Vec3i parentLocation = grabVector(userLocation); + super.push(parentLocation, transform(userFace)); + releaseVector(parentLocation); + + location.set(userLocation.x, userLocation.y, userLocation.z); isLocationValid = true; - face = transform(userFace); - super.push(location, face); + face = userFace; + return this; } @Override public ServerTileContext push(Vec3i userLocation, RelFace userFace, int layer) { - transform(userLocation, location); + Vec3i parentLocation = grabVector(userLocation); + super.push(parentLocation, transform(userFace), layer); + releaseVector(parentLocation); + + location.set(userLocation.x, userLocation.y, userLocation.z); isLocationValid = true; - face = transform(userFace); - super.push(location, face, layer); + face = userFace; + return this; } From a6fd81ba1e81900bf424ab6e9592037f9830ee58 Mon Sep 17 00:00:00 2001 From: OLEGSHA Date: Mon, 16 Aug 2021 13:05:57 +0300 Subject: [PATCH 46/55] Contexts now only accept RelFace; fixed tile placement crash --- .../world/context/BlockDataContext.java | 6 +- .../world/context/BlockDataContextRO.java | 6 +- .../context/BlockGenericContextRO.java | 17 +++--- .../context/BlockGenericContextWO.java | 11 ++-- .../world/generic/context/WorldContexts.java | 8 +-- .../context/WorldGenericContextRO.java | 58 ++----------------- .../context/WorldGenericContextWO.java | 5 +- .../common/world/tile/PacketAddTile.java | 2 +- .../common/world/tile/PacketAffectTile.java | 14 +++-- .../world/context/ServerBlockContext.java | 10 ++-- .../world/context/ServerBlockContextRO.java | 10 ++-- .../impl/DefaultServerContextImpl.java | 16 ++--- .../impl/DefaultServerContextLogic.java | 13 ++--- .../context/impl/FilterServerContext.java | 17 +++--- .../context/impl/ReportingServerContext.java | 5 +- .../impl/TransformingServerContext.java | 33 +++++------ .../windcorp/progressia/test/TestContent.java | 2 +- .../progressia/test/TestTileLogicGrass.java | 4 +- 18 files changed, 94 insertions(+), 143 deletions(-) diff --git a/src/main/java/ru/windcorp/progressia/common/world/context/BlockDataContext.java b/src/main/java/ru/windcorp/progressia/common/world/context/BlockDataContext.java index 36e7dbe..e535014 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/context/BlockDataContext.java +++ b/src/main/java/ru/windcorp/progressia/common/world/context/BlockDataContext.java @@ -21,8 +21,8 @@ import glm.vec._3.i.Vec3i; import ru.windcorp.progressia.common.world.block.BlockData; import ru.windcorp.progressia.common.world.entity.EntityData; import ru.windcorp.progressia.common.world.generic.context.BlockGenericContextWO; -import ru.windcorp.progressia.common.world.rels.AbsRelation; import ru.windcorp.progressia.common.world.rels.RelFace; +import ru.windcorp.progressia.common.world.rels.RelRelation; import ru.windcorp.progressia.common.world.tile.TileData; public interface BlockDataContext @@ -45,8 +45,8 @@ public interface BlockDataContext } @Override - default BlockDataContext pushRelative(AbsRelation direction) { - return push(getLocation().add_(direction.getVector())); + default BlockDataContext pushRelative(RelRelation direction) { + return push(getLocation().add_(direction.getRelVector())); } @Override diff --git a/src/main/java/ru/windcorp/progressia/common/world/context/BlockDataContextRO.java b/src/main/java/ru/windcorp/progressia/common/world/context/BlockDataContextRO.java index 8d75845..621cc9a 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/context/BlockDataContextRO.java +++ b/src/main/java/ru/windcorp/progressia/common/world/context/BlockDataContextRO.java @@ -21,8 +21,8 @@ import glm.vec._3.i.Vec3i; import ru.windcorp.progressia.common.world.block.BlockData; import ru.windcorp.progressia.common.world.entity.EntityData; import ru.windcorp.progressia.common.world.generic.context.BlockGenericContextRO; -import ru.windcorp.progressia.common.world.rels.AbsRelation; import ru.windcorp.progressia.common.world.rels.RelFace; +import ru.windcorp.progressia.common.world.rels.RelRelation; import ru.windcorp.progressia.common.world.tile.TileData; public interface BlockDataContextRO @@ -44,8 +44,8 @@ public interface BlockDataContextRO } @Override - default BlockDataContextRO pushRelative(AbsRelation direction) { - return push(getLocation().add_(direction.getVector())); + default BlockDataContextRO pushRelative(RelRelation direction) { + return push(getLocation().add_(direction.getRelVector())); } @Override diff --git a/src/main/java/ru/windcorp/progressia/common/world/generic/context/BlockGenericContextRO.java b/src/main/java/ru/windcorp/progressia/common/world/generic/context/BlockGenericContextRO.java index cacbe45..8984ad3 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/generic/context/BlockGenericContextRO.java +++ b/src/main/java/ru/windcorp/progressia/common/world/generic/context/BlockGenericContextRO.java @@ -20,9 +20,8 @@ package ru.windcorp.progressia.common.world.generic.context; import glm.vec._3.i.Vec3i; import ru.windcorp.progressia.common.world.context.Context; import ru.windcorp.progressia.common.world.generic.*; -import ru.windcorp.progressia.common.world.rels.AbsRelation; -import ru.windcorp.progressia.common.world.rels.BlockFace; import ru.windcorp.progressia.common.world.rels.RelFace; +import ru.windcorp.progressia.common.world.rels.RelRelation; /** * A {@link Context} referencing a world with a block location specified. The @@ -68,7 +67,7 @@ public interface BlockGenericContextRO< * @param layer the layer of the tile * @return {@code true} iff the tile exists */ - default boolean hasTile(BlockFace face, int layer) { + default boolean hasTile(RelFace face, int layer) { return hasTile(getLocation(), face, layer); } @@ -80,7 +79,7 @@ public interface BlockGenericContextRO< * @param tag the tag of the tile * @return {@code true} iff the tile exists */ - default boolean isTagValid(BlockFace face, int tag) { + default boolean isTagValid(RelFace face, int tag) { return isTagValid(getLocation(), face, tag); } @@ -97,7 +96,7 @@ public interface BlockGenericContextRO< * @param layer the layer of the tile stack that the tile occupies * @return the tile or {@code null} if the position does not contain a tile */ - default T getTile(BlockFace face, int layer) { + default T getTile(RelFace face, int layer) { return getTile(getLocation(), face, layer); } @@ -115,7 +114,7 @@ public interface BlockGenericContextRO< * @param tag the tag of the tile * @return the tile or {@code null} if the position does not contain a tile */ - default T getTileByTag(BlockFace face, int tag) { + default T getTileByTag(RelFace face, int tag) { return getTileByTag(getLocation(), face, tag); } @@ -129,7 +128,7 @@ public interface BlockGenericContextRO< * @return the count of tiles in the tile stack or {@code -1} if the tile * stack could not exist */ - default int getTileCount(BlockFace face) { + default int getTileCount(RelFace face) { return getTileCount(face); } @@ -148,8 +147,8 @@ public interface BlockGenericContextRO< } @Override - default BlockGenericContextRO pushRelative(AbsRelation direction) { - return push(getLocation().add_(direction.getVector())); + default BlockGenericContextRO pushRelative(RelRelation direction) { + return push(getLocation().add_(direction.getRelVector())); } @Override diff --git a/src/main/java/ru/windcorp/progressia/common/world/generic/context/BlockGenericContextWO.java b/src/main/java/ru/windcorp/progressia/common/world/generic/context/BlockGenericContextWO.java index c1fa216..3555c09 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/generic/context/BlockGenericContextWO.java +++ b/src/main/java/ru/windcorp/progressia/common/world/generic/context/BlockGenericContextWO.java @@ -20,9 +20,8 @@ package ru.windcorp.progressia.common.world.generic.context; import glm.vec._3.i.Vec3i; import ru.windcorp.progressia.common.world.context.Context; import ru.windcorp.progressia.common.world.generic.*; -import ru.windcorp.progressia.common.world.rels.AbsRelation; -import ru.windcorp.progressia.common.world.rels.BlockFace; import ru.windcorp.progressia.common.world.rels.RelFace; +import ru.windcorp.progressia.common.world.rels.RelRelation; /** * A writable {@link Context} referencing a world with a block location @@ -59,7 +58,7 @@ public interface BlockGenericContextWO< * @param face the face of the block to add the tile to * @param tile the tile to add */ - default void addTile(BlockFace face, T tile) { + default void addTile(RelFace face, T tile) { addTile(getLocation(), face, tile); } @@ -72,7 +71,7 @@ public interface BlockGenericContextWO< * @param face the of the block to remove the tile from * @param tag the tag of the tile to remove */ - default void removeTile(BlockFace face, int tag) { + default void removeTile(RelFace face, int tag) { removeTile(getLocation(), face, tag); } @@ -91,8 +90,8 @@ public interface BlockGenericContextWO< } @Override - default BlockGenericContextWO pushRelative(AbsRelation direction) { - return push(getLocation().add_(direction.getVector())); + default BlockGenericContextWO pushRelative(RelRelation direction) { + return push(getLocation().add_(direction.getRelVector())); } @Override diff --git a/src/main/java/ru/windcorp/progressia/common/world/generic/context/WorldContexts.java b/src/main/java/ru/windcorp/progressia/common/world/generic/context/WorldContexts.java index 5cf9f44..f8953d3 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/generic/context/WorldContexts.java +++ b/src/main/java/ru/windcorp/progressia/common/world/generic/context/WorldContexts.java @@ -21,9 +21,9 @@ package ru.windcorp.progressia.common.world.generic.context; import glm.vec._3.i.Vec3i; import ru.windcorp.progressia.common.world.context.Context; import ru.windcorp.progressia.common.world.rels.AbsFace; -import ru.windcorp.progressia.common.world.rels.AbsRelation; import ru.windcorp.progressia.common.world.rels.BlockFace; import ru.windcorp.progressia.common.world.rels.RelFace; +import ru.windcorp.progressia.common.world.rels.RelRelation; /** * This class defines several {@link Context} subinterfaces that are further @@ -139,7 +139,7 @@ class WorldContexts { * system * @return the face expressed in absolute coordinate system */ - AbsFace toAbsolute(BlockFace contextFace); + AbsFace toAbsolute(RelFace contextFace); /** * Converts the provided face given in the absolute coordinate @@ -221,8 +221,8 @@ class WorldContexts { * @return this object * @see #pop() */ - default Block pushRelative(AbsRelation direction) { - return push(getLocation().add_(direction.getVector())); + default Block pushRelative(RelRelation direction) { + return push(getLocation().add_(direction.getRelVector())); } /** diff --git a/src/main/java/ru/windcorp/progressia/common/world/generic/context/WorldGenericContextRO.java b/src/main/java/ru/windcorp/progressia/common/world/generic/context/WorldGenericContextRO.java index 59707e9..ec188d1 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/generic/context/WorldGenericContextRO.java +++ b/src/main/java/ru/windcorp/progressia/common/world/generic/context/WorldGenericContextRO.java @@ -20,11 +20,9 @@ package ru.windcorp.progressia.common.world.generic.context; import java.util.Collection; import java.util.function.Consumer; -import glm.vec._3.Vec3; import glm.vec._3.i.Vec3i; import ru.windcorp.progressia.common.world.context.Context; import ru.windcorp.progressia.common.world.generic.*; -import ru.windcorp.progressia.common.world.rels.BlockFace; import ru.windcorp.progressia.common.world.rels.RelFace; /** @@ -76,7 +74,7 @@ public interface WorldGenericContextRO< * @param layer the layer of the tile stack that the tile occupies * @return the tile or {@code null} if the position does not contain a tile */ - T getTile(Vec3i location, BlockFace face, int layer); + T getTile(Vec3i location, RelFace face, int layer); /** * Retrieves the tile at the specified position and the tile's tag. This @@ -92,7 +90,7 @@ public interface WorldGenericContextRO< * @param tag the tag of the tile * @return the tile or {@code null} if the position does not contain a tile */ - T getTileByTag(Vec3i location, BlockFace face, int tag); + T getTileByTag(Vec3i location, RelFace face, int tag); /** * Determines whether the specified position has a tile. @@ -102,7 +100,7 @@ public interface WorldGenericContextRO< * @param layer the layer of the tile * @return {@code true} iff the tile exists */ - boolean hasTile(Vec3i location, BlockFace face, int layer); + boolean hasTile(Vec3i location, RelFace face, int layer); /** * Determines whether the specified position has a tile with the given tag. @@ -112,7 +110,7 @@ public interface WorldGenericContextRO< * @param tag the tag of the tile * @return {@code true} iff the tile exists */ - boolean isTagValid(Vec3i location, BlockFace face, int tag); + boolean isTagValid(Vec3i location, RelFace face, int tag); /** * Counts the amount of tiles in the specified tile stack. @@ -124,7 +122,7 @@ public interface WorldGenericContextRO< * @return the count of tiles in the tile stack or {@code -1} if the tile * stack could not exist */ - int getTileCount(Vec3i location, BlockFace face); + int getTileCount(Vec3i location, RelFace face); /** * Retrieves a listing of all entities. {@link #forEachEntity(Consumer)} @@ -143,52 +141,6 @@ public interface WorldGenericContextRO< */ E getEntity(long entityId); - /* - * Convenience methods - */ - - /** - * Iterates all entities safely - */ - default void forEachEntity(Consumer action) { - getEntities().forEach(action); - } - - /** - * Iterates all entities in cuboid safely - */ - default void forEachEntityIn(Vec3i min, Vec3i max, Consumer action) { - forEachEntity(e -> { - Vec3 pos = e.getPosition(); - if (pos.x < min.x || pos.y < min.y || pos.z < min.z || pos.x > max.x || pos.y > max.y || pos.z > max.z) { - action.accept(e); - } - }); - } - - /** - * Iterates all entities in cuboid safely - */ - default void forEachEntityIn(Vec3 min, Vec3 max, Consumer action) { - forEachEntity(e -> { - Vec3 pos = e.getPosition(); - if (pos.x < min.x || pos.y < min.y || pos.z < min.z || pos.x > max.x || pos.y > max.y || pos.z > max.z) { - action.accept(e); - } - }); - } - - /** - * Iterates all entities with ID safely - */ - default void forEachEntityWithId(String id, Consumer action) { - forEachEntity(e -> { - if (id.equals(e.getId())) { - action.accept(e); - } - }); - } - /* * Subcontexting */ diff --git a/src/main/java/ru/windcorp/progressia/common/world/generic/context/WorldGenericContextWO.java b/src/main/java/ru/windcorp/progressia/common/world/generic/context/WorldGenericContextWO.java index 3f27b17..d1dac01 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/generic/context/WorldGenericContextWO.java +++ b/src/main/java/ru/windcorp/progressia/common/world/generic/context/WorldGenericContextWO.java @@ -22,7 +22,6 @@ import ru.windcorp.progressia.common.state.StateChange; import ru.windcorp.progressia.common.state.StatefulObject; import ru.windcorp.progressia.common.world.context.Context; import ru.windcorp.progressia.common.world.generic.*; -import ru.windcorp.progressia.common.world.rels.BlockFace; import ru.windcorp.progressia.common.world.rels.RelFace; /** @@ -76,7 +75,7 @@ public interface WorldGenericContextWO< * @param face the face of the block to add the tile to * @param tile the tile to add */ - void addTile(Vec3i location, BlockFace face, T tile); + void addTile(Vec3i location, RelFace face, T tile); /** * Requests that a tile identified by its tag is removed from the specified @@ -88,7 +87,7 @@ public interface WorldGenericContextWO< * @param face the of the block to remove the tile from * @param tag the tag of the tile to remove */ - void removeTile(Vec3i location, BlockFace face, int tag); + void removeTile(Vec3i location, RelFace face, int tag); /** * Requests that the referenced tile is removed from its tile stack. If the diff --git a/src/main/java/ru/windcorp/progressia/common/world/tile/PacketAddTile.java b/src/main/java/ru/windcorp/progressia/common/world/tile/PacketAddTile.java index 1655446..a2f805e 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/tile/PacketAddTile.java +++ b/src/main/java/ru/windcorp/progressia/common/world/tile/PacketAddTile.java @@ -44,7 +44,7 @@ public class PacketAddTile extends PacketAffectTile { } public void set(TileData tile, Vec3i blockInWorld, AbsFace face) { - super.set(blockInWorld, face, -1); + super.set(blockInWorld, face, TAG_NOT_APPLICABLE); this.tileId = tile.getId(); } diff --git a/src/main/java/ru/windcorp/progressia/common/world/tile/PacketAffectTile.java b/src/main/java/ru/windcorp/progressia/common/world/tile/PacketAffectTile.java index 41cffef..747dfa6 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/tile/PacketAffectTile.java +++ b/src/main/java/ru/windcorp/progressia/common/world/tile/PacketAffectTile.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.common.world.tile; import java.io.DataInput; @@ -34,6 +34,12 @@ public abstract class PacketAffectTile extends PacketAffectChunk { private AbsFace face; private int tag; + /** + * Indicates to the safeguards in {@link #set(Vec3i, AbsFace, int)} that the + * concept of a tile tag is not applicable to this action. + */ + protected static final int TAG_NOT_APPLICABLE = -2; + public PacketAffectTile(String id) { super(id); } @@ -51,10 +57,10 @@ public abstract class PacketAffectTile extends PacketAffectChunk { } public void set(Vec3i blockInWorld, AbsFace face, int tag) { - if (tag < 0) { - throw new IllegalArgumentException("Cannot affect tile with tag -1"); + if (tag < 0 && tag != TAG_NOT_APPLICABLE) { + throw new IllegalArgumentException("Cannot affect tile with tag " + tag); } - + this.blockInWorld.set(blockInWorld.x, blockInWorld.y, blockInWorld.z); this.face = face; this.tag = tag; diff --git a/src/main/java/ru/windcorp/progressia/server/world/context/ServerBlockContext.java b/src/main/java/ru/windcorp/progressia/server/world/context/ServerBlockContext.java index 6b66ba0..e0b5c70 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/context/ServerBlockContext.java +++ b/src/main/java/ru/windcorp/progressia/server/world/context/ServerBlockContext.java @@ -19,8 +19,8 @@ package ru.windcorp.progressia.server.world.context; import glm.vec._3.i.Vec3i; import ru.windcorp.progressia.common.world.context.BlockDataContext; -import ru.windcorp.progressia.common.world.rels.AbsRelation; import ru.windcorp.progressia.common.world.rels.RelFace; +import ru.windcorp.progressia.common.world.rels.RelRelation; public interface ServerBlockContext extends BlockDataContext, ServerWorldContext, ServerBlockContextRO { @@ -40,8 +40,8 @@ public interface ServerBlockContext extends BlockDataContext, ServerWorldContext } @Override - default ServerBlockContext.Logic pushRelative(AbsRelation direction) { - return push(getLocation().add_(direction.getVector())); + default ServerBlockContext.Logic pushRelative(RelRelation direction) { + return push(getLocation().add_(direction.getRelVector())); } @Override @@ -70,8 +70,8 @@ public interface ServerBlockContext extends BlockDataContext, ServerWorldContext } @Override - default ServerBlockContext pushRelative(AbsRelation direction) { - return push(getLocation().add_(direction.getVector())); + default ServerBlockContext pushRelative(RelRelation direction) { + return push(getLocation().add_(direction.getRelVector())); } @Override diff --git a/src/main/java/ru/windcorp/progressia/server/world/context/ServerBlockContextRO.java b/src/main/java/ru/windcorp/progressia/server/world/context/ServerBlockContextRO.java index 8ef355e..1fdb90e 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/context/ServerBlockContextRO.java +++ b/src/main/java/ru/windcorp/progressia/server/world/context/ServerBlockContextRO.java @@ -21,8 +21,8 @@ import glm.vec._3.i.Vec3i; import ru.windcorp.progressia.common.world.context.BlockDataContextRO; import ru.windcorp.progressia.common.world.entity.EntityData; import ru.windcorp.progressia.common.world.generic.context.BlockGenericContextRO; -import ru.windcorp.progressia.common.world.rels.AbsRelation; import ru.windcorp.progressia.common.world.rels.RelFace; +import ru.windcorp.progressia.common.world.rels.RelRelation; import ru.windcorp.progressia.server.world.block.BlockLogic; import ru.windcorp.progressia.server.world.tile.TileLogic; @@ -45,8 +45,8 @@ public interface ServerBlockContextRO extends ServerWorldContextRO, BlockDataCon } @Override - default ServerBlockContextRO.Logic pushRelative(AbsRelation direction) { - return push(getLocation().add_(direction.getVector())); + default ServerBlockContextRO.Logic pushRelative(RelRelation direction) { + return push(getLocation().add_(direction.getRelVector())); } @Override @@ -75,8 +75,8 @@ public interface ServerBlockContextRO extends ServerWorldContextRO, BlockDataCon } @Override - default ServerBlockContextRO pushRelative(AbsRelation direction) { - return push(getLocation().add_(direction.getVector())); + default ServerBlockContextRO pushRelative(RelRelation direction) { + return push(getLocation().add_(direction.getRelVector())); } @Override diff --git a/src/main/java/ru/windcorp/progressia/server/world/context/impl/DefaultServerContextImpl.java b/src/main/java/ru/windcorp/progressia/server/world/context/impl/DefaultServerContextImpl.java index aeda6e8..7d4f6cf 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/context/impl/DefaultServerContextImpl.java +++ b/src/main/java/ru/windcorp/progressia/server/world/context/impl/DefaultServerContextImpl.java @@ -318,7 +318,7 @@ class DefaultServerContextImpl extends DefaultServerContext } @Override - public AbsFace toAbsolute(BlockFace contextFace) { + public AbsFace toAbsolute(RelFace contextFace) { return contextFace.resolve(AbsFace.POS_Z); } @@ -362,19 +362,19 @@ class DefaultServerContextImpl extends DefaultServerContext } @Override - public TileData getTile(Vec3i location, BlockFace face, int layer) { + public TileData getTile(Vec3i location, RelFace face, int layer) { assert requireContextRole(Role.WORLD); return world.getTile(location, face, layer); } @Override - public boolean hasTile(Vec3i location, BlockFace face, int layer) { + public boolean hasTile(Vec3i location, RelFace face, int layer) { assert requireContextRole(Role.WORLD); return world.hasTile(location, face, layer); } @Override - public TileData getTileByTag(Vec3i location, BlockFace face, int tag) { + public TileData getTileByTag(Vec3i location, RelFace face, int tag) { assert requireContextRole(Role.WORLD); TileDataStack stack = world.getTilesOrNull(location, face); if (stack == null) @@ -386,7 +386,7 @@ class DefaultServerContextImpl extends DefaultServerContext } @Override - public boolean isTagValid(Vec3i location, BlockFace face, int tag) { + public boolean isTagValid(Vec3i location, RelFace face, int tag) { assert requireContextRole(Role.WORLD); TileDataStack stack = world.getTilesOrNull(location, face); if (stack == null) @@ -404,7 +404,7 @@ class DefaultServerContextImpl extends DefaultServerContext } @Override - public int getTileCount(Vec3i location, BlockFace face) { + public int getTileCount(Vec3i location, RelFace face) { assert requireContextRole(Role.TILE_STACK); TileDataStack stack = world.getTilesOrNull(frame.location, frame.face); if (stack == null) @@ -453,13 +453,13 @@ class DefaultServerContextImpl extends DefaultServerContext } @Override - public void addTile(Vec3i location, BlockFace face, TileData tile) { + public void addTile(Vec3i location, RelFace face, TileData tile) { assert requireContextRole(Role.WORLD); world.getTiles(location, face).addFarthest(tile); } @Override - public void removeTile(Vec3i location, BlockFace face, int tag) { + public void removeTile(Vec3i location, RelFace face, int tag) { assert requireContextRole(Role.WORLD); TileDataStack stack = world.getTilesOrNull(location, face); if (stack == null) diff --git a/src/main/java/ru/windcorp/progressia/server/world/context/impl/DefaultServerContextLogic.java b/src/main/java/ru/windcorp/progressia/server/world/context/impl/DefaultServerContextLogic.java index 640a475..d6bb661 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/context/impl/DefaultServerContextLogic.java +++ b/src/main/java/ru/windcorp/progressia/server/world/context/impl/DefaultServerContextLogic.java @@ -24,7 +24,6 @@ import glm.vec._3.i.Vec3i; import ru.windcorp.progressia.common.world.block.BlockData; import ru.windcorp.progressia.common.world.entity.EntityData; import ru.windcorp.progressia.common.world.rels.AbsFace; -import ru.windcorp.progressia.common.world.rels.BlockFace; import ru.windcorp.progressia.common.world.rels.RelFace; import ru.windcorp.progressia.common.world.tile.TileData; import ru.windcorp.progressia.server.Server; @@ -97,7 +96,7 @@ public class DefaultServerContextLogic implements ServerTileContext.Logic { } @Override - public AbsFace toAbsolute(BlockFace contextFace) { + public AbsFace toAbsolute(RelFace contextFace) { return parent.toAbsolute(contextFace); } @@ -112,13 +111,13 @@ public class DefaultServerContextLogic implements ServerTileContext.Logic { } @Override - public TileLogic getTile(Vec3i location, BlockFace face, int layer) { + public TileLogic getTile(Vec3i location, RelFace face, int layer) { TileData data = parent.getTile(location, face, layer); return data == null ? null : TileLogicRegistry.getInstance().get(data.getId()); } @Override - public TileLogic getTileByTag(Vec3i location, BlockFace face, int tag) { + public TileLogic getTileByTag(Vec3i location, RelFace face, int tag) { TileData data = parent.getTileByTag(location, face, tag); return data == null ? null : TileLogicRegistry.getInstance().get(data.getId()); } @@ -129,12 +128,12 @@ public class DefaultServerContextLogic implements ServerTileContext.Logic { } @Override - public boolean hasTile(Vec3i location, BlockFace face, int layer) { + public boolean hasTile(Vec3i location, RelFace face, int layer) { return parent.hasTile(location, face, layer); } @Override - public boolean isTagValid(Vec3i location, BlockFace face, int tag) { + public boolean isTagValid(Vec3i location, RelFace face, int tag) { return parent.isTagValid(location, face, tag); } @@ -144,7 +143,7 @@ public class DefaultServerContextLogic implements ServerTileContext.Logic { } @Override - public int getTileCount(Vec3i location, BlockFace face) { + public int getTileCount(Vec3i location, RelFace face) { return parent.getTileCount(location, face); } diff --git a/src/main/java/ru/windcorp/progressia/server/world/context/impl/FilterServerContext.java b/src/main/java/ru/windcorp/progressia/server/world/context/impl/FilterServerContext.java index 677f9d3..80c5073 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/context/impl/FilterServerContext.java +++ b/src/main/java/ru/windcorp/progressia/server/world/context/impl/FilterServerContext.java @@ -28,7 +28,6 @@ import ru.windcorp.progressia.common.world.block.BlockData; import ru.windcorp.progressia.common.world.entity.EntityData; import ru.windcorp.progressia.common.world.generic.EntityGeneric; import ru.windcorp.progressia.common.world.rels.AbsFace; -import ru.windcorp.progressia.common.world.rels.BlockFace; import ru.windcorp.progressia.common.world.rels.RelFace; import ru.windcorp.progressia.common.world.tile.TileData; import ru.windcorp.progressia.server.Server; @@ -99,12 +98,12 @@ public abstract class FilterServerContext implements ServerTileContext { } @Override - public void addTile(Vec3i location, BlockFace face, TileData tile) { + public void addTile(Vec3i location, RelFace face, TileData tile) { parent.addTile(location, face, tile); } @Override - public void removeTile(Vec3i location, BlockFace face, int tag) { + public void removeTile(Vec3i location, RelFace face, int tag) { parent.removeTile(location, face, tag); } @@ -149,27 +148,27 @@ public abstract class FilterServerContext implements ServerTileContext { } @Override - public TileData getTile(Vec3i location, BlockFace face, int layer) { + public TileData getTile(Vec3i location, RelFace face, int layer) { return parent.getTile(location, face, layer); } @Override - public TileData getTileByTag(Vec3i location, BlockFace face, int tag) { + public TileData getTileByTag(Vec3i location, RelFace face, int tag) { return parent.getTileByTag(location, face, tag); } @Override - public boolean hasTile(Vec3i location, BlockFace face, int layer) { + public boolean hasTile(Vec3i location, RelFace face, int layer) { return parent.hasTile(location, face, layer); } @Override - public boolean isTagValid(Vec3i location, BlockFace face, int tag) { + public boolean isTagValid(Vec3i location, RelFace face, int tag) { return parent.isTagValid(location, face, tag); } @Override - public int getTileCount(Vec3i location, BlockFace face) { + public int getTileCount(Vec3i location, RelFace face) { return parent.getTileCount(location, face); } @@ -212,7 +211,7 @@ public abstract class FilterServerContext implements ServerTileContext { } @Override - public AbsFace toAbsolute(BlockFace contextFace) { + public AbsFace toAbsolute(RelFace contextFace) { return parent.toAbsolute(contextFace); } diff --git a/src/main/java/ru/windcorp/progressia/server/world/context/impl/ReportingServerContext.java b/src/main/java/ru/windcorp/progressia/server/world/context/impl/ReportingServerContext.java index 302a47f..732b2a0 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/context/impl/ReportingServerContext.java +++ b/src/main/java/ru/windcorp/progressia/server/world/context/impl/ReportingServerContext.java @@ -24,6 +24,7 @@ import ru.windcorp.progressia.common.world.block.BlockData; import ru.windcorp.progressia.common.world.entity.EntityData; import ru.windcorp.progressia.common.world.generic.EntityGeneric; import ru.windcorp.progressia.common.world.rels.BlockFace; +import ru.windcorp.progressia.common.world.rels.RelFace; import ru.windcorp.progressia.common.world.tile.TileData; import ru.windcorp.progressia.server.world.context.ServerTileContext; @@ -83,7 +84,7 @@ public class ReportingServerContext extends FilterServerContext { } @Override - public void addTile(Vec3i location, BlockFace face, TileData tile) { + public void addTile(Vec3i location, RelFace face, TileData tile) { if (passToParent) { super.addTile(location, face, tile); } @@ -93,7 +94,7 @@ public class ReportingServerContext extends FilterServerContext { } @Override - public void removeTile(Vec3i location, BlockFace face, int tag) { + public void removeTile(Vec3i location, RelFace face, int tag) { if (passToParent) { super.removeTile(location, face, tag); } diff --git a/src/main/java/ru/windcorp/progressia/server/world/context/impl/TransformingServerContext.java b/src/main/java/ru/windcorp/progressia/server/world/context/impl/TransformingServerContext.java index 1fb387e..9c0be6c 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/context/impl/TransformingServerContext.java +++ b/src/main/java/ru/windcorp/progressia/server/world/context/impl/TransformingServerContext.java @@ -23,7 +23,6 @@ import java.util.List; import glm.vec._3.i.Vec3i; import ru.windcorp.progressia.common.world.block.BlockData; import ru.windcorp.progressia.common.world.rels.AbsFace; -import ru.windcorp.progressia.common.world.rels.BlockFace; import ru.windcorp.progressia.common.world.rels.RelFace; import ru.windcorp.progressia.common.world.tile.TileData; import ru.windcorp.progressia.server.world.context.ServerBlockContext; @@ -163,8 +162,8 @@ public abstract class TransformingServerContext extends FilterServerContext { } @Override - public AbsFace toAbsolute(BlockFace contextFace) { - return super.toAbsolute(transform(contextFace.relativize(AbsFace.POS_Z))); + public AbsFace toAbsolute(RelFace contextFace) { + return super.toAbsolute(transform(contextFace)); } @Override @@ -206,77 +205,77 @@ public abstract class TransformingServerContext extends FilterServerContext { } @Override - public boolean hasTile(Vec3i userLocation, BlockFace userFace, int layer) { + public boolean hasTile(Vec3i userLocation, RelFace userFace, int layer) { Vec3i parentLocation = grabVector(userLocation); try { - return super.hasTile(parentLocation, transform(userFace.relativize(AbsFace.POS_Z)), layer); + return super.hasTile(parentLocation, transform(userFace), layer); } finally { releaseVector(parentLocation); } } @Override - public TileData getTile(Vec3i userLocation, BlockFace userFace, int layer) { + public TileData getTile(Vec3i userLocation, RelFace userFace, int layer) { Vec3i parentLocation = grabVector(userLocation); try { - return super.getTile(parentLocation, transform(userFace.relativize(AbsFace.POS_Z)), layer); + return super.getTile(parentLocation, transform(userFace), layer); } finally { releaseVector(parentLocation); } } @Override - public boolean isTagValid(Vec3i userLocation, BlockFace userFace, int tag) { + public boolean isTagValid(Vec3i userLocation, RelFace userFace, int tag) { Vec3i parentLocation = grabVector(userLocation); try { - return super.isTagValid(parentLocation, transform(userFace.relativize(AbsFace.POS_Z)), tag); + return super.isTagValid(parentLocation, transform(userFace), tag); } finally { releaseVector(parentLocation); } } @Override - public TileData getTileByTag(Vec3i userLocation, BlockFace userFace, int tag) { + public TileData getTileByTag(Vec3i userLocation, RelFace userFace, int tag) { Vec3i parentLocation = grabVector(userLocation); try { - return super.getTileByTag(parentLocation, transform(userFace.relativize(AbsFace.POS_Z)), tag); + return super.getTileByTag(parentLocation, transform(userFace), tag); } finally { releaseVector(parentLocation); } } @Override - public int getTileCount(Vec3i userLocation, BlockFace userFace) { + public int getTileCount(Vec3i userLocation, RelFace userFace) { Vec3i parentLocation = grabVector(userLocation); try { - return super.getTileCount(parentLocation, transform(userFace.relativize(AbsFace.POS_Z))); + return super.getTileCount(parentLocation, transform(userFace)); } finally { releaseVector(parentLocation); } } @Override - public void addTile(Vec3i userLocation, BlockFace userFace, TileData tile) { + public void addTile(Vec3i userLocation, RelFace userFace, TileData tile) { Vec3i parentLocation = grabVector(userLocation); try { - super.addTile(parentLocation, transform(userFace.relativize(AbsFace.POS_Z)), tile); + super.addTile(parentLocation, transform(userFace), tile); } finally { releaseVector(parentLocation); } } @Override - public void removeTile(Vec3i userLocation, BlockFace userFace, int tag) { + public void removeTile(Vec3i userLocation, RelFace userFace, int tag) { Vec3i parentLocation = grabVector(userLocation); try { - super.removeTile(parentLocation, transform(userFace.relativize(AbsFace.POS_Z)), tag); + super.removeTile(parentLocation, transform(userFace), tag); } finally { releaseVector(parentLocation); } diff --git a/src/main/java/ru/windcorp/progressia/test/TestContent.java b/src/main/java/ru/windcorp/progressia/test/TestContent.java index 7b9122f..fe972a4 100644 --- a/src/main/java/ru/windcorp/progressia/test/TestContent.java +++ b/src/main/java/ru/windcorp/progressia/test/TestContent.java @@ -428,7 +428,7 @@ public class TestContent { return; if (server.getWorld().getData().getTiles(blockInWorld, face).isFull()) return; - server.createAbsoluteContext().addTile(blockInWorld, face, tile); + server.createAbsoluteContext().addTile(blockInWorld, face.relativize(AbsFace.POS_Z), tile); } private static void registerMisc() { diff --git a/src/main/java/ru/windcorp/progressia/test/TestTileLogicGrass.java b/src/main/java/ru/windcorp/progressia/test/TestTileLogicGrass.java index c197ce1..8a42bee 100644 --- a/src/main/java/ru/windcorp/progressia/test/TestTileLogicGrass.java +++ b/src/main/java/ru/windcorp/progressia/test/TestTileLogicGrass.java @@ -18,7 +18,6 @@ package ru.windcorp.progressia.test; -import ru.windcorp.progressia.common.world.rels.AbsFace; import ru.windcorp.progressia.common.world.rels.RelFace; import ru.windcorp.progressia.server.world.block.BlockLogic; import ru.windcorp.progressia.server.world.context.ServerTileContext; @@ -65,8 +64,7 @@ public class TestTileLogicGrass extends HangingTileLogic implements TickableTile } private boolean isBlockAboveTransparent(ServerTileContextRO context) { - // TODO rework - context.pushRelative(RelFace.UP.resolve(AbsFace.POS_Z)); + context.pushRelative(RelFace.UP); BlockLogic block = context.logic().getBlock(); return context.popAndReturn(block == null || block.isTransparent(context)); } From d33b48578d7f41cee5e3e62769ce1f49f67ccc62 Mon Sep 17 00:00:00 2001 From: OLEGSHA Date: Tue, 17 Aug 2021 16:05:44 +0300 Subject: [PATCH 47/55] 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); + +} From a3760d742561ecffeae67e2e4a4a8c51e57455d0 Mon Sep 17 00:00:00 2001 From: OLEGSHA Date: Tue, 17 Aug 2021 19:21:57 +0300 Subject: [PATCH 48/55] Removed erroneous RelFace resolution by WorldAccessor --- .../context/impl/DefaultServerContextImpl.java | 16 ++++++++-------- .../context/impl/ReportingServerContext.java | 5 ++--- .../server/world/tasks/WorldAccessor.java | 12 +++++++----- 3 files changed, 17 insertions(+), 16 deletions(-) diff --git a/src/main/java/ru/windcorp/progressia/server/world/context/impl/DefaultServerContextImpl.java b/src/main/java/ru/windcorp/progressia/server/world/context/impl/DefaultServerContextImpl.java index 7d4f6cf..b4dfedc 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/context/impl/DefaultServerContextImpl.java +++ b/src/main/java/ru/windcorp/progressia/server/world/context/impl/DefaultServerContextImpl.java @@ -364,19 +364,19 @@ class DefaultServerContextImpl extends DefaultServerContext @Override public TileData getTile(Vec3i location, RelFace face, int layer) { assert requireContextRole(Role.WORLD); - return world.getTile(location, face, layer); + return world.getTile(location, face.resolve(AbsFace.POS_Z), layer); } @Override public boolean hasTile(Vec3i location, RelFace face, int layer) { assert requireContextRole(Role.WORLD); - return world.hasTile(location, face, layer); + return world.hasTile(location, face.resolve(AbsFace.POS_Z), layer); } @Override public TileData getTileByTag(Vec3i location, RelFace face, int tag) { assert requireContextRole(Role.WORLD); - TileDataStack stack = world.getTilesOrNull(location, face); + TileDataStack stack = world.getTilesOrNull(location, face.resolve(AbsFace.POS_Z)); if (stack == null) return null; int layer = stack.getIndexByTag(tag); @@ -388,7 +388,7 @@ class DefaultServerContextImpl extends DefaultServerContext @Override public boolean isTagValid(Vec3i location, RelFace face, int tag) { assert requireContextRole(Role.WORLD); - TileDataStack stack = world.getTilesOrNull(location, face); + TileDataStack stack = world.getTilesOrNull(location, face.resolve(AbsFace.POS_Z)); if (stack == null) return false; return stack.getIndexByTag(tag) != -1; @@ -397,7 +397,7 @@ class DefaultServerContextImpl extends DefaultServerContext @Override public int getTag() { assert requireContextRole(Role.TILE); - TileDataStack stack = world.getTilesOrNull(frame.location, frame.face); + TileDataStack stack = world.getTilesOrNull(frame.location, frame.face.resolve(AbsFace.POS_Z)); if (stack == null) return -1; return stack.getTagByIndex(frame.layer); @@ -406,7 +406,7 @@ class DefaultServerContextImpl extends DefaultServerContext @Override public int getTileCount(Vec3i location, RelFace face) { assert requireContextRole(Role.TILE_STACK); - TileDataStack stack = world.getTilesOrNull(frame.location, frame.face); + TileDataStack stack = world.getTilesOrNull(location, face.resolve(AbsFace.POS_Z)); if (stack == null) return 0; return stack.size(); @@ -455,13 +455,13 @@ class DefaultServerContextImpl extends DefaultServerContext @Override public void addTile(Vec3i location, RelFace face, TileData tile) { assert requireContextRole(Role.WORLD); - world.getTiles(location, face).addFarthest(tile); + world.getTiles(location, face.resolve(AbsFace.POS_Z)).addFarthest(tile); } @Override public void removeTile(Vec3i location, RelFace face, int tag) { assert requireContextRole(Role.WORLD); - TileDataStack stack = world.getTilesOrNull(location, face); + TileDataStack stack = world.getTilesOrNull(location, face.resolve(AbsFace.POS_Z)); if (stack == null) return; int layer = stack.getIndexByTag(tag); diff --git a/src/main/java/ru/windcorp/progressia/server/world/context/impl/ReportingServerContext.java b/src/main/java/ru/windcorp/progressia/server/world/context/impl/ReportingServerContext.java index 732b2a0..57ff66c 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/context/impl/ReportingServerContext.java +++ b/src/main/java/ru/windcorp/progressia/server/world/context/impl/ReportingServerContext.java @@ -23,7 +23,6 @@ import ru.windcorp.progressia.common.state.StatefulObject; import ru.windcorp.progressia.common.world.block.BlockData; import ru.windcorp.progressia.common.world.entity.EntityData; import ru.windcorp.progressia.common.world.generic.EntityGeneric; -import ru.windcorp.progressia.common.world.rels.BlockFace; import ru.windcorp.progressia.common.world.rels.RelFace; import ru.windcorp.progressia.common.world.tile.TileData; import ru.windcorp.progressia.server.world.context.ServerTileContext; @@ -34,9 +33,9 @@ public class ReportingServerContext extends FilterServerContext { void onBlockSet(Vec3i location, BlockData block); - void onTileAdded(Vec3i location, BlockFace face, TileData tile); + void onTileAdded(Vec3i location, RelFace face, TileData tile); - void onTileRemoved(Vec3i location, BlockFace face, int tag); + void onTileRemoved(Vec3i location, RelFace face, int tag); void onEntityAdded(EntityData entity); diff --git a/src/main/java/ru/windcorp/progressia/server/world/tasks/WorldAccessor.java b/src/main/java/ru/windcorp/progressia/server/world/tasks/WorldAccessor.java index cb95063..76ab835 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/tasks/WorldAccessor.java +++ b/src/main/java/ru/windcorp/progressia/server/world/tasks/WorldAccessor.java @@ -27,7 +27,9 @@ import ru.windcorp.progressia.common.util.MultiLOC; import ru.windcorp.progressia.common.world.block.BlockData; import ru.windcorp.progressia.common.world.entity.EntityData; import ru.windcorp.progressia.common.world.generic.EntityGeneric; +import ru.windcorp.progressia.common.world.rels.AbsFace; import ru.windcorp.progressia.common.world.rels.BlockFace; +import ru.windcorp.progressia.common.world.rels.RelFace; import ru.windcorp.progressia.common.world.tile.TileData; import ru.windcorp.progressia.server.Server; import ru.windcorp.progressia.server.world.context.impl.ReportingServerContext; @@ -64,16 +66,16 @@ public class WorldAccessor implements ReportingServerContext.ChangeListener { } @Override - public void onTileAdded(Vec3i blockInWorld, BlockFace face, TileData tile) { + public void onTileAdded(Vec3i blockInWorld, RelFace face, TileData tile) { AddTile change = cache.grab(AddTile.class); - change.getPacket().set(tile, blockInWorld, face.resolve(server.getWorld().getUp(blockInWorld))); + change.getPacket().set(tile, blockInWorld, face.resolve(AbsFace.POS_Z)); server.requestChange(change); } @Override - public void onTileRemoved(Vec3i blockInWorld, BlockFace face, int tag) { + public void onTileRemoved(Vec3i blockInWorld, RelFace face, int tag) { RemoveTile change = cache.grab(RemoveTile.class); - change.getPacket().set(blockInWorld, face.resolve(server.getWorld().getUp(blockInWorld)), tag); + change.getPacket().set(blockInWorld, face.resolve(AbsFace.POS_Z), tag); server.requestChange(change); } @@ -131,7 +133,7 @@ public class WorldAccessor implements ReportingServerContext.ChangeListener { // TODO rename to something meaningful public void triggerUpdates(Vec3i blockInWorld, BlockFace face) { TileTriggeredUpdate evaluation = cache.grab(TileTriggeredUpdate.class); - evaluation.init(blockInWorld, face.resolve(server.getWorld().getUp(blockInWorld))); + evaluation.init(blockInWorld, face.resolve(AbsFace.POS_Z)); server.requestEvaluation(evaluation); } From 539a61e85475d798a585af6fe89e24e38f1ef11a Mon Sep 17 00:00:00 2001 From: OLEGSHA Date: Wed, 18 Aug 2021 00:26:45 +0300 Subject: [PATCH 49/55] Almost resolved feature generation issue, removed dead code - SurfaceFeatures that change neighboring chunks no longer suffer from tearing if world saving is enabled - World saving is still disabled by default - wontfix until we get a new, more optimized world IO system - See GitHub issue #13 for details - Removed WorldAccessor getter from Server. This is an implementation detail. - Removed SurfaceWorld, SurfaceFeature.Request (see previous commit) --- .../ru/windcorp/progressia/server/Server.java | 7 +- .../server/world/DefaultWorldLogic.java | 5 +- .../test/gen/planet/TestPlanetGenerator.java | 5 +- .../test/gen/surface/SurfaceFeature.java | 79 ------- .../test/gen/surface/SurfaceWorld.java | 205 ------------------ 5 files changed, 6 insertions(+), 295 deletions(-) delete mode 100644 src/main/java/ru/windcorp/progressia/test/gen/surface/SurfaceWorld.java diff --git a/src/main/java/ru/windcorp/progressia/server/Server.java b/src/main/java/ru/windcorp/progressia/server/Server.java index 132b5bf..2ad6171 100644 --- a/src/main/java/ru/windcorp/progressia/server/Server.java +++ b/src/main/java/ru/windcorp/progressia/server/Server.java @@ -82,7 +82,8 @@ public class Server { this.world = new DefaultWorldLogic( world, this, - new TestPlanetGenerator("Test:PlanetGenerator", this, new Planet(4, 9.8f, 16f, 16f)) + new TestPlanetGenerator("Test:PlanetGenerator", this, new Planet(4, 9.8f, 16f, 16f)), + worldAccessor ); this.serverThread = new ServerThread(this); @@ -308,10 +309,6 @@ public class Server { public long getUptimeTicks() { return this.serverThread.getTicker().getUptimeTicks(); } - - public WorldAccessor getWorldAccessor___really_bad_dont_use() { - return worldAccessor; - } /** * Returns the ticking settings for this server. diff --git a/src/main/java/ru/windcorp/progressia/server/world/DefaultWorldLogic.java b/src/main/java/ru/windcorp/progressia/server/world/DefaultWorldLogic.java index f2b1883..3e654b6 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/DefaultWorldLogic.java +++ b/src/main/java/ru/windcorp/progressia/server/world/DefaultWorldLogic.java @@ -33,6 +33,7 @@ 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.tasks.TickEntitiesTask; +import ru.windcorp.progressia.server.world.tasks.WorldAccessor; import ru.windcorp.progressia.server.world.ticking.Evaluation; public class DefaultWorldLogic implements WorldLogic { @@ -46,7 +47,7 @@ public class DefaultWorldLogic implements WorldLogic { private final Evaluation tickEntitiesTask = new TickEntitiesTask(); - public DefaultWorldLogic(DefaultWorldData data, Server server, WorldGenerator generator) { + public DefaultWorldLogic(DefaultWorldData data, Server server, WorldGenerator generator, WorldAccessor accessor) { this.data = data; this.server = server; @@ -65,7 +66,7 @@ public class DefaultWorldLogic implements WorldLogic { } }); - data.addListener(ChunkDataListeners.createAdder(new UpdateTriggerer(server.getWorldAccessor___really_bad_dont_use()))); + data.addListener(ChunkDataListeners.createAdder(new UpdateTriggerer(accessor))); } @Override 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 f531282..0846be7 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 @@ -88,11 +88,8 @@ public class TestPlanetGenerator extends AbstractWorldGenerator { } private void conjureTerrain(Vec3i chunkPos) { + getServer().getLoadManager().getChunkManager().loadChunk(chunkPos); DefaultChunkData chunk = getWorldData().getChunk(chunkPos); - - if (chunk == null) { - chunk = getWorldData().getChunk(chunkPos); - } if (chunk == null) { chunk = terrainGenerator.generateTerrain(chunkPos); 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 7bd1cc4..e4bb250 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 @@ -17,90 +17,11 @@ */ package ru.windcorp.progressia.test.gen.surface; -import java.util.Random; - -import glm.Glm; -import glm.vec._3.i.Vec3i; 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 { - public static class Request { - - private final SurfaceWorld world; - private final DefaultChunkData chunk; - private final Vec3i minSfc = new Vec3i(); - private final Vec3i maxSfc = new Vec3i(); - - private final Random random; - - public Request(SurfaceWorld world, DefaultChunkData chunk, Random random) { - this.world = world; - this.chunk = chunk; - this.random = random; - - Vec3i tmpMin = chunk.getMinBIW(null); - Vec3i tmpMax = chunk.getMaxBIW(null); - - GenericChunks.relativize(tmpMin, chunk.getUp(), tmpMin); - GenericChunks.relativize(tmpMax, chunk.getUp(), tmpMax); - - Glm.min(tmpMin, tmpMax, minSfc); - Glm.max(tmpMin, tmpMax, maxSfc); - - minSfc.z -= world.getSurface().getSeaLevel(); - maxSfc.z -= world.getSurface().getSeaLevel(); - } - - public DefaultChunkData getChunk() { - return chunk; - } - - public SurfaceWorld getWorld() { - return world; - } - - public Random getRandom() { - return random; - } - - public int getMinX() { - return minSfc.x; - } - - public int getMaxX() { - return maxSfc.x; - } - - public int getMinY() { - return minSfc.y; - } - - public int getMaxY() { - return maxSfc.y; - } - - public int getMinZ() { - return minSfc.z; - } - - public int getMaxZ() { - return maxSfc.z; - } - - public Vec3i getMin() { - return minSfc; - } - - public Vec3i getMax() { - return maxSfc; - } - - } - public SurfaceFeature(String id) { super(id); } diff --git a/src/main/java/ru/windcorp/progressia/test/gen/surface/SurfaceWorld.java b/src/main/java/ru/windcorp/progressia/test/gen/surface/SurfaceWorld.java deleted file mode 100644 index 43a218e..0000000 --- a/src/main/java/ru/windcorp/progressia/test/gen/surface/SurfaceWorld.java +++ /dev/null @@ -1,205 +0,0 @@ -/* - * 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.util.Collection; - -import glm.vec._3.i.Vec3i; -import ru.windcorp.progressia.common.state.StateChange; -import ru.windcorp.progressia.common.state.StatefulObject; -import ru.windcorp.progressia.common.util.Vectors; -import ru.windcorp.progressia.common.world.ChunkData; -import ru.windcorp.progressia.common.world.GravityModel; -import ru.windcorp.progressia.common.world.block.BlockData; -import ru.windcorp.progressia.common.world.entity.EntityData; -import ru.windcorp.progressia.common.world.generic.EntityGeneric; -import ru.windcorp.progressia.common.world.generic.GenericChunks; -import ru.windcorp.progressia.common.world.rels.BlockFace; -import ru.windcorp.progressia.common.world.tile.TileData; -import ru.windcorp.progressia.common.world.TileDataStack; -import ru.windcorp.progressia.common.world.WorldData; - -public class SurfaceWorld - implements WorldData { - - private final Surface surface; - private final WorldData parent; - - public SurfaceWorld( - Surface surface, - WorldData parent - ) { - this.surface = surface; - this.parent = parent; - } - - /** - * @return the surface - */ - public Surface getSurface() { - return surface; - } - - /** - * @return the parent - */ - public WorldData getParent() { - return parent; - } - - /* - * Delegate methods - */ - - @Override - public Collection getChunks() { - return parent.getChunks(); - } - - @Override - public ChunkData getChunk(Vec3i pos) { - return parent.getChunk(pos); - } - - @Override - public Collection getEntities() { - return parent.getEntities(); - } - - @Override - public EntityData getEntity(long entityId) { - return parent.getEntity(entityId); - } - - @Override - public void setBlock(Vec3i blockInWorld, BlockData block, boolean notify) { - parent.setBlock(blockInWorld, block, notify); - } - - @Override - public void addEntity(EntityData entity) { - parent.addEntity(entity); - } - - @Override - public void removeEntity(long entityId) { - parent.removeEntity(entityId); - } - - public Vec3i resolve(Vec3i surfacePosition, Vec3i output) { - if (output == null) { - output = new Vec3i(); - } - - output.set(surfacePosition.x, surfacePosition.y, surfacePosition.z); - output.z += getSurface().getSeaLevel(); - - GenericChunks.resolve(output, getSurface().getUp(), output); - - return output; - } - - public Vec3i relativize(Vec3i absolutePosition, Vec3i output) { - if (output == null) { - output = new Vec3i(); - } - - output.set(absolutePosition.x, absolutePosition.y, absolutePosition.z); - - GenericChunks.relativize(output, getSurface().getUp(), output); - output.z -= getSurface().getSeaLevel(); - - return output; - } - - public BlockData getBlockSfc(Vec3i surfaceBlockInWorld) { - Vec3i blockInWorld = Vectors.grab3i(); - resolve(surfaceBlockInWorld, blockInWorld); - BlockData result = parent.getBlock(blockInWorld); - Vectors.release(blockInWorld); - return result; - } - - public void setBlockSfc(Vec3i surfaceBlockInWorld, BlockData block, boolean notify) { - Vec3i blockInWorld = Vectors.grab3i(); - resolve(surfaceBlockInWorld, blockInWorld); - parent.setBlock(blockInWorld, block, notify); - Vectors.release(blockInWorld); - } - - public TileDataStack getTilesSfc(Vec3i surfaceBlockInWorld, BlockFace face) { - Vec3i blockInWorld = Vectors.grab3i(); - resolve(surfaceBlockInWorld, blockInWorld); - TileDataStack result = parent.getTiles(blockInWorld, face); - Vectors.release(blockInWorld); - return result; - } - - public TileDataStack getTilesOrNullSfc(Vec3i surfaceBlockInWorld, BlockFace face) { - Vec3i blockInWorld = Vectors.grab3i(); - resolve(surfaceBlockInWorld, blockInWorld); - TileDataStack result = parent.getTilesOrNull(blockInWorld, face); - Vectors.release(blockInWorld); - return result; - } - - public boolean hasTilesSfc(Vec3i surfaceBlockInWorld, BlockFace face) { - Vec3i blockInWorld = Vectors.grab3i(); - resolve(surfaceBlockInWorld, blockInWorld); - boolean result = parent.hasTiles(blockInWorld, face); - Vectors.release(blockInWorld); - return result; - } - - public TileData getTileSfc(Vec3i surfaceBlockInWorld, BlockFace face, int layer) { - Vec3i blockInWorld = Vectors.grab3i(); - resolve(surfaceBlockInWorld, blockInWorld); - TileData result = parent.getTile(blockInWorld, face, layer); - Vectors.release(blockInWorld); - return result; - } - - public boolean isBlockLoadedSfc(Vec3i surfaceBlockInWorld) { - Vec3i blockInWorld = Vectors.grab3i(); - resolve(surfaceBlockInWorld, blockInWorld); - boolean result = parent.isLocationLoaded(blockInWorld); - Vectors.release(blockInWorld); - return result; - } - - @Override - public float getTime() { - return parent.getTime(); - } - - @Override - public GravityModel getGravityModel() { - return parent.getGravityModel(); - } - - @Override - public void changeEntity(SE entity, StateChange change) { - parent.changeEntity(entity, change); - } - - @Override - public void advanceTime(float change) { - parent.advanceTime(change); - } - -} From ca2014802a9925917355b6448e8881293fbb0f80 Mon Sep 17 00:00:00 2001 From: OLEGSHA Date: Wed, 18 Aug 2021 09:30:29 +0300 Subject: [PATCH 50/55] Resolved a random deadlock that became way too frequent to ignore There was a deadlock that sometimes occurred when passing PacketSetBlock to client: PacketSetBlock first acquired monitor of the chunk it modified, than attempted to lock the visible chunks set. In parallel, a chunk update first acquires the visible chunks, than the individual chunk. Turns out, markForUpdate() doesn't need to be synchronized, so PacketSetBlock can now acquire the locks sequentially, avoiding the deadlock. --- .../java/ru/windcorp/progressia/client/world/ChunkRender.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/ru/windcorp/progressia/client/world/ChunkRender.java b/src/main/java/ru/windcorp/progressia/client/world/ChunkRender.java index e96166d..41aa933 100644 --- a/src/main/java/ru/windcorp/progressia/client/world/ChunkRender.java +++ b/src/main/java/ru/windcorp/progressia/client/world/ChunkRender.java @@ -97,7 +97,7 @@ public class ChunkRender return data; } - public synchronized void markForUpdate() { + public void markForUpdate() { getWorld().markChunkForUpdate(getPosition()); } From 15b5d367b4f87c2774c8c9047c1492950795ad35 Mon Sep 17 00:00:00 2001 From: OLEGSHA Date: Wed, 18 Aug 2021 10:58:18 +0300 Subject: [PATCH 51/55] Chunk loading region around the player is now compressed vertically --- .../ru/windcorp/progressia/server/Player.java | 34 ++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) diff --git a/src/main/java/ru/windcorp/progressia/server/Player.java b/src/main/java/ru/windcorp/progressia/server/Player.java index 008c000..e0a9db7 100644 --- a/src/main/java/ru/windcorp/progressia/server/Player.java +++ b/src/main/java/ru/windcorp/progressia/server/Player.java @@ -20,8 +20,12 @@ package ru.windcorp.progressia.server; import java.util.function.Consumer; +import glm.mat._3.Mat3; +import glm.vec._3.Vec3; import glm.vec._3.i.Vec3i; import ru.windcorp.progressia.common.Units; +import ru.windcorp.progressia.common.util.Matrices; +import ru.windcorp.progressia.common.util.Vectors; import ru.windcorp.progressia.common.world.DefaultChunkData; import ru.windcorp.progressia.common.world.Coordinates; import ru.windcorp.progressia.common.world.PlayerData; @@ -60,10 +64,35 @@ public class Player extends PlayerData implements ChunkLoader { float radiusSq = radius * radius; int iRadius = (int) Math.ceil(radius); + // The sphere around the player is stretched by this factor vertically + // (along the player's up vector) + final float verticalStretching = 0.4f; + + float factor = (1/verticalStretching - 1); + Vec3 up = getServer().getWorld().getData().getGravityModel().getUp(getEntity().getPosition(), null); + + Mat3 transform = Matrices.grab3(); + + //@formatter:off + transform.set( + 1 + factor * up.x * up.x, 0 + factor * up.x * up.y, 0 + factor * up.x * up.z, + 0 + factor * up.y * up.x, 1 + factor * up.y * up.y, 0 + factor * up.y * up.z, + 0 + factor * up.z * up.x, 0 + factor * up.z * up.y, 1 + factor * up.z * up.z + ); + //@formatter:on + + Vec3 transformedCursor = Vectors.grab3(); + for (cursor.x = -iRadius; cursor.x <= +iRadius; ++cursor.x) { for (cursor.y = -iRadius; cursor.y <= +iRadius; ++cursor.y) { for (cursor.z = -iRadius; cursor.z <= +iRadius; ++cursor.z) { - if (cursor.x * cursor.x + cursor.y * cursor.y + (cursor.z/* * 2*/) * (cursor.z/* * 2*/) <= radiusSq) { + + transformedCursor.set(cursor.x, cursor.y, cursor.z); + + // .mul(Vec3) is cursed + transform.mul(transformedCursor, transformedCursor); + + if (transformedCursor.dot(transformedCursor) <= radiusSq) { cursor.add(start); chunkConsumer.accept(cursor); @@ -73,6 +102,9 @@ public class Player extends PlayerData implements ChunkLoader { } } } + + Matrices.release(transform); + Vectors.release(transformedCursor); } public String getLogin() { From 2328f2ae3a557df88daf52f88582a04cca3b481e Mon Sep 17 00:00:00 2001 From: OLEGSHA Date: Fri, 20 Aug 2021 18:07:41 +0300 Subject: [PATCH 52/55] Replaced placeholder worldgen with a passable one - Removed old (pre-planet) worldgen - TestGravityModel remains - Moved surface generator to .logic.world.generation.surface - Split planet generator into generator logic and config - Logic moved to .logic.world.generation.planet - Config extracted into TestGenerationConfig & others in .test.gen - GravityModel renamed to Test:PlanetGravityModel - TestTerrainGenerator utilities moved and made public thru Fields - Reconfigured planet generator to be a passable - Increased planet size to R=0.5 km - Added noise-based heightmaps (fabulous cliffs included) - Added noise-based forest density map - Reworked all SurfaceFeatures - TestGrassFeature now also places scatter and flowers - TestTreeFeature and TestBushFeature: - Common code exctracted to MultiblockVegetationFeature - Made prettier - gud muscle flex yeeeeeeeeeeee - Fixed a bug in the gravity model - A lot of other changes that I already forgot about --- .../ru/windcorp/progressia/server/Server.java | 8 +- .../progressia/server/ServerState.java | 3 +- .../context/impl/RotatingServerContext.java | 6 +- .../world/generation}/planet/Planet.java | 8 +- .../planet/PlanetFeatureGenerator.java | 25 +- .../generation/planet/PlanetGenerator.java} | 46 +- .../planet/PlanetGravityModel.java} | 15 +- .../planet/PlanetTerrainGenerator.java | 48 +-- .../world/generation}/surface/Surface.java | 2 +- .../generation}/surface/SurfaceFeature.java | 19 +- .../surface/SurfaceFeatureGenerator.java | 10 +- .../surface/SurfaceFloatField.java | 11 +- .../surface/SurfaceTerrainGenerator.java | 7 +- .../surface/SurfaceTopLayerFeature.java | 6 +- .../generation/surface}/TerrainLayer.java | 6 +- .../surface/context/SurfaceBlockContext.java | 2 +- .../surface/context/SurfaceContext.java | 4 +- .../surface/context/SurfaceContextImpl.java | 4 +- .../context/SurfaceContextImplLogic.java | 4 +- .../surface/context/SurfaceTileContext.java | 2 +- .../context/SurfaceTileStackContext.java | 2 +- .../surface/context/SurfaceWorldContext.java | 2 +- .../progressia/test/TestBushFeature.java | 66 --- .../windcorp/progressia/test/TestContent.java | 5 +- .../progressia/test/TestGrassFeature.java | 70 --- .../progressia/test/TestTreeFeature.java | 106 ----- .../windcorp/progressia/test/gen/Fields.java | 321 ++++++++++++++ .../test/gen/MultiblockVegetationFeature.java | 148 +++++++ .../progressia/test/gen/TestBushFeature.java | 49 +++ .../test/gen/TestGenerationConfig.java | 118 ++++++ .../progressia/test/gen/TestGrassFeature.java | 122 ++++++ .../progressia/test/gen/TestHeightMap.java | 79 ++++ .../test/gen/TestTerrainGenerator.java | 152 ------- .../progressia/test/gen/TestTreeFeature.java | 69 +++ .../test/gen/TestWorldGenerator.java | 400 ------------------ .../test/gen/planet/TestHeightMap.java | 70 --- .../gen/surface/SurfaceCachingFloatField.java | 77 ---- .../gen/surface/SurfaceFieldRegistry.java | 29 -- .../test/gen/surface/SurfaceNodeStorage.java | 57 --- 39 files changed, 1032 insertions(+), 1146 deletions(-) rename src/main/java/ru/windcorp/progressia/{test/gen => server/world/generation}/planet/Planet.java (88%) rename src/main/java/ru/windcorp/progressia/{test/gen => server/world/generation}/planet/PlanetFeatureGenerator.java (70%) rename src/main/java/ru/windcorp/progressia/{test/gen/planet/TestPlanetGenerator.java => server/world/generation/planet/PlanetGenerator.java} (74%) rename src/main/java/ru/windcorp/progressia/{test/gen/planet/TestPlanetGravityModel.java => server/world/generation/planet/PlanetGravityModel.java} (94%) rename src/main/java/ru/windcorp/progressia/{test/gen => server/world/generation}/planet/PlanetTerrainGenerator.java (67%) rename src/main/java/ru/windcorp/progressia/{test/gen => server/world/generation}/surface/Surface.java (94%) rename src/main/java/ru/windcorp/progressia/{test/gen => server/world/generation}/surface/SurfaceFeature.java (60%) rename src/main/java/ru/windcorp/progressia/{test/gen => server/world/generation}/surface/SurfaceFeatureGenerator.java (86%) rename src/main/java/ru/windcorp/progressia/{test/gen => server/world/generation}/surface/SurfaceFloatField.java (68%) rename src/main/java/ru/windcorp/progressia/{test/gen => server/world/generation}/surface/SurfaceTerrainGenerator.java (91%) rename src/main/java/ru/windcorp/progressia/{test/gen => server/world/generation}/surface/SurfaceTopLayerFeature.java (86%) rename src/main/java/ru/windcorp/progressia/{test/gen => server/world/generation/surface}/TerrainLayer.java (81%) rename src/main/java/ru/windcorp/progressia/{test/gen => server/world/generation}/surface/context/SurfaceBlockContext.java (97%) rename src/main/java/ru/windcorp/progressia/{test/gen => server/world/generation}/surface/context/SurfaceContext.java (95%) rename src/main/java/ru/windcorp/progressia/{test/gen => server/world/generation}/surface/context/SurfaceContextImpl.java (94%) rename src/main/java/ru/windcorp/progressia/{test/gen => server/world/generation}/surface/context/SurfaceContextImplLogic.java (92%) rename src/main/java/ru/windcorp/progressia/{test/gen => server/world/generation}/surface/context/SurfaceTileContext.java (95%) rename src/main/java/ru/windcorp/progressia/{test/gen => server/world/generation}/surface/context/SurfaceTileStackContext.java (96%) rename src/main/java/ru/windcorp/progressia/{test/gen => server/world/generation}/surface/context/SurfaceWorldContext.java (95%) delete mode 100644 src/main/java/ru/windcorp/progressia/test/TestBushFeature.java delete mode 100644 src/main/java/ru/windcorp/progressia/test/TestGrassFeature.java delete mode 100644 src/main/java/ru/windcorp/progressia/test/TestTreeFeature.java create mode 100644 src/main/java/ru/windcorp/progressia/test/gen/Fields.java create mode 100644 src/main/java/ru/windcorp/progressia/test/gen/MultiblockVegetationFeature.java create mode 100644 src/main/java/ru/windcorp/progressia/test/gen/TestBushFeature.java create mode 100644 src/main/java/ru/windcorp/progressia/test/gen/TestGenerationConfig.java create mode 100644 src/main/java/ru/windcorp/progressia/test/gen/TestGrassFeature.java create mode 100644 src/main/java/ru/windcorp/progressia/test/gen/TestHeightMap.java delete mode 100644 src/main/java/ru/windcorp/progressia/test/gen/TestTerrainGenerator.java create mode 100644 src/main/java/ru/windcorp/progressia/test/gen/TestTreeFeature.java delete mode 100644 src/main/java/ru/windcorp/progressia/test/gen/TestWorldGenerator.java delete mode 100644 src/main/java/ru/windcorp/progressia/test/gen/planet/TestHeightMap.java delete mode 100644 src/main/java/ru/windcorp/progressia/test/gen/surface/SurfaceCachingFloatField.java delete mode 100644 src/main/java/ru/windcorp/progressia/test/gen/surface/SurfaceFieldRegistry.java delete mode 100644 src/main/java/ru/windcorp/progressia/test/gen/surface/SurfaceNodeStorage.java diff --git a/src/main/java/ru/windcorp/progressia/server/Server.java b/src/main/java/ru/windcorp/progressia/server/Server.java index 2ad6171..e975b90 100644 --- a/src/main/java/ru/windcorp/progressia/server/Server.java +++ b/src/main/java/ru/windcorp/progressia/server/Server.java @@ -19,6 +19,7 @@ package ru.windcorp.progressia.server; import java.util.function.Consumer; +import java.util.function.Function; import org.apache.logging.log4j.LogManager; @@ -44,12 +45,11 @@ import ru.windcorp.progressia.server.world.context.ServerWorldContext; 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.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; public class Server { @@ -78,11 +78,11 @@ public class Server { private final TickingSettings tickingSettings = new TickingSettings(); - public Server(DefaultWorldData world) { + public Server(DefaultWorldData world, Function generatorCreator) { this.world = new DefaultWorldLogic( world, this, - new TestPlanetGenerator("Test:PlanetGenerator", this, new Planet(4, 9.8f, 16f, 16f)), + generatorCreator.apply(this), worldAccessor ); this.serverThread = new ServerThread(this); diff --git a/src/main/java/ru/windcorp/progressia/server/ServerState.java b/src/main/java/ru/windcorp/progressia/server/ServerState.java index de505f5..00aa901 100644 --- a/src/main/java/ru/windcorp/progressia/server/ServerState.java +++ b/src/main/java/ru/windcorp/progressia/server/ServerState.java @@ -19,6 +19,7 @@ package ru.windcorp.progressia.server; import ru.windcorp.progressia.common.world.DefaultWorldData; +import ru.windcorp.progressia.test.gen.TestGenerationConfig; public class ServerState { @@ -33,7 +34,7 @@ public class ServerState { } public static void startServer() { - Server server = new Server(new DefaultWorldData()); + Server server = new Server(new DefaultWorldData(), TestGenerationConfig.createGenerator()); setInstance(server); server.start(); } diff --git a/src/main/java/ru/windcorp/progressia/server/world/context/impl/RotatingServerContext.java b/src/main/java/ru/windcorp/progressia/server/world/context/impl/RotatingServerContext.java index c6459c4..a73d2b0 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/context/impl/RotatingServerContext.java +++ b/src/main/java/ru/windcorp/progressia/server/world/context/impl/RotatingServerContext.java @@ -18,8 +18,8 @@ package ru.windcorp.progressia.server.world.context.impl; import glm.vec._3.i.Vec3i; +import ru.windcorp.progressia.common.world.generic.GenericChunks; import ru.windcorp.progressia.common.world.rels.AbsFace; -import ru.windcorp.progressia.common.world.rels.AxisRotations; import ru.windcorp.progressia.common.world.rels.RelFace; import ru.windcorp.progressia.server.world.context.ServerTileContext; @@ -38,12 +38,12 @@ public class RotatingServerContext extends TransformingServerContext { @Override protected void transform(Vec3i userLocation, Vec3i output) { - AxisRotations.resolve(userLocation, up, output); + GenericChunks.resolve(userLocation, up, output); } @Override protected void untransform(Vec3i parentLocation, Vec3i output) { - AxisRotations.relativize(parentLocation, up, output); + GenericChunks.relativize(parentLocation, up, output); } @Override diff --git a/src/main/java/ru/windcorp/progressia/test/gen/planet/Planet.java b/src/main/java/ru/windcorp/progressia/server/world/generation/planet/Planet.java similarity index 88% rename from src/main/java/ru/windcorp/progressia/test/gen/planet/Planet.java rename to src/main/java/ru/windcorp/progressia/server/world/generation/planet/Planet.java index 3637078..161e2c0 100644 --- a/src/main/java/ru/windcorp/progressia/test/gen/planet/Planet.java +++ b/src/main/java/ru/windcorp/progressia/server/world/generation/planet/Planet.java @@ -15,7 +15,7 @@ * 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.planet; +package ru.windcorp.progressia.server.world.generation.planet; import ru.windcorp.progressia.common.world.DefaultChunkData; @@ -23,7 +23,7 @@ public class Planet { private final int radiusInChunks; - private final TestPlanetGravityModel.Settings gravityModelSettings; + private final PlanetGravityModel.Settings gravityModelSettings; public Planet( int radiusInChunks, @@ -32,7 +32,7 @@ public class Planet { float innerGravityRadius ) { this.radiusInChunks = radiusInChunks; - this.gravityModelSettings = new TestPlanetGravityModel.Settings( + this.gravityModelSettings = new PlanetGravityModel.Settings( surfaceGravitationalAcceleration, curvature, innerGravityRadius @@ -82,7 +82,7 @@ public class Planet { /** * @return the gravityModelSettings */ - public TestPlanetGravityModel.Settings getGravityModelSettings() { + public PlanetGravityModel.Settings getGravityModelSettings() { return gravityModelSettings; } diff --git a/src/main/java/ru/windcorp/progressia/test/gen/planet/PlanetFeatureGenerator.java b/src/main/java/ru/windcorp/progressia/server/world/generation/planet/PlanetFeatureGenerator.java similarity index 70% rename from src/main/java/ru/windcorp/progressia/test/gen/planet/PlanetFeatureGenerator.java rename to src/main/java/ru/windcorp/progressia/server/world/generation/planet/PlanetFeatureGenerator.java index 38ed248..97e2424 100644 --- a/src/main/java/ru/windcorp/progressia/test/gen/planet/PlanetFeatureGenerator.java +++ b/src/main/java/ru/windcorp/progressia/server/world/generation/planet/PlanetFeatureGenerator.java @@ -15,10 +15,9 @@ * 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.planet; +package ru.windcorp.progressia.server.world.generation.planet; -import java.util.ArrayList; -import java.util.Collection; +import java.util.List; import java.util.Map; import glm.vec._3.i.Vec3i; @@ -26,26 +25,18 @@ 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; -import ru.windcorp.progressia.test.gen.surface.Surface; -import ru.windcorp.progressia.test.gen.surface.SurfaceFeature; -import ru.windcorp.progressia.test.gen.surface.SurfaceFeatureGenerator; +import ru.windcorp.progressia.server.world.generation.surface.Surface; +import ru.windcorp.progressia.server.world.generation.surface.SurfaceFeature; +import ru.windcorp.progressia.server.world.generation.surface.SurfaceFeatureGenerator; public class PlanetFeatureGenerator { - private final TestPlanetGenerator parent; + private final PlanetGenerator parent; private final Map surfaceGenerators; - public PlanetFeatureGenerator(TestPlanetGenerator generator) { + public PlanetFeatureGenerator(PlanetGenerator generator, List features) { this.parent = generator; - - Collection features = new ArrayList<>(); - features.add(new TestBushFeature("Test:BushFeature")); - features.add(new TestTreeFeature("Test:TreeFeature")); - features.add(new TestGrassFeature("Test:GrassFeature")); int seaLevel = (int) parent.getPlanet().getRadius(); this.surfaceGenerators = AbsFace.mapToFaces(face -> new SurfaceFeatureGenerator( @@ -54,7 +45,7 @@ public class PlanetFeatureGenerator { )); } - public TestPlanetGenerator getGenerator() { + public PlanetGenerator getGenerator() { return parent; } diff --git a/src/main/java/ru/windcorp/progressia/test/gen/planet/TestPlanetGenerator.java b/src/main/java/ru/windcorp/progressia/server/world/generation/planet/PlanetGenerator.java similarity index 74% rename from src/main/java/ru/windcorp/progressia/test/gen/planet/TestPlanetGenerator.java rename to src/main/java/ru/windcorp/progressia/server/world/generation/planet/PlanetGenerator.java index 0846be7..1d31417 100644 --- a/src/main/java/ru/windcorp/progressia/test/gen/planet/TestPlanetGenerator.java +++ b/src/main/java/ru/windcorp/progressia/server/world/generation/planet/PlanetGenerator.java @@ -15,49 +15,61 @@ * 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.planet; +package ru.windcorp.progressia.server.world.generation.planet; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; +import java.util.List; import glm.vec._3.Vec3; import glm.vec._3.i.Vec3i; +import ru.windcorp.progressia.common.util.FloatRangeMap; import ru.windcorp.progressia.common.util.VectorUtil; import ru.windcorp.progressia.common.world.DefaultChunkData; import ru.windcorp.progressia.common.world.DecodingException; import ru.windcorp.progressia.server.Server; import ru.windcorp.progressia.server.world.generation.AbstractWorldGenerator; +import ru.windcorp.progressia.server.world.generation.surface.SurfaceFeature; +import ru.windcorp.progressia.server.world.generation.surface.SurfaceFloatField; +import ru.windcorp.progressia.server.world.generation.surface.TerrainLayer; + +public class PlanetGenerator extends AbstractWorldGenerator { -public class TestPlanetGenerator extends AbstractWorldGenerator { - private final Planet planet; - + private final PlanetTerrainGenerator terrainGenerator; private final PlanetFeatureGenerator featureGenerator; - public TestPlanetGenerator(String id, Server server, Planet planet) { + public PlanetGenerator( + String id, + Server server, + Planet planet, + SurfaceFloatField heightMap, + FloatRangeMap layers, + List features + ) { super(id, server, Boolean.class, "Test:PlanetGravityModel"); - + this.planet = planet; - - TestPlanetGravityModel model = (TestPlanetGravityModel) this.getGravityModel(); + + PlanetGravityModel model = (PlanetGravityModel) this.getGravityModel(); model.configure(planet.getGravityModelSettings()); - - this.terrainGenerator = new PlanetTerrainGenerator(this); - this.featureGenerator = new PlanetFeatureGenerator(this); + + this.terrainGenerator = new PlanetTerrainGenerator(this, heightMap, layers); + this.featureGenerator = new PlanetFeatureGenerator(this, features); } - + /** * @return the planet */ public Planet getPlanet() { return planet; } - + @Override public Vec3 suggestSpawnLocation() { - return new Vec3(7f, 7f, getPlanet().getRadius() + 10); + return new Vec3(407f, 1f, getPlanet().getRadius() + 10); } @Override @@ -79,14 +91,14 @@ public class TestPlanetGenerator extends AbstractWorldGenerator { public DefaultChunkData generate(Vec3i chunkPos) { VectorUtil.iterateCuboidAround(chunkPos, 3, r -> conjureTerrain(r)); DefaultChunkData chunk = getWorldData().getChunk(chunkPos); - + if (!isChunkReady(chunk.getGenerationHint())) { featureGenerator.generateFeatures(getServer(), chunk); } - + return chunk; } - + private void conjureTerrain(Vec3i chunkPos) { getServer().getLoadManager().getChunkManager().loadChunk(chunkPos); DefaultChunkData chunk = getWorldData().getChunk(chunkPos); diff --git a/src/main/java/ru/windcorp/progressia/test/gen/planet/TestPlanetGravityModel.java b/src/main/java/ru/windcorp/progressia/server/world/generation/planet/PlanetGravityModel.java similarity index 94% rename from src/main/java/ru/windcorp/progressia/test/gen/planet/TestPlanetGravityModel.java rename to src/main/java/ru/windcorp/progressia/server/world/generation/planet/PlanetGravityModel.java index a7fb334..e2545b5 100644 --- a/src/main/java/ru/windcorp/progressia/test/gen/planet/TestPlanetGravityModel.java +++ b/src/main/java/ru/windcorp/progressia/server/world/generation/planet/PlanetGravityModel.java @@ -15,7 +15,7 @@ * 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.planet; +package ru.windcorp.progressia.server.world.generation.planet; import glm.vec._3.Vec3; import glm.vec._3.i.Vec3i; @@ -30,7 +30,7 @@ import java.io.DataInput; import java.io.DataOutput; import java.io.IOException; -public class TestPlanetGravityModel extends GravityModel { +public class PlanetGravityModel extends GravityModel { public static class Settings { public float surfaceGravitationalAcceleration; @@ -66,7 +66,7 @@ public class TestPlanetGravityModel extends GravityModel { private Settings settings = new Settings(); - public TestPlanetGravityModel(String id) { + public PlanetGravityModel(String id) { super(id); } @@ -90,7 +90,6 @@ public class TestPlanetGravityModel extends GravityModel { 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 - DefaultChunkData.CHUNK_RADIUS + 0.5f; @@ -142,14 +141,14 @@ public class TestPlanetGravityModel extends GravityModel { assert output.dot(output) == 1 : "maxAbs - midAbs = " + maxAbs + " - " + midAbs + " > " + c + " yet l*l != 1"; } - output.mul(-g); + output.mul(-getSurfaceGravitationalAcceleration()); } 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(); + float c = getCurvature(); if (lx == 0) rx = 0; if (ly == 0) ry = 0; @@ -159,10 +158,10 @@ public class TestPlanetGravityModel extends GravityModel { float rSquared = rx*rx + ry*ry + rz*rz; float distanceAlongEdge = scalarProduct - (float) sqrt( - scalarProduct*scalarProduct - rSquared + r*r + scalarProduct*scalarProduct - rSquared + c*c ); - output.set(lx, ly, lz).mul(-distanceAlongEdge).add(rx, ry, rz).div(r); + output.set(lx, ly, lz).mul(-distanceAlongEdge).add(rx, ry, rz).div(c); final float f = (float) sqrt(3.0/2); diff --git a/src/main/java/ru/windcorp/progressia/test/gen/planet/PlanetTerrainGenerator.java b/src/main/java/ru/windcorp/progressia/server/world/generation/planet/PlanetTerrainGenerator.java similarity index 67% rename from src/main/java/ru/windcorp/progressia/test/gen/planet/PlanetTerrainGenerator.java rename to src/main/java/ru/windcorp/progressia/server/world/generation/planet/PlanetTerrainGenerator.java index 227187d..ab081db 100644 --- a/src/main/java/ru/windcorp/progressia/test/gen/planet/PlanetTerrainGenerator.java +++ b/src/main/java/ru/windcorp/progressia/server/world/generation/planet/PlanetTerrainGenerator.java @@ -15,11 +15,10 @@ * 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.planet; +package ru.windcorp.progressia.server.world.generation.planet; import glm.vec._3.Vec3; import glm.vec._3.i.Vec3i; -import ru.windcorp.progressia.common.util.ArrayFloatRangeMap; import ru.windcorp.progressia.common.util.FloatRangeMap; import ru.windcorp.progressia.common.util.VectorUtil; import ru.windcorp.progressia.common.world.DefaultChunkData; @@ -27,37 +26,22 @@ import ru.windcorp.progressia.common.world.Coordinates; import ru.windcorp.progressia.common.world.block.BlockData; import ru.windcorp.progressia.common.world.block.BlockDataRegistry; import ru.windcorp.progressia.common.world.generic.GenericChunks; -import ru.windcorp.progressia.test.gen.TerrainLayer; -import ru.windcorp.progressia.test.gen.surface.SurfaceFloatField; -import ru.windcorp.progressia.test.gen.surface.SurfaceTerrainGenerator; +import ru.windcorp.progressia.server.world.generation.surface.SurfaceFloatField; +import ru.windcorp.progressia.server.world.generation.surface.SurfaceTerrainGenerator; +import ru.windcorp.progressia.server.world.generation.surface.TerrainLayer; class PlanetTerrainGenerator { - private final TestPlanetGenerator parent; + private final PlanetGenerator parent; private final SurfaceTerrainGenerator surfaceGenerator; - public PlanetTerrainGenerator(TestPlanetGenerator generator) { + public PlanetTerrainGenerator(PlanetGenerator generator, SurfaceFloatField heightMap, FloatRangeMap layers) { this.parent = generator; - - SurfaceFloatField heightMap = new TestHeightMap( - generator.getPlanet().getRadius() - DefaultChunkData.BLOCKS_PER_CHUNK, - generator.getPlanet().getRadius() / 4, - 5, - 6 - ); - - FloatRangeMap layers = new ArrayFloatRangeMap<>(); - BlockData granite = BlockDataRegistry.getInstance().get("Test:GraniteMonolith"); - BlockData dirt = BlockDataRegistry.getInstance().get("Test:Dirt"); - BlockData air = BlockDataRegistry.getInstance().get("Test:Air"); - layers.put(Float.NEGATIVE_INFINITY, 0, (n, w, d, r, c) -> air); - layers.put(0, 4, (n, w, d, r, c) -> dirt); - layers.put(4, Float.POSITIVE_INFINITY, (n, w, d, r, c) -> granite); - - this.surfaceGenerator = new SurfaceTerrainGenerator((f, n, w) -> heightMap.get(f, n, w) + generator.getPlanet().getRadius(), layers); + SurfaceFloatField adjustedHeightMap = (f, n, w) -> heightMap.get(f, n, w) + generator.getPlanet().getRadius(); + this.surfaceGenerator = new SurfaceTerrainGenerator(adjustedHeightMap, layers); } - public TestPlanetGenerator getGenerator() { + public PlanetGenerator getGenerator() { return parent; } @@ -69,7 +53,7 @@ class PlanetTerrainGenerator { } else { generateBorderTerrain(chunk); } - + chunk.setGenerationHint(false); return chunk; @@ -87,24 +71,24 @@ class PlanetTerrainGenerator { private void generateBorderTerrain(DefaultChunkData chunk) { BlockData stone = BlockDataRegistry.getInstance().get("Test:Stone"); BlockData air = BlockDataRegistry.getInstance().get("Test:Air"); - + float radius = parent.getPlanet().getRadius(); Vec3 biw = new Vec3(); - + GenericChunks.forEachBiC(bic -> { - + biw.set( Coordinates.getInWorld(chunk.getX(), bic.x), Coordinates.getInWorld(chunk.getY(), bic.y), Coordinates.getInWorld(chunk.getZ(), bic.z) ); - + biw.sub(DefaultChunkData.CHUNK_RADIUS - 0.5f); VectorUtil.sortAfterAbs(biw, biw); - + chunk.setBlock(bic, biw.x <= radius ? stone : air, false); - + }); } diff --git a/src/main/java/ru/windcorp/progressia/test/gen/surface/Surface.java b/src/main/java/ru/windcorp/progressia/server/world/generation/surface/Surface.java similarity index 94% rename from src/main/java/ru/windcorp/progressia/test/gen/surface/Surface.java rename to src/main/java/ru/windcorp/progressia/server/world/generation/surface/Surface.java index 0baa6f0..296e3eb 100644 --- a/src/main/java/ru/windcorp/progressia/test/gen/surface/Surface.java +++ b/src/main/java/ru/windcorp/progressia/server/world/generation/surface/Surface.java @@ -15,7 +15,7 @@ * 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; +package ru.windcorp.progressia.server.world.generation.surface; import ru.windcorp.progressia.common.world.rels.AbsFace; diff --git a/src/main/java/ru/windcorp/progressia/test/gen/surface/SurfaceFeature.java b/src/main/java/ru/windcorp/progressia/server/world/generation/surface/SurfaceFeature.java similarity index 60% rename from src/main/java/ru/windcorp/progressia/test/gen/surface/SurfaceFeature.java rename to src/main/java/ru/windcorp/progressia/server/world/generation/surface/SurfaceFeature.java index e4bb250..8430168 100644 --- a/src/main/java/ru/windcorp/progressia/test/gen/surface/SurfaceFeature.java +++ b/src/main/java/ru/windcorp/progressia/server/world/generation/surface/SurfaceFeature.java @@ -15,10 +15,13 @@ * 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; +package ru.windcorp.progressia.server.world.generation.surface; + +import java.util.List; import ru.windcorp.progressia.common.util.namespaces.Namespaced; -import ru.windcorp.progressia.test.gen.surface.context.SurfaceWorldContext; +import ru.windcorp.progressia.server.world.context.ServerContext; +import ru.windcorp.progressia.server.world.generation.surface.context.SurfaceWorldContext; public abstract class SurfaceFeature extends Namespaced { @@ -27,5 +30,17 @@ public abstract class SurfaceFeature extends Namespaced { } public abstract void process(SurfaceWorldContext context); + + protected static double randomDouble(ServerContext context, double from, double to) { + return from + (to - from) * context.getRandom().nextDouble(); + } + + protected static double stretch(double t, double from, double to) { + return from + (to - from) * t; + } + + protected static T pickRandom(ServerContext context, List from) { + return from.get(context.getRandom().nextInt(from.size())); + } } diff --git a/src/main/java/ru/windcorp/progressia/test/gen/surface/SurfaceFeatureGenerator.java b/src/main/java/ru/windcorp/progressia/server/world/generation/surface/SurfaceFeatureGenerator.java similarity index 86% rename from src/main/java/ru/windcorp/progressia/test/gen/surface/SurfaceFeatureGenerator.java rename to src/main/java/ru/windcorp/progressia/server/world/generation/surface/SurfaceFeatureGenerator.java index aafd0ea..abfbcb3 100644 --- a/src/main/java/ru/windcorp/progressia/test/gen/surface/SurfaceFeatureGenerator.java +++ b/src/main/java/ru/windcorp/progressia/server/world/generation/surface/SurfaceFeatureGenerator.java @@ -15,10 +15,10 @@ * 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; +package ru.windcorp.progressia.server.world.generation.surface; import java.util.ArrayList; -import java.util.Collection; +import java.util.List; import java.util.Random; import glm.Glm; @@ -27,15 +27,15 @@ 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; +import ru.windcorp.progressia.server.world.generation.surface.context.SurfaceContextImpl; public class SurfaceFeatureGenerator { private final Surface surface; - private final Collection features; // TODO make ordered + private final List features; - public SurfaceFeatureGenerator(Surface surface, Collection features) { + public SurfaceFeatureGenerator(Surface surface, List features) { this.surface = surface; this.features = new ArrayList<>(features); } diff --git a/src/main/java/ru/windcorp/progressia/test/gen/surface/SurfaceFloatField.java b/src/main/java/ru/windcorp/progressia/server/world/generation/surface/SurfaceFloatField.java similarity index 68% rename from src/main/java/ru/windcorp/progressia/test/gen/surface/SurfaceFloatField.java rename to src/main/java/ru/windcorp/progressia/server/world/generation/surface/SurfaceFloatField.java index 4b368d4..81506f1 100644 --- a/src/main/java/ru/windcorp/progressia/test/gen/surface/SurfaceFloatField.java +++ b/src/main/java/ru/windcorp/progressia/server/world/generation/surface/SurfaceFloatField.java @@ -15,13 +15,20 @@ * 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; +package ru.windcorp.progressia.server.world.generation.surface; +import glm.vec._3.i.Vec3i; import ru.windcorp.progressia.common.world.rels.AbsFace; +import ru.windcorp.progressia.server.world.generation.surface.context.SurfaceBlockContext; @FunctionalInterface public interface SurfaceFloatField { - float get(AbsFace face, float north, float west); + float get(AbsFace face, float x, float y); + + default float get(SurfaceBlockContext context) { + Vec3i location = context.getLocation(); + return get(context.getSurface().getUp(), location.x, location.y); + } } diff --git a/src/main/java/ru/windcorp/progressia/test/gen/surface/SurfaceTerrainGenerator.java b/src/main/java/ru/windcorp/progressia/server/world/generation/surface/SurfaceTerrainGenerator.java similarity index 91% rename from src/main/java/ru/windcorp/progressia/test/gen/surface/SurfaceTerrainGenerator.java rename to src/main/java/ru/windcorp/progressia/server/world/generation/surface/SurfaceTerrainGenerator.java index ec93d58..a3511bd 100644 --- a/src/main/java/ru/windcorp/progressia/test/gen/surface/SurfaceTerrainGenerator.java +++ b/src/main/java/ru/windcorp/progressia/server/world/generation/surface/SurfaceTerrainGenerator.java @@ -15,7 +15,7 @@ * 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; +package ru.windcorp.progressia.server.world.generation.surface; import java.util.Random; @@ -26,7 +26,6 @@ import ru.windcorp.progressia.common.util.FloatRangeMap; import ru.windcorp.progressia.common.world.DefaultChunkData; import ru.windcorp.progressia.common.world.block.BlockData; import ru.windcorp.progressia.common.world.rels.AxisRotations; -import ru.windcorp.progressia.test.gen.TerrainLayer; public class SurfaceTerrainGenerator { @@ -44,7 +43,7 @@ public class SurfaceTerrainGenerator { Vec3 offset = new Vec3(chunk.getMinX(), chunk.getMinY(), chunk.getMinZ()); AxisRotations.relativize(offset, chunk.getUp(), offset); - offset.sub(DefaultChunkData.CHUNK_RADIUS - 0.5f); + offset.z -= DefaultChunkData.CHUNK_RADIUS - 0.5f; Random random = new Random(CoordinatePacker.pack3IntsIntoLong(chunk.getPosition()) /* ^ seed*/); @@ -65,7 +64,7 @@ public class SurfaceTerrainGenerator { for (relBIC.z = 0; relBIC.z < DefaultChunkData.BLOCKS_PER_CHUNK; ++relBIC.z) { float depth = relSurface - relBIC.z; - BlockData block = layers.get(depth).get(north, west, depth, random, chunk); + BlockData block = layers.get(depth).get(chunk.getUp(), north, west, depth, random); chunk.resolve(relBIC, relBIC); chunk.setBlock(relBIC, block, false); diff --git a/src/main/java/ru/windcorp/progressia/test/gen/surface/SurfaceTopLayerFeature.java b/src/main/java/ru/windcorp/progressia/server/world/generation/surface/SurfaceTopLayerFeature.java similarity index 86% rename from src/main/java/ru/windcorp/progressia/test/gen/surface/SurfaceTopLayerFeature.java rename to src/main/java/ru/windcorp/progressia/server/world/generation/surface/SurfaceTopLayerFeature.java index 4981dff..d96d68b 100644 --- a/src/main/java/ru/windcorp/progressia/test/gen/surface/SurfaceTopLayerFeature.java +++ b/src/main/java/ru/windcorp/progressia/server/world/generation/surface/SurfaceTopLayerFeature.java @@ -15,11 +15,11 @@ * 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; +package ru.windcorp.progressia.server.world.generation.surface; import glm.vec._3.i.Vec3i; -import ru.windcorp.progressia.test.gen.surface.context.SurfaceBlockContext; -import ru.windcorp.progressia.test.gen.surface.context.SurfaceWorldContext; +import ru.windcorp.progressia.server.world.generation.surface.context.SurfaceBlockContext; +import ru.windcorp.progressia.server.world.generation.surface.context.SurfaceWorldContext; public abstract class SurfaceTopLayerFeature extends SurfaceFeature { diff --git a/src/main/java/ru/windcorp/progressia/test/gen/TerrainLayer.java b/src/main/java/ru/windcorp/progressia/server/world/generation/surface/TerrainLayer.java similarity index 81% rename from src/main/java/ru/windcorp/progressia/test/gen/TerrainLayer.java rename to src/main/java/ru/windcorp/progressia/server/world/generation/surface/TerrainLayer.java index 21c1809..7af46fa 100644 --- a/src/main/java/ru/windcorp/progressia/test/gen/TerrainLayer.java +++ b/src/main/java/ru/windcorp/progressia/server/world/generation/surface/TerrainLayer.java @@ -15,16 +15,16 @@ * 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; +package ru.windcorp.progressia.server.world.generation.surface; import java.util.Random; -import ru.windcorp.progressia.common.world.DefaultChunkData; import ru.windcorp.progressia.common.world.block.BlockData; +import ru.windcorp.progressia.common.world.rels.AbsFace; @FunctionalInterface public interface TerrainLayer { - BlockData get(float north, float west, float depth, Random random, DefaultChunkData chunk); + BlockData get(AbsFace face, float north, float west, float depth, Random random); } diff --git a/src/main/java/ru/windcorp/progressia/test/gen/surface/context/SurfaceBlockContext.java b/src/main/java/ru/windcorp/progressia/server/world/generation/surface/context/SurfaceBlockContext.java similarity index 97% rename from src/main/java/ru/windcorp/progressia/test/gen/surface/context/SurfaceBlockContext.java rename to src/main/java/ru/windcorp/progressia/server/world/generation/surface/context/SurfaceBlockContext.java index be3c285..64531fb 100644 --- a/src/main/java/ru/windcorp/progressia/test/gen/surface/context/SurfaceBlockContext.java +++ b/src/main/java/ru/windcorp/progressia/server/world/generation/surface/context/SurfaceBlockContext.java @@ -15,7 +15,7 @@ * 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; +package ru.windcorp.progressia.server.world.generation.surface.context; import glm.vec._3.i.Vec3i; import ru.windcorp.progressia.common.world.rels.RelFace; diff --git a/src/main/java/ru/windcorp/progressia/test/gen/surface/context/SurfaceContext.java b/src/main/java/ru/windcorp/progressia/server/world/generation/surface/context/SurfaceContext.java similarity index 95% rename from src/main/java/ru/windcorp/progressia/test/gen/surface/context/SurfaceContext.java rename to src/main/java/ru/windcorp/progressia/server/world/generation/surface/context/SurfaceContext.java index b0b1aca..a69d60b 100644 --- a/src/main/java/ru/windcorp/progressia/test/gen/surface/context/SurfaceContext.java +++ b/src/main/java/ru/windcorp/progressia/server/world/generation/surface/context/SurfaceContext.java @@ -15,13 +15,13 @@ * 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; +package ru.windcorp.progressia.server.world.generation.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; +import ru.windcorp.progressia.server.world.generation.surface.Surface; public interface SurfaceContext { diff --git a/src/main/java/ru/windcorp/progressia/test/gen/surface/context/SurfaceContextImpl.java b/src/main/java/ru/windcorp/progressia/server/world/generation/surface/context/SurfaceContextImpl.java similarity index 94% rename from src/main/java/ru/windcorp/progressia/test/gen/surface/context/SurfaceContextImpl.java rename to src/main/java/ru/windcorp/progressia/server/world/generation/surface/context/SurfaceContextImpl.java index 307330e..6050c49 100644 --- a/src/main/java/ru/windcorp/progressia/test/gen/surface/context/SurfaceContextImpl.java +++ b/src/main/java/ru/windcorp/progressia/server/world/generation/surface/context/SurfaceContextImpl.java @@ -15,7 +15,7 @@ * 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; +package ru.windcorp.progressia.server.world.generation.surface.context; import java.util.Random; @@ -23,7 +23,7 @@ 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; +import ru.windcorp.progressia.server.world.generation.surface.Surface; public class SurfaceContextImpl extends RotatingServerContext implements SurfaceTileContext { diff --git a/src/main/java/ru/windcorp/progressia/test/gen/surface/context/SurfaceContextImplLogic.java b/src/main/java/ru/windcorp/progressia/server/world/generation/surface/context/SurfaceContextImplLogic.java similarity index 92% rename from src/main/java/ru/windcorp/progressia/test/gen/surface/context/SurfaceContextImplLogic.java rename to src/main/java/ru/windcorp/progressia/server/world/generation/surface/context/SurfaceContextImplLogic.java index b8f45df..cbf9b88 100644 --- a/src/main/java/ru/windcorp/progressia/test/gen/surface/context/SurfaceContextImplLogic.java +++ b/src/main/java/ru/windcorp/progressia/server/world/generation/surface/context/SurfaceContextImplLogic.java @@ -15,12 +15,12 @@ * 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; +package ru.windcorp.progressia.server.world.generation.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; +import ru.windcorp.progressia.server.world.generation.surface.Surface; public class SurfaceContextImplLogic extends DefaultServerContextLogic implements SurfaceTileContext.Logic { diff --git a/src/main/java/ru/windcorp/progressia/test/gen/surface/context/SurfaceTileContext.java b/src/main/java/ru/windcorp/progressia/server/world/generation/surface/context/SurfaceTileContext.java similarity index 95% rename from src/main/java/ru/windcorp/progressia/test/gen/surface/context/SurfaceTileContext.java rename to src/main/java/ru/windcorp/progressia/server/world/generation/surface/context/SurfaceTileContext.java index 13f2211..ce28c6e 100644 --- a/src/main/java/ru/windcorp/progressia/test/gen/surface/context/SurfaceTileContext.java +++ b/src/main/java/ru/windcorp/progressia/server/world/generation/surface/context/SurfaceTileContext.java @@ -15,7 +15,7 @@ * 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; +package ru.windcorp.progressia.server.world.generation.surface.context; import ru.windcorp.progressia.server.world.context.ServerTileContext; diff --git a/src/main/java/ru/windcorp/progressia/test/gen/surface/context/SurfaceTileStackContext.java b/src/main/java/ru/windcorp/progressia/server/world/generation/surface/context/SurfaceTileStackContext.java similarity index 96% rename from src/main/java/ru/windcorp/progressia/test/gen/surface/context/SurfaceTileStackContext.java rename to src/main/java/ru/windcorp/progressia/server/world/generation/surface/context/SurfaceTileStackContext.java index 54f65bc..d090e94 100644 --- a/src/main/java/ru/windcorp/progressia/test/gen/surface/context/SurfaceTileStackContext.java +++ b/src/main/java/ru/windcorp/progressia/server/world/generation/surface/context/SurfaceTileStackContext.java @@ -15,7 +15,7 @@ * 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; +package ru.windcorp.progressia.server.world.generation.surface.context; import ru.windcorp.progressia.server.world.context.ServerTileStackContext; diff --git a/src/main/java/ru/windcorp/progressia/test/gen/surface/context/SurfaceWorldContext.java b/src/main/java/ru/windcorp/progressia/server/world/generation/surface/context/SurfaceWorldContext.java similarity index 95% rename from src/main/java/ru/windcorp/progressia/test/gen/surface/context/SurfaceWorldContext.java rename to src/main/java/ru/windcorp/progressia/server/world/generation/surface/context/SurfaceWorldContext.java index 76510cf..96a0922 100644 --- a/src/main/java/ru/windcorp/progressia/test/gen/surface/context/SurfaceWorldContext.java +++ b/src/main/java/ru/windcorp/progressia/server/world/generation/surface/context/SurfaceWorldContext.java @@ -15,7 +15,7 @@ * 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; +package ru.windcorp.progressia.server.world.generation.surface.context; import glm.vec._3.i.Vec3i; import ru.windcorp.progressia.common.world.rels.RelFace; diff --git a/src/main/java/ru/windcorp/progressia/test/TestBushFeature.java b/src/main/java/ru/windcorp/progressia/test/TestBushFeature.java deleted file mode 100644 index a7174f9..0000000 --- a/src/main/java/ru/windcorp/progressia/test/TestBushFeature.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * 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; - -import glm.vec._3.i.Vec3i; -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.test.gen.surface.SurfaceTopLayerFeature; -import ru.windcorp.progressia.test.gen.surface.context.SurfaceBlockContext; -import ru.windcorp.progressia.test.gen.surface.context.SurfaceWorldContext; - -public class TestBushFeature extends SurfaceTopLayerFeature { - - public TestBushFeature(String id) { - super(id); - } - - 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(SurfaceBlockContext context) { - if (context.getRandom().nextInt(10*10) > 0) return; - - Vec3i center = context.getLocation().add_(0, 0, 1); - - BlockData log = BlockDataRegistry.getInstance().get("Test:Log"); - BlockData leaves = BlockDataRegistry.getInstance().get("Test:TemporaryLeaves"); - - context.setBlock(center, log); - - VectorUtil.iterateCuboidAround(center.x, center.y, center.z, 3, 3, 3, p -> { - tryToSetLeaves(context, p, leaves); - }); - - VectorUtil.iterateCuboidAround(center.x, center.y, center.z, 5, 5, 1, p -> { - tryToSetLeaves(context, p, leaves); - }); - } - - @Override - protected boolean isSolid(SurfaceBlockContext context) { - return context.logic().getBlock().isSolid(RelFace.UP); - } - -} diff --git a/src/main/java/ru/windcorp/progressia/test/TestContent.java b/src/main/java/ru/windcorp/progressia/test/TestContent.java index fe972a4..b8a5b33 100644 --- a/src/main/java/ru/windcorp/progressia/test/TestContent.java +++ b/src/main/java/ru/windcorp/progressia/test/TestContent.java @@ -27,7 +27,6 @@ import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.function.Consumer; - import org.lwjgl.glfw.GLFW; import glm.vec._3.i.Vec3i; @@ -56,9 +55,9 @@ import ru.windcorp.progressia.server.Server; import ru.windcorp.progressia.server.comms.controls.*; import ru.windcorp.progressia.server.world.block.*; import ru.windcorp.progressia.server.world.entity.*; +import ru.windcorp.progressia.server.world.generation.planet.PlanetGravityModel; import ru.windcorp.progressia.server.world.tile.*; import ru.windcorp.progressia.test.gen.TestGravityModel; -import ru.windcorp.progressia.test.gen.planet.TestPlanetGravityModel; public class TestContent { @@ -435,7 +434,7 @@ public class TestContent { ChunkIO.registerCodec(new TestChunkCodec()); ChunkRenderOptimizerRegistry.getInstance().register("Core:SurfaceOptimizer", ChunkRenderOptimizerSurface::new); GravityModelRegistry.getInstance().register("Test:TheGravityModel", TestGravityModel::new); - GravityModelRegistry.getInstance().register("Test:PlanetGravityModel", TestPlanetGravityModel::new); + GravityModelRegistry.getInstance().register("Test:PlanetGravityModel", PlanetGravityModel::new); } } diff --git a/src/main/java/ru/windcorp/progressia/test/TestGrassFeature.java b/src/main/java/ru/windcorp/progressia/test/TestGrassFeature.java deleted file mode 100644 index cd18ebe..0000000 --- a/src/main/java/ru/windcorp/progressia/test/TestGrassFeature.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * 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; - -import java.util.Set; - -import com.google.common.collect.ImmutableSet; - -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.test.gen.surface.SurfaceTopLayerFeature; -import ru.windcorp.progressia.test.gen.surface.context.SurfaceBlockContext; - -public class TestGrassFeature extends SurfaceTopLayerFeature { - - private static final Set WHITELIST = ImmutableSet.of( - "Test:Dirt", - "Test:Stone", - "Test:GraniteMonolith", - "Test:GraniteCracked", - "Test:GraniteGravel" - ); - - public TestGrassFeature(String id) { - super(id); - } - - @Override - protected void processTopBlock(SurfaceBlockContext context) { - if (!WHITELIST.contains(context.getBlock().getId())) { - return; - } - - TileData grass = TileDataRegistry.getInstance().get("Test:Grass"); - - for (RelFace face : RelFace.getFaces()) { - if (face == RelFace.DOWN) continue; - - if (context.pushRelative(face).logic().getBlock().isTransparent()) { - context.pop(); - context.addTile(face, grass); - } else { - context.pop(); - } - - } - } - - @Override - 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 deleted file mode 100644 index 2e91dc9..0000000 --- a/src/main/java/ru/windcorp/progressia/test/TestTreeFeature.java +++ /dev/null @@ -1,106 +0,0 @@ -/* - * 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; - -import java.util.function.Consumer; - -import glm.vec._3.i.Vec3i; -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.test.gen.surface.SurfaceTopLayerFeature; -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(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, - (int) Math.ceil(horDiameter) / 2 * 2 + 5, - (int) Math.ceil(horDiameter) / 2 * 2 + 5, - (int) Math.ceil(vertDiameter) / 2 * 2 + 5, - pos -> { - 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) { - action.accept(pos); - } - } - ); - } - - @Override - 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 = context.getRandom().nextInt(3) + 5; - for (; center.z < start.z + height; ++center.z) { - context.setBlock(center, log); - } - - double branchHorDistance = 0; - - do { - 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(context, p, leaves); - }); - - branchHorDistance = 1 + 2 * context.getRandom().nextDouble(); - } while (context.getRandom().nextInt(8) > 1); - } - - @Override - protected boolean isSolid(SurfaceBlockContext context) { - return context.logic().getBlock().isSolid(RelFace.UP); - } - -} diff --git a/src/main/java/ru/windcorp/progressia/test/gen/Fields.java b/src/main/java/ru/windcorp/progressia/test/gen/Fields.java new file mode 100644 index 0000000..86741df --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/test/gen/Fields.java @@ -0,0 +1,321 @@ +/* + * 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; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; +import java.util.Random; +import java.util.function.Function; +import java.util.function.Supplier; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import kdotjpg.opensimplex2.areagen.OpenSimplex2S; +import ru.windcorp.progressia.common.util.namespaces.Namespaced; +import ru.windcorp.progressia.common.world.Coordinates; +import ru.windcorp.progressia.common.world.DefaultChunkData; +import ru.windcorp.progressia.common.world.rels.AbsFace; +import ru.windcorp.progressia.server.world.generation.planet.Planet; +import ru.windcorp.progressia.server.world.generation.surface.SurfaceFloatField; + +public class Fields { + + @FunctionalInterface + public interface Field { + double compute(double x, double y); + } + + public static class FieldSet extends Namespaced implements SurfaceFloatField { + + private final Field[] fields = new Field[AbsFace.getFaces().size()]; + + public FieldSet(String id) { + super(id); + } + + public void put(AbsFace face, Field field) { + fields[face.getId()] = field; + } + + public Field get(AbsFace face) { + return fields[face.getId()]; + } + + @Override + public float get(AbsFace face, float x, float y) { + float offset = DefaultChunkData.CHUNK_RADIUS - 0.5f; + return (float) fields[face.getId()].compute(x - offset, y - offset); + } + + } + + private final Random primitiveRandomizer; + + private final OpenSimplex2S noise; + + private final Map registeredFields = Collections.synchronizedMap(new HashMap<>()); + + private final Logger logger = LogManager.getLogger(getClass()); + + public Fields(long seed) { + this.primitiveRandomizer = new Random(seed); + this.noise = new OpenSimplex2S(seed); + } + + public Field register(String id, AbsFace face, Field f) { + Objects.requireNonNull(f, "f"); + Objects.requireNonNull(face, "face"); + + synchronized (registeredFields) { + FieldSet fieldSet = registeredFields.computeIfAbsent(id, FieldSet::new); + + Field previous = fieldSet.get(face); + if (previous != null) { + throw new IllegalArgumentException( + "Duplicate field definition " + id + ":" + face + " for fields " + f + " and " + previous + ); + } + fieldSet.put(face, f); + + logger.debug("Registering {}:{} in {}", id, face, getClass().getSimpleName()); + } + + return f; + } + + public SurfaceFloatField register(String id, Function fieldGenerator) { + for (AbsFace face : AbsFace.getFaces()) { + register(id, face, fieldGenerator.apply(face)); + } + return get(id); + } + + public SurfaceFloatField register(String id, Supplier fieldGenerator) { + for (AbsFace face : AbsFace.getFaces()) { + register(id, face, fieldGenerator.get()); + } + return get(id); + } + + public SurfaceFloatField get(String id) { + return registeredFields.get(id); + } + + public Field get(String id, AbsFace face) { + return registeredFields.get(id).get(face); + } + + public static Field cutoff(Field f, double outerRadius, double thickness) { + return (x, y) -> { + + double cutoffCoefficient = 1; + cutoffCoefficient *= cutoffFunction(outerRadius - x, thickness); + cutoffCoefficient *= cutoffFunction(outerRadius + x, thickness); + cutoffCoefficient *= cutoffFunction(outerRadius - y, thickness); + cutoffCoefficient *= cutoffFunction(outerRadius + y, thickness); + + if (cutoffCoefficient == 0) { + return 0; + } + + return cutoffCoefficient * f.compute(x, y); + + }; + } + + public static Field cutoff(Field f, Planet planet, double thickness) { + return cutoff(f, planet.getRadius() - Coordinates.CHUNK_SIZE, thickness); + } + + private static double cutoffFunction(double distanceToCutoffPoint, double thickness) { + if (distanceToCutoffPoint < 0) { + return 0; + } else if (distanceToCutoffPoint < thickness) { + double t = distanceToCutoffPoint / thickness; + return (1 - Math.cos(Math.PI * t)) / 2; + } else { + return 1; + } + } + + public Field primitive() { + double xOffset = primitiveRandomizer.nextDouble() * 200 - 100; + double yOffset = primitiveRandomizer.nextDouble() * 200 - 100; + double rotation = primitiveRandomizer.nextDouble() * 2 * Math.PI; + + double sin = Math.sin(rotation); + double cos = Math.cos(rotation); + + return (x, y) -> noise.noise2(x * cos - y * sin + xOffset, x * sin + y * cos + yOffset); + } + + public static Field add(Field a, Field b) { + return (x, y) -> a.compute(x, y) + b.compute(x, y); + } + + public static Field multiply(Field a, Field b) { + return (x, y) -> a.compute(x, y) * b.compute(x, y); + } + + public static Field add(Field... functions) { + return (x, y) -> { + double sum = 0; + for (Field function : functions) { + sum += function.compute(x, y); + } + return sum; + }; + } + + public static Field multiply(Field... functions) { + return (x, y) -> { + double product = 1; + for (Field function : functions) { + product *= function.compute(x, y); + } + return product; + }; + } + + public static Field tweak(Field f, double scale, double amplitude, double bias) { + return (x, y) -> f.compute(x / scale, y / scale) * amplitude + bias; + } + + public static Field tweak(Field f, double scale, double amplitude) { + return tweak(f, scale, amplitude, 0); + } + + public static Field scale(Field f, double scale) { + return tweak(f, scale, 1, 0); + } + + public static Field amplify(Field f, double amplitude) { + return tweak(f, 1, amplitude, 0); + } + + public static Field bias(Field f, double bias) { + return tweak(f, 1, 1, bias); + } + + public static Field octaves(Field f, double scaleFactor, double amplitudeFactor, int octaves) { + return (x, y) -> { + double result = 0; + + double scale = 1; + double amplitude = 1; + + for (int i = 0; i < octaves; ++i) { + result += f.compute(x * scale, y * scale) * amplitude; + scale *= scaleFactor; + amplitude /= amplitudeFactor; + } + + return result; + }; + } + + public static Field octaves(Field f, double factor, int octaves) { + return octaves(f, factor, factor, octaves); + } + + public static Field squash(Field f, double slope) { + return (x, y) -> 1 / (1 + Math.exp(-slope * f.compute(x, y))); + } + + public static Field ridge(Field f) { + return (x, y) -> 1 - Math.abs(f.compute(x, y)); + } + + public static Field clamp(Field f, double min, double max) { + return (x, y) -> Math.min(Math.max(f.compute(x, y), min), max); + } + + public static Field withMin(Field f, double min) { + return (x, y) -> Math.max(f.compute(x, y), min); + } + + public static Field withMax(Field f, double max) { + return (x, y) -> Math.min(f.compute(x, y), max); + } + + public static Field select(Field f, double target, double width) { + return (x, y) -> { + double value = f.compute(x, y); + if (value < target - width) { + return 0; + } else if (value < target) { + return (width - (target - value)) / width; + } else if (value < target + width) { + return (width - (value - target)) / width; + } else { + return 0; + } + }; + } + + public static Field selectPositive(Field f, double target, double width) { + return (x, y) -> { + double value = f.compute(x, y); + if (value < target - width) { + return 0; + } else if (value < target + width) { + return (width - (target - value)) / (2*width); + } else { + return 1; + } + }; + } + + public static Field selectNegative(Field f, double target, double width) { + return (x, y) -> { + double value = target - f.compute(x, y); + if (value < target - width) { + return 0; + } else if (value < target + width) { + return (width - (target - value)) / (2*width); + } else { + return 1; + } + }; + } + + public static Field cliff(Field f, double target, double featureWidth, double slopeWidth) { + return (x, y) -> { + double value = f.compute(x, y); + + if (value < target - featureWidth) { + return 0; + } else if (value < target - slopeWidth) { + double t = (value - (target - featureWidth)) / (featureWidth - slopeWidth); + return -0.5 + Math.cos(t * Math.PI) / 2; + } else if (value < target + slopeWidth) { + double t = (value - (target - slopeWidth)) / (2 * slopeWidth); + return -Math.cos(t * Math.PI); + } else if (value < target + featureWidth) { + double t = (value - (target + slopeWidth)) / (featureWidth - slopeWidth); + return +0.5 + Math.cos(t * Math.PI) / 2; + } else { + return 0; + } + }; + } + +} diff --git a/src/main/java/ru/windcorp/progressia/test/gen/MultiblockVegetationFeature.java b/src/main/java/ru/windcorp/progressia/test/gen/MultiblockVegetationFeature.java new file mode 100644 index 0000000..5cfcc43 --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/test/gen/MultiblockVegetationFeature.java @@ -0,0 +1,148 @@ +/* + * 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; + +import java.util.Set; +import java.util.function.Consumer; + +import com.google.common.collect.ImmutableSet; + +import glm.vec._3.i.Vec3i; +import kdotjpg.opensimplex2.areagen.OpenSimplex2S; +import ru.windcorp.progressia.common.util.VectorUtil; +import ru.windcorp.progressia.common.world.block.BlockData; +import ru.windcorp.progressia.common.world.rels.RelFace; +import ru.windcorp.progressia.server.world.generation.surface.SurfaceFloatField; +import ru.windcorp.progressia.server.world.generation.surface.SurfaceTopLayerFeature; +import ru.windcorp.progressia.server.world.generation.surface.context.SurfaceBlockContext; +import ru.windcorp.progressia.server.world.generation.surface.context.SurfaceWorldContext; + +public abstract class MultiblockVegetationFeature extends SurfaceTopLayerFeature { + + private final SurfaceFloatField selector; + private final OpenSimplex2S wavinessGenerator = new OpenSimplex2S(0); + + private final double maximumDensity; + + private final Set soilWhitelist; + + public MultiblockVegetationFeature(String id, SurfaceFloatField selector, double minimumPeriod) { + super(id); + this.selector = selector; + this.maximumDensity = 1 / minimumPeriod; + + ImmutableSet.Builder soilWhitelistBuilder = ImmutableSet.builder(); + createSoilWhitelist(soilWhitelistBuilder::add); + this.soilWhitelist = soilWhitelistBuilder.build(); + } + + protected void createSoilWhitelist(Consumer output) { + output.accept("Test:Dirt"); + } + + @Override + protected void processTopBlock(SurfaceBlockContext context) { + Vec3i location = context.getLocation(); + + if (location.z < 0) { + return; + } + + if (!soilWhitelist.isEmpty() && !soilWhitelist.contains(context.getBlock().getId())) { + return; + } + + double selectorValue = selector.get(context); + double chance = selectorValue * maximumDensity; + if (context.getRandom().nextDouble() >= chance) { + return; + } + + grow(context, selectorValue); + } + + protected abstract void grow(SurfaceBlockContext context, double selectorValue); + + @Override + protected boolean isSolid(SurfaceBlockContext context) { + return context.logic().getBlock().isSolid(RelFace.UP); + } + + /* + * Utilities + */ + + protected void setLeaves(SurfaceWorldContext context, Vec3i location, BlockData leaves) { + if (context.getBlock(location).getId().equals("Test:Air")) { + context.setBlock(location, leaves); + } + } + + protected void iterateBlob( + Vec3i center, + double horDiameter, + double vertDiameter, + double wavinessAmplitude, + double wavinessScale, + Consumer action + ) { + VectorUtil.iterateCuboidAround( + 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, + pos -> { + + double sx = (pos.x - center.x) / horDiameter; + double sy = (pos.y - center.y) / horDiameter; + double sz = (pos.z - center.z) / vertDiameter; + + double radius = 1; + + if (wavinessAmplitude > 0) { + radius += wavinessAmplitude * wavinessGenerator.noise3_Classic( + sx / wavinessScale, + sy / wavinessScale, + sz / wavinessScale + ); + } + + if (sx * sx + sy * sy + sz * sz <= radius * radius) { + action.accept(pos); + } + + } + ); + } + + protected void iterateSpheroid( + Vec3i center, + double horDiameter, + double vertDiameter, + Consumer action + ) { + iterateBlob(center, horDiameter, vertDiameter, 0, 0, action); + } + + protected void iterateSphere(Vec3i center, double diameter, Consumer action) { + iterateBlob(center, diameter, diameter, 0, 0, action); + } + +} diff --git a/src/main/java/ru/windcorp/progressia/test/gen/TestBushFeature.java b/src/main/java/ru/windcorp/progressia/test/gen/TestBushFeature.java new file mode 100644 index 0000000..ca2765c --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/test/gen/TestBushFeature.java @@ -0,0 +1,49 @@ +/* + * 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; + +import glm.vec._3.i.Vec3i; +import ru.windcorp.progressia.common.world.block.BlockData; +import ru.windcorp.progressia.common.world.block.BlockDataRegistry; +import ru.windcorp.progressia.server.world.generation.surface.SurfaceFloatField; +import ru.windcorp.progressia.server.world.generation.surface.context.SurfaceBlockContext; + +public class TestBushFeature extends MultiblockVegetationFeature { + + private final BlockData trunk = BlockDataRegistry.getInstance().get("Test:Log"); + private final BlockData leaves = BlockDataRegistry.getInstance().get("Test:TemporaryLeaves"); + + public TestBushFeature(String id, SurfaceFloatField selector) { + super(id, selector, 7 * 7); + } + + @Override + protected void grow(SurfaceBlockContext context, double selectorValue) { + double size = selectorValue * randomDouble(context, 0.8, 1.2); + + Vec3i center = context.getLocation().add_(0, 0, 1); + + context.setBlock(center, trunk); + context.setBlock(center.add_(0, 0, 1), leaves); + + iterateBlob(center, stretch(size, 1.3, 2.5), stretch(size, 0.6, 1.5), 0.7, 2, p -> { + setLeaves(context, p, leaves); + }); + } + +} diff --git a/src/main/java/ru/windcorp/progressia/test/gen/TestGenerationConfig.java b/src/main/java/ru/windcorp/progressia/test/gen/TestGenerationConfig.java new file mode 100644 index 0000000..b4ed652 --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/test/gen/TestGenerationConfig.java @@ -0,0 +1,118 @@ +/* + * 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; + +import static ru.windcorp.progressia.test.gen.Fields.*; + +import java.util.ArrayList; +import java.util.List; +import java.util.function.Function; + +import ru.windcorp.progressia.common.Units; +import ru.windcorp.progressia.common.util.ArrayFloatRangeMap; +import ru.windcorp.progressia.common.util.FloatRangeMap; +import ru.windcorp.progressia.common.world.Coordinates; +import ru.windcorp.progressia.common.world.block.BlockData; +import ru.windcorp.progressia.common.world.block.BlockDataRegistry; +import ru.windcorp.progressia.server.Server; +import ru.windcorp.progressia.server.world.generation.WorldGenerator; +import ru.windcorp.progressia.server.world.generation.planet.Planet; +import ru.windcorp.progressia.server.world.generation.planet.PlanetGenerator; +import ru.windcorp.progressia.server.world.generation.surface.SurfaceFeature; +import ru.windcorp.progressia.server.world.generation.surface.SurfaceFloatField; +import ru.windcorp.progressia.server.world.generation.surface.TerrainLayer; + +public class TestGenerationConfig { + + private static final float PLANET_RADIUS = Units.get("0.5 km"); + private static final float SURFACE_GRAVITY = Units.get("9.8 m/s^2"); + 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("No bugs please".hashCode()); + + public static Function createGenerator() { + + Planet planet = new Planet( + ((int) PLANET_RADIUS) / Coordinates.CHUNK_SIZE, + SURFACE_GRAVITY, + CURVATURE, + INNER_RADIUS + ); + + TestHeightMap heightMap = new TestHeightMap(planet, planet.getRadius() / 4, FIELDS); + + FloatRangeMap layers = new ArrayFloatRangeMap<>(); + registerTerrainLayers(layers); + + List features = new ArrayList<>(); + registerFeatures(features); + + return server -> new PlanetGenerator("Test:PlanetGenerator", server, planet, heightMap, layers, features); + + } + + private static void registerTerrainLayers(FloatRangeMap layers) { + BlockData granite = BlockDataRegistry.getInstance().get("Test:GraniteMonolith"); + BlockData graniteCracked = BlockDataRegistry.getInstance().get("Test:GraniteCracked"); + BlockData graniteGravel = BlockDataRegistry.getInstance().get("Test:GraniteGravel"); + + BlockData dirt = BlockDataRegistry.getInstance().get("Test:Dirt"); + BlockData air = BlockDataRegistry.getInstance().get("Test:Air"); + + SurfaceFloatField cliffs = FIELDS.get("Test:CliffSelector"); + + layers.put(Float.NEGATIVE_INFINITY, 0, (f, n, w, d, r) -> air); + layers.put(0, 4, (f, n, w, d, r) -> { + if (cliffs.get(f, n, w) > 0) { + switch (r.nextInt(4)) { + case 0: + return granite; + case 1: + return graniteCracked; + default: + return graniteGravel; + } + } else { + return dirt; + } + }); + layers.put(4, Float.POSITIVE_INFINITY, (f, n, w, d, r) -> granite); + } + + private static void registerFeatures(List features) { + + SurfaceFloatField forestiness = FIELDS.register( + "Test:Forestiness", + () -> squash(scale(FIELDS.primitive(), 200), 5) + ); + + SurfaceFloatField floweriness = FIELDS.register( + "Test:Floweriness", + f -> multiply( + scale(octaves(FIELDS.primitive(), 2, 2), 40), + tweak(FIELDS.get("Test:Forestiness", f), 1, -1, 1.1) + ) + ); + + features.add(new TestBushFeature("Test:BushFeature", forestiness)); + features.add(new TestTreeFeature("Test:TreeFeature", forestiness)); + features.add(new TestGrassFeature("Test:GrassFeature", FIELDS.get("Test:CliffSelector"), floweriness)); + } + +} diff --git a/src/main/java/ru/windcorp/progressia/test/gen/TestGrassFeature.java b/src/main/java/ru/windcorp/progressia/test/gen/TestGrassFeature.java new file mode 100644 index 0000000..d1d73e5 --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/test/gen/TestGrassFeature.java @@ -0,0 +1,122 @@ +/* + * 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; + +import java.util.List; +import java.util.Set; + +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableSet; + +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.generation.surface.SurfaceFloatField; +import ru.windcorp.progressia.server.world.generation.surface.SurfaceTopLayerFeature; +import ru.windcorp.progressia.server.world.generation.surface.context.SurfaceBlockContext; + +public class TestGrassFeature extends SurfaceTopLayerFeature { + + private static final Set WHITELIST = ImmutableSet.of( + "Test:Dirt", + "Test:Stone", + "Test:GraniteMonolith", + "Test:GraniteCracked", + "Test:GraniteGravel" + ); + + private final SurfaceFloatField grassiness; + private final SurfaceFloatField floweriness; + private final double scatterDensity = 1.0 / (3*3); + + private final TileData grass = TileDataRegistry.getInstance().get("Test:Grass"); + private final List flowers = ImmutableList.of( + TileDataRegistry.getInstance().get("Test:YellowFlowers") + ); + private final List scatter = ImmutableList.of( + TileDataRegistry.getInstance().get("Test:Stones"), + TileDataRegistry.getInstance().get("Test:Sand") + ); + + public TestGrassFeature(String id, SurfaceFloatField grassiness, SurfaceFloatField floweriness) { + super(id); + this.grassiness = grassiness; + this.floweriness = floweriness; + } + + @Override + protected void processTopBlock(SurfaceBlockContext context) { + if (context.getLocation().z < 0) { + return; + } + if (!WHITELIST.contains(context.getBlock().getId())) { + return; + } + + if (!context.pushRelative(RelFace.UP).logic().getBlock().isTransparent()) { + context.pop(); + return; + } + context.pop(); + + double grassiness = this.grassiness.get(context); + if (grassiness < 0.2) { + growGrass(context); + } + + placeScatter(context); + + if (grassiness < 0.2) { + growFlowers(context); + } + } + + private void placeScatter(SurfaceBlockContext context) { + if (context.getRandom().nextDouble() < scatterDensity) { + TileData tile = pickRandom(context, scatter); + context.addTile(RelFace.UP, tile); + } + } + + private void growGrass(SurfaceBlockContext context) { + for (RelFace face : RelFace.getFaces()) { + if (face == RelFace.DOWN) continue; + + if (context.pushRelative(face).logic().getBlock().isTransparent()) { + context.pop(); + context.addTile(face, grass); + } else { + context.pop(); + } + + } + } + + private void growFlowers(SurfaceBlockContext context) { + if (context.getRandom().nextDouble() < floweriness.get(context)) { + TileData tile = pickRandom(context, flowers); + context.addTile(RelFace.UP, tile); + } + } + + @Override + protected boolean isSolid(SurfaceBlockContext context) { + return context.logic().getBlock().isSolid(RelFace.UP); + } + +} diff --git a/src/main/java/ru/windcorp/progressia/test/gen/TestHeightMap.java b/src/main/java/ru/windcorp/progressia/test/gen/TestHeightMap.java new file mode 100644 index 0000000..c09aec1 --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/test/gen/TestHeightMap.java @@ -0,0 +1,79 @@ +/* + * 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; + +import static ru.windcorp.progressia.test.gen.Fields.*; + +import ru.windcorp.progressia.common.world.rels.AbsFace; +import ru.windcorp.progressia.server.world.generation.planet.Planet; +import ru.windcorp.progressia.server.world.generation.surface.SurfaceFloatField; + +public class TestHeightMap implements SurfaceFloatField { + + private final SurfaceFloatField shape; + + public TestHeightMap( + Planet planet, + float cutoffThickness, + Fields fields + ) { + + for (AbsFace face : AbsFace.getFaces()) { + + Field landmassDistribution = scale(octaves(fields.primitive(), 2, 5), 400); + Field landmasses = tweak(squash(landmassDistribution, 4), 1, 20, -20); + + Field plainsSelector = squash(withMin(landmassDistribution, 0), 10); + Field plains = tweak(octaves(fields.primitive(), 2, 3), 100, 3); + + Field randomCliffSelector = scale(fields.primitive(), 200); + randomCliffSelector = add( + select(randomCliffSelector, +0.7, 0.3), + amplify(select(randomCliffSelector, -0.7, 0.3), -1) + ); + Field randomCliffs = octaves(scale(fields.primitive(), 300), 3, 5); + + Field shoreCliffSelector = withMin(scale(fields.primitive(), 200), 0); + Field shoreCliffs = add( + landmassDistribution, + tweak(octaves(fields.primitive(), 2, 3), 50, 0.2) + ); + + fields.register("Test:CliffSelector", face, multiply( + shoreCliffSelector, + bias(select(shoreCliffs, 0, 0.07), 0) + )); + + fields.register("Test:Height", face, cutoff(add( + landmasses, + multiply(plains, plainsSelector), + multiply(amplify(cliff(randomCliffs, 0, 0.5, 0.03), 10), randomCliffSelector), + multiply(tweak(cliff(shoreCliffs, 0, 0.5, 0.03), 1, 15, 15), shoreCliffSelector) + ), planet, cutoffThickness)); + + } + + this.shape = fields.get("Test:Height"); + } + + @Override + public float get(AbsFace face, float x, float y) { + return (float) shape.get(face, x, y); + } + +} diff --git a/src/main/java/ru/windcorp/progressia/test/gen/TestTerrainGenerator.java b/src/main/java/ru/windcorp/progressia/test/gen/TestTerrainGenerator.java deleted file mode 100644 index 8112105..0000000 --- a/src/main/java/ru/windcorp/progressia/test/gen/TestTerrainGenerator.java +++ /dev/null @@ -1,152 +0,0 @@ -/* - * 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; - -import kdotjpg.opensimplex2.areagen.OpenSimplex2S; -import ru.windcorp.progressia.server.world.DefaultWorldLogic; - -class TestTerrainGenerator { - - @FunctionalInterface - private interface Func2D { - double compute(double x, double y); - } - - private final OpenSimplex2S noise; - private final Func2D shape; - - public TestTerrainGenerator(TestWorldGenerator testWorldGenerator, DefaultWorldLogic world) { - this.noise = new OpenSimplex2S("We're getting somewhere".hashCode()); - - Func2D plainsHeight = tweak( - octaves( - tweak(primitive(), 0.01, 0.5), - 2, - 3 - ), - 1, - 0.2, - 0.2 - ); - - Func2D mountainsHeight = tweak( - octaves( - ridge(tweak(primitive(), 0.01, 1)), - 2, - 1.5, - 12 - ), - 1, - 3 - ); - - Func2D mountainousity = tweak( - octaves( - tweak(primitive(), 0.007, 1), - 2, - 3 - ), - 1, - 1, - -0.25 - ); - - shape = tweak( - add(multiply(squash(mountainousity, 10), mountainsHeight), plainsHeight), - 0.001, - 1000, - 0 - ); - } - - public void compute(int startX, int startY, double[][] heightMap, double[][] slopeMap) { - for (int x = 0; x < heightMap.length; ++x) { - for (int y = 0; y < heightMap.length; ++y) { - heightMap[x][y] = shape.compute(x + startX, y + startY); - slopeMap[x][y] = computeSlope(shape, x + startX, y + startY, heightMap[x][y]); - } - } - } - - private double computeSlope(Func2D f, double x0, double y0, double f0) { - double di = 0.5; - - double dfdx = (f.compute(x0 + di, y0) - f0) / di; - double dfdy = (f.compute(x0, y0 + di) - f0) / di; - - return Math.hypot(dfdx, dfdy); - } - - /* - * Utility functions - */ - - private Func2D primitive() { - return noise::noise2; - } - - private Func2D add(Func2D a, Func2D b) { - return (x, y) -> a.compute(x, y) + b.compute(x, y); - } - - private Func2D multiply(Func2D a, Func2D b) { - return (x, y) -> a.compute(x, y) * b.compute(x, y); - } - - private Func2D tweak(Func2D f, double scale, double amplitude, double bias) { - return (x, y) -> f.compute(x * scale, y * scale) * amplitude + bias; - } - - private Func2D tweak(Func2D f, double scale, double amplitude) { - return tweak(f, scale, amplitude, 0); - } - - private Func2D octaves(Func2D f, double scaleFactor, double amplitudeFactor, int octaves) { - return (x, y) -> { - double result = 0; - - double scale = 1; - double amplitude = 1; - - for (int i = 0; i < octaves; ++i) { - result += f.compute(x * scale, y * scale) * amplitude; - scale *= scaleFactor; - amplitude /= amplitudeFactor; - } - - return result; - }; - } - - private Func2D octaves(Func2D f, double factor, int octaves) { - return octaves(f, factor, factor, octaves); - } - - private Func2D squash(Func2D f, double slope) { - return (x, y) -> 1 / (1 + Math.exp(-slope * f.compute(x, y))); - } - - private Func2D ridge(Func2D f) { - return (x, y) -> { - double result = 1 - Math.abs(f.compute(x, y)); - return result * result; - }; - } - -} diff --git a/src/main/java/ru/windcorp/progressia/test/gen/TestTreeFeature.java b/src/main/java/ru/windcorp/progressia/test/gen/TestTreeFeature.java new file mode 100644 index 0000000..d08862e --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/test/gen/TestTreeFeature.java @@ -0,0 +1,69 @@ +/* + * 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; + +import glm.vec._3.i.Vec3i; +import ru.windcorp.progressia.common.world.block.BlockData; +import ru.windcorp.progressia.common.world.block.BlockDataRegistry; +import ru.windcorp.progressia.server.world.generation.surface.SurfaceFloatField; +import ru.windcorp.progressia.server.world.generation.surface.context.SurfaceBlockContext; + +public class TestTreeFeature extends MultiblockVegetationFeature { + + private final BlockData trunk = BlockDataRegistry.getInstance().get("Test:Log"); + private final BlockData leaves = BlockDataRegistry.getInstance().get("Test:TemporaryLeaves"); + + public TestTreeFeature(String id, SurfaceFloatField selector) { + super(id, selector, 10 * 10); + } + + @Override + protected void grow(SurfaceBlockContext context, double selectorValue) { + + Vec3i start = context.getLocation().add_(0, 0, 1); + Vec3i center = start.add_(0); + + double size = selectorValue * randomDouble(context, 0.8, 1.2); + + int height = (int) stretch(size, 3, 7); + for (; center.z < start.z + height; ++center.z) { + context.setBlock(center, trunk); + } + + double branchHorDistance = 0; + + do { + double branchSize = 0.5 + randomDouble(context, 1, 2) * size; + double branchHorAngle = randomDouble(context, 0, 2 * Math.PI); + int branchVertOffset = (int) randomDouble(context, -2, 0); + + Vec3i branchCenter = center.add_( + (int) (Math.sin(branchHorAngle) * branchHorDistance), + (int) (Math.cos(branchHorAngle) * branchHorDistance), + branchVertOffset + ); + + iterateBlob(branchCenter, 1 * branchSize, 2.3 * branchSize, 0.5, 3, p -> { + setLeaves(context, p, leaves); + }); + + branchHorDistance = randomDouble(context, 0.7, 1.5); + } while (context.getRandom().nextInt(8) > 1); + } + +} diff --git a/src/main/java/ru/windcorp/progressia/test/gen/TestWorldGenerator.java b/src/main/java/ru/windcorp/progressia/test/gen/TestWorldGenerator.java deleted file mode 100644 index 75d4eb0..0000000 --- a/src/main/java/ru/windcorp/progressia/test/gen/TestWorldGenerator.java +++ /dev/null @@ -1,400 +0,0 @@ -/* - * 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; - -import java.io.DataInputStream; -import java.io.DataOutputStream; -import java.io.IOException; -import java.util.Random; - -import glm.vec._3.Vec3; -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.world.DefaultChunkData; -import ru.windcorp.progressia.common.world.Coordinates; -import ru.windcorp.progressia.common.world.DecodingException; -import ru.windcorp.progressia.common.world.DefaultWorldData; -import ru.windcorp.progressia.common.world.WorldDataListener; -import ru.windcorp.progressia.common.world.block.BlockData; -import ru.windcorp.progressia.common.world.block.BlockDataRegistry; -import ru.windcorp.progressia.common.world.rels.AbsFace; -import ru.windcorp.progressia.common.world.tile.TileData; -import ru.windcorp.progressia.common.world.tile.TileDataRegistry; -import ru.windcorp.progressia.server.Server; -import ru.windcorp.progressia.server.world.generation.AbstractWorldGenerator; - -public class TestWorldGenerator extends AbstractWorldGenerator { - - private final TestTerrainGenerator terrainGen; - - public TestWorldGenerator(Server server) { - super("Test:WorldGenerator", server, Boolean.class, "Test:TheGravityModel"); - this.terrainGen = new TestTerrainGenerator(this, server.getWorld()); - - getWorldData().addListener(new WorldDataListener() { - @Override - public void onChunkLoaded(DefaultWorldData world, DefaultChunkData chunk) { - findAndPopulate(chunk.getPosition(), world); - } - }); - } - - @Override - public Vec3 suggestSpawnLocation() { - return new Vec3(8, 8, 880); - } - - @Override - protected Boolean doReadGenerationHint(DataInputStream input) throws IOException, DecodingException { - return input.readBoolean(); - } - - @Override - protected void doWriteGenerationHint(DataOutputStream output, Boolean hint) throws IOException { - output.writeBoolean(hint); - } - - @Override - protected boolean checkIsChunkReady(Boolean hint) { - return hint; - } - - @Override - public DefaultChunkData generate(Vec3i chunkPos) { - DefaultChunkData chunk = generateUnpopulated(chunkPos, getWorldData()); - getWorldData().addChunk(chunk); - return chunk; - } - - private DefaultChunkData generateUnpopulated(Vec3i chunkPos, DefaultWorldData world) { - DefaultChunkData chunk = new DefaultChunkData(chunkPos, world); - chunk.setGenerationHint(false); - - final int bpc = DefaultChunkData.BLOCKS_PER_CHUNK; - Random random = new Random(chunkPos.x + chunkPos.y + chunkPos.z); - - BlockData dirt = BlockDataRegistry.getInstance().get("Test:Dirt"); - BlockData stone = BlockDataRegistry.getInstance().get("Test:Stone"); - BlockData air = BlockDataRegistry.getInstance().get("Test:Air"); - - BlockData[] granites = new BlockData[] { - BlockDataRegistry.getInstance().get("Test:GraniteGravel"), - BlockDataRegistry.getInstance().get("Test:GraniteGravel"), - BlockDataRegistry.getInstance().get("Test:GraniteCracked"), - BlockDataRegistry.getInstance().get("Test:GraniteMonolith") - }; - - double[][] heightMap = new double[bpc][bpc]; - double[][] gradMap = new double[bpc][bpc]; - - int startX = Coordinates.getInWorld(chunk.getX(), 0); - int startY = Coordinates.getInWorld(chunk.getY(), 0); - int startZ = Coordinates.getInWorld(chunk.getZ(), 0); - - terrainGen.compute(startX, startY, heightMap, gradMap); - - VectorUtil.iterateCuboid(0, 0, 0, bpc, bpc, bpc, pos -> { - double layer = pos.z - heightMap[pos.x][pos.y] + startZ; - - if (layer < -4) { - chunk.setBlock(pos, stone, false); - } else if (layer < 0) { - if (gradMap[pos.x][pos.y] > 0.5) { - BlockData granite = granites[random.nextInt(4)]; - chunk.setBlock(pos, granite, false); - } else { - chunk.setBlock(pos, dirt, false); - } - } else { - chunk.setBlock(pos, air, false); - } - }); - - return chunk; - } - - private void findAndPopulate(Vec3i changePos, DefaultWorldData world) { - VectorUtil.iterateCuboidAround(changePos, 3, candidatePos -> { - if (canBePopulated(candidatePos, world)) { - populate(candidatePos, world); - } - }); - } - - private boolean canBePopulated(Vec3i candidatePos, DefaultWorldData world) { - Vec3i cursor = Vectors.grab3i(); - - DefaultChunkData candidate = world.getChunk(candidatePos); - if (candidate == null || isChunkReady(candidate.getGenerationHint())) - return false; - - for (int dx = -1; dx <= 1; ++dx) { - cursor.x = candidatePos.x + dx; - for (int dy = -1; dy <= 1; ++dy) { - cursor.y = candidatePos.y + dy; - for (int dz = -1; dz <= 1; ++dz) { - - if ((dx | dy | dz) == 0) - continue; - - cursor.z = candidatePos.z + dz; - - DefaultChunkData chunk = world.getChunk(cursor); - if (chunk == null) { - return false; - } - - } - } - } - - Vectors.release(cursor); - return true; - } - - private void populate(Vec3i chunkPos, DefaultWorldData world) { - Random random = new Random(chunkPos.x + chunkPos.y + chunkPos.z); - - DefaultChunkData chunk = world.getChunk(chunkPos); - assert chunk != null : "Something went wrong when populating chunk at (" + chunkPos.x + "; " + chunkPos.y + "; " - + chunkPos.z + ")"; - - BlockData air = BlockDataRegistry.getInstance().get("Test:Air"); - BlockData dirt = BlockDataRegistry.getInstance().get("Test:Dirt"); - - Vec3i biw = new Vec3i(); - - int minX = chunk.getMinX(); - int maxX = chunk.getMaxX() + 1; - int minY = chunk.getMinY(); - int maxY = chunk.getMaxY() + 1; - int minZ = chunk.getMinZ(); - int maxZ = chunk.getMaxZ() + 1; - - final int bpc = DefaultChunkData.BLOCKS_PER_CHUNK; - double[][] heightMap = new double[bpc][bpc]; - double[][] gradMap = new double[bpc][bpc]; - - terrainGen.compute(minX, minY, heightMap, gradMap); - - for (biw.x = minX; biw.x < maxX; ++biw.x) { - for (biw.y = minY; biw.y < maxY; ++biw.y) { - - for (biw.z = minZ; biw.z < maxZ + 1 && world.getBlock(biw) != air; ++biw.z) - ; - biw.z -= 1; - - if (biw.z == maxZ) - continue; - if (biw.z < minZ) - continue; - - int xic = Coordinates.convertInWorldToInChunk(biw.x); - int yic = Coordinates.convertInWorldToInChunk(biw.y); - - addTiles( - chunk, - biw, - world, - random, - world.getBlock(biw) == dirt, - heightMap[xic][yic], - gradMap[xic][yic] - ); - - } - } - - chunk.setGenerationHint(true); - } - - private void addTiles( - DefaultChunkData chunk, - Vec3i biw, - DefaultWorldData world, - Random random, - boolean isDirt, - double height, - double grad - ) { - if (isDirt) - addGrass(chunk, biw, world, random); - addDecor(chunk, biw, world, random, isDirt); - addSnow(chunk, biw, world, random, isDirt, height, grad); - } - - private void addGrass(DefaultChunkData chunk, Vec3i biw, DefaultWorldData world, Random random) { - BlockData air = BlockDataRegistry.getInstance().get("Test:Air"); - TileData grass = TileDataRegistry.getInstance().get("Test:Grass"); - - world.getTiles(biw, AbsFace.POS_Z).add(grass); - - for (AbsFace face : AbsFace.getFaces()) { - if (face.getVector().z != 0) - continue; - biw.add(face.getVector()); - - if (world.getBlock(biw) == air) { - biw.sub(face.getVector()); - world.getTiles(biw, face).add(grass); - } else { - biw.sub(face.getVector()); - } - } - } - - private void addDecor(DefaultChunkData chunk, Vec3i biw, DefaultWorldData world, Random random, boolean isDirt) { - if (isDirt) { - if (random.nextInt(8) == 0) { - world.getTiles(biw, AbsFace.POS_Z).addFarthest( - TileDataRegistry.getInstance().get("Test:Sand") - ); - } - - if (random.nextInt(8) == 0) { - world.getTiles(biw, AbsFace.POS_Z).addFarthest( - TileDataRegistry.getInstance().get("Test:Stones") - ); - } - - if (random.nextInt(8) == 0) { - world.getTiles(biw, AbsFace.POS_Z).addFarthest( - TileDataRegistry.getInstance().get("Test:YellowFlowers") - ); - } - } else { - if (random.nextInt(2) == 0) { - world.getTiles(biw, AbsFace.POS_Z).addFarthest( - TileDataRegistry.getInstance().get("Test:Stones") - ); - } - } - } - - private void addSnow( - DefaultChunkData chunk, - Vec3i biw, - DefaultWorldData world, - Random random, - boolean isDirt, - double height, - double grad - ) { - if (height < 1500) - return; - - BlockData air = BlockDataRegistry.getInstance().get("Test:Air"); - - double quarterChance = computeSnowQuarterChance(height, grad); - double halfChance = computeSnowHalfChance(height, grad); - double opaqueChance = computeSnowOpaqueChance(height, grad); - - for (AbsFace face : AbsFace.getFaces()) { - if (face == AbsFace.NEG_Z) - continue; - - if (face.getVector().z == 0) { - biw.add(face.getVector()); - BlockData neighbour = world.getBlock(biw); - biw.sub(face.getVector()); - - if (neighbour != air) - continue; - } - - TileData tile; - - double maxValue = height > 3000 ? 3 : (1 + 2 * ((height - 1500) / 1500)); - double value = random.nextDouble() * maxValue; - if (value < quarterChance) { - tile = TileDataRegistry.getInstance().get("Test:SnowQuarter"); - } else if ((value -= quarterChance) < halfChance) { - tile = TileDataRegistry.getInstance().get("Test:SnowHalf"); - } else if ((value -= halfChance) < opaqueChance) { - tile = TileDataRegistry.getInstance().get("Test:SnowOpaque"); - } else { - tile = null; - } - - if (tile != null) { - world.getTiles(biw, face).addFarthest(tile); - } - } - } - - private double computeSnowQuarterChance(double height, double grad) { - double heightCoeff; - - if (height < 1500) - heightCoeff = 0; - else if (height < 2000) - heightCoeff = (height - 1500) / 500; - else - heightCoeff = 1; - - if (heightCoeff < 1e-4) - return 0; - - double gradCoeff = computeSnowGradCoeff(height, grad); - return heightCoeff * gradCoeff; - } - - private double computeSnowHalfChance(double height, double grad) { - double heightCoeff; - - if (height < 2000) - heightCoeff = 0; - else if (height < 2500) - heightCoeff = (height - 2000) / 500; - else - heightCoeff = 1; - - if (heightCoeff < 1e-4) - return 0; - - double gradCoeff = computeSnowGradCoeff(height, grad); - return heightCoeff * gradCoeff; - } - - private double computeSnowOpaqueChance(double height, double grad) { - double heightCoeff; - - if (height < 2500) - heightCoeff = 0; - else if (height < 3000) - heightCoeff = (height - 2500) / 500; - else - heightCoeff = 1; - - if (heightCoeff < 1e-4) - return 0; - - double gradCoeff = computeSnowGradCoeff(height, grad); - return heightCoeff * gradCoeff; - } - - private double computeSnowGradCoeff(double height, double grad) { - final double a = -0.00466666666666667; - final double b = 12.66666666666667; - double characteristicGrad = 1 / (a * height + b); - return Math.exp(-grad / characteristicGrad); - } - -} diff --git a/src/main/java/ru/windcorp/progressia/test/gen/planet/TestHeightMap.java b/src/main/java/ru/windcorp/progressia/test/gen/planet/TestHeightMap.java deleted file mode 100644 index 2141c63..0000000 --- a/src/main/java/ru/windcorp/progressia/test/gen/planet/TestHeightMap.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * 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.planet; - -import ru.windcorp.progressia.common.world.rels.AbsFace; -import ru.windcorp.progressia.test.gen.surface.SurfaceFloatField; - -public class TestHeightMap implements SurfaceFloatField { - - private final float cutoffPoint; - private final float cutoffDistance; - private final float amplitude; - private final float characteristicSize; - - public TestHeightMap( - float cutoffPoint, - float cutoffDistance, - float amplitude, - float characteristicSize - ) { - this.cutoffPoint = cutoffPoint; - this.cutoffDistance = cutoffDistance; - this.amplitude = amplitude; - this.characteristicSize = characteristicSize; - } - - @Override - public float get(AbsFace face, float north, float west) { - double cutoffCoefficient = 1; - cutoffCoefficient *= cutoffFunction(cutoffPoint - north); - cutoffCoefficient *= cutoffFunction(cutoffPoint + north); - cutoffCoefficient *= cutoffFunction(cutoffPoint - west); - cutoffCoefficient *= cutoffFunction(cutoffPoint + west); - - if (cutoffCoefficient == 0) { - return 0; - } - - double base = Math.sin(north / characteristicSize) * Math.sin(west / characteristicSize); - base *= amplitude; - - return (float) (base * cutoffCoefficient); - } - - private double cutoffFunction(float distanceToCutoffPoint) { - if (distanceToCutoffPoint < 0) { - return 0; - } else if (distanceToCutoffPoint < cutoffDistance) { - return (1 - Math.cos(Math.PI * distanceToCutoffPoint / cutoffDistance)) / 2; - } else { - return 1; - } - } - -} 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 deleted file mode 100644 index 01a98f0..0000000 --- a/src/main/java/ru/windcorp/progressia/test/gen/surface/SurfaceCachingFloatField.java +++ /dev/null @@ -1,77 +0,0 @@ -/* - * 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 deleted file mode 100644 index f1decd4..0000000 --- a/src/main/java/ru/windcorp/progressia/test/gen/surface/SurfaceFieldRegistry.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * 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 deleted file mode 100644 index ad1ec39..0000000 --- a/src/main/java/ru/windcorp/progressia/test/gen/surface/SurfaceNodeStorage.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * 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"); - } - -} From 6f90bf345b13f093d3298d6dec2bde9f80818f37 Mon Sep 17 00:00:00 2001 From: OLEGSHA Date: Fri, 20 Aug 2021 21:37:49 +0300 Subject: [PATCH 53/55] Incremented version and made some small changes - Version is now pre-alpha 2. Yay? - Removed compass display in the lower-left - The cross can now be hidden by pressing F1 - Does not hide LayerAbout though - Generator spawns the player in the middle of a surface rather than at its edge --- .../generation/planet/PlanetGenerator.java | 2 +- .../windcorp/progressia/test/LayerAbout.java | 2 +- .../windcorp/progressia/test/LayerTestUI.java | 62 +++---------------- 3 files changed, 10 insertions(+), 56 deletions(-) diff --git a/src/main/java/ru/windcorp/progressia/server/world/generation/planet/PlanetGenerator.java b/src/main/java/ru/windcorp/progressia/server/world/generation/planet/PlanetGenerator.java index 1d31417..b568639 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/generation/planet/PlanetGenerator.java +++ b/src/main/java/ru/windcorp/progressia/server/world/generation/planet/PlanetGenerator.java @@ -69,7 +69,7 @@ public class PlanetGenerator extends AbstractWorldGenerator { @Override public Vec3 suggestSpawnLocation() { - return new Vec3(407f, 1f, getPlanet().getRadius() + 10); + return new Vec3(7f, 1f, getPlanet().getRadius() + 10); } @Override diff --git a/src/main/java/ru/windcorp/progressia/test/LayerAbout.java b/src/main/java/ru/windcorp/progressia/test/LayerAbout.java index 7b45fd4..334b462 100644 --- a/src/main/java/ru/windcorp/progressia/test/LayerAbout.java +++ b/src/main/java/ru/windcorp/progressia/test/LayerAbout.java @@ -50,7 +50,7 @@ public class LayerAbout extends GUILayer { new Label( "Version", font, - new MutableStringLocalized("LayerAbout.Version").format("pre-alpha 1") + new MutableStringLocalized("LayerAbout.Version").format("pre-alpha 2") ) ); diff --git a/src/main/java/ru/windcorp/progressia/test/LayerTestUI.java b/src/main/java/ru/windcorp/progressia/test/LayerTestUI.java index 7962ca1..19c10aa 100755 --- a/src/main/java/ru/windcorp/progressia/test/LayerTestUI.java +++ b/src/main/java/ru/windcorp/progressia/test/LayerTestUI.java @@ -15,14 +15,13 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package ru.windcorp.progressia.test; import org.lwjgl.glfw.GLFW; import com.google.common.eventbus.Subscribe; -import glm.mat._4.Mat4; import glm.vec._4.Vec4; import ru.windcorp.progressia.client.graphics.Colors; import ru.windcorp.progressia.client.graphics.backend.GraphicsInterface; @@ -30,9 +29,6 @@ import ru.windcorp.progressia.client.graphics.flat.AssembledFlatLayer; import ru.windcorp.progressia.client.graphics.flat.RenderTarget; import ru.windcorp.progressia.client.graphics.input.KeyEvent; import ru.windcorp.progressia.client.graphics.input.bus.Input; -import ru.windcorp.progressia.client.graphics.model.LambdaModel; -import ru.windcorp.progressia.client.graphics.texture.SimpleTextures; -import ru.windcorp.progressia.client.graphics.texture.Texture; public class LayerTestUI extends AssembledFlatLayer { @@ -42,55 +38,13 @@ public class LayerTestUI extends AssembledFlatLayer { GraphicsInterface.subscribeToInputEvents(this); } - private boolean flag = false; - - private static final int SCALE = 4; - private static final int TEX_SIZE = 16 * SCALE; - private static final int TEX_SHADOW = SCALE / 2; - private static final int BORDER = 5; - private static final int HEIGHT = TEX_SIZE + 4 * BORDER; - private static final int WIDTH = HEIGHT; + private boolean drawUI = true; @Override protected void assemble(RenderTarget target) { - final int boxColor = flag ? 0xFFEE8888 : 0xFFEEEE88; - final int borderColor = flag ? 0xFFAA4444 : 0xFFAAAA44; - final int boxShadowColor = flag ? 0xFF440000 : 0xFF444400; - - int x = 2 * BORDER; - int y = 2 * BORDER; - - target.fill(x + BORDER, y - BORDER, WIDTH, HEIGHT, boxShadowColor); - target.fill(x - 1, y - 1, WIDTH + 2, HEIGHT + 2, boxShadowColor); - target.fill(x, y, WIDTH, HEIGHT, borderColor); - target.fill(x + BORDER, y + BORDER, WIDTH - 2 * BORDER, HEIGHT - 2 * BORDER, boxColor); - - target.pushTransform(new Mat4().identity().translate(x + 2 * BORDER, y + 2 * BORDER, 0)); - - final Texture compassBg = SimpleTextures.get("compass_icon"); - final Texture compassFg = SimpleTextures.get("compass_icon_arrow"); - - target.drawTexture(TEX_SHADOW, -TEX_SHADOW, TEX_SIZE, TEX_SIZE, Colors.BLACK, compassBg); - target.drawTexture(0, 0, TEX_SIZE, TEX_SIZE, compassBg); - - target.addCustomRenderer( - new LambdaModel( - LambdaModel.lambdaBuilder() - .addDynamicPart( - target.createRectagle(0, 0, TEX_SIZE, TEX_SIZE, Colors.WHITE, compassFg), - mat -> mat.translate(TEX_SIZE / 2, TEX_SIZE / 2, 0) - .rotateZ(getCompassRotation()) - .translate(-TEX_SIZE / 2, -TEX_SIZE / 2, 0) - ) - ) - ); - target.popTransform(); - - drawCross(target); - } - - private double getCompassRotation() { - return 0; + if (drawUI) { + drawCross(target); + } } private void drawCross(RenderTarget target) { @@ -138,16 +92,16 @@ public class LayerTestUI extends AssembledFlatLayer { @Override protected void handleInput(Input input) { - + // Do nothing } @Subscribe public void onKeyEvent(KeyEvent event) { - if (event.isRepeat() || event.getKey() != GLFW.GLFW_KEY_LEFT_CONTROL) { + if (!event.isPress() || event.getKey() != GLFW.GLFW_KEY_F1) { return; } - flag = event.isPress(); + drawUI = !drawUI; invalidate(); } From 4f620b72619db8d6d0fbc43ebefe9bcd105176ed Mon Sep 17 00:00:00 2001 From: IvanZ Date: Sat, 21 Aug 2021 17:44:01 +0300 Subject: [PATCH 54/55] Added 6 more types of rocks - Added black granite, dolomite, eclogite, gabbro, limestone and marble - Monolith, cracked, gravel and sand variants - Renamed Test:Granite to Test:RedGranite - Added red granite sand --- .../windcorp/progressia/test/TestContent.java | 40 +++++++++++++++--- .../test/gen/TestGenerationConfig.java | 6 +-- .../textures/blocks/BlackGraniteCracked.png | Bin 0 -> 2051 bytes .../textures/blocks/BlackGraniteGravel.png | Bin 0 -> 2078 bytes .../textures/blocks/BlackGraniteMonolith.png | Bin 0 -> 1962 bytes .../textures/blocks/BlackGraniteSand.png | Bin 0 -> 2211 bytes .../textures/blocks/DolomiteCracked.png | Bin 0 -> 2156 bytes .../assets/textures/blocks/DolomiteGravel.png | Bin 0 -> 2229 bytes .../textures/blocks/DolomiteMonolith.png | Bin 0 -> 2026 bytes .../assets/textures/blocks/DolomiteSand.png | Bin 0 -> 2261 bytes .../textures/blocks/EclogiteCracked.png | Bin 0 -> 2235 bytes .../assets/textures/blocks/EclogiteGravel.png | Bin 0 -> 2235 bytes .../textures/blocks/EclogiteMonolith.png | Bin 0 -> 2132 bytes .../assets/textures/blocks/EclogiteSand.png | Bin 0 -> 2298 bytes .../assets/textures/blocks/GabbroCracked.png | Bin 0 -> 2291 bytes .../assets/textures/blocks/GabbroGravel.png | Bin 0 -> 2311 bytes .../assets/textures/blocks/GabbroMonolith.png | Bin 0 -> 2254 bytes .../assets/textures/blocks/GabbroSand.png | Bin 0 -> 2167 bytes .../assets/textures/blocks/GraniteCracked.png | Bin 7700 -> 0 bytes .../assets/textures/blocks/GraniteGravel.png | Bin 8882 -> 0 bytes .../textures/blocks/LimestoneCracked.png | Bin 0 -> 1919 bytes .../textures/blocks/LimestoneGravel.png | Bin 0 -> 1998 bytes .../textures/blocks/LimestoneMonolith.png | Bin 0 -> 1602 bytes .../assets/textures/blocks/LimestoneSand.png | Bin 0 -> 2017 bytes .../assets/textures/blocks/MarbleCracked.png | Bin 0 -> 1877 bytes .../assets/textures/blocks/MarbleGravel.png | Bin 0 -> 2098 bytes .../assets/textures/blocks/MarbleMonolith.png | Bin 0 -> 1844 bytes .../assets/textures/blocks/MarbleSand.png | Bin 0 -> 2202 bytes .../textures/blocks/RedGraniteCracked.png | Bin 0 -> 8017 bytes .../textures/blocks/RedGraniteGravel.png | Bin 0 -> 9110 bytes ...iteMonolith.png => RedGraniteMonolith.png} | Bin .../assets/textures/blocks/RedGraniteSand.png | Bin 0 -> 10019 bytes 32 files changed, 36 insertions(+), 10 deletions(-) create mode 100644 src/main/resources/assets/textures/blocks/BlackGraniteCracked.png create mode 100644 src/main/resources/assets/textures/blocks/BlackGraniteGravel.png create mode 100644 src/main/resources/assets/textures/blocks/BlackGraniteMonolith.png create mode 100644 src/main/resources/assets/textures/blocks/BlackGraniteSand.png create mode 100644 src/main/resources/assets/textures/blocks/DolomiteCracked.png create mode 100644 src/main/resources/assets/textures/blocks/DolomiteGravel.png create mode 100644 src/main/resources/assets/textures/blocks/DolomiteMonolith.png create mode 100644 src/main/resources/assets/textures/blocks/DolomiteSand.png create mode 100644 src/main/resources/assets/textures/blocks/EclogiteCracked.png create mode 100644 src/main/resources/assets/textures/blocks/EclogiteGravel.png create mode 100644 src/main/resources/assets/textures/blocks/EclogiteMonolith.png create mode 100644 src/main/resources/assets/textures/blocks/EclogiteSand.png create mode 100644 src/main/resources/assets/textures/blocks/GabbroCracked.png create mode 100644 src/main/resources/assets/textures/blocks/GabbroGravel.png create mode 100644 src/main/resources/assets/textures/blocks/GabbroMonolith.png create mode 100644 src/main/resources/assets/textures/blocks/GabbroSand.png delete mode 100644 src/main/resources/assets/textures/blocks/GraniteCracked.png delete mode 100644 src/main/resources/assets/textures/blocks/GraniteGravel.png create mode 100644 src/main/resources/assets/textures/blocks/LimestoneCracked.png create mode 100644 src/main/resources/assets/textures/blocks/LimestoneGravel.png create mode 100644 src/main/resources/assets/textures/blocks/LimestoneMonolith.png create mode 100644 src/main/resources/assets/textures/blocks/LimestoneSand.png create mode 100644 src/main/resources/assets/textures/blocks/MarbleCracked.png create mode 100644 src/main/resources/assets/textures/blocks/MarbleGravel.png create mode 100644 src/main/resources/assets/textures/blocks/MarbleMonolith.png create mode 100644 src/main/resources/assets/textures/blocks/MarbleSand.png create mode 100644 src/main/resources/assets/textures/blocks/RedGraniteCracked.png create mode 100644 src/main/resources/assets/textures/blocks/RedGraniteGravel.png rename src/main/resources/assets/textures/blocks/{GraniteMonolith.png => RedGraniteMonolith.png} (100%) create mode 100644 src/main/resources/assets/textures/blocks/RedGraniteSand.png diff --git a/src/main/java/ru/windcorp/progressia/test/TestContent.java b/src/main/java/ru/windcorp/progressia/test/TestContent.java index b8a5b33..9e868b4 100644 --- a/src/main/java/ru/windcorp/progressia/test/TestContent.java +++ b/src/main/java/ru/windcorp/progressia/test/TestContent.java @@ -29,6 +29,8 @@ import java.util.Set; import java.util.function.Consumer; import org.lwjgl.glfw.GLFW; +import com.google.common.collect.ImmutableList; + import glm.vec._3.i.Vec3i; import ru.windcorp.progressia.client.ClientState; import ru.windcorp.progressia.client.audio.Sound; @@ -101,13 +103,7 @@ public class TestContent { register(new BlockRenderOpaqueCube("Test:Stone", getBlockTexture("Stone"))); register(new BlockLogic("Test:Stone")); - for (String type : new String[] { "Monolith", "Cracked", "Gravel" }) { - String id = "Test:Granite" + type; - - register(new BlockData(id)); - register(new BlockRenderOpaqueCube(id, getBlockTexture("Granite" + type))); - register(new BlockLogic(id)); - } + registerRocks(); register(new BlockData("Test:Brick")); register(new BlockRenderOpaqueCube("Test:Brick", getBlockTexture("Brick"))); @@ -153,6 +149,36 @@ public class TestContent { } + private static void registerRocks() { + List rockNames = ImmutableList.of( + "BlackGranite", + "Dolomite", + "Eclogite", + "Gabbro", + "Limestone", + "Marble", + "RedGranite" + ); + + List rockVariants = ImmutableList.of( + "Monolith", + "Cracked", + "Gravel", + "Sand" + ); + + for (String name : rockNames) { + for (String variant : rockVariants) { + String fullName = name + variant; + String id = "Test:" + fullName; + + register(new BlockData(id)); + register(new BlockRenderOpaqueCube(id, getBlockTexture(fullName))); + register(new BlockLogic(id)); + } + } + } + private static void registerTiles() { Set placeableBlacklist = new HashSet<>(); diff --git a/src/main/java/ru/windcorp/progressia/test/gen/TestGenerationConfig.java b/src/main/java/ru/windcorp/progressia/test/gen/TestGenerationConfig.java index b4ed652..22a66d7 100644 --- a/src/main/java/ru/windcorp/progressia/test/gen/TestGenerationConfig.java +++ b/src/main/java/ru/windcorp/progressia/test/gen/TestGenerationConfig.java @@ -68,9 +68,9 @@ public class TestGenerationConfig { } private static void registerTerrainLayers(FloatRangeMap layers) { - BlockData granite = BlockDataRegistry.getInstance().get("Test:GraniteMonolith"); - BlockData graniteCracked = BlockDataRegistry.getInstance().get("Test:GraniteCracked"); - BlockData graniteGravel = BlockDataRegistry.getInstance().get("Test:GraniteGravel"); + BlockData granite = BlockDataRegistry.getInstance().get("Test:RedGraniteMonolith"); + BlockData graniteCracked = BlockDataRegistry.getInstance().get("Test:RedGraniteCracked"); + BlockData graniteGravel = BlockDataRegistry.getInstance().get("Test:RedGraniteGravel"); BlockData dirt = BlockDataRegistry.getInstance().get("Test:Dirt"); BlockData air = BlockDataRegistry.getInstance().get("Test:Air"); diff --git a/src/main/resources/assets/textures/blocks/BlackGraniteCracked.png b/src/main/resources/assets/textures/blocks/BlackGraniteCracked.png new file mode 100644 index 0000000000000000000000000000000000000000..5d3afa4706d14489547053b72d0ad9c78b72256b GIT binary patch literal 2051 zcmV+e2>kbnP)EX>4Tx04R}tkv&MmKpe$iQ>7v;9oj*}AwzX)K~%(1s#pXIrLEAagUO{|(8Q3W zxHt-~1qVMCs}3&Cx;nTDg5U>;o12rOi;))n}g@7<3h$AF1Q%~m>^6(sA_we!cF2S?B&;2<Nu%s>LxK48fDJ&w53`EFipoTguBxu!0F_ESHq=$dl@n^^-ldA?s zj(KcAh2;3b|KNAGW_fbLO$sJ~{ukT+7zF~mK)Y$%-^aGyJ^}pCz?IhZZ?u4!Ptu!R zEp`Niw}Ff6t|spRmpj1FlP(#OBl&3xkM>^7x z&N-j>{U81~CP_lJ-STO<qVIc(vf}c^IWJyZ;0FO(E8;lj z-*5hf(h_Y9QfbC<Dh?SDc=mBlA3G^R!`b z7ULTj9kZi3Z{L2;z9@0yNWR~5_wgfb-*bF&!Z287vpHHDtQ*O)4Ph985I8qd)eYNh z%P!B+%jJ^YE+-6p!Zg8JM_t!|%R82IqvmZ$ZK z#o~lX9FylcWm#}&4rr~>QYzAEN}433Ny6jfBVD&)7zUJ*9O|0O>nlzcr>xg&+NNO= zMU?x3Z~yjJwARdKb3ET;GMSL3F>TXwcXy9xJhbO~bVW;+W%PZ|6AE~5{3cRT84h$^8AAOaG+(^IrIG);q2lD=(dn*&|jBBbEIKm5Sv z>4_kWP*;~%--Kbv=U;q=8%N5r{JCVo@zLV>bd02F%K7OTWmS;xa*Xd0Mj=rcV6-9# zL!?yC%NhoRRE*A|{UG4gFJ9yO0a{fkB{9a}8I9HgU-<;y5k*n3-DOl|O*&0!n+BXi z2#`{swLxnSfJqdwTs|-i7Oj-R4wkAaDT;!oX)&IM9|YuCMifPKeNUe6Dfb0J3Z#_y zK|t3w*kQo;ecHA~Yr{B>^g|Cq&<{P@TF3jF8$91fYRxb>1Op#$Z+UJ3j4||Ghv)gv znpB*goRaTzs&bD2n!^D^OWXAv>KZ=?kV2xuTxxBi@ z7>~{7iKaP_PG>Yti=ImC(4&nZ-{tJGjM0r$Wy$rcmuRHq`qfL8clQ+goVIC5r&E$N z<8I8o9#3FjHjvV8Yv}3 zQ813MI62|f>(^|ao><=B)3y!H`G6zv0(2Ngv~7bi9#Z)%@9$Wz*L?BiujslS1PsG~ zb(Yh`Db_i(F?fDJRaX>6fgLQ_c7yMGXsvNLq!a{!j|_qUr8Nk_`fYs5G??NrJxU1Pzki3|nL$DbnnQ!p1~-n>^#Lga`7XouJ)ZA# hyg1=$y{4*a{s#=NI-)Rwc&PvY002ovPDHLkV1mEi)xZD% literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/textures/blocks/BlackGraniteGravel.png b/src/main/resources/assets/textures/blocks/BlackGraniteGravel.png new file mode 100644 index 0000000000000000000000000000000000000000..bd49f48603a62c4724dd4a92d67a846b3c1ec138 GIT binary patch literal 2078 zcmV+(2;ujMP)EX>4Tx04R}tkv&MmKpe$iQ>7v;9oj*}AwzX)K~%(1s#pXIrLEAagUO{|(8Q3W zxHt-~1qVMCs}3&Cx;nTDg5U>;o12rOi;))n}g@7<3h$AF1Q%~m>^6(sA_we!cF2S?B&;2<Nu%s>LxK48fDJ&w53`EFipoTguBxu!0F_ESHq=$dl@n^^-ldA?s zj(KcAh2;3b|KNAGW_fbLO$sJ~{ukT+7zF~mK)Y$%-^aGyJ^}pCz?IhZZ?u4!Ptu!R zEp`Niw}Ff6t|spRmpj1FlP(#OBl&3x8HPSmDV(EOHkD30m%`-DLVKv9$kArY=XYfW1>Tz~V5+2s{wSt7G6Bg+odb%nK-B0phl zhqYik5JIq6Eb%>$UYar;k8vD9nhrUgPPE1l2N6l!qtqqBb;%3OcDJRfYUGFa?^!Na zOwZ3L@)OI&65+bkRm&ke;5gt4K@bG=l7zA>Ns^d2i7B;4DaC%jB@7~l!y%O}IUX~b zw!xSdk?k|CUR`rBoAHP5f4~?+mSt?W8``GET8r&E-hTT#I@?icO=mlFsrk>p|3z7r zSYuJ1q~Gt;>m_u?;&dHKD&)oG3}Xzt-Ht_7A;inky3Qhmhg6cXC|Ix8;5fulOw%;{ z^B;dl>xy2lPcj}5h5^PHCX)$)=QIEMl~=D{BYodzyGDH)O{n&kv8t5AWVl6vYc*JOKxm zizQ(aBU~5H4{?M`nV$ggltL;+nht5(mZoWFDov$JmWu^-U88kHQ`dMwfNbgpAp}4E z_*ZuOjMZ|5)*3p8Q98odmecXTpx@(sJmG$R&vLnh<7~l#ADII**C-6obk4GM!9yuJ2G);p&9a%jKl3q+z z)trsTL{SVt97U{F8?r1zMsdvJ!y`>q(X<9@JEAzom6B|?BZ?yGrXkA?qXS8jN@&o)JAj=LkP0L{L!mvCq zkYO0{FrOoY;NpD7?CO%iAmw;C(6lYa8cbyf!;tNEgX_BZLBMb{LTgQ)=U8j;e2>X= z%66A=JRYfZNfIZ>&mTT8NQVT0&w8`s?YD1vetclF+hL5sT8l0V@>32D+k1rxD;{utc}@JAMoeqaS|jDlMDs8A^!q)0Pa=fCT0;={$RG%4 zO$(00VV{BH;Q1b(K7GO(iz_9L(;*zeX1gU#Q-muB!-(hS1#R1MfA^XGphp<^v~`U& z2FG!@m|Y>7w#D}Yz~TA%nK(&srQ*%aTY7^5mDYIb#kTW2r!@x05hx{@PA3Q<=nn=c z*X8l?iO+X;2-ihPkL7ZO%ugqDRdLwwdG*aVxUOKo&uH5QhmPrVg6m3x&}X~Zve|52 zp89Zz?|b;3qG=jhBiL;=2q6dppVKizDi^t0ZRk3KQVKutNaBS1yF0eq4N6MlBq2=$ zjJ2H4F8Dg1Q{*|7u4v6m)B%U4X;4ZM#W82&33s19u~~2UKaa&wYV>6a8UO$Q07*qo IM6N<$fEX>4Tx04R}tkv&MmKpe$iQ>7v;9oj*}AwzX)K~%(1s#pXIrLEAagUO{|(8Q3W zxHt-~1qVMCs}3&Cx;nTDg5U>;o12rOi;))n}g@7<3h$AF1Q%~m>^6(sA_we!cF2S?B&;2<Nu%s>LxK48fDJ&w53`EFipoTguBxu!0F_ESHq=$dl@n^^-ldA?s zj(KcAh2;3b|KNAGW_fbLO$sJ~{ukT+7zF~mK)Y$%-^aGyJ^}pCz?IhZZ?u4!Ptu!R zEp`Niw}Ff6t|spRmpj1FlP(#OBl&3xKTAF2Qp zx~fO2DN&Rb{vPDL?GxEPi0|p}LQ;GUBzvf?2{XK)Zjh0Y@1^+Xzy4h|n+-8We*5hY z%=1hs1xn`kZ$F7Ku*@_2!vP`S@xvq6OOGI9Ov5xSyqqrNoLS}xr8QmGaXMXCnFe`x zIAEP47nr66=R8#f)>@8td!C+NFsl_xNsKZ4`2Le_-BO8~#u!Qw=wYHD$T_2wk-Iksob$+U-@b9Z_HY!Y~YY7g^?oMk}%~VxBEZ)})kZ z8pD2f$Mf?u&RV**#V!_SEipzwFi#_0*RkEMan^CZTqy;lZZv*yTrL-KE)-z9-4S9$ zNr{v-<2bU+mXtGH+aZMDa(SV@-k2AQ(haM&C8b0Rkq-}#IPXCSWKM|?10h7DoX9z& zwMJ=;_a5sUX2*ay!29

    uJxybf^+a7)D5cO!BBh|I8;rhV7zSMM04&QwE(LN%2&gK7lnN;|0D?lv1#2Br zDMgBjX&M=Z0c#yfYZ_x1ZZ}NRP}Mc_yl}l<@!nC@HA+gnv!oblng-__QYuO*gcv{w zG9c@!=6pV5t)-IkSGSoTKYk)*jZz9qVHyXT#$cBPsWkV;BmJ#s8gB@|E(-{U^8x1^ zo6UyJW{aHXk=rm5V`8(}AnS@0BlpK6(>zmhCIrX3hxaI@(OR==TOJ=juxdMAo-0xe zNTuknJ=eGSiJEzNqloB~->@rhV zHMX|wwmXb5jN`yO&rH)o%8`$UJO20WzwGu09v<>HzPs#~nH1j-DRTaZ9PzoIH@7e8kq?9N{kaEHM0A!3dRI61> z$**EFtCmU#re(oH@Cz5^)uc_O3A!?`xd1n^SmGsg!HO~Tr!PmkWzAY zx95E6i7AnCCZvR}DpCsEZZq<9zG94K8YjH>?DspyX=1odTyHm2U9&6`-Umu47}L;o wYhsAxQkdt3N(ii75T&qgSFgtt6XQ7Xf14Gl&qBV~^Z)<=07*qoM6N<$g8r(GJOBUy literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/textures/blocks/BlackGraniteSand.png b/src/main/resources/assets/textures/blocks/BlackGraniteSand.png new file mode 100644 index 0000000000000000000000000000000000000000..71b867e90c96497803e9c0ed996f700dcd62b4cc GIT binary patch literal 2211 zcmV;U2weAxP)EX>4Tx04R}tkv&MmKpe$iQ>7v;9oj*}AwzX)K~%(1s#pXIrLEAagUO{|(8Q3W zxHt-~1qVMCs}3&Cx;nTDg5U>;o12rOi;))n}g@7<3h$AF1Q%~m>^6(sA_we!cF2S?B&;2<Nu%s>LxK48fDJ&w53`EFipoTguBxu!0F_ESHq=$dl@n^^-ldA?s zj(KcAh2;3b|KNAGW_fbLO$sJ~{ukT+7zF~mK)Y$%-^aGyJ^}pCz?IhZZ?u4!Ptu!R zEp`Niw}Ff6t|spRmpj1FlP(#OBl&3xCRT&S* zoR&_R&*um~{`dpgY!+)}QLA3?@~8g+@Wtn!69{2Ub4fa#qSxtS+A9DAA%d>=X*OF} z)(S;Y$fdKaRx1tyM50HO&dMay8H8HB#%y7*+xgtx-E#HhF?a1d2Ez%X!2l(lX7BrC zG8q75Ri%A<%OMCjubxvpJ;U+VINlmbmN@JKGT9V2*Da2sVT7Azi|b~SPcAP2`2M@^ z@z!g?p%Cuc;r{L|0OoSZMg0>1a`_yUN|j2b%6K@$_kCnpW;oEvWV6_|jcG2iZHLg; zU;pbM#$p(&CHYK-SFc`CES}Ko_t3NohOt0OB+#@9mgAtPD)ZTtp|0aNYtA%{AQa-F zUS~2Iv34v@iYK(1Es~iG5m`~NtQA9DCmaePNzzA^dHVexi9`a^`~Z2qcCc0{jK!Q} zDv9H)nU2Tg3Izb#Z*R$FGrYTNqoh=3(+NT}4A;#j+NR!bApSP%pO_nr4>`nQ8tuL7`IT1+Qn#^WiC%S+BG8vptBTduAiv)}JAjU`&C%-g#*gP~47pCf*=t7^2@(G@ArEQ^Z|;ZqW5)FRV5Kmp!a)dS{c{%m`o;& z$75FZibO&rdUQkxFiewdHbbj*jU>tBiv|4MmXHuej7x+|XJ^kXYsF@>#q~V2N`>ik zMz9Y^$TGvhkjlq@+ISlTLEvxz(=>?1V)(v~=WWOp@JzB zhw)XabsWb=QWWYRIrjAd(a15=*@W|26+u>2-1QpI^?3B)5m%3%aDU$+e^SKVZYUHB zbh{n?_@_U!Fy>6A6U2C&#>0oW?wY|sM^@wyC0W^w1|z}<_}d+e*&LyJ-$9mScDo%f zU%eom%TOtoX*ST(LkhndIpop3=U(MHEFUS_RK_*?2D9ZU;@P5KF{qx7(CTC0x&A zF`to2sYnT#zz;~LlQ>(K*=&Yk8myf)f@#hPf&fWYKG?KuWLd&>918h7aZyB!$7wd- zFd7XJMUnA%jO#emYc(u;&8JVFQm$069fzbMGaHRKEtRQN>xBRD)jywGt0moT7YJc4 z790)-#^W)Xrm@{^*=#nXk|{P@mrtL3ieZ}Ajzg!{ClrE#u5%m{@!U0@>ry@|BOV>o zAL4Z+F%TeqYIU#X*d5NsZ*lQbo(C6;mdt#zUI-NmPlZ+>0l1Y`o_j&g087pgr zD8`shMp%|bK9{3?*QR~f#`8SFilRQxWHL-AQ%u z(P)&-b_0N#N}(z$yX}Uf<0FFLK)qJwmsh{=@Zkeimc`|RM+g^}7X*g`iFktD&Zp66 zZ~&G|6W{kyk_uuhMm!d$QmGIQM;ML9EX^gJ=P{ejSeeU@HMJ-dPkHm^4UOMDW;z}q z^g23$|{fU{mxyQrgS8mg+&YP}(s$EX>4Tx04R}tkv&MmKpe$iQ>CI6hgK1B$WWauh>AE$6^me@v=v%)FuC+YXws0R zxHt-~1qVMCs}3&Cx;nTDg5U>;o12rOi`@g@6Hs(2pL8nR+6}v_(bAarW+RVI`Q*kx9)Fhl#~v8_R9XN`^{2MI2F7jq-)8 z%L?Z$&T6^Jn)l={4Cb}vG}mbkBaTHRkc0>sRcxRP3sG7%QcR?1Kjz^da{Nhh$>iDq zBgZ@{P$4;f@IUz7ty!3yaFc>Dp!3DHKSqGSF3_mi_V=-EH%pV2qvfY2?_z3TSX+{ftykfE-YZh(VB zV6;ftYaZ|JYVYmeGtK^f07zhRmJ&y_%K!iX24YJ`L;&Cb%>cZLH-;1d000SaNLh0L z01m_e01m_fl`9S#00007bV*G`2jv156Co{9&o2!C00wADL_t(Y$0gE9ZXD+UK;c(^ z{WVwhSk2}nQIu#gF%T=Q zc?E9gfZgaL0tLe`d6+E;!Vodu<^1@=4}{^CMA69=L8)8hMTsm@vek%XkWlIl9luGd zStHIXrn4E##S%p+!ElKc4Xw7%WD}uDSS{zMN{MKDCJkHiFxwKP5vFZo$r4i(WO>fz zyN`H=!XICLhizNz@B6fUpW(xjcFjU9GFIaO4O^kR*WwS~{gp6I5sE?-M#%27=hQka z{`=+@QRWCrT-Rk&N*;Ox@;Ib>{)8f!pzA8pcFUu>ib$Hgem~&Jkx$dLNXMTjgdpi% z^6OQPdZWhq`E!)sPyea1X^(KXBM4%K_Y=}AClNM|uJZiQLw8-Is*>;4R8>imRR~ow zp3F&-l#bt}QYti2aMQoX(gY`GXQ)Mr42L&VNq~|jIHKaq(*v?F;Md^_q1q^(Ptd!h zwckP-IzgDDIW{^u^@hh}y5@d1Bd;pbG~@T@Clmz)Nsc2WLd`?+Btf@r;>`|JjY`w- zbir@BHcmK3dUfX8k_d}TT8#QbcB;)ZgiR20^ymQ3vG8n@JTIsK)3&GpVH5$LXQE3% z`>2bqOAN~)EedY#9!N_C-E(LjA7MA^AOtnn)t2CIbmVgqGGu-u|n1-aDGOr0Ya7HNfU z=%`iBQK!Ll9dX+qq1PK|ZUglnfB(zBC<9}Z`21O1iBnT8r9v^iGb|ItTm@v+e!{PXIXt{XJCVsnx?RQx%XJ9&H z^EsYlqbdsb_Y>-lMa{K98fd0PvYwJfVA>|=28HGG;$?^1i?@_Xj5L~iXrdyHLdX(w z&1D;;I9Wor-H>ECwq?<=4Q$tCFc@=qxQA}qWV;obX@C$+mpeQsr;P7d%O=umv5m(_ zr*p)f8bIkWoNvk3W9()JEsfE1fpc^~5pKvTjq&Ug(lF4yJ&N4~Mb%JD54-yqVcju$ zn4x$L_RNxx{XT}FA)4iqDh(03!IP5%c0oj4gt&W0NJGca6l}*OsRZFJM582Ljmb(u zfnZTc#`7&z5^{R}0?SmHJ=Z+co(nAV-kqB|rXr!?V+bX3e6ABjP0G z>UzL_yG~Il-1UY$Iyu2Kbi8zdmMs9t@(@{;eCQ2$`RA`$&ZfxKazloS*iD&CW}JWX zEm>M|{mUEX8=J*!hHDvg>n=r6;`=Q|qmb=lf~-5F(jkijwoyU4xT4n|@w+ch$f6M6 zZy^W$9;Iet6e&-iKEZD8lLcFZZctSfLI~O&A0ZT?ToObvPR(O{|3H5KL)Q&jx=x%| zT)qFm*|R6irwcU4!H^23q0y+jyuIvERu$KG_f!aEG#R1M6*1yEFmv)C<;FI@40w;#Wu`v>K>nl6ONC&)I1x@)M<70k%r0p z4|ix%U>To5SsbDOqeYCWS;#WWc>U7_n_bAB-{kD<6pEZMjG%(6>mCi)qSLCQ877M1 zuv#priVY_xM@(jGe*Wc#Zl{5+3f56UWjNH_2D(}x?}jr9MR440({9)4eVSnVdvs0? zIDC9cyj}42)hl#OMe)ywl88n}M@d%n`XeUu&F2X$i-xV^w-pq-$*b3w2<-r=>XOcW zmu9n$lEid<7op}jN=z9{P_qzeNOo~bdi@ioZ88sH2ICp^c84#&JfzGLk}OB+8f8^b irCW}UJG^~&#s2|5EX>4Tx04R}tkv&MmKpe$iQ>CI6hgK1B$WWauh>AE$6^me@v=v%)FuC+YXws0R zxHt-~1qVMCs}3&Cx;nTDg5U>;o12rOi`@g@6Hs(2pL8nR+6}v_(bAarW+RVI`Q*kx9)Fhl#~v8_R9XN`^{2MI2F7jq-)8 z%L?Z$&T6^Jn)l={4Cb}vG}mbkBaTHRkc0>sRcxRP3sG7%QcR?1Kjz^da{Nhh$>iDq zBgZ@{P$4;f@IUz7ty!3yaFc>Dp!3DHKSqGSF3_mi_V=-EH%pV2qvfY2?_z3TSX+{ftykfE-YZh(VB zV6;ftYaZ|JYVYmeGtK^f07zhRmJ&y_%K!iX24YJ`L;&Cb%>cZLH-;1d000SaNLh0L z01m_e01m_fl`9S#00007bV*G`2jv156C?_XvTh>)00yy1L_t(Y#|6R3a@&RhfZ-oI z2!cB(QX(x=Qe;VXVkb`0Ow+WT9(wAnPt*34OWvc?$7m0o>14(kx3Lp>kz%csL~-8$ z0>qAfpYZx0f6a{M9-<=g`uqQ|Sh?uBj;3qGNyfpKUopMGg=(dUA7_jw6Xvryf{-$tIXI5P(bMPjXEurqi}@5uND*rVow6a*8_YofSyL$) z5>->7y;Wzm^2kXkUw-p@3?oOgX_3#H^oDcFrpD!Em*sfC*MIn${rwKV|I?rG{18zP zSbJ;a#@-`}^(z1T*9#0YPZanpmn+ti#;|*bDnhHhN#c%B6p8!Z08@%Esuf5_C^FIqOm=ntXC}h>T`%adwTEMm*Wwq}Lzu=IsXrqeMa1dG@f*b@!I@ zUoNQRRgxrOvr$8oWE4dt2trgz#b1XgV#4KZpISl1_CxNwS4e;Sc=OwC_mf8^fNUDSv3xu;VPxqUYOD4VH65CJMs+Y(F0e2l?yB-VIV>EMkdazBoR3?*D zPCr~B`mRk*Q&>eQzP$oTAyX7eIfc3|aA-;F?``AwB8gI<(Q4tXR;(n0u?M#6(|WK; zA)ljQ=)`eC2532*#|OKJhpi&5MwRhoPIaq+s>*1&Jd!NoxjqRJY9UXh-NLAp$eRYc z?Ki9 zQsU(Rqf#exSN#0ujIY1>io~;tGKJZ4fLSb}7B)y$BQ~2GG#=!+yq_W{bKF=Y)hssj zl!Xu?iXc`?2L8&XVpZup++?v_k=P^Np7;6e(?c{xz{r~fnTTUMB!Q2=7!ai*2_j2W zv_h3Ej_5r4gq$uh8BVw#O!@rz$B0Kyj=1hkux*#|#3qbWPA~iHY+2}%K(Jh}oK1Ou ze2k$fh?303>2CDl5Y2oZ+`up$a9gSFvhG@`RS)OSOuLY zUwlOrW}Lq}W@;OZhC@O>q+yjXat2ka%KOtZ=A%CKT9H>Lw?7)rt6eUoh`EX7Y1q4Be^xb!V`!-Ee#-kyIA|S;9-eSt-^)34k8`R1LmW~UV z$o5tpNzHM0)8p__2O&wZ8g=qHjcPGRsc0~sE=iJvmFqK_+Q{os55b*NE0_4?ddSnF z#r5?qA9dQ4EDLFA^Qchd^7;;YGUUT`k3z9P7zJ!?)er>%fa8-(WJP1=!3Lrr;`#}S zrXsEZ*?(yTRV;sjt7E-b}MpY%UC?E=b#QWVDX z6^Jr>+YPKriL2W_5K%6fh_a?ptX5ER1uo9d$pA4+x#-^W)A27jUW8)gNRpH=%P1BM za=OaF;Q@XEKm6|<{o#~nM;)>_Ch|Q5;C|*KDLI6ffB#GN{``*l(&j;{iK6GQ7YkHH z!Cm_x2$annwTg-31uRzq58Dm0B%)$!j3!I2?}k(>1yo7Ii(u}B7-pHrof`6WZ$c2q zbXrX|HY)u5?gF!F(cJB@wY`Jy%y|3qC7L2pefArM!#?*nmpu8XN%!WS(bPs$6}%wE zC*@#g6TztP^7SdAvWe`40T1@~s8mV_flp4CG3AuJ;FG!|q{u_oWLADic>W_rLuZi$ z{QLXYboO?6{CJBr3UJ&t_q{$rk|BoEX>4Tx04R}tkv&MmKpe$iQ>CI6hgK1B$WWauh>AE$6^me@v=v%)FuC+YXws0R zxHt-~1qVMCs}3&Cx;nTDg5U>;o12rOi`@g@6Hs(2pL8nR+6}v_(bAarW+RVI`Q*kx9)Fhl#~v8_R9XN`^{2MI2F7jq-)8 z%L?Z$&T6^Jn)l={4Cb}vG}mbkBaTHRkc0>sRcxRP3sG7%QcR?1Kjz^da{Nhh$>iDq zBgZ@{P$4;f@IUz7ty!3yaFc>Dp!3DHKSqGSF3_mi_V=-EH%pV2qvfY2?_z3TSX+{ftykfE-YZh(VB zV6;ftYaZ|JYVYmeGtK^f07zhRmJ&y_%K!iX24YJ`L;&Cb%>cZLH-;1d000SaNLh0L z01m_e01m_fl`9S#00007bV*G`2jv156C5|iMV`q300rhrL_t(Y$0gNCk{nk7fZ_km zIn~(J-BL>y*q9+$Km;6s9hc%d>^TU*!fbFjuyIQ&bz4Vc>qR1%nlytqtcMa#$86jqH1zs4; z@)e)U4x{1I$M=lBMux6tWh2cX=!T9YOGx!hA}7WW`0CGKRMlvH9%NJtb;f!RMB2fywADE|zRTke3#L#0D6ed7~p**77{rAMaK@2^1 zj%aHchn}$ij%tFzTMdyBD-Y*DaYX3WEYmJ(|X zNtO};?WP8^$U#bO-rN(VMu;3@&C}C~+uId(kx?u*Xlv*XXI4c*^Z6&DTam9eboCWY z1PRRmr)x=~VY5ikr%qsl#}5IQShSL~-H1sFHgA_)>IN4FY#wRO6)H}w?rv$j9&y=o zN;a&VMfe7yL=`JE8Ht@p@&q|x7>1dbI`H`6NZST%x@7hBpRmP>GVQD75Sb>`-8b6_Z(=ckq`u>4jM}&}!Hs^9a646{wSGLQ7 ztXMLIKo~~i99S-LOp?-H4~!ioSpwEEr8}e%$o`3`Ezx3iN0ul=9GSi6!V)nK zGkeT%C9{GzZ(g%ZBvL1QK9yA6fL+`%^({gfWU;0A@(;=lEgW34gT`XI7=oZr%ChtQW5)>FMs<-(nL|7 zFZ}m$&m=V3=1aQjN+=tuF3|Q9r=;!}<}`iRu-k2siJH(>GX}`lw`7}FC~atl8KX4T8kXBF(K1v5$CUJ)Ks^ENWu|}boxzq!?etOUOX^$TU3^VIY zV1!_iT5O&Xg+ggVk|vz?d#=}#S8raErw(UskU{`Iv+aF?Rp7K>hz^@-WOv+?CWhE| zsBFzJ&Q!H$>>B2A#9GDBHZ<20QVPC!_kd*PR5rZq_b6lV!-RA>z3;H*=T7^sA;uZ4 zog-bY0FBL3;ymG-j@k!QlH>9MsWhj2`5GJhEOeQDW14Yq-=N z-u|AvyCCOr5ud!lA%ShaPP1kp< zZ!My~FnZ5R*^wBih8ZO1HjfK39Y*&p#T5?07*qo IM6N<$g6hoF;{X5v literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/textures/blocks/DolomiteSand.png b/src/main/resources/assets/textures/blocks/DolomiteSand.png new file mode 100644 index 0000000000000000000000000000000000000000..b419bcf4c3623acd3d8eea850685b113c530a315 GIT binary patch literal 2261 zcmV;`2rBo9P)EX>4Tx04R}tkv&MmKpe$iQ>CI6hgK1B$WWauh>AE$6^me@v=v%)FuC+YXws0R zxHt-~1qVMCs}3&Cx;nTDg5U>;o12rOi`@g@6Hs(2pL8nR+6}v_(bAarW+RVI`Q*kx9)Fhl#~v8_R9XN`^{2MI2F7jq-)8 z%L?Z$&T6^Jn)l={4Cb}vG}mbkBaTHRkc0>sRcxRP3sG7%QcR?1Kjz^da{Nhh$>iDq zBgZ@{P$4;f@IUz7ty!3yaFc>Dp!3DHKSqGSF3_mi_V=-EH%pV2qvfY2?_z3TSX+{ftykfE-YZh(VB zV6;ftYaZ|JYVYmeGtK^f07zhRmJ&y_%K!iX24YJ`L;&Cb%>cZLH-;1d000SaNLh0L z01m_e01m_fl`9S#00007bV*G`2jv156cH%+to!r;00z-XL_t(Y#|6RZlG=s=!0|si z03jhRAp{F}PqU71*PbNfbf)c>%=C5owIBQveS^M7XOd2vG>M&Euf1OO;=aTo4heDh z_Y3^%AAj5RyZ2=B1&mahW@mt^MrhP7F|!BQjS8oaONgNeuIm$6``lmOar(5x4?mZA zQrhSI{3B1FJt38fGqi{FS~XsO{WU-R??=SHeslaTWmq_Nhl%fUc~v763=ot9sF5gU z#zIxX%-l6U{^vcSw8Pp<69~ZR$sy(P?|k>&w}fT5xOh)8nMIArq*4jC8xY@qRe1NH zm}9%!U}g8P%s7kLgu}xpOx+3fMjLnH&}-E=I6gs(Mllj8EL@bfOuq=iHoB4DG z>jkF|A2D%VZtG3vJA>Qy3?Zm+vY$oKvlwOuJ#8XLvPRDyQNDUlI+vzeui<$<>9kI> zUSmERQ?1{isu~$n$8lQpMswbOtN=TLnnj~g}Q_0=6xD72&2 zs-lXJGc6*D!D2CIx7kr`&4}qsHam@8e}JwjXqry1d&8qci+!jVdFDu*AbRuj8uYrv4AMbELR(f`v(Zc{ig(j0*%`` zt!9UimP8Ed)Ne0%P)sv)x>z}j``ar9c8`!4;M+GZvF$E)&t~jy7_UVX&7jw=BgxR| z4LSc(MGk8Sx~9?VPskmd5>}(6(^1x|6`8$b+T9+#c7<3pOg3MjQLCT^xBPzgUqYII z8kbqkdz6kcOvV#TbB{0A9k%Nw$NPD1zkEde%cJOnPCs6q~mEu{Wg*)psFg1nZt6kqwt`Jlr*#0-8O1C zz^hlUn0sSJ-5QFjBMNJVtt$$dJe69Fk>m3HpIl_ z;Fb zA+RC0SD;*NqikKImnQ~VG|XhspjEGvOlAp%0+@R_ZYpK^_LM)pK0?x?^!iN>jt;r{ z{F#;Su-nY(cN;7`pW@M11VakVc8x+|hpC4kRz&I#nrwF_)n<)EGRGQ$Uw-*F{sNvo ze@o9kW4VpsjXe_a1eIEa;mBv~i7eJS?LNe08Q=9;thP*-F|P0XG+IL*JuDFT`JaE^ z34rfUQB)mg?6a7=NOF+rc#dJFh-(o>!x}N8$mMMnGZAO$yGTKuf!$}XkVBRPDtEu~ z@bnMNXHx<@s5Q$7+vSvn@AJ!t8@lZ-io9jLoG`F&C_UUK9ap)#z96C+IGrY66-*LZ zkcm@63=A<70%}OacYUH-7P~uQ>TbBJH_^2u!hO|74u&uiQ8F2eR`m|gb4VKnCX*o_ z&Oeee64Y+L5Y!Bo>jk&>w;UB7;0$JL0wTYE`ivA3SRVx;8?JCsY=` z&5LIx=KhvgI)@U8vG&I(VHsJLS#Jf*+#Yc~%+OiU>`vLZBhuMJ67dv@5~E!HLR8-3 zc^>-`jHOtkEvx`eg`4nTv;r#NRWZIzBzCe^#M2*L6))J+o j0`_3QZ|64%ioyQ@6YNa@_mwB(00000NkvXXu0mjf=rBB+ literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/textures/blocks/EclogiteCracked.png b/src/main/resources/assets/textures/blocks/EclogiteCracked.png new file mode 100644 index 0000000000000000000000000000000000000000..585efcfcbc6719a9a9042fe3a7a50766300c6716 GIT binary patch literal 2235 zcmV;s2t@aZP)EX>4Tx04R}tkv&MmKpe$iQ$>-AqE$p3GE^rEq9Tq`#UfZJZG~1HOfLO`CJjl7 zi=*ILaPVWX>fqw6tAnc`2!4RLxj8AiNQwVT3N2zhIPS;0dyl(!fKV$j)ohypRLwFH z(TJGNtco445HNr~^kPtArXEW!rrU6^NipZjxkD_N5PK9P8i>4rtTK|Hf* z>74h8gRCGa#OK8023?T&k?XR{Z=CZE3p_Juq!RPQL1HoA!g336_Voz|AXJ%nz^Y-Hz^PS+Fxw@V-)Dv1?pAX{yw(t`U&8F2ClTGzgz=mKS{4P zwa^jJvkhEaH#K<=xZDATo^;8O9LY~p$mM|dGy0|s(0>bbt+~B5_Hp_Eq^PUq8{ps& z7|T=ky2raaTYLNWOryUaQb2N=_TNs@00006VoOIv0N?=40KAGfh7@)uiT8IDvDpjkZii`HTQeS~r@VoR4KvjE#get*BMMy&eG1Ob^@p#5_ zX3m-A>{~B*hfn&1&p!LKxEVVvZD!L6 zcRM|*?KV@_=jnGp^624R)KE0%QJ>-0_#LzSXd%}9%fUsaX9dpoc@a<0{#5-$sK6-qJ zWob<2D|E}CVn~E;gf3f5oQRq2BIiIZvWimd#S+t0P<4|=-Qvb}7_EG6{g7vaTf9Wz zhrt|G*N{H=`0%J_iquV=fxAGIBt~N&*(~w&WI&oAXAu4rnFi$B)wTaYL_e`KSUM^MzaO)-@C){&6GtD@aV|_ch);N zj?2x+rrR`WuXkB*)o@31YV{KRojysH@}S>lI$JSyX2^=b;r?KJeV6T?AOOGg%a26TPWX3!UkyMqnJ2jT` z06Cg0&^PN;}~A&Tbg_5^~$BAvP{CNo3{cFSv&*4J<{7_Ab9wo4TIY^?Y2!-(Z# zN*X6T*y~~^F-a2h(e@_t$XzgST+CJ#&t9;<->226kop-?smt(mLZ@qy=Lywz15L~@ z#|vz!#N{mE8$SQ)8PehJ`$zYy zO=2(O?fo8?;}Lqjj-u$STN;DuoG?jw_Ue+*_sGH(|2cOEqL??|++w=4kyV9~Ch(`< zyv6x+&g=1vPP;^s$B1>a%6R5rRaGh*4SxIXTWE1g%`_P;5*pPOW?e^BWL}S!sGTjc z0{;BTJ3QH}@MM3Jjkd+Z2L~iVN`Jdfo~7K5XLP&kNFTm;_oxt6u56c32(b#0jk3vw zGbfE=?(ZLP72ML%bf%8SeC1QCSs${ZgLY1S;3tB5cNDX9u)Q;#%Qkwh_JnqgH8e!8|9 z-ngu{4ID2+eEjYk93CFfZr3Pscz!&jYn6#rox}Tk^m}WZo(`}bA61jtz0)R1bIykg zGD*UdOHAD*o82z5WO98qLlJXacZJjtkag9du~wn3L)a*DJ$CrVH{avuDRBbxX~1me z^Tys9{kBQXFnDyZ#rGFOE(bP(qA;`*UVZgn!Xm>g%SgG-{&t(od4kw$S&T>5+%6V~ zy2yJEcBr*19LHyNGeMRL8qEszvd%`iOi5F@8Vr!K6mJ>u`pPC3G71%%YdYixi$%;} zIHhkX$m(*+uXlEEhu2t!ilivq+uLF0rpQ8$D(7g3JU-k*Cc$;)1ms-XGfIX=y`obf zu+^*KN)kpXCia#@QHEF)i1u{B&o5rGwR?{og@qS!aXsU5FhydbAyDl~g_IyHlKyUwe@6-f}W-L>eJ%KZF#j6V<1^MHEEBFS^EXZ|mb zT;I;w>1&LGkVPtR(6^X6KCgd1B^OePLLn{+!g;{uWW|krPOa5pVFbjX!rhG)?QWZY ze)EEpWlpOm(rDKyH#4Na{_T?^Rg*Y>eM1)dWO>Tz*@RZz6*_I7L(7b{?Q<22mE$>{OB7|M2nAR?EUrG)^uiL}ASC)*2n9 zVEb3=497lsCLEX>4Tx04R}tkv&MmKpe$iQ$>-AqE$p3GE^rEq9Tq`#UfZJZG~1HOfLO`CJjl7 zi=*ILaPVWX>fqw6tAnc`2!4RLxj8AiNQwVT3N2zhIPS;0dyl(!fKV$j)ohypRLwFH z(TJGNtco445HNr~^kPtArXEW!rrU6^NipZjxkD_N5PK9P8i>4rtTK|Hf* z>74h8gRCGa#OK8023?T&k?XR{Z=CZE3p_Juq!RPQL1HoA!g336_Voz|AXJ%nz^Y-Hz^PS+Fxw@V-)Dv1?pAX{yw(t`U&8F2ClTGzgz=mKS{4P zwa^jJvkhEaH#K<=xZDATo^;8O9LY~p$mM|dGy0|s(0>bbt+~B5_Hp_Eq^PUq8{ps& z7|T=ky2raaTYLNWOryUaQb2N=_TNs@00006VoOIv0N?=40KAGfh7mo1_gS5&?=pv?@~J17AQwyg^^V@4_P>BqUBDC?dQ zdw6$_J!W=h=i>JhKK}S;d2it2`5{GB!73HW$(e@>npTm$b_G8XdH$k{Qjpl*U&pbB z>@`;?HyYSpz-OQTkGJ32BbfwTyy?(r*15SEP^;<)KmF*PoD9+=XQx#~SHTMtrhZ7X zs?l6BIqT05B#C;{Ku$%Rp~GU4v1G|yb*5;lil&JKVMJ9^DVhbWVu4Rz^bt3ft9<|A zF@~Ws9M32k8iyM-q#QJ*#C30qGx8{k5@aH?C}A|2QYtAFiY01QgWkx6f=Joa&?_o_ zEbvWdOubP-`rdoTClx8BY3X#l326p{+kj@h##v{8Qqsw?gkT;aN)kyJQ85(irb$tj zF^nRXC1TrC2E%}YZZc05oS{v7eF;fhGEYb{9B)QJ6tE`&PY>F>>^u0;f(PHd%ldL1 z+jbcYY+6et8mlc<>lM8Im`YV=b7zw{O*qidF|sIQ-;7vkFA>EdlUYRX#wE`sMzbm2)F(RM|P$!K#`p77Lb5fmpN1vy7QDM#&SlOF9RY8cCQTiW1$Chcok0bdw;Am`-fm zFyd&xMZI2RV*Bh^8gk#8&~ZIV^)miw!ks&tEY~cOAVtz!bT5XiHg&GLx14ny?(VN( zNiw5Z#2Y8()y20|%p!rmz%VovRi#xEsVOBcM`OgMWnt+hMwhpw^Oz)0=(r9S_G{EE z;9BNvrU@A z&)3-Gx{DD_wTSKdjAsFriUD#$JA?Di1W}TBdD)|Hj~Uog6j>oBXJk*1R9!n6x>FD! z&!D|r;oklls+f}`DOa5yd&?`Fopo8N7))mo;XFhyD17>QNZ*^GDI&`all`3*BR{}# z1C}h6MJ6CVd~%QD;{zIv3gqzW&4`v^vM3b!;JtU*-(KVS^K;zEoPsK|yU`#{GA=qE z2?F)9Nz0IUc(6^`C}WRiC}Kvk2x)DVk&6Y5+OkEp2ts0s)Ik^)f%-N6Li(2&ST#T=um;E!eeiBDOV zAQzFhYDFm28QU(aHIu5Ta@X9!@e;CRL8&AoiwZw{a?ETp=Fgv;;*S?({PVwObbGhtl7Q{`D8&-L`~5%o z?EHoWIq!b&h&y|m%;qU;s|KO(6NDL-p|U9?7)nl>#$0w?B%^7apeWcApH{g7$sA`o zC&_Y-A0Hx$8H+@KG{y6Le(>xr+uN(0cD^N^M{KnWTDr;0>jA-dPBEKP)eYh-5s4|<*vE2zftE>F-qYn|p66YP4-tCBy8#A9LO#CTp8yi#`JIGSt zk!2#Eo?deF)-I-2RpiXypcvA3p+QkTlj;>x{fPhe!Lg)|EX>4Tx04R}tkv&MmKpe$iQ$>-AqE$p3GE^rEq9Tq`#UfZJZG~1HOfLO`CJjl7 zi=*ILaPVWX>fqw6tAnc`2!4RLxj8AiNQwVT3N2zhIPS;0dyl(!fKV$j)ohypRLwFH z(TJGNtco445HNr~^kPtArXEW!rrU6^NipZjxkD_N5PK9P8i>4rtTK|Hf* z>74h8gRCGa#OK8023?T&k?XR{Z=CZE3p_Juq!RPQL1HoA!g336_Voz|AXJ%nz^Y-Hz^PS+Fxw@V-)Dv1?pAX{yw(t`U&8F2ClTGzgz=mKS{4P zwa^jJvkhEaH#K<=xZDATo^;8O9LY~p$mM|dGy0|s(0>bbt+~B5_Hp_Eq^PUq8{ps& z7|T=ky2raaTYLNWOryUaQb2N=_TNs@00006VoOIv0N?=40KAGfh7FP?ZfO)gq{JY#v$PLU!h?(Fv|KmYvq?zgWm zECQb|-`*H{J%mtrcQa>w*ix4jf!E{9>k(<0IIfMTE3$LJ-TNh*&4Dzpuw+M9#@OR) zzO7a)g8@aFB7VPrLMkfRX~Wo5k(Ufxg_qriURyz3^On@Knu*i|uBvl=HKlD@&d)23 zyAyYwgHqNs=&Uy@RJB7i71pqiP`j49!2r_<_;feJbS!*B!lh&v)eKCV<7UlrG(;eY z^ODuup1ew#IyP6X#eW{|X>G~Kb+~bThK9$tsN!iIqgrkcOBQ6sg@3NLEd2>_T5&U5 z5H}^~qQ!PxoI#&XQ|Qhq`y?SS9oAt^LxQi&h_=2r*Drut{&;j7H{aWxVfTf!09{u@W(%4*$#crVt1*~ z9g8dtnfWgAhrfROsi#0CCHp+X@H`4*Nc#K?x<*m7h&0D=4NR$XzuO}lfhkR-Y`A~f zQ8bbyZBR%Vx;Fc?Vi_1*;uIm`9M!YYdp5(tfFwF_>lGxr!y$~BdOBHjV$@0k6h2O8 zNV`u|);L!qZg1x3ItWAIoK&EIp_gpZ1XndsCnJZaFsARf)LF%NI%jvT@l*x<;}lUA zTn}{OONL?FIF3rYi8&wki4WY02?)#?uuX-Ju`22wI7y8NBWz#PAP^hDEmWJagJ(Ah;}RoHeK7Y>l!|ddf*CbLvsJ`d+b)nR(gbK&Rc#! z+?N|Z4;+%Bp{i^2BBc>3?qEXDGx=?Qg?OVOecwba8s1Ml>ZT?42!wq-6FgRp3^DfdSatg3c4uKbd}ZazgDCqzYoNRDd`rvnI$OWClF zVur5ADoc6F3TBH5vTErKe7?$(jEV~_`{;zCX!Kl_v!bE9Hr`@Pbll>~oW8KRv=`*x z{&M@1kIIMJ8}zQhF?CcwplwQQ+u|iW(enfT_w@yPUaZG-F{6^3AXtE2Z^%|+0`13Kts{w~7!tVFbH4WV~pv>78 z8J$*QN(lNc$JH86C211l*(M(cE~|5l_&6J3XeO;?@vrEGs8;Y@$%o|?;cm-*ccjiT zhPuXjb)de~yu60^&J=`2TbqPM#UDO@hgR35WrtK1c1?}%>WIp8Na7k|CIw_GtfxM&*6DIzY?Wy1p#k?FtOwHo=RKqdg!)#7qs`UGFYE|Q$#Oy99 zO{H@<9l3k|4mB^4&h6wU%~1IgZt&*;j~{tY`AvrP+Dhc%92u^7)dM>$txht)R3 zQEIfN;JkZ9Q=l;=LC@pTsl-W!CNv5~L0k{Ja9Q*BK{9%r8R&}c>!7g0000< KMNUMnLSTY?68VAv literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/textures/blocks/EclogiteSand.png b/src/main/resources/assets/textures/blocks/EclogiteSand.png new file mode 100644 index 0000000000000000000000000000000000000000..d00b06de5dc2f40c3711e6386a5fafe4413585ef GIT binary patch literal 2298 zcmVEX>4Tx04R}tkv&MmKpe$iQ>7vmk#;EJkfAzR5EXHhDi*;)X)CnqU~=gfG-*gu zTpR`0f`cE6RRe3JS*_Mt`=0!T!GgAu;X2I`B(Q`eQV=1djtZ)<5TjKi#YCF+;~xHD$DbmXOs)zT zITlcZ3d!+<|H1EW&EnLgn-q)#y)U-?F$x5BfmXw|zmILZbprUGfh(=!uQh?$PtqG5 zEqVkDZUYzB9ZlW?E_Z;)lP(#OBl&3x#Uk*2M&FbNLbpKwn%i4@AEysMmbzNL0S*p< zu@Yskd%U}^ySIPOwEO!3IXH5VI2XZR00006VoOIv0N?=40KAGfh7Hq%Zo?V*=Ei?4l*zCe3w4{4`uoMw;gI94RtqE<>= z1TG*65ClLFJ@k8tPx#Z*Kl(>EJyz0jN~JVseUnbJNh+-(s0oVVlzMASab=NbpMJ+$ zF~;woJm#p;r1AQKSLZkEK7L3t5aRoT1D018snp6G9bB=uUL~-!v-osk&H3%)hy3|3 z|01T$>5W}*O(JuVk>S!Xrr3tTPOX9!3NbJyoSdB_$I@)ARIogkcB4To8b*pH`TEm+ z41LTjBq9nj1ZFmW|LfoQU}uSVGQm6VY@oz4oL*`OkswR?94XV}@!nk~gE2=}4bN-+g-XK|fEE=RFcMKc_xhKt~fs8NO8jWUzo z2st!IN@w`u@R*$FvY@Ic!i@csH@rE%Bp}6DTwS2iAF{YrBcMvO-yCw)>msgZRoYsE z?|wL@KkU=$k64K(5rP62oj%!On%epza!Nr^6e6~R8;qfMZwcuJyASV@4u|>tlh4U! zA{eI4RF-LYGM8r^0*^k}dP*onv6P^^x=z2R^XB>nr`MxxP0{-XDK&%?Rfxu-{QKJz z7Ly*2?%l_nSah^5%lFo~z3q|Aq%o&1t7}UH%`v`bBMv4L+}RAJvcNx{eMdOxk&HwL zmI^E@aVCb1D@Y7)#=QCVM}GET8Btbw-5GM$>>$Yjw977~Vu3=rNb9o6;q!eEf;@is zfZ*7LdS}Skbolx921am>7z(1FU6M=|`9)sk$I~X&S{2(3l9pu-HJ#mZ1gnuYIjvym`_QM-A?UqzNjiQA4rfnikTYT~C8Qty>Uz9M0 z9%??vTnM7~hbV%}uRnaBaL~gy4KleD`p6SG+$`PIPj@yeIN>DvY|45f%Fq)rMh=>$;R|zenK=1W1|)%7?G}6iHJRY+ zgCin=AhHrBTgcOFw79pqf+&f!XC{s@L#(&EGL)C%EO5}BAciFHY~I>lMU_Re zOBIY@0R2XzP+mX|CrBr=lof^hyKfUuBzaN4;PrKvZ(klD%uLe0M6cOFT-mI0TEC*S zSmNgNl1eep%jbuv`5dC>GO#QT_YZL`6F(wj*)FzaF}i6HmSbq0Hs=>@{K=5}8|z5v zJnOYJ-rK#;U^qnh_~ZBd+ER}3XohP~aApF+YVZH#M^tDy!@eo9P$w@ zgW1?67!M*i5Re6CVHsyIWW7|RZQAI4jbJ>9=*(QaNq}5BPc)fkGBUs(vbwy&!>u)l z#E9mLeEOen$VEfk-fH~jgP&l|Jn(%Y#We2N!JAlkbBV8xkC{zOjH!z~858*EqX$pJ zB8=u!@|6N}(I+VS-1H56XO3u%8EP$R)kWqZkEN9&pM7;mDlAahC=*j;hOR|NH(0Ob zalJ5-@3XK{qSNgmc66H`&)bv}DYT0lE-ubFYxPJb6<#%(9G;$2$R;UNGT5d?!jnm4 z6o!(>)p?i8*VlAfW7f(GG_PCy^wA??S%stH3yRqiVp)yzyFWZZ45^s9$@=CtNi{=2 zQkjqYlopEE-kkG`EB3#yGalViODL405k|cp*3?GyMP_rGh@$ZPzn`$CM)7C<|3@R@ zF={rcU)O2&4c^~eCMXJ^_ep1pY~S4>o5`@fvBASTTTHw#j_G0zCUkoPLQ#eHcUBqq z#%O(qTTkL-3Z~_9a@|B!Vk%!AUNP#ANahP%cY6dRf!?i-h0XPKi&nRXF_|!(S=?Kx zFckwBjzwj$MlGFSV{Hjt0DEe(S;^6B->|t^LAR#_9(=g_G$_Xi+mMV08RBASI2hEsbe=fG0~Nm~zqT;!G{-jVt1cisM@xUk-5k2HW>HamOarYJmws(y<`_1CNw% UI(sds3IG5A07*qoM6N<$g4zl}Jpcdz literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/textures/blocks/GabbroCracked.png b/src/main/resources/assets/textures/blocks/GabbroCracked.png new file mode 100644 index 0000000000000000000000000000000000000000..5388eb30da0faf8d6f7715b1a5d4391ba4a0c44f GIT binary patch literal 2291 zcmVEX>4Tx04R}tkv&MmKpe$iQ$;BiK|6>zWN4i%ii$W&6^me@v=v%)FuC*#nlvOS zE{=k0!NHHks)LKOt`4q(Aou~|=H{g6A|?JWDYS_3;J6>}?mh0_0Yam~RI_UWP&La) z#baVNw<`9$LO=im7)L~6rk+SIX5cx#?&0I>U6f~epZjz4DS49tK9P8i>4rtTK|Hf* z>74h8L#!kz#OK6g23?T&k?XR{Z=8z`3p_JqWK#3QA!4!E!Ey()lA#h$6NeR5qkJLj zvch?bvs$UK);;+PgL!Qw&2^e1h+_!}Bq2gZ4P{hdAxf)8iis5M$2|PQjz38*nOtQs zax9<<6_Voz|AXJ%nuV!JHz^ncx?gPjBLej70?oQ@e;?a+^91le16NwxUu^)hpQP8@ zTKEX)-v%zO+nT%wTIZtkV;Oe;sNv?9C9M}Y!xaM5<{TC1{}#) zn`I;+YZi@W)AZgw-JJt@ga14H!iOLJAuvsY)_Irb&kwoz$}Mcy;_&b}g~BY3ZKK3u z^e!&Aw$z|ruhG98GF!;9zkAGNG^TUeAruO+erKJdqaz&0;r{&%ip3J5Wf^o@7j(Mk z++APi-raS?0DkwI-*Wf%ZPwOq;o3HqWr8P?OV6R}CMPH77^cDMttRQr47OttmZNx6 zA5~R3esRoXGD6B_=C&NiCaOe;Dltam5vw;>`R6AebAMw4RiCiCw~ssZxVF4Py-~(; zO?1OV*Hm;vM^#lcP2=drbE?%cmT94CI<{>irBdmw(ba&E6e63=piK;1Kfnj}_6~?f z6YT9i!*N`qkuYC9dc=Hb4nsFMJ~<^43885k@pz0}E>Edc{xp`TX-QkR*wGE{lLjB9X+l9SZpp zi;ZP^-2ti841-}0xm>O@Q8i`@^YnUc{`!}{A)3qo!S8wbLzh<@VO*}njRRBDDuB+O-hjA`1qwnMdA;j-VS zR;^%JI@9SCK@ho`Xvm!oPqv>B4n^49d;?V-BCo78QDQMdvdrVhPdGa}rg>wPcp`y1 znb2u>Fin%q%}r*KY4-N_2!+C2^m?3~od8fO&NCigarEMdd@jfP@Bf;eoo%wYEYjxY zgDu-~v2B}n=Nu)LWT9Ti&`e&vcMo0Duq}&ryG7vpB$5fn;~}H*2yZ%NW8*&g*))MC z;7vVB#S%aKa7?3K!8BAPNepj|$0JO`#Bm&6X|B?0oufp;ghFA$kto-1tnlLKh>MFJ zLExe3I&O|wB+r>03f*@crQ88_kAP_0f&vVv( zNh+B{jw>;W`2vU{-qhv4JKys5TR%g!4DQ^!ix32Op2ykg8MFC3nM{UQEJi#QBcGk+ z^z4L}XXhA(hV3{!HJ%~}0?A~O+CmLk*G($b3e{-^L(@4tI^dIspArZGwMLb}<%pG~ zCW;beGSPVQWSf5fl6X9hqC^lxnQFDla4^L4JTzS+o6C|;rx{$1k=}m$7hC)L`$&Ss z%kwi9stuG_3?-`Y;^=z_0%EZ!t@AdU8=I8!c?`?KbzDr#VSVim<#L6nq9BPs4!F0s z$Nc;pQ`bUtZH?unCEDFKsniUPVaWppQcH3B{jcJ+`=L#g^aWa`CuRnM|CX=OD zEU|X)Hlb*k;bg?ko40UW2Y2c+nOvdjS5#{i9zTABWtvP~mvC6%qSr_I>6>qEg(DHv zs|mN)ZWD=wXf*2hzC)+erc$YJaB#?U>S34`x~cQ<(}#$nh^ng8s%3oNMG^%r&Nqjzg`s@PD>~D2P~= zP5-jbvuAr0N=178KGkXkKkzXO8{4rteEu9kghH`MtuoKdOooUO;eQ(Jh{vgs%EEX>4Tx04R}tkv&MmKpe$iQ$;BiK|6>zWN4i%ii$W&6^me@v=v%)FuC*#nlvOS zE{=k0!NHHks)LKOt`4q(Aou~|=H{g6A|?JWDYS_3;J6>}?mh0_0Yam~RI_UWP&La) z#baVNw<`9$LO=im7)L~6rk+SIX5cx#?&0I>U6f~epZjz4DS49tK9P8i>4rtTK|Hf* z>74h8L#!kz#OK6g23?T&k?XR{Z=8z`3p_JqWK#3QA!4!E!Ey()lA#h$6NeR5qkJLj zvch?bvs$UK);;+PgL!Qw&2^e1h+_!}Bq2gZ4P{hdAxf)8iis5M$2|PQjz38*nOtQs zax9<<6_Voz|AXJ%nuV!JHz^ncx?gPjBLej70?oQ@e;?a+^91le16NwxUu^)hpQP8@ zTKEX)-v%zO+nT%wTzeM|bFDLpD3a^wTIF7TC*ba%e z*s)~KXtXb*(MU5r^!Fux!r%Y)56^X7{`t)}n5IcCn(`MbNut;96N|+O27}b= zb-LXio(r8$7Y~a{wa z=OO&%&wuqQl`@85kjZ8Nk8CDOr`sW*s*Ic=jYbpK1yPi#RLcD7laG1$@FCrP7uWTe zotfdS*;#VA9FF5)+crPmxyQ`(B$6zLR;#9g?brx{0Ejf2O-f6PNTS5l)D($Cf?B{15pq_4fy%!+Ev1#Fx_qkQI^ql1JkTA8jUeclR_~^zu)EH-~dq&kR*v8@7zUE z{5*PmpGLFBv**vL*J~KM&Z%Cd)oLKkOux07N~S0j3%KJkg1i6x1{1{zPEK_q zT9o0?!RM3F!W!vxhD0L4FE3tl?%X@nYgInH@&SIuk9c%+M4^x)5{dF)eFHquA`$j> z_mCtRMNtTaLM$&Y6AFbW6!ToZdRI)1-G zNDZ>_@G;3`8q;iGnkLiJ6C57ylSm{u`_3|{RDy`6@%?w-W7`&TuirzKLV z@xldEHOORffIR8ql1L;xx{l|0938!(QLkfE4ZisNb3&mIp6AhSw{e^iuXc6_C;|M6 zkKNr@#NtV|w_XqmsSGR&Q53m#>lV`d{Nn2F?jEUB3VS$23u~-zY)~}}Tz5n!lfmcn zlS-$s1{Rv8(P}s8TSGeS4xzA0G#W+3!y0t)`xFxK1Zq%ae{UaYa&l_bvijt5IV{WK z-`{;lu~_8X`DNPe7L{^^fImc`ki#eY*xGtQwc6mx(?@*p!TV_8Fn!CS*Xt7qsC@Co zADNq*BNzCn4ib&pu;i7GP)EX>4Tx04R}tkv&MmKpe$iQ$;BiK|6>zWN4i%ii$W&6^me@v=v%)FuC*#nlvOS zE{=k0!NHHks)LKOt`4q(Aou~|=H{g6A|?JWDYS_3;J6>}?mh0_0Yam~RI_UWP&La) z#baVNw<`9$LO=im7)L~6rk+SIX5cx#?&0I>U6f~epZjz4DS49tK9P8i>4rtTK|Hf* z>74h8L#!kz#OK6g23?T&k?XR{Z=8z`3p_JqWK#3QA!4!E!Ey()lA#h$6NeR5qkJLj zvch?bvs$UK);;+PgL!Qw&2^e1h+_!}Bq2gZ4P{hdAxf)8iis5M$2|PQjz38*nOtQs zax9<<6_Voz|AXJ%nuV!JHz^ncx?gPjBLej70?oQ@e;?a+^91le16NwxUu^)hpQP8@ zTKEX)-v%zO+nT%wTp4s;t%?uYbJa{gWfs{u?Ekw^-GVG7g^f+6kJf|Pr zM~vX_fBhTPN`;e?V-DWiW7Hp#N@U1qD>#lzv)N|pF8T1I2S{-UBA@AahP!l`O=i4p zzGXh2AhzE05fGS8=lH>f^OqOgKfTX?|MwsEZtbvK*<4&*V3bQpib5)*Qmz&eBoTxV zB!PUfKvGxv_Pg&mJ~?1#caL6w$i>A=q{^0gRyTKe_`!YNwOTA@4(l)?1TKGkjjmOkY1V5WYi!Z!beK<+}QnB#bKdls6Oq|uOgcK!?^I5|1Nb3*b)ftBx*&7>&i4VJEtrln}UX|Y_c$QfyV z^V`R~ZFXqBxh5h&(c(0(-r#vIv2|Lqa5ay*{ESkh%WJz#<4D4v!9yWQm>K27{r6=dCc!I){hHbUIzs zgodhWEEY?yuA01h^^*DArrqlDuGPk@Z4(3m2{nQA=+Vb#p6jz(t&rj}k|YxmGMmh} zwYy8+$Wbnqu*MdIu>amZDP0Ev=8HMowJPbfN*KV>USgWt2!v=!8GA8BeDUHHL9jvB z)A;TRBdybEw~>U1@n}r9*C&>UGqEPTYjtp(IUy0&WJJADXR(+O1QCi7L)VgIb%k%A ze$C70*L?T=E2KaD<2^A}u16F_L?L|i=n>!l@QkFcQ86oIGbyBpr$0Xv1p$8@Ac-OiXU6+S$H=OJ zk;{|PHI%r*mtTB=9FGx2P%4*Lc`IsF6KCnLS%*}s+jKi!Y{w>u0<7Tx1Oe&f;Z$qkGdQp(Yp%dxTNM!R-Tv!y&WTj9!0$ zEXx>1j$wao-(uRn9NYF^mi=&m*a-h?D7(>2yrL*Cz}k z%9RqjrePQv$|2kGrS$kP~sn^9hGXM}$#?xAK_JXDpl+wA(jGu^8?44RTy%vk8dH3d`k^ z#?B6JnoUGeLRA$elL>`Fo?+iY5=0jEgzEM-^TiA!lSS8c+MOP;jUN)16S$&>q!{ssYo zTrNwe(`LO6IXFB*ipBWq>u(4G0RaK&qYr;^X71ji-R&?O^yzmkA|ftdU4R%8Mn0z5 zpwqcQRTUh^!C5RZaz$#j8mW|yAc?4Il0n}h9+wfMh@myYG%Lg!dlg*Q!?ibL(s@j? zPWR>p*YlZ9r}!(MAc)B2ay);2L20YZz_KvS8etUDZg&`s2h3&;rw{IN`|tqQwaKJ1 cD5}E$0V?=!3Qy+C_5c6?07*qoM6N<$f;K}w0ssI2 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/textures/blocks/GabbroSand.png b/src/main/resources/assets/textures/blocks/GabbroSand.png new file mode 100644 index 0000000000000000000000000000000000000000..b562d38fb015279612d9da56c65601609b8f105f GIT binary patch literal 2167 zcmV--2#EKIP)EX>4Tx04R}tkv&MmKpe$iQ$;BiK|6>zWN4i%ii$W&6^me@v=v%)FuC*#nlvOS zE{=k0!NHHks)LKOt`4q(Aou~|=H{g6A|?JWDYS_3;J6>}?mh0_0Yam~RI_UWP&La) z#baVNw<`9$LO=im7)L~6rk+SIX5cx#?&0I>U6f~epZjz4DS49tK9P8i>4rtTK|Hf* z>74h8L#!kz#OK6g23?T&k?XR{Z=8z`3p_JqWK#3QA!4!E!Ey()lA#h$6NeR5qkJLj zvch?bvs$UK);;+PgL!Qw&2^e1h+_!}Bq2gZ4P{hdAxf)8iis5M$2|PQjz38*nOtQs zax9<<6_Voz|AXJ%nuV!JHz^ncx?gPjBLej70?oQ@e;?a+^91le16NwxUu^)hpQP8@ zTKEX)-v%zO+nT%wT4T(i;wS60on#6Z1p|Shlwu3p=)AjHtyZf&_9B@) z!}t57@4x?Rt?N3gRYo+Mv%9y)^>vRye?+6vptIFsI2=>tDF+8fq^p$E2Pgdd#W~3$ z!EtR=Rbv*07>3DO+e1+ldc6xAr-7mcLVEt6;#QIrLno3{``VKf@y`x6=sk5;RV5JKQOE{3k7=_+5o+z>@E^Ek#^ zYcr2#)Dp;=Lf}UziiD7%D0418eZp-t0OpezfP%M{D9v1}7n(|Gjg0bw}f^5POn zf^3zsy|azTvW!lri=ms8Wr?clWLd_19z$KD>l(Ul&}y}K^V4hUs>1gJ9zJ}8ZfKZ> zMY4$b@yCA=h5@Rg;5aUlkO+Jq;ZFlVqOL*L4P4j7Ff4RUqpm9s4h~Qhg)od*EMkVE zA&z6x>-8w|oXK>8EGyi*cY>;F_`wvLZ;szQkE5Yo{^?2Y{w=D0_wUV&vP_QW4TO_s1ZU&7=}Srm27U_ zLe~xM?BC()x`!kQc6WCfkH^@y&HnyAWl^GO8qsWqEDP2*)}gL(-3Doz62~z@NEo_- zX=1%Ox8d>)4J%zu#xEh%rrz z$z%l7G+dX%!+UJpx`mJ-ie|{$-R@bI=VYrK$FUeqCIGyD{~wZMiQ`zPn!)`C_bG~; zmgiBHC5~eQ629*vNdRD(7F*qIuC6{~=oX5qA%FLm@6KGe!7^QP`tUKmiymp3BFhTR zW&__3ff^wsnk|pvaDeYmfEwSQqN*x;dv_>`oG6Ou_rIVhGKWWZk!2aBEK3H1F_I+l z{Mj>hcD9gZnJAiL+cvJ_VmmfTlJN24f6+7*)3neuoj6{gC>mv%BS{jTx5ks-{*LF* zp0kJ-Twh%wE-!o3b&aA(7=}Wx*Tc3g9LHij9${K0TU(n0V_ z|DN@A58HNVHa&FRAXzL}ty13n^qR6N5l2V&a9xWhPagmJ!g9GH3_~o-psp+4zkg3v z)%@e{e`7T2MOjuH9UXJ$&HG$@LKAPBg*xgm~Yiaa9- zCg{3Or_&+Ja*Cp0u}J84yR_HV*xlX5pHA_8A8~PUi6jZKtibcy^m;v>K7EQL)hyEl z)71I)+duq5Qeo;(X*OHjzP-cKr{AFKDzXsBvdnliLe&&hRig&Bwz|m2$0uiBef14x zS>U=3MUm6*k4e)ML)WRQ3g4fyv$Kn3IShvbilSr|Mhu1{f*=B^!f_nJS@835NK7YF zOw&X@IXO8S4hCqNj_0*FJ$-~_nV6y=Kl7uWPESD*& zs?lnBbUNF3-Ws0Q;_&c*vaC>54a>BUg+{yG=JxI`ZllS&ckhq{7>3PY&_|IZXf&FH zVMq}8B*_9%J|PTdgtLG=FKISgxUPe$Dr{`rBFi!+;~{}RrPXS( zv2jEghRCvv&~=@ zaB^>EX>4U6ba`-PAZ2)IW&i+q+O3-Bkt92Ih5y3}ngA`#fsCLBG@su=W>xphE;p7z zPQTZpL?&>>5f^3lfBok%|G~dhqct&=np@76f3d~pJHJ%>{Ok9-v+;g^{`frS{(Rhg zpYS{s_!*u*YknW!JnnhDe;=RkbvloyUl(foePaCiM1L>j>wAOu@z0Hddv0Lg3!DC4 zDERlz@%ei^+p@XU@_P&Oef@c#zhU5iqi-=3pHp@v@;!Q6N^bmKy^V#qEiLp+-}JsT z-V6QpxB0x(vnIcT3zqLyD-8PIh0f3CJGbDs!0#y(zQ^F7m69!QY~lCziR-`q_perN zK1+X7{zpo`zq$Y6@n4xXH=v&M7?Ita@ z>~hsmJ&ubx-tvF?GXKtt&QU`-XX`gstjnt$S%os^oUx9Vkr8*^pr#w(&)47ol-EE8 z(+zWFgWV2Yf%K2$eu^vHL}>Jg6z2$JB|)8~ zdm3tx7MGG=EYimiGRdI}xHs=9?!MF~|2zy3l86+tq5Ucu>Le@1ME#UlsiB@iiYcX> zN~)=)o&f zPB`(TlTSJIG;{hlYj0Zr;p=~qHTP!C-%RO+<(oAgE#-3wCpbyU85#5RE*Vn>Trl1% zXSTW+y)vhq+2-krsSOoW8|c32dfoAib!y6F2XrhkoVClDlMAFslhhgeHhM~T@T1uiBYjeq z?$w8j$K~E!o7Hon6~-Ltq!6bqDIQ)o!%4js$5NXSD(dcVIZv%}xB^f2mV9EvGlPD1 zkCa$K*eil#zK_E4cAsbEZdVO!cSA9T%sRr#pp9qEE7j9iN_}ju;?L|eR<}y+?9s8I zwey*~0++KVw|oORiy4b;#=cyrDG{7HPl%06juLwY1HkGL^^U`hN|-6FKdwhT2HU&g z_Io!iVV}+8<&3GIwyN*8hdq<)1vb{-0gDuUyEtB*&R(_=f!LjfXB!3gg2AiL~V>Qdn8&sI#x1Ebv3A~ zNL?L(!RK4U@Pu6y{f&v^jd6j$NR&9;yX$1f8a>vHkg6sh76xj8eG6F4Pbt7QwD-1W zXOh)Z^{l@F4s=OLthv%i{0u2g`q3k6^tQeF$h?o05rA791|x{Sa;KAgn#5OXOvxr~?cLNpeJS4iJcH zLms~=%4>jX^MYgI?NlNd-Kd?tD7s3xX9>flT?42-T27Qg9|553b((4^n={gEy!JGu z%fUkQHl4#IeI5C>3IW|qP3qL7qt}paW!=2f(~c(B6WUm`i4{KOIv#k63D%(&#sIES zL}4yZ=4_0VeuFn@s0?ZX%sBu{qU^a&Th@ov8{`OO9T@IJP-N|sW6aa0xZ8qKY)$}z z(#fp?RlNr2MZtD6_L$({3tx~V9J&)l(ECkHg7LzF{%g(h8Z^K}z_B8(baoJ5aKCM8 z9w9@4UDYu%#p*kR;sfSe)f`BBIw4AMj;C5 zfLXL0J(i|g(+LKF`(#u-WT!@?r-P0qq*zTsUXg>`CjbD1heI{dH(Zez<~(Yhq)+BB z06GoIrZOl*gu|^G0nt`3P1W0ucBiXMLp^X6T2LS? z^et@(4*i80QA(z4ARUJY7T%=elNQHT7CjMRCED2(9vyS80S#8&i`;`j@car7ThQXm z)4Fsg_@s-1qfi*Fs+0ZAunWpsFK>F z0&}{$dM!g2Mzn$TnFfOUCd7rpMqFoZ>5*d_K~0Zk+!#1S>0`zb_P6K34|G_dhs?OT za_=PRfGd+=1F}TEVw1gL6ZF)MpoAZ3ZKx=s@;6L7&lJ3FBttPsUjaSMu1OIfvFP!9 z{Ed5ns!&S}XsJ|3(p@SJfUAQ|AOZ{xS|Po*Np8SeJK&s>L$g#ET;6cJw9V3S~3gll%&swHgFPG1QFk@cKG zm}-!>RK|n<2!5|Rx>4y$^IVE&DA{i`=+!cES|6BW_qAO{?gn*SyDe&4Pe#D=_uUC? zH9V4lDgt=@PY0(-(N(VaNFwT<)ETrT6~#W@p2t@Ewx{mq>3q{JoY(=-FAC`otT~x6{i6OH;kFM(CXu*=6xQ<_U<)}R-!4)^ z)fg@?jRJKqJm9ijn1#a4yFS}`KoOrsXCGR&jkzVMfd3f^stxW!rb*0!KQjg)Ne#vZ zaWI56_uUf>C}sfT2>K&%}O&C0ENp+ ze7A4KMhvWni~&!W4ZNUrM!kG#-X|w^!%LVyV!}~>x&oPyJR+qm4|TB`;2NXHvmu#* z*(B>lf|KdcTMfPe>{0-$rE6mFZ&vU`nKb%_9XwLx|-yfK}XwDOuSt9%j{g4ZvCmmX@1d1Lyir9fjom5R|C zLS^oQc*5K{gY1SeU}9zF#rE2KewUH4c_;;bSoV(R(vO zh^mYQmDEINsZ}k3h2Mj(APPO{%r!38$)UZIrV_SkrUqtb2(}?-R%I;>EikH}o_@NG zgolx*(m8`<&C*=czfM(J9~jvkAduIkz44vo4P%YE0@JAY2j%2%G}V-3E+~$xYQwOI z7@8Zw5a1>isFPAqZ)5r0oQQpxL~ceSnasHK40) zs@MBLe#DGZMY!D-Nl`A4&=1*Uv1qdh@&m487BL)(0!mBhvk|*xNKI~wFhYnGw8Cx% z%D*ZiFO4D6IlqSx0^fxR(QqNX<`8x)6RAf{MOlePm$(AB`W0@1??XF^mYD@Bv zE`%(r=~OaVJemAsdEG~D3EB``wMsfeBhWM|{>IanS7EnRBS}CJYK~^CG=&8Et2Gn> z1ONuD<&RUeFxza!iv6Fdf%c3SXOmo(pFNv8tV^9>+I7!`E@lr96v_M<+ad<29L&Wt zsamsp4fM&9hF%AAf1;7z<;I$gPQ3RnBAZ^O#!T!*_6`IZ8VPFWP7}!4pbj`HBN6d) zEz&ZkL25FL-}yI?AjD;Zi^98NJlsNSD|`_DK&|19E7sGUs~ZhquX`heU>F(#5_Q;t zVWql=NBJd(z?g_357Kp!-q@ERp*W%0fZ9ejzkh#Y;v(^#QjGYV9Kq3Hk+-ce$g-DL{OUI^`STFtnqFVYEhgv;o!YH1l`vPGI4j z^AH<%Od7)rS$o3A0Z*5}sX(b@eBfodwEvjKgV`FFDP8n}dsPHwIpb%t|I+x;FcUOD z(aeY!KSk2cR%E+$sX_fqxp;Iweq)j0_??x&(9e`$aEGotU;w;kks9F?<)G8a0&8y& zZjc8>UZ(|ww9Y%y2Nh03(PK@(+b90S(4)X5Yt)nHjhq)5DHZ~jjcZvE7tSK8~OmT2VYHP4|#hE6bY0+dGi zm@T7`J63%y%+f+f0qo`K*{N$FjDH(+%|$6D)>Pjylnr>A24Na98|WLIPDFKuzsDmd ztn1j4j)FEzYffWaeA>AOiaJF8J=kc=Oq2rjSdk%aq3Y|^H5#+C0nmIxMu7H3_Wm5v zXhwFxx!!s4JySqq7#AJ~2eE@8z!=Iv^UtLuajC7LOZK9lMGxwr*J^6CWE&?74PXpX z&pe%9zMUVwoxeaf4+-jwD2ugqmV1u^kxPQ=qQoGQupl8CmaZ#&=W^@Zy0LQ+|4;oq zQ%-P4obBwU`@uF!^*sx*d7Bn>lsO%3{A?05pr;6dNLHWek&A$MaT+<{es%nJ`;awN z??2Nk!@ZjZ^_w_#i^1WI517K^i0(O_%Dt>j$-tylgEk$P>60QQ?xR>4yx8MP6OJAz zXjb=@3HDi38-J(^xE=8x$3=`=yKc4l`b_Z6bDUD7pQCf#R>@hxu^hscIg;f%z)5l! zC^bN`94{H+F|I^r@EhE}Eg2j?Ltl2Jsa8Wp0eTvrmiwuy-Nc-=+3%>{0T&1_$ZzIg zXpfkuCNDJ>AS|nRq+V5oGdOYLJ;u}sf~F!zP4mDcc*6sJJg$*X)u&poLOvLnSnizw7{MEHrsTfSjzOpVoUe?E1zlUvf_Xv%i@fy2n5&o}3 zpFk}}$uyIOLp!Nw>X8-vC?uT>NYTH7o(rX?K-n&(7Fto%J%r54@45O0)Icrd0_xO$s#&c%&IWog0qIl`f zS%V}4oe`v(TT9gn`T=A!#O6&OTU38vuUQdhBh3qGGtVni?|G3^WtKp>!$cSgv@)2d z5t3}yijQj1jH>*`JPndjkzQxm`iuXq8H3_o{l=dA}St&HW)|H88ZC8+IKb(skf`WhA&4bTl$I8iF+bCI7S=O*XtB zceU1lr$|>*@x~^XZJtFZ)h|*bsch25ct>pdpv=05tW6`D1UgdJF2Fv0vW22Kf-B}7 zB&_=}2}%kbzI2{fgS;KPEwl?l83%fY02EGYJm@w0l`3^2k1)-+;3(4cKWD1}lGo!J z%5HlLleSqpjf9M*KBI(796Cr#IvST>L-IU6NwetsoENHKtfm5p3s1$*pNYnxkx6CI z=c6=e&?vfT#&3|cw~zHv1|23Jeah&^;fy*Hz~=77($S%2j^~A< z7$X8xAA)KY*^L(M$hM_v;~1#gXV|O>yEx*$Wn(s5-oUvE_yoeKVq2esy$%}U1u0w% zh`RjwYyeFP%qP;XnJwk3qwn%_=!pDoe?k{QRx#pIH8{@tL@aEn0}s`=(I)~nJ@b1u ztE~Xc-Hyt2kvn7szNfg*njpWsmk$(Qeh=;7wGo~P@yEKJ;xf1{qR& z!Ty{D4^000SaNLh0L04^f{04^f|c%?sf00007bV*G`2ju|- z3OOp^_g~Ba000?uMObu0Z*6U5Zgc=ca%Ew3Wn>_CX>@2HM@dakSAh-}000HwNklSqHvObXpK7sP_eV?LkC{8EVSM(RV#sYlP?X^!i3O_E>Al z^PIceJ5Yi!PB`1%kY-Cp>xd#BB^2W@ptqM>+-&K_fqHiYrJ356^?E_qwS0GfkDW&T z^Z5%>N*oGLYO*ZhSQHpxh$Dlw7NZOZMc;HJNy4E#p{ue+0!qIVt(aNm5$p3c(kX-x z9J+?>W`nVort8^Up3}B1aS$bE14WwWyd94CTC!NK0nl2pz1Sdxpr0qY zp(e|7{{7=WF~%^OiNN#ml)_kxOwx#9w1ifFgp>j^ z4hRX4504CePaOJKYtdQ~#32$%TQ!_tUDC~ly6XYBxxPUMfx^v>BuyCmjxdf$)0AnN zaKb~o4ZFjUvT9f_GD4+^;{z+hUo*Vi12BX%@IVTyI`eS_zhH|lZVuzREH z8s45BY1<0RgdHtb8k+jV#}8lQ`-*9vY3d3oC7$-NcA~0U+%(fx4Q+kG%wVvbiV}T1 zmNZR=Glt9UIT%BKs)+IooM0N^`udXURIxcf0|SE@>Dq=w`B-C60>1q6i8M>eHWz@Q zX(qhbM+123-HdSQUt^6S z3R0TBMotEu=Q-EsXS^PEXsPkEW`Eq{P#nu6Km6_o@C5VVA!b8a97(ek+7J2s>nDa` zz|EG(*W_6Sz%vOts#`j}_G+~$xVVa}U zh#*V3xxXjyeLM+TYXHn_kWw*C|NEBhcFWj}RCSG1ig9ub^UT%t6;dgNsi&wa{2*bu z+0Z*!UEHyIeWsfyZtuTBM-f2~&<-6aP+E|$^7k;Ov1KqL>wHDk55!5#{deDUDh>z? zN zaB^>EX>4U6ba`-PAZ2)IW&i+q+O3;ek|euvMgOr1Edlee9E@h#ftIgx5s_KdO^QaD z)WugrW@H2acfW%JH2c5)^O*nOUoIt@m`cqpXUo6XV)LC}s(t?T``y`izdwI`-gAGx zZoY4LUJCpS&!08FuWw%WT<_o4=X;;d>*?2x+J4^{f4+NSnK$pEtr^5z616|MYd2eqJ}fLwe)(>&ZEPpZv$`wtW`k zCvxT!zH?SRXFs#+F*D`-PU+%uf|uUBqn*ZNV37#bj^9f zcwBVLb$8spKc|}vG5YNbKfRv>cN$)-1f%(R!yNVHjxV8w6)FiZNr%9z{yP?TAKUKZ zCMCA)a@CMMj+;3?@_+g=|IS6{sGyv)^}AM#%d65Dg(Byiv5w1#h&%71rn|tOufP8( zu7L=qyUdjdb~|(j!atJxNv?1M9k?*@^C@6g)_Vh%h!G?P;{p+|*@fh?v&DN;oMRy? z0qP9hQ&5AjxRm^2kUoZx2@X}jv-wPM_fnty^D;n4AX3PN@~cFs6Ra2$`BP#ghk6Pr zrj&9jsiu~C4p|kJbIC%~UP6f_6;QU+(n>cq)L2u^wbWW$?aj9U;-*GDw%S_joriYr z-1&6pg5HN8VZ@O}9%awgh7_eRa%Na@1zjT*0(^0|c*oFv7Ji23LUcu@pg zFy1R>wz?R-BBz+y=BbM08Dvs$mQ%!tVBF59Pg&Y>nwtGQa*F{RQt?O zkB@_wPI7U^M9@ZLSbKXeMFj-kh-I54q{N7j1DVOX*-jY;(m$=QO;qi0nQ+G0h-4^> zQ6)mt7lrS^=dj02zOaU2CDW^OeZ-YFvnqQPU%Ed##hJ%wAuLypM^V&8kPde$XRSV( z5`ue&*$T^BlQ~>YM7k%IrJdY~VNiIa_n`ar{ zCrJo;*O)hJ!n&3a*9mDX%EXg@%M)-$<7XKwkZ-U8i)PziEPHO}l-$iugrP8=xQHmK z1!`H5q0RPAi@IHu3Zq_!s*mIBZO_iR&%y{3fA+FX%tK{0dLcm>kw040IUzSy=r}xP z>kL7(uVSADMeb}}451_~;1C#DsN zLvYSY_4Jh>W@HWN9uoyWRvEU}F;_lOvW=XE|5_(09r;7p+_H^yDsxYz+#Eh|quO^3 zdjbB3LG6_0+AV2ZEW={nj%Dy8`_}v^!52r0j8!-Pn-sl|hiY*o=v<45m{lmY!7!ty zn_Any=+XBFbQ%9s#j2cRC`U)K;{+<__{z79ceQ*^n}4 zt`j5mlMaSDg)B$}t_Hjt;mANHyao>lxAplw+@1bbrrzIN>W%`jLL|=vqk(y~k z9!5xIhFSAmGolf0MU0)#0U}hO+$0ZAu;R{Dnv(VBDITV)iwZDn1nP86ZV0RG5V_^_ zi$Dc9gW6maU;W}Cg?r|Z-gGJSU79TBY9rvXNj!k2`HW~9*JS5{%>W3Vh3u@8%RmL} z+67ZA%L4y0rQ}JvdJU#|ph%Xs4S_m==2_mI&?Gcq^DtTAJ*6C&WJF-3(M2AsdKeHb zp>#0hCu;;}xPeC+CC)=tPTLPEffDck^c#-Mv!bq~f zMzwWU#fiRmg2yBqVR=f6!QJAb+#*nZ&@uVGS_IsJ5!ksxgMIUSB!tAvb`CkhLiNuh zTrP83nUY-jToCvI@}5-*(AO{-`9R(Uj56sJD|ih_lA|pZidZBS+s&6|!BSlY?jnF@ zi5q`)=awcy>setw&#bOqwGI5ky4@+}Sq%5Mu5rrnv#3a#B=%X`^ zqYjJeuyrqF+83Ev4nD<@J;=nU@>9%&>;P?HkdnEz7&@_qAdwymUtu?RilFE9u9LoNjEtJk!6E>h6GFx<Suin~>1l>Wc06G2hI_BV!`QV7~>Ofe-fUZb8)cF`; zC%nk!0>py%Z3*r3)pC@5ex*LTqN108`g#}_tB92J@LJe&3Tn`{tTFoDCaRPP&I=1( z9_|NGa861dAl6E8LlE#FzN#CnE#jM+RB3=IqJTrGP&rz?jXXQ;(xbbmPCAd8Z^sF` zApjNuQ-fe+k*M8A;dn{8vjJlu5lFaWKpQSgf*MMa{DIQ;&5m@{{~3r2kPy-Yc88=% zQOfTvq;N3EQy2#ECRcD>V16+8;vz(Yu!TMK)KIOG-`_&PAAn5(hy?RIBNSd_(`R@K zCwB`-pc^tzhOJ3x+_{npvBokMCPM|0<%6k3iEjuSl=!W-{oxX(vLRtX9(vD!$Z{ktuhgKD{b3C#A8K#j$w9 zj1I>YTv8TgIK1f!PK4rlOh=9&N9s+u?-FiG}U~Xqh~Xh^JFTc z6Ae{iKk0b@4xou5TvzIKk{gstPV&A3L8wEE6^H5TL7%i?{+w@cRdyPyhrFqnNhbvt z@wp*6xeJ*+5|gNtd6-ve|E@wZ*`6dL0wKc0r-;#*I`t76poLl%7awRwSWZ35v0H+M z3Q4s>mnkx=V7Nab1BzNp6=h4t@S^qO)yF{Q*A+dftG+k1A^FvjZ!)F$-CoV+-b;EE zvPXs`EFyg1twY!pr3PkFlj553D2PO&4Y^zUW9yQag<$nipHXdd4Bb+jp^((UWeceU z>dvZiB?d6SR3N47u%d8{DC*dkbz($VPPk|o1 z9Z|=W!j)@}Si?v3VLF98iaa=Lhf~B)V~wr}rwqKpdswR`rtVoO*wFCt0UR}VL`R5g zQ*_~YFRVSv$q?7FqhzeiOC5+QwY^nds6EuhL=#~(2nedCQ7;Xqm9#v}oauLHz+->Z zFo0^V-u137b+aG2Yn|_E{Q#*bhl&Wss}fHLQoNx4yeEIy5_+L0cpD%@rYNIva54a#g6UZHCl``VT-fx&bZJV%bY9U6K@DhGu3&xu*26 z%eh(G@vs}4frdrb$6%Nq;_q5=o>VlyU4VWjpl~kGVa}z-y+qHsDqu@3-(JqHQqJmB znxhmh0C?;q$67Z}Q{h6b#GnSZI6cn*8p~XeE{DNv^`IhdQ$UK^FftGmjfN^~4)cUb zq@4HV8I{9^e&M@Pu7!2Aa&0=TJjqHGAJ&cKLDpc8)P2Z|Q9=w|Nc!dsKLNJX=h^Gi zt-?yQmZNt1v{K}mFn7Q~$#@hcUJbAg_I4dl^J2&LX_PWXhzp9vFK_991?e+REN8OH zO!Y>fBNj}WH9YM9G{;~;H9e5rND2fY>YpT*)!tGOh+G2wGBdEZ@`aJ~wq%gj4J|@M zFcTfi0qu>DAJI9VCK4J7_YlEBEKl3&A|fWW=9N6k>ZHu>o_?*zE<%N1cUA>gz#Ey0 ztGXLFRBb~`fn*!O*B1h9L#%i(gLRLE{O`Ib`(|M!v}FOdQ6tzG7jj}EvhpYWkwsK@ zqf$y9l(wN-bOYuvVK&k>O8Tt<*d1w4_iec#+T7FWzWu`WXoAP3lSk#J9S-ZAKDEEs zmCe8g^h#0Hy>tHMKcLgqCfNfC3{XepmrZ_QCr$aL@k!{^(>}jRAUf3q7huHDH?e9ZzdF83z#53G7!v z3018A`>x8UqKu;WmhOkcIvypj24T2M{j=moYc9}>IX@k45OPYFYC9|!biDQmuUnuX zvSvkTOceBjZ3jL%IR`A7k3&El+ap@fCGX}xjs0=&;6aV?be5T}grG#RwoyisxODIu z(j5iJrw|wADETq-*FP|Y+orh&wn=6@&4IeQxM?XvNEN764LuVab_c)bhg1Zfbv@;~ zuQ>1O=-`#ICKShNOI;(Byj9TzsSR*foiKA-Ba~{qD!lAFLA5U|(uc}fKb}U7X*`dk zO5r4QnC7~$X7^eg`kiGgC1GDWYRTg>tkD7DByk$U-1*l>Dz5jUv%qo8$J z*$%CRRhFQ2)sEctc18a!WdH4L2V#NYBJ16)T4L}G60DVZ-U1l_0mcYpRcxn z25)l^8Iqr9If3L39v*{QTqf0W`=Ly>XQs-)DZ{;Di$6Dn|#$Xmiuk+&hlHl$M7|#i&?KjM1kJ_f= zb|`p1k5XfxMv$+_Q8c%LJk^{=vOJxxS=4D;YH*$3ro5XPg)m{1TT_-TKwL;Ee=W&62;X(Y{$9tuDv?(!*Y||plnuRuKm)d2lsAOGHYsF{-#ph?g zXpZvjIrQrV0{(nj3CHp@VsPk4xomlYxkgoeQSC-Y0(QBSI#c3#XR$Kc7Lb=YToeRg#|kt!4+#h6!$MG^tSWg#7|3?*ZWT#;*8!7B#4Ckig|Hys zQZ{XM@(X;@wwKI#b~{n*NXPbQ$n23I+9$F|E*+Rb=3f8bVD9qh^zo}@07YSVSZ7vO zy))Q3Zj`^8V(LDs7mT;gIyazA8$!t}M<@4U){d$3o{@AIUKqMsS|F2cIs?YkD2Lmk z&`0~zK81$MXu=t4f2bRbZV&TZ5P?oV&K;ORehcGK4Qh;oZ_PgKIBtm2ULzJ6SD*G+ z^`bc3(4%zoH5K?~(X8xJpROe9i5jVHYo0(MCPYo_x!=A+w5&8Njh;=?oAWC-5%ikm zHGnz=K@J*H^Si@DveyZ}60NPBHHv|#eYZK@H5GkN6!vJKh2hyiT!~JA+or z%85Nq#~+FJ$eMgNoRRY7o|_b85iU$y{7Af5yJwMbmS`Jo+k%TpB6tK@mf*}xso_ha zjyh;}rB_i5dd&TD8r%qk0UWpmFLgC99b<~oi8nIqW7ND9;G^ht%mf&)z>&POR1_cH zTG2*YK4v|WQbWfy=AK>Rb^+@UjKQoPfRH7D4%B)Lct)LF86OYdmyYysJINkbaqYMy zow@t;0g$Ds7(@xI0!xOat;JY{j5fY)Y8^xAp*b}DMr31?Tn^eD!4=(Yj{Ml<-pwT6 zG8%aTd(9_wvOIMeTU{jN=RIBlJN%>kyhjAkcm3)+=m=Z{@*k+xUV+7%vu=@Ca3S6* z-cuutW|9gik9X59fou+~$~fb624O~->x}5{+!+ZIt79$N9osrAJG9kLjkKW_QIBuq zo;e4r;xKP@XpG^r6G#8dg-5~5oV`N8)d|YbO-W1Pra1C^TI;qnrF~r|V-n_5y zv{l2`6G8SZR`nD%2AT!|fvpds>@!k$qU>SpfAbN$_Z#&n90 z{jg5@_OCMz+WG@W4MM<1e;X~_&ZgVVkg!a*LzzjemNWU?Z4I|R!p#iK*dGll1I7!% z^6^VDE--0u_mUKvMO;tqQfk?6^*qRh@^%=;W97At!>eZD$wC+yNO45=QYP3f@)IG$ z3>{-gjyhld*#`XXQMruaEcho(pc|&an79QhrF}X}xExX<-BV@~Zh1;8=XyyG3Ovfh z-7hs$nku;i_$zEH-;NUUxFNbI=BZN{&f|{4a|%Z7px@#W+uhzXPN1(%%jlqu`sWD4 zju?)9xB70Hh_Oe{kER~s%h@)sicdr?;1vM9rLA8RbRZ#Xzw_$hr(+Ga-A+f9m*E-sL_#_nOJ8Pq>ec}$Fq>nXn0Q+0&JOd))6Z{M3tc+o;`J>$+b5+ zenSyVa{@oMOgLm!!*5~bbTA1mxzuv`9;Ub*8nwb1lFd^G$K}M0b`9tGZk(W?;OP6u z*jGG4vH%uinD;TuR4=Qw~}-i=Qek;89_QU!>zN+c@`E3NQnv3hDYX4{<3Oh2J_a2 zB`Qjr18Rq9Ti+dSbQ{=K9YzG|y2f7HGu{Pkr0Bl5tuw8qsM!mPr@_kG-EliA%2VH$M01A6^F=cljOCJDiM&5O@paKD@* zUEjybGkQ;sStl8Fx6bWkLaH?wl2*fKzF1JE8D6u2<#_nr0nuhj&90GW8H?!zou>qw zkZlyvZnwFe+)nn93x}Vw&9^ z-EIfBRzs&TS6A=(?Bpq<(TH^t5v~J@qCf(mAzm%G`EZMrih85Ta<(MZ1==u>DkF*3 zq;Z5%f$2BNk~Nd-3BBDej@zfqHE&+OW*x=UT?ef-QcC1{agTBxZZB_ma`c!Y)0BD2 zG~FU(4ac!5;)t8s6wh@zcyh$$`Fny@fFTT`DCFVp04WXDVN9p#(;fC%&6dJK3@=T)|3b=$7b|!2S*7?45YI7^!aDZr(-&eI+o)iq~gWTz9L8x#C1SFxnx@H9`nn3qJk&8=9>yX|9>B zH@v&}Kweff8Xid$lOzejW=W=VqyhawpJba+VtmYa8z($`^pK-3o@1DjWw@cz6^`Su z33JZ>`yJO;*Bn3pgnp+9K&R!iUaj#wk7Sz@h9TrRQ52D+Iku%p)0C&rj*uo57jMs~ zs*1h65oK9oR1u}lSuU3V^!t6ze|*beFd)h2h%jb%{}Iy<*GS_djA@!^T~KVd0JyeA zg+%6M#o_*tjB&W_Mg&UeVcofLk+AQh?T2j*DfP zoPGC_^=yL9GHlPM-QB^IHCCID@pw!e#(1uW0Ql*LQ~vgszfx8uX%bU!b?9~4R8__G z`8!<4!?tW3$ALnVW*K>&vwM7u<<>BzNv?CGFmP%PMV1o9F^7kH2un#$jz2+E0z)Zm z&*MM;`j%$D%kJ(jy=EKXxHQ`x0FWkjz0N$0`2O$zAcmLPajq7+MVNA_&N%Jk^%L~Rg*E~M?gofi`6q;vWykPY3fZgGc zZIU9SBCkp;+oDnT80|ga^vyZOpML+_3L)?uk8QTa_F4#OFqzy@=?d2pWLZYO%}I-b zs;qE5i~eB9;P8aYA78RwuSt>w+x4jO97>I{9IC2BMqvUblw}DTnmv!AC^$TMPJ1xo z{j2W~n~>%F1DGbJ3FsR4_X{vi(HMB1M{j3HvI)446O?I?rd#^MA<}UzhKGmz@bB*d z5at!ab{LPZanIhM4Vd2E;@0cLQH&5KNwTG`Ear zce8t5zkEfOW?0fB3M0yGf~72SonzM&zUL4}G0&epW&hwIhLnU!grjO0LSmSb%lBsp zVe<6z&rptyZ7aINosXFoMMb~crqG(QENS=KbUGc%vLp;cgfOveo4e_h`69r!6^>J< z(Q320UvRX)$Eeq)X4N=5ea)cX!>-xvAAgGR=Rf?e%CeI4s|ySyQW+F^Mbq~P!ib&W z19VZ46&bCD&vY{7=-G3E#T`|i69fTKmZC6t^yCrBRCEU;-v024%{oNBKD%P4-^RA< z6h)2@5@lDc)*+3$i!KV3V?hFo#fmS!{y9~pnBCn{Qwj_dRT&skGQF8nmYOgOS%(R_ zG7zroQWhmyk#R5@&}_IETI1C{GzNkS+qO}%MrY7vn`F$!S0qVFRS6DGo>6Z$QA)AR z3%>l-*91X;QUYBR$eotY&2&NCwwW&jy1PBP!vh-K23K$1Atm&8_jq;lPsFNZy|||` z1eTKctqzXY;K7q4&QDM2wtY^&eMuap|6jf4f3uo9;_F?P_5c6?07*qoM6N<$g4lWm Al>h($ diff --git a/src/main/resources/assets/textures/blocks/LimestoneCracked.png b/src/main/resources/assets/textures/blocks/LimestoneCracked.png new file mode 100644 index 0000000000000000000000000000000000000000..588f8361bc68478471bd411335aa5c30ff0d2f01 GIT binary patch literal 1919 zcmV-_2Y~pAP)EX>4Tx04R}tkv&MmKpe$iQ$;BiK|6>zWN4i%ii$W&6^me@v=v%)FuC*#nlvOS zE{=k0!NHHks)LKOt`4q(Aou~|=H{g6A|?JWDYS_3;J6>}?mh0_0Yam~RI_UWP&La) z#baVNw<`9$LO=im7)L~6rk+SIX5cx#?&0I>U6f~epZjz4DS49tK9P8i>4rtTK|Hf* z>74h8L#!kz#OK6g23?T&k?XR{Z=8z`3p_JqWK#3QA!4!E!Ey()lA#h$6NeR5qkJLj zvch?bvs$UK);;+PgL!Qw&2^e1h+_!}Bq2gZ4P{hdAxf)8iis5M$2|PQjz38*nOtQs zax9<<6_Voz|AXJ%nuV!JHz^ncx?gPjBLej70?oQ@e;?a+^91le16NwxUu^)hpQP8@ zTKEX)-v%zO+nT%wTz1-Q@18+r2%;y?fXSH9gAo*o~lsuBRD zH9`o2_jn&DijuF--WZqgAO!2WV+%`4iNoPQQ&;#9kU}C54E;ci5h>t#zH$07B8A{M3}|aD zQYxydB812=41^HawjCc9hC|1`?`-=ADu9HAXA6QiKpG zY{B_@W!+bD&U9@@*By9ze1lSg)9VkWdExu_7xsN8#>n&c7xcPr?9LH?w;1 zB_&b{5a7awwTA07@$tiZLQ13<*>*=xk+;7*@%;QkT~$Uak{bE1IU^ za5!*iTZ}d=>jnsvlo+L%mzkz%a3Nr|BISgV5^D>L(HLXconz=*ilX4#^NE-;dfz=t z?RdY?_bnhWMpG1qAL9>%6j)=4G2L~p1erurm&BB~UM4aMV=XynrrS)65v>(vS)kjd z!g-G|n)$X+*A>qH7z*vcNeH2topx5+Nk4wWOSpQu6NITh8Yz$K!xj5-BA) z!?Jl|OdJj^^Rja2TC@}bTNF6w@ZOViMkz%M9>~NXu+|`z#u@`cAcP?0#O*dS^c~K7 zQcR=-+qQDO-jGsaw7xr82>}S4kN5o08s|ORG*Oln<9MO03UY?7ZSFHlG0zKq-=U=B zdYy^gAtZL^3Ep9iK?p%k87UO|?#L-Iju)ho%(t1gtvS7p7-RVI z^_i3sAw*Kj1RtoHiicr9X@yqu-ldmqV_8-XhnBu;`SSHUF((RZ+4h}({^NIijEv)j zd09F32kNHca=l@Up)BtgYONXio}44zd$e<&>2@Qg#P6Rz0I=_#=BGc}w&7vu`SbJt z82XNfW6!pi%(wYowPi)hk;gX=eEIr}0HlO{5A559cHR?XWZymBIh0ZuEvc*OuAC5X zDbjTnr`M6&yr7gMr;L)4rl~2cCWMG{4r}dCCu_#d@qeLLF*?Dh`l$c_002ovPDHLk FV1j>8dR71c literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/textures/blocks/LimestoneGravel.png b/src/main/resources/assets/textures/blocks/LimestoneGravel.png new file mode 100644 index 0000000000000000000000000000000000000000..d5229d7e57817d75d3a5509927bdae331b24601f GIT binary patch literal 1998 zcmV;<2Qm1GP)EX>4Tx04R}tkv&MmKpe$iQ>7vmK|6>zM5s;{L`57+6^me@v=v%)FuC*#nlvOS zE{=k0!NHHks)LKOt`4q(Aou~|=H{g6A|?JWDYS_3;J6>}?mh0_0Yam~RI_UmP&La) z#baVNw<-o+As~POj6#%{sVCBl8F-Gbd-(Wz7vWjn=l&dhO5S9EPb7{q-LQx^h-Wt~ zo%23%h?OLT_?&pcpbHW|a$R=$jdRgqfoFz{OlqDuL@X9NSngm}GF0Lj;;^D>lrLmm zRyc2QRx35ux+i~OFt4qoxlVHgaV#N$Bt*!lp^OSFL}=AWF_EJEn1_GZ@h8b8ldB9y zjs;YqLUR1zfAG6ovoJm7CIw?a_ls?Ri~)gNpjo%=?_=9;o&f%5;7V)zs|{f8lk|F9 z3m*af+rY(jTa)*I%N=0oNtX=Ck^D4;LIHR`qi@OqgSSBMn%i4zAEysMhPqn50S*p< z@gilfd%U}+v$ucGwEFu2a%XaRzkDc_ zlB!g%u6DN>@XUBY*a1Nh@VDU)z{=9z@zWRHynD~0EV$qAFu5V6 zNLekI=D>e``iXHI5D4nJrtb$%rz6ue(+?who+r9%BF{2bbn%b+ zRhF16!?}^Jy|AbXw2}qh!O3RzK?=i;U+{C+gANc+|%e5bfA=399uU~&lijltW2_dlC-Jzt!=7zi7 z7VYPm<#LJf4(}(5!t(yz2LOZ+tX4J0;}IbhuU@?*CLkvEcRLOzL3_C{x{>F@fyc)O zx~@m0MBfi6rO>M=M2)ffysskLc&ak#)U9DMglLIPYoOmfYqbBB0o9ceHI!rZwJAJUu0S_ z#DFadhG9f&MYdic5WM)+*UWQZ4iPCN^Bho0qeBb~!!1nL>wuJsaU2m+ac<7U7DP!^n)Wr*sPbFnk(}hcs?A7VJ6Ql?>{`DyRHWkQc0GJ zilVffju$rTH7O;gIWW2rTUv^u#O8(=6XQ5?K3~X9hRrqm-4;L1rZYwXZQHV3E>TL8n~W^W=&l3S8tP@q zGzXlUNF=oP9wjV73Lx>}=Z`!-JdlVSn3z$vk_8VStnfAt1%= zsL6X$N?fl4T|aQSoH3bZQI+VT$eHJxLx?cCk)NMFVy)%z;el}&m}A1`hTP_yPZzxR zD5Yq-j!&PS*=*KWn_~;hUhP2M7*-S(xn8f??RLZv=!b!8KX7U;gcu3)jMSP;D?$iN z-cwdL7KIoQQlXS&935p@P?aUNusG*|#5@P|^?Jp7hcTA!+S7F%MNtqVv~5RKm4p!S zZlo-4bG=-E5Io%9v)^tILU3vtKoMi4s!F~bPSncy1J-091@jyba^l<^Da#TmiqJot8@BiMi-EGlYVvNQ4 ziD5WnOim1u%xFT4EEfyft|QYm-uH~7pk6E}3QI~*|H8Ed*xaD!`DU?twPG9xwALso zQBu-%3FkagNQO%XLLd>eZA%Chk@gEX>4Tx04R}tkv&MmKpe$iQ>7vmK|6>zM5s;{L`57+6^me@v=v%)FuC*#nlvOS zE{=k0!NHHks)LKOt`4q(Aou~|=H{g6A|?JWDYS_3;J6>}?mh0_0Yam~RI_UmP&La) z#baVNw<-o+As~POj6#%{sVCBl8F-Gbd-(Wz7vWjn=l&dhO5S9EPb7{q-LQx^h-Wt~ zo%23%h?OLT_?&pcpbHW|a$R=$jdRgqfoFz{OlqDuL@X9NSngm}GF0Lj;;^D>lrLmm zRyc2QRx35ux+i~OFt4qoxlVHgaV#N$Bt*!lp^OSFL}=AWF_EJEn1_GZ@h8b8ldB9y zjs;YqLUR1zfAG6ovoJm7CIw?a_ls?Ri~)gNpjo%=?_=9;o&f%5;7V)zs|{f8lk|F9 z3m*af+rY(jTa)*I%N=0oNtX=Ck^D4;LIHR`qi@OqgSSBMn%i4zAEysMhPqn50S*p< z@gilfd%U}+v$ucGwEFu2a%Xazs#&E zpqqRO*Ka^h7ors2sc~u(7KJa`>l||NiISRe-4y5dc_ghzLF>b2{6$ zW7as&6M%icQ5Br$iJI{|PAZf4w|C5x<6LhwrMWxqjv?j{$)KSs6pDz@j^kjua}%Mp#+;L?A|nx?C?1awwtc4xs-T%+x^WyQ z+qPk?bH6E7#rME!#;}f#F}UAu?EB8w*B1cW7(^9?P+5#^AR?$hZ%SqG^?YKsibe!g ziKwvOc3SUi5}@_o`TjhD&&PxJ_jmSfkP)~iy$_~4k%6kxdVBHp4X690fH@tZ5CJG! zAA@kGs@TRrbzv6~%o+67ux9Ir-Y6DCX~yT{!Tq)aAOe|1W;4^R22*Hh0mWq|H7=TMiIDA+?~^% z(Tr^ys0ed95y3fw){OgYEP|_0Rn*K-RmL_hy9vEFwykr{Cs6cD|5de|OajU6K4{He z5}$Kkt}f&WwQn z+uPe4b51}|HQb%!I2dCr$7XW7H8PW9PSS(QTsuUNRqWfwzO6W^g4Pr>TQEf?YPRk{ z<|`^ZR^B7RoRi}?n8$Gm7^Vk^LKPp6gNP)eDBzEue_gUxw5piriHBnjJs6dM=^UoQ}y_Nj>%R3^%$LEuxc%H#+U(-LI&vo^(K;XUiSBmz&B>Oy^ zx7%0{nJUc$5nJWGrm6tk_l~v3 zj~{Ow$3z9TVV7x&<2Y9Qw#L3~P=%;*&Y)i$smLpt&%+6Knp`sc^XCV@{CLC6=xt4# znM62QLFBi_4KpFUppq(H2P-1@`24)M>hv-AKe^%?urW0Nwg3PC07*qoM6N<$f;YeV A*#H0l literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/textures/blocks/LimestoneSand.png b/src/main/resources/assets/textures/blocks/LimestoneSand.png new file mode 100644 index 0000000000000000000000000000000000000000..2dec5bdf6298b2b25fba4d21628e5caaca5ebcf1 GIT binary patch literal 2017 zcmV<72Oju|P)EX>4Tx04R}tkv&MmKpe$iQ>8^Jf_4xQ%ut;yh>AK&6^me@v=v%)FuC+YXws0R zxHt-~1qVMCs}3&Cx;nTDg5U>;o12rOi`@g@7P>F@$M}nR+6jGx_(bAarW+RVI`Pz| zrE}gV4zrS^5T6r|8gxP8N3P2*zi}=)Ebz>*kx9)Fhl#~v8_R9XN`^{2NgPpBjq-)8 z%L?Z$&T6^Jn)l={4CS@uG}mbkB928Qkc0>sRcxRP3sG7%QcR?1Kjz^daQsPf$>iDq zBgZ@{P$4;f@IUz7ty!2DcauUfp!3DHKZb$8F3_mi_V=-EH%pV2qvfWBLxYt`+oxsTHaAVXa(-2exN zz(|p@*F4@GZ13&gGtK^f0I4T(z1{}VQ~&?~24YJ`L;(K){{a7>y{D4^000SaNLh0L z01m_e01m_fl`9S#00007bV*G`2jv0?6A%Pu=8%5?00rGiL_t(Y$0gKPawFFPK+*eB z=SCm^azt_{$+jGp?*;hFUVwh=vTACi@dO4CAaaKn{h>XaI^tjd_z7YBXNfUleZpiJci-L9Oy_t6kFQ&_G8tJGIG>M{VxXGN z*&cU1e*1z)uv%Rc-AHZ}?Q+RzM_h=MQW0XH?>e+G9F99~R@c0|z9OT;Mz~%r(Z(pG zD2OTI`ZLj6n#qiz@2QKDsxWw8VTuy(93lxalM#YLXEoXwvMl3jamDUWijmIxsz zv_P)cYceHyd|s2~1#aj$cRg8IlN-h81J*}Ae*A=U0q-39*JrE?)J=mF5TfV#=?Nt@ z4|jLyte`APHv1FeKR^F7xxPawO$0{gQA#7FWV8c$UNZC}QVK{A{6O>`T{J+%7>QDv zrkxN&B+m@LeE5~sYRPi7LTYX3tV5WBzUy$-(_JoD=XiR0<*?n7kPM?ksSI6A>4V_u z<%O)MnA9y&X@=1ge4y_wv#SN?&appUkV+dCixpA|x^X0o7p!$iAy_PzWO)t=hQ6oo zPNd{WDN&XcVeA>Kr>JVI3nUcB(w1g^hu z>U+wnq@GL(-Z7ockijzy9YPu&*Pr>@Pk+K%OIFp~G!5fu5xz$rj(g6hBQKvnQIsX~ z>5TjPdwfikMiZpu?QKT_QiQG_c-w5r@{-APhCr}dE_hzQFuH-Zsi>+363nlb=yB+Y zAt99{#=z_AhSl{AqaFD4^%-q4zPtMY{6MlD^VyX54-W)4;Jn9%p6D#YFffiiZ8=g@ z4Kg|U{(_7lB1p7X3q(rHmMfa7AX^9E&`hR0 zKfjQbB}z%8)X1zRD{}HIgQiB#=5rQ{B`HP@hdsyLD{tEkulobm4pi-or_Bx*!Fx|; zB$uuuB{+6H=kCn$utzIFicn-3hKPy-Dme7%tsF^bFZ`%9g*Eao$s(xA2BcskQmC3#-ZcL(nkp%o;Pp_C#? z#cZ`iAkf-ybu~xtb~{$nk{CVBd`?l6>~?#s9msRTyLUH~S%LSSq;i^8(+>lF=rKy* z$DZZQ4W_85>V^bl^9kMM%=vsmi(m;U5qv=E#BaZSrfn*wlL>ybSUZAHoXKb^A!m=oz8e~NhD5hJ0_C}S)TEKPzOV}y*L8&00000NkvXXu0mjfcE`lD literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/textures/blocks/MarbleCracked.png b/src/main/resources/assets/textures/blocks/MarbleCracked.png new file mode 100644 index 0000000000000000000000000000000000000000..b1bd018fe9a5920d82d4ce7aa7194376a2e66cc1 GIT binary patch literal 1877 zcmV-b2demqP)EX>4Tx04R}tkv&MmKpe$iQ$;BiK|6>zWN4i%ii$W&6^me@v=v%)FuC*#nlvOS zE{=k0!NHHks)LKOt`4q(Aou~|=H{g6A|?JWDYS_3;J6>}?mh0_0Yam~RI_UWP&La) z#baVNw<`9$LO=im7)L~6rk+SIX5cx#?&0I>U6f~epZjz4DS49tK9P8i>4rtTK|Hf* z>74h8L#!kz#OK6g23?T&k?XR{Z=8z`3p_JqWK#3QA!4!E!Ey()lA#h$6NeR5qkJLj zvch?bvs$UK);;+PgL!Qw&2^e1h+_!}Bq2gZ4P{hdAxf)8iis5M$2|PQjz38*nOtQs zax9<<6_Voz|AXJ%nuV!JHz^ncx?gPjBLej70?oQ@e;?a+^91le16NwxUu^)hpQP8@ zTKEX)-v%zO+nT%wTSX5OIFwVKt*q_G{xI$9@-X9B&T>;~7s#{Lic2jutP|KUHp z|9}Y$aUA2lM?`pfnqec$C>vsffWN+eWiW`DPNxWh!-I!!cXw1(MPLG&rs4d2jB}2z z>o^<^$mh?0cxx>pf-#1oEZOh(j7B4p!2lZsD5a>Xiuruba5Us>JjQhn5fBkxjz>QK z`!hE;H%xD*xX#fu4bC~_`}hC)yeJ5*rD=0F)?{)_CuE{PD=&Zg24( zL<#fR0`Od2UA>`quETjxUDX&t&`Pu2?f}o=@)E5>wCalr;JoiIQo`A2#NFLJ#soBV z&G>vw6i0vuJYDAi5PC+8Qo>*mqm*zs9MD=5oKS!VrBHo+wwo=>^_tCQL)Ug>S&A1= z+GeClf=J)22xx6kN@0vKc<-^+QWPZuv~5dZ1Ms}T#zWh6)K$sN&2>+S^K3R7=Ce8B z?d=;9rF!HZFaj)BYpS~9Y$N>o$EzTvkU+$0yJE{yQC~j?(ZM?@cup426zueQSiLoP!t7uoW@ACKHlKj554DMiy%?6%w9#v(Z9(OPKR7A3+k zOHoSUoyUu(m!{XpybAR2_(HkJU*jyj;3u1tYwf4sGEww2joSL zHU?`gN))r%oZ)at6ouFzzze+wbzM_8HCdXG=LJa?5QQNE1SY^LMVchkbxmHD9p~dQqtOTv`N^)3Whq&fvRo|r@#6=k$P3QLV+KirK6NUhUX{l?$6r%w_nN945dVIHX0#Hv0N_un%?)}>w6R;iq(3><>iE%n;SlT z`pEtL!-<}^8^FWium^AH^PYQ@#NcU)h+Ly2%a zzVx|O!}IeqL0~D%imIy6T62DWjxnZ};)G1Sx**RBy!RwYg4T*SiWp`?q9_7{>+37( zy2W`<)6`sDU1P(5`-cbq^XH$;=X1)cq;rnWxi{8ivH0#c+g<;-YfW(K;F#wGK|e%B z89Y2TR$S}EGLWwl!4T*t4UKH@zb4ljhE<>_h0e7@j+KUc1lk=VWT P00000NkvXXu0mjfJtu?X literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/textures/blocks/MarbleGravel.png b/src/main/resources/assets/textures/blocks/MarbleGravel.png new file mode 100644 index 0000000000000000000000000000000000000000..5ef8d573d94d0f8b45705798b86e8bcea76e6ba3 GIT binary patch literal 2098 zcmV-22+jA2P)EX>4Tx04R}tkv&MmKpe$iQ$;BiK|6>zWN4i%ii$W&6^me@v=v%)FuC*#nlvOS zE{=k0!NHHks)LKOt`4q(Aou~|=H{g6A|?JWDYS_3;J6>}?mh0_0Yam~RI_UWP&La) z#baVNw<`9$LO=im7)L~6rk+SIX5cx#?&0I>U6f~epZjz4DS49tK9P8i>4rtTK|Hf* z>74h8L#!kz#OK6g23?T&k?XR{Z=8z`3p_JqWK#3QA!4!E!Ey()lA#h$6NeR5qkJLj zvch?bvs$UK);;+PgL!Qw&2^e1h+_!}Bq2gZ4P{hdAxf)8iis5M$2|PQjz38*nOtQs zax9<<6_Voz|AXJ%nuV!JHz^ncx?gPjBLej70?oQ@e;?a+^91le16NwxUu^)hpQP8@ zTKEX)-v%zO+nT%wT+twLH7Y+b| z1VHdAlCnfnvg2vor%v+!`;eJF*ljb@bmB~G$Bre77Yigv;NT9N(+8#be!>3sUbBq1 zZ~volsZ3d|mROcWo)-lD0M~VCwPFwi zMA4BXj`2K?%gZ^2VbCf?r(?6*?a8tn%QOY=-+$oh>WZ=~Da(>Hm5c^Mmdk67#|W)8 zGEI5)>RXDkVDqq{+wD=+HCI>9Foj7N9s%h0`v_qm(-hb3VSN7mgANY|hQlGJ(}}?# zAdVBXR)B#p4D61L)|$)91w~P?+wD0CDJ4zQ(Cv1~^MbmrF-(D!k}S(eWy-^5i!e>b;}I9L3tYFyV!j{<0%r3I!tlWP ze8%%!#^VvckkabpU=pPoOkculf=oNJ1V6}k_4;Y@3Y(OsH&1~*P*H^vMfVuO<7e~ zmdS7s;Ce2T>6ARn2_HjD(_}ChVA(dex3@G+gJ}v3)8ze!-?(~q`9zTcoK7bWha*K% zVp$fgYWeq%KQf=qXxo-pO1?fm;(8wQ#hffniQ|MMkq7~<>r$2_lgWfv-~NR(P3d-f z{Pfd*F@E^r@A~%kh9pTy(+s5*P1A65vwlh&hO}+VY&Ihp3^+v*r_&i>nJg9yiaetz zO6-nJp5;%U7bWw>9AOv;0F5Tga@w|GI2=(|HTU=T6lICyIE3K=(5SX$G#VkL#4rq$ zRt!f&lu|^;i0yVqT~*vZzhOR`VcRxVzwh&P|A>?l%Q88HA&HdqdJb*dVhF+Q^IJ~m zggh^3ng+|V*za}>1_Rt)k2Fn*&oQPca9x*=zkMPI0zA*f>ewBEX+WOmw5`JPeO?T2 zP)ZRe65FyE4u?!96Fz?YM91l1I~|7h=&7z_gfIl_n>Fz{W;`CFl%lR{s;b5s35p6AiAEWltecuJYX z3C}JUltsyCJjVBZOw%MwGd_L#otH1aK}v~fn)rPmw5BMFC(-#XbyabSPFSAnQRD@! zYC*$td5z;ZoX=<8z59Ugd$^uUs~XPd6Q1j0nI>75v0ks(Znuji4MGTR)+>zHum7O|Oj9tM&uN>6H~;(> zFJFFxX_~lhkN6zpI9-~iVLTpjcXy9r7`SeiG<_1B<2aOM!Duujiq522hUdD7@nnQB z1w~O3MG;CVuCK4Tm`<5aCKw2srseW-f$w=7qlo`sT{T=@F8EX>4Tx04R}tkv&MmKpe$iQ>7wRhjtKg$WWau_=P%36^me@v=v%)FuC+YXws0R zxHt-~1qVMCs}3&Cx;nTDg5U>;o12rOi`@g@9g!FotP~nR+6*kx9)Fhl#~v8_R9XN`^{2NgPpBjq-)8 z%L?Z$&T6^Jn)l={4Cb}vG}mbkB928Qkc0>sRcxRP3sG7%QcR?1Kjz^daQsPf$>iDq zBgZ@{P$4;f@IUz7ty!2DcawrKp!3DHKZbz7F3_mi_V=-EH%pV2qvfY2?_z3TSX+{ftykfE-YZh(VB zV7N%xYaZ|JYVYmeGtK^f0OzQ3)+2RaiU0rr24YJ`L;&Cb%>cZLH-;1d000SaNLh0L z01m_e01m_fl`9S#00007bV*G`2jv0|6c#WsEQ%EX00l5fL_t(Y$32!?a~ru4g}=sa zE+mJftk_!TR{8(`CQrMSswA$sTx(krDN>vPW&m^^Myodz9=cDTKIZ`P+i(BWuIo5G zpZNUw&!iZ+-EPDbQB{KX7;C9jdHCglS}Ua#RKaxgWu;jvRoQNrLzPwONCg;o)Bb(ih>*YdG`0()) zUDuJOhBSAAkQFDb2J^LmCZD+oDx5M#wpH z8%Mgf#Tdh)GtL;H?>hig6=Mv}IZDoi;4#|`B^R0|tUzQ1GN(jZGV}S27(){Rw{axJ zgmacAG|VaCu9pkO8m#v;p+SJWEI98l#-gfNYXAY1S}V0wrfI@E3)XUexnOoXy0)cl z8l17@yiiKTPzz0Hc>Ml@+vSDt-@f8Qz=%NrQ5eSwtrZk%tt_RGtCC7#o)@~VrPPYn z%K7;j6_~~eRmJW0d#=|j`{RLH3U~MSfT9Sfq9`?ImXev%jEGQcp=(=8EhrFt;QaKH z#Rm$)>FJ4nvq7nt)AKVZ1m~zZ({FYNf{381ps?9(F=9Z3&@_mcH$SYXQ;Hbpan8{O z$8H!fMi5n;bsl34(|BWd_kpEkymPFo6E5dxYN<5+hU@E(GyBqM%QOe4-$V$|_6qZu>@~>YB&hz~EgL!6Q7 zp0RC**2>{-rA4a(ycY+MZ{Pl_##qvv0Kphxo@c5m%d*gffU%ZkUMRIb z0^7|7Yb>P{y!U|eaz4|v9Zp1W)x*3Iep7FuIHBeHD%rVhzdP-UOpO+a`Mc;}#9}x40 z>(@G}mFK4?swzfxy^JYgj6rox)v6We9NS^QT8DFMfLUwt-s3|6G31;nxga8M%28@n zcEiA&3kFrLmkX$pVkE`*9uv6~YAGyvA(z7Ce8L#Rc)b8%ty$@?mRc&c6tpS=Oerz! zb~u1>n(%qShlVBu(wx?)HL{NV_88rNe0YDktab0S`@`c@Qpp?S? zxL+yq!EEX>4Tx04R}tkv&MmKpe$iQ>7v;9oj*}AwzX)K~%(1s#pXIrLEAagUO{|(8Q3W zxHt-~1qVMCs}3&Cx;nTDg5U>;o12rOi;))n}g@7<3h$AF1Q%~m>^6(sA_we!cF2S?B&;2<Nu%s>LxK48fDJ&w53`EFipoTguBxu!0F_ESHq=$dl@n^^-ldA?s zj(KcAh2;3b|KNAGW_fbLO$sJ~{ukT+7zF~mK)Y$%-^aGyJ^}pCz?IhZZ?u4!Ptu!R zEp`Niw}Ff6t|spRmpj1FlP(#OBl&3xL0*7)(KpQzU=j3;9@n+>mDy&_5y;wT18e9vO| z^hBxZQYh%WeS5>nNtM}rj_7+1jb{y@K$6U;1RmY~kc(Gelg262`GBv!IwOu_Y|Exv z4cO&-oMMsbH00HbXY@y1ioQd%SkdkEv22Rk;}j6>VhLRr$g&JU(5U(zuIr*{7B63ZNwy4WG@68A$ZZtt7|4>%&CMnM`Q=B-r3ym6{k^l>(=ybynFPNhl(8I<0&(8W99lG)*N* zQWQldjx%ga=kaNXX=?0t0_Bp6X&LkfkC>*(!@~pRQkngF%VL@E{Pcv96VQ3M#c>>Z zy)j}GB^(CF>~>pPtp^OFK%Q(V7ELyrExzxwT5a(>k4nX35lsmEBgUf;+bXh(mpGL& zK@iYxcbU#-luABPl;Id9#PN7ew1`k;n{v5C6h%ze3p%YfdcmgCZc%n^{EE+HI^eke z9NV^;%@RaGq7symMGajuu`Cls*|W?R93J`Hc0M62CX0NYj!BY~AgHlSmb4#lIXi3O zSC07gmtUz?YixHBnx-=e=cuAYo@-cTnQWO7_|NGLZds;F@;s+f@laJ2avAaM<$qB% zl{}ZYYkfjDG)`)#Wa);>%eS08KcjtrO`hjGJq|didNi9&mfI=&d{3!d;_>mCWwfE! z?NPK{j_VC<%VxJ*A${$VZnwvge}p6|^hS?}vVdMNP*nvGh~tEVYCxXnL~%r` zb&=G0e)~6u-2t;S zWIkJBSSq@%V-yO^#xY7kMV4j4FvPGlDix2>aEPWFjK?FKlFMeDp@}j(Q9_hdo4S9B zs;N|~HCmrFq*GUkUa7<9Z$+Ki(q>62noK^=d^>tsqM>pIe`4G|o6bf5yj;_oQjcvqqDg zobSK?0pYjbE_2^EiRWu_ag8KeNUFweJ>}rA!S&S#5TI785yd+K&*tsh54`&FjBanj zK{a3!4$xJV**wAb%ZQ>ze=tH-K-?~uWXlY#pd$z>org9eOLE}u?uzHlm$V#S!I1eP#V`#_!=>W6Jairq1c4k0$MHFDHo3m}fL*jn zmwPld$1q*02Pvce3}HMR=O3?baoqy>R>HK3%ocsJY{$`&&tegwstPa8zogr1)9X)g ziUr2QDToTk$39UM;kq@l)s)Q|6h&aW+mP>N#LmM5u4@y93yQ7*V#aPSQ?35K0^dI* zO;dXPCjbr)J;K45(`FOH5V^kYU|AM zaB^>EX>4U6ba`-PAZ2)IW&i+q+O3*bawNGGMgOr1Edkyv2R1@G(DHRIGK*$rq>w`D zjwabv#Z2ItYaY_idR!X+Kv4x-8C$9hg&%ax_ z`7HfS`LC3I{p9||>pwDWZa_b8gg;~`e|`VU*IoL4-TX}H&D)PV=lpf&->(Okf9?5` zHT^qh)pPcPm((gFIJM#{3NN4l=9adUqTCuwEHkAhrp};Yc1~Hw%yxJ zT5Q?ns-b!u7jyi||Mb`VCm%XT4dtAzU$J6cUY*7&lsV^&b$pDBxbp@z-2i|7{_&6U z8pvR}VXkbj+o3Cv{*l~wafO@czy}lGp9Xeiy%!)vtRS%%7s!CkE+m(oE#8~r9D%GP zsIzn*q93HirQ{cj^f81?a_9o?&F>U5{gha#p`JpD zDW#lBs;Q-(Lsp07T(S_gmr!C!C6`iaX{DPQYOJZ|T57GW_U2mvaZ{roTWziN&P_X4 z?)-M=1HBJF!iXb{Jj$q}jXu4ZVaAzeo@LhAW?z1VMIW!c%BriazTKvjcHC*_U3T4V z_d}_jaNpc|3T*d zoVUNq+Ul3+!p)G{P(ihU?%RbW)UdZZeTB2<AD?gbRP6sd;3i^4|&cQ@&PpmUtfMt97^_mOhY`Xbx+J#B&SA|z?* z)uyuGdyZ-7d)evCS&pd*=qfaQ&voqG6pJ#4+b7NfoJOKlAwc5Hx@=p6y6`P8OK5ZQ zRiHQ8HokB8V-v^|%7(vd;szwS#6H*^pX9#dSxxO>PbyKb@L~41>gYx9na&0jJgNhR z=rl(5uJ}2cr+!%m>#A#0Y|gb6Yw0VFVGAK;VM}u9#O|lDGY@`Zk*GDd21{SDZ0fz! zkAy3dheQzibbM|&!rQn}j8p|x+d7SQ)-t45McWVsj^^03aA{LZXmr}{JF)cMwe=L( z*uI72ec8L_mG+Gut2JcKX^(DirLG)+vyIdPO*Ch%)aBaqknb}`;$m^eQ$nIRMK7g= zqyC;?cB`)Bfii^^XQEQ8&u8qr@Zmc0<+QqO3WIvhoklvPo<(KQ=MX5Z?PE8?aSf_1 z=#`b?-cOB_EV|s00^es1LO%A;M(tUpJ&sjx)6rl_Z)uw}!d$)*Y#NTBhE#gvhPkcT zGS>k)KvtTXe9mj z5vxtV@(HdWA*vsBs}!4=gXnkAjw&vj^7E~YX4yBr=g6zNR${^-82}eTHAgrcmVy+As?xpn5krb~up)B$;YB*F2fMgS&&4CSp+(i)~b9<$1}wq;D4y3Biec$ia~{A=sW=UsqsXZ$ ziW1yn$I4)yx9A0&?9Z$|fy1$gZv|T-EkN-3@BnD`?u8~$8;J?%8>oe5OpWCfZc9a~ zA%Q1YB-t=3$jAM98YSA}2>~TK5(qm0OuE)msi^%1cn@w!rjB3tQWSrMY)xHoDh$>0 z3he;Db1sXt$<$DsN-T)b{Myui?GZ`(A!?pPLaD%%Xh9Orb>Y?! zl2A|{AfX%IvIMh2%TgAOLV%qYz-^PsJ`dU}+3((mu2{w-M?TcV&j4`hq$v;b>dFx; z#{jmFuTwT9QkLQU<)~dk;sV=*(n`L-x{A9Mc33P0vnP?BG}uUmGPH+;f@@@oUDggA z4a&1o@F~-D>;)Szi5ZkNJhedAi=;Odl`_0I?H&L{+Yx4DQ}!t{z`uMlLmSa$Y^sZB zU)sV;*>MQ~*abhSzY!AaM;u2uipH;6pt&nVx4`j7Kngz0Msw*`F}Cp3g6}gPk3|&0 z3L(Ey6{6}pAITOvBBmATFV+YGF;;N_p~r6|L`%AEDmfJK6}WA4v&2)_pxl?vcJ3)PY@ zew>^2QKYo;b;ANtwv#fX(aJv9Z4BtFCeOXr^15oesRg$LGEUUqr%;qtAUgNj(h*L@ z=L&Vv7uCPUnXj_nJ=vlx2L%qZ1VQ8Yj?L~PYrA<-E%flEh}z(PxK zM=_5APY5{b-YtnqRJXy*eklRW*Mi^ZmN>z%N86<1=iL&^TMmWf1#OVEo8s=Ccsq)dItzxeA~?XLM3i=>Id&*2t^V7WOF#oa{pZY_7Q8z=mYVpawpJ z@*Md>IfxdCJ{JPolWHV;ctNsxedNRk){3XLu5vR?*qx&S_6-|a7?G{#xzwvDDc9}+ z{7>8W4?&EPt3eA?n!jkO1av?;szUDU)GokYrW~L=43~3@CIsWTe!Iv3ze876*k%ge zHZ;kCID4(C?(13vTi3$1l4%plv13h848RNKi{2rRb38z0mqW1uxIp`&A3%f?!K@Jw z5HQHpZ1KQ}RbmHY!8*sYPAQ?B(ameonlp2usNn}w*1k#Os(DxAvz>9PgRaS3F4inJmid1P#lYys;vKmk&f452)_)EMo3 zBy%w`PMo02*o=rT*`g8br5Xe%2K8GVt!^|lMaNw2RWKB!I}PEADib>= zcB3w&MLcQph>?nwiSW=Y;2+yPZQOE%d&TP;2>W7SSp*3)uM(pTQZVW|*g^6Xss?G< zHqV zY?vBBN2KZS6duJLfDKWafju6H1k-76b=(;oVoScz^1@?dQEgm~$|w>c+Y)TdhFUgb zBND+L#PlJwTlwSAyDV#jTNGJD{3h$0-w>RfW*=Ax?k}08!oJc?(}Z3? ztvh^(zzID?^2uKpraFHq`hiq73UA`d`!f0jR?WRgMUi8#{BM@Pk~f)07$66HBmyv9 zq@EBGfP832T7>3;+i5o%XZ4~xRS1b5i)V3imfHYlYI~#7A8lsq*HyzOj&)fT7;E|hqfk){mh~PEh zfYDwrl!I*uY2YFNH{E}HP0dtxTpenVB8BR@sM*owK;ZPKI6W#hPg@gd0VA|)cX3b#&B7c%d? zL*9-Ee!#TFP+I_RxOO&OV99-NFs*}kE77MB&%<4c)w}R4 zlFU|uF@@oL{7nba;Cy0-J=2s25~H#+Zd|H=BXn?_vC_L9K~Simt$;-pbRSJKJ1H~@ z2R+J-cfcdZJk^D`>;~i()Jc-F1N5Y|^QK-99bY)wq*fHS$K;Bi!1Ec3hVFzKOfi~- z!AI+z{ox(a9*%b~%{yo+02HFFbQX(LjRW?P;7cgA3 z6Y2^X3Z-8AOo7yCMMPK|Rh!uNntDyN5>_5XZFlB2@B%b^lg4sDDfRR{qnJ@1+_0spk|8&+gP)x^!61{s zH%FOr@rGwX``Y|mn(7P>lj8|gFPiQYgJ|9wCLuPKbKg_1j;w&dv2g%=YZI@FTB;rC zu|NR4$Y~O6aBxgq+++>PH_}H9vnsp)@ez&O_JnUTO+-I8pe0O-3`_6(4=#x`EjUJ` zB`yms3cxy9s1NTAH{_JYJ-FMMePUx1y@MNlrw1O0*xuk2sgBScd(>178UD;OQ40^2 zOL~*;D04(?5l~P*kP93E{M=?#AEN>NP@!NtKu*6y2{h)2nw@RZ0o@=CB-UC5tjKe| z2H`P({bn(1h-eo2C|_IY5Gf7Ij*y9(0gMMb7r|oZQ)1~`{h(H+ms|*Yil=GXcSOpT zBj!xDtOPU`7!fsBesefI3rFrXbudeOhJ~bi#A_NB-H$-GH31jUC}>Z7zrmguCk)7= zK$~X1bl`aA{;x~$8#=JZ3>8wRNCo3fu8(3u`Q25)*7-BHC2GVL$dkL0pvE&u#NId- z57hP|Lng(5w~k76hW#ly$2RWuYjqCsRCZzIsJ;|GvCfSgrEfuo`0Mz^C^%_U^A;9SiQ z7g|W{^qJ(Qf^#*lwNMkh;R&qM0W1EU_vP=Al>`D!szF$w zL&7sr&|Dhkl=~1DVzbi0_k)qhi93D{60cCIfLEpnL4ctlc+gv9^E6bz`BPG;FjbqT zM!_J?y^aGU!|7RzSZES1nXBL>v1d8}IZXqVN-=`%=!WZNrl#3getHE@`<@q()}SH2 zTu>Na_}mH6etOgo{#r*Kr@bq*v4lHVDb>7ZJW!r+j@or(;jfF7Q>D?-I5cQ zYj{aUc}uT30lm_`T6)-KY(GeCm;uYD`LEB^>>~J`{vU^Yw3mYMBLq^DW8ps?-ZUXj zp)Q}WqW;S=A29yV%l_gb3<>I&AA@I$?qFkdoX*LgslN_^!nI@Ob7r%C&yNr^IKKxX zk#s@d!Q7R(qL;I8!Ry#h`T+K?-3$bu1{K%+K(voae@0-)gNPLX0;sZmhq>nwWstk*c!UIImle#;09k~^1yjoUM z+8ZHv>$CK^OPBnxbqu{dd(FMeY!*_QmFh_JdO^O%8 zbQvb|Qcy`P%}I)U1))pM*F_y&5p7__;B^M!@sZ<7E}i<2#+vl>7lacXW&FyAEP3j5 z29JJ|emUiv@@8DZRU(5c)RW@(@i-jO46kIh5?3o8K`x7fjI>pcaAI;V}r z1-KOFC=ZMr%gkG&@M-9(LAnGD*rcMSeGJHc+8il$mCMrd0$#egUBFz()XRg6YNkF`yM_%Oh$rAq}b>usZB2 zv;8{kqO$K0m;6Pe$0}Ucq4C$eI~<^000y^G1DedsQ)Qg*)Y-5^SdtZQ4OM^R zQR4IP$$OYM*XZJ>T&0o2A*Nq)-9kr35Zy2>J5KbVDu z^aY9xapDco5MKWVDj{o*o_mQJ&&nv&IpWttq{ys_8vkdYgdTfc*BRohp&8-<% zA?ctZx$SC?^Ler*N}knqop+Z90JvdvSljSvB6=OS9uiHUfn+u@O6UwijS3~(E!+`n z^8@VX=0i_A-Cg@~Uo_V>xVW(c4N%qL;3G}Q67JOox_9fz9Q>2NXDY>~CIS8)Wa~+a zT<=--&9k0Xk`l&M>)=?sMOPM`kkZr-gD2YFX=D-WxsRCOPt;deXk9K5XNpJ=PvF#~ zOQo_rmy^)>;XZyJfN0?F~Tv z!RUFO^1>f`6w7Ok=_e9|=hvB%q27SJ?+Lbsgz~f?VnS=%de4J;{XBg1X#UiOPcvxn00QM9vt#Qctf5@l9AU%<>rYN3($qVi(=$g;3spe{{jQ^YO^!JoIE(r;4h$FijIh zU30hD^6~KrnJ?GuRw-ByfN7kVr-3j|`SkgT-~aXlQ6#yR1@GT~Lo#U0?C6JyAWZ11 z0zC{62N-SW`kqz3q#p-V93bB9H_XNm1QOvxQ51MWBAw;i{f1O}3>J28?r7VQ0FN|F ziQ@?ATh8YTNhob#cPRmVBCyuN75{z?|Xt+ z(G?W|&^pU%z2fodMB5Hnz!!o{Eoj@8ejHdNDV`9Ru|qsxUU+)B@afAFNt$AW&w7!Q z#1XzH@McY54gdJ~FPgeWTF1-r$m{t;QI+&v&$Vg*sJfOcNy+k@$Mcnpw@=6ZAc=8QVP#nUg{R5 z6rvd?4%-#yqN3{uJm--wbJ8>gAj=jwK&g!9%Y{#;7hbLg+yqAWg0t|!ehvP2;~ zfpd=4dP!?$l)Pnmv!tqPvMk~0bRm>Jxl+t+g9rnTRfqLFx~V5m70XQVw~rsWTd&!z zR!GnDcsib_`+?nVO%wzizr50D!|%R1pdI*u-^NZE~y`hx%cyTeam7_!MzCJR459k~=0k@RpDV&6jq0i)4`GGORC4*NUI zG%?SX)oRIyUq5ia+tIhpFZ|4GZAGDkV>C*z69s!haO`L z!aDkPz-dj5BZ(Aonxcn^Bo29feWfZYvN*I7MvoKYI3h%do;CS0$9NutF#wF(P_`X1@qM(>NE~?_ z(hZv3;SGM^g0tWip24jnD8)2WhHk$C0|95T13| zX{7BsJiytBzN)c$MhLiEE{s}pyj(feJ+pCq|J?)on-t}TbmK@GM?60t31rA(kupq% zqHcMA*dcr&Fta6!BkH#2Tz++qZylJK-FC~QCl*=4o0|nUix^{OR;wGFb2LpwQ5C2l zz!*b$tqFZeo+Vgok%0;kPVo73MEVkA;4gpuJMZpyUxRK}{OWK=SvIV1GR9#biZiV6 z5q^W7XR5lT?gzH(70x-tFn(pBsE|$D5`-c9-7V62Xst2U@={#cZ8p3V9V$&wSqd^l z0R~_X_K}y%m2dCw5WdfA*&x$^e(JH>B45gp8#S{?Ba})BiS9)rIgJH-*fm%kz|@AQD5hB5i?tjiXw`>K{j2@e!b&%v-$tCSgmiU znv!c%^LDjhoi2F#? zaB^>EX>4U6ba`-PAZ2)IW&i+q+O3;eavVK#Mc=UsF9Gwg9E=g(ftT-dQPoXK-*1N< zwipu0?&>N4nR$l7}?~~*6`*@~hbF1a|6y|&VdEdXwz+a<(VkkbR>`LU{=xr&v@pJVy7S?TPplAA~ z&!zF+=&#?+=Tgs@{0=Ty{;e8e&|eoi-z)#}yRHf0`$`J=87a~7#uk2VpLPB3|NM6& zH=m)uA^#(!-=Exn@%pbwo4cT&H^N^L%HQw*@^zPfUN^r(dgJ!%$vJWDd%@mpQ+rRxNc~*?x!+eg}=#GEw;WIUzL)Wjx6fBG{2lZ(z#K{;pZcdZzgSEVruMb0^69hVUiciu%!cY!}&fB#Wj z0})JjnJW|QcIXa-efaAD&6Q^2mQ_XaExBS;L!1tMUx3&~|?i}$8D$3j*D z)ET-D(GSAnQu2#I`WQkcI8*`8<}=0JOMUXs%K#yPpz2I0#HNK#uwqQ)Pl=Tr>M5j{ zQp%~Mnp)~PWK~$sB@0n|2_=?Paw(;jR=TO7#+qubrPkVNZ@vW(H#O?9)z(_?JhXG? z&Zj#U^gjFuBaSrkD5H)x`t)Xo8E2Y#mRV<;efbp@b-eN_tFE^CcAHe%ai^Vk*>$(w z52<#-i6@SFYYoML91fG~LmnG~Gm6fq(gxAW<^Z|r^|mrTh2KXEez!vB9n&M0*MgUJ0e zZvQH3t6!oEH$o~yEvgMvUoXs+Ppkr>l{|Vqd)86TK69J~6pBk{SlQ&|1A`l^kDt-i z>2^G$bwG$g&CVK}J@~{JtVee%beEV+Mk(;x8oPU@xXoMqY=lgJFkGF7512CQI@dWU8{92!}8$z(byHVv#CQTZsWzR&_M; z^wM@NfofKl@7Af?$-5Is)5%(E^bQ&p5mf6>}y^m&azr82wB~4yEC$Uxxmtgd> zqW4UM--=?|c4$4F;Ks5kcybB=%y}s|W~IiUo?jrSqm?9wme2Y=HuJ6&%FtxVRG^l` z-FzEkXRl>wj%=73(b1$ej6N1mSk3xL&CC-SJ}FOW_8!VmK9!qK$MJYl2GMgLM*vM+ zv67QvD}N)2$A=mt7$b+B?DKoxA=;UK)+xm?S5}UBpJwQci2IR>-8p3ii5B&_2DJ{~ zQl?l&2{R>zi$a?a!sc;-arv?%Gs{XnG?M|i`AjTOV0C5ZLupfB#g}{Int`X>7!!4y zMoStIMaHro&!R`sO(5e;*h1{CLqx=G$9SZ!^m4HygTLwf$^K=F`V@DAcJ&3#` zwddgO;Q9hQ08RgdKClK1Dn$x#0CR*ypl=8}Fld*GdICmkRlw`CJrvvumbxC{8%m<+ zgGbbDS;gqfXqmOD#3gsbT21md_qhO{PI(o3%&>>P@t?5X2JtAcj5Xe%vtL)+Fqy;R&KYS z44BD=;aJ!aQH_*yV>0JxguFTCtvg{yeb;K8fHKd zCLJcY1W#m+SAO)*=jNc^Ch6!zQJ3fI(k}_h;~9)F?cUmoJvS37dKe`k-=hl&2{?CH zklBGEXlK@?r~cUCDWp2UIS2Bd2kVuIEw8)ea?H^=T}~ zF8#gegr-r0yBns24joE)hnIg1EMbVVV$UIt?&@iaKJ2C9`!&z;|E*Q6%DKLu9PO>vePM}ACshm6|S}`@n%{xHAv=>wwi|Nn| zUV}%EuDX>?LBgjJ)llZXXuGmQ6c7W%Bz0>dOTCy*>Ihx1%0rB87NT2<=!v`uTf8|n z^8tZRTL1Ptbs0_h2{@b~crJ29uE2&8Y| zAS5_4OCqdImU|T`t*%9ai^&`+3?bSvy-@!V1NEjPL5yaSq~}H6nH?4(K|=tyBd9K! zS}wXct+|OdEId*9eG`80aAtJbMZ<4e1)Gzp)UHGRH5PSN?~vb9G6uc3S?QeKHOP|H z{w6K&>U-b$axNpN4o}>MOT^WFn)V)x8~w`WP8T9F?Kx)_EVR8|;a-VPDM2!!1N95we0p>fx0K?zK?ii#6! ze>RdCOzS1?{c@hv5m=|GD7P_|G4msDc)(K1Ig_S`PGK*j#UGO*MWz$;FE zQ%#THNYP+^Al0j(0k~1_YGpEGG&zR#BYlp& z5cV>2ZPyz))QpJ$Qs$)Iy8=j^`X3_wOry3aNhQVi<$D?SLtZThJ6tktRSPn91 zqYj#S6>4Mv{n!q*cgmLlMi5_)`hnMu3A5A{VREurz9#7b*PCtli%O+i zT&LHT&1qxbE2y}O+IyNrI{tK()Lxm8L?CkcVeyjY^v3T}o5goAmv=|oBp8*=& zj!1Ea^7YT5PuxaGxFhX`Sfn&8g%MjqL58WMkAGGan()uFU{HSkQXcI$$Y8=6w+i| zHV#mcitMt&jD?i%MM&EO*zNWNSdAY9wgD0Rx1meTw5Js}&?4RmS$cW8g1FAMzv>tK z95CIO4ggOZktp)jx=>MqcBZB^Mu~*(v};E0&f;15!kRtFdKKT5>sFnXw2=g5sH}Xv z+Iz6(EH+hU88%FiuCeKoKo4m~$>j<^!@7(Kl`GK5pxMR8j#mO-MedqA*f7(WyX90}&0f`o&cjXk;^S z4fxwxB&qd;&okl975tSI++KUk@^Kf70a8b-5F>AoSvuPySBUx~7C1d0wc*(}H5(sf zRCYA(7Dbu!YD8-Oq6ekMOmOqvXtG^B$O~i^LkkFxpZ-;WS1F05#(bAbgNgvAVWC$q zYbI4yP;G5um`+fC!ZGTFT%87iezSc) zrM9`-lyhLs0*{a#MBYqd-_+eJZ*%7MW<1tK9ZoE5F}Dl%DtcaP<8~Ux?LG;iXDJV> z#uBIJq9jrGbdprkH^b_|K}t`uW{Mmp=pbe)rv*oSzLpy<{@KP8z}u|3k5cM1e@H{zTkNk`-PG=?4#o1Yoa{ZShJDv zpc=P?Hfr&X>e0?bgGH+m#zzjzdx%5OX@vM$B3w`30HcEvjD5BQ@*mwE(Ce4T%X06q zrpqG|d28Y465d z=QNfQYt@j)cMsyZH0P|nwYY{h;2fNtS}4t**(RQW(uVN>mIxk|s`;V=mUYjE;f|r*li*LHmapOj*g7QI&Q-Fk`f7t5j>=Z^8ZTeqU?Pb2^-aAH;dj=yNV=x z8vdXVbv8N~M(VCWE*s%n`4bxWu$mchyHVZ1CdMmJtGklx)7sDJnw&>MjDpT~m`v3B zCK&q?hEZeGY7qjO>F$69^orgbw`X$j|Q&LtB4&MNz)lW-bOgFcI19aMpQnwA>8!(fkN@BSr)mYg9vQ6MXSrYFi)*o4ewl`mg1so90t-X z=~7ogTMc~+hh7wv$?;wWQYvO@H=Ot8?01`$^}U@!CR7qU3m40q|I$7m=`$N8%++hCT^ethBq}Jq*6v2;2jNviL&dbt=7supGnc8HTC$%6lQCb&u&gEu`oYkk5>jaTGEk8%E6E4Q1+(Tki zv(@cPa&K#{j_}i84YwsWbhx9dmjj1u|0H^btlp~j!;-pRS3pQVn5!6IaFtwmy#k6R z6C@02YiJ?$NW3-?8v+?kmxi|UD|IV%^f=FG{?QjBdb5+`zVF)rdpdHMiDfD5gg^x} zq3UG=(5(J`ij=4s3=)DPICp|*qoqDr`PE>NAifxnL|k*A8Y;AF`@1tPVcv(KfIeL% zNT_a-cQ*>VKD%6VkSWcpg$rA6BKGW}l8rFMs8E7>8aAcP)wySC@Pq7!Y z)^#!gLVUYW)QHo8i1PLp2KL@He5S#(pbF5Dz=Z@A1Z1W1bBH><0reuuj<#$Bq)ko; zK45|G?lOjHPvQMGXQrQ4Gr0l8X@3W`c)L?JvZxwni#mcwQE>ln_YY7fG6-=N+e;ZD z3PAkuY+K^@i-te7kBcK1L?FlfcE*>Fm|Cl2DEG!bO8_=!&fQO>u<&n)AnF!}JXM}# zP@r~V5M5#z>emrT_#9aQBpEl3J*8@bQ@4!U|28gG5Z2=c8GOTXqXUK*TBlXSTd+)g z3jK_CN5VW?5+pt2!_dtkzrhDO7eMN*_9fb&PP+n(G3UcCZ7zVWlpK}hHNk8~CjCz_55gU3C_I!8y z!nXrm*1tTL1P(vA0|go#Tk%+ebIq9?>mt`5U5U@>cefb}AHv<|yefs^RkfdOW7+p} z{>P~Ec{{Nk8vo(5E+|J5_ZkreV6F$|kXnd7|{i_SDU7rX`lHpl;Pe$Y6?2?cF0!OS|@V4nG(_&cmvK?OHYJ9AF5o=CwZH zO#G`_{~Cl21A#(A`!P~9(lg;UZ5uKbByDwgN(7U^6nOCZ_*9($rV?C5jYb`TdaNPY zl7IHpnpLWMT*Zd`P}8PR(gf>+Nrl^8)GTWCdoTm4fYH0d&3v zU`JH&!~%<35cB%;?>mOKJZP^IAiuUwRmoV!rE_EwLPuIrrz_jDhcll&oO)$8Yt#}5 z*;>hV+k43GRrl$qPl}tbSoM1M!Xk-48UjeReA<0UxhtWi-VX3?J&+;1TCk{-T2c4+ zZ6uXnbzHKCQQnXSUrv=tqn`SJzZz(<^lB8NP`K(-s&nw+!k)E zplXR8xgeCUSRp3;?pboZeJsScY2_5q#*!g);F)%+&cwWe-$>oD;LSevXdv~1&Q)a! zYu&@m2(pZS0xY0vL}c0ULiz0GETL)g671*@pO+ z3*!?uQUju)gP-CRwo6mPxHt{1&WxcO8+6%519tmx9SS z}tw+VG2YU5y4oc@QyNgJQ#&-J&zjSo=3GCVt25^?A4?HM)q80nhrN}l+%arUn& z#hiKM8nQ%(hAc2{2X8?UI%TA}!*qY1P$kptU_(ZMp~|SNdn+-&(0A=(Qm7HVKgK|k7OD(t%~u#56BGt|DX5xS*t6c^UU%<8>l+6GX*TeUXZZK1w2o&W4p5GO|9=ASNqtP>WqC&c000JJ zOGiWi000000Qp0^e*gdg32;bRa{vG?BLDy{BLR4&KXw2B00(qQO+^Rg2ow|uI|r-7 z7ytkO8FWQhbVF}#ZDnqB07G(RVRU6=Aa`kWXdp*PO;A^X4i^9b28T&RK~zY`CDB=O z+lB#v;U7ClfB-=f1W8e}q(oj~$4=A9WZG#n(?j&BC+IDFh~6k^`qECLIE`$@u`Ej5 zcVZ#2_aPVfUOwR;fB#!KoiFj+7UPEz{nI|{Af)ZN^!j~%e)ERQCzlAKMz~v&Wdgck z;PyKF=ezGP>JDw!L)R2m(=m(1l7fO-#X!|H#LLfKpsNziR*UB^Kc{9{Xp%_Hv`FKW zm%sapI8GUjM^r3}YTcqU7;ro$eD%jaV`>^A1&RoHnvoS5$0%mC*&xay^6mR~)a@FE zX^ad<@6HDpzx-Dz|7={ZS!Aj=Dm zam;M7MAKC!lNr5^M^P52S{2Xr2!fEN>$2YZ@8`Ch@ z@AnjvL|GOTMNYVn*ljjEd+{9C^{{Q5z-F5M|0b-J6 zByrB?uRdoqnxLsFH`h1(boB70xcsD6#@k6seeX z?uKLL%Nfb>NE&BUYZYWgQRoi_%qL^&R*k0XBC8UCu2Gg?+cpmmBhuuEuBqs{#Jid)9-S1^#hh^ar$TgMb05j zkyM346k(ZFthx;Xc-=1R-43g6GF!|Db|JlP7ekYY(}YU3N|EQtjb;Nu6q(QGNTP_{ zXmaAU$+9DPRaNRTK4G<7v)}BgHyl2xRw(m~C_K>hJihmNek4s(E*?MO>B|>{Sx&2eieWk=1w20ggj&rc%~K}h5mlqgWHLn-O42xIHJ=j( zKJg(UihR6ohuzjkdev>c{^gfnsTjYl*USoxr764p4!6;yTGe?N-jgO7kIqgJyB&`&fBy=rW?)pSNTNVlLLNn|r!!uD z@dbhiNs_WzZ7>@){nI{{U8C)J=(<9dCq#Q6Q4|nL0lQ|Ss0zW}M=Zn=r`{kh3&ztK z!{LZ`Z{L#UIfW#X*e!P97T0ajv~7|kB?(IKSFb9%iV zs;Xib2D90mx9{GPBstPwzxmVaLm1+EEn2N6X_nwPbvh@f@s>1A`S17NVpJ_Io;(3S+Xozv2U?95qA0Qo)?EGY6N)DDe`Xa* Ufu*Ubg8%>k07*qoM6N<$g3@?8X#fBK literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/textures/blocks/GraniteMonolith.png b/src/main/resources/assets/textures/blocks/RedGraniteMonolith.png similarity index 100% rename from src/main/resources/assets/textures/blocks/GraniteMonolith.png rename to src/main/resources/assets/textures/blocks/RedGraniteMonolith.png diff --git a/src/main/resources/assets/textures/blocks/RedGraniteSand.png b/src/main/resources/assets/textures/blocks/RedGraniteSand.png new file mode 100644 index 0000000000000000000000000000000000000000..28abf603622a5e2f2c682c6b9fec27d9c69190db GIT binary patch literal 10019 zcmV+;C*0VHP) zaB^>EX>4U6ba`-PAZ2)IW&i+q+O3;wawNHOrT=3UvxLAKSPq_M+JTlo-|@&~vHD)g zG&ZX0CRv%05dhr%JRG1q|M?%+{U83++KNk=uf3FqKdGl420ygt{WI*Vf0BKD|M7j# z|NXlAc_Z*rPo*~;hj!|Q?T!{_z&xzFJB{Od;jeBPLUzcD^H3hncN&+Fd@MgKnF z`P|rz&y8aEJUPApp6|4t(p&vKh4s1qe%`lb;D4ttDb`SO@ip-^g{Rii`MHHBRn~25 zpm&9?&*k~K(Les}zLy5Z6i)Q<;cL?fqyG1C@V)Vsf9skU`8mdFulIMPL@T(b@^k;L z>wo{}zZ<#x4*e7Ize4)+lm9PX{}pLx3;KN{{v$%==lj2X-RD2AyWb(Txcz!^DL+sC z>-Bs5`fJYLsOkTEcf0qzvm2=}{J)X;mh`*mj z&9=bbzyJKBxJDwFZJ8Sr9M9Ap2>;CfPjW>IbmYR!_qTw3-Jct8s`o5pBS3?phnT`7EI#M38DvN?7J@?+@N7O)y*V2 z>7=^(Sh)TI=@~UT~5X zGa?p}C*V~P@X>{!m_5y>6cjnd?CAo+92jI)aJE;(h+sNC7TLiaz2+`q={-$iW?Bf4l2QWOFDic{lS~EwkR2Rl6wYbYv7&9}w9DO5OC!=M}iCoUSpGr|=>tQvP<57bfk99!HwS&sFrIxfJG`}8B}1?l#ZTME>KpjOXbl( zoP%Hhm7hPWmG+!ZFLQWbNTI;`qgNip1bDJoGVthdE2LXdxyF5|()amP>RL9kT$p7V zC5Jf+Nj9Qq($7#>Y`DGOE1@;!1^K9={B-6WM(Sm60Oxi}atENV+zBA{lvkQ5fMqFqcax>cI4!yht&o~!l0-9(vsggOPZnOnS71pXR zMVM5jgfqkluL`}Y;H;H3H+KxXPFGpK#khliW(B}OUf_ng!i*FWcb`lWtxr840te1@ zP*H`m2-#_5Cq$YZOtbc)T5G5oa%QZc0a-o!r9Oq=;sdQ)5Cz#v0zAb}Sm~tRsIN7z z3nZvONcaLBcaUbV(tAC7&DGQ3kkarsRRhNezhz9GN} zyO7F}Cx{}1Et6@aJkpbl1912^I?EHYU7yRy883$ciVC*NsPz z3TQl%9f`ZBpa#e=5p|!?39=B6)OJOx0jse9dg@9osC}$oyozG+iGoDe2THxbf2^sd zi6EeO!*Et9)g+Ge4Z2MBNuT4+KCnvhtv^0YxpCKGGz_K+pmCuLy!PY(WHk)LH$eq; zGUA6NG{Jy~!*xI|d7I_)(()y1p|{?w{zxid0fcHU7!xf*WVq~Akoogeyc_w$<;`-p=>X^f$e}nck%5FajsW3C?f}eEVYl3z&K-LZ+Jp=LP|gc z3^djqcSk~!KLCJ?*DG{nw~$6Hm9vcdk=^#hOF_T!8z})$p!kn{ zMA210%+dK1(T7BgTomV-(sRAMQcqt&eJ<5tz#ak}a26m@xCk*u$zmX#Ps*PKz^xxmvSdz zw?L?4WckjRqVsZXfDa|HQFEL6$gBqpiv`dOfo3Gu>lG;FOdd90S>uVgkQ!mxdEXsr zDA}<;X6!+)*ZCJUT1P3bjUcm)ekP)60!oxW*?qon0b(5uzs0%B+wb20`+l|uRjX0 z?*fvwgU?FtknSv?r5bR~Y~c^JJu*4oZ9{~-+MxoIFfSlRE@xs)Zs2P$L})&&hC}Ue zo7J+EfWWt78BD4Z-9JJd_W+%PlxqwONJ(mbs4F%>^8=5$juHOlu~ypaAeI)@PJZFI zS0RZ=Zm~gwieAb2l#welr%qAaSS$AsdBHh_6=fsLYARo5N>%D7oKO%IKm;Vo5K2+b z9!1mGkk}NM)Wsr+npE-XK2k=XcHzz}$qEZ8(Kob2;!LU^>q@M6D5Vdhykv-Ga+#b$ zl_c3o_2JZS*cWTm!KW)r0*eE%x1Oh+*!a=^(^z2jk4w~vf5ce$sRGHxYL~>N=^p6y zFI3EBBEd^!qGo1L#*(fH2iZ!I>Tj4=N|C#wFh8JHC}NSkwew`Q%xTQoLDHZNOa6H~ zSc6w_xnejU{L<$UTV*<>ba(jlv4qNMl|p-f5NOM@AkA}1{x1-6$2|^G;b0;NVO_6DVy=)4Eb^UGm;a1ex>daiS5m^OP1;63feSOHd+B@V94_z{QdfSp+~- z`b38UJIxXeE}0oYvy-}71!_!Yg!~(yC*^O;^a-W-jIL$v`zN#9uhin%GeP8(V@Tk1 zCx=?FZlBuhco?FNl0diQyx}w{Q}o(EtR^SflRo;0K(Aw+UVJ&VLkKR(pw8-RiP3$E za?y?}4(eU@R=DoC8DF@3%bCJ^Fv(pHuL&ke*RN*O!xXkSwT57}vh4@k8^87K+DqA1 z;s_@I+D61Z-Yy_ zFsNquRkT!CrhOfGX_JEdA1sLsXZ^juK}k&5Yh}#wpT=%kyO3b>B|r0<-UMV09~(%a8xc!0 zy^ISy0q(s&(G5E-APL=n30M3kphC5S7#nDeF|BbhaJ3x&fY=D3Dlz`*H9*oWlcDLp zEYgHID^K-E)$@IKF<2Yw`RQn{{f-z?{G4z)W85| zi4;m$BA$g_8#IqWGpw?(Fl16r!u>Iz7JhkP#JW1*#D7*6s!j$&6_afJEfsXq*DL_# zYCm~Yl51D~o1{~(aTKYwUp`Y!=&)4+FELk<-PrIPQquE!fuD)vqSk;HL>hvvy#w9m z{>p2@JxcLvZ|VTXxMX=jI3-G?HJ)f0%Lnds9~4RxbIqKKRj-7WbR71uz_c`oz8fPQwRl-VBPDkjiw0Sbd*ApKZOWP?Qf1w?rlkx|s$ zklot3@53MgPr&wK$ZSB?w|FFJ;@7b`BwAl9L>!W~QkL2nm|z5&HtEnT@DwA~{@7J} zrCNIm2oi)3ZD*jn!4CKC1O?mN>v;9GhUj5c(l?eR6;CPc`}QOAD|5Vz65?=yNQCE* zTn?Ru4E^!ph|W1Z0IFNR2~a*Q-lZ0Io_I|1p5*k}7~{*NNUF!wAn36h+EAO)ld?-P zOR`Gj8m1DJyZf59dEDOKLb(7_il9jH+9XA1{|@%Rb&zYQ)HFT0m=OsG&<+El@iyz+ z@4IuFxhSeTln?@%8g`vBRU>TuroYN?s;u?4R8V8S1V!<+!%zduHey5PkgiD@-wo^u zMuvjj`O$}j!lZ2V65t1J?yNWxfT#|12|gi`j~fgojNWevCBjYAUf(R)6`xa5lO0O+ zMW`&G6exK$wcGi&MtDHdehYNfNh|cOlVyPk;lZFy5f~Bf`Po}N%WGpU{%hkta=lCr z>93c(izvgSRM!TuT(fdbG^hsuC-=f^UYpLK{lclD!PWXus+on-9?@`9U0ZJ2pI4== zXzkffk{BLd?LiH4_L+NPmSQuwlOY|+I(8@vfXTfWgh(bXwZREpJKJQIsxebCO4omE zj5iVraw-8jnF~AFM|S}kM%HAQmVxKiZD%d1H|0&SYVW|DefzzK^T0&fiq4_o0CAzt zy3V%u71YGeKd^?b6i6Mpz6b{Yk@9Ft)^eI44Y0D|4^zv1YJc~$8}iN+9E7={!c=_A zXs<&;j1HX$T$6NDlj35X5bHqIc7NGSbzDRY2%4S`1clN~pM6NR3#CJaeaQ6g`z%Mh zCbb(Lm5M&aAY$yo)@GD8$Rsm5$`B$$Nq}QW4OmM;!TyngN zItz$l>wZJ++ey!xE}UOo7}O(9wQ5fl#z~>{77+jd@8gm5vhO(NtW7Zt{M3H#$#3;b zOoJTDA_SD#*|@2=${AA$0V_-HSfjdc9b~CKf)RFX^K?YAlSLgV#dld=*M`iq&C6JWTR>HMaz0RVPK!5(t{w zp>i zuny|}nQj%ch5Ry`(+McB6(P}%ohS0;jy! zdUK@Je)opIanKo!LdI+mevJ6`i9pe|ot~mI4eP5fArst;W%(GNcA7-ZZi{k#nq8=V zu5UOY9LgIaS9MfDnqH0J{Y?V7Nu=cLO$|Tr2z#i01NDR{`bRBhkPn?5l5G}5ZE|SO z18J!iPhyn%EWZR-fLB_b3(hTrtpYYIpB*24f*pP!0uNA!F~8qU6D}1-a!B5F7ctVb^x8 zr9Ld!A6)kEho|Utnp)}LCorcTihA&$?Nvkt3A<+`g9ht_R#ST^7f&2;fD?BF|Ee6D z4yqhdO}|2T}(W#T)Z4ZLYvtL|-^p##FF z9;(_H+s|jNc67!sgRwe@v7W13t+;v?5g6HOfy}dgLDq(Ar)Ovml}=Y+_^Qo$^qT*@H{3ZIYI(Akfoy*KoB%!dvGs_6;EwrIA1#dAMc7ktJ7{(^fVx`)>K<_q+kRe@pt~)vNY76U+^)fuSk`z+k<-1ByY6+7G$pK09d47z}4+ zC|d^kX_Z=|l=v`avnm~Lqa#Mzxk?j*@SY(FsB2fFwM!CAkIN-0U^w*gbvKzbA{?He z2Ptml&!_Q5vJWh`ueP)7bhPzk#ss5J6eF`&(t2$SK|v70b9KgSZp?Ga`0KX|xw4(< zQv2N0g0n8B^3fXEQOB4UOfo4Wcf!w%g9=pIhW;m9ghkw7(D&iIYy6B=v@)re;QK*(Ld|ZLCUK4s_qjJr6iZ{l`M9jCBq`Z z5O5snGS6H(AoOOB8lM%NS+vZQ9M}UEmrxpdAF(01hD>o%3SFCiCv=^r4!gGs zNsk!=3Jbd!Nz-~_4Z;j5@}SO3)wvQ2%}y(c&l(z@wNvT2B%|MpP8*=G$zVCL?bNf-h#p1^t z0P_0SE+^It>^!p|n`?cXoiNeqG%6nPH{=oJKR>5T($qm%9rfBi;37e(&siB&Jw>;) zgR#~w!laf45(SQinc&l<@y0l_1>r=bf-9;CCn z-G7c~2v0k1EDE1D8TrJZH2))vSrx!b=gi}nZmI>#cvJ1R^*YnmQ4%>?HR)lk9bo;p zZ?^5^`}1o>S$l8^S z0%??fS-axBbey|8o#%f0jP30+{yiHVZEtd3Rqaj?^vPSejH5D!p2d^UK$YtmQaNjY zv4K=x+ReoT=ywYC2=+T7=zH5-CEkBFIdf}4J9&6pB3pCBwNE}BRB#aD)2~}B?Tg)t{T>4O-Lx~WUyp$i z3MTld=`Pcm#E9e(1+#^MDZl+@+0tSiv76QVWi`ga&;=dSfi}lPq~Q8R6(VA-HwoxA zpX-1j#2T?#m{^_seE=M(-0#U>P?m+$#Do$kFH_sntnkIQ192p?ex;HWK!JiA6zS2{ z*bQ%EJeR+Wr?!WQO#s;Xd<$FM!(>MpfQtI_>kp{$#H{zRHWZo;w(X_bw!`>+YRgmN z^1*XqGWGi+0Jio={lD1}0eFAdH`bP2y`}fd+w&TK{hC)u1y!Vfuz1f$-(K5*RR<$3lF1N^F0ss8^1B?DSyu{qGza9wCS(kl4(w7V7(5Q0)j@J z4Y^4Lw{2S?+Al4h0oH~XBFe?&9T(`>vs!IBCwtVqz>;(wkG>YTGqvgW zwpsgMZB{?Tpgn1?(h=LFLkdm3pt)5aP-gyhQm5ja>rb2K-B6R_7$(F>GHXD)PX`)H zc%#mh)}UVqwbQ(QwXulm`TVj9D%Tf4t1m1dq|7IV!Z8FWQhbVF}#ZDnqB07G(RVRU6=Aa`kWXdp*PO;A^X4i^9b z2FOW7K~zY`1;I&gTn7Qb@&DV`neoh<&G9&1VkdD@QkphxMN?4JqOzPo0wICKrQ(Lf zl@tC3d;kte9QXuWP=Nyy5-n0o$>!McKA!PxZ?-pYo%bHUpYZ!%{VX5P7ql96#-7jJ zy}MjrUlW7@^+ugAj1jT~MK2J{N2ulsuIo~ADwK-_^x_KMV2JAu>2x~?fT4&K>=GOI z-aw25h420J=UfiQ^d~dC$rz{6#Hl!p-6{3v8oFr{BnhdaV--wf!=P9w5c?sW<0CFE z&nfB}x9{BL{-gJi6^-d)&eiLei0?iAfU9T!;okNJ@4x+kBm>>FAxWrJ%bXq_kO?BC zqQT|$5M9yOy}gT5tx{QSAS5xCDsw%!W-%JDxH?CXM7%}F)|>AlJ>FW|e|mgM5Qb!N zLS=0oNl1D5;suHr8+1aIgaY_;eq?y2^bB$?RsJemg`7Hbeoxy;jVWO%s z^FbGBr&->2>;mJ-jJH4dkUWWTuiBI=4vV?RV&Y;KiX0suA!T4FDhqGMd_Lpys!bS# z7`jFnh9t|FTX*iUSS*;#J<>Es_~UPXosR|s)^6Tp?hdg_CER|WMZBc7zD|Y!Sw^&s z(R1(vA4%0vb%P*DNTP^RsmQ3;AxkpiJf~vYXoi7NTtW0_6EbrC{;$s&xKmtrN~v68 z7RE%21+oB($p|&e*?jZ?x@9qOM|}R(*M#02NfB|HYi#V^r@p$%jYgH`_BPJ?CUbX) z@aNzCCU4xl#o4Q8NahMfRbVg};M5v;u1jw+WoLH>#VRqpJY(U_2}7Ul`wzG{I;2#q zFr9ihDuRCa>Ea#5jz(I(&(t>ZHDhgn**zw9igBylAtrv%_LC!Rue* zP9{{Ft33Sp`@DMo6kXHkcX|{|15uW#-MmGy)}T}@k)}(wTMeXlZ*T3-LLW;viQ|aV zt1h}GViikNYc)J~MCg0OQNr1EA0>?lT^B@w$;=~@Wi(Y`KAjRwMgS~kQ<_^_%qKIX zPk;QweO;2MZ{FhQ-~eZ3g|7~du{4eLRhve$Nwam6z?<{vqfd||i71Y!)@qb&lkMAk zuuPC-m67XmadFD}+B&0N4^bA7GXzvkXVz_FS{563?x83mGe1BUC4@BL;`k8DGWhpj z|3b+&5ppmso9=ZVMb>DnZ!#GVn2*O~x<Wxk4RIEP zh_D zkGGzDLZx0qQ#I^r9r2sr*rPufaPZ|9Ox+QEcScG^^~O5KhljK~T^d`v6ioxwv{>KX z<-y}8D2hUYfGkLK`$L+wGET{+ck~>V31+FxXaD#c!e@W_L!KoOz1Ih5hRJy5p$QqD zACSZmmSrJ|5@Fy|zjd4L>jMNqAd_UawzfGsIiXy%31%LZS`~LR!Zu8TAfV!u5y@h_ z!8MW~;Esmaip2BdQ=&A%&FU~HAL;=OJ z5ham>^ER3yljj-Iqt)`hJDnktBZ?xU>6}8PjA5A+3ng^BgcpQtx7G;agqb%d@#e^) z$VI2a@p+pp&Dh;&F=$_)83wI}LzZUvVT|0|+9g}Y96Wzcm@K(>_cnXqdcx5c|70|o zAqyfwlrRj2Xr_v#8N}oqy?V)7bB*=p4cuX$;c$SV>WFzp97X7M5hV(c8k)G@tk?PO zFFqw6^$>vZ#R*{$k|YV1uA^%*tvh!J=X2ir_y^27=j^@n9w#TK1fI)m?qMo2nrX9s z{~^7La|Z4hQ2=58mp{t)ws-j7i|15}MWSShsjGy`j7q(UEG&^!mC<;Lo@eA)j|j zeQlFkqlTzx*cAuUaS+IO=lyRp4I-{OR~VKJKpZc*vG)Mi?USY{(oeqg;eHZDAmkKG zlXBg`Dy*PuI@M+ii6u#zQLu|hvP`$v!*Qxi-2rjnQ!W)4dkg#^MAH>&Yb~ Date: Sat, 21 Aug 2021 23:05:54 +0300 Subject: [PATCH 55/55] Added rock DB and worldgen - Added Rocks container - Added DiscreteNoise and a DIY Worley generator - Added RockLayer - Used to generate rock strata - Reworked SurfaceTerrainGenerator to use contexts --- .../util/noise/discrete/DiscreteNoise.java | 25 ++ .../noise/discrete/WorleyProceduralNoise.java | 228 ++++++++++++++++++ .../generation/planet/PlanetGenerator.java | 2 +- .../planet/PlanetTerrainGenerator.java | 36 ++- .../world/generation/surface/Surface.java | 39 ++- .../surface/SurfaceFeatureGenerator.java | 26 +- .../surface/SurfaceTerrainGenerator.java | 51 ++-- .../generation/surface/TerrainLayer.java | 6 +- .../ru/windcorp/progressia/test/Rocks.java | 126 ++++++++++ .../windcorp/progressia/test/TestContent.java | 38 +-- .../progressia/test/gen/RockLayer.java | 57 +++++ .../test/gen/TestGenerationConfig.java | 44 ++-- 12 files changed, 574 insertions(+), 104 deletions(-) create mode 100644 src/main/java/ru/windcorp/progressia/common/util/noise/discrete/DiscreteNoise.java create mode 100644 src/main/java/ru/windcorp/progressia/common/util/noise/discrete/WorleyProceduralNoise.java create mode 100644 src/main/java/ru/windcorp/progressia/test/Rocks.java create mode 100644 src/main/java/ru/windcorp/progressia/test/gen/RockLayer.java diff --git a/src/main/java/ru/windcorp/progressia/common/util/noise/discrete/DiscreteNoise.java b/src/main/java/ru/windcorp/progressia/common/util/noise/discrete/DiscreteNoise.java new file mode 100644 index 0000000..3e600f0 --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/common/util/noise/discrete/DiscreteNoise.java @@ -0,0 +1,25 @@ +/* + * 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.common.util.noise.discrete; + +public interface DiscreteNoise { + + T get(double x, double y); + T get(double x, double y, double z); + +} diff --git a/src/main/java/ru/windcorp/progressia/common/util/noise/discrete/WorleyProceduralNoise.java b/src/main/java/ru/windcorp/progressia/common/util/noise/discrete/WorleyProceduralNoise.java new file mode 100644 index 0000000..258e9b0 --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/common/util/noise/discrete/WorleyProceduralNoise.java @@ -0,0 +1,228 @@ +/* + * 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.common.util.noise.discrete; + +import java.util.Collection; +import com.google.common.collect.ImmutableList; + +public class WorleyProceduralNoise implements DiscreteNoise { + + /* + * Stolen from OpenJDK's Random implementation + * *evil cackling* + */ + private static final long MULTIPLIER = 0x5DEECE66DL; + private static final long ADDEND = 0xBL; + private static final long MASK = (1L << 48) - 1; + private static final double DOUBLE_UNIT = 0x1.0p-53; // 1.0 / (1L << 53) + + private static long permute(long seed) { + return (seed * MULTIPLIER + ADDEND) & MASK; + } + + private static double getDouble(long seed) { + final int mask26bits = (1 << 26) - 1; + final int mask27bits = (1 << 27) - 1; + + int randomBitsX26 = (int) (seed & 0xFFFFFFFF); + int randomBitsX27 = (int) ((seed >>> Integer.SIZE) & 0xFFFFFFFF); + + randomBitsX26 = randomBitsX26 & mask26bits; + randomBitsX27 = randomBitsX27 & mask27bits; + + return (((long) (randomBitsX26) << 27) + randomBitsX27) * DOUBLE_UNIT; + } + + public static class Entry { + private final T value; + private final double chance; + + public Entry(T value, double chance) { + this.value = value; + this.chance = chance; + } + } + + public static class Builder { + + com.google.common.collect.ImmutableList.Builder> builder = ImmutableList.builder(); + + public Builder add(T value, double chance) { + builder.add(new Entry<>(value, chance)); + return this; + } + + public WorleyProceduralNoise build(long seed) { + return new WorleyProceduralNoise<>(this, seed); + } + + } + + public static Builder builder() { + return new Builder<>(); + } + + private final Entry[] entries; + private final long seed; + + public WorleyProceduralNoise(Builder builder, long seed) { + this(builder.builder.build(), seed); + } + + public WorleyProceduralNoise(Collection> entries, long seed) { + this.entries = new Entry[entries.size()]; + + double chancesSum = 0; + for (Entry entry : entries) { + chancesSum += entry.chance; + } + + int i = 0; + for (Entry entry : entries) { + this.entries[i] = new Entry(entry.value, entry.chance / chancesSum); + i++; + } + + this.seed = seed; + } + + @Override + public T get(double x, double y) { + + int ox = (int) x; + int oy = (int) y; + + T closest = null; + double closestDistanceSq = Double.POSITIVE_INFINITY; + + for (int cellX = ox - 1; cellX <= ox + 1; ++cellX) { + for (int cellY = oy - 1; cellY <= oy + 1; ++cellY) { + + long cellSeed = permute(cellY ^ permute(cellX ^ seed)); + + int nodes = getNodeCount(cellSeed); + cellSeed = permute(cellSeed); + + for (int i = 0; i < nodes; ++i) { + + double nodeX = getDouble(cellSeed) + cellX; + cellSeed = permute(cellSeed); + + double nodeY = getDouble(cellSeed) + cellY; + cellSeed = permute(cellSeed); + + T value = getValue(getDouble(cellSeed)); + cellSeed = permute(cellSeed); + + double distanceSq = (x - nodeX) * (x - nodeX) + (y - nodeY) * (y - nodeY); + if (distanceSq < closestDistanceSq) { + closestDistanceSq = distanceSq; + closest = value; + } + + } + } + } + + return closest; + + } + + @Override + public T get(double x, double y, double z) { + + int ox = (int) x; + int oy = (int) y; + int oz = (int) z; + + T closest = null; + double closestDistanceSq = Double.POSITIVE_INFINITY; + + for (int cellX = ox - 1; cellX <= ox + 1; ++cellX) { + for (int cellY = oy - 1; cellY <= oy + 1; ++cellY) { + for (int cellZ = oz - 1; cellZ <= oz + 1; ++cellZ) { + + long cellSeed = permute(cellZ ^ permute(cellY ^ permute(cellX ^ seed))); + + int nodes = getNodeCount(cellSeed); + cellSeed = permute(cellSeed); + + for (int i = 0; i < nodes; ++i) { + + double nodeX = getDouble(cellSeed) + cellX; + cellSeed = permute(cellSeed); + + double nodeY = getDouble(cellSeed) + cellY; + cellSeed = permute(cellSeed); + + double nodeZ = getDouble(cellSeed) + cellZ; + cellSeed = permute(cellSeed); + + T value = getValue(getDouble(cellSeed)); + cellSeed = permute(cellSeed); + + double distanceSq = (x - nodeX) * (x - nodeX) + (y - nodeY) * (y - nodeY) + + (z - nodeZ) * (z - nodeZ); + if (distanceSq < closestDistanceSq) { + closestDistanceSq = distanceSq; + closest = value; + } + + } + } + } + } + + return closest; + + } + + @SuppressWarnings("unchecked") + private T getValue(double target) { + int i; + + for (i = 0; i < entries.length && target > entries[i].chance; ++i) { + target -= entries[i].chance; + } + + return (T) entries[i].value; + } + + private int getNodeCount(long seed) { + int uniform = ((int) seed) % 8; + + switch (uniform) { + case 0: + case 1: + case 2: + case 3: + return 1; + + case 4: + case 5: + return 2; + + case 6: + return 3; + + default: + return 4; + } + } + +} diff --git a/src/main/java/ru/windcorp/progressia/server/world/generation/planet/PlanetGenerator.java b/src/main/java/ru/windcorp/progressia/server/world/generation/planet/PlanetGenerator.java index b568639..b2c5c8c 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/generation/planet/PlanetGenerator.java +++ b/src/main/java/ru/windcorp/progressia/server/world/generation/planet/PlanetGenerator.java @@ -104,7 +104,7 @@ public class PlanetGenerator extends AbstractWorldGenerator { DefaultChunkData chunk = getWorldData().getChunk(chunkPos); if (chunk == null) { - chunk = terrainGenerator.generateTerrain(chunkPos); + chunk = terrainGenerator.generateTerrain(getServer(), chunkPos); getWorldData().addChunk(chunk); } } diff --git a/src/main/java/ru/windcorp/progressia/server/world/generation/planet/PlanetTerrainGenerator.java b/src/main/java/ru/windcorp/progressia/server/world/generation/planet/PlanetTerrainGenerator.java index ab081db..dba3b8a 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/generation/planet/PlanetTerrainGenerator.java +++ b/src/main/java/ru/windcorp/progressia/server/world/generation/planet/PlanetTerrainGenerator.java @@ -17,6 +17,8 @@ */ package ru.windcorp.progressia.server.world.generation.planet; +import java.util.Map; + import glm.vec._3.Vec3; import glm.vec._3.i.Vec3i; import ru.windcorp.progressia.common.util.FloatRangeMap; @@ -26,6 +28,9 @@ import ru.windcorp.progressia.common.world.Coordinates; import ru.windcorp.progressia.common.world.block.BlockData; import ru.windcorp.progressia.common.world.block.BlockDataRegistry; import ru.windcorp.progressia.common.world.generic.GenericChunks; +import ru.windcorp.progressia.common.world.rels.AbsFace; +import ru.windcorp.progressia.server.Server; +import ru.windcorp.progressia.server.world.generation.surface.Surface; import ru.windcorp.progressia.server.world.generation.surface.SurfaceFloatField; import ru.windcorp.progressia.server.world.generation.surface.SurfaceTerrainGenerator; import ru.windcorp.progressia.server.world.generation.surface.TerrainLayer; @@ -33,25 +38,38 @@ import ru.windcorp.progressia.server.world.generation.surface.TerrainLayer; class PlanetTerrainGenerator { private final PlanetGenerator parent; - private final SurfaceTerrainGenerator surfaceGenerator; + private final Map surfaceGenerators; - public PlanetTerrainGenerator(PlanetGenerator generator, SurfaceFloatField heightMap, FloatRangeMap layers) { + public PlanetTerrainGenerator( + PlanetGenerator generator, + SurfaceFloatField heightMap, + FloatRangeMap layers + ) { this.parent = generator; + + int seaLevel = (int) parent.getPlanet().getRadius(); SurfaceFloatField adjustedHeightMap = (f, n, w) -> heightMap.get(f, n, w) + generator.getPlanet().getRadius(); - this.surfaceGenerator = new SurfaceTerrainGenerator(adjustedHeightMap, layers); + + this.surfaceGenerators = AbsFace.mapToFaces( + face -> new SurfaceTerrainGenerator( + new Surface(face, seaLevel), + adjustedHeightMap, + layers + ) + ); } public PlanetGenerator getGenerator() { return parent; } - public DefaultChunkData generateTerrain(Vec3i chunkPos) { + public DefaultChunkData generateTerrain(Server server, Vec3i chunkPos) { DefaultChunkData chunk = new DefaultChunkData(chunkPos, getGenerator().getWorldData()); if (isOrdinaryChunk(chunkPos)) { - generateOrdinaryTerrain(chunk); + generateOrdinaryTerrain(server, chunk); } else { - generateBorderTerrain(chunk); + generateBorderTerrain(server, chunk); } chunk.setGenerationHint(false); @@ -64,11 +82,11 @@ class PlanetTerrainGenerator { return sorted.x != sorted.y; } - private void generateOrdinaryTerrain(DefaultChunkData chunk) { - surfaceGenerator.generateTerrain(chunk); + private void generateOrdinaryTerrain(Server server, DefaultChunkData chunk) { + surfaceGenerators.get(chunk.getUp()).generateTerrain(server, chunk); } - private void generateBorderTerrain(DefaultChunkData chunk) { + private void generateBorderTerrain(Server server, DefaultChunkData chunk) { BlockData stone = BlockDataRegistry.getInstance().get("Test:Stone"); BlockData air = BlockDataRegistry.getInstance().get("Test:Air"); diff --git a/src/main/java/ru/windcorp/progressia/server/world/generation/surface/Surface.java b/src/main/java/ru/windcorp/progressia/server/world/generation/surface/Surface.java index 296e3eb..08c9308 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/generation/surface/Surface.java +++ b/src/main/java/ru/windcorp/progressia/server/world/generation/surface/Surface.java @@ -17,18 +17,28 @@ */ package ru.windcorp.progressia.server.world.generation.surface; +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.generic.ChunkGenericRO; import ru.windcorp.progressia.common.world.rels.AbsFace; +import ru.windcorp.progressia.server.Server; +import ru.windcorp.progressia.server.world.context.ServerTileContext; +import ru.windcorp.progressia.server.world.generation.surface.context.SurfaceContextImpl; +import ru.windcorp.progressia.server.world.generation.surface.context.SurfaceWorldContext; public class Surface { - + private final AbsFace up; private final int seaLevel; - + public Surface(AbsFace up, int seaLevel) { this.up = up; this.seaLevel = seaLevel; } - + /** * @return the up */ @@ -43,4 +53,27 @@ public class Surface { return seaLevel; } + public SurfaceWorldContext createContext(Server server, ChunkGenericRO chunk, long seed) { + + Random random = new Random(CoordinatePacker.pack3IntsIntoLong(chunk.getPosition()) ^ seed); + + SurfaceContextImpl context = new SurfaceContextImpl((ServerTileContext) server.createAbsoluteContext(), this); + 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()); + + return context; + + } + } diff --git a/src/main/java/ru/windcorp/progressia/server/world/generation/surface/SurfaceFeatureGenerator.java b/src/main/java/ru/windcorp/progressia/server/world/generation/surface/SurfaceFeatureGenerator.java index abfbcb3..3548184 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/generation/surface/SurfaceFeatureGenerator.java +++ b/src/main/java/ru/windcorp/progressia/server/world/generation/surface/SurfaceFeatureGenerator.java @@ -19,15 +19,9 @@ package ru.windcorp.progressia.server.world.generation.surface; import java.util.ArrayList; import java.util.List; -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.server.world.generation.surface.context.SurfaceContextImpl; +import ru.windcorp.progressia.server.world.generation.surface.context.SurfaceWorldContext; public class SurfaceFeatureGenerator { @@ -48,23 +42,7 @@ public class SurfaceFeatureGenerator { } public void generateFeatures(Server server, DefaultChunkData chunk) { - - Random random = new Random(CoordinatePacker.pack3IntsIntoLong(chunk.getPosition()) /* ^ seed*/); - - 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()); + SurfaceWorldContext context = surface.createContext(server, chunk, 0); for (SurfaceFeature feature : features) { feature.process(context); diff --git a/src/main/java/ru/windcorp/progressia/server/world/generation/surface/SurfaceTerrainGenerator.java b/src/main/java/ru/windcorp/progressia/server/world/generation/surface/SurfaceTerrainGenerator.java index a3511bd..35b4a58 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/generation/surface/SurfaceTerrainGenerator.java +++ b/src/main/java/ru/windcorp/progressia/server/world/generation/surface/SurfaceTerrainGenerator.java @@ -17,60 +17,73 @@ */ package ru.windcorp.progressia.server.world.generation.surface; -import java.util.Random; - import glm.vec._3.Vec3; import glm.vec._3.i.Vec3i; -import ru.windcorp.progressia.common.util.CoordinatePacker; import ru.windcorp.progressia.common.util.FloatRangeMap; +import ru.windcorp.progressia.common.util.Vectors; import ru.windcorp.progressia.common.world.DefaultChunkData; import ru.windcorp.progressia.common.world.block.BlockData; import ru.windcorp.progressia.common.world.rels.AxisRotations; +import ru.windcorp.progressia.server.Server; +import ru.windcorp.progressia.server.world.generation.surface.context.SurfaceBlockContext; +import ru.windcorp.progressia.server.world.generation.surface.context.SurfaceWorldContext; public class SurfaceTerrainGenerator { - + + private final Surface surface; + private final SurfaceFloatField heightMap; private final FloatRangeMap layers; - public SurfaceTerrainGenerator(SurfaceFloatField heightMap, FloatRangeMap layers) { + public SurfaceTerrainGenerator(Surface surface, SurfaceFloatField heightMap, FloatRangeMap layers) { + this.surface = surface; this.heightMap = heightMap; this.layers = layers; } - - public void generateTerrain(DefaultChunkData chunk) { + + public void generateTerrain(Server server, DefaultChunkData chunk) { Vec3i relBIC = new Vec3i(); Vec3 offset = new Vec3(chunk.getMinX(), chunk.getMinY(), chunk.getMinZ()); AxisRotations.relativize(offset, chunk.getUp(), offset); - offset.z -= DefaultChunkData.CHUNK_RADIUS - 0.5f; - Random random = new Random(CoordinatePacker.pack3IntsIntoLong(chunk.getPosition()) /* ^ seed*/); + SurfaceWorldContext context = surface.createContext(server, chunk, 0); for (relBIC.x = 0; relBIC.x < DefaultChunkData.BLOCKS_PER_CHUNK; ++relBIC.x) { for (relBIC.y = 0; relBIC.y < DefaultChunkData.BLOCKS_PER_CHUNK; ++relBIC.y) { - generateColumn(chunk, relBIC, offset, random); + generateColumn(chunk, relBIC, offset, context); } } } - - public void generateColumn(DefaultChunkData chunk, Vec3i relBIC, Vec3 offset, Random random) { - - float north = relBIC.x + offset.x; - float west = relBIC.y + offset.y; - - float relSurface = heightMap.get(chunk.getUp(), north, west) - offset.z; - + + public void generateColumn(DefaultChunkData chunk, Vec3i relBIC, Vec3 offset, SurfaceWorldContext context) { + + int north = (int) (relBIC.x + offset.x); + int west = (int) (relBIC.y + offset.y); + + float relSurface = heightMap.get(chunk.getUp(), north, west) - offset.z + DefaultChunkData.CHUNK_RADIUS - 0.5f; + Vec3i location = Vectors.grab3i(); + for (relBIC.z = 0; relBIC.z < DefaultChunkData.BLOCKS_PER_CHUNK; ++relBIC.z) { float depth = relSurface - relBIC.z; - BlockData block = layers.get(depth).get(chunk.getUp(), north, west, depth, random); + int altitude = (int) (relBIC.z + offset.z); + location.set(north, west, altitude); + SurfaceBlockContext blockContext = context.push(location); + + BlockData block = layers.get(depth).get(blockContext, depth); + + blockContext.pop(); + chunk.resolve(relBIC, relBIC); chunk.setBlock(relBIC, block, false); chunk.relativize(relBIC, relBIC); } + Vectors.release(location); + } } diff --git a/src/main/java/ru/windcorp/progressia/server/world/generation/surface/TerrainLayer.java b/src/main/java/ru/windcorp/progressia/server/world/generation/surface/TerrainLayer.java index 7af46fa..5ec131c 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/generation/surface/TerrainLayer.java +++ b/src/main/java/ru/windcorp/progressia/server/world/generation/surface/TerrainLayer.java @@ -17,14 +17,12 @@ */ package ru.windcorp.progressia.server.world.generation.surface; -import java.util.Random; - import ru.windcorp.progressia.common.world.block.BlockData; -import ru.windcorp.progressia.common.world.rels.AbsFace; +import ru.windcorp.progressia.server.world.generation.surface.context.SurfaceBlockContext; @FunctionalInterface public interface TerrainLayer { - BlockData get(AbsFace face, float north, float west, float depth, Random random); + BlockData get(SurfaceBlockContext context, float depth); } diff --git a/src/main/java/ru/windcorp/progressia/test/Rocks.java b/src/main/java/ru/windcorp/progressia/test/Rocks.java new file mode 100644 index 0000000..ebf31fe --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/test/Rocks.java @@ -0,0 +1,126 @@ +/* + * 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; + +import java.util.Collection; +import java.util.Collections; +import java.util.EnumMap; +import java.util.HashMap; +import java.util.Map; + +import com.google.common.collect.HashMultimap; +import com.google.common.collect.Multimap; +import com.google.common.collect.Multimaps; + +import ru.windcorp.progressia.client.world.block.BlockRenderOpaqueCube; +import ru.windcorp.progressia.client.world.block.BlockRenderRegistry; +import ru.windcorp.progressia.common.world.block.BlockData; +import ru.windcorp.progressia.common.world.block.BlockDataRegistry; +import ru.windcorp.progressia.server.world.block.BlockLogic; +import ru.windcorp.progressia.server.world.block.BlockLogicRegistry; + +public class Rocks { + + public enum RockType { + IGNEOUS, METAMORPHIC, SEDIMENTARY; + } + + public enum RockVariant { + + MONOLITH("Monolith"), + CRACKED("Cracked"), + GRAVEL("Gravel"), + SAND("Sand"); + + private final String name; + + private RockVariant(String name) { + this.name = name; + } + + public String getName() { + return name; + } + + } + + public static class Rock { + + private final String name; + private final RockType type; + + private final Map blocks = new EnumMap<>(RockVariant.class); + + public Rock(String name, RockType type) { + this.name = name; + this.type = type; + } + + public String getName() { + return name; + } + + public RockType getType() { + return type; + } + + public BlockData getBlock(RockVariant variant) { + return blocks.get(variant); + } + + private void register() { + for (RockVariant variant : RockVariant.values()) { + + String fullName = name + variant.getName(); + String id = "Test:" + fullName; + + BlockData blockData = new BlockData(id); + blocks.put(variant, blockData); + BlockDataRegistry.getInstance().register(blockData); + BlockLogicRegistry.getInstance().register(new BlockLogic(id)); + BlockRenderRegistry.getInstance() + .register(new BlockRenderOpaqueCube(id, BlockRenderRegistry.getBlockTexture(fullName))); + + } + } + + } + + private final Map rocksByName = Collections.synchronizedMap(new HashMap<>()); + private final Multimap rocksByType = Multimaps.synchronizedMultimap(HashMultimap.create()); + + public Rock create(RockType type, String name) { + Rock rock = new Rock(name, type); + rocksByName.put(name, rock); + rocksByType.put(type, rock); + return rock; + } + + public void registerAllRocks() { + getRocks().forEach(Rock::register); + } + + public Collection getRocks() { + return rocksByName.values(); + } + + public Collection getRocks(RockType type) { + return rocksByType.get(type); + } + +} diff --git a/src/main/java/ru/windcorp/progressia/test/TestContent.java b/src/main/java/ru/windcorp/progressia/test/TestContent.java index 9e868b4..1244560 100644 --- a/src/main/java/ru/windcorp/progressia/test/TestContent.java +++ b/src/main/java/ru/windcorp/progressia/test/TestContent.java @@ -29,8 +29,6 @@ import java.util.Set; import java.util.function.Consumer; import org.lwjgl.glfw.GLFW; -import com.google.common.collect.ImmutableList; - import glm.vec._3.i.Vec3i; import ru.windcorp.progressia.client.ClientState; import ru.windcorp.progressia.client.audio.Sound; @@ -59,6 +57,7 @@ import ru.windcorp.progressia.server.world.block.*; import ru.windcorp.progressia.server.world.entity.*; import ru.windcorp.progressia.server.world.generation.planet.PlanetGravityModel; import ru.windcorp.progressia.server.world.tile.*; +import ru.windcorp.progressia.test.Rocks.RockType; import ru.windcorp.progressia.test.gen.TestGravityModel; public class TestContent { @@ -69,6 +68,8 @@ public class TestContent { public static final List PLACEABLE_BLOCKS = new ArrayList<>(); public static final List PLACEABLE_TILES = new ArrayList<>(); + + public static final Rocks ROCKS = new Rocks(); public static void registerContent() { registerWorldContent(); @@ -150,33 +151,16 @@ public class TestContent { } private static void registerRocks() { - List rockNames = ImmutableList.of( - "BlackGranite", - "Dolomite", - "Eclogite", - "Gabbro", - "Limestone", - "Marble", - "RedGranite" - ); - List rockVariants = ImmutableList.of( - "Monolith", - "Cracked", - "Gravel", - "Sand" - ); + ROCKS.create(RockType.IGNEOUS, "BlackGranite"); + ROCKS.create(RockType.IGNEOUS, "RedGranite"); + ROCKS.create(RockType.IGNEOUS, "Gabbro"); + ROCKS.create(RockType.METAMORPHIC, "Marble"); + ROCKS.create(RockType.METAMORPHIC, "Eclogite"); + ROCKS.create(RockType.SEDIMENTARY, "Limestone"); + ROCKS.create(RockType.SEDIMENTARY, "Dolomite"); - for (String name : rockNames) { - for (String variant : rockVariants) { - String fullName = name + variant; - String id = "Test:" + fullName; - - register(new BlockData(id)); - register(new BlockRenderOpaqueCube(id, getBlockTexture(fullName))); - register(new BlockLogic(id)); - } - } + ROCKS.registerAllRocks(); } private static void registerTiles() { diff --git a/src/main/java/ru/windcorp/progressia/test/gen/RockLayer.java b/src/main/java/ru/windcorp/progressia/test/gen/RockLayer.java new file mode 100644 index 0000000..5b41ef1 --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/test/gen/RockLayer.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; + +import ru.windcorp.progressia.common.util.noise.discrete.DiscreteNoise; +import ru.windcorp.progressia.common.world.block.BlockData; +import ru.windcorp.progressia.server.world.generation.surface.SurfaceFloatField; +import ru.windcorp.progressia.server.world.generation.surface.TerrainLayer; +import ru.windcorp.progressia.server.world.generation.surface.context.SurfaceBlockContext; + +public class RockLayer implements TerrainLayer { + + private final DiscreteNoise strata; + private final SurfaceFloatField depthOffsets; + + private final double horizontalScale = 200; + private final double verticalScale = 10; + private final double depthInfluense = 0.1; + + public RockLayer(DiscreteNoise strata, SurfaceFloatField depthOffsets) { + this.strata = strata; + this.depthOffsets = depthOffsets; + } + + @Override + public BlockData get(SurfaceBlockContext context, float depth) { + + double z = context.getLocation().z; + z -= depth * depthInfluense; + z += depthOffsets.get(context); + z /= verticalScale; + + return strata + .get( + context.getLocation().x / horizontalScale, + context.getLocation().y / horizontalScale, + z + ) + .get(context, depth); + } + +} diff --git a/src/main/java/ru/windcorp/progressia/test/gen/TestGenerationConfig.java b/src/main/java/ru/windcorp/progressia/test/gen/TestGenerationConfig.java index 22a66d7..cc1ff8b 100644 --- a/src/main/java/ru/windcorp/progressia/test/gen/TestGenerationConfig.java +++ b/src/main/java/ru/windcorp/progressia/test/gen/TestGenerationConfig.java @@ -26,6 +26,7 @@ import java.util.function.Function; import ru.windcorp.progressia.common.Units; import ru.windcorp.progressia.common.util.ArrayFloatRangeMap; import ru.windcorp.progressia.common.util.FloatRangeMap; +import ru.windcorp.progressia.common.util.noise.discrete.WorleyProceduralNoise; import ru.windcorp.progressia.common.world.Coordinates; import ru.windcorp.progressia.common.world.block.BlockData; import ru.windcorp.progressia.common.world.block.BlockDataRegistry; @@ -36,15 +37,19 @@ import ru.windcorp.progressia.server.world.generation.planet.PlanetGenerator; import ru.windcorp.progressia.server.world.generation.surface.SurfaceFeature; import ru.windcorp.progressia.server.world.generation.surface.SurfaceFloatField; import ru.windcorp.progressia.server.world.generation.surface.TerrainLayer; +import ru.windcorp.progressia.test.Rocks.RockVariant; +import ru.windcorp.progressia.test.TestContent; public class TestGenerationConfig { + private static final long SEED = "No bugs please".hashCode(); + private static final float PLANET_RADIUS = Units.get("0.5 km"); private static final float SURFACE_GRAVITY = Units.get("9.8 m/s^2"); 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("No bugs please".hashCode()); + private static final Fields FIELDS = new Fields(SEED); public static Function createGenerator() { @@ -68,31 +73,36 @@ public class TestGenerationConfig { } private static void registerTerrainLayers(FloatRangeMap layers) { - BlockData granite = BlockDataRegistry.getInstance().get("Test:RedGraniteMonolith"); - BlockData graniteCracked = BlockDataRegistry.getInstance().get("Test:RedGraniteCracked"); - BlockData graniteGravel = BlockDataRegistry.getInstance().get("Test:RedGraniteGravel"); - BlockData dirt = BlockDataRegistry.getInstance().get("Test:Dirt"); BlockData air = BlockDataRegistry.getInstance().get("Test:Air"); SurfaceFloatField cliffs = FIELDS.get("Test:CliffSelector"); - layers.put(Float.NEGATIVE_INFINITY, 0, (f, n, w, d, r) -> air); - layers.put(0, 4, (f, n, w, d, r) -> { - if (cliffs.get(f, n, w) > 0) { - switch (r.nextInt(4)) { - case 0: - return granite; - case 1: - return graniteCracked; - default: - return graniteGravel; + WorleyProceduralNoise.Builder builder = WorleyProceduralNoise.builder(); + TestContent.ROCKS.getRocks().forEach(rock -> { + builder.add((c, d) -> { + if (c.getRandom().nextInt(3) == 0) { + return rock.getBlock(RockVariant.CRACKED); + } else { + return rock.getBlock(RockVariant.MONOLITH); } + }, 1); + }); + SurfaceFloatField rockDepthOffsets = FIELDS.register( + "Test:RockDepthOffsets", + () -> tweak(FIELDS.primitive(), 40, 5) + ); + RockLayer rockLayer = new RockLayer(builder.build(SEED), rockDepthOffsets); + + layers.put(Float.NEGATIVE_INFINITY, 0, (c, d) -> air); + layers.put(0, 4, (c, d) -> { + if (cliffs.get(c.getSurface().getUp(), c.getLocation().x, c.getLocation().y) > 0) { + return rockLayer.get(c, d); } else { return dirt; } }); - layers.put(4, Float.POSITIVE_INFINITY, (f, n, w, d, r) -> granite); + layers.put(4, Float.POSITIVE_INFINITY, rockLayer); } private static void registerFeatures(List features) { @@ -101,7 +111,7 @@ public class TestGenerationConfig { "Test:Forestiness", () -> squash(scale(FIELDS.primitive(), 200), 5) ); - + SurfaceFloatField floweriness = FIELDS.register( "Test:Floweriness", f -> multiply(