Compare commits
5 Commits
1.21.7
...
014517a96a
| Author | SHA1 | Date | |
|---|---|---|---|
| 014517a96a | |||
| 4652f58415 | |||
| 75021b3360 | |||
| fec526c2c1 | |||
| b4e6c8c794 |
19
README.md
Normal file
19
README.md
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
# Kepler
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
Simplest arrow trajectory visualizer.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
## Dependencies
|
||||||
|
|
||||||
|
No dependency. This is the independent mod.
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
Copy the JAR to `mods` folder.
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
Pull your bowstring!
|
||||||
BIN
docs/image1.png
Normal file
BIN
docs/image1.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 316 KiB |
@@ -8,10 +8,18 @@ maven_group=org.walruslab
|
|||||||
archives_base_name=kepler
|
archives_base_name=kepler
|
||||||
# Dependencies
|
# Dependencies
|
||||||
# check this on https://modmuss50.me/fabric.html
|
# check this on https://modmuss50.me/fabric.html
|
||||||
minecraft_version=1.21.7
|
#minecraft_version=1.21.7
|
||||||
yarn_mappings=1.21.7+build.8
|
#yarn_mappings=1.21.7+build.8
|
||||||
loader_version=0.16.14
|
#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
|
loom_version=1.11-SNAPSHOT
|
||||||
|
|
||||||
# Fabric API
|
# Fabric API
|
||||||
fabric_version=0.129.0+1.21.7
|
fabric_version=0.131.0+1.21.8
|
||||||
@@ -10,8 +10,9 @@ public class KeplerClient implements ClientModInitializer {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onInitializeClient() {
|
public void onInitializeClient() {
|
||||||
|
var renderer = new TrajectoryRenderer();
|
||||||
ClientEntityEvents.ENTITY_LOAD.register((entity, _a) -> {
|
ClientEntityEvents.ENTITY_LOAD.register((entity, _a) -> {
|
||||||
if (entity instanceof PlayerEntity) TrajectoryRenderer.setupRenderLine((PlayerEntity) entity);
|
if (entity instanceof PlayerEntity) renderer.setupRenderLine((PlayerEntity) entity);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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<TrajectoryHit> lastHits;
|
||||||
|
|
||||||
|
public void calculateTrajectories(List<ArrowEntity> 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<TrajectoryHit> 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,100 +1,81 @@
|
|||||||
package org.walruslab.kepler.render;
|
package org.walruslab.kepler.render;
|
||||||
|
|
||||||
import com.mojang.blaze3d.opengl.GlStateManager;
|
import com.mojang.blaze3d.opengl.GlStateManager;
|
||||||
import com.mojang.blaze3d.systems.RenderSystem;
|
|
||||||
import com.mojang.blaze3d.vertex.VertexFormat;
|
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.WorldRenderContext;
|
||||||
import net.fabricmc.fabric.api.client.rendering.v1.WorldRenderEvents;
|
import net.fabricmc.fabric.api.client.rendering.v1.WorldRenderEvents;
|
||||||
import net.jpountz.util.Utils;
|
|
||||||
import net.minecraft.client.MinecraftClient;
|
import net.minecraft.client.MinecraftClient;
|
||||||
import net.minecraft.client.render.RenderLayer;
|
import net.minecraft.client.render.RenderLayer;
|
||||||
import net.minecraft.client.render.Tessellator;
|
import net.minecraft.client.render.Tessellator;
|
||||||
import net.minecraft.client.render.VertexFormats;
|
import net.minecraft.client.render.VertexFormats;
|
||||||
|
import net.minecraft.entity.LivingEntity;
|
||||||
import net.minecraft.entity.player.PlayerEntity;
|
import net.minecraft.entity.player.PlayerEntity;
|
||||||
import net.minecraft.entity.projectile.ArrowEntity;
|
import net.minecraft.entity.projectile.ArrowEntity;
|
||||||
import net.minecraft.item.BowItem;
|
import net.minecraft.item.BowItem;
|
||||||
import net.minecraft.item.Items;
|
import net.minecraft.item.Items;
|
||||||
import net.minecraft.predicate.entity.EntityPredicate;
|
|
||||||
import net.minecraft.predicate.entity.EntityPredicates;
|
import net.minecraft.predicate.entity.EntityPredicates;
|
||||||
import net.minecraft.text.Text;
|
import net.minecraft.text.Text;
|
||||||
import net.minecraft.util.TypeFilter;
|
import net.minecraft.util.TypeFilter;
|
||||||
import net.minecraft.util.Util;
|
|
||||||
import net.minecraft.util.math.Box;
|
import net.minecraft.util.math.Box;
|
||||||
import net.minecraft.util.math.Vec3d;
|
import net.minecraft.util.math.Vec3d;
|
||||||
import net.minecraft.util.math.Vec3i;
|
import net.minecraft.util.math.Vec3i;
|
||||||
import org.joml.Vector3d;
|
|
||||||
import org.joml.Vector3f;
|
import org.joml.Vector3f;
|
||||||
import org.lwjgl.opengl.GL11;
|
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.List;
|
||||||
import java.util.function.Predicate;
|
|
||||||
|
|
||||||
public class TrajectoryRenderer {
|
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);
|
player.sendMessage(Text.of("Kepler: TrajectoryRenderer setupRenderLine"), false);
|
||||||
WorldRenderEvents.END.register((drawContext) -> {
|
WorldRenderEvents.END.register((drawContext) -> {
|
||||||
// get all error entity in player world
|
|
||||||
var world = player.getWorld();
|
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);
|
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) {
|
trajectoryManager.calculateTrajectories(arrows);
|
||||||
if (arrow.groundCollision) return;
|
|
||||||
|
|
||||||
var pos = arrow.getPos();
|
var hits = trajectoryManager.getLastHits();
|
||||||
var velocity = arrow.getVelocity();
|
if (hits != null) {
|
||||||
|
for (var hit : hits) {
|
||||||
var tr = new Trajectory(pos.toVector3f(), velocity.toVector3f());
|
if (hit != null)
|
||||||
var hit = tr.getTrajectoryPoints(world, 0.1f, player);
|
renderForArrow(hit, drawContext);
|
||||||
var points = hit.points();
|
}
|
||||||
|
|
||||||
if (points.size() < 2) {
|
|
||||||
continue; // Skip if not enough points
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Render the trajectory line
|
for (LivingEntity entity : entities) {
|
||||||
if (hit.hitEntity()) {
|
var activeItem = entity.getMainHandStack();
|
||||||
|
if (activeItem != null && (activeItem.isOf(Items.BOW) || activeItem.isOf(Items.CROSSBOW))) {
|
||||||
|
renderForPlayer(entity, drawContext);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
renderLine(drawContext, points, 0.0f, 1.0f, 0.0f); // Red for hit
|
||||||
} else {
|
} else {
|
||||||
renderLine(drawContext, points, 1.0f, 0.0f, 1.0f); // Green for no hit
|
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
|
private void renderForPlayer(LivingEntity player, WorldRenderContext drawContext) {
|
||||||
|
// get all error entity in player world
|
||||||
|
var world = player.getWorld();
|
||||||
|
|
||||||
var activeItem = player.getMainHandStack();
|
var activeItem = player.getMainHandStack();
|
||||||
if (activeItem != null && (activeItem.isOf(Items.BOW) || activeItem.isOf(Items.CROSSBOW))) {
|
float progress = 1.0f;
|
||||||
float speed;
|
|
||||||
if (activeItem.isOf(Items.BOW)) {
|
if (activeItem.isOf(Items.BOW)) {
|
||||||
var item = (BowItem) activeItem.getItem();
|
progress = BowItem.getPullProgress(player.getItemUseTime());
|
||||||
var f = BowItem.getPullProgress(player.getItemUseTime());
|
|
||||||
speed = f * 3.0f;
|
|
||||||
} else {
|
|
||||||
speed = 3.15f;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var dirDouble = player.getRotationVec(1.0f);
|
var dirDouble = player.getRotationVec(1.0f);
|
||||||
@@ -108,13 +89,9 @@ public class TrajectoryRenderer {
|
|||||||
var pos = player.getEyePos();
|
var pos = player.getEyePos();
|
||||||
var playerVelocity = player.getVelocity();
|
var playerVelocity = player.getVelocity();
|
||||||
|
|
||||||
var velocity = new Vector3f(
|
var item = ShootableItemFactory.create(activeItem);
|
||||||
(float) (dir.x * speed + playerVelocity.x),
|
if (item != null) {
|
||||||
(float) (dir.y * speed + playerVelocity.y),
|
var tr = item.makeTrajectory(pos.toVector3f(), dir, playerVelocity.toVector3f(), progress);
|
||||||
(float) (dir.z * speed + playerVelocity.z)
|
|
||||||
);
|
|
||||||
|
|
||||||
var tr = new Trajectory(pos.toVector3f(), velocity);
|
|
||||||
var hit = tr.getTrajectoryPoints(world, 0.1f, player);
|
var hit = tr.getTrajectoryPoints(world, 0.1f, player);
|
||||||
|
|
||||||
var points = hit.points();
|
var points = hit.points();
|
||||||
@@ -133,17 +110,16 @@ public class TrajectoryRenderer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Render the trajectory line
|
// Render the trajectory line
|
||||||
if (hit.hitEntity()) {
|
if (hit.hitEntity() != null) {
|
||||||
renderLine(drawContext, points, 0.0f, 1.0f, 0.0f); // Red for hit
|
renderLine(drawContext, points, 0.0f, 1.0f, 0.0f); // Red for hit
|
||||||
} else {
|
} else {
|
||||||
renderLine(drawContext, points, 1.0f, 0.0f, 1.0f); // Green for no hit
|
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) {
|
private void renderLine(WorldRenderContext drawContext, List<Vector3f> points, float r, float g, float b) {
|
||||||
// enable z-buffer
|
// enable z-buffer
|
||||||
GlStateManager._enableDepthTest();
|
GlStateManager._enableDepthTest();
|
||||||
GlStateManager._depthFunc(GL11.GL_LEQUAL);
|
GlStateManager._depthFunc(GL11.GL_LEQUAL);
|
||||||
@@ -155,7 +131,7 @@ public class TrajectoryRenderer {
|
|||||||
|
|
||||||
var playerPos = MinecraftClient.getInstance().getCameraEntity().getCameraPosVec(0);
|
var playerPos = MinecraftClient.getInstance().getCameraEntity().getCameraPosVec(0);
|
||||||
|
|
||||||
for (var point: points) {
|
for (var point : points) {
|
||||||
float dx = (float) (point.x - playerPos.x);
|
float dx = (float) (point.x - playerPos.x);
|
||||||
float dy = (float) (point.y - playerPos.y);
|
float dy = (float) (point.y - playerPos.y);
|
||||||
float dz = (float) (point.z - playerPos.z);
|
float dz = (float) (point.z - playerPos.z);
|
||||||
|
|||||||
@@ -53,21 +53,11 @@ public class Trajectory {
|
|||||||
var bb = entity.getBoundingBox();
|
var bb = entity.getBoundingBox();
|
||||||
var entityVelocity = entity.getVelocity();
|
var entityVelocity = entity.getVelocity();
|
||||||
// predict entity position by adding its velocity * seconds(by tick)
|
// 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 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 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);
|
var entityBox = new Box(entityStart, entityEnd);
|
||||||
if (this.boxIntersectsLine(start, end, entityBox)) {
|
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) {
|
if (hitResult.getType() != HitResult.Type.MISS) {
|
||||||
// Check if the hit result is a block
|
// Check if the hit result is a block
|
||||||
if (hitResult.getType() == HitResult.Type.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
|
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) {
|
private boolean boxIntersectsLine(Vec3d start, Vec3d end, Box box) {
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
package org.walruslab.kepler.trajectory;
|
package org.walruslab.kepler.trajectory;
|
||||||
|
|
||||||
|
import net.minecraft.entity.Entity;
|
||||||
import net.minecraft.util.Pair;
|
import net.minecraft.util.Pair;
|
||||||
import org.joml.Vector3f;
|
import org.joml.Vector3f;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public record TrajectoryHit(List<Vector3f> points, boolean hitEntity) {
|
public record TrajectoryHit(List<Vector3f> points, Entity hitEntity, int ticks) {
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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);
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user