Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/ryanhcode/sable/llms.txt

Use this file to discover all available pages before exploring further.

PhysicsPipeline is the abstraction layer between Sable’s sub-level system and the underlying physics engine (Rapier). It manages rigid bodies, physics ticking, force application, and constraints. All physics operations on sub-levels go through this interface, which you obtain from SubLevelPhysicsSystem.getPipeline().

Initialization

init

void init(Vector3dc gravity, double universalDrag)
Initializes the physics pipeline with a gravity vector and a universal drag coefficient applied to all bodies.
gravity
Vector3dc
required
The gravity vector applied to all dynamic bodies each tick.
universalDrag
double
required
A drag coefficient applied uniformly to every body in the simulation.

dispose

void dispose()
Releases all native and managed resources held by the physics pipeline. Call this when the pipeline is no longer needed (e.g. when the level unloads).

Physics tick lifecycle

These methods are called by Sable’s tick scheduler in a fixed order every game tick. You do not call them directly unless you are implementing a custom pipeline.

prePhysicsTicks

void prePhysicsTicks()
Prepares the pipeline for one or more physics substeps at 1.0 / 20.0 seconds total. Called once before any substeps run.

physicsTick

void physicsTick(double timeStep)
Runs a single physics substep.
timeStep
double
required
Duration of this substep in seconds: 1.0 / 20.0 / substeps.

postPhysicsTicks

void postPhysicsTicks()
Finalizes the physics tick after all substeps have completed. Use this to read back updated poses.

tick

void tick()
Runs non-physics update logic (data tracking, bookkeeping) even when physics is paused. Called every server game tick regardless of pause state.

Body management

add(ServerSubLevel, Pose3dc)

void add(ServerSubLevel subLevel, Pose3dc pose)
Registers a dynamic sub-level with the physics engine at the given initial pose.
subLevel
ServerSubLevel
required
The sub-level to add as a dynamic rigid body.
pose
Pose3dc
required
The initial world-space pose for the body.

remove(ServerSubLevel)

void remove(ServerSubLevel subLevel)
Removes a sub-level’s rigid body from the physics simulation.

add(KinematicContraption)

void add(KinematicContraption contraption)
Adds a kinematic contraption (an externally driven body that is not affected by forces) to the scene.

remove(KinematicContraption)

void remove(KinematicContraption contraption)
Removes a kinematic contraption from the scene.

Pose reading

readPose

Pose3d readPose(ServerSubLevel subLevel, Pose3d dest)
Queries the current world-space pose of a sub-level’s rigid body from the physics engine and writes it into dest.
This method is annotated @ApiStatus.OverrideOnly. Call ServerSubLevel.logicalPose() in normal game code rather than calling this directly.
subLevel
ServerSubLevel
required
The sub-level to query.
dest
Pose3d
required
The destination pose object to write into.
Returns dest with the current pose written in.

Force application

teleport

void teleport(PhysicsPipelineBody body, Vector3dc position, Quaterniondc orientation)
Instantly moves a physics body to a new position and orientation, bypassing velocity integration.
body
PhysicsPipelineBody
required
The body to teleport.
position
Vector3dc
required
New world-space position.
orientation
Quaterniondc
required
New world-space orientation.

applyImpulse

void applyImpulse(PhysicsPipelineBody body, Vector3dc position, Vector3dc force)
Applies a force impulse at a specific world-space position on the body. The offset from the center of mass generates a torque automatically.
body
PhysicsPipelineBody
required
The target body.
position
Vector3dc
required
World-space application point, assumed to be inside the body’s plot [m].
force
Vector3dc
required
Force to apply [N].

applyLinearAndAngularImpulse

void applyLinearAndAngularImpulse(PhysicsPipelineBody body, Vector3dc force, Vector3dc torque, boolean wakeUp)
Adds a local linear force and a local torque to the body in a single call.
body
PhysicsPipelineBody
required
The target body.
force
Vector3dc
required
Local linear impulse [N].
torque
Vector3dc
required
Local angular impulse [Nm].
wakeUp
boolean
required
If true, wakes the body from sleep before applying the impulse.

addLinearAndAngularVelocity

default void addLinearAndAngularVelocity(PhysicsPipelineBody body, Vector3dc linearVelocity, Vector3dc angularVelocity)
Adds linear and angular velocity deltas to the body without applying a force.
linearVelocity
Vector3dc
required
Velocity to add [m/s].
angularVelocity
Vector3dc
required
Angular velocity to add [rad/s].

resetVelocity

default void resetVelocity(PhysicsPipelineBody body)
Sets both linear and angular velocity to zero by applying the negation of the current velocity. Delegates to addLinearAndAngularVelocity.

Velocity queries

getLinearVelocity

default Vector3d getLinearVelocity(PhysicsPipelineBody body, Vector3d dest)
Reads the current global linear velocity of the body from the engine into dest. Returns dest [m/s]. Returns a zero vector if not implemented.

getAngularVelocity

default Vector3d getAngularVelocity(PhysicsPipelineBody body, Vector3d dest)
Reads the current global angular velocity of the body from the engine into dest. Returns dest [rad/s]. Returns a zero vector if not implemented.

Wake and sleep

wakeUp

void wakeUp(PhysicsPipelineBody body)
Wakes a sleeping body, signalling that its environment has changed and physics simulation should resume.

Constraints

addConstraint

