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.

Sable organizes forces applied to sub-levels into named ForceGroup buckets. Each tick, block entities and system-level providers (gravity, drag, lift, propulsion) accumulate linear and angular impulses into their respective group’s ForceTotal. At the end of the physics substep, all totals are flushed to the rigid body via RigidBodyHandle.applyForcesAndReset(). This design makes force contributions inspectable and separable in the GUI.

ForceGroup

public record ForceGroup(
    @NotNull Component name,
    @Nullable Component description,
    int color,
    boolean defaultDisplayed
)
A ForceGroup is a named, colored category for grouping force contributions. It is a registry object stored in the sable:force_groups registry.
name
Component
A translatable display name for this group (e.g. shown in the contraption GUI).
description
Component | null
An optional longer description. May be null.
color
int
An RGB integer color used when rendering force vectors in the debug overlay.
defaultDisplayed
boolean
Whether this group’s force vectors are shown by default in the GUI without the user enabling them.

ForceGroups

public class ForceGroups
ForceGroups is the registry for all built-in force groups and exposes the registry itself for iteration.
public static final ResourceKey<Registry<ForceGroup>> REGISTRY_KEY; // sable:force_groups
public static final Registry<ForceGroup> REGISTRY;

Built-in groups

FieldRegistry pathDefault displayed
GRAVITYsable:gravityNo
DRAGsable:dragNo
LEVITATIONsable:levitationYes
BALLOON_LIFTsable:balloon_liftYes
PROPULSIONsable:propulsionYes
LIFTsable:liftYes
MAGNETIC_FORCEsable:magnetic_forceNo

count

public static int count()
Returns the total number of registered force groups.
To register your own force group, use RegistrationProvider.get(ForceGroups.REGISTRY_KEY, YOUR_MOD_ID) and register a ForceGroup record during mod initialization.

ForceTotal

public class ForceTotal
ForceTotal accumulates local linear and angular impulses within a single physics substep and then flushes them to a RigidBodyHandle. It is the primary accumulator used by QueuedForceGroup and RigidBodyHandle.applyForcesAndReset().
Forces are expressed in the local frame of the sub-level unless otherwise noted.

applyLinearAndAngularImpulse

public void applyLinearAndAngularImpulse(Vector3dc impulse, Vector3dc torque)
Adds a local linear impulse [N] and a local torque [Nm] to the running total.

applyLinearImpulse

public void applyLinearImpulse(Vector3dc impulse)
Adds a local linear impulse [N]. Torque contribution is zero.

applyAngularImpulse

public void applyAngularImpulse(Vector3dc impulse)
Adds a local angular impulse [N].

applyTorqueImpulse

public void applyTorqueImpulse(Vector3dc torque)
Alias for applyAngularImpulse — adds a local torque [Nm].

applyImpulseAtPoint(MassData, Vector3dc, Vector3dc)

public void applyImpulseAtPoint(MassData massTracker, Vector3dc position, Vector3dc force)
Applies a local force [N] at a local position [m] and computes the resulting torque from the offset to the center of mass automatically.
massTracker
MassData
required
Provides the center-of-mass used for torque calculation.
position
Vector3dc
required
Application point inside the plot [m].
force
Vector3dc
required
Force to apply [N].

applyImpulseAtPoint(ServerSubLevel, Vector3dc, Vector3dc)

public void applyImpulseAtPoint(ServerSubLevel massTracker, Vector3dc position, Vector3dc force)
Convenience overload that reads the center-of-mass from ServerSubLevel.getMassTracker().

applyImpulseAtPoint(MassTracker, Vec3, Vec3)

public void applyImpulseAtPoint(MassTracker massTracker, Vec3 position, Vec3 force)
Overload accepting Minecraft Vec3 arguments for interoperability with Minecraft code.

applyForceTotal

public void applyForceTotal(ForceTotal other)
Merges the accumulated linear force and torque from other into this total.

reset

public void reset()
Zeros out the accumulated linear force and torque. Called automatically after applyForces flushes to the engine.

getLocalForce

public Vector3d getLocalForce()
Returns a mutable reference to the current accumulated local force [N].

getLocalTorque

public Vector3d getLocalTorque()
Returns a mutable reference to the current accumulated local torque [Nm].

QueuedForceGroup

public class QueuedForceGroup
QueuedForceGroup is a per-sub-level, per-ForceGroup accumulator that additionally records individual point forces for debug visualization when the sub-level’s tracking is enabled. Obtain an instance via ServerSubLevel.getOrCreateQueuedForceGroup(ForceGroup).

Constructor

public QueuedForceGroup(ServerSubLevel serverSubLevel)

getForceTotal

public ForceTotal getForceTotal()
Returns the ForceTotal accumulator for this group. Add forces here.

applyAndRecordPointForce

public void applyAndRecordPointForce(Vector3dc point, Vector3dc force)
Applies a point force to the force total (computing torque from the CoM offset) and records it in the point-force list if the sub-level has individual force tracking enabled.
point
Vector3dc
required
World position of the force application point inside the plot [m].
force
Vector3dc
required
Force vector [N].

recordPointForce

public void recordPointForce(Vector3dc point, Vector3dc force)
Records a point force for visualization without applying it to the force total. Only records when ServerSubLevel.isTrackingIndividualQueuedForces() returns true and the force magnitude exceeds 0.001 N.

getRecordedPointForces

