From 75021b3360d21dd1edcdc490a185322084d91190 Mon Sep 17 00:00:00 2001 From: minco Date: Wed, 13 Aug 2025 23:52:32 +0900 Subject: [PATCH 1/2] renderer update --- gradle.properties | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/gradle.properties b/gradle.properties index 0962040..09c94f4 100644 --- a/gradle.properties +++ b/gradle.properties @@ -8,10 +8,18 @@ maven_group=org.walruslab archives_base_name=kepler # Dependencies # check this on https://modmuss50.me/fabric.html -minecraft_version=1.21.7 -yarn_mappings=1.21.7+build.8 -loader_version=0.16.14 +#minecraft_version=1.21.7 +#yarn_mappings=1.21.7+build.8 +#loader_version=0.16.14 +#loom_version=1.11-SNAPSHOT +# +## Fabric API +#fabric_version=0.129.0+1.21.7 + +minecraft_version=1.21.8 +yarn_mappings=1.21.8+build.1 +loader_version=0.17.2 loom_version=1.11-SNAPSHOT # Fabric API -fabric_version=0.129.0+1.21.7 \ No newline at end of file +fabric_version=0.131.0+1.21.8 \ No newline at end of file -- 2.49.1 From 4652f58415a039f9e4c423c29668829ab255e2eb Mon Sep 17 00:00:00 2001 From: minco Date: Mon, 18 Aug 2025 14:19:28 +0900 Subject: [PATCH 2/2] 1.21.8 --- .../walruslab/kepler/client/KeplerClient.java | 3 +- .../render/ParallelTrajectoryManager.java | 56 ++++++ .../kepler/render/TrajectoryRenderer.java | 190 ++++++++---------- .../kepler/trajectory/Trajectory.java | 16 +- .../kepler/trajectory/TrajectoryHit.java | 3 +- .../kepler/trajectory/item/ShootableBow.java | 14 ++ .../trajectory/item/ShootableCrossbow.java | 14 ++ .../kepler/trajectory/item/ShootableItem.java | 8 + .../trajectory/item/ShootableItemFactory.java | 15 ++ 9 files changed, 197 insertions(+), 122 deletions(-) create mode 100644 src/main/java/org/walruslab/kepler/render/ParallelTrajectoryManager.java create mode 100644 src/main/java/org/walruslab/kepler/trajectory/item/ShootableBow.java create mode 100644 src/main/java/org/walruslab/kepler/trajectory/item/ShootableCrossbow.java create mode 100644 src/main/java/org/walruslab/kepler/trajectory/item/ShootableItem.java create mode 100644 src/main/java/org/walruslab/kepler/trajectory/item/ShootableItemFactory.java diff --git a/src/main/java/org/walruslab/kepler/client/KeplerClient.java b/src/main/java/org/walruslab/kepler/client/KeplerClient.java index da3605b..a2764b4 100644 --- a/src/main/java/org/walruslab/kepler/client/KeplerClient.java +++ b/src/main/java/org/walruslab/kepler/client/KeplerClient.java @@ -10,8 +10,9 @@ public class KeplerClient implements ClientModInitializer { @Override public void onInitializeClient() { + var renderer = new TrajectoryRenderer(); ClientEntityEvents.ENTITY_LOAD.register((entity, _a) -> { - if (entity instanceof PlayerEntity) TrajectoryRenderer.setupRenderLine((PlayerEntity) entity); + if (entity instanceof PlayerEntity) renderer.setupRenderLine((PlayerEntity) entity); }); } } diff --git a/src/main/java/org/walruslab/kepler/render/ParallelTrajectoryManager.java b/src/main/java/org/walruslab/kepler/render/ParallelTrajectoryManager.java new file mode 100644 index 0000000..9867a34 --- /dev/null +++ b/src/main/java/org/walruslab/kepler/render/ParallelTrajectoryManager.java @@ -0,0 +1,56 @@ +package org.walruslab.kepler.render; + +import net.minecraft.entity.projectile.ArrowEntity; +import org.jetbrains.annotations.Nullable; +import org.walruslab.kepler.trajectory.Trajectory; +import org.walruslab.kepler.trajectory.TrajectoryHit; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.atomic.AtomicInteger; + +public class ParallelTrajectoryManager { + private boolean isDataAvailable = false; + private List lastHits; + + public void calculateTrajectories(List arrows) { + if (!isDataAvailable) { + AtomicInteger i = new AtomicInteger(); + lastHits = new ArrayList<>(); + for (var arrow : arrows) { + var t = new Thread(() -> { + var hit = calculateArrow(arrow); + if (hit != null) { + lastHits.add(hit); + } + i.addAndGet(1); + + if (arrows.size() == i.get()) { + isDataAvailable = true; + } + }); + t.start(); + } + } + } + + public List getLastHits() { + if (isDataAvailable) { + isDataAvailable = false; + return lastHits; + } else return null; + } + + private @Nullable TrajectoryHit calculateArrow(ArrowEntity arrow) { + if (arrow.groundCollision) return null; + + var pos = arrow.getPos(); + var velocity = arrow.getVelocity(); + + var tr = new Trajectory(pos.toVector3f(), velocity.toVector3f()); + var hit = tr.getTrajectoryPoints(arrow.getWorld(), 0.1f, arrow.getOwner()); + + return hit; + } + +} diff --git a/src/main/java/org/walruslab/kepler/render/TrajectoryRenderer.java b/src/main/java/org/walruslab/kepler/render/TrajectoryRenderer.java index d7180ff..6fdde33 100644 --- a/src/main/java/org/walruslab/kepler/render/TrajectoryRenderer.java +++ b/src/main/java/org/walruslab/kepler/render/TrajectoryRenderer.java @@ -1,149 +1,125 @@ package org.walruslab.kepler.render; import com.mojang.blaze3d.opengl.GlStateManager; -import com.mojang.blaze3d.systems.RenderSystem; import com.mojang.blaze3d.vertex.VertexFormat; -import net.fabricmc.fabric.api.client.rendering.v1.HudRenderCallback; import net.fabricmc.fabric.api.client.rendering.v1.WorldRenderContext; import net.fabricmc.fabric.api.client.rendering.v1.WorldRenderEvents; -import net.jpountz.util.Utils; import net.minecraft.client.MinecraftClient; import net.minecraft.client.render.RenderLayer; import net.minecraft.client.render.Tessellator; import net.minecraft.client.render.VertexFormats; +import net.minecraft.entity.LivingEntity; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.projectile.ArrowEntity; import net.minecraft.item.BowItem; import net.minecraft.item.Items; -import net.minecraft.predicate.entity.EntityPredicate; import net.minecraft.predicate.entity.EntityPredicates; import net.minecraft.text.Text; import net.minecraft.util.TypeFilter; -import net.minecraft.util.Util; import net.minecraft.util.math.Box; import net.minecraft.util.math.Vec3d; import net.minecraft.util.math.Vec3i; -import org.joml.Vector3d; import org.joml.Vector3f; import org.lwjgl.opengl.GL11; -import org.walruslab.kepler.trajectory.Trajectory; +import org.walruslab.kepler.trajectory.TrajectoryHit; +import org.walruslab.kepler.trajectory.item.ShootableItemFactory; import java.util.List; -import java.util.function.Predicate; public class TrajectoryRenderer { - public static void setupRenderLine(PlayerEntity player) { + private final ParallelTrajectoryManager trajectoryManager = new ParallelTrajectoryManager(); + + public void setupRenderLine(PlayerEntity player) { player.sendMessage(Text.of("Kepler: TrajectoryRenderer setupRenderLine"), false); WorldRenderEvents.END.register((drawContext) -> { - // get all error entity in player world var world = player.getWorld(); + + var entities = world.getEntitiesByClass(LivingEntity.class, new Box(player.getPos().subtract(Vec3d.of(new Vec3i(100, 100, 100))), player.getPos().add(Vec3d.of(new Vec3i(100, 100, 100)))), EntityPredicates.VALID_ENTITY); var arrows = world.getEntitiesByType(TypeFilter.instanceOf(ArrowEntity.class), new Box(player.getPos().subtract(Vec3d.of(new Vec3i(100, 100, 100))), player.getPos().add(Vec3d.of(new Vec3i(100, 100, 100)))), EntityPredicates.VALID_ENTITY); - for (ArrowEntity arrow : arrows) { - if (arrow.groundCollision) return; + trajectoryManager.calculateTrajectories(arrows); - var pos = arrow.getPos(); - var velocity = arrow.getVelocity(); - - var tr = new Trajectory(pos.toVector3f(), velocity.toVector3f()); - var hit = tr.getTrajectoryPoints(world, 0.1f, player); - var points = hit.points(); - - if (points.size() < 2) { - continue; // Skip if not enough points - } - - // Render the trajectory line - if (hit.hitEntity()) { - renderLine(drawContext, points, 0.0f, 1.0f, 0.0f); // Red for hit - } else { - renderLine(drawContext, points, 1.0f, 0.0f, 1.0f); // Green for no hit + var hits = trajectoryManager.getLastHits(); + if (hits != null) { + for (var hit : hits) { + if (hit != null) + renderForArrow(hit, drawContext); } } - var livingEntities = world.getOtherEntities(player, new Box(player.getPos().subtract(Vec3d.of(new Vec3i(100, 100, 100))), player.getPos().add(Vec3d.of(new Vec3i(100, 100, 100)))), EntityPredicates.VALID_ENTITY); - for (var entity : livingEntities) { - if (entity instanceof ArrowEntity) continue; - - var pos = entity.getPos(); - var velocity = entity.getVelocity(); - - if (velocity.length() < 0.1) continue; // Skip if velocity is too low - - var predictedPos = new Vector3f( - (float) (entity.getX() + velocity.x * 20), - (float) (entity.getY() + velocity.y * 20), - (float) (entity.getZ() + velocity.z * 20) - ); - - var points = List.of( - new Vector3f((float) pos.x, (float) pos.y, (float) pos.z), - predictedPos - ); - - // Render the trajectory line - renderLine(drawContext, points, 0.0f, 0.0f, 1.0f); // Blue for entity - } - - // check player is shooting bow - var activeItem = player.getMainHandStack(); - if (activeItem != null && (activeItem.isOf(Items.BOW) || activeItem.isOf(Items.CROSSBOW))) { - float speed; - if (activeItem.isOf(Items.BOW)) { - var item = (BowItem) activeItem.getItem(); - var f = BowItem.getPullProgress(player.getItemUseTime()); - speed = f * 3.0f; - } else { - speed = 3.15f; - } - - var dirDouble = player.getRotationVec(1.0f); - - var dir = new Vector3f( - (float) dirDouble.x, - (float) dirDouble.y, - (float) dirDouble.z - ).normalize(); - - var pos = player.getEyePos(); - var playerVelocity = player.getVelocity(); - - var velocity = new Vector3f( - (float) (dir.x * speed + playerVelocity.x), - (float) (dir.y * speed + playerVelocity.y), - (float) (dir.z * speed + playerVelocity.z) - ); - - var tr = new Trajectory(pos.toVector3f(), velocity); - var hit = tr.getTrajectoryPoints(world, 0.1f, player); - - var points = hit.points(); - - if (points.size() >= 2) { - var playerRight = dir.cross(new Vector3f(0, 1, 0)).normalize(); - // move points to the right, closest point -> move 1, farthest point -> move 0, linear - for (int i = 0; i < points.size(); i++) { - var point = points.get(i); - var rightOffset = 0.05; - var dx = (float) (point.x + playerRight.x * rightOffset * (1 - ((float) i / points.size()))); - var dy = (float) (point.y + playerRight.y * rightOffset * (1 - ((float) i / points.size()))); - var dz = (float) (point.z + playerRight.z * rightOffset * (1 - ((float) i / points.size()))); - - points.set(i, new Vector3f(dx, dy, dz)); - } - - // Render the trajectory line - if (hit.hitEntity()) { - renderLine(drawContext, points, 0.0f, 1.0f, 0.0f); // Red for hit - } else { - renderLine(drawContext, points, 1.0f, 0.0f, 1.0f); // Green for no hit - } + for (LivingEntity entity : entities) { + var activeItem = entity.getMainHandStack(); + if (activeItem != null && (activeItem.isOf(Items.BOW) || activeItem.isOf(Items.CROSSBOW))) { + renderForPlayer(entity, drawContext); } } }); } - private static void renderLine(WorldRenderContext drawContext, List points, float r, float g, float b) { + private void renderForArrow(TrajectoryHit hit, WorldRenderContext drawContext) { + var points = hit.points(); + + if (points.size() >= 2) { + if (hit.hitEntity() != null) { + renderLine(drawContext, points, 0.0f, 1.0f, 0.0f); // Red for hit + } else { + renderLine(drawContext, points, 1.0f, 0.0f, 1.0f); // Green for no hit + } + } + } + + private void renderForPlayer(LivingEntity player, WorldRenderContext drawContext) { + // get all error entity in player world + var world = player.getWorld(); + + var activeItem = player.getMainHandStack(); + float progress = 1.0f; + if (activeItem.isOf(Items.BOW)) { + progress = BowItem.getPullProgress(player.getItemUseTime()); + } + + var dirDouble = player.getRotationVec(1.0f); + + var dir = new Vector3f( + (float) dirDouble.x, + (float) dirDouble.y, + (float) dirDouble.z + ).normalize(); + + var pos = player.getEyePos(); + var playerVelocity = player.getVelocity(); + + var item = ShootableItemFactory.create(activeItem); + if (item != null) { + var tr = item.makeTrajectory(pos.toVector3f(), dir, playerVelocity.toVector3f(), progress); + var hit = tr.getTrajectoryPoints(world, 0.1f, player); + + var points = hit.points(); + + if (points.size() >= 2) { + var playerRight = dir.cross(new Vector3f(0, 1, 0)).normalize(); + // move points to the right, closest point -> move 1, farthest point -> move 0, linear + for (int i = 0; i < points.size(); i++) { + var point = points.get(i); + var rightOffset = 0.05; + var dx = (float) (point.x + playerRight.x * rightOffset * (1 - ((float) i / points.size()))); + var dy = (float) (point.y + playerRight.y * rightOffset * (1 - ((float) i / points.size()))); + var dz = (float) (point.z + playerRight.z * rightOffset * (1 - ((float) i / points.size()))); + + points.set(i, new Vector3f(dx, dy, dz)); + } + + // Render the trajectory line + if (hit.hitEntity() != null) { + renderLine(drawContext, points, 0.0f, 1.0f, 0.0f); // Red for hit + } else { + renderLine(drawContext, points, 1.0f, 0.0f, 1.0f); // Green for no hit + } + } + } + } + + private void renderLine(WorldRenderContext drawContext, List points, float r, float g, float b) { // enable z-buffer GlStateManager._enableDepthTest(); GlStateManager._depthFunc(GL11.GL_LEQUAL); @@ -155,7 +131,7 @@ public class TrajectoryRenderer { var playerPos = MinecraftClient.getInstance().getCameraEntity().getCameraPosVec(0); - for (var point: points) { + for (var point : points) { float dx = (float) (point.x - playerPos.x); float dy = (float) (point.y - playerPos.y); float dz = (float) (point.z - playerPos.z); diff --git a/src/main/java/org/walruslab/kepler/trajectory/Trajectory.java b/src/main/java/org/walruslab/kepler/trajectory/Trajectory.java index 53cf13d..89b65ce 100644 --- a/src/main/java/org/walruslab/kepler/trajectory/Trajectory.java +++ b/src/main/java/org/walruslab/kepler/trajectory/Trajectory.java @@ -53,21 +53,11 @@ public class Trajectory { var bb = entity.getBoundingBox(); var entityVelocity = entity.getVelocity(); // predict entity position by adding its velocity * seconds(by tick) - var curEntityPos = new Vector3f( - (float) (entity.getX()), - (float) (entity.getY()), - (float) (entity.getZ()) - ); - var predictEntityPos = new Vector3f( - (float) (entity.getX() + entityVelocity.x * currentTick), - (float) (entity.getY() + entityVelocity.y * currentTick), - (float) (entity.getZ() + entityVelocity.z * currentTick) - ); var entityStart = new Vec3d(bb.minX, bb.minY, bb.minZ).add(entityVelocity.x * currentTick, entityVelocity.y * currentTick, entityVelocity.z * currentTick); var entityEnd = new Vec3d(bb.maxX, bb.maxY, bb.maxZ).add(entityVelocity.x * currentTick, entityVelocity.y * currentTick, entityVelocity.z * currentTick); var entityBox = new Box(entityStart, entityEnd); if (this.boxIntersectsLine(start, end, entityBox)) { - return new TrajectoryHit(points, true); // Hit an entity + return new TrajectoryHit(points, entity, currentTick); // Hit an entity } } @@ -83,7 +73,7 @@ public class Trajectory { if (hitResult.getType() != HitResult.Type.MISS) { // Check if the hit result is a block if (hitResult.getType() == HitResult.Type.BLOCK) { - return new TrajectoryHit(points, false); // Hit a block + return new TrajectoryHit(points, null, currentTick); // Hit a block } } @@ -99,7 +89,7 @@ public class Trajectory { break; // Prevent infinite loop } } - return new TrajectoryHit(points, false); // No hit + return new TrajectoryHit(points, null, currentTick); // No hit } private boolean boxIntersectsLine(Vec3d start, Vec3d end, Box box) { diff --git a/src/main/java/org/walruslab/kepler/trajectory/TrajectoryHit.java b/src/main/java/org/walruslab/kepler/trajectory/TrajectoryHit.java index 2c1ed46..45ddbd7 100644 --- a/src/main/java/org/walruslab/kepler/trajectory/TrajectoryHit.java +++ b/src/main/java/org/walruslab/kepler/trajectory/TrajectoryHit.java @@ -1,9 +1,10 @@ package org.walruslab.kepler.trajectory; +import net.minecraft.entity.Entity; import net.minecraft.util.Pair; import org.joml.Vector3f; import java.util.List; -public record TrajectoryHit(List points, boolean hitEntity) { +public record TrajectoryHit(List points, Entity hitEntity, int ticks) { } diff --git a/src/main/java/org/walruslab/kepler/trajectory/item/ShootableBow.java b/src/main/java/org/walruslab/kepler/trajectory/item/ShootableBow.java new file mode 100644 index 0000000..b87f452 --- /dev/null +++ b/src/main/java/org/walruslab/kepler/trajectory/item/ShootableBow.java @@ -0,0 +1,14 @@ +package org.walruslab.kepler.trajectory.item; + +import org.joml.Vector3f; +import org.walruslab.kepler.trajectory.Trajectory; + +public class ShootableBow implements ShootableItem { + public final float speed = 3.0f; + + @Override + public Trajectory makeTrajectory(Vector3f pos, Vector3f dir, Vector3f bias, float mul) { + var velocity = dir.mul(speed * mul).add(bias); + return new Trajectory(pos, velocity); + } +} diff --git a/src/main/java/org/walruslab/kepler/trajectory/item/ShootableCrossbow.java b/src/main/java/org/walruslab/kepler/trajectory/item/ShootableCrossbow.java new file mode 100644 index 0000000..6734f7d --- /dev/null +++ b/src/main/java/org/walruslab/kepler/trajectory/item/ShootableCrossbow.java @@ -0,0 +1,14 @@ +package org.walruslab.kepler.trajectory.item; + +import org.joml.Vector3f; +import org.walruslab.kepler.trajectory.Trajectory; + +public class ShootableCrossbow implements ShootableItem { + public final float speed = 3.15f; + + @Override + public Trajectory makeTrajectory(Vector3f pos, Vector3f dir, Vector3f bias, float mul) { + var velocity = dir.mul(speed * mul).add(bias); + return new Trajectory(pos, velocity); + } +} diff --git a/src/main/java/org/walruslab/kepler/trajectory/item/ShootableItem.java b/src/main/java/org/walruslab/kepler/trajectory/item/ShootableItem.java new file mode 100644 index 0000000..0e2de8a --- /dev/null +++ b/src/main/java/org/walruslab/kepler/trajectory/item/ShootableItem.java @@ -0,0 +1,8 @@ +package org.walruslab.kepler.trajectory.item; + +import org.joml.Vector3f; +import org.walruslab.kepler.trajectory.Trajectory; + +public interface ShootableItem { + public Trajectory makeTrajectory(Vector3f pos, Vector3f dir, Vector3f bias, float mul); +} diff --git a/src/main/java/org/walruslab/kepler/trajectory/item/ShootableItemFactory.java b/src/main/java/org/walruslab/kepler/trajectory/item/ShootableItemFactory.java new file mode 100644 index 0000000..48b14ed --- /dev/null +++ b/src/main/java/org/walruslab/kepler/trajectory/item/ShootableItemFactory.java @@ -0,0 +1,15 @@ +package org.walruslab.kepler.trajectory.item; + +import net.minecraft.item.ItemStack; +import net.minecraft.item.Items; +import org.jetbrains.annotations.Nullable; + +public class ShootableItemFactory { + public static @Nullable ShootableItem create(ItemStack itemStack) { + if (itemStack.isOf(Items.BOW)) + return new ShootableBow(); + else if (itemStack.isOf(Items.CROSSBOW)) + return new ShootableCrossbow(); + else return null; + } +} -- 2.49.1