From 0efc8dd18d2517fbd1b682c84d9cbd075345c7b8 Mon Sep 17 00:00:00 2001 From: ScarletRedMan Date: Mon, 7 Apr 2025 22:04:03 +0700 Subject: [PATCH 1/8] feat: quaternion tests --- .../msb3/api/boot/DefaultBootstrap.java | 67 ++++++++++++++++++- .../dragonestia/msb3/api/math/Quaternion.java | 21 +++--- 2 files changed, 77 insertions(+), 11 deletions(-) diff --git a/api/src/main/java/ru/dragonestia/msb3/api/boot/DefaultBootstrap.java b/api/src/main/java/ru/dragonestia/msb3/api/boot/DefaultBootstrap.java index edc547a..e7e806c 100644 --- a/api/src/main/java/ru/dragonestia/msb3/api/boot/DefaultBootstrap.java +++ b/api/src/main/java/ru/dragonestia/msb3/api/boot/DefaultBootstrap.java @@ -1,14 +1,29 @@ package ru.dragonestia.msb3.api.boot; import lombok.extern.log4j.Log4j2; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.NamedTextColor; +import net.minestom.server.coordinate.Pos; +import net.minestom.server.coordinate.Vec; +import net.minestom.server.entity.EntityType; import net.minestom.server.entity.GameMode; +import net.minestom.server.entity.metadata.display.BlockDisplayMeta; +import net.minestom.server.instance.Instance; +import net.minestom.server.instance.block.Block; +import ru.dragonestia.msb3.api.entity.debug.DebugCollider; +import ru.dragonestia.msb3.api.entity.debug.DebugLine; +import ru.dragonestia.msb3.api.entity.debug.DebugMarker; +import ru.dragonestia.msb3.api.entity.debug.DebugRendererEntity; import ru.dragonestia.msb3.api.module.FlatWorldModule; import ru.dragonestia.msb3.api.module.MotdModule; import ru.dragonestia.msb3.api.module.PrometheusMetricsModule; import ru.dragonestia.msb3.api.module.ResourcePackRepositoryModule; +import ru.dragonestia.msb3.api.math.Quaternion; import team.unnamed.creative.ResourcePack; import java.net.InetSocketAddress; +import java.util.List; +import java.util.concurrent.atomic.AtomicInteger; @Log4j2 public class DefaultBootstrap extends ServerInitializer { @@ -20,7 +35,7 @@ public class DefaultBootstrap extends ServerInitializer { @Override public void onDefaultModulesLoaded() { MotdModule.init("logo.png", "msb3 server"); - FlatWorldModule.init(GameMode.ADVENTURE); + FlatWorldModule.init(GameMode.CREATIVE); PrometheusMetricsModule.init(new InetSocketAddress("0.0.0.0", 7500)); } @@ -33,4 +48,54 @@ public class DefaultBootstrap extends ServerInitializer { public void onResourcePackCompiled(ResourcePack resourcePack) { ResourcePackRepositoryModule.init("0.0.0.0", 7270); } + + @Override + public void onServerStarted() { + var instance = FlatWorldModule.getWorld().getInstance(); + + drawLine(instance, new Pos(0, 12, 10), new Pos(5, 16, 20)); + drawLine(instance, new Pos(0, 12, -10), new Pos(5, 16, -20)); + drawLine(instance, new Pos(10, 16, 2), new Pos(5, 12, 3)); + drawLine(instance, new Pos(9, 20, 10), new Pos(-2, 18, 7)); + + var collider = new DebugCollider("test", Block.ORANGE_STAINED_GLASS, new Vec(5, 5, 5), Component.text("Collider")); + collider.setInstance(instance, new Vec(30, 11, 10)); + } + + private static final AtomicInteger I = new AtomicInteger(1); + + private void drawLine(Instance instance, Pos startPos, Pos endPos) { + var id = I.getAndIncrement(); + { + var marker = new DebugMarker("test", Block.RED_CONCRETE, Component.text("[%s] START".formatted(id))); + marker.setInstance(instance, startPos); + } + + { + var marker = new DebugMarker("test", Block.RED_CONCRETE, Component.text("[%s] END".formatted(id))); + marker.setInstance(instance, endPos); + } + + var dist = startPos.distance(endPos); + record LineColor(Block block, Vec rot) {} + for (var rot: List.of( + new LineColor(Block.RED_CONCRETE, new Vec(dist, 0.1, 0.1)), + new LineColor(Block.LIME_CONCRETE, new Vec(0.1, dist, 0.1)), + new LineColor(Block.LIGHT_BLUE_CONCRETE, new Vec(0.1, 0.1, dist)) + )) { + var entity = new DebugRendererEntity(EntityType.BLOCK_DISPLAY, "test"); + var meta = (BlockDisplayMeta) entity.getEntityMeta(); + var normal = endPos.sub(startPos).asVec().normalize(); + meta.setBlockState(rot.block()); + meta.setScale(rot.rot()); + + var quaternion = Quaternion.DEFAULT // В классе кватерниона уже писать логику для его вычисления + .normalize(); + meta.setLeftRotation(quaternion.toFloatArray()); + + entity.setInstance(instance, startPos); + } + var line = new DebugLine("test", startPos, endPos, NamedTextColor.GOLD); + line.setInstance(instance, startPos); + } } diff --git a/api/src/main/java/ru/dragonestia/msb3/api/math/Quaternion.java b/api/src/main/java/ru/dragonestia/msb3/api/math/Quaternion.java index 1f49256..9da251b 100644 --- a/api/src/main/java/ru/dragonestia/msb3/api/math/Quaternion.java +++ b/api/src/main/java/ru/dragonestia/msb3/api/math/Quaternion.java @@ -1,18 +1,19 @@ package ru.dragonestia.msb3.api.math; -import net.minestom.server.coordinate.Vec; +public record Quaternion(double x, double y, double z, double w) { -public record Quaternion(float w, float x, float y, float z) { + public static final Quaternion DEFAULT = new Quaternion(0, 0, 0, 1); - public static Quaternion fromVec(Vec vec, double angle) { - double halfAngle = angle / 2.0; - double sinHalfAngle = Math.sin(halfAngle); + public float[] toFloatArray() { + return new float[] { (float) x, (float) y, (float) z, (float) w }; + } - double qX = vec.x() * sinHalfAngle; - double qY = vec.y() * sinHalfAngle; - double qZ = vec.z() * sinHalfAngle; - double qW = Math.cos(halfAngle); + public double length() { + return Math.sqrt(x * x + y * y + z * z + w * w); + } - return new Quaternion((float) qW, (float) qX, (float) qY, (float) qZ); + public Quaternion normalize() { + var length = length(); + return new Quaternion(x / length, y / length, z / length, w); } } From 4a4ade110a9d91e69c11773a5429b6c26749f844 Mon Sep 17 00:00:00 2001 From: ScarletRedMan Date: Mon, 7 Apr 2025 23:33:12 +0700 Subject: [PATCH 2/8] feat: fixed quaternion normalization --- api/src/main/java/ru/dragonestia/msb3/api/math/Quaternion.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/src/main/java/ru/dragonestia/msb3/api/math/Quaternion.java b/api/src/main/java/ru/dragonestia/msb3/api/math/Quaternion.java index 9da251b..051b905 100644 --- a/api/src/main/java/ru/dragonestia/msb3/api/math/Quaternion.java +++ b/api/src/main/java/ru/dragonestia/msb3/api/math/Quaternion.java @@ -14,6 +14,6 @@ public record Quaternion(double x, double y, double z, double w) { public Quaternion normalize() { var length = length(); - return new Quaternion(x / length, y / length, z / length, w); + return new Quaternion(x / length, y / length, z / length, w / length); } } From 315fe01034bf3b3ef5126df02a92793aaa6f99e2 Mon Sep 17 00:00:00 2001 From: ScarletRedMan Date: Tue, 8 Apr 2025 00:07:57 +0700 Subject: [PATCH 3/8] checkpoint --- .../msb3/api/boot/DefaultBootstrap.java | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/api/src/main/java/ru/dragonestia/msb3/api/boot/DefaultBootstrap.java b/api/src/main/java/ru/dragonestia/msb3/api/boot/DefaultBootstrap.java index e7e806c..97f4af5 100644 --- a/api/src/main/java/ru/dragonestia/msb3/api/boot/DefaultBootstrap.java +++ b/api/src/main/java/ru/dragonestia/msb3/api/boot/DefaultBootstrap.java @@ -89,13 +89,25 @@ public class DefaultBootstrap extends ServerInitializer { meta.setBlockState(rot.block()); meta.setScale(rot.rot()); - var quaternion = Quaternion.DEFAULT // В классе кватерниона уже писать логику для его вычисления - .normalize(); - meta.setLeftRotation(quaternion.toFloatArray()); + var defaultVector = new Vec(0, 1, 0); + + double t = defaultVector.dot(normal) / 2; + + double x = 1 - Math.cos(t); + meta.setLeftRotation(new Quaternion( + normal.x(), + normal.y(), + normal.z(), + n(normal.x()) - n(normal.y()) - n(normal.z()) + ).normalize().toFloatArray()); entity.setInstance(instance, startPos); } var line = new DebugLine("test", startPos, endPos, NamedTextColor.GOLD); line.setInstance(instance, startPos); } + + public static double n(double input) { + return Math.sqrt(1 - input * input); + } } From 1dbbdef1c07e8f46e07a3c31ed43a98c016f1b09 Mon Sep 17 00:00:00 2001 From: ScarletRedMan Date: Tue, 8 Apr 2025 23:16:37 +0700 Subject: [PATCH 4/8] checkpoint --- .../msb3/api/boot/DefaultBootstrap.java | 49 +++++++++---------- .../dragonestia/msb3/api/math/Quaternion.java | 34 +++++++++++++ 2 files changed, 56 insertions(+), 27 deletions(-) diff --git a/api/src/main/java/ru/dragonestia/msb3/api/boot/DefaultBootstrap.java b/api/src/main/java/ru/dragonestia/msb3/api/boot/DefaultBootstrap.java index 97f4af5..4e0326d 100644 --- a/api/src/main/java/ru/dragonestia/msb3/api/boot/DefaultBootstrap.java +++ b/api/src/main/java/ru/dragonestia/msb3/api/boot/DefaultBootstrap.java @@ -3,14 +3,13 @@ package ru.dragonestia.msb3.api.boot; import lombok.extern.log4j.Log4j2; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.format.NamedTextColor; -import net.minestom.server.coordinate.Pos; +import net.minestom.server.coordinate.Point; import net.minestom.server.coordinate.Vec; import net.minestom.server.entity.EntityType; import net.minestom.server.entity.GameMode; import net.minestom.server.entity.metadata.display.BlockDisplayMeta; import net.minestom.server.instance.Instance; import net.minestom.server.instance.block.Block; -import ru.dragonestia.msb3.api.entity.debug.DebugCollider; import ru.dragonestia.msb3.api.entity.debug.DebugLine; import ru.dragonestia.msb3.api.entity.debug.DebugMarker; import ru.dragonestia.msb3.api.entity.debug.DebugRendererEntity; @@ -53,18 +52,28 @@ public class DefaultBootstrap extends ServerInitializer { public void onServerStarted() { var instance = FlatWorldModule.getWorld().getInstance(); - drawLine(instance, new Pos(0, 12, 10), new Pos(5, 16, 20)); - drawLine(instance, new Pos(0, 12, -10), new Pos(5, 16, -20)); - drawLine(instance, new Pos(10, 16, 2), new Pos(5, 12, 3)); - drawLine(instance, new Pos(9, 20, 10), new Pos(-2, 18, 7)); + int radius = 20; + int length = 8; + var center = new Vec(0, 40, 0); + for (int i = -20; i < 40; i++) { + var rad = Math.toRadians(360.0 / 30 * i); + var normal = new Vec(Math.sin(rad), (i - 15.0) / 7, Math.cos(rad)).normalize(); + var startPos = center.add(normal.mul(radius, 1, radius)); + var endPos = startPos.add(normal.mul(length)); + drawLine(instance, startPos, endPos); + } - var collider = new DebugCollider("test", Block.ORANGE_STAINED_GLASS, new Vec(5, 5, 5), Component.text("Collider")); - collider.setInstance(instance, new Vec(30, 11, 10)); + drawLine(instance, new Vec(3, 20, 0), new Vec(3, 60, 0)); + drawLine(instance, new Vec(-3, 60, 0), new Vec(-3, 20, 0)); + drawLine(instance, new Vec(10, 60, 3), new Vec(-10, 60, 3)); + drawLine(instance, new Vec(-10, 60, -3), new Vec(10, 60, -3)); + drawLine(instance, new Vec(0, 57, 10), new Vec(0, 57, -10)); + drawLine(instance, new Vec(0, 53, -10), new Vec(0, 53, 10)); } private static final AtomicInteger I = new AtomicInteger(1); - private void drawLine(Instance instance, Pos startPos, Pos endPos) { + private void drawLine(Instance instance, Point startPos, Point endPos) { var id = I.getAndIncrement(); { var marker = new DebugMarker("test", Block.RED_CONCRETE, Component.text("[%s] START".formatted(id))); @@ -79,35 +88,21 @@ public class DefaultBootstrap extends ServerInitializer { var dist = startPos.distance(endPos); record LineColor(Block block, Vec rot) {} for (var rot: List.of( - new LineColor(Block.RED_CONCRETE, new Vec(dist, 0.1, 0.1)), + new LineColor(Block.RED_CONCRETE, new Vec(3, 0.1, 0.1)), new LineColor(Block.LIME_CONCRETE, new Vec(0.1, dist, 0.1)), - new LineColor(Block.LIGHT_BLUE_CONCRETE, new Vec(0.1, 0.1, dist)) + new LineColor(Block.LIGHT_BLUE_CONCRETE, new Vec(0.1, 0.1, 3)) )) { var entity = new DebugRendererEntity(EntityType.BLOCK_DISPLAY, "test"); var meta = (BlockDisplayMeta) entity.getEntityMeta(); - var normal = endPos.sub(startPos).asVec().normalize(); + var normal = Vec.fromPoint(endPos.sub(startPos)).normalize(); meta.setBlockState(rot.block()); meta.setScale(rot.rot()); - var defaultVector = new Vec(0, 1, 0); - - double t = defaultVector.dot(normal) / 2; - - double x = 1 - Math.cos(t); - meta.setLeftRotation(new Quaternion( - normal.x(), - normal.y(), - normal.z(), - n(normal.x()) - n(normal.y()) - n(normal.z()) - ).normalize().toFloatArray()); + meta.setLeftRotation(Quaternion.DEFAULT.rotate(normal).toFloatArray()); entity.setInstance(instance, startPos); } var line = new DebugLine("test", startPos, endPos, NamedTextColor.GOLD); line.setInstance(instance, startPos); } - - public static double n(double input) { - return Math.sqrt(1 - input * input); - } } diff --git a/api/src/main/java/ru/dragonestia/msb3/api/math/Quaternion.java b/api/src/main/java/ru/dragonestia/msb3/api/math/Quaternion.java index 051b905..3a010d7 100644 --- a/api/src/main/java/ru/dragonestia/msb3/api/math/Quaternion.java +++ b/api/src/main/java/ru/dragonestia/msb3/api/math/Quaternion.java @@ -1,5 +1,7 @@ package ru.dragonestia.msb3.api.math; +import net.minestom.server.coordinate.Vec; + public record Quaternion(double x, double y, double z, double w) { public static final Quaternion DEFAULT = new Quaternion(0, 0, 0, 1); @@ -16,4 +18,36 @@ public record Quaternion(double x, double y, double z, double w) { var length = length(); return new Quaternion(x / length, y / length, z / length, w / length); } + + public Quaternion conjugate() { + return new Quaternion(-x, -y, -z, w); + } + + public Quaternion mul(Quaternion target) { + return new Quaternion( + w() * target.x() + x() * target.w() + y() * target.z() - z() * target.y(), + w() * target.y() - x() * target.z() + y() * target.w() + z() * target.x(), + w() * target.z() + x() * target.y() - y() * target.x() + z() * target.w(), + w() * target.w() - x() * target.x() - y() * target.y() - z() * target.z() + ); + } + + public Quaternion rotate(Vec normal) { + var defaultQuaternion = new Quaternion(0, 0, 0, 1); + + var feta_x = Math.atan(normal.z()/normal.y()); + + var q0 = new Quaternion((Math.sin(feta_x / 2)), 0, 0, (Math.cos(feta_x / 2))); + var q = q0.mul(defaultQuaternion); + var localPos = new Quaternion(0, 1, 0, 0); + var qvq0 = q0.mul(localPos); + var qvq = qvq0.mul(q0.conjugate()); + var q_vector = new Vec(qvq.x(), qvq.y(), qvq.z()).normalize(); + + var multiply = normal.x() > q_vector.x() ? -1 : 1; + var feta_z = Math.acos(q_vector.dot(normal)); + + var q1 = new Quaternion(0, 0, multiply * (Math.sin(feta_z / 2)), (Math.cos(feta_z / 2))); + return q.mul(q1); + } } From 5f3cab0634b03a434e05c25c3bdb4524ef0fbd99 Mon Sep 17 00:00:00 2001 From: ScarletRedMan Date: Sat, 12 Apr 2025 22:46:05 +0700 Subject: [PATCH 5/8] feat: updated rotation --- .../dragonestia/msb3/api/math/Quaternion.java | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 deletions(-) diff --git a/api/src/main/java/ru/dragonestia/msb3/api/math/Quaternion.java b/api/src/main/java/ru/dragonestia/msb3/api/math/Quaternion.java index 3a010d7..bcce778 100644 --- a/api/src/main/java/ru/dragonestia/msb3/api/math/Quaternion.java +++ b/api/src/main/java/ru/dragonestia/msb3/api/math/Quaternion.java @@ -34,20 +34,13 @@ public record Quaternion(double x, double y, double z, double w) { public Quaternion rotate(Vec normal) { var defaultQuaternion = new Quaternion(0, 0, 0, 1); + var defaultVector = new Vec(0, 1, 0); - var feta_x = Math.atan(normal.z()/normal.y()); + var feta = Math.acos(defaultVector.dot(normal)); + var r = defaultVector.cross(normal).normalize(); + var r_sin = r.mul(Math.sin(feta/2)); - var q0 = new Quaternion((Math.sin(feta_x / 2)), 0, 0, (Math.cos(feta_x / 2))); - var q = q0.mul(defaultQuaternion); - var localPos = new Quaternion(0, 1, 0, 0); - var qvq0 = q0.mul(localPos); - var qvq = qvq0.mul(q0.conjugate()); - var q_vector = new Vec(qvq.x(), qvq.y(), qvq.z()).normalize(); - - var multiply = normal.x() > q_vector.x() ? -1 : 1; - var feta_z = Math.acos(q_vector.dot(normal)); - - var q1 = new Quaternion(0, 0, multiply * (Math.sin(feta_z / 2)), (Math.cos(feta_z / 2))); - return q.mul(q1); + var rotation = new Quaternion(r_sin.x(), r_sin.y(), r_sin.z(), Math.cos(feta/2)); + return defaultQuaternion.mul(rotation); } } From bbcba20499e4b4f14e363e55e2e06832b83d198e Mon Sep 17 00:00:00 2001 From: ScarletRedMan Date: Sat, 12 Apr 2025 23:17:44 +0700 Subject: [PATCH 6/8] refactor: refactored entity DebugLine --- .../msb3/api/boot/DefaultBootstrap.java | 30 +------- .../msb3/api/entity/debug/DebugLine.java | 71 ++++++++----------- 2 files changed, 33 insertions(+), 68 deletions(-) diff --git a/api/src/main/java/ru/dragonestia/msb3/api/boot/DefaultBootstrap.java b/api/src/main/java/ru/dragonestia/msb3/api/boot/DefaultBootstrap.java index 4e0326d..935f4f0 100644 --- a/api/src/main/java/ru/dragonestia/msb3/api/boot/DefaultBootstrap.java +++ b/api/src/main/java/ru/dragonestia/msb3/api/boot/DefaultBootstrap.java @@ -2,26 +2,20 @@ package ru.dragonestia.msb3.api.boot; import lombok.extern.log4j.Log4j2; import net.kyori.adventure.text.Component; -import net.kyori.adventure.text.format.NamedTextColor; import net.minestom.server.coordinate.Point; import net.minestom.server.coordinate.Vec; -import net.minestom.server.entity.EntityType; import net.minestom.server.entity.GameMode; -import net.minestom.server.entity.metadata.display.BlockDisplayMeta; import net.minestom.server.instance.Instance; import net.minestom.server.instance.block.Block; import ru.dragonestia.msb3.api.entity.debug.DebugLine; import ru.dragonestia.msb3.api.entity.debug.DebugMarker; -import ru.dragonestia.msb3.api.entity.debug.DebugRendererEntity; import ru.dragonestia.msb3.api.module.FlatWorldModule; import ru.dragonestia.msb3.api.module.MotdModule; import ru.dragonestia.msb3.api.module.PrometheusMetricsModule; import ru.dragonestia.msb3.api.module.ResourcePackRepositoryModule; -import ru.dragonestia.msb3.api.math.Quaternion; import team.unnamed.creative.ResourcePack; import java.net.InetSocketAddress; -import java.util.List; import java.util.concurrent.atomic.AtomicInteger; @Log4j2 @@ -63,8 +57,8 @@ public class DefaultBootstrap extends ServerInitializer { drawLine(instance, startPos, endPos); } - drawLine(instance, new Vec(3, 20, 0), new Vec(3, 60, 0)); - drawLine(instance, new Vec(-3, 60, 0), new Vec(-3, 20, 0)); + drawLine(instance, new Vec(3, 50, 0), new Vec(3, 60, 0)); + drawLine(instance, new Vec(-3, 60, 0), new Vec(-3, 50, 0)); drawLine(instance, new Vec(10, 60, 3), new Vec(-10, 60, 3)); drawLine(instance, new Vec(-10, 60, -3), new Vec(10, 60, -3)); drawLine(instance, new Vec(0, 57, 10), new Vec(0, 57, -10)); @@ -85,24 +79,6 @@ public class DefaultBootstrap extends ServerInitializer { marker.setInstance(instance, endPos); } - var dist = startPos.distance(endPos); - record LineColor(Block block, Vec rot) {} - for (var rot: List.of( - new LineColor(Block.RED_CONCRETE, new Vec(3, 0.1, 0.1)), - new LineColor(Block.LIME_CONCRETE, new Vec(0.1, dist, 0.1)), - new LineColor(Block.LIGHT_BLUE_CONCRETE, new Vec(0.1, 0.1, 3)) - )) { - var entity = new DebugRendererEntity(EntityType.BLOCK_DISPLAY, "test"); - var meta = (BlockDisplayMeta) entity.getEntityMeta(); - var normal = Vec.fromPoint(endPos.sub(startPos)).normalize(); - meta.setBlockState(rot.block()); - meta.setScale(rot.rot()); - - meta.setLeftRotation(Quaternion.DEFAULT.rotate(normal).toFloatArray()); - - entity.setInstance(instance, startPos); - } - var line = new DebugLine("test", startPos, endPos, NamedTextColor.GOLD); - line.setInstance(instance, startPos); + DebugLine.spawn(instance, startPos, endPos, Block.LIME_CONCRETE, "test"); } } diff --git a/api/src/main/java/ru/dragonestia/msb3/api/entity/debug/DebugLine.java b/api/src/main/java/ru/dragonestia/msb3/api/entity/debug/DebugLine.java index 17aa1de..1edf950 100644 --- a/api/src/main/java/ru/dragonestia/msb3/api/entity/debug/DebugLine.java +++ b/api/src/main/java/ru/dragonestia/msb3/api/entity/debug/DebugLine.java @@ -2,63 +2,52 @@ package ru.dragonestia.msb3.api.entity.debug; import lombok.Getter; import lombok.extern.log4j.Log4j2; -import net.kyori.adventure.text.format.TextColor; import net.minestom.server.coordinate.Point; import net.minestom.server.coordinate.Vec; import net.minestom.server.entity.EntityType; -import net.minestom.server.network.packet.server.play.ParticlePacket; -import net.minestom.server.particle.Particle; +import net.minestom.server.entity.metadata.display.BlockDisplayMeta; +import net.minestom.server.instance.Instance; +import net.minestom.server.instance.block.Block; +import ru.dragonestia.msb3.api.math.Quaternion; +@Getter @Log4j2 public class DebugLine extends DebugRendererEntity { - @Getter private Point startPos; - @Getter private Point endPos; - private double dist; - private long lastTick = 0; - private final Particle particle; + private Vec normalWithLength; + private Block block; - public DebugLine(String layerName, Point start, Point end, TextColor color) { - super(EntityType.TEXT_DISPLAY, layerName); - this.startPos = start; - this.endPos = end; - updateDist(); + protected DebugLine(String layerName, Vec normalWithLength, Block block) { + super(EntityType.BLOCK_DISPLAY, layerName); - particle = Particle.DUST.withColor(color).withScale(1); + var meta = getMeta(); + meta.setBrightnessOverride(15); + meta.setBrightness(15, 15); + + updateNormalWithLength(normalWithLength); + updateBlock(block); } - @Override - public void tick(long time) { - super.tick(time); - - if (time - lastTick < 500) return; - lastTick = time; - - if (getViewers().isEmpty()) return; - - double currentDist = 0; - while ((currentDist += 0.7) < dist) { - var pos = Vec.fromPoint(endPos.sub(startPos)) - .normalize() - .mul(currentDist) - .add(startPos); - - var pk = new ParticlePacket(particle, pos.x(), pos.y(), pos.z(), 0, 0, 0, 0, 1); - getViewers().forEach(player -> player.sendPacket(pk)); - } + public void updateNormalWithLength(Vec newValue) { + normalWithLength = newValue; + var meta = getMeta(); + meta.setScale(new Vec(0.1, normalWithLength.length(), 0.1)); + meta.setLeftRotation(Quaternion.DEFAULT + .rotate(newValue.normalize()) + .toFloatArray()); } - private void updateDist() { - dist = endPos.distance(startPos); + public void updateBlock(Block block) { + getMeta().setBlockState(this.block = block); } - public void setStartPos(Point startPos) { - this.startPos = startPos; - updateDist(); + private BlockDisplayMeta getMeta() { + return (BlockDisplayMeta) getEntityMeta(); } - public void setEndPos(Point endPos) { - this.endPos = endPos; - updateDist(); + public static DebugLine spawn(Instance instance, Point start, Point end, Block block, String layerName) { + var entity = new DebugLine(layerName, Vec.fromPoint(end.sub(start)), block); + entity.setInstance(instance, start); + return entity; } } From 7a0e18b9a02a832057fd41e5dfd38ac5317bc755 Mon Sep 17 00:00:00 2001 From: Helios Pe Date: Sat, 12 Apr 2025 19:02:33 +0200 Subject: [PATCH 7/8] fix: quaternion rotation and implemented more operations --- .../msb3/api/boot/DefaultBootstrap.java | 15 ++++---- .../dragonestia/msb3/api/math/Quaternion.java | 36 ++++++++++++++++--- 2 files changed, 41 insertions(+), 10 deletions(-) diff --git a/api/src/main/java/ru/dragonestia/msb3/api/boot/DefaultBootstrap.java b/api/src/main/java/ru/dragonestia/msb3/api/boot/DefaultBootstrap.java index 4e0326d..7f0eff0 100644 --- a/api/src/main/java/ru/dragonestia/msb3/api/boot/DefaultBootstrap.java +++ b/api/src/main/java/ru/dragonestia/msb3/api/boot/DefaultBootstrap.java @@ -3,13 +3,13 @@ package ru.dragonestia.msb3.api.boot; import lombok.extern.log4j.Log4j2; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.format.NamedTextColor; -import net.minestom.server.coordinate.Point; import net.minestom.server.coordinate.Vec; import net.minestom.server.entity.EntityType; import net.minestom.server.entity.GameMode; import net.minestom.server.entity.metadata.display.BlockDisplayMeta; import net.minestom.server.instance.Instance; import net.minestom.server.instance.block.Block; +import ru.dragonestia.msb3.api.entity.debug.DebugCollider; import ru.dragonestia.msb3.api.entity.debug.DebugLine; import ru.dragonestia.msb3.api.entity.debug.DebugMarker; import ru.dragonestia.msb3.api.entity.debug.DebugRendererEntity; @@ -69,11 +69,14 @@ public class DefaultBootstrap extends ServerInitializer { drawLine(instance, new Vec(-10, 60, -3), new Vec(10, 60, -3)); drawLine(instance, new Vec(0, 57, 10), new Vec(0, 57, -10)); drawLine(instance, new Vec(0, 53, -10), new Vec(0, 53, 10)); + + var collider = new DebugCollider("test", Block.ORANGE_STAINED_GLASS, new Vec(5, 5, 5), Component.text("Collider")); + collider.setInstance(instance, new Vec(30, 11, 10)); } private static final AtomicInteger I = new AtomicInteger(1); - private void drawLine(Instance instance, Point startPos, Point endPos) { + private void drawLine(Instance instance, Vec startPos, Vec endPos) { var id = I.getAndIncrement(); { var marker = new DebugMarker("test", Block.RED_CONCRETE, Component.text("[%s] START".formatted(id))); @@ -88,17 +91,17 @@ public class DefaultBootstrap extends ServerInitializer { var dist = startPos.distance(endPos); record LineColor(Block block, Vec rot) {} for (var rot: List.of( - new LineColor(Block.RED_CONCRETE, new Vec(3, 0.1, 0.1)), + new LineColor(Block.RED_CONCRETE, new Vec(dist, 0.1, 0.1)), new LineColor(Block.LIME_CONCRETE, new Vec(0.1, dist, 0.1)), - new LineColor(Block.LIGHT_BLUE_CONCRETE, new Vec(0.1, 0.1, 3)) + new LineColor(Block.LIGHT_BLUE_CONCRETE, new Vec(0.1, 0.1, dist)) )) { var entity = new DebugRendererEntity(EntityType.BLOCK_DISPLAY, "test"); var meta = (BlockDisplayMeta) entity.getEntityMeta(); - var normal = Vec.fromPoint(endPos.sub(startPos)).normalize(); + var normal = endPos.sub(startPos).normalize(); meta.setBlockState(rot.block()); meta.setScale(rot.rot()); - meta.setLeftRotation(Quaternion.DEFAULT.rotate(normal).toFloatArray()); + meta.setLeftRotation(Quaternion.DEFAULT.rotate(normal).normalize().toFloatArray()); entity.setInstance(instance, startPos); } diff --git a/api/src/main/java/ru/dragonestia/msb3/api/math/Quaternion.java b/api/src/main/java/ru/dragonestia/msb3/api/math/Quaternion.java index bcce778..16df674 100644 --- a/api/src/main/java/ru/dragonestia/msb3/api/math/Quaternion.java +++ b/api/src/main/java/ru/dragonestia/msb3/api/math/Quaternion.java @@ -6,6 +6,10 @@ public record Quaternion(double x, double y, double z, double w) { public static final Quaternion DEFAULT = new Quaternion(0, 0, 0, 1); + public static Quaternion fromVec (Vec vec, double realPart) { + return new Quaternion(vec.x(), vec.y(), vec.z(), realPart); + } + public float[] toFloatArray() { return new float[] { (float) x, (float) y, (float) z, (float) w }; } @@ -23,6 +27,11 @@ public record Quaternion(double x, double y, double z, double w) { return new Quaternion(-x, -y, -z, w); } + public double dotProduct(Quaternion target) { + return (x * target.x + y * target.y + z * target.z + w * target.w + ); + } + public Quaternion mul(Quaternion target) { return new Quaternion( w() * target.x() + x() * target.w() + y() * target.z() - z() * target.y(), @@ -32,15 +41,34 @@ public record Quaternion(double x, double y, double z, double w) { ); } + public Quaternion add(Quaternion target) { + return new Quaternion( + x + target.x, + y + target.y, + z + target.z, + w + target.w + ); + } + + public Quaternion sub(Quaternion target) { + return new Quaternion( + x - target.x, + y - target.y, + z - target.z, + w - target.w + ); + } + public Quaternion rotate(Vec normal) { var defaultQuaternion = new Quaternion(0, 0, 0, 1); var defaultVector = new Vec(0, 1, 0); var feta = Math.acos(defaultVector.dot(normal)); - var r = defaultVector.cross(normal).normalize(); - var r_sin = r.mul(Math.sin(feta/2)); - - var rotation = new Quaternion(r_sin.x(), r_sin.y(), r_sin.z(), Math.cos(feta/2)); + var r = defaultVector.cross(normal); + if (r.isZero()){ + r = new Vec(0, 0, 1); + } + var rotation = fromVec(r.normalize().mul(Math.sin(feta / 2)), Math.cos(feta / 2)); return defaultQuaternion.mul(rotation); } } From 35b6644dd082ae46e43ca51d19a6c5aff9500496 Mon Sep 17 00:00:00 2001 From: ScarletRedMan Date: Sun, 13 Apr 2025 00:03:20 +0700 Subject: [PATCH 8/8] feat: implemented Graph --- .../ru/dragonestia/msb3/api/debug/Graph.java | 129 ++++++++++++++++++ 1 file changed, 129 insertions(+) create mode 100644 api/src/main/java/ru/dragonestia/msb3/api/debug/Graph.java diff --git a/api/src/main/java/ru/dragonestia/msb3/api/debug/Graph.java b/api/src/main/java/ru/dragonestia/msb3/api/debug/Graph.java new file mode 100644 index 0000000..531cc6b --- /dev/null +++ b/api/src/main/java/ru/dragonestia/msb3/api/debug/Graph.java @@ -0,0 +1,129 @@ +package ru.dragonestia.msb3.api.debug; + +import lombok.Getter; +import lombok.RequiredArgsConstructor; +import net.minestom.server.coordinate.Vec; + +import java.util.*; +import java.util.concurrent.atomic.AtomicInteger; + +public class Graph { + + private final static AtomicInteger freeId = new AtomicInteger(1); + + private final Map nodes = new HashMap<>(); + + public Node addNode(Vec pos) { + var node = new Node(pos); + nodes.put(node.getId(), node); + return node; + } + + public boolean addNodeLink(Node from, Node to) { + return from.addLink(to) && to.addLink(from); + } + + public void removeLink(Node from, Node to) { + from.removeLink(to); + to.removeLink(from); + } + + public void removeNode(Node node) { + nodes.remove(node.getId()); + node.getLinks().forEach(other -> removeLink(other, node)); + } + + public Collection getNodes() { + return nodes.values(); + } + + public Optional findNode(int id) { + return Optional.ofNullable(nodes.get(id)); + } + + public SerializedGraph serialize() { + var nodes = new ArrayList(); + var links = new HashSet(); + + for (var node: getNodes()) { + nodes.add(new SerializedNode(node.id, node.position.x(), node.position.y(), node.position.z())); + + for (var otherNode: node.getLinks()) { + if (links.contains(new IntPair(otherNode.getId(), node.getId()))) continue; + links.add(new IntPair(node.getId(), otherNode.getId())); + } + } + return new SerializedGraph(nodes, links); + } + + public static Graph deserialize(SerializedGraph serializedGraph) { + var graph = new Graph(); + for (var node: serializedGraph.nodes) { + graph.addNode(new Vec(node.x(), node.y(), node.z())); + } + for (var link: serializedGraph.links) { + graph.addNodeLink(graph.findNode(link.a).orElseThrow(), graph.findNode(link.b).orElseThrow()); + } + return graph; + } + + @RequiredArgsConstructor + public static class Node { + + @Getter private final int id = freeId.getAndIncrement(); + @Getter private final Vec position; + private final Map links = new HashMap<>(); + + private boolean addLink(Node node) { + if (id == node.getId()) return false; + return links.put(node, position.distance(node.position)) == null; + } + + private void removeLink(Node node) { + links.remove(node); + node.links.remove(this); + } + + public boolean hasLink(Node node) { + if (id == node.getId()) return true; + return links.containsKey(node); + } + + public Set getLinks() { + return links.keySet(); + } + + public Collection getLinksWithDistance() { + return links.entrySet().stream() + .map(entry -> new DistancePair(entry.getKey(), entry.getValue())) + .toList(); + } + + public double getDistanceTo(Node node) { + return links.getOrDefault(node, Double.NaN); + } + + @Override + public int hashCode() { + return id; + } + + @Override + public boolean equals(Object obj) { + if (obj == this) return true; + if (obj == null) return false; + if (obj instanceof Node other) { + return id == other.id; + } + return false; + } + } + + public record SerializedGraph(List nodes, Set links) {} + + public record SerializedNode(int id, double x, double y, double z) {} + + public record IntPair(int a, int b) {} + + public record DistancePair(Node node, double distance) {} +}