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 has a specific system for how entities interact with sub-levels. By default, entities spawned inside a sub-level’s plot are “kicked” to global space — Sable teleports them out, applies the sub-level’s velocity, and transforms their velocity and rotation so movement feels continuous.

Entity kicking

When an entity is spawned inside the plot of a sub-level, Sable teleports it to its equivalent global position. The entity inherits the sub-level’s velocity and has its own velocity and look-angle transformed out of the sub-level’s local coordinate space. This prevents entities from being carried around silently inside a moving structure when they should interact with the world normally. For some entities — such as Armor Stands or Paintings — this behavior is undesired. Sable provides entity type tags to customize kicking on a per-type basis.

Entity tags

#sable:retain_in_sub_level

Entities of types in this tag are never kicked from sub-levels. Use this for decorative or structural entities that belong to the sub-level itself, such as Armor Stands or Paintings.

#sable:destroy_when_leaving_plot

Entities of types in this tag are destroyed when they are inside a sub-level plot but exit the bounding region that contains the sub-level’s blocks. This is useful for short-lived entities (e.g. particles or projectiles) that should not survive leaving the structure.

#sable:destroy_with_sub_level

Entities of types in this tag are destroyed when the sub-level plot that contains them is destroyed, rather than being kicked to global space. The Super Glue item from the Create mod is a canonical example — it exists only to hold blocks together and has no meaning outside the sub-level.

Adding an entity type to a tag

To specify that your entity should always stay inside sub-level plots and never be kicked, add it to #sable:retain_in_sub_level in your datapack:
// /data/sable/tags/entity_type/retain_in_sub_level.json
{
  "replace": false,
  "values": [
    "examplemod:example_entity"
  ]
}
Use "replace": false to merge your additions with Sable’s existing tag entries rather than overwriting them.

Tracking

Entities can be outside the plot of a sub-level but still move with it — for example a player standing on top of a moving ship, or livestock penned on a floating platform. When an entity is standing on (or riding) a sub-level, Sable marks it as tracking that sub-level. Entities that are tracking a sub-level:
  • Are networked relative to the sub-level, reducing positional jitter.
  • Are interpolated relative to the sub-level for smooth rendering.
  • Move with the sub-level as it rotates and translates.
Players that are tracking a sub-level additionally log out and log back in with a position relative to the sub-level, so they reconnect in the same spot on the structure regardless of where it has moved. To read the sub-level a given entity is currently tracking, use Sable.HELPER.getTrackingSubLevel():
Entity entity = ...;
SubLevel subLevel = Sable.HELPER.getTrackingSubLevel(entity);
getTrackingSubLevel returns null if the entity is not currently tracking any sub-level. This method is exposed through Sable.HELPER (the platform helper singleton) rather than as a static method on EntitySubLevelUtil.

EntitySubLevelUtil methods

EntitySubLevelUtil is the primary API surface for entity–sub-level interactions. The key methods are summarised below.
MethodDescription
kickEntity(SubLevel, Entity)Manually kicks an entity out of a sub-level. Transforms the entity’s position, velocity, and look-angle from sub-level local space to global space, and inherits sub-level velocity.
shouldKick(Entity)Returns true if the entity should be kicked (i.e. its type is not in #sable:retain_in_sub_level). Use this to replicate Sable’s default kicking decision in custom code.
setOldPosNoMovement(Entity)Sets the entity’s previous-tick position fields (xOld, yOld, zOld, etc.) to its current position, accounting for any tracking sub-level. Use this to suppress interpolated movement after a teleport.

Build docs developers (and LLMs) love