From d36e27d4d71e6f5d595472bd03d52298e9b69eda Mon Sep 17 00:00:00 2001 From: nick <32414396+qurle@users.noreply.github.com> Date: Sat, 23 May 2026 23:12:23 +0300 Subject: [PATCH 1/6] Refactor native directory handling in Rapier3D It tries to place Rapier natives in `../.sable/` folder and fallbacks to user root directory (`%userprofile%/.sable` on Windows, `~/.sable/` on Mac or Linux) --- .../sable/physics/impl/rapier/Rapier3D.java | 40 +++++++++++++++++-- 1 file changed, 36 insertions(+), 4 deletions(-) diff --git a/common/src/main/java/dev/ryanhcode/sable/physics/impl/rapier/Rapier3D.java b/common/src/main/java/dev/ryanhcode/sable/physics/impl/rapier/Rapier3D.java index de0bf136..9b231d7e 100644 --- a/common/src/main/java/dev/ryanhcode/sable/physics/impl/rapier/Rapier3D.java +++ b/common/src/main/java/dev/ryanhcode/sable/physics/impl/rapier/Rapier3D.java @@ -19,6 +19,7 @@ import java.io.FileNotFoundException; import java.io.InputStream; +import java.net.URISyntaxException; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; @@ -32,7 +33,7 @@ @ApiStatus.Internal public class Rapier3D { - private static final String NATIVE_DIR = ".sable/natives"; + private static final Path NATIVE_DIR = resolveNativeDir(); private static final String LIB_NAME = "sable_rapier"; public static final String NATIVE_NAME = getNativeName(); @@ -44,6 +45,32 @@ public class Rapier3D { loadLibrary(); } + private static Path resolveNativeDir() { + // Trying to use mod.jar relative path: ../.sable for using natives + final Path jarPath = getCodeSourcePath(); + if (jarPath != null && Files.isRegularFile(jarPath)) { + final Path jarRelativeDir = jarPath.getParent().resolve("..").resolve(".sable").resolve("natives") + .normalize(); + Sable.LOGGER.info("Using jar-relative Rapier native directory {}", jarRelativeDir.toAbsolutePath()); + return jarRelativeDir; + } + + // Using a bit overly generic ~/.sable directory as a fallback + final Path fallbackDir = Paths.get(System.getProperty("user.home", System.getProperty("user.dir")), ".sable", + "natives"); + Sable.LOGGER.info("Using fallback Rapier native directory {}", fallbackDir.toAbsolutePath()); + return fallbackDir; + } + + private static Path getCodeSourcePath() { + try { + return Paths.get(Rapier3D.class.getProtectionDomain().getCodeSource().getLocation().toURI()); + } catch (final URISyntaxException | SecurityException e) { + Sable.LOGGER.debug("Unable to resolve Rapier code source path, falling back to user home", e); + return null; + } + } + private static String getNativeName() { final String arch; if (System.getProperty("os.arch").equals("arm") || System.getProperty("os.arch").startsWith("aarch64")) { @@ -59,23 +86,28 @@ private static String getNativeName() { return LIB_NAME + "_" + arch + "_macos.dylib"; } else { if (os != OS.LINUX) { - Sable.LOGGER.error("Unknown platform '{}' detected, sable will attempt to use linux natives, this may or may not work.", System.getProperty("os.name")); + Sable.LOGGER.error( + "Unknown platform '{}' detected, sable will attempt to use linux natives, this may or may not work.", + System.getProperty("os.name")); } return LIB_NAME + "_" + arch + "_linux.so"; } } private static void loadLibrary() { - try (final InputStream is = Rapier3D.class.getResourceAsStream("/natives/" + LIB_NAME + "/sable_rapier_binaries.zip.l4z")) { + try (final InputStream is = Rapier3D.class + .getResourceAsStream("/natives/" + LIB_NAME + "/sable_rapier_binaries.zip.l4z")) { if (is == null) { throw new FileNotFoundException("sable_rapier_binaries.zip.l4z"); } - final Path dir = Paths.get(NATIVE_DIR); + final Path dir = NATIVE_DIR; if (!Files.exists(dir)) { Files.createDirectories(dir); } + Sable.LOGGER.info("Using Rapier native directory {}", dir.toAbsolutePath()); + try (final LZ4FrameInputStream is2 = new LZ4FrameInputStream(is); final ZipInputStream ti = new ZipInputStream(is2)) { From aa9969b44046178d4ba5a3d9c478a3e8bd195e5f Mon Sep 17 00:00:00 2001 From: nick <32414396+qurle@users.noreply.github.com> Date: Sun, 24 May 2026 14:42:08 +0000 Subject: [PATCH 2/6] replaced jar-file directory resolving with platfrom-specific game directory --- .../sable/physics/impl/rapier/Rapier3D.java | 14 +++++++------- .../platform/SableGameDirectoryPlatform.java | 18 ++++++++++++++++++ .../SableGameDirectoryPlatformImpl.java | 18 ++++++++++++++++++ ...e.sable.platform.SableGameDirectoryPlatform | 1 + .../SableGameDirectoryPlatformImpl.java | 18 ++++++++++++++++++ ...e.sable.platform.SableGameDirectoryPlatform | 1 + 6 files changed, 63 insertions(+), 7 deletions(-) create mode 100644 common/src/main/java/dev/ryanhcode/sable/platform/SableGameDirectoryPlatform.java create mode 100644 fabric/src/main/java/dev/ryanhcode/sable/fabric/platform/SableGameDirectoryPlatformImpl.java create mode 100644 fabric/src/main/resources/META-INF/services/dev.ryanhcode.sable.platform.SableGameDirectoryPlatform create mode 100644 neoforge/src/main/java/dev/ryanhcode/sable/neoforge/platform/SableGameDirectoryPlatformImpl.java create mode 100644 neoforge/src/main/resources/META-INF/services/dev.ryanhcode.sable.platform.SableGameDirectoryPlatform diff --git a/common/src/main/java/dev/ryanhcode/sable/physics/impl/rapier/Rapier3D.java b/common/src/main/java/dev/ryanhcode/sable/physics/impl/rapier/Rapier3D.java index 9b231d7e..c743a847 100644 --- a/common/src/main/java/dev/ryanhcode/sable/physics/impl/rapier/Rapier3D.java +++ b/common/src/main/java/dev/ryanhcode/sable/physics/impl/rapier/Rapier3D.java @@ -46,13 +46,13 @@ public class Rapier3D { } private static Path resolveNativeDir() { - // Trying to use mod.jar relative path: ../.sable for using natives - final Path jarPath = getCodeSourcePath(); - if (jarPath != null && Files.isRegularFile(jarPath)) { - final Path jarRelativeDir = jarPath.getParent().resolve("..").resolve(".sable").resolve("natives") - .normalize(); - Sable.LOGGER.info("Using jar-relative Rapier native directory {}", jarRelativeDir.toAbsolutePath()); - return jarRelativeDir; + // Trying to get game directory + final Path gameDir = SableGameDirectoryPlatform.INSTANCE.getGameDirectory(); + if (gameDir != null) { + final Path gameDirRelativeDir = gameDir.resolve(".sable").resolve("natives").normalize(); + Sable.LOGGER.info("Using game-dir-relative Rapier native directory {}", + gameDirRelativeDir.toAbsolutePath()); + return gameDirRelativeDir; } // Using a bit overly generic ~/.sable directory as a fallback diff --git a/common/src/main/java/dev/ryanhcode/sable/platform/SableGameDirectoryPlatform.java b/common/src/main/java/dev/ryanhcode/sable/platform/SableGameDirectoryPlatform.java new file mode 100644 index 00000000..f95d0cf3 --- /dev/null +++ b/common/src/main/java/dev/ryanhcode/sable/platform/SableGameDirectoryPlatform.java @@ -0,0 +1,18 @@ +package dev.ryanhcode.sable.platform; + +import org.jetbrains.annotations.ApiStatus; +import org.jetbrains.annotations.Nullable; + +import java.nio.file.Path; + +@ApiStatus.Internal +public interface SableGameDirectoryPlatform { + SableGameDirectoryPlatform INSTANCE = SablePlatformUtil.load(SableGameDirectoryPlatform.class); + + /** + * @return the absolute game directory for the current loader, or {@code null} + * if it is unavailable. + */ + @Nullable + Path getGameDirectory(); +} diff --git a/fabric/src/main/java/dev/ryanhcode/sable/fabric/platform/SableGameDirectoryPlatformImpl.java b/fabric/src/main/java/dev/ryanhcode/sable/fabric/platform/SableGameDirectoryPlatformImpl.java new file mode 100644 index 00000000..72c85a58 --- /dev/null +++ b/fabric/src/main/java/dev/ryanhcode/sable/fabric/platform/SableGameDirectoryPlatformImpl.java @@ -0,0 +1,18 @@ +package dev.ryanhcode.sable.fabric.platform; + +import dev.ryanhcode.sable.platform.SableGameDirectoryPlatform; +import net.fabricmc.loader.api.FabricLoader; +import org.jetbrains.annotations.ApiStatus; +import org.jetbrains.annotations.Nullable; + +import java.nio.file.Path; + +@ApiStatus.Internal +public class SableGameDirectoryPlatformImpl implements SableGameDirectoryPlatform { + + @Override + @Nullable + public Path getGameDirectory() { + return FabricLoader.getInstance().getGameDir(); + } +} diff --git a/fabric/src/main/resources/META-INF/services/dev.ryanhcode.sable.platform.SableGameDirectoryPlatform b/fabric/src/main/resources/META-INF/services/dev.ryanhcode.sable.platform.SableGameDirectoryPlatform new file mode 100644 index 00000000..91f1ad54 --- /dev/null +++ b/fabric/src/main/resources/META-INF/services/dev.ryanhcode.sable.platform.SableGameDirectoryPlatform @@ -0,0 +1 @@ +dev.ryanhcode.sable.fabric.platform.SableGameDirectoryPlatformImpl diff --git a/neoforge/src/main/java/dev/ryanhcode/sable/neoforge/platform/SableGameDirectoryPlatformImpl.java b/neoforge/src/main/java/dev/ryanhcode/sable/neoforge/platform/SableGameDirectoryPlatformImpl.java new file mode 100644 index 00000000..7ca3a262 --- /dev/null +++ b/neoforge/src/main/java/dev/ryanhcode/sable/neoforge/platform/SableGameDirectoryPlatformImpl.java @@ -0,0 +1,18 @@ +package dev.ryanhcode.sable.neoforge.platform; + +import dev.ryanhcode.sable.platform.SableGameDirectoryPlatform; +import net.minecraftforge.fml.loading.FMLPaths; +import org.jetbrains.annotations.ApiStatus; +import org.jetbrains.annotations.Nullable; + +import java.nio.file.Path; + +@ApiStatus.Internal +public class SableGameDirectoryPlatformImpl implements SableGameDirectoryPlatform { + + @Override + @Nullable + public Path getGameDirectory() { + return FMLPaths.GAMEDIR.get(); + } +} diff --git a/neoforge/src/main/resources/META-INF/services/dev.ryanhcode.sable.platform.SableGameDirectoryPlatform b/neoforge/src/main/resources/META-INF/services/dev.ryanhcode.sable.platform.SableGameDirectoryPlatform new file mode 100644 index 00000000..a98885f0 --- /dev/null +++ b/neoforge/src/main/resources/META-INF/services/dev.ryanhcode.sable.platform.SableGameDirectoryPlatform @@ -0,0 +1 @@ +dev.ryanhcode.sable.neoforge.platform.SableGameDirectoryPlatformImpl From 7365ed4c174870fd211b897e738158ec7458edf1 Mon Sep 17 00:00:00 2001 From: nick <32414396+qurle@users.noreply.github.com> Date: Sun, 24 May 2026 15:25:17 +0000 Subject: [PATCH 3/6] moved getDirectory to SableLoaderPlatform --- .../sable/physics/impl/rapier/Rapier3D.java | 256 ++++++++++-------- .../platform/SableGameDirectoryPlatform.java | 18 -- .../sable/platform/SableLoaderPlatform.java | 9 + .../SableGameDirectoryPlatformImpl.java | 18 -- .../platform/SableLoaderPlatformImpl.java | 9 + ....sable.platform.SableGameDirectoryPlatform | 1 - .../SableGameDirectoryPlatformImpl.java | 18 -- .../platform/SableLoaderPlatformImpl.java | 22 ++ ....sable.platform.SableGameDirectoryPlatform | 1 - 9 files changed, 190 insertions(+), 162 deletions(-) delete mode 100644 common/src/main/java/dev/ryanhcode/sable/platform/SableGameDirectoryPlatform.java delete mode 100644 fabric/src/main/java/dev/ryanhcode/sable/fabric/platform/SableGameDirectoryPlatformImpl.java delete mode 100644 fabric/src/main/resources/META-INF/services/dev.ryanhcode.sable.platform.SableGameDirectoryPlatform delete mode 100644 neoforge/src/main/java/dev/ryanhcode/sable/neoforge/platform/SableGameDirectoryPlatformImpl.java delete mode 100644 neoforge/src/main/resources/META-INF/services/dev.ryanhcode.sable.platform.SableGameDirectoryPlatform diff --git a/common/src/main/java/dev/ryanhcode/sable/physics/impl/rapier/Rapier3D.java b/common/src/main/java/dev/ryanhcode/sable/physics/impl/rapier/Rapier3D.java index c743a847..db5d6a77 100644 --- a/common/src/main/java/dev/ryanhcode/sable/physics/impl/rapier/Rapier3D.java +++ b/common/src/main/java/dev/ryanhcode/sable/physics/impl/rapier/Rapier3D.java @@ -6,6 +6,7 @@ import dev.ryanhcode.sable.api.physics.mass.MassData; import dev.ryanhcode.sable.mixinterface.physics.ServerLevelSceneExtension; import dev.ryanhcode.sable.physics.impl.rapier.collider.RapierVoxelColliderData; +import dev.ryanhcode.sable.platform.SableLoaderPlatform; import net.jpountz.lz4.LZ4FrameInputStream; import net.minecraft.CrashReport; import net.minecraft.CrashReportCategory; @@ -47,7 +48,7 @@ public class Rapier3D { private static Path resolveNativeDir() { // Trying to get game directory - final Path gameDir = SableGameDirectoryPlatform.INSTANCE.getGameDirectory(); + final Path gameDir = SableLoaderPlatform.INSTANCE.getGameDirectory(); if (gameDir != null) { final Path gameDirRelativeDir = gameDir.resolve(".sable").resolve("natives").normalize(); Sable.LOGGER.info("Using game-dir-relative Rapier native directory {}", @@ -109,7 +110,7 @@ private static void loadLibrary() { Sable.LOGGER.info("Using Rapier native directory {}", dir.toAbsolutePath()); try (final LZ4FrameInputStream is2 = new LZ4FrameInputStream(is); - final ZipInputStream ti = new ZipInputStream(is2)) { + final ZipInputStream ti = new ZipInputStream(is2)) { ZipEntry entry; while ((entry = ti.getNextEntry()) != null) { @@ -131,7 +132,9 @@ private static void loadLibrary() { "Sable has failed to load the natives needed for its Rapier pipeline. Please report with system details and logs to {}", Sable.ISSUE_TRACKER_URL, t); - final CrashReport crashReport = CrashReport.forThrowable(t instanceof UnsatisfiedLinkError ? t.getCause() : t, "Sable linking with Rapier natives"); + final CrashReport crashReport = CrashReport.forThrowable( + t instanceof UnsatisfiedLinkError ? t.getCause() : + t, "Sable linking with Rapier natives"); final CrashReportCategory category = crashReport.addCategory("Natives"); category.setDetail("Name", Rapier3D.NATIVE_NAME); throw new ReportedException(crashReport); @@ -161,24 +164,26 @@ public static synchronized int nextBodyID() { @ApiStatus.Internal public static synchronized int getID(final ServerLevel level) { if (!(level instanceof final ServerLevelSceneExtension extension)) { - throw new IllegalArgumentException("ServerLevel must implement ServerLevelSceneExtension to be used with Rapier"); + throw new IllegalArgumentException( + "ServerLevel must implement ServerLevelSceneExtension to be used with Rapier"); } if (extension.sable$getSceneID() == -1) { extension.sable$setSceneID(countingSceneID++); - Sable.LOGGER.info("Assigned physics scene ID {} to {}", extension.sable$getSceneID(), level.dimension().location()); + Sable.LOGGER.info("Assigned physics scene ID {} to {}", extension.sable$getSceneID(), + level.dimension().location()); } return extension.sable$getSceneID(); } @ApiStatus.Internal - public static native void initialize(final int dimensionID, double gravityX, double gravityY, double gravityZ, double universalDrag); + public static native void initialize(final int dimensionID, double gravityX, double gravityY, double gravityZ, + double universalDrag); @ApiStatus.Internal public static native void tick(final int dimensionID, double timeStep); - @ApiStatus.Internal public static native void step(final int dimensionID, double timeStep); @@ -201,7 +206,8 @@ public static synchronized int getID(final ServerLevel level) { * [x, y, z, qx, qy, qz, qw] */ @ApiStatus.Internal - public static native void createBox(final int dimensionID, int id, double mass, double halfExtentsX, double halfExtentsY, double halfExtentsZ, double[] pose); + public static native void createBox(final int dimensionID, int id, double mass, double halfExtentsX, + double halfExtentsY, double halfExtentsZ, double[] pose); /** * All poses are formatted in a double array as: @@ -214,7 +220,8 @@ public static synchronized int getID(final ServerLevel level) { * Gets the pose of an object. * * @param id the object ID - * @param store The array to store pose of the object in the format [x, y, z, qx, qy, qz, qw] + * @param store The array to store pose of the object in the format [x, y, z, + * qx, qy, qz, qw] */ @ApiStatus.Internal public static native void getPose(final int dimensionID, int id, double[] store); @@ -242,7 +249,8 @@ public static synchronized int getID(final ServerLevel level) { * @param maxZ the maximum z bound (inclusive) */ @ApiStatus.Internal - public static native void setLocalBounds(final int dimensionID, int id, int minX, int minY, int minZ, int maxX, int maxY, int maxZ); + public static native void setLocalBounds(final int dimensionID, int id, int minX, int minY, int minZ, int maxX, + int maxY, int maxZ); /** * Sets a chunk at given chunk coordinates. @@ -250,7 +258,8 @@ public static synchronized int getID(final ServerLevel level) { * @param x the chunk x coordinate * @param y the chunk y coordinate * @param z the chunk z coordinate - * @param chunk a 4096-long (16x16x16) integer array stored in xzy order, with x fastest changing. + * @param chunk a 4096-long (16x16x16) integer array stored in xzy order, with + * x fastest changing. * @param global if the chunk is a part of the global world * @param id the object ID the chunk is in, if not global */ @@ -288,13 +297,16 @@ public static synchronized int getID(final ServerLevel level) { * @return the ID of the new block collider data entry */ @ApiStatus.Internal - protected static native int newVoxelCollider(double frictionMultiplier, double volume, double restitution, boolean isFluid, BlockSubLevelCollisionCallback contactEvents); + protected static native int newVoxelCollider(double frictionMultiplier, double volume, double restitution, + boolean isFluid, BlockSubLevelCollisionCallback contactEvents); /** * Adds a new box to a voxel collider data entry. * - * @param index the ID of the block physics data entry from {@link Rapier3D#newVoxelCollider(double, double, double, boolean, BlockSubLevelCollisionCallback)}} - * @param bounds a 6-long double array, formatted [minX, minY, minZ, maxX, maxY, maxZ] + * @param index the ID of the block physics data entry from + * {@link Rapier3D#newVoxelCollider(double, double, double, boolean, BlockSubLevelCollisionCallback)}} + * @param bounds a 6-long double array, formatted [minX, minY, minZ, maxX, maxY, + * maxZ] */ @ApiStatus.Internal public static native void addVoxelColliderBox(int index, double[] bounds); @@ -302,18 +314,21 @@ public static synchronized int getID(final ServerLevel level) { /** * Clears all boxes from a voxel collider data entry. * - * @param index the ID of the block physics data entry from {@link Rapier3D#newVoxelCollider(double, double, double, boolean, BlockSubLevelCollisionCallback)}} + * @param index the ID of the block physics data entry from + * {@link Rapier3D#newVoxelCollider(double, double, double, boolean, BlockSubLevelCollisionCallback)}} */ @ApiStatus.Internal public static native void clearVoxelColliderBoxes(int index); /** - * Sets the mass, center of mass, and inertia tensor of a block physics data entry. + * Sets the mass, center of mass, and inertia tensor of a block physics data + * entry. * * @param index the ID of the physics object */ @ApiStatus.Internal - protected static native void setMassProperties(final int dimensionID, int index, double mass, double[] centerOfMass, double[] inertiaTensor); + protected static native void setMassProperties(final int dimensionID, int index, double mass, double[] centerOfMass, + double[] inertiaTensor); /** * Allocates a new block physics data entry @@ -324,8 +339,10 @@ public static synchronized int getID(final ServerLevel level) { * @return the handle of the new block physics data entry */ @ApiStatus.Internal - public static RapierVoxelColliderData createVoxelColliderEntry(final double frictionMultiplier, final double volume, final double restitution, final boolean isFluid, final BlockSubLevelCollisionCallback contactEvents) { - return new RapierVoxelColliderData(Rapier3D.newVoxelCollider(frictionMultiplier, volume, restitution, isFluid, contactEvents)); + public static RapierVoxelColliderData createVoxelColliderEntry(final double frictionMultiplier, final double volume, + final double restitution, final boolean isFluid, final BlockSubLevelCollisionCallback contactEvents) { + return new RapierVoxelColliderData( + Rapier3D.newVoxelCollider(frictionMultiplier, volume, restitution, isFluid, contactEvents)); } /** @@ -337,10 +354,12 @@ public static RapierVoxelColliderData createVoxelColliderEntry(final double fric * @param z the new z position */ @ApiStatus.Internal - public static native void teleportObject(final int dimensionID, int id, double x, double y, double z, double i, double j, double k, double r); + public static native void teleportObject(final int dimensionID, int id, double x, double y, double z, double i, + double j, double k, double r); /** - * "Wakes up" an object, indicating environmental or other changes have occurred that should resume physics if idled or sleeping + * "Wakes up" an object, indicating environmental or other changes have occurred + * that should resume physics if idled or sleeping * * @param id the object ID */ @@ -367,20 +386,20 @@ public static RapierVoxelColliderData createVoxelColliderEntry(final double fric */ @ApiStatus.Internal public static native long addRotaryConstraint(final int dimensionID, - int id, - int otherId, - double localAnchorXA, - double localAnchorYA, - double localAnchorZA, - double localAnchorXB, - double localAnchorYB, - double localAnchorZB, - double localAxisXA, - double localAxisYA, - double localAxisZA, - double localAxisXB, - double localAxisYB, - double localAxisZB); + int id, + int otherId, + double localAnchorXA, + double localAnchorYA, + double localAnchorZA, + double localAnchorXB, + double localAnchorYB, + double localAnchorZB, + double localAxisXA, + double localAxisYA, + double localAxisZA, + double localAxisXB, + double localAxisYB, + double localAxisZB); /** * Adds a fixed constraint between two objects. @@ -393,25 +412,29 @@ public static native long addRotaryConstraint(final int dimensionID, * @param localAnchorXB the local anchor X on the second object * @param localAnchorYB the local anchor Y on the second object * @param localAnchorZB the local anchor Z on the second object - * @param localOrientationXB the local orientation X of the second object relative to the first - * @param localOrientationYB the local orientation Y of the second object relative to the first - * @param localOrientationZB the local orientation Z of the second object relative to the first - * @param localOrientationWB the local orientation W of the second object relative to the first + * @param localOrientationXB the local orientation X of the second object + * relative to the first + * @param localOrientationYB the local orientation Y of the second object + * relative to the first + * @param localOrientationZB the local orientation Z of the second object + * relative to the first + * @param localOrientationWB the local orientation W of the second object + * relative to the first */ @ApiStatus.Internal public static native long addFixedConstraint(final int dimensionID, - int id, - int otherId, - double localAnchorXA, - double localAnchorYA, - double localAnchorZA, - double localAnchorXB, - double localAnchorYB, - double localAnchorZB, - double localOrientationXB, - double localOrientationYB, - double localOrientationZB, - double localOrientationWB); + int id, + int otherId, + double localAnchorXA, + double localAnchorYA, + double localAnchorZA, + double localAnchorXB, + double localAnchorYB, + double localAnchorZB, + double localOrientationXB, + double localOrientationYB, + double localOrientationZB, + double localOrientationWB); /** * Adds a free constraint between two objects. @@ -421,18 +444,18 @@ public static native long addFixedConstraint(final int dimensionID, */ @ApiStatus.Internal public static native long addFreeConstraint(final int dimensionID, - int id, - int otherId, - double localAnchorXA, - double localAnchorYA, - double localAnchorZA, - double localAnchorXB, - double localAnchorYB, - double localAnchorZB, - double localOrientationXB, - double localOrientationYB, - double localOrientationZB, - double localOrientationWB); + int id, + int otherId, + double localAnchorXA, + double localAnchorYA, + double localAnchorZA, + double localAnchorXB, + double localAnchorYB, + double localAnchorZB, + double localOrientationXB, + double localOrientationYB, + double localOrientationZB, + double localOrientationWB); /** * Adds a generic constraint between two objects. @@ -453,27 +476,29 @@ public static native long addFreeConstraint(final int dimensionID, * @param localOrientationYB the local orientation Y of the second object * @param localOrientationZB the local orientation Z of the second object * @param localOrientationWB the local orientation W of the second object - * @param lockedAxesMask bit mask of locked axes; bit {@code n} corresponds to {@link dev.ryanhcode.sable.api.physics.constraint.ConstraintJointAxis#ordinal()} + * @param lockedAxesMask bit mask of locked axes; bit {@code n} corresponds + * to + * {@link dev.ryanhcode.sable.api.physics.constraint.ConstraintJointAxis#ordinal()} */ @ApiStatus.Internal public static native long addGenericConstraint(final int dimensionID, - int id, - int otherId, - double localAnchorXA, - double localAnchorYA, - double localAnchorZA, - double localOrientationXA, - double localOrientationYA, - double localOrientationZA, - double localOrientationWA, - double localAnchorXB, - double localAnchorYB, - double localAnchorZB, - double localOrientationXB, - double localOrientationYB, - double localOrientationZB, - double localOrientationWB, - int lockedAxesMask); + int id, + int otherId, + double localAnchorXA, + double localAnchorYA, + double localAnchorZA, + double localOrientationXA, + double localOrientationYA, + double localOrientationZA, + double localOrientationWA, + double localAnchorXB, + double localAnchorYB, + double localAnchorZB, + double localOrientationXB, + double localOrientationYB, + double localOrientationZB, + double localOrientationWB, + int lockedAxesMask); /** * Sets the local frame on one side of a constraint. @@ -482,7 +507,9 @@ public static native long addGenericConstraint(final int dimensionID, * @param side {@code 0} for the first body, {@code 1} for the second body */ @ApiStatus.Internal - public static native void setConstraintFrame(final int dimensionID, long handle, int side, double localPosX, double localPosY, double localPosZ, double localOrientationX, double localOrientationY, double localOrientationZ, double localOrientationW); + public static native void setConstraintFrame(final int dimensionID, long handle, int side, double localPosX, + double localPosY, double localPosZ, double localOrientationX, double localOrientationY, + double localOrientationZ, double localOrientationW); /** * Sets if contacts are enabled between the two bodies in the constraint @@ -516,15 +543,16 @@ public static native long addGenericConstraint(final int dimensionID, @ApiStatus.Internal public static native void removeConstraint(final int dimensionID, long handle); - /** - * Sets a constraint to a servo, with a desired angle and PD controller coefficients. + * Sets a constraint to a servo, with a desired angle and PD controller + * coefficients. * * @param dimensionID the ID of the dimension * @param handle the handle of the constraint */ @ApiStatus.Internal - public static native void setConstraintMotor(final int dimensionID, long handle, int axis, double desiredPosition, double stiffness, double damping, boolean hasForceLimit, double maxForce); + public static native void setConstraintMotor(final int dimensionID, long handle, int axis, double desiredPosition, + double stiffness, double damping, boolean hasForceLimit, double maxForce); /** * Adds linear and angular velocities @@ -538,13 +566,15 @@ public static native long addGenericConstraint(final int dimensionID, * @param angularZ z component of the angular velocity to add [rad/s] */ @ApiStatus.Internal - public static native void addLinearAngularVelocities(final int dimensionID, int bodyId, double linearX, double linearY, double linearZ, double angularX, double angularY, double angularZ, final boolean wakeUp); + public static native void addLinearAngularVelocities(final int dimensionID, int bodyId, double linearX, + double linearY, double linearZ, double angularX, double angularY, double angularZ, final boolean wakeUp); /** * Reads & clears all reported collisions from the physics engine. *
* Each collision is formatted as: - * [body_a, body_b, force_amount, local_normal_a, local_normal_b, local_point_a, local_point_b] + * [body_a, body_b, force_amount, local_normal_a, local_normal_b, local_point_a, + * local_point_b] */ @ApiStatus.Internal public static native double[] clearCollisions(int dimensionID); @@ -561,7 +591,8 @@ public static native long addGenericConstraint(final int dimensionID, * @param fz the z component of the force to apply [N] */ @ApiStatus.Internal - public static native void applyForce(final int dimensionID, final int bodyID, final double x, final double y, final double z, final double fx, final double fy, final double fz, final boolean wakeUp); + public static native void applyForce(final int dimensionID, final int bodyID, final double x, final double y, + final double z, final double fx, final double fy, final double fz, final boolean wakeUp); /** * Applies a force to a given body @@ -575,13 +606,15 @@ public static native long addGenericConstraint(final int dimensionID, * @param tz the z component of the torque to apply [Nm] */ @ApiStatus.Internal - public static native void applyForceAndTorque(final int dimensionID, final int bodyID, final double fx, final double fy, final double fz, final double tx, final double ty, final double tz, final boolean wakeUp); + public static native void applyForceAndTorque(final int dimensionID, final int bodyID, final double fx, + final double fy, final double fz, final double tx, final double ty, final double tz, final boolean wakeUp); /** * Gets the linear velocity of a given body * * @param bodyID the ID of an already created rigid-body - * @param store The array to store the linear velocity of the body in the format [x, y, z] + * @param store The array to store the linear velocity of the body in the + * format [x, y, z] */ @ApiStatus.Internal public static native void getLinearVelocity(final int dimensionID, final int bodyID, final double[] store); @@ -590,7 +623,8 @@ public static native long addGenericConstraint(final int dimensionID, * Gets the angular velocity of a given body * * @param bodyID the ID of an already created rigid-body - * @param store The array to store the angular velocity of the body in the format [x, y, z] + * @param store The array to store the angular velocity of the body in the + * format [x, y, z] */ @ApiStatus.Internal public static native void getAngularVelocity(final int dimensionID, final int bodyID, final double[] store); @@ -601,7 +635,8 @@ public static native long addGenericConstraint(final int dimensionID, * @param sceneId the scene ID * @param mountId the mount rigid body ID (or -1 for ground) * @param id the kinematic sub-level ID - * @param pose a 7-long double array, formatted [x, y, z, qx, qy, qz, qw] for position and quaternion + * @param pose a 7-long double array, formatted [x, y, z, qx, qy, qz, qw] for + * position and quaternion */ @ApiStatus.Internal public static native void createKinematicContraption(final int sceneId, int mountId, int id, double[] pose); @@ -616,14 +651,17 @@ public static native long addGenericConstraint(final int dimensionID, public static native void removeKinematicContraption(final int sceneId, int id); /** - * Sets the transform (position/quaternion) of a kinematic sub-level's center of mass relative to its parent. + * Sets the transform (position/quaternion) of a kinematic sub-level's center of + * mass relative to its parent. * * @param sceneId the scene ID * @param id the kinematic sub-level ID - * @param pose a 7-long double array, formatted [x, y, z, qx, qy, qz, qw] for position and quaternion + * @param pose a 7-long double array, formatted [x, y, z, qx, qy, qz, qw] for + * position and quaternion */ @ApiStatus.Internal - public static native void setKinematicContraptionTransform(final int sceneId, int id, double[] centerOfMass, double[] pose, double[] velocities); + public static native void setKinematicContraptionTransform(final int sceneId, int id, double[] centerOfMass, + double[] pose, double[] velocities); /** * Adds a chunk to a kinematic sub-level (4096 blocks, each as packed int). @@ -633,10 +671,12 @@ public static native long addGenericConstraint(final int dimensionID, * @param x the chunk x coordinate * @param y the chunk y coordinate * @param z the chunk z coordinate - * @param data a 4096-long int array containing packed block data (block_collider_id << 16 | voxel_state_id) + * @param data a 4096-long int array containing packed block data + * (block_collider_id << 16 | voxel_state_id) */ @ApiStatus.Internal - public static native void addKinematicContraptionChunkSection(final int sceneId, int id, int x, int y, int z, int[] data); + public static native void addKinematicContraptionChunkSection(final int sceneId, int id, int x, int y, int z, + int[] data); /** * Creates a rope @@ -644,7 +684,8 @@ public static native long addGenericConstraint(final int dimensionID, * @return a rope id */ @ApiStatus.Internal - public static native long createRope(final int dimensionID, final double pointRadius, final double firstJointLength, final double[] points, final int pointCount); + public static native long createRope(final int dimensionID, final double pointRadius, final double firstJointLength, + final double[] points, final int pointCount); /** * Removes a rope @@ -655,10 +696,12 @@ public static native long addGenericConstraint(final int dimensionID, public static native long removeRope(final int dimensionID, final long ropeId); @ApiStatus.Internal - public static native void setRopeAttachment(final int dimensionID, final long ropeId, final int subLevelId, final double x, final double y, final double z, final boolean end); + public static native void setRopeAttachment(final int dimensionID, final long ropeId, final int subLevelId, + final double x, final double y, final double z, final boolean end); @ApiStatus.Internal - public static native void addRopePointAtStart(final int dimensionID, final long ropeId, final double x, final double y, final double z); + public static native void addRopePointAtStart(final int dimensionID, final long ropeId, final double x, + final double y, final double z); @ApiStatus.Internal public static native void removeRopePointAtStart(final int dimensionID, final long ropeId); @@ -667,8 +710,8 @@ public static native long addGenericConstraint(final int dimensionID, public static native void wakeUpRope(final int dimensionID, final long ropeId); @ApiStatus.Internal - public static native void setRopeFirstSegmentLength(final int dimensionID, final long ropeId, final double firstSegmentLength); - + public static native void setRopeFirstSegmentLength(final int dimensionID, final long ropeId, + final double firstSegmentLength); /** * Queries a rope @@ -684,7 +727,8 @@ public static native void configFrequencyAndDamping( double contactDampingRatio); @ApiStatus.Internal - public static native void configSolverIterations(int solverIterations, int pgsIterations, int stabilizationIterations); + public static native void configSolverIterations(int solverIterations, int pgsIterations, + int stabilizationIterations); @ApiStatus.Internal public static native void configMinIslandSize(int islandSize); @@ -699,9 +743,9 @@ public static void setMassPropertiesFrom(final int dimensionID, final int id, fi final double mass = massTracker.getMass(); // This is only called in one location and the center of mass can't be null - //noinspection DataFlowIssue - final double[] centerOfMassArray = new double[]{centerOfMass.x(), centerOfMass.y(), centerOfMass.z()}; - final double[] inertiaTensorArray = new double[]{ + // noinspection DataFlowIssue + final double[] centerOfMassArray = new double[] { centerOfMass.x(), centerOfMass.y(), centerOfMass.z() }; + final double[] inertiaTensorArray = new double[] { inertiaTensor.m00(), inertiaTensor.m01(), inertiaTensor.m02(), inertiaTensor.m10(), inertiaTensor.m11(), inertiaTensor.m12(), inertiaTensor.m20(), inertiaTensor.m21(), inertiaTensor.m22() diff --git a/common/src/main/java/dev/ryanhcode/sable/platform/SableGameDirectoryPlatform.java b/common/src/main/java/dev/ryanhcode/sable/platform/SableGameDirectoryPlatform.java deleted file mode 100644 index f95d0cf3..00000000 --- a/common/src/main/java/dev/ryanhcode/sable/platform/SableGameDirectoryPlatform.java +++ /dev/null @@ -1,18 +0,0 @@ -package dev.ryanhcode.sable.platform; - -import org.jetbrains.annotations.ApiStatus; -import org.jetbrains.annotations.Nullable; - -import java.nio.file.Path; - -@ApiStatus.Internal -public interface SableGameDirectoryPlatform { - SableGameDirectoryPlatform INSTANCE = SablePlatformUtil.load(SableGameDirectoryPlatform.class); - - /** - * @return the absolute game directory for the current loader, or {@code null} - * if it is unavailable. - */ - @Nullable - Path getGameDirectory(); -} diff --git a/common/src/main/java/dev/ryanhcode/sable/platform/SableLoaderPlatform.java b/common/src/main/java/dev/ryanhcode/sable/platform/SableLoaderPlatform.java index 174e3946..5671d445 100644 --- a/common/src/main/java/dev/ryanhcode/sable/platform/SableLoaderPlatform.java +++ b/common/src/main/java/dev/ryanhcode/sable/platform/SableLoaderPlatform.java @@ -1,10 +1,19 @@ package dev.ryanhcode.sable.platform; import org.jetbrains.annotations.ApiStatus; +import org.jetbrains.annotations.Nullable; + +import java.nio.file.Path; @ApiStatus.Internal public interface SableLoaderPlatform { SableLoaderPlatform INSTANCE = SablePlatformUtil.load(SableLoaderPlatform.class); String getModVersion(String modId); + + /** + * @return the absolute game directory for the current loader, or {@code null} if it is unavailable. + */ + @Nullable + Path getGameDirectory(); } diff --git a/fabric/src/main/java/dev/ryanhcode/sable/fabric/platform/SableGameDirectoryPlatformImpl.java b/fabric/src/main/java/dev/ryanhcode/sable/fabric/platform/SableGameDirectoryPlatformImpl.java deleted file mode 100644 index 72c85a58..00000000 --- a/fabric/src/main/java/dev/ryanhcode/sable/fabric/platform/SableGameDirectoryPlatformImpl.java +++ /dev/null @@ -1,18 +0,0 @@ -package dev.ryanhcode.sable.fabric.platform; - -import dev.ryanhcode.sable.platform.SableGameDirectoryPlatform; -import net.fabricmc.loader.api.FabricLoader; -import org.jetbrains.annotations.ApiStatus; -import org.jetbrains.annotations.Nullable; - -import java.nio.file.Path; - -@ApiStatus.Internal -public class SableGameDirectoryPlatformImpl implements SableGameDirectoryPlatform { - - @Override - @Nullable - public Path getGameDirectory() { - return FabricLoader.getInstance().getGameDir(); - } -} diff --git a/fabric/src/main/java/dev/ryanhcode/sable/fabric/platform/SableLoaderPlatformImpl.java b/fabric/src/main/java/dev/ryanhcode/sable/fabric/platform/SableLoaderPlatformImpl.java index c5711e91..dfb9c1cd 100644 --- a/fabric/src/main/java/dev/ryanhcode/sable/fabric/platform/SableLoaderPlatformImpl.java +++ b/fabric/src/main/java/dev/ryanhcode/sable/fabric/platform/SableLoaderPlatformImpl.java @@ -2,6 +2,9 @@ import dev.ryanhcode.sable.platform.SableLoaderPlatform; import net.fabricmc.loader.api.FabricLoader; +import org.jetbrains.annotations.Nullable; + +import java.nio.file.Path; public class SableLoaderPlatformImpl implements SableLoaderPlatform { @Override @@ -13,4 +16,10 @@ public String getModVersion(final String modId) { .getVersion() .getFriendlyString(); } + + @Override + @Nullable + public Path getGameDirectory() { + return FabricLoader.getInstance().getGameDir(); + } } diff --git a/fabric/src/main/resources/META-INF/services/dev.ryanhcode.sable.platform.SableGameDirectoryPlatform b/fabric/src/main/resources/META-INF/services/dev.ryanhcode.sable.platform.SableGameDirectoryPlatform deleted file mode 100644 index 91f1ad54..00000000 --- a/fabric/src/main/resources/META-INF/services/dev.ryanhcode.sable.platform.SableGameDirectoryPlatform +++ /dev/null @@ -1 +0,0 @@ -dev.ryanhcode.sable.fabric.platform.SableGameDirectoryPlatformImpl diff --git a/neoforge/src/main/java/dev/ryanhcode/sable/neoforge/platform/SableGameDirectoryPlatformImpl.java b/neoforge/src/main/java/dev/ryanhcode/sable/neoforge/platform/SableGameDirectoryPlatformImpl.java deleted file mode 100644 index 7ca3a262..00000000 --- a/neoforge/src/main/java/dev/ryanhcode/sable/neoforge/platform/SableGameDirectoryPlatformImpl.java +++ /dev/null @@ -1,18 +0,0 @@ -package dev.ryanhcode.sable.neoforge.platform; - -import dev.ryanhcode.sable.platform.SableGameDirectoryPlatform; -import net.minecraftforge.fml.loading.FMLPaths; -import org.jetbrains.annotations.ApiStatus; -import org.jetbrains.annotations.Nullable; - -import java.nio.file.Path; - -@ApiStatus.Internal -public class SableGameDirectoryPlatformImpl implements SableGameDirectoryPlatform { - - @Override - @Nullable - public Path getGameDirectory() { - return FMLPaths.GAMEDIR.get(); - } -} diff --git a/neoforge/src/main/java/dev/ryanhcode/sable/neoforge/platform/SableLoaderPlatformImpl.java b/neoforge/src/main/java/dev/ryanhcode/sable/neoforge/platform/SableLoaderPlatformImpl.java index d06c1563..c9348890 100644 --- a/neoforge/src/main/java/dev/ryanhcode/sable/neoforge/platform/SableLoaderPlatformImpl.java +++ b/neoforge/src/main/java/dev/ryanhcode/sable/neoforge/platform/SableLoaderPlatformImpl.java @@ -2,10 +2,32 @@ import dev.ryanhcode.sable.platform.SableLoaderPlatform; import net.neoforged.fml.loading.LoadingModList; +import org.jetbrains.annotations.Nullable; + +import java.nio.file.Path; +import java.nio.file.Paths; public class SableLoaderPlatformImpl implements SableLoaderPlatform { @Override public String getModVersion(final String modId) { return LoadingModList.get().getModFileById(modId).versionString(); } + + @Override + @Nullable + public Path getGameDirectory() { + try { + final Class> fmlPathsClass = Class.forName("net.neoforged.fml.loading.FMLPaths"); + final Object gameDirSupplier = fmlPathsClass.getField("GAMEDIR").get(null); + final Object gameDir = gameDirSupplier.getClass().getMethod("get").invoke(gameDirSupplier); + if (gameDir instanceof Path path) { + return path; + } + if (gameDir != null) { + return Paths.get(gameDir.toString()); + } + } catch (final ReflectiveOperationException | SecurityException ignored) { + } + return null; + } } diff --git a/neoforge/src/main/resources/META-INF/services/dev.ryanhcode.sable.platform.SableGameDirectoryPlatform b/neoforge/src/main/resources/META-INF/services/dev.ryanhcode.sable.platform.SableGameDirectoryPlatform deleted file mode 100644 index a98885f0..00000000 --- a/neoforge/src/main/resources/META-INF/services/dev.ryanhcode.sable.platform.SableGameDirectoryPlatform +++ /dev/null @@ -1 +0,0 @@ -dev.ryanhcode.sable.neoforge.platform.SableGameDirectoryPlatformImpl From 96a67f99ae54010c52449c5bbbbdac5303a5381e Mon Sep 17 00:00:00 2001 From: nick <32414396+qurle@users.noreply.github.com> Date: Sun, 24 May 2026 16:54:33 +0000 Subject: [PATCH 4/6] Cleaned up Rapier3D, fixed formatting --- .../sable/physics/impl/rapier/Rapier3D.java | 269 +++++++----------- 1 file changed, 107 insertions(+), 162 deletions(-) diff --git a/common/src/main/java/dev/ryanhcode/sable/physics/impl/rapier/Rapier3D.java b/common/src/main/java/dev/ryanhcode/sable/physics/impl/rapier/Rapier3D.java index db5d6a77..086acaff 100644 --- a/common/src/main/java/dev/ryanhcode/sable/physics/impl/rapier/Rapier3D.java +++ b/common/src/main/java/dev/ryanhcode/sable/physics/impl/rapier/Rapier3D.java @@ -63,15 +63,6 @@ private static Path resolveNativeDir() { return fallbackDir; } - private static Path getCodeSourcePath() { - try { - return Paths.get(Rapier3D.class.getProtectionDomain().getCodeSource().getLocation().toURI()); - } catch (final URISyntaxException | SecurityException e) { - Sable.LOGGER.debug("Unable to resolve Rapier code source path, falling back to user home", e); - return null; - } - } - private static String getNativeName() { final String arch; if (System.getProperty("os.arch").equals("arm") || System.getProperty("os.arch").startsWith("aarch64")) { @@ -87,17 +78,14 @@ private static String getNativeName() { return LIB_NAME + "_" + arch + "_macos.dylib"; } else { if (os != OS.LINUX) { - Sable.LOGGER.error( - "Unknown platform '{}' detected, sable will attempt to use linux natives, this may or may not work.", - System.getProperty("os.name")); + Sable.LOGGER.error("Unknown platform '{}' detected, sable will attempt to use linux natives, this may or may not work.", System.getProperty("os.name")); } return LIB_NAME + "_" + arch + "_linux.so"; } } private static void loadLibrary() { - try (final InputStream is = Rapier3D.class - .getResourceAsStream("/natives/" + LIB_NAME + "/sable_rapier_binaries.zip.l4z")) { + try (final InputStream is = Rapier3D.class.getResourceAsStream("/natives/" + LIB_NAME + "/sable_rapier_binaries.zip.l4z")) { if (is == null) { throw new FileNotFoundException("sable_rapier_binaries.zip.l4z"); } @@ -110,7 +98,7 @@ private static void loadLibrary() { Sable.LOGGER.info("Using Rapier native directory {}", dir.toAbsolutePath()); try (final LZ4FrameInputStream is2 = new LZ4FrameInputStream(is); - final ZipInputStream ti = new ZipInputStream(is2)) { + final ZipInputStream ti = new ZipInputStream(is2)) { ZipEntry entry; while ((entry = ti.getNextEntry()) != null) { @@ -132,9 +120,7 @@ private static void loadLibrary() { "Sable has failed to load the natives needed for its Rapier pipeline. Please report with system details and logs to {}", Sable.ISSUE_TRACKER_URL, t); - final CrashReport crashReport = CrashReport.forThrowable( - t instanceof UnsatisfiedLinkError ? t.getCause() : - t, "Sable linking with Rapier natives"); + final CrashReport crashReport = CrashReport.forThrowable(t instanceof UnsatisfiedLinkError ? t.getCause() : t, "Sable linking with Rapier natives"); final CrashReportCategory category = crashReport.addCategory("Natives"); category.setDetail("Name", Rapier3D.NATIVE_NAME); throw new ReportedException(crashReport); @@ -164,26 +150,24 @@ public static synchronized int nextBodyID() { @ApiStatus.Internal public static synchronized int getID(final ServerLevel level) { if (!(level instanceof final ServerLevelSceneExtension extension)) { - throw new IllegalArgumentException( - "ServerLevel must implement ServerLevelSceneExtension to be used with Rapier"); + throw new IllegalArgumentException("ServerLevel must implement ServerLevelSceneExtension to be used with Rapier"); } if (extension.sable$getSceneID() == -1) { extension.sable$setSceneID(countingSceneID++); - Sable.LOGGER.info("Assigned physics scene ID {} to {}", extension.sable$getSceneID(), - level.dimension().location()); + Sable.LOGGER.info("Assigned physics scene ID {} to {}", extension.sable$getSceneID(), level.dimension().location()); } return extension.sable$getSceneID(); } @ApiStatus.Internal - public static native void initialize(final int dimensionID, double gravityX, double gravityY, double gravityZ, - double universalDrag); + public static native void initialize(final int dimensionID, double gravityX, double gravityY, double gravityZ, double universalDrag); @ApiStatus.Internal public static native void tick(final int dimensionID, double timeStep); + @ApiStatus.Internal public static native void step(final int dimensionID, double timeStep); @@ -206,8 +190,7 @@ public static native void initialize(final int dimensionID, double gravityX, dou * [x, y, z, qx, qy, qz, qw] */ @ApiStatus.Internal - public static native void createBox(final int dimensionID, int id, double mass, double halfExtentsX, - double halfExtentsY, double halfExtentsZ, double[] pose); + public static native void createBox(final int dimensionID, int id, double mass, double halfExtentsX, double halfExtentsY, double halfExtentsZ, double[] pose); /** * All poses are formatted in a double array as: @@ -220,8 +203,7 @@ public static native void createBox(final int dimensionID, int id, double mass, * Gets the pose of an object. * * @param id the object ID - * @param store The array to store pose of the object in the format [x, y, z, - * qx, qy, qz, qw] + * @param store The array to store pose of the object in the format [x, y, z, qx, qy, qz, qw] */ @ApiStatus.Internal public static native void getPose(final int dimensionID, int id, double[] store); @@ -249,8 +231,7 @@ public static native void createBox(final int dimensionID, int id, double mass, * @param maxZ the maximum z bound (inclusive) */ @ApiStatus.Internal - public static native void setLocalBounds(final int dimensionID, int id, int minX, int minY, int minZ, int maxX, - int maxY, int maxZ); + public static native void setLocalBounds(final int dimensionID, int id, int minX, int minY, int minZ, int maxX, int maxY, int maxZ); /** * Sets a chunk at given chunk coordinates. @@ -258,8 +239,7 @@ public static native void setLocalBounds(final int dimensionID, int id, int minX * @param x the chunk x coordinate * @param y the chunk y coordinate * @param z the chunk z coordinate - * @param chunk a 4096-long (16x16x16) integer array stored in xzy order, with - * x fastest changing. + * @param chunk a 4096-long (16x16x16) integer array stored in xzy order, with x fastest changing. * @param global if the chunk is a part of the global world * @param id the object ID the chunk is in, if not global */ @@ -297,16 +277,13 @@ public static native void setLocalBounds(final int dimensionID, int id, int minX * @return the ID of the new block collider data entry */ @ApiStatus.Internal - protected static native int newVoxelCollider(double frictionMultiplier, double volume, double restitution, - boolean isFluid, BlockSubLevelCollisionCallback contactEvents); + protected static native int newVoxelCollider(double frictionMultiplier, double volume, double restitution, boolean isFluid, BlockSubLevelCollisionCallback contactEvents); /** * Adds a new box to a voxel collider data entry. * - * @param index the ID of the block physics data entry from - * {@link Rapier3D#newVoxelCollider(double, double, double, boolean, BlockSubLevelCollisionCallback)}} - * @param bounds a 6-long double array, formatted [minX, minY, minZ, maxX, maxY, - * maxZ] + * @param index the ID of the block physics data entry from {@link Rapier3D#newVoxelCollider(double, double, double, boolean, BlockSubLevelCollisionCallback)}} + * @param bounds a 6-long double array, formatted [minX, minY, minZ, maxX, maxY, maxZ] */ @ApiStatus.Internal public static native void addVoxelColliderBox(int index, double[] bounds); @@ -314,21 +291,18 @@ protected static native int newVoxelCollider(double frictionMultiplier, double v /** * Clears all boxes from a voxel collider data entry. * - * @param index the ID of the block physics data entry from - * {@link Rapier3D#newVoxelCollider(double, double, double, boolean, BlockSubLevelCollisionCallback)}} + * @param index the ID of the block physics data entry from {@link Rapier3D#newVoxelCollider(double, double, double, boolean, BlockSubLevelCollisionCallback)}} */ @ApiStatus.Internal public static native void clearVoxelColliderBoxes(int index); /** - * Sets the mass, center of mass, and inertia tensor of a block physics data - * entry. + * Sets the mass, center of mass, and inertia tensor of a block physics data entry. * * @param index the ID of the physics object */ @ApiStatus.Internal - protected static native void setMassProperties(final int dimensionID, int index, double mass, double[] centerOfMass, - double[] inertiaTensor); + protected static native void setMassProperties(final int dimensionID, int index, double mass, double[] centerOfMass, double[] inertiaTensor); /** * Allocates a new block physics data entry @@ -339,10 +313,8 @@ protected static native void setMassProperties(final int dimensionID, int index, * @return the handle of the new block physics data entry */ @ApiStatus.Internal - public static RapierVoxelColliderData createVoxelColliderEntry(final double frictionMultiplier, final double volume, - final double restitution, final boolean isFluid, final BlockSubLevelCollisionCallback contactEvents) { - return new RapierVoxelColliderData( - Rapier3D.newVoxelCollider(frictionMultiplier, volume, restitution, isFluid, contactEvents)); + public static RapierVoxelColliderData createVoxelColliderEntry(final double frictionMultiplier, final double volume, final double restitution, final boolean isFluid, final BlockSubLevelCollisionCallback contactEvents) { + return new RapierVoxelColliderData(Rapier3D.newVoxelCollider(frictionMultiplier, volume, restitution, isFluid, contactEvents)); } /** @@ -354,12 +326,10 @@ public static RapierVoxelColliderData createVoxelColliderEntry(final double fric * @param z the new z position */ @ApiStatus.Internal - public static native void teleportObject(final int dimensionID, int id, double x, double y, double z, double i, - double j, double k, double r); + public static native void teleportObject(final int dimensionID, int id, double x, double y, double z, double i, double j, double k, double r); /** - * "Wakes up" an object, indicating environmental or other changes have occurred - * that should resume physics if idled or sleeping + * "Wakes up" an object, indicating environmental or other changes have occurred that should resume physics if idled or sleeping * * @param id the object ID */ @@ -386,20 +356,20 @@ public static native void teleportObject(final int dimensionID, int id, double x */ @ApiStatus.Internal public static native long addRotaryConstraint(final int dimensionID, - int id, - int otherId, - double localAnchorXA, - double localAnchorYA, - double localAnchorZA, - double localAnchorXB, - double localAnchorYB, - double localAnchorZB, - double localAxisXA, - double localAxisYA, - double localAxisZA, - double localAxisXB, - double localAxisYB, - double localAxisZB); + int id, + int otherId, + double localAnchorXA, + double localAnchorYA, + double localAnchorZA, + double localAnchorXB, + double localAnchorYB, + double localAnchorZB, + double localAxisXA, + double localAxisYA, + double localAxisZA, + double localAxisXB, + double localAxisYB, + double localAxisZB); /** * Adds a fixed constraint between two objects. @@ -412,29 +382,25 @@ public static native long addRotaryConstraint(final int dimensionID, * @param localAnchorXB the local anchor X on the second object * @param localAnchorYB the local anchor Y on the second object * @param localAnchorZB the local anchor Z on the second object - * @param localOrientationXB the local orientation X of the second object - * relative to the first - * @param localOrientationYB the local orientation Y of the second object - * relative to the first - * @param localOrientationZB the local orientation Z of the second object - * relative to the first - * @param localOrientationWB the local orientation W of the second object - * relative to the first + * @param localOrientationXB the local orientation X of the second object relative to the first + * @param localOrientationYB the local orientation Y of the second object relative to the first + * @param localOrientationZB the local orientation Z of the second object relative to the first + * @param localOrientationWB the local orientation W of the second object relative to the first */ @ApiStatus.Internal public static native long addFixedConstraint(final int dimensionID, - int id, - int otherId, - double localAnchorXA, - double localAnchorYA, - double localAnchorZA, - double localAnchorXB, - double localAnchorYB, - double localAnchorZB, - double localOrientationXB, - double localOrientationYB, - double localOrientationZB, - double localOrientationWB); + int id, + int otherId, + double localAnchorXA, + double localAnchorYA, + double localAnchorZA, + double localAnchorXB, + double localAnchorYB, + double localAnchorZB, + double localOrientationXB, + double localOrientationYB, + double localOrientationZB, + double localOrientationWB); /** * Adds a free constraint between two objects. @@ -444,18 +410,18 @@ public static native long addFixedConstraint(final int dimensionID, */ @ApiStatus.Internal public static native long addFreeConstraint(final int dimensionID, - int id, - int otherId, - double localAnchorXA, - double localAnchorYA, - double localAnchorZA, - double localAnchorXB, - double localAnchorYB, - double localAnchorZB, - double localOrientationXB, - double localOrientationYB, - double localOrientationZB, - double localOrientationWB); + int id, + int otherId, + double localAnchorXA, + double localAnchorYA, + double localAnchorZA, + double localAnchorXB, + double localAnchorYB, + double localAnchorZB, + double localOrientationXB, + double localOrientationYB, + double localOrientationZB, + double localOrientationWB); /** * Adds a generic constraint between two objects. @@ -476,29 +442,27 @@ public static native long addFreeConstraint(final int dimensionID, * @param localOrientationYB the local orientation Y of the second object * @param localOrientationZB the local orientation Z of the second object * @param localOrientationWB the local orientation W of the second object - * @param lockedAxesMask bit mask of locked axes; bit {@code n} corresponds - * to - * {@link dev.ryanhcode.sable.api.physics.constraint.ConstraintJointAxis#ordinal()} + * @param lockedAxesMask bit mask of locked axes; bit {@code n} corresponds to {@link dev.ryanhcode.sable.api.physics.constraint.ConstraintJointAxis#ordinal()} */ @ApiStatus.Internal public static native long addGenericConstraint(final int dimensionID, - int id, - int otherId, - double localAnchorXA, - double localAnchorYA, - double localAnchorZA, - double localOrientationXA, - double localOrientationYA, - double localOrientationZA, - double localOrientationWA, - double localAnchorXB, - double localAnchorYB, - double localAnchorZB, - double localOrientationXB, - double localOrientationYB, - double localOrientationZB, - double localOrientationWB, - int lockedAxesMask); + int id, + int otherId, + double localAnchorXA, + double localAnchorYA, + double localAnchorZA, + double localOrientationXA, + double localOrientationYA, + double localOrientationZA, + double localOrientationWA, + double localAnchorXB, + double localAnchorYB, + double localAnchorZB, + double localOrientationXB, + double localOrientationYB, + double localOrientationZB, + double localOrientationWB, + int lockedAxesMask); /** * Sets the local frame on one side of a constraint. @@ -507,9 +471,7 @@ public static native long addGenericConstraint(final int dimensionID, * @param side {@code 0} for the first body, {@code 1} for the second body */ @ApiStatus.Internal - public static native void setConstraintFrame(final int dimensionID, long handle, int side, double localPosX, - double localPosY, double localPosZ, double localOrientationX, double localOrientationY, - double localOrientationZ, double localOrientationW); + public static native void setConstraintFrame(final int dimensionID, long handle, int side, double localPosX, double localPosY, double localPosZ, double localOrientationX, double localOrientationY, double localOrientationZ, double localOrientationW); /** * Sets if contacts are enabled between the two bodies in the constraint @@ -543,16 +505,15 @@ public static native void setConstraintFrame(final int dimensionID, long handle, @ApiStatus.Internal public static native void removeConstraint(final int dimensionID, long handle); + /** - * Sets a constraint to a servo, with a desired angle and PD controller - * coefficients. + * Sets a constraint to a servo, with a desired angle and PD controller coefficients. * * @param dimensionID the ID of the dimension * @param handle the handle of the constraint */ @ApiStatus.Internal - public static native void setConstraintMotor(final int dimensionID, long handle, int axis, double desiredPosition, - double stiffness, double damping, boolean hasForceLimit, double maxForce); + public static native void setConstraintMotor(final int dimensionID, long handle, int axis, double desiredPosition, double stiffness, double damping, boolean hasForceLimit, double maxForce); /** * Adds linear and angular velocities @@ -566,15 +527,13 @@ public static native void setConstraintMotor(final int dimensionID, long handle, * @param angularZ z component of the angular velocity to add [rad/s] */ @ApiStatus.Internal - public static native void addLinearAngularVelocities(final int dimensionID, int bodyId, double linearX, - double linearY, double linearZ, double angularX, double angularY, double angularZ, final boolean wakeUp); + public static native void addLinearAngularVelocities(final int dimensionID, int bodyId, double linearX, double linearY, double linearZ, double angularX, double angularY, double angularZ, final boolean wakeUp); /** * Reads & clears all reported collisions from the physics engine. *
* Each collision is formatted as: - * [body_a, body_b, force_amount, local_normal_a, local_normal_b, local_point_a, - * local_point_b] + * [body_a, body_b, force_amount, local_normal_a, local_normal_b, local_point_a, local_point_b] */ @ApiStatus.Internal public static native double[] clearCollisions(int dimensionID); @@ -591,8 +550,7 @@ public static native void addLinearAngularVelocities(final int dimensionID, int * @param fz the z component of the force to apply [N] */ @ApiStatus.Internal - public static native void applyForce(final int dimensionID, final int bodyID, final double x, final double y, - final double z, final double fx, final double fy, final double fz, final boolean wakeUp); + public static native void applyForce(final int dimensionID, final int bodyID, final double x, final double y, final double z, final double fx, final double fy, final double fz, final boolean wakeUp); /** * Applies a force to a given body @@ -606,15 +564,13 @@ public static native void applyForce(final int dimensionID, final int bodyID, fi * @param tz the z component of the torque to apply [Nm] */ @ApiStatus.Internal - public static native void applyForceAndTorque(final int dimensionID, final int bodyID, final double fx, - final double fy, final double fz, final double tx, final double ty, final double tz, final boolean wakeUp); + public static native void applyForceAndTorque(final int dimensionID, final int bodyID, final double fx, final double fy, final double fz, final double tx, final double ty, final double tz, final boolean wakeUp); /** * Gets the linear velocity of a given body * * @param bodyID the ID of an already created rigid-body - * @param store The array to store the linear velocity of the body in the - * format [x, y, z] + * @param store The array to store the linear velocity of the body in the format [x, y, z] */ @ApiStatus.Internal public static native void getLinearVelocity(final int dimensionID, final int bodyID, final double[] store); @@ -623,8 +579,7 @@ public static native void applyForceAndTorque(final int dimensionID, final int b * Gets the angular velocity of a given body * * @param bodyID the ID of an already created rigid-body - * @param store The array to store the angular velocity of the body in the - * format [x, y, z] + * @param store The array to store the angular velocity of the body in the format [x, y, z] */ @ApiStatus.Internal public static native void getAngularVelocity(final int dimensionID, final int bodyID, final double[] store); @@ -635,8 +590,7 @@ public static native void applyForceAndTorque(final int dimensionID, final int b * @param sceneId the scene ID * @param mountId the mount rigid body ID (or -1 for ground) * @param id the kinematic sub-level ID - * @param pose a 7-long double array, formatted [x, y, z, qx, qy, qz, qw] for - * position and quaternion + * @param pose a 7-long double array, formatted [x, y, z, qx, qy, qz, qw] for position and quaternion */ @ApiStatus.Internal public static native void createKinematicContraption(final int sceneId, int mountId, int id, double[] pose); @@ -651,17 +605,14 @@ public static native void applyForceAndTorque(final int dimensionID, final int b public static native void removeKinematicContraption(final int sceneId, int id); /** - * Sets the transform (position/quaternion) of a kinematic sub-level's center of - * mass relative to its parent. + * Sets the transform (position/quaternion) of a kinematic sub-level's center of mass relative to its parent. * * @param sceneId the scene ID * @param id the kinematic sub-level ID - * @param pose a 7-long double array, formatted [x, y, z, qx, qy, qz, qw] for - * position and quaternion + * @param pose a 7-long double array, formatted [x, y, z, qx, qy, qz, qw] for position and quaternion */ @ApiStatus.Internal - public static native void setKinematicContraptionTransform(final int sceneId, int id, double[] centerOfMass, - double[] pose, double[] velocities); + public static native void setKinematicContraptionTransform(final int sceneId, int id, double[] centerOfMass, double[] pose, double[] velocities); /** * Adds a chunk to a kinematic sub-level (4096 blocks, each as packed int). @@ -671,12 +622,10 @@ public static native void setKinematicContraptionTransform(final int sceneId, in * @param x the chunk x coordinate * @param y the chunk y coordinate * @param z the chunk z coordinate - * @param data a 4096-long int array containing packed block data - * (block_collider_id << 16 | voxel_state_id) + * @param data a 4096-long int array containing packed block data (block_collider_id << 16 | voxel_state_id) */ @ApiStatus.Internal - public static native void addKinematicContraptionChunkSection(final int sceneId, int id, int x, int y, int z, - int[] data); + public static native void addKinematicContraptionChunkSection(final int sceneId, int id, int x, int y, int z, int[] data); /** * Creates a rope @@ -684,8 +633,7 @@ public static native void addKinematicContraptionChunkSection(final int sceneId, * @return a rope id */ @ApiStatus.Internal - public static native long createRope(final int dimensionID, final double pointRadius, final double firstJointLength, - final double[] points, final int pointCount); + public static native long createRope(final int dimensionID, final double pointRadius, final double firstJointLength, final double[] points, final int pointCount); /** * Removes a rope @@ -696,12 +644,10 @@ public static native long createRope(final int dimensionID, final double pointRa public static native long removeRope(final int dimensionID, final long ropeId); @ApiStatus.Internal - public static native void setRopeAttachment(final int dimensionID, final long ropeId, final int subLevelId, - final double x, final double y, final double z, final boolean end); + public static native void setRopeAttachment(final int dimensionID, final long ropeId, final int subLevelId, final double x, final double y, final double z, final boolean end); @ApiStatus.Internal - public static native void addRopePointAtStart(final int dimensionID, final long ropeId, final double x, - final double y, final double z); + public static native void addRopePointAtStart(final int dimensionID, final long ropeId, final double x, final double y, final double z); @ApiStatus.Internal public static native void removeRopePointAtStart(final int dimensionID, final long ropeId); @@ -710,8 +656,8 @@ public static native void addRopePointAtStart(final int dimensionID, final long public static native void wakeUpRope(final int dimensionID, final long ropeId); @ApiStatus.Internal - public static native void setRopeFirstSegmentLength(final int dimensionID, final long ropeId, - final double firstSegmentLength); + public static native void setRopeFirstSegmentLength(final int dimensionID, final long ropeId, final double firstSegmentLength); + /** * Queries a rope @@ -727,8 +673,7 @@ public static native void configFrequencyAndDamping( double contactDampingRatio); @ApiStatus.Internal - public static native void configSolverIterations(int solverIterations, int pgsIterations, - int stabilizationIterations); + public static native void configSolverIterations(int solverIterations, int pgsIterations, int stabilizationIterations); @ApiStatus.Internal public static native void configMinIslandSize(int islandSize); @@ -743,9 +688,9 @@ public static void setMassPropertiesFrom(final int dimensionID, final int id, fi final double mass = massTracker.getMass(); // This is only called in one location and the center of mass can't be null - // noinspection DataFlowIssue - final double[] centerOfMassArray = new double[] { centerOfMass.x(), centerOfMass.y(), centerOfMass.z() }; - final double[] inertiaTensorArray = new double[] { + //noinspection DataFlowIssue + final double[] centerOfMassArray = new double[]{centerOfMass.x(), centerOfMass.y(), centerOfMass.z()}; + final double[] inertiaTensorArray = new double[]{ inertiaTensor.m00(), inertiaTensor.m01(), inertiaTensor.m02(), inertiaTensor.m10(), inertiaTensor.m11(), inertiaTensor.m12(), inertiaTensor.m20(), inertiaTensor.m21(), inertiaTensor.m22() From b856b43939dac8c8be59bd3e59a4f1be14552b48 Mon Sep 17 00:00:00 2001 From: nick <32414396+qurle@users.noreply.github.com> Date: Sun, 24 May 2026 17:04:02 +0000 Subject: [PATCH 5/6] Simplified NeoForge getGameDirectory implementation --- .../platform/SableLoaderPlatformImpl.java | 30 +++++++++++-------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/neoforge/src/main/java/dev/ryanhcode/sable/neoforge/platform/SableLoaderPlatformImpl.java b/neoforge/src/main/java/dev/ryanhcode/sable/neoforge/platform/SableLoaderPlatformImpl.java index c9348890..4d7e136c 100644 --- a/neoforge/src/main/java/dev/ryanhcode/sable/neoforge/platform/SableLoaderPlatformImpl.java +++ b/neoforge/src/main/java/dev/ryanhcode/sable/neoforge/platform/SableLoaderPlatformImpl.java @@ -7,6 +7,21 @@ import java.nio.file.Path; import java.nio.file.Paths; +public class SableLoaderPlatformImpl implements SableLoaderPlatform { + @Override + public String getModVersion(final String modId) { + return LoadingModList.get().getModFileById(modId).versionString(); + } + +package dev.ryanhcode.sable.neoforge.platform; + +import dev.ryanhcode.sable.platform.SableLoaderPlatform; +import net.neoforged.fml.loading.FMLPaths; +import net.neoforged.fml.loading.LoadingModList; +import org.jetbrains.annotations.Nullable; + +import java.nio.file.Path; + public class SableLoaderPlatformImpl implements SableLoaderPlatform { @Override public String getModVersion(final String modId) { @@ -16,18 +31,7 @@ public String getModVersion(final String modId) { @Override @Nullable public Path getGameDirectory() { - try { - final Class> fmlPathsClass = Class.forName("net.neoforged.fml.loading.FMLPaths"); - final Object gameDirSupplier = fmlPathsClass.getField("GAMEDIR").get(null); - final Object gameDir = gameDirSupplier.getClass().getMethod("get").invoke(gameDirSupplier); - if (gameDir instanceof Path path) { - return path; - } - if (gameDir != null) { - return Paths.get(gameDir.toString()); - } - } catch (final ReflectiveOperationException | SecurityException ignored) { - } - return null; + return FMLPaths.GAMEDIR.get(); } } + From 326e588f852410d57d7b40919ad01c1dfd7ac8cf Mon Sep 17 00:00:00 2001 From: nick <32414396+qurle@users.noreply.github.com> Date: Sun, 24 May 2026 17:05:37 +0000 Subject: [PATCH 6/6] Fixed errors in NeoForge implementation --- .../platform/SableLoaderPlatformImpl.java | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/neoforge/src/main/java/dev/ryanhcode/sable/neoforge/platform/SableLoaderPlatformImpl.java b/neoforge/src/main/java/dev/ryanhcode/sable/neoforge/platform/SableLoaderPlatformImpl.java index 4d7e136c..3432d513 100644 --- a/neoforge/src/main/java/dev/ryanhcode/sable/neoforge/platform/SableLoaderPlatformImpl.java +++ b/neoforge/src/main/java/dev/ryanhcode/sable/neoforge/platform/SableLoaderPlatformImpl.java @@ -1,20 +1,5 @@ package dev.ryanhcode.sable.neoforge.platform; -import dev.ryanhcode.sable.platform.SableLoaderPlatform; -import net.neoforged.fml.loading.LoadingModList; -import org.jetbrains.annotations.Nullable; - -import java.nio.file.Path; -import java.nio.file.Paths; - -public class SableLoaderPlatformImpl implements SableLoaderPlatform { - @Override - public String getModVersion(final String modId) { - return LoadingModList.get().getModFileById(modId).versionString(); - } - -package dev.ryanhcode.sable.neoforge.platform; - import dev.ryanhcode.sable.platform.SableLoaderPlatform; import net.neoforged.fml.loading.FMLPaths; import net.neoforged.fml.loading.LoadingModList; @@ -34,4 +19,3 @@ public Path getGameDirectory() { return FMLPaths.GAMEDIR.get(); } } -