diff --git a/src/main/java/ru/windcorp/progressia/client/Client.java b/src/main/java/ru/windcorp/progressia/client/Client.java
index de6fa54..cd8c5a4 100644
--- a/src/main/java/ru/windcorp/progressia/client/Client.java
+++ b/src/main/java/ru/windcorp/progressia/client/Client.java
@@ -3,6 +3,7 @@ package ru.windcorp.progressia.client;
import ru.windcorp.progressia.client.comms.DefaultClientCommsListener;
import ru.windcorp.progressia.client.comms.ServerCommsChannel;
import ru.windcorp.progressia.client.graphics.world.Camera;
+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.entity.EntityData;
@@ -10,7 +11,7 @@ import ru.windcorp.progressia.common.world.entity.EntityData;
public class Client {
private final WorldRender world;
- private EntityData localPlayer;
+ private LocalPlayer localPlayer;
private final Camera camera = new Camera((float) Math.toRadians(70));
@@ -27,12 +28,12 @@ public class Client {
return world;
}
- public EntityData getLocalPlayer() {
+ public LocalPlayer getLocalPlayer() {
return localPlayer;
}
public void setLocalPlayer(EntityData localPlayer) {
- this.localPlayer = localPlayer;
+ this.localPlayer = new LocalPlayer(localPlayer);
}
public Camera getCamera() {
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 fb7557e..2e4b6be 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
@@ -20,6 +20,7 @@ package ru.windcorp.progressia.client.graphics.world;
import java.util.ArrayList;
import java.util.List;
+import glm.vec._3.i.Vec3i;
import ru.windcorp.progressia.client.Client;
import ru.windcorp.progressia.client.ClientState;
import ru.windcorp.progressia.client.comms.controls.InputBasedControls;
@@ -65,6 +66,10 @@ public class LayerWorld extends Layer {
if (camera.hasAnchor()) {
renderWorld();
}
+
+ if (client.getLocalPlayer() != null) {
+ client.getLocalPlayer().update(client.getWorld());
+ }
}
private void renderWorld() {
@@ -89,6 +94,7 @@ public class LayerWorld extends Layer {
try {
tmp_performCollisions(tickLength);
+ tmp_drawSelectionBox();
tmp_testControls.applyPlayerControls();
@@ -122,13 +128,25 @@ public class LayerWorld extends Layer {
);
}
+ private void tmp_drawSelectionBox() {
+ LocalPlayer player = client.getLocalPlayer();
+ if (player == null) return;
+
+ Vec3i lookingAt = player.getLookingAt();
+ if (lookingAt == null) return;
+
+ helper.pushTransform().translate(lookingAt.x, lookingAt.y, lookingAt.z).scale(1.1f);
+ CollisionModelRenderer.renderCollisionModel(client.getWorld().getData().getCollisionModelOfBlock(lookingAt), helper);
+ helper.popTransform();
+ }
+
private void tmp_applyFriction(EntityData entity) {
final float frictionCoeff = 1 - 1e-5f;
entity.getVelocity().mul(frictionCoeff);
}
private void tmp_applyGravity(EntityData entity, float tickLength) {
- if (ClientState.getInstance().getLocalPlayer() == entity && tmp_testControls.isFlying()) {
+ if (ClientState.getInstance().getLocalPlayer().getEntity() == entity && tmp_testControls.isFlying()) {
return;
}
diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/world/LocalPlayer.java b/src/main/java/ru/windcorp/progressia/client/graphics/world/LocalPlayer.java
new file mode 100644
index 0000000..5df2b84
--- /dev/null
+++ b/src/main/java/ru/windcorp/progressia/client/graphics/world/LocalPlayer.java
@@ -0,0 +1,64 @@
+package ru.windcorp.progressia.client.graphics.world;
+
+import glm.vec._3.Vec3;
+import glm.vec._3.i.Vec3i;
+import ru.windcorp.progressia.client.world.WorldRender;
+import ru.windcorp.progressia.client.world.entity.EntityRenderable;
+import ru.windcorp.progressia.common.util.Vectors;
+import ru.windcorp.progressia.common.world.BlockRay;
+import ru.windcorp.progressia.common.world.Player;
+import ru.windcorp.progressia.common.world.entity.EntityData;
+
+public class LocalPlayer extends Player {
+
+ private Vec3i lookingAt = new Vec3i();
+ private boolean isLookingAtBlock = false;
+
+ private BlockRay lookingAtRay = new BlockRay();
+
+ public LocalPlayer(EntityData entity) {
+ super(entity);
+ }
+
+ public Vec3i getLookingAt() {
+ return isLookingAtBlock ? lookingAt : null;
+ }
+
+ public void update(WorldRender world) {
+ updateLookingAt(world);
+ }
+
+ private void updateLookingAt(WorldRender world) {
+ Vec3 direction = Vectors.grab3();
+ Vec3 start = Vectors.grab3();
+
+ BlockRay ray = lookingAtRay;
+ EntityData player = getEntity();
+
+ player.getLookingAtVector(direction);
+ world.getEntityRenderable(player).getViewPoint(start);
+ start.add(player.getPosition());
+
+ isLookingAtBlock = false;
+
+ for (ray.start(start, direction); ray.getDistance() < 6; ray.next()) {
+ Vec3i blockInWorld = ray.current();
+
+ if (world.getData().getCollisionModelOfBlock(blockInWorld) != null) {
+ isLookingAtBlock = true;
+ lookingAt.set(blockInWorld.x, blockInWorld.y, blockInWorld.z);
+ break;
+ }
+ }
+
+ ray.end();
+
+ Vectors.release(direction);
+ Vectors.release(start);
+ }
+
+ public EntityRenderable getRenderable(WorldRender world) {
+ return world.getEntityRenderable(getEntity());
+ }
+
+}
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 712a9cf..2b42481 100644
--- a/src/main/java/ru/windcorp/progressia/common/util/VectorUtil.java
+++ b/src/main/java/ru/windcorp/progressia/common/util/VectorUtil.java
@@ -3,12 +3,22 @@ package ru.windcorp.progressia.common.util;
import java.util.function.Consumer;
import glm.mat._4.Mat4;
+import glm.vec._2.Vec2;
+import glm.vec._2.d.Vec2d;
+import glm.vec._2.i.Vec2i;
import glm.vec._3.Vec3;
+import glm.vec._3.d.Vec3d;
import glm.vec._3.i.Vec3i;
import glm.vec._4.Vec4;
+import glm.vec._4.d.Vec4d;
+import glm.vec._4.i.Vec4i;
public class VectorUtil {
+ public static enum Axis {
+ X, Y, Z, W;
+ }
+
public static void forEachVectorInCuboid(
int x0, int y0, int z0,
int x1, int y1, int z1,
@@ -47,6 +57,204 @@ public class VectorUtil {
inOut.set(vec4.x, vec4.y, vec4.z);
}
+ public static Vec3 linearCombination(
+ Vec3 va, float ka,
+ Vec3 vb, float kb,
+ Vec3 output
+ ) {
+ output.set(
+ va.x * ka + vb.x * kb,
+ va.y * ka + vb.y * kb,
+ va.z * ka + vb.z * kb
+ );
+ return output;
+ }
+
+ public static Vec3 linearCombination(
+ Vec3 va, float ka,
+ Vec3 vb, float kb,
+ Vec3 vc, float kc,
+ Vec3 output
+ ) {
+ output.set(
+ va.x * ka + vb.x * kb + vc.x * kc,
+ va.y * ka + vb.y * kb + vc.y * kc,
+ va.z * ka + vb.z * kb + vc.z * kc
+ );
+ return output;
+ }
+
+ public static float get(Vec2 v, Axis a) {
+ switch (a) {
+ case X: return v.x;
+ case Y: return v.y;
+ default: throw new IllegalArgumentException("Vec2 does not have axis " + a);
+ }
+ }
+
+ public static Vec2 set(Vec2 v, Axis a, float value) {
+ switch (a) {
+ case X: v.x = value; break;
+ case Y: v.y = value; break;
+ default: throw new IllegalArgumentException("Vec2 does not have axis " + a);
+ }
+ return v;
+ }
+
+ public static int get(Vec2i v, Axis a) {
+ switch (a) {
+ case X: return v.x;
+ case Y: return v.y;
+ default: throw new IllegalArgumentException("Vec2i does not have axis " + a);
+ }
+ }
+
+ public static Vec2i set(Vec2i v, Axis a, int value) {
+ switch (a) {
+ case X: v.x = value; break;
+ case Y: v.y = value; break;
+ default: throw new IllegalArgumentException("Vec2i does not have axis " + a);
+ }
+ return v;
+ }
+
+ public static double get(Vec2d v, Axis a) {
+ switch (a) {
+ case X: return v.x;
+ case Y: return v.y;
+ default: throw new IllegalArgumentException("Vec2d does not have axis " + a);
+ }
+ }
+
+ public static Vec2d set(Vec2d v, Axis a, double value) {
+ switch (a) {
+ case X: v.x = value; break;
+ case Y: v.y = value; break;
+ default: throw new IllegalArgumentException("Vec2d does not have axis " + a);
+ }
+ return v;
+ }
+
+ public static float get(Vec3 v, Axis a) {
+ switch (a) {
+ case X: return v.x;
+ case Y: return v.y;
+ case Z: return v.z;
+ default: throw new IllegalArgumentException("Vec3 does not have axis " + a);
+ }
+ }
+
+ public static Vec3 set(Vec3 v, Axis a, float value) {
+ switch (a) {
+ case X: v.x = value; break;
+ case Y: v.y = value; break;
+ case Z: v.z = value; break;
+ default: throw new IllegalArgumentException("Vec3 does not have axis " + a);
+ }
+ return v;
+ }
+
+ public static int get(Vec3i v, Axis a) {
+ switch (a) {
+ case X: return v.x;
+ case Y: return v.y;
+ case Z: return v.z;
+ default: throw new IllegalArgumentException("Vec3i does not have axis " + a);
+ }
+ }
+
+ public static Vec3i set(Vec3i v, Axis a, int value) {
+ switch (a) {
+ case X: v.x = value; break;
+ case Y: v.y = value; break;
+ case Z: v.z = value; break;
+ default: throw new IllegalArgumentException("Vec3i does not have axis " + a);
+ }
+ return v;
+ }
+
+ public static double get(Vec3d v, Axis a) {
+ switch (a) {
+ case X: return v.x;
+ case Y: return v.y;
+ case Z: return v.z;
+ default: throw new IllegalArgumentException("Vec3d does not have axis " + a);
+ }
+ }
+
+ public static Vec3d set(Vec3d v, Axis a, double value) {
+ switch (a) {
+ case X: v.x = value; break;
+ case Y: v.y = value; break;
+ case Z: v.z = value; break;
+ default: throw new IllegalArgumentException("Vec3d does not have axis " + a);
+ }
+ return v;
+ }
+
+ public static float get(Vec4 v, Axis a) {
+ switch (a) {
+ case X: return v.x;
+ case Y: return v.y;
+ case Z: return v.z;
+ case W: return v.w;
+ default: throw new IllegalArgumentException("Vec4 does not have axis " + a);
+ }
+ }
+
+ public static Vec4 set(Vec4 v, Axis a, float value) {
+ switch (a) {
+ case X: v.x = value; break;
+ case Y: v.y = value; break;
+ case Z: v.z = value; break;
+ case W: v.w = value; break;
+ default: throw new IllegalArgumentException("Vec4 does not have axis " + a);
+ }
+ return v;
+ }
+
+ public static int get(Vec4i v, Axis a) {
+ switch (a) {
+ case X: return v.x;
+ case Y: return v.y;
+ case Z: return v.z;
+ case W: return v.w;
+ default: throw new IllegalArgumentException("Vec4i does not have axis " + a);
+ }
+ }
+
+ public static Vec4i set(Vec4i v, Axis a, int value) {
+ switch (a) {
+ case X: v.x = value; break;
+ case Y: v.y = value; break;
+ case Z: v.z = value; break;
+ case W: v.w = value; break;
+ default: throw new IllegalArgumentException("Vec4i does not have axis " + a);
+ }
+ return v;
+ }
+
+ public static double get(Vec4d v, Axis a) {
+ switch (a) {
+ case X: return v.x;
+ case Y: return v.y;
+ case Z: return v.z;
+ case W: return v.w;
+ default: throw new IllegalArgumentException("Vec4d does not have axis " + a);
+ }
+ }
+
+ public static Vec4d set(Vec4d v, Axis a, double value) {
+ switch (a) {
+ case X: v.x = value; break;
+ case Y: v.y = value; break;
+ case Z: v.z = value; break;
+ case W: v.w = value; break;
+ default: throw new IllegalArgumentException("Vec4d does not have axis " + a);
+ }
+ return v;
+ }
+
private VectorUtil() {}
}
diff --git a/src/main/java/ru/windcorp/progressia/common/world/BlockRay.java b/src/main/java/ru/windcorp/progressia/common/world/BlockRay.java
new file mode 100644
index 0000000..158a1fc
--- /dev/null
+++ b/src/main/java/ru/windcorp/progressia/common/world/BlockRay.java
@@ -0,0 +1,123 @@
+package ru.windcorp.progressia.common.world;
+
+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 static java.lang.Math.*;
+
+public class BlockRay {
+
+ private final Vec3 position = new Vec3();
+ private final Vec3 direction = new Vec3();
+
+ private float distance;
+
+ private final Vec3i block = new Vec3i();
+
+ private boolean isValid = false;
+
+ public void start(Vec3 position, Vec3 direction) {
+ if (!direction.any()) {
+ throw new IllegalArgumentException("Direction is a zero vector");
+ }
+
+ isValid = true;
+ this.position.set(position).sub(0.5f); // Make sure lattice points are block vertices, not centers
+ this.direction.set(direction).normalize();
+ this.block.set(toBlock(position.x), toBlock(position.y), toBlock(position.z));
+ this.distance = 0;
+ }
+
+ public void end() {
+ isValid = false;
+ }
+
+ public Vec3i next() {
+ checkState();
+
+ float tx = distanceToEdge(position.x, direction.x);
+ float ty = distanceToEdge(position.y, direction.y);
+ float tz = distanceToEdge(position.z, direction.z);
+
+ float tMin;
+ Axis axis;
+
+ if (tx < ty && tx < tz) {
+ tMin = tx;
+ axis = Axis.X;
+ } else if (ty < tx && ty < tz) {
+ tMin = ty;
+ axis = Axis.Y;
+ } else {
+ tMin = tz;
+ axis = Axis.Z;
+ }
+
+ // block.(axis) += signum(direction.(axis))
+ 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
+ distance += tMin;
+
+ // position.(axis) = round(position.(axis))
+ VectorUtil.set(position, axis, round(VectorUtil.get(position, axis)));
+
+ return block;
+ }
+
+ public Vec3i current() {
+ checkState();
+ return block;
+ }
+
+ private static float distanceToEdge(float c, float dir) {
+ if (dir == 0) return Float.POSITIVE_INFINITY;
+
+ float edge;
+
+ if (dir > 0) {
+ edge = strictCeil(c);
+ } else {
+ edge = strictFloor(c);
+ }
+
+ return (edge - c) / dir;
+ }
+
+ public float getDistance() {
+ checkState();
+ return distance;
+ }
+
+ private void checkState() {
+ if (!isValid) {
+ throw new IllegalStateException("BlockRay not started");
+ }
+ }
+
+ private static int toBlock(float c) {
+ return (int) round(c);
+ }
+
+ /**
+ * Returns a smallest integer a such that a > c.
+ * @param c the number to compute strict ceiling of
+ * @return the strict ceiling of c
+ */
+ private static float strictCeil(float c) {
+ return (float) (floor(c) + 1);
+ }
+
+ /**
+ * Returns a largest integer a such that a < c.
+ * @param c the number to compute strict ceiling of
+ * @return the strict ceiling of c
+ */
+ private static float strictFloor(float c) {
+ return (float) (ceil(c) - 1);
+ }
+
+}
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 f25ac0a..031be35 100644
--- a/src/main/java/ru/windcorp/progressia/common/world/ChunkData.java
+++ b/src/main/java/ru/windcorp/progressia/common/world/ChunkData.java
@@ -133,14 +133,6 @@ public class ChunkData {
}
if (!getPosition().any()) {
-// EntityData javapony = EntityDataRegistry.getInstance().create("Test:Javapony");
-// javapony.setEntityId(0x42);
-// javapony.setPosition(new Vec3(-6, -6, 20));
-// javapony.setDirection(new Vec2(
-// (float) Math.toRadians(40), (float) Math.toRadians(45)
-// ));
-// getEntities().add(javapony);
-
EntityData player = EntityDataRegistry.getInstance().create("Test:Player");
player.setEntityId(0x42);
player.setPosition(new Vec3(-6, -6, 20));
diff --git a/src/main/java/ru/windcorp/progressia/common/world/Player.java b/src/main/java/ru/windcorp/progressia/common/world/Player.java
new file mode 100644
index 0000000..14d8c76
--- /dev/null
+++ b/src/main/java/ru/windcorp/progressia/common/world/Player.java
@@ -0,0 +1,17 @@
+package ru.windcorp.progressia.common.world;
+
+import ru.windcorp.progressia.common.world.entity.EntityData;
+
+public class Player {
+
+ private EntityData entity;
+
+ public Player(EntityData entity) {
+ this.entity = entity;
+ }
+
+ public EntityData getEntity() {
+ return 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 0b3b73c..5cd79fd 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
@@ -119,5 +119,15 @@ public class EntityData extends StatefulObject implements Collideable {
public void changeVelocityOnCollision(Vec3 velocityChange) {
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())
+ );
+
+ return output;
+ }
}
diff --git a/src/main/java/ru/windcorp/progressia/test/CollisionModelRenderer.java b/src/main/java/ru/windcorp/progressia/test/CollisionModelRenderer.java
index 15463d4..e2d226f 100644
--- a/src/main/java/ru/windcorp/progressia/test/CollisionModelRenderer.java
+++ b/src/main/java/ru/windcorp/progressia/test/CollisionModelRenderer.java
@@ -53,7 +53,7 @@ public class CollisionModelRenderer {
}
public static void renderBlock(Vec3i coords, ShapeRenderHelper helper) {
- helper.pushTransform().translate(coords.x, coords.y, coords.z);
+ helper.pushTransform().translate(coords.x, coords.y, coords.z).scale(0.25f);
CUBE_GRAY.render(helper);
helper.popTransform();
}
diff --git a/src/main/java/ru/windcorp/progressia/test/TestContent.java b/src/main/java/ru/windcorp/progressia/test/TestContent.java
index 1b2d16e..3074815 100644
--- a/src/main/java/ru/windcorp/progressia/test/TestContent.java
+++ b/src/main/java/ru/windcorp/progressia/test/TestContent.java
@@ -87,10 +87,6 @@ public class TestContent {
}
private static void registerEntities() {
-// registerEntityData("Test", "Javapony", e -> e.setCollisionModel(new AABB(0, 0, -0.05f, 0.75f, 0.75f, 1.2f)));
-// register(new TestEntityRenderJavapony());
-// register(new EntityLogic("Test", "Javapony"));
-
float scale = 1.8f / 8;
registerEntityData("Test", "Player", e -> e.setCollisionModel(new AABB(0, 0, 4*scale, 0.75f, 0.75f, 1.8f)));
register(new TestEntityRenderHuman());
@@ -121,6 +117,26 @@ public class TestContent {
server.getAdHocChanger().setBlock(z000, block);
}
});
+
+// ControlDataRegistry.getInstance().register(new ControlData("Test", "BreakBlock"));
+// ControlTriggerRegistry.getInstance().register(new ControlTriggerOnKeyPress("Test", "BreakBlock", new KeyMatcher(GLFW.GLFW_KEY_ENTER, new int[0], 0)::matches));
+// ControlLogicRegistry.getInstance().register(new ControlLogic("Test", "BreakBlock") {
+// @Override
+// public void apply(Server server, PacketControl packet, Client client) {
+// Vec3i z000 = new Vec3i(0, 0, 0);
+//
+// ChunkData data = server.getWorld().getChunk(z000).getData();
+//
+// BlockData block;
+// if (data.getBlock(z000).getId().equals("Test:Stone")) {
+// block = BlockDataRegistry.getInstance().get("Test:Glass");
+// } else {
+// block = BlockDataRegistry.getInstance().get("Test:Stone");
+// }
+//
+// server.getAdHocChanger().setBlock(z000, block);
+// }
+// });
}
private static void register(BlockData x) {
diff --git a/src/main/java/ru/windcorp/progressia/test/TestPlayerControls.java b/src/main/java/ru/windcorp/progressia/test/TestPlayerControls.java
index 5ad784b..6282145 100644
--- a/src/main/java/ru/windcorp/progressia/test/TestPlayerControls.java
+++ b/src/main/java/ru/windcorp/progressia/test/TestPlayerControls.java
@@ -13,6 +13,7 @@ import ru.windcorp.progressia.client.graphics.input.CursorMoveEvent;
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.world.LocalPlayer;
import ru.windcorp.progressia.common.Units;
import ru.windcorp.progressia.common.util.FloatMathUtils;
import ru.windcorp.progressia.common.util.Matrices;
@@ -65,7 +66,7 @@ public class TestPlayerControls {
return;
}
- EntityData player = getPlayer();
+ EntityData player = getEntity();
Mat3 angMat = Matrices.grab3();
angMat.identity().rotateZ(player.getYaw());
@@ -185,7 +186,7 @@ public class TestPlayerControls {
}
private void jump() {
- getPlayer().getVelocity().add(0, 0, JUMP_VELOCITY * (useMinecraftGravity ? 2 : 1));
+ getEntity().getVelocity().add(0, 0, JUMP_VELOCITY * (useMinecraftGravity ? 2 : 1));
}
private void handleShift(int multiplier) {
@@ -223,7 +224,7 @@ public class TestPlayerControls {
final float yawScale = -0.002f;
final float pitchScale = yawScale;
- EntityData player = getPlayer();
+ EntityData player = getEntity();
normalizeAngles(player.getDirection().add(
(float) (event.getChangeX() * yawScale),
@@ -241,7 +242,11 @@ public class TestPlayerControls {
);
}
- private EntityData getPlayer() {
+ private EntityData getEntity() {
+ return getPlayer().getEntity();
+ }
+
+ private LocalPlayer getPlayer() {
return ClientState.getInstance().getLocalPlayer();
}