Skip to content

Commit effec5f

Browse files
committed
Separate sable_rapier into its own module
1 parent 48f5c24 commit effec5f

59 files changed

Lines changed: 386 additions & 227 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/build-rust.yml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ name: Build Rust Natives
22
on:
33
push:
44
paths:
5-
- 'common/src/main/rust/**'
5+
- 'sable_rapier/src/main/rust/**'
66
- '.github/workflows/build-rust.yml'
77
workflow_dispatch:
88

@@ -33,11 +33,11 @@ jobs:
3333
- name: Cache cargo
3434
uses: actions/cache@v4
3535
with:
36-
path: ${{ github.workspace }}/common/build/cargo
37-
key: ${{ runner.os }}-node-${{ hashFiles('common/src/main/rust/**/Cargo.lock') }}
36+
path: ${{ github.workspace }}/sable_rapier/build/cargo
37+
key: ${{ runner.os }}-node-${{ hashFiles('sable_rapier/src/main/rust/**/Cargo.lock') }}
3838

3939
- name: Run Gradle Task
40-
run: ./gradlew common:buildImages common:buildRustNatives
40+
run: ./gradlew sable_rapier:buildImages sable_rapier:buildRustNatives
4141

4242
- name: Take ownership of the workspace
4343
run: sudo chown -R $USER:$USER .

.gitignore

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@
77
*.iws
88

99
# Rust
10-
/common/src/main/rust/target
11-
/common/src/main/rust/flamegraph.svg
10+
/sable_rapier/src/main/rust/target
11+
/sable_rapier/src/main/rust/flamegraph.svg
1212

