Merge pull request 'Implemented debug line renderer' (#2) from feat/quaternion into feat/debug-render
Reviewed-on: http://git.dragonestia.ru/MSB/msb3/pulls/2
This commit is contained in:
commit
6a8fbfc06a
@ -1,7 +1,14 @@
|
|||||||
package ru.dragonestia.msb3.api.boot;
|
package ru.dragonestia.msb3.api.boot;
|
||||||
|
|
||||||
import lombok.extern.log4j.Log4j2;
|
import lombok.extern.log4j.Log4j2;
|
||||||
|
import net.kyori.adventure.text.Component;
|
||||||
|
import net.minestom.server.coordinate.Point;
|
||||||
|
import net.minestom.server.coordinate.Vec;
|
||||||
import net.minestom.server.entity.GameMode;
|
import net.minestom.server.entity.GameMode;
|
||||||
|
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.module.FlatWorldModule;
|
import ru.dragonestia.msb3.api.module.FlatWorldModule;
|
||||||
import ru.dragonestia.msb3.api.module.MotdModule;
|
import ru.dragonestia.msb3.api.module.MotdModule;
|
||||||
import ru.dragonestia.msb3.api.module.PrometheusMetricsModule;
|
import ru.dragonestia.msb3.api.module.PrometheusMetricsModule;
|
||||||
@ -9,6 +16,7 @@ import ru.dragonestia.msb3.api.module.ResourcePackRepositoryModule;
|
|||||||
import team.unnamed.creative.ResourcePack;
|
import team.unnamed.creative.ResourcePack;
|
||||||
|
|
||||||
import java.net.InetSocketAddress;
|
import java.net.InetSocketAddress;
|
||||||
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
|
||||||
@Log4j2
|
@Log4j2
|
||||||
public class DefaultBootstrap extends ServerInitializer {
|
public class DefaultBootstrap extends ServerInitializer {
|
||||||
@ -20,7 +28,7 @@ public class DefaultBootstrap extends ServerInitializer {
|
|||||||
@Override
|
@Override
|
||||||
public void onDefaultModulesLoaded() {
|
public void onDefaultModulesLoaded() {
|
||||||
MotdModule.init("logo.png", "<gradient:#ff0059:#e06806><bold>msb3 server</bold></gradient>");
|
MotdModule.init("logo.png", "<gradient:#ff0059:#e06806><bold>msb3 server</bold></gradient>");
|
||||||
FlatWorldModule.init(GameMode.ADVENTURE);
|
FlatWorldModule.init(GameMode.CREATIVE);
|
||||||
PrometheusMetricsModule.init(new InetSocketAddress("0.0.0.0", 7500));
|
PrometheusMetricsModule.init(new InetSocketAddress("0.0.0.0", 7500));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -33,4 +41,44 @@ public class DefaultBootstrap extends ServerInitializer {
|
|||||||
public void onResourcePackCompiled(ResourcePack resourcePack) {
|
public void onResourcePackCompiled(ResourcePack resourcePack) {
|
||||||
ResourcePackRepositoryModule.init("0.0.0.0", 7270);
|
ResourcePackRepositoryModule.init("0.0.0.0", 7270);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onServerStarted() {
|
||||||
|
var instance = FlatWorldModule.getWorld().getInstance();
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
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));
|
||||||
|
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, Point startPos, Point 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
DebugLine.spawn(instance, startPos, endPos, Block.LIME_CONCRETE, "test");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
129
api/src/main/java/ru/dragonestia/msb3/api/debug/Graph.java
Normal file
129
api/src/main/java/ru/dragonestia/msb3/api/debug/Graph.java
Normal file
@ -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<Integer, Node> 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<Node> getNodes() {
|
||||||
|
return nodes.values();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Optional<Node> findNode(int id) {
|
||||||
|
return Optional.ofNullable(nodes.get(id));
|
||||||
|
}
|
||||||
|
|
||||||
|
public SerializedGraph serialize() {
|
||||||
|
var nodes = new ArrayList<SerializedNode>();
|
||||||
|
var links = new HashSet<IntPair>();
|
||||||
|
|
||||||
|
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<Node, Double> 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<Node> getLinks() {
|
||||||
|
return links.keySet();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Collection<DistancePair> 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<SerializedNode> nodes, Set<IntPair> 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) {}
|
||||||
|
}
|
||||||
@ -2,63 +2,52 @@ package ru.dragonestia.msb3.api.entity.debug;
|
|||||||
|
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.extern.log4j.Log4j2;
|
import lombok.extern.log4j.Log4j2;
|
||||||
import net.kyori.adventure.text.format.TextColor;
|
|
||||||
import net.minestom.server.coordinate.Point;
|
import net.minestom.server.coordinate.Point;
|
||||||
import net.minestom.server.coordinate.Vec;
|
import net.minestom.server.coordinate.Vec;
|
||||||
import net.minestom.server.entity.EntityType;
|
import net.minestom.server.entity.EntityType;
|
||||||
import net.minestom.server.network.packet.server.play.ParticlePacket;
|
import net.minestom.server.entity.metadata.display.BlockDisplayMeta;
|
||||||
import net.minestom.server.particle.Particle;
|
import net.minestom.server.instance.Instance;
|
||||||
|
import net.minestom.server.instance.block.Block;
|
||||||
|
import ru.dragonestia.msb3.api.math.Quaternion;
|
||||||
|
|
||||||
|
@Getter
|
||||||
@Log4j2
|
@Log4j2
|
||||||
public class DebugLine extends DebugRendererEntity {
|
public class DebugLine extends DebugRendererEntity {
|
||||||
|
|
||||||
@Getter private Point startPos;
|
private Vec normalWithLength;
|
||||||
@Getter private Point endPos;
|
private Block block;
|
||||||
private double dist;
|
|
||||||
private long lastTick = 0;
|
|
||||||
private final Particle particle;
|
|
||||||
|
|
||||||
public DebugLine(String layerName, Point start, Point end, TextColor color) {
|
protected DebugLine(String layerName, Vec normalWithLength, Block block) {
|
||||||
super(EntityType.TEXT_DISPLAY, layerName);
|
super(EntityType.BLOCK_DISPLAY, layerName);
|
||||||
this.startPos = start;
|
|
||||||
this.endPos = end;
|
|
||||||
updateDist();
|
|
||||||
|
|
||||||
particle = Particle.DUST.withColor(color).withScale(1);
|
var meta = getMeta();
|
||||||
|
meta.setBrightnessOverride(15);
|
||||||
|
meta.setBrightness(15, 15);
|
||||||
|
|
||||||
|
updateNormalWithLength(normalWithLength);
|
||||||
|
updateBlock(block);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
public void updateNormalWithLength(Vec newValue) {
|
||||||
public void tick(long time) {
|
normalWithLength = newValue;
|
||||||
super.tick(time);
|
var meta = getMeta();
|
||||||
|
meta.setScale(new Vec(0.1, normalWithLength.length(), 0.1));
|
||||||
if (time - lastTick < 500) return;
|
meta.setLeftRotation(Quaternion.DEFAULT
|
||||||
lastTick = time;
|
.rotate(newValue.normalize())
|
||||||
|
.toFloatArray());
|
||||||
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));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateDist() {
|
public void updateBlock(Block block) {
|
||||||
dist = endPos.distance(startPos);
|
getMeta().setBlockState(this.block = block);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setStartPos(Point startPos) {
|
private BlockDisplayMeta getMeta() {
|
||||||
this.startPos = startPos;
|
return (BlockDisplayMeta) getEntityMeta();
|
||||||
updateDist();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setEndPos(Point endPos) {
|
public static DebugLine spawn(Instance instance, Point start, Point end, Block block, String layerName) {
|
||||||
this.endPos = endPos;
|
var entity = new DebugLine(layerName, Vec.fromPoint(end.sub(start)), block);
|
||||||
updateDist();
|
entity.setInstance(instance, start);
|
||||||
|
return entity;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,17 +2,73 @@ package ru.dragonestia.msb3.api.math;
|
|||||||
|
|
||||||
import net.minestom.server.coordinate.Vec;
|
import net.minestom.server.coordinate.Vec;
|
||||||
|
|
||||||
public record Quaternion(float w, float x, float y, float z) {
|
public record Quaternion(double x, double y, double z, double w) {
|
||||||
|
|
||||||
public static Quaternion fromVec(Vec vec, double angle) {
|
public static final Quaternion DEFAULT = new Quaternion(0, 0, 0, 1);
|
||||||
double halfAngle = angle / 2.0;
|
|
||||||
double sinHalfAngle = Math.sin(halfAngle);
|
|
||||||
|
|
||||||
double qX = vec.x() * sinHalfAngle;
|
public static Quaternion fromVec (Vec vec, double realPart) {
|
||||||
double qY = vec.y() * sinHalfAngle;
|
return new Quaternion(vec.x(), vec.y(), vec.z(), realPart);
|
||||||
double qZ = vec.z() * sinHalfAngle;
|
}
|
||||||
double qW = Math.cos(halfAngle);
|
|
||||||
|
|
||||||
return new Quaternion((float) qW, (float) qX, (float) qY, (float) qZ);
|
public float[] toFloatArray() {
|
||||||
|
return new float[] { (float) x, (float) y, (float) z, (float) w };
|
||||||
|
}
|
||||||
|
|
||||||
|
public double length() {
|
||||||
|
return Math.sqrt(x * x + y * y + z * z + w * w);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Quaternion normalize() {
|
||||||
|
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 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(),
|
||||||
|
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 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);
|
||||||
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user