public List<PointForce> getRecordedPointForces()
Returns the list of recorded point forces since the last reset(). Each entry is a PointForce(Vector3dc point, Vector3dc force) record.

reset

public void reset()
Clears both the force total and the recorded point forces list.

MassData

public interface MassData
Read-only access to the mass and inertia properties of a physics body.

Methods

getMass()
double
Total mass in kilo-Minecraft-physics-grams (kpg).
getInverseMass()
double
1 / mass [1/kpg]. Returns 0 if mass is 0 (invalid).
getInertiaTensor()
Matrix3dc
Inertia tensor in local space [kpg·m²].
getInverseInertiaTensor()
Matrix3dc
Inverse inertia tensor in local space [1/(kpg·m²)].
getCenterOfMass()
Vector3dc | null
Center-of-mass position in local (plot-relative) space [m]. May be null if the body has no solid blocks.
isInvalid()
boolean
Returns true when getMass() <= 0. Indicates no solid blocks or uninitialized state.

getInverseNormalMass

default double getInverseNormalMass(Vector3dc position, Vector3dc direction)
Returns the inverse effective (normal) mass at position along direction. Used for impulse-based collision resolution.

MassTracker

public class MassTracker implements MassData
MassTracker is the concrete, mutable implementation of MassData for sub-levels. It is built once during assembly via MassTracker.build() and updated incrementally as blocks are added or removed.

build

public static MassTracker build(BlockGetter blockGetter, BoundingBox3ic bounds)
Constructs a MassTracker from all solid blocks within bounds, computing the aggregate mass, center-of-mass, and inertia tensor using the parallel-axis theorem.

addBlockMass

public void addBlockMass(
    BlockGetter blockGetter,
    BlockState state,
    BlockPos blockPos,
    double blockMass,
    @Nullable Vec3 blockInertia
)
Incrementally adds (or removes, when blockMass is negative) a block’s contribution to the tracker using the parallel-axis theorem.

moveCenterOfMass

public void moveCenterOfMass(Vector3d newCenterOfMass)
Shifts the center-of-mass to newCenterOfMass and adjusts the inertia tensor accordingly.

BLOCK_CENTER_OF_MASS

public static BiFunction<BlockGetter, BlockState, Vector3dc> BLOCK_CENTER_OF_MASS
A memoized function that returns the center-of-mass position for a given BlockState. Respects BlockSubLevelCustomCenterOfMass overrides. Results are cached by block-state hash code.

BoxPhysicsObject and BoxHandle

BoxPhysicsObject is a standalone cuboid rigid body not tied to any sub-level. It is useful for projectiles, debris, or other physics objects that have no associated block data.

BoxPhysicsObject

public BoxPhysicsObject(Pose3dc pose, Vector3dc halfExtents, double mass)
pose
Pose3dc
required
Initial world-space pose. Rotation and scale components of the pose are ignored; only position is used.
halfExtents
Vector3dc
required
Half-sizes of the box along each axis [m].
mass
double
required
Mass of the box [kpg].
MethodDescription
getPose()Returns the last pose read back from the engine. Call updatePose() first.
getHalfExtents()Returns the box’s half-extents.
getMass()Returns the box mass [kpg].
isActive()Returns true while the box is registered in the physics world.
updatePose()Queries the physics engine and updates the stored pose.
wakeUp()Wakes the box.

BoxHandle

public interface BoxHandle
Low-level handle returned by PhysicsPipeline.addBox().
MethodDescription
readPose(Pose3d dest)Queries the current pose from the engine into dest.
remove()Removes the box from the pipeline.
wakeUp()Wakes the box.
getRuntimeId()Returns the runtime ID assigned by the pipeline.

RopePhysicsObject and RopeHandle

RopePhysicsObject simulates a chain of point masses with distance constraints, suitable for hanging ropes, cables, and chains.

RopePhysicsObject

public RopePhysicsObject(Collection<Vector3d> points, double collisionRadius)
points
Collection<Vector3d>
required
The initial world-space positions of the rope’s nodes, ordered from start to end.
collisionRadius
double
required
The radius of each rope segment’s capsule collider [m].
MethodDescription
getPoints()Returns an unmodifiable view of the current node positions.
getCollisionRadius()Returns the collision radius [m].
updatePose()Reads updated node positions from the physics engine.
addPoint(Vector3dc)Prepends a node to the start of the rope.
removeFirstPoint()Removes the first (start) node.
setFirstSegmentLength(double)Sets the extension constraint length of the first segment [m].
setAttachment(AttachmentPoint, Vector3dc, ServerSubLevel)Attaches an endpoint to a position on a sub-level.
isActive()Returns true while the rope is registered in the physics world.

RopeHandle

public interface RopeHandle
Low-level handle returned by PhysicsPipeline.addRope().
MethodDescription
readPose(List<Vector3d> dest)Reads current node positions into dest.
remove()Removes the rope from the pipeline.
addPoint(Vector3dc)Prepends a node.
removeFirstPoint()Removes the first node.
setFirstSegmentLength(double)Sets the extension constraint length of the first segment.
setAttachment(AttachmentPoint, Vector3dc, ServerSubLevel)Attaches an endpoint.
wakeUp()Wakes all rope segments.

RopeHandle.AttachmentPoint

enum AttachmentPoint { START, END }
Identifies which end of the rope to attach.

Build docs developers (and LLMs) love