1313
# C# - Sharp
1414
/common/src/main/csharp/*/bin/

common/build.gradle

Lines changed: 1 addition & 205 deletions
Original file line numberDiff line numberDiff line change
@@ -1,212 +1,8 @@
1-
import org.apache.tools.ant.taskdefs.condition.Os
2-
import net.jpountz.lz4.LZ4FrameOutputStream
3-
4-
import java.nio.file.Files
5-
6-
buildscript {
7-
dependencies {
8-
classpath 'at.yawk.lz4:lz4-java:1.11.0'
9-
}
10-
}
11-
121
plugins {
132
id 'multiloader-common'
143
id 'net.neoforged.moddev'
154
}
165

17-
def mac(arch) {
18-
[triple: "${arch}-apple-darwin", suffix: "", arch: arch, os: "macos", ext: "dylib", lib: true]
19-
}
20-
21-
def linux(arch) {
22-
[triple: "${arch}-unknown-linux-gnu", suffix: ".2.17", arch: arch, os: "linux", ext: "so", lib: true]
23-
}
24-
25-
def freebsd(arch) {
26-
[triple: "${arch}-unknown-freebsd", suffix: "", arch: arch, os: "freebsd", ext: "so", lib: true]
27-
}
28-
29-
def windows(arch) {
30-
[triple: "${arch}-pc-windows-msvc", suffix: "", arch: arch, os: "windows", ext: "dll", lib: false]
31-
}
32-
33-
def supportedTargets = [
34-
mac("x86_64"),
35-
mac("aarch64"),
36-
linux("x86_64"),
37-
linux("aarch64"),
38-
windows("x86_64"),
39-
windows("aarch64"),
40-
// freebsd("x86_64"),
41-
// freebsd("aarch64"),
42-
]
43-
def pinnedRustVersion = 'nightly-2026-01-29'
44-
def rustRootDir = file("src/main/rust")
45-
def rustProjectDir = file("$rustRootDir/rapier")
46-
def nativesDir = file("src/main/resources/natives/sable_rapier")
47-
def cargoCacheDir = project.layout.buildDirectory.file("cargo").get().asFile
48-
def docker = Os.isFamily(Os.FAMILY_MAC) ? "/usr/local/bin/docker" : "docker"
49-
def xWinImage = 'sable-build-xwin'
50-
def zigbuildImage = 'sable-build-zigbuild'
51-
52-
def baseDockerCommand = [
53-
docker,
54-
'run',
55-
'--rm',
56-
'-v',
57-
"$rustRootDir:/io",
58-
'-v',
59-
"$cargoCacheDir/git:/usr/local/cargo/git",
60-
'-v',
61-
"$cargoCacheDir/registry:/usr/local/cargo/registry",
62-
'-w',
63-
'/io/rapier',
64-
]
65-
project.ext.zigbuildCargo = [baseDockerCommand, zigbuildImage, 'cargo'].flatten()
66-
project.ext.xWinCargo = [baseDockerCommand, xWinImage, 'cargo'].flatten()
67-
68-
tasks.register('createContainersDirectory') {
69-
doLast {
70-
if (!cargoCacheDir.exists()) {
71-
cargoCacheDir.mkdirs()
72-
}
73-
}
74-
}
75-
76-
77-
tasks.register('buildZigbuildImage', Exec) {
78-
group = 'rust'
79-
workingDir rustRootDir
80-
commandLine docker, 'build', '-t', zigbuildImage, 'container/zigbuild', '--build-arg', "RUST_VERSION=${pinnedRustVersion}"
81-
dependsOn createContainersDirectory
82-
}
83-
tasks.register('buildXWinImage', Exec) {
84-
group = 'rust'
85-
workingDir rustRootDir
86-
commandLine docker, 'build', '-t', xWinImage, 'container/xwin', '--build-arg', "RUST_VERSION=${pinnedRustVersion}"
87-
dependsOn createContainersDirectory
88-
}
89-
90-
tasks.register('buildImages') {
91-
group = 'rust'
92-
dependsOn buildZigbuildImage, buildXWinImage
93-
}
94-
95-
tasks.register('cleanRust', Exec) {
96-
group = 'rust'
97-
workingDir rustProjectDir
98-
commandLine project.ext.zigbuildCargo
99-
// only need to use zigbuild cargo since both containers share the same target folder
100-
args 'clean'
101-
dependsOn createContainersDirectory
102-
}
103-
104-
def compileRustTaskName = { target ->
105-
"compileRust-${target.os}-${target.arch}"
106-
}
107-
108-
def commandLineForTarget(target) {
109-
if (target.triple.contains('msvc')) {
110-
[project.ext.xWinCargo, 'xwin', 'build', '--target', target.triple + target.suffix].flatten()
111-
// support meme platforms, this does nothing by default because the target is disabled
112-
} else if (target.triple == 'aarch64-unknown-freebsd') {
113-
[project.ext.zigbuildCargo, 'zigbuild', '-Z', 'build-std', '--target', target.triple + target.suffix].flatten()
114-
} else {
115-
[project.ext.zigbuildCargo, 'zigbuild', '--target', target.triple + target.suffix].flatten()
116-
}
117-
}
118-
119-
def nativesNameForTarget(target) {
120-
"sable_rapier_${target.arch}_${target.os}.${target.ext}"
121-
}
122-
123-
supportedTargets.forEach { target ->
124-
tasks.register(compileRustTaskName(target), Exec) {
125-
group = 'rust'
126-
workingDir rustProjectDir
127-
description = "Cross-compiles natives for the ${target.triple} target"
128-
def commands= commandLineForTarget(target)
129-
commands.add('--release')
130-
commandLine = commands
131-
}
132-
}
133-
134-
tasks.register("compileRustDev", Exec) {
135-
group = 'rust'
136-
workingDir rustProjectDir
137-
description = "Compiles debug natives"
138-
commandLine = [project.ext.zigbuildCargo, 'zigbuild'].flatten()
139-
}
140-
141-
tasks.register('buildRustNatives') {
142-
group = 'build'
143-
description = 'Compiles all Rust natives and moves them to resources.'
144-
145-
dependsOn = supportedTargets.stream().map(compileRustTaskName).collect()
146-
finalizedBy copyRustNatives
147-
}
148-
149-
tasks.register('buildRustNativesDev') {
150-
group = 'build'
151-
description = 'Compiles all Rust natives and moves them to resources.'
152-
153-
dependsOn compileRustDev
154-
finalizedBy copyRustNativesDev
155-
}
156-
157-
tasks.register('copyRustNatives', Copy) {
158-
group = 'rust'
159-
into nativesDir
160-
mustRunAfter(buildRustNatives)
161-
162-
supportedTargets.forEach { target ->
163-
from(file("$rustRootDir/target/${target.triple}/release/${if (target.lib) { "lib" } else { "" }}sable_rapier.${target.ext}")) {
164-
rename { nativesNameForTarget(target) }
165-
}
166-
}
167-
finalizedBy packRustNatives
168-
}
169-
170-
tasks.register('copyRustNativesDev', Copy) {
171-
group = 'rust'
172-
into nativesDir
173-
mustRunAfter(buildRustNativesDev)
174-
175-
supportedTargets.forEach { target ->
176-
var library = file("$rustRootDir/target/debug/${if (target.lib) { "lib" } else { "" }}sable_rapier.${target.ext}")
177-
if (!library.exists()) return
178-
179-
from(library) {
180-
rename { nativesNameForTarget(target) }
181-
}
182-
}
183-
finalizedBy packRustNatives
184-
}
185-
tasks.register('packRustNatives', Zip) {
186-
group = 'rust'
187-
archiveFile.set file("${nativesDir}/sable_rapier_binaries.zip.l4z")
188-
entryCompression = ZipEntryCompression.STORED
189-
into nativesDir
190-
191-
mustRunAfter copyRustNatives, copyRustNativesDev
192-
supportedTargets.forEach { target ->
193-
var f = nativesNameForTarget(target)
194-
// No, you can't use rename here in case you were wondering.
195-
from(file("${nativesDir}/${f}")) { eachFile { setPath f } }
196-
}
197-
doLast {
198-
byte[] bytes = Files.readAllBytes(getArchiveFile().get().asFile.toPath())
199-
try (var f = new FileOutputStream(getArchiveFile().get().asFile)) {
200-
try (var x = new LZ4FrameOutputStream(f, LZ4FrameOutputStream.BLOCKSIZE.SIZE_4MB, bytes.length, LZ4FrameOutputStream.FLG.Bits.BLOCK_INDEPENDENCE)) {
201-
x.write(bytes)
202-
}
203-
}
204-
supportedTargets.forEach { t ->
205-
delete(file("${nativesDir}/${nativesNameForTarget(t)}"))
206-
}
207-
}
208-
}
209-
2106
neoForge {
2117
neoFormVersion = neo_form_version
2128
// Automatically enable AccessTransformers if the file exists
@@ -256,6 +52,6 @@ dependencies {
25652
transitive = false
25753
}
25854

259-
implementation "fuzs.forgeconfigapiport:forgeconfigapiport-common-neoforgeapi:${forgeconfigapiport_version}"
26055
//source: https://github.com/Fuzss/forgeconfigapiport
56+
implementation "fuzs.forgeconfigapiport:forgeconfigapiport-common-neoforgeapi:${forgeconfigapiport_version}"
26157
}

common/src/main/java/dev/ryanhcode/sable/Sable.java

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
package dev.ryanhcode.sable;
22

33
import com.mojang.logging.LogUtils;
4-
import dev.ryanhcode.sable.api.physics.PhysicsPipeline;
54
import dev.ryanhcode.sable.api.physics.force.ForceGroups;
65
import dev.ryanhcode.sable.api.sublevel.ServerSubLevelContainer;
76
import dev.ryanhcode.sable.api.sublevel.SubLevelContainer;
@@ -11,7 +10,6 @@
1110
import dev.ryanhcode.sable.network.tcp.SableTCPPackets;
1211
import dev.ryanhcode.sable.physics.config.block_properties.PhysicsBlockPropertiesDefinitionLoader;
1312
import dev.ryanhcode.sable.physics.config.block_properties.PhysicsBlockPropertyTypes;
14-
import dev.ryanhcode.sable.physics.impl.rapier.RapierPhysicsPipeline;
1513
import dev.ryanhcode.sable.sublevel.system.SubLevelPhysicsSystem;
1614
import dev.ryanhcode.sable.sublevel.system.SubLevelTrackingSystem;
1715
import dev.ryanhcode.sable.sublevel.tracking_points.SubLevelTrackingPointObserver;
@@ -45,14 +43,6 @@ public static void init() {
4543

4644
LOGGER.info("{} loaded!", MOD_NAME);
4745
}
48-
49-
/**
50-
* Creates a physics pipeline with the current configuration.
51-
*/
52-
public static PhysicsPipeline createPhysicsPipeline(final ServerLevel level) {
53-
return new RapierPhysicsPipeline(level);
54-
}
55-
5646
/**
5747
* @param path the path to the resource
5848
* @return a {@link ResourceLocation} with a {@link Sable#MOD_ID} namespace

common/src/main/java/dev/ryanhcode/sable/api/physics/PhysicsPipeline.java

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -224,7 +224,15 @@ default Vector3d getAngularVelocity(final PhysicsPipelineBody body, final Vector
224224
@Nullable
225225
@Contract("null, null, _ -> fail")
226226
default <T extends PhysicsConstraintHandle> T addConstraint(@Nullable final PhysicsPipelineBody bodyA, @Nullable final PhysicsPipelineBody bodyB, @NotNull final PhysicsConstraintConfiguration<T> configuration) {
227-
throw new UnsupportedOperationException("Not implemented");
227+
if (bodyA == null && bodyB == null) {
228+
throw new IllegalArgumentException("Cannot add a constraint between the static world and static world");
229+
}
230+
231+
if (bodyA == bodyB) {
232+
throw new IllegalArgumentException("Cannot add a constraint between a body and itself");
233+
}
234+
235+
return null;
228236
}
229237

230238
/**
@@ -234,7 +242,7 @@ default <T extends PhysicsConstraintHandle> T addConstraint(@Nullable final Phys
234242
*/
235243
@ApiStatus.OverrideOnly
236244
default void updateConfigFrom(final PhysicsConfigData data) {
237-
throw new UnsupportedOperationException("Not implemented");
245+
238246
}
239247

240248
/**
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
package dev.ryanhcode.sable.api.physics;
2+
3+
import net.minecraft.server.level.ServerLevel;
4+
import org.jetbrains.annotations.Contract;
5+
import org.jetbrains.annotations.NotNull;
6+
7+
import java.lang.annotation.Retention;
8+
import java.lang.annotation.RetentionPolicy;
9+
import java.util.Comparator;
10+
import java.util.ServiceLoader;
11+
12+
/**
13+
* A provider of physics pipelines for levels
14+
*/
15+
public interface PhysicsPipelineProvider {
16+
17+
/**
18+
* @since 1.0.0
19+
*/
20+
@Retention(RetentionPolicy.RUNTIME)
21+
@interface LoadPriority {
22+
/**
23+
* @return The load priority value. The highest priority available pipeline provider is loaded
24+
*/
25+
int value() default 1000;
26+
}
27+
28+
/**
29+
* The physics pipeline provider instance.
30+
*/
31+
PhysicsPipelineProvider INSTANCE = ServiceLoader.load(PhysicsPipelineProvider.class)
32+
.stream().max(Comparator.comparingInt(provider -> {
33+
Class<? extends PhysicsPipelineProvider> type = provider.type();
34+
LoadPriority annotation = type.getAnnotation(LoadPriority.class);
35+
return annotation != null ? annotation.value() : 1000;
36+
}))
37+
.map(ServiceLoader.Provider::get)
38+
.orElseThrow(() -> new RuntimeException("Failed to find any physics pipeline providers"));
39+
40+
/**
41+
* Creates a physics pipeline for a given level
42+
* @param level the level to create the pipeline for
43+
* @return the new physics pipeline
44+
*/
45+
@NotNull
46+
@Contract(value = "_ -> new", pure = true)
47+
PhysicsPipeline createPipeline(@NotNull final ServerLevel level);
48+
49+
}

common/src/main/java/dev/ryanhcode/sable/physics/impl/none/StaticPhysicsPipeline.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ public void remove(final KinematicContraption contraption) {
7373

7474
@Override
7575
public Pose3d readPose(final ServerSubLevel subLevel, final Pose3d dest) {
76-
return dest;
76+
return dest.set(subLevel.logicalPose());
7777
}
7878

7979
/**
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
package dev.ryanhcode.sable.physics.impl.none;
2+
3+
import dev.ryanhcode.sable.api.physics.PhysicsPipeline;
4+
import dev.ryanhcode.sable.api.physics.PhysicsPipelineProvider;
5+
import net.minecraft.server.level.ServerLevel;
6+
import org.jetbrains.annotations.NotNull;
7+
8+
@PhysicsPipelineProvider.LoadPriority(900)
9+
public final class StaticPhysicsPipelineProvider implements PhysicsPipelineProvider {
10+
11+
@Override
12+
public @NotNull PhysicsPipeline createPipeline(@NotNull final ServerLevel level) {
13+
return new StaticPhysicsPipeline();
14+
}
15+
16+
}

0 commit comments

Comments
 (0)