default <T extends PhysicsConstraintHandle> T addConstraint(
    @Nullable ServerSubLevel sublevelA,
    @Nullable ServerSubLevel sublevelB,
    PhysicsConstraintConfiguration<T> configuration
)
Creates a joint constraint between two sub-levels (or between a sub-level and the static world) and returns a handle for later management.
sublevelA
ServerSubLevel | null
The first body. Pass null to attach sublevelB to the world.
sublevelB
ServerSubLevel | null
The second body. Pass null to attach sublevelA to the world.
configuration
PhysicsConstraintConfiguration<T>
required
A typed configuration record that determines the joint type and returns a matching handle.
Returns a handle T that you must retain to remove or modify the constraint later.
The default implementation throws UnsupportedOperationException. Constraint support requires a pipeline implementation that overrides this method.
See Physics constraints and joints for all configuration types.

World geometry

handleChunkSectionAddition

void handleChunkSectionAddition(LevelChunkSection chunk, int x, int y, int z, boolean uploadDataIfGlobal)
Notifies the pipeline that a chunk section has been loaded and its geometry should be added to the static collision world.

handleChunkSectionRemoval

void handleChunkSectionRemoval(int x, int y, int z)
Removes a chunk section’s geometry from the static collision world.

handleBlockChange

void handleBlockChange(SectionPos sectionPos, LevelChunkSection chunk, int x, int y, int z, BlockState oldState, BlockState newState)
Updates the static collision geometry for a single block change. Only called server-side.

onStatsChanged

default void onStatsChanged(@NotNull ServerSubLevel serverSubLevel)
Re-uploads center-of-mass, mass properties, and local bounds for the given sub-level to the physics pipeline. Called automatically when the sub-level’s block contents change.

updateConfigFrom

@ApiStatus.OverrideOnly
default void updateConfigFrom(PhysicsConfigData data)
Applies live configuration changes from a PhysicsConfigData object (gravity, substep count, drag, etc.).

Misc

getNextRuntimeID

int getNextRuntimeID()
Returns the next monotonically increasing runtime integer ID for assigning to a new collider or sub-level.

Physics objects

addRope

@ApiStatus.OverrideOnly
RopeHandle addRope(RopePhysicsObject rope)
Registers a RopePhysicsObject with the physics engine and returns a RopeHandle for controlling it.
This method is @ApiStatus.OverrideOnly. Use RopePhysicsObject.onAddition() instead of calling this directly.

addBox

BoxHandle addBox(BoxPhysicsObject boxPhysicsObject)
Registers a BoxPhysicsObject with the physics engine and returns a BoxHandle.

PhysicsPipelineBody

PhysicsPipelineBody represents any rigid body tracked by a PhysicsPipeline — including sub-levels and standalone objects like boxes.
public interface PhysicsPipelineBody {
    int NULL_RUNTIME_ID = -1;

    int getRuntimeId();
    MassData getMassTracker();
    boolean isRemoved();
}
NULL_RUNTIME_ID
int
Sentinel value (-1) indicating the body has no valid runtime ID.
getRuntimeId()
int
Returns the runtime integer ID assigned by the pipeline. Returns NULL_RUNTIME_ID if not yet registered.
getMassTracker()
MassData
Returns the mass/inertia data for this body. See Force groups and mass tracking.
isRemoved()
boolean
Returns true if this body has been removed from the pipeline.

RigidBodyHandle

RigidBodyHandle is a convenience wrapper around a PhysicsPipelineBody that exposes commonly used force and velocity operations without needing a direct PhysicsPipeline reference. Obtain one via RigidBodyHandle.of(ServerSubLevel) or SubLevelPhysicsSystem.getPhysicsHandle(ServerSubLevel).
// Obtain a handle
RigidBodyHandle handle = RigidBodyHandle.of(subLevel);

// Apply a linear impulse
handle.applyLinearImpulse(new Vector3d(0, 100, 0));

// Read back velocity
Vector3d vel = handle.getLinearVelocity(new Vector3d());

Factory methods

static @Nullable RigidBodyHandle of(ServerLevel level, PhysicsPipelineBody body)
static @Nullable RigidBodyHandle of(ServerSubLevel subLevel)
Both return null if the level has no SubLevelContainer (e.g. the level is not physics-enabled).

Force methods

MethodDescription
applyImpulseAtPoint(Vector3dc position, Vector3dc force)Force [N] at world position [m]
applyImpulseAtPoint(Vec3 position, Vec3 force)Minecraft Vec3 overload
applyLinearAndAngularImpulse(Vector3dc impulse, Vector3dc torque)Local force + torque, wakes body
applyLinearAndAngularImpulse(Vector3dc impulse, Vector3dc torque, boolean wakeUp)Explicit wake control
applyLinearImpulse(Vector3dc impulse)Linear only [N]
applyAngularImpulse(Vector3dc impulse)Angular only [N]
applyTorqueImpulse(Vector3dc torque)Torque alias [Nm]
applyForcesAndReset(ForceTotal forceTotal)Drains a ForceTotal accumulator into this body
addLinearAndAngularVelocity(Vector3dc linear, Vector3dc angular)Velocity delta [m/s, rad/s]
teleport(Vector3dc position, Quaterniondc orientation)Instant teleport

Velocity methods

MethodReturnsUnit
getLinearVelocity(Vector3d dest)Vector3dm/s
getAngularVelocity(Vector3d dest)Vector3drad/s
The zero-argument overloads getLinearVelocity() and getAngularVelocity() are deprecated. Use the dest-accepting overloads to avoid allocation.

isValid

public boolean isValid()
Returns true if the underlying body has not been removed from the pipeline.

Build docs developers (and LLMs) love