adfds
This commit is contained in:
119
.gitignore
vendored
Normal file
119
.gitignore
vendored
Normal file
@@ -0,0 +1,119 @@
|
|||||||
|
# User-specific stuff
|
||||||
|
.idea/
|
||||||
|
|
||||||
|
*.iml
|
||||||
|
*.ipr
|
||||||
|
*.iws
|
||||||
|
|
||||||
|
# IntelliJ
|
||||||
|
out/
|
||||||
|
# mpeltonen/sbt-idea plugin
|
||||||
|
.idea_modules/
|
||||||
|
|
||||||
|
# JIRA plugin
|
||||||
|
atlassian-ide-plugin.xml
|
||||||
|
|
||||||
|
# Compiled class file
|
||||||
|
*.class
|
||||||
|
|
||||||
|
# Log file
|
||||||
|
*.log
|
||||||
|
|
||||||
|
# BlueJ files
|
||||||
|
*.ctxt
|
||||||
|
|
||||||
|
# Package Files #
|
||||||
|
*.jar
|
||||||
|
*.war
|
||||||
|
*.nar
|
||||||
|
*.ear
|
||||||
|
*.zip
|
||||||
|
*.tar.gz
|
||||||
|
*.rar
|
||||||
|
|
||||||
|
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
|
||||||
|
hs_err_pid*
|
||||||
|
|
||||||
|
*~
|
||||||
|
|
||||||
|
# temporary files which can be created if a process still has a handle open of a deleted file
|
||||||
|
.fuse_hidden*
|
||||||
|
|
||||||
|
# KDE directory preferences
|
||||||
|
.directory
|
||||||
|
|
||||||
|
# Linux trash folder which might appear on any partition or disk
|
||||||
|
.Trash-*
|
||||||
|
|
||||||
|
# .nfs files are created when an open file is removed but is still being accessed
|
||||||
|
.nfs*
|
||||||
|
|
||||||
|
# General
|
||||||
|
.DS_Store
|
||||||
|
.AppleDouble
|
||||||
|
.LSOverride
|
||||||
|
|
||||||
|
# Icon must end with two \r
|
||||||
|
Icon
|
||||||
|
|
||||||
|
# Thumbnails
|
||||||
|
._*
|
||||||
|
|
||||||
|
# Files that might appear in the root of a volume
|
||||||
|
.DocumentRevisions-V100
|
||||||
|
.fseventsd
|
||||||
|
.Spotlight-V100
|
||||||
|
.TemporaryItems
|
||||||
|
.Trashes
|
||||||
|
.VolumeIcon.icns
|
||||||
|
.com.apple.timemachine.donotpresent
|
||||||
|
|
||||||
|
# Directories potentially created on remote AFP share
|
||||||
|
.AppleDB
|
||||||
|
.AppleDesktop
|
||||||
|
Network Trash Folder
|
||||||
|
Temporary Items
|
||||||
|
.apdisk
|
||||||
|
|
||||||
|
# Windows thumbnail cache files
|
||||||
|
Thumbs.db
|
||||||
|
Thumbs.db:encryptable
|
||||||
|
ehthumbs.db
|
||||||
|
ehthumbs_vista.db
|
||||||
|
|
||||||
|
# Dump file
|
||||||
|
*.stackdump
|
||||||
|
|
||||||
|
# Folder config file
|
||||||
|
[Dd]esktop.ini
|
||||||
|
|
||||||
|
# Recycle Bin used on file shares
|
||||||
|
$RECYCLE.BIN/
|
||||||
|
|
||||||
|
# Windows Installer files
|
||||||
|
*.cab
|
||||||
|
*.msi
|
||||||
|
*.msix
|
||||||
|
*.msm
|
||||||
|
*.msp
|
||||||
|
|
||||||
|
# Windows shortcuts
|
||||||
|
*.lnk
|
||||||
|
|
||||||
|
.gradle
|
||||||
|
build/
|
||||||
|
|
||||||
|
# Ignore Gradle GUI config
|
||||||
|
gradle-app.setting
|
||||||
|
|
||||||
|
# Cache of project
|
||||||
|
.gradletasknamecache
|
||||||
|
|
||||||
|
**/build/
|
||||||
|
|
||||||
|
# Common working directory
|
||||||
|
run/
|
||||||
|
runs/
|
||||||
|
|
||||||
|
# Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored)
|
||||||
|
!gradle-wrapper.jar
|
||||||
2
LICENSE.txt
Normal file
2
LICENSE.txt
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
Copyright (c) 2025
|
||||||
|
All rights reserved.
|
||||||
95
build.gradle
Normal file
95
build.gradle
Normal file
@@ -0,0 +1,95 @@
|
|||||||
|
plugins {
|
||||||
|
id 'fabric-loom' version '1.10-SNAPSHOT'
|
||||||
|
id 'maven-publish'
|
||||||
|
}
|
||||||
|
|
||||||
|
version = project.mod_version
|
||||||
|
group = project.maven_group
|
||||||
|
|
||||||
|
base {
|
||||||
|
archivesName = project.archives_base_name
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fabricApi {
|
||||||
|
configureDataGeneration {
|
||||||
|
client = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
repositories {
|
||||||
|
// Add repositories to retrieve artifacts from in here.
|
||||||
|
// You should only use this when depending on other mods because
|
||||||
|
// Loom adds the essential maven repositories to download Minecraft and libraries from automatically.
|
||||||
|
// See https://docs.gradle.org/current/userguide/declaring_repositories.html
|
||||||
|
// for more information about repositories.
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
// To change the versions see the gradle.properties file
|
||||||
|
minecraft "com.mojang:minecraft:${project.minecraft_version}"
|
||||||
|
mappings "net.fabricmc:yarn:${project.yarn_mappings}:v2"
|
||||||
|
modImplementation "net.fabricmc:fabric-loader:${project.loader_version}"
|
||||||
|
|
||||||
|
modImplementation "net.fabricmc.fabric-api:fabric-api:${project.fabric_version}"
|
||||||
|
}
|
||||||
|
|
||||||
|
processResources {
|
||||||
|
inputs.property "version", project.version
|
||||||
|
inputs.property "minecraft_version", project.minecraft_version
|
||||||
|
inputs.property "loader_version", project.loader_version
|
||||||
|
filteringCharset "UTF-8"
|
||||||
|
|
||||||
|
filesMatching("fabric.mod.json") {
|
||||||
|
expand "version": project.version,
|
||||||
|
"minecraft_version": project.minecraft_version,
|
||||||
|
"loader_version": project.loader_version
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def targetJavaVersion = 21
|
||||||
|
tasks.withType(JavaCompile).configureEach {
|
||||||
|
// ensure that the encoding is set to UTF-8, no matter what the system default is
|
||||||
|
// this fixes some edge cases with special characters not displaying correctly
|
||||||
|
// see http://yodaconditions.net/blog/fix-for-java-file-encoding-problems-with-gradle.html
|
||||||
|
// If Javadoc is generated, this must be specified in that task too.
|
||||||
|
it.options.encoding = "UTF-8"
|
||||||
|
if (targetJavaVersion >= 10 || JavaVersion.current().isJava10Compatible()) {
|
||||||
|
it.options.release.set(targetJavaVersion)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
java {
|
||||||
|
def javaVersion = JavaVersion.toVersion(targetJavaVersion)
|
||||||
|
if (JavaVersion.current() < javaVersion) {
|
||||||
|
toolchain.languageVersion = JavaLanguageVersion.of(targetJavaVersion)
|
||||||
|
}
|
||||||
|
// Loom will automatically attach sourcesJar to a RemapSourcesJar task and to the "build" task
|
||||||
|
// if it is present.
|
||||||
|
// If you remove this line, sources will not be generated.
|
||||||
|
withSourcesJar()
|
||||||
|
}
|
||||||
|
|
||||||
|
jar {
|
||||||
|
from("LICENSE") {
|
||||||
|
rename { "${it}_${project.archivesBaseName}" }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// configure the maven publication
|
||||||
|
publishing {
|
||||||
|
publications {
|
||||||
|
create("mavenJava", MavenPublication) {
|
||||||
|
artifactId = project.archives_base_name
|
||||||
|
from components.java
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// See https://docs.gradle.org/current/userguide/publishing_maven.html for information on how to set up publishing.
|
||||||
|
repositories {
|
||||||
|
// Add repositories to publish to here.
|
||||||
|
// Notice: This block does NOT have the same function as the block in the top level.
|
||||||
|
// The repositories here will be used for publishing your artifact, not for
|
||||||
|
// retrieving dependencies.
|
||||||
|
}
|
||||||
|
}
|
||||||
14
gradle.properties
Normal file
14
gradle.properties
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
# Done to increase the memory available to gradle.
|
||||||
|
org.gradle.jvmargs=-Xmx1G
|
||||||
|
# Fabric Properties
|
||||||
|
# check these on https://modmuss50.me/fabric.html
|
||||||
|
minecraft_version=1.21.4
|
||||||
|
yarn_mappings=1.21.4+build.8
|
||||||
|
loader_version=0.16.14
|
||||||
|
# Mod Properties
|
||||||
|
mod_version=1.0
|
||||||
|
maven_group=org.walruslab
|
||||||
|
archives_base_name=kepler
|
||||||
|
# Dependencies
|
||||||
|
# check this on https://modmuss50.me/fabric.html
|
||||||
|
fabric_version=0.119.2+1.21.4
|
||||||
1
gradle/wrapper/gradle-wrapper.properties
vendored
Normal file
1
gradle/wrapper/gradle-wrapper.properties
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
distributionUrl=https\://services.gradle.org/distributions/gradle-8.12-bin.zip
|
||||||
9
settings.gradle
Normal file
9
settings.gradle
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
pluginManagement {
|
||||||
|
repositories {
|
||||||
|
maven {
|
||||||
|
name = 'Fabric'
|
||||||
|
url = 'https://maven.fabricmc.net/'
|
||||||
|
}
|
||||||
|
gradlePluginPortal()
|
||||||
|
}
|
||||||
|
}
|
||||||
10
src/main/java/org/walruslab/kepler/Kepler.java
Normal file
10
src/main/java/org/walruslab/kepler/Kepler.java
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
package org.walruslab.kepler;
|
||||||
|
|
||||||
|
import net.fabricmc.api.ModInitializer;
|
||||||
|
|
||||||
|
public class Kepler implements ModInitializer {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onInitialize() {
|
||||||
|
}
|
||||||
|
}
|
||||||
17
src/main/java/org/walruslab/kepler/client/KeplerClient.java
Normal file
17
src/main/java/org/walruslab/kepler/client/KeplerClient.java
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
package org.walruslab.kepler.client;
|
||||||
|
|
||||||
|
import net.fabricmc.api.ClientModInitializer;
|
||||||
|
import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientEntityEvents;
|
||||||
|
import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientLifecycleEvents;
|
||||||
|
import net.minecraft.entity.player.PlayerEntity;
|
||||||
|
import org.walruslab.kepler.render.TrajectoryRenderer;
|
||||||
|
|
||||||
|
public class KeplerClient implements ClientModInitializer {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onInitializeClient() {
|
||||||
|
ClientEntityEvents.ENTITY_LOAD.register((entity, _a) -> {
|
||||||
|
if (entity instanceof PlayerEntity) TrajectoryRenderer.setupRenderLine((PlayerEntity) entity);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
package org.walruslab.kepler.client;
|
||||||
|
|
||||||
|
import net.fabricmc.fabric.api.datagen.v1.DataGeneratorEntrypoint;
|
||||||
|
import net.fabricmc.fabric.api.datagen.v1.FabricDataGenerator;
|
||||||
|
|
||||||
|
public class KeplerDataGenerator implements DataGeneratorEntrypoint {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onInitializeDataGenerator(FabricDataGenerator fabricDataGenerator) {
|
||||||
|
FabricDataGenerator.Pack pack = fabricDataGenerator.createPack();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,176 @@
|
|||||||
|
package org.walruslab.kepler.render;
|
||||||
|
|
||||||
|
import com.mojang.blaze3d.systems.RenderSystem;
|
||||||
|
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.gl.ShaderProgramKeys;
|
||||||
|
import net.minecraft.client.render.BufferRenderer;
|
||||||
|
import net.minecraft.client.render.Tessellator;
|
||||||
|
import net.minecraft.client.render.VertexFormat;
|
||||||
|
import net.minecraft.client.render.VertexFormats;
|
||||||
|
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 java.util.List;
|
||||||
|
import java.util.function.Predicate;
|
||||||
|
|
||||||
|
public class TrajectoryRenderer {
|
||||||
|
public static 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 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;
|
||||||
|
|
||||||
|
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 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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void renderLine(WorldRenderContext drawContext, List<Vector3f> points, float r, float g, float b) {
|
||||||
|
// enable z-buffer
|
||||||
|
RenderSystem.enableDepthTest();
|
||||||
|
RenderSystem.depthFunc(GL11.GL_LEQUAL);
|
||||||
|
RenderSystem.enableBlend();
|
||||||
|
RenderSystem.defaultBlendFunc();
|
||||||
|
|
||||||
|
RenderSystem.setShaderColor(r, g, b, 1.0f);
|
||||||
|
|
||||||
|
var tesselator = Tessellator.getInstance();
|
||||||
|
var buf = tesselator.begin(VertexFormat.DrawMode.DEBUG_LINE_STRIP, VertexFormats.POSITION_COLOR);
|
||||||
|
var mat = drawContext.positionMatrix();
|
||||||
|
|
||||||
|
var playerPos = MinecraftClient.getInstance().getCameraEntity().getCameraPosVec(0);
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
buf.vertex(mat, dx, dy, dz);
|
||||||
|
|
||||||
|
buf.color(r, g, b, 1.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
RenderSystem.setShader(ShaderProgramKeys.POSITION_COLOR);
|
||||||
|
RenderSystem.setShaderColor(1.0f, 1.0f, 1.0f, 1.0f);
|
||||||
|
|
||||||
|
BufferRenderer.drawWithGlobalProgram(buf.end());
|
||||||
|
}
|
||||||
|
}
|
||||||
142
src/main/java/org/walruslab/kepler/trajectory/Trajectory.java
Normal file
142
src/main/java/org/walruslab/kepler/trajectory/Trajectory.java
Normal file
@@ -0,0 +1,142 @@
|
|||||||
|
package org.walruslab.kepler.trajectory;
|
||||||
|
|
||||||
|
import net.minecraft.block.ShapeContext;
|
||||||
|
import net.minecraft.entity.Entity;
|
||||||
|
import net.minecraft.entity.LivingEntity;
|
||||||
|
import net.minecraft.entity.decoration.EndCrystalEntity;
|
||||||
|
import net.minecraft.util.Pair;
|
||||||
|
import net.minecraft.util.hit.HitResult;
|
||||||
|
import net.minecraft.util.math.Box;
|
||||||
|
import net.minecraft.util.math.Vec3d;
|
||||||
|
import net.minecraft.world.RaycastContext;
|
||||||
|
import net.minecraft.world.World;
|
||||||
|
import org.joml.Vector3f;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
|
public class Trajectory {
|
||||||
|
public final Vector3f position;
|
||||||
|
public final Vector3f velocity;
|
||||||
|
public final float speedMultiplier;
|
||||||
|
public final float gravity;
|
||||||
|
|
||||||
|
public Trajectory(Vector3f position, Vector3f velocity) {
|
||||||
|
this.position = position;
|
||||||
|
this.velocity = velocity;
|
||||||
|
this.speedMultiplier = 0.99f;
|
||||||
|
this.gravity = 1.0f / 20;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Trajectory(Vector3f position, Vector3f velocity, float speedMultiplier, float gravity) {
|
||||||
|
this.position = position;
|
||||||
|
this.velocity = velocity;
|
||||||
|
this.speedMultiplier = speedMultiplier;
|
||||||
|
this.gravity = gravity;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TrajectoryHit getTrajectoryPoints(World world, float density, Entity exclusionEntity) {
|
||||||
|
List<Vector3f> points = new ArrayList<>();
|
||||||
|
Vector3f currentPosition = new Vector3f(position);
|
||||||
|
Vector3f currentVelocity = new Vector3f(velocity);
|
||||||
|
int currentTick = 0;
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
Vec3d start = new Vec3d(currentPosition.x, currentPosition.y, currentPosition.z);
|
||||||
|
Vec3d end = new Vec3d(currentPosition.x + currentVelocity.x, currentPosition.y + currentVelocity.y, currentPosition.z + currentVelocity.z);
|
||||||
|
|
||||||
|
// get all entities in range of 10 blocks
|
||||||
|
var entities = world.getOtherEntities(null, new Box(start.subtract(100, 100, 100), end.add(100, 100, 100)), entity -> entity instanceof LivingEntity || entity instanceof EndCrystalEntity);
|
||||||
|
for (Entity entity : entities) {
|
||||||
|
if (entity.equals(exclusionEntity)) continue;
|
||||||
|
// check start-end line collides with entity bounding box
|
||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var rContext = new RaycastContext(
|
||||||
|
start,
|
||||||
|
end,
|
||||||
|
RaycastContext.ShapeType.COLLIDER,
|
||||||
|
RaycastContext.FluidHandling.NONE,
|
||||||
|
ShapeContext.absent()
|
||||||
|
);
|
||||||
|
|
||||||
|
var hitResult = world.raycast(rContext);
|
||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
points.add(new Vector3f(currentPosition));
|
||||||
|
|
||||||
|
// Update position and velocity
|
||||||
|
currentPosition.add(currentVelocity);
|
||||||
|
currentVelocity.y -= gravity; // Apply gravity
|
||||||
|
currentVelocity.mul(speedMultiplier); // Apply speed multiplier
|
||||||
|
currentTick++;
|
||||||
|
|
||||||
|
if (currentTick > 5000 / density) {
|
||||||
|
break; // Prevent infinite loop
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return new TrajectoryHit(points, false); // No hit
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean boxIntersectsLine(Vec3d start, Vec3d end, Box box) {
|
||||||
|
double tMin = 0.0;
|
||||||
|
double tMax = 1.0;
|
||||||
|
|
||||||
|
double[] startArr = {start.x, start.y, start.z};
|
||||||
|
double[] endArr = {end.x, end.y, end.z};
|
||||||
|
double[] boxMin = {box.minX, box.minY, box.minZ};
|
||||||
|
double[] boxMax = {box.maxX, box.maxY, box.maxZ};
|
||||||
|
|
||||||
|
for (int i = 0; i < 3; i++) {
|
||||||
|
double d = endArr[i] - startArr[i];
|
||||||
|
|
||||||
|
if (Math.abs(d) < 1e-8) {
|
||||||
|
if (startArr[i] < boxMin[i] || startArr[i] > boxMax[i]) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
double t1 = (boxMin[i] - startArr[i]) / d;
|
||||||
|
double t2 = (boxMax[i] - startArr[i]) / d;
|
||||||
|
|
||||||
|
if (t1 > t2) {
|
||||||
|
double temp = t1;
|
||||||
|
t1 = t2;
|
||||||
|
t2 = temp;
|
||||||
|
}
|
||||||
|
|
||||||
|
tMin = Math.max(tMin, t1);
|
||||||
|
tMax = Math.min(tMax, t2);
|
||||||
|
|
||||||
|
if (tMin > tMax) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
package org.walruslab.kepler.trajectory;
|
||||||
|
|
||||||
|
import net.minecraft.util.Pair;
|
||||||
|
import org.joml.Vector3f;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public record TrajectoryHit(List<Vector3f> points, boolean hitEntity) {
|
||||||
|
}
|
||||||
31
src/main/resources/fabric.mod.json
Normal file
31
src/main/resources/fabric.mod.json
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
{
|
||||||
|
"schemaVersion": 1,
|
||||||
|
"id": "kepler",
|
||||||
|
"version": "${version}",
|
||||||
|
"name": "Kepler",
|
||||||
|
"description": "",
|
||||||
|
"authors": [],
|
||||||
|
"contact": {},
|
||||||
|
"license": "All-Rights-Reserved",
|
||||||
|
"icon": "assets/kepler/icon.png",
|
||||||
|
"environment": "client",
|
||||||
|
"entrypoints": {
|
||||||
|
"fabric-datagen": [
|
||||||
|
"org.walruslab.kepler.client.KeplerDataGenerator"
|
||||||
|
],
|
||||||
|
"client": [
|
||||||
|
"org.walruslab.kepler.client.KeplerClient"
|
||||||
|
],
|
||||||
|
"main": [
|
||||||
|
"org.walruslab.kepler.Kepler"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"mixins": [
|
||||||
|
"kepler.mixins.json"
|
||||||
|
],
|
||||||
|
"depends": {
|
||||||
|
"fabricloader": ">=${loader_version}",
|
||||||
|
"fabric": "*",
|
||||||
|
"minecraft": "${minecraft_version}"
|
||||||
|
}
|
||||||
|
}
|
||||||
13
src/main/resources/kepler.mixins.json
Normal file
13
src/main/resources/kepler.mixins.json
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
{
|
||||||
|
"required": true,
|
||||||
|
"minVersion": "0.8",
|
||||||
|
"package": "org.walruslab.kepler.mixin",
|
||||||
|
"compatibilityLevel": "JAVA_21",
|
||||||
|
"mixins": [
|
||||||
|
],
|
||||||
|
"client": [
|
||||||
|
],
|
||||||
|
"injectors": {
|
||||||
|
"defaultRequire": 1
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user