-
Notifications
You must be signed in to change notification settings - Fork 0
Home
Welcome to the Gadgets-And-Gizmos-Library wiki!
gadgetsngizmos is the reusable API shipped with Gadgets & Gizmos. It gives other mods typed access to controller input, precise kinetics, Sable bodies, physics helpers, ACC graph extensions, SCM controls, display frames, shipping reservations, tablet apps and shared client rendering.
This page specifies the supported 1.2.x library surface. Import the library packages, not the createthrusters addon implementation. If an integration needs a missing capability, add a small reusable contract to the library instead of reaching into an addon class.
- Supported versions
- Adding the library
- API rules
- Foundation and lifecycle
- Block entity probes and lookup
- Controllers and orientation
- Discovery, SubLevels and menus
- Kinetics and bearing heads
- Virtual kinetics and alternators
- Sable physics
- Client rendering
- ACC graph extensions
- Display integration
- SCM integration
- Shipping
- Tablet apps
- Complete public surface
- Lifecycle checklist
- Compatibility and failure behaviour
- Jar layout
| Component | Supported version |
|---|---|
| Library mod ID | gadgetsngizmos |
| Library API range | 1.2.x |
| Minecraft | 1.21.1 |
| Java | 21 |
| NeoForge |
21.1.225 or newer |
| Create |
6.0.10 or newer |
| Sable |
2.0.3 or newer compatible version |
| Simulated |
1.2.1 or newer compatible version |
| Aeroworks | Optional, 1.2.11 or newer when installed |
| AeroClaims | Optional, 0.9.0 or newer when installed |
The loader version and artifact label can differ while a beta is being built. Depend on the loader-facing 1.2.x API range unless a release says otherwise.
Use the standalone library jar while developing another mod. Do not compile against the addon jar just to reach library classes.
dependencies {
compileOnly files("libs/gadgetsngizmos-<version>.jar")
runtimeOnly files("libs/gadgetsngizmos-<version>.jar")
}Use the dependency form required by your NeoForge development plugin if it remaps local mod jars. The important part is that the standalone library is available on both the compile and development runtime classpaths.
Declare the loader dependency in your neoforge.mods.toml:
[[dependencies.your_mod_id]]
modId="gadgetsngizmos"
type="required"
versionRange="[1.2.0,1.3.0)"
ordering="AFTER"
side="BOTH"The library itself requires Create, Sable and Simulated. Your mod should still declare any of those dependencies it calls directly.
Replace the old standalone library jar with gadgetsngizmos; never keep both copies installed. Update loader dependencies to gadgetsngizmos and use the renamed public entry types shown below. Deprecated Java aliases remain so already-compiled beta integrations can still resolve their old class and method owners where the loader dependency allows them to start.
The addon itself still uses createthrusters for blocks, items, entities, recipes, translations, packets and saved content. Those IDs have not moved, so existing worlds keep their registered content and saved references. The library also removes the old Sable residency ticket as it retains the renamed ticket.
- Import supported types below
com.rieno.gadgetsandgizmos.lib. - Never import
com.rieno.gadgetsandgizmos.lib.mixin. - Never import
com.rieno.gadgetsandgizmos.content,compat,mixinorneoforgeclasses from the addon source set. - Bootstrap and event subscriber classes are lifecycle wiring. NeoForge calls them; another mod should not.
- Built-in ACC documents, screens, packets, SQLite stores and content block entities are addon implementation, not library API.
Use your own namespace for every registered graph node, tablet app, display source, SCM mode, probe factory and guard exception.
ResourceLocation id = ResourceLocation.fromNamespaceAndPath(
"your_mod", "steerable_nozzle");Treat IDs, serialized enum values, NBT keys and saved target references as persistent data. Do not build an ID from a translated label or a Java class name.
- Public snapshots and registry views are immutable unless their type says otherwise.
-
GraphValue, display envelopes, tablet storage values and other NBT boundaries copy mutable payloads. - Keep the UUID or registration ID needed to release anything you claim.
- Close leases and native handles. Unregister dynamic integrations when their owning mod or runtime feature goes away.
- Do not retain a live
BlockEntity,LevelorServerSubLevelas saved identity. Store the supplied stable target value instead.
| Registry | Normal registration |
|---|---|
| Graph definitions and runtimes | Keeps the existing identical entry and rejects a conflicting implementation |
| ACC display sources | Rejects a block that already has a source; registerIfAbsent reports the conflict |
| Tablet apps | Rejects a duplicate; replacement must use registerOrReplace
|
| Tablet client renderers | Rejects a duplicate; registerIfAbsent reports the conflict |
| Physics goggles overlays | Rejects a duplicate; replacement must use registerOrReplace
|
| SCM control modes | Replaces the entry under the same ID |
| SCM probe factories | Replaces the entry under the same ID |
Never replace an entry outside your namespace. Prefer the strict registration method when the registry supplies one.
- Physics, topology, control authority, shipping and tablet storage are server-side systems.
- Client render packages must only be loaded from client setup or another client-only class.
- Registry mutations belong in mod setup unless the registry explicitly supports a dynamic integration.
- Run level and block entity mutations on the owning game thread.
- A common/server class must not eagerly reference a client-only implementation type.
Required APIs are direct typed calls. Do not wrap Create, Sable, Simulated, NeoForge or this library in reflection just to avoid a dependency or import.
Reflection is only appropriate for a genuinely optional dependency, a supported upstream version split without one stable API, or unavoidable private upstream access. Keep that reflection inside one compatibility adapter, cache its lookups, expose a typed result and report a real failure. Never silently report success after a required call failed.
Package: com.rieno.gadgetsandgizmos.lib
| Type | Use |
|---|---|
GadgetsNGizmosLibrary |
Supplies the stable MOD_ID and shared library identity |
GadgetsNGizmosLibraryNeoForge |
NeoForge server/common entry point; lifecycle-owned |
PhysicsStaffPowerEvents |
NeoForge event bridge for Physics Staff operation cleanup; lifecycle-owned |
Package: com.rieno.gadgetsandgizmos.lib.client
| Type | Use |
|---|---|
GadgetsNGizmosLibraryClientBootstrap |
Installs the library client hooks and shaders; lifecycle-owned |
GadgetsNGizmosLibraryClientNeoForge |
NeoForge client entry point; lifecycle-owned |
GadgetsNGizmosLibraryConfigs owns the server settings for held angles, precise angle propagation, virtual kinetic propagation and kinetic guard logging. Read the settings when a compatible feature needs to respect them. Do not call its registration method or write the library config from another mod.
The old CreateThrustersLibrary, NeoForge entry point, client bootstrap, CTLibraryConfigs and CTKineticGuard names remain as deprecated compatibility aliases. New integrations must use the Gadgets & Gizmos names and depend on gadgetsngizmos.
The library automatically installs its own mixins and client setup. A consumer does not add the library mixin config to its own manifest.
Package: com.rieno.gadgetsandgizmos.lib.probe
Implement this on a block entity that exposes detailed named data without making the caller import its implementation class.
-
graphReadableData()publishes readable field IDs and value types. -
graphWritableData()publishes writable field IDs and value types. -
graphWritableOptions()optionally supplies allowed values or editor hints. -
readGraphValue(...)resolves one field. -
writeGraphValue(...)validates and applies one mutation.
Field IDs are part of your integration contract. Keep them stable after release.
Implement connectedBlockEntities() when a mechanism can expose its live related block entities. Return only loaded, current connections. The caller must handle an empty collection when a carriage, rope endpoint, bearing head or another member is unloaded.
This is the normal probe for questions such as "which carriages belong to this shaft" or "which body is connected to this mechanism". Do not expose the mechanism's private block entity type through the library contract.
Use this instead of duplicating root/SubLevel traversal.
| Method | Behaviour |
|---|---|
findIncludingSubLevels |
Finds a block entity at a world-facing position in the root level or a loaded SubLevel |
resolveIncludingSubLevels |
Returns the block entity together with its resolved internal position and SubLevel ID |
find |
Uses an optional saved SubLevel ID and can fall back to the root scope |
findExact |
Resolves only the requested scope |
findLoadedExact |
Resolves only an already-loaded target and never requests a load |
findInSubLevel |
Looks up one typed block entity inside a known SubLevel |
BlockEntityLookupApi.ResolvedBlockPosition keeps the resolved BlockPos and owning SubLevel UUID together. Keep both parts when a later packet or menu action must target the same body.
Package: com.rieno.gadgetsandgizmos.lib.control
| Type | Contract |
|---|---|
AnalogueChannel |
One configurable value with mode, limits, rate, smoothing, debounce, repeat, step and NBT state |
AnalogueAxis |
Combines negative and positive channels into a signed axis |
AnalogueChannelMode |
Stable channel behaviour IDs such as momentary, ramp, step, latch and direct |
AnalogueControlChannel |
Canonical named controller channels used by Gadgets & Gizmos integrations |
AnalogueSignalPacket |
Serializable channel update value |
AnalogueTransmissionTarget |
Receiver contract for transmitted analogue updates |
FrequencyBinding |
Persistent Create Redstone Link frequency pair |
CustomKeyEntry |
Persistent user-defined controller key entry |
Use the channel and axis types for deadzones, rise/fall rates, smoothing and input state. Do not reproduce those calculations in a screen, peripheral or block entity.
Implement IDirectControlReceiver when a block entity accepts a named direct value:
public final class MyNozzleBlockEntity extends BlockEntity
implements IDirectControlReceiver {
@Override
public void applyDirectControllerSignal(String channelId, float val) {
if (!"throttle".equals(channelId)) return;
setThrottle(Mth.clamp(val, 0.0F, 1.0F));
setChanged();
}
}ControllerDirectTargetReference stores a stable root/SubLevel target without retaining a live block entity. ControllerMechanic and ControllerMechanicBinding describe a supported controller mechanic and its configured binding.
DirectionalAnalogSource supplies local input. DirectionalAnalogMath applies deadzone and square/circular conversion. DirectionalAnalogSnapshot carries the resolved forward, back, left and right values. Use these together so controller screens, blocks and peripherals agree on diagonal input.
| Type | Contract |
|---|---|
OrientationPayload |
Serializable orientation value |
OrientationTarget |
Consumer of an orientation target |
LinkedOrientationSource |
Producer that can be linked to a target |
OrientationMath |
Shared orientation conversion and normalization helpers |
CardinalTiltController |
Resolves a facing direction and cardinal pulls into a clean tilt direction |
Angles in the control maths package are radians unless a method explicitly says degrees.
Package: com.rieno.gadgetsandgizmos.lib.control.hardware
HardwareControllerState is an immutable device snapshot with safe axis/button access. HardwareControllerBindings owns the hardware:* binding IDs, standard device layout, conventional channels and deadzone application. Use these IDs when a controller UI needs to save the same hardware binding format.
Package: com.rieno.gadgetsandgizmos.lib.control.math
| Type | Contract |
|---|---|
PidControllerMath |
Finite PID calculations and controller state |
LqrControllerMath |
Linear quadratic regulator calculations |
AdrcControllerMath |
ADRC calculations and state |
AdrcControllerNthOrderMath |
Nth-order ADRC calculations and state |
Vector3 |
Small immutable three-component maths value |
Quaternion |
Immutable quaternion maths value |
RotationMath |
Quaternion, Z-X-Z Euler and X-Y-Z Tait-Bryan conversions |
All helpers sanitize non-finite values at their API boundary. Keep one controller state per controlled system; sharing state between unrelated targets also shares their accumulated error.
Package: com.rieno.gadgetsandgizmos.lib.discovery
ControllerDiscoveryService.scanBlockEntities(...) builds stable ControllerDiscoveryNode values for loaded targets. Use classify(...) or classifyKind(...) when a custom UI needs the same classification without running a complete scan. ControllerDiscoveryKind contains the stable kind ID and translation key.
Implement INamedBlockEntity when discovery should show a useful player-facing name. The name is a display value, not a persistent identity.
SubLevelBlockEntityCollector is the compatibility collector for loaded Sable bodies and short-lived lazy-load operations. It can test or request target loading, identify plot positions, enumerate live bodies, read one loaded block entity and collect loaded world block entities around a position. Prefer BlockEntityLookupApi and SableLevelApi for ordinary typed lookup. Use the collector only when its load-aware enumeration behaviour is actually required; its Object-typed methods are retained for compatibility.
Package: com.rieno.gadgetsandgizmos.lib.physics
SableLevelApi is the typed ownership boundary:
-
serverLevel(...)resolves the rootServerLevelfrom a root or Sable level. -
containing(...)finds the loaded body containing a block, entity or precise position. -
containingId(...)returns its stable UUID. -
tracking(...)returns the body currently carrying an entity. -
subLevel(...)andsubLevels(...)resolve already-live bodies.
The methods call the required Sable API directly. An empty result means the target is absent or unavailable, not that reflection silently failed.
SubLevelConnectionApi.resolve(...) resolves one live SubLevel by UUID. merge(...) combines dependency sets without duplicate bodies. connectedTo(...) reads bodies published by connected block entities.
Use it when implementing BlockEntitySubLevelActor.sable$getConnectionDependencies:
@Override
public Iterable<SubLevel> sable$getConnectionDependencies() {
return SubLevelConnectionApi.connectedTo(connectedBlockEntities());
}Only publish real current links. Returning every nearby SubLevel makes unrelated assemblies one topology.
SubLevelAssemblyApi assembles an explicit set of blocks, assembles one block and disassembles a live body through typed Sable/Simulated calls. AssemblyResult reports the created body and moved-block offset. Null or empty selections return no body; assembleBlock(...) can throw Create's AssemblyException when the selected block cannot assemble.
SableSubLevelResidency is in lib.discovery. lease(...) creates an owner-scoped lease, retain(...) adds one live server body and synchronize(...) makes the retained set match a collection. Close the Lease when ownership ends. Use detach() during normal world shutdown or a block entity chunk transition when the saved ticket should survive that Java object. bootstrap() is lifecycle wiring and is called by the library.
Package: com.rieno.gadgetsandgizmos.lib.menuconfig
| Type | Contract |
|---|---|
MenuConfigTarget |
Block position plus optional SubLevel UUID |
MenuOpenHeader |
Encodes and decodes the target in menu opening data |
MenuBackedBlockEntityTarget<B> |
Menu contract exposing its typed target |
MenuBackedBlockEntityResolver |
Resolves the target in a server payload handler |
ISimulatedMenuOpen |
Marks a menu using the extended simulated target |
Use the header and resolver together. Sending only a BlockPos works in the root world but targets the wrong coordinates when the same block is mounted on a body.
Package: com.rieno.gadgetsandgizmos.lib.kinetics
| Type | Contract |
|---|---|
HeldKineticAngleAccess |
Stores the held kinetic angle exposed by the library mixin |
PreciseKineticOutputAccess |
Applies or clears one exact output angle |
DirectionalPreciseKineticOutputAccess |
Applies an exact angle for a selected face |
PreciseKineticOutputBoundary |
Marker for a graph boundary that owns precise output behaviour |
KineticAngleHelper |
Normalizes, compares and resolves kinetic angles |
KineticGraphHelper |
Shared Create kinetic graph traversal |
HeldAngleKineticGraph |
Applies held angles through a compatible graph |
PreciseKineticOutputGraph |
Applies precise output angles through a compatible graph |
The graph helpers return ApplyResult values so a caller can distinguish a handled update from an unavailable or incompatible target. Use the supplied synchronizer callback when the changed block entity needs an explicit sync.
GadgetsNGizmosKineticGuard owns configuration-aware package guards used by the library mixins. Register a keyed exception only for a compatible block that must cross one guard. A throwing predicate is logged and treated as no match. Unregister a dynamic exception when its integration unloads.
SingleFaceRotationConfiguration supplies the standard one-face IRotate implementation.
ServoMotionController is the reusable bounded servo planner. Construct it with ServoMotionController.ServoMotionConfig, call update(...) while active and read the current angle and generated speed.
Use applySyncedState(angle, speed) when restoring client sync or persisted state. It updates the current state without scheduling new motion.
BearingHead contains the stable PRIMARY and SECONDARY serialized IDs and colours. The legacy names cyan, left and top resolve to PRIMARY; orange, right and bottom resolve to SECONDARY.
Implement BearingHeadAccess when a bearing exposes one or more controllable heads. The contract covers:
- current, target and interpolated angle
- angle range and range updates
- direct target updates
- mounted block and mounted SubLevel identity
- assembly and disassembly state of the mounted head
Use BearingAngleDriver to drive the first compatible downstream Create or Simulated bearing. Its BlockEntitySynchronizer lets the host perform the correct sync without the helper importing addon networking.
Package: com.rieno.gadgetsandgizmos.lib.virtualkinetics
| Type | Contract |
|---|---|
VirtualKineticProvider |
Real owner that exposes virtual kinetic members |
VirtualKineticBlockEntity |
One virtual member participating in the Create graph |
VirtualKineticHostBlock |
Host-state access for a virtual member |
VirtualKineticPos |
Stable owner position and slot identity |
The library mixins handle graph lookup, source resolution, persistence and propagation after these contracts are implemented. Keep a virtual slot stable for the lifetime of its saved block entity.
Package: com.rieno.gadgetsandgizmos.lib.power.alternator
Implement AlternatorTuning with minimum RPM, rated RPM, maximum FE per tick and maximum stress impact. AlternatorKinetics supplies matching effective RPM, output and stress calculations.
AlternatorTuning tuning = new AlternatorTuning() {
public double minRpm() { return 32.0D; }
public double ratedRpm() { return 256.0D; }
public int maxFePerTick() { return 4096; }
public double maxStressImpact() { return 16.0D; }
};
int fePerTick = AlternatorKinetics.generatedFePerTick(speed, tuning);
float stress = AlternatorKinetics.stressAtSpeed(speed, tuning);Package: com.rieno.gadgetsandgizmos.lib.physics
SableSubLevelTelemetryApi.sample(...) reads one already-loaded body without forcing a load. Its Snapshot separates loaded from physicsAvailable and exposes finite position, linear/angular velocity, speed and mass.
SableTransformApi converts points and directions between root and SubLevel space, projects through one or every nested body, measures transformed distances and finds loaded bodies intersecting a world box.
SableAssemblyBoundsApi.envelope(...) combines loaded SubLevel world bounds around a world-space reference point. Envelope exposes a conservative horizontal radius, height and lower-hull offset. Missing bodies return Envelope.DEFAULT.
- Use
projectOutOne(...)for one immediate body boundary. - Use
projectOut(...)for the complete nested chain. - Use
kick(...)only when intentionally moving an entity into the supplied SubLevel. - Treat an empty lookup as unavailable and retry from a later lifecycle event when appropriate.
Implement SableAssemblyConnectionProvider on a BlockEntitySubLevelActor when the actor publishes an explicit assembly link. Each SableAssemblyConnection is STRUCTURAL or CARRIAGE_COUPLER.
SableAssemblyTopologyApi.discover(...) creates a deterministic connected topology around a loaded root body. Actor dependencies are treated as undirected. Optional ActorFilter and ActorClassifier callbacks select and classify actors.
Topology contains ordered bodies and edges, graph depth, coupler depth, structural carriage partitions and a stable fingerprint. Removing coupler edges creates the carriage partitions; the partition containing the requested root is primary.
Use SableAssemblyTopologyCache for continuous control. It keeps the topology until its revision changes and performs a staggered safety refresh. Call SableAssemblyTopologyInvalidation.invalidate(...) when a connection changes outside a known library event.
private final SableAssemblyTopologyCache topologyCache =
new SableAssemblyTopologyCache();
void tickControl(ServerSubLevel root) {
SableAssemblyTopologyApi.Topology topology = topologyCache.get(root);
SableAssemblyDynamicsApi.Snapshot dynamics =
SableAssemblyDynamicsApi.sample(topology);
if (!topology.available()
|| !dynamics.loaded()
|| !dynamics.physicsAvailable()) return;
// Reuse the same topology and dynamics snapshot for this control tick
}SableAssemblyTopologyEvents is the library event bridge and is not called by consumers.
SableAssemblyDynamicsApi.sample(topology) samples exactly the topology already selected. Its Snapshot contains root-local aggregate mass, centre of mass, inertia, inverse inertia and ordered BodyDynamics entries. Use aggregate(...) for one selected subset. A missing or mass-unavailable selected body returns a loaded zero aggregate instead of a misleading partial mass.
SablePointImpulseApi.apply(...) and applyDirectional(...) validate finite values, write one point impulse and wake the body only after a successful write. A non-finite queued accumulator is cleared before it reaches Sable.
SableMagneticCaptureApi.pullTogether(...) applies bounded equal-and-opposite pulls between two loaded bodies. Supply local anchors, capture radius, maximum closing acceleration and physics time step. Invalid, coincident and out-of-range bodies are ignored.
SableYawJointApi.create(...) creates a rotary joint that locks translation, pitch and roll while allowing yaw around the supplied local axes. Joint exposes validity, contacts, servo setup, true zero-force disable, wake, removal and close(). Contacts start disabled.
progressiveResponse(...) returns a smooth dead-zone spring, damping and force response. It stays exactly zero through the free angle, rises smoothly and saturates at the supplied maximum. It is a soft force response, not a native hard angular limit.
SableConstraintApi is the one supported compatibility facade for Sable constraint package differences. It supplies fixed, free and generic configurations plus add, frame, wake and remove operations. Do not reproduce its compatibility reflection in feature code. Use stable typed Sable calls directly for APIs that do not vary.
SubLevelParticleOcclusion provides shared collision, clearance and particle-occlusion queries over loaded plots. ProbeCache reuses repeated query state and SweptBoundsScan describes a swept collision result. Empty results mean the body could not be queried.
Package: com.rieno.gadgetsandgizmos.lib.client.render
All types in this section are client-only.
AreaHighlightRenderTypes supplies the registered translucent highlight render type. The library client bootstrap owns shader registration.
SubLevelClientRenderApi.withPoses(...) installs interpolated Sable poses for one lookup or raycast and always restores the previous provider. renderPosition(...) returns the interpolated render position of one ClientSubLevel.
Register an extra HUD layer through PhysicsGogglesOverlayRegistry:
PhysicsGogglesOverlayRegistry.register(
ResourceLocation.fromNamespaceAndPath("your_mod", "engine_load"),
ctx -> drawEngineLoad(ctx.graphics(), ctx.target(), ctx.partialTick()));Context supplies the GUI graphics, player, root level, looked-at block entity, active SubLevel ID and partial tick. register(...) rejects ID conflicts. Use registerOrReplace(...) only for an integration you own, and unregister(...) when a dynamic layer unloads. One failing renderer is logged with its exception and does not stop later layers.
SimulatedDiagramMiniRenderer embeds the Simulated diagram in another screen. Supply a DiagramDataSource; each force entry implements DiagramForceData.
The renderer owns its input forwarding, hosted tick and cleanup. Failed setup is logged with the operation, attempt and retry delay, then retried with bounded backoff. Stable Simulated APIs are called directly and are assumed to be present.
DiagramScreenAccess is the mixin-backed bridge for upstream private screen details. The library installs it automatically. Consumers may use the typed bridge where required but must not implement it or call the mixin class.
Package: com.rieno.gadgetsandgizmos.lib.client.tablet
TabletAppClientRenderer draws one registered tablet app. TabletAppClientContext supplies its definition, snapshot, safe canvas, input state and ActionSender. Register it through TabletAppClientRegistry during client setup. Apps without a custom renderer use the standard layout.
Package: com.rieno.gadgetsandgizmos.lib.graph
Register one GraphNodeDefinition and a matching GraphNodeExecutor under the same stable ID:
ResourceLocation nodeId = ResourceLocation.fromNamespaceAndPath(
"your_mod", "scale");
GraphApi.nodes().register(new GraphNodeDefinition(
nodeId.toString(),
"math",
Map.of("value", "number", "factor", "number"),
Map.of("value", "number"),
false));
GraphApi.runtimes().register(nodeId.toString(), (ctx, inputs) -> Map.of(
"value", GraphValue.number(
inputs.get("value").asNumber()
* inputs.get("factor").asNumber())));GraphNodeDefinition describes the editor category, typed ports and persistent-state requirement. GraphNodeExecutor receives immutable inputs and GraphExecutionContext.
GraphValue supports numbers, booleans, strings, lists and maps. Factory methods normalize values, defensively copy nested collections and reject recursive collections and mutable arrays. Use asNumber, asBoolean and asString for the normal conversions.
GraphExecutionContext supplies the current tick, namespaced persistent state and typed optional host services. Define a GraphServiceKey<T> when a reusable node needs a host service. GraphHostServices.BLOCK_ENTITY exposes the common host block entity without leaking the addon controller type.
The deprecated raw services() map is an empty compatibility method. Do not build a new integration on string keys or Object casts.
| Type | Contract |
|---|---|
GraphModel |
Addon-owned node and edge document model |
GraphCompiler |
Validates and compiles a graph model |
CompiledGraph |
Immutable indexed nodes, ports and data/execution edges |
GraphNodeRegistry |
Conflict-safe definition registry with immutable snapshots |
GraphRuntimeRegistry |
Conflict-safe executor registry with immutable snapshots |
GraphEventScheduler |
Bounded immediate and delayed event queues with cancellation and cleanup |
GraphEventScheduler releases delayed events deterministically by tick. Clear a scheduler when the owning runtime is removed.
Package: com.rieno.gadgetsandgizmos.lib.graph.render
GraphViewport contains client-free pan, zoom and coordinate conversion. GraphWireGeometry produces points and segments for graph wires. The ACC editor and its document format remain addon implementation.
Package: com.rieno.gadgetsandgizmos.lib.display
DisplayFrameEnvelope.create(...) copies a render payload, keeps presentation metadata separate and records its pixel size. Use payload(...), presentation(...) and requestedMode(...) to read it. hasRenderablePayload(...) validates the supported text, terminal and widget shapes.
CompoundTag frame = DisplayFrameEnvelope.create(
payload, presentation, 256, 128);
if (DisplayFrameEnvelope.hasRenderablePayload(
DisplayFrameEnvelope.payload(frame))) {
forwardFrame(frame);
}Preserve the public envelope keys when relaying a frame. Do not merge presentation fields into the source payload.
AccDisplaySourceRegistry registers one block type with an AccDisplaySource. The source returns the normal render payload for a requested size and can handle normalized click/input events when interactive.
AccDisplaySourceRegistry.register(
ResourceLocation.fromNamespaceAndPath(
"your_mod", "weather_station"),
YOUR_WEATHER_STATION.get(),
(source, width, height) -> {
CompoundTag frame = new CompoundTag();
frame.putString("Format", "text");
frame.putString("Source", "Weather Station");
return frame;
});Normal register(...) rejects a conflict. registerIfAbsent(...) is for optional cooperative integration. Call unregister(...) when a dynamic source disappears.
DisplaySurfaceProjection.normalizedPoint(...) converts a local tile hit into normalized joined-display coordinates and accounts for the texture-pixel border. Point contains the normalized X/Y result.
ShipInformationDisplayModes is the canonical mode list. Use ids, contains, normalize, label and isStaticText rather than copying mode strings.
Package: com.rieno.gadgetsandgizmos.lib.scm
Implement ScmControlMode to convert one navigation sample into world-space force and torque. ControlInput supplies pose, velocity, route direction, accumulated error, clearances and navigation limits. ControlOutput contains force, torque, gravity compensation, upright stabilization and drive direction.
ScmControlModeRegistry.register(new ScmControlMode() {
public ResourceLocation id() {
return ResourceLocation.fromNamespaceAndPath(
"your_mod", "submarine");
}
public String displayName() {
return "Submarine";
}
public ControlOutput navigate(ControlInput input) {
return new ControlOutput(
force, torque, false, 0.0D, 1.0D);
}
});ScmControlModeRegistry.register(...) installs or replaces the mode under its ID. Release a dynamic non-built-in mode with unregister(...). resolve(...), modes() and serializedIds() provide stable read access. Only replace an ID owned by your mod.
ScmBuiltinControlModes exposes the built-in AIRSHIP_ID, PLANE_ID and CAR_ID. ScmFlightBehavior owns the saved direct_vector and prefer_ship_direction values. Custom modes always use their own namespace.
ScmTarget is a stable SubLevel-aware selected block and face. stableId() is suitable for saved map references.
Implement ScmControlProbe for a reversible control the SCM can calibrate. A probe supplies:
- stable adapter ID and display name
- optional shared control group ID
- minimum and maximum control
- neutral control, which defaults to zero
- apply and exact restore operations
- live
Reading - target-sublevel-local effect direction and position
- current availability
Register a factory through ScmControlProbeRegistry:
ScmControlProbeRegistry.register(
ResourceLocation.fromNamespaceAndPath(
"your_mod", "steerable_nozzle"),
100,
(blockEntity, ctx) -> blockEntity instanceof MyNozzleBlockEntity nozzle
? List.of(new MyNozzleProbe(nozzle, ctx.target()))
: List.of());The Context supplies the selected target, target-sublevel-local suggested direction and full linked target list. Registering the same factory ID replaces its previous entry, so only replace IDs owned by your mod. A factory returns zero or more probes. neutralControl() must disengage the control without detaching it or changing ownership. The probe must restore the exact original state after every sample, including failed or cancelled calibration.
ScmMapCompositionApi composes a primary fragment and connected fragments deterministically. Fragment carries an ID, owner, coverage set and value. SelectedFragment records the chosen order. Composition exposes accepted fragments, rejected duplicate IDs, values and ownership queries.
ScmControlAuthorityApi.claim(...) elects one controller for a server/assembly key across tick boundaries. Claim while active, respect ownerChanged before writing outputs, heartbeat by reclaiming with the current tick and release when control ends. Owner records controller ID, priority and expiry. ClaimResult records whether the caller won and whether ownership changed.
ScmControlProbeRegistry and ScmControlModeRegistry are separate. A mode decides navigation demand; a probe describes one reversible physical control.
Package: com.rieno.gadgetsandgizmos.lib.shipping
ShipLogisticsRun is the immutable persistent model for named ITEM, FLUID, ENERGY and FUEL runs. Each Endpoint stores a SubLevel UUID and internal block position. Runs and endpoints support NBT conversion.
Use withName(...) and withEndpoints(...) to create changed copies. isFuelRun() distinguishes the combined refuelling contract from normal single-resource routes.
ShipDockScheduler reserves interchangeable named resources without importing the addon Ship Dock block. DockSlot.resource(...) can represent a connector, berth or another deterministic resource. RequestKey gives one vessel independent channels; the UUID overload remains the primary dock channel.
ShipDockScheduler scheduler = ShipDockScheduler.get(server);
ShipDockScheduler.Lease lease = scheduler.request(
new ShipDockScheduler.RequestKey(shipId, "holding"),
candidates,
occupiedSlots,
currentSlot,
new ShipDockScheduler.RequestPriority(
distance, etaTicks, committed),
new ShipDockScheduler.VesselEnvelope(
radius, height, bottomOffset),
level.getGameTime());
scheduler.heartbeat(
new ShipDockScheduler.RequestKey(shipId, "holding"),
priority, level.getGameTime());
scheduler.release(new ShipDockScheduler.RequestKey(shipId, "holding"));RequestPriority contains distance, ETA and committed state. VesselEnvelope carries conservative radius, height and lower-hull offset, with enclosed-volume and footprint fit helpers. Lease returns the granted dock/resource or the queue position plus a size-aware HoldingPlacement for safe fallback lanes.
Call release(RequestKey) for one channel and release(UUID) only when every channel owned by that vessel should be removed. Call removeDock(...) when a dock disappears. Call shutdown(server) during server stopping and finishShutdown(server) after stop so late requests are rejected and the server reference is released.
Package: com.rieno.gadgetsandgizmos.lib.tablet
TabletAppDefinition describes a stable app ID, title, description, accent colour, icon, immutable tabs and declared shared keys. TabletTabDefinition describes a tab, action IDs and which actions require keyboard input.
TabletAction carries the selected app, tab, action and string arguments. TabletActionContext supplies the authenticated player, tablet stack and optional SubLevel-aware target, including placed-tablet source data.
Register the definition and server handler during common setup:
TabletAppRegistry.register(definition, (ctx, action) -> {
if (!"refresh".equals(action.actionId())) {
return TabletActionHandler.Result.failure(
Component.literal("Unknown action"));
}
// Validate the player and target before changing app data
return TabletActionHandler.Result.success(
Component.literal("Updated"));
});register(...) rejects a conflict. Use registerIfAbsent(...) for cooperative optional support and registerOrReplace(...) only for an app you own. TabletAppRegistry.snapshot() returns a revisioned immutable app list for long-lived screens.
TabletStorage is the server persistence contract. TabletStorageApi.storage() returns the installed provider; available() tells a standalone consumer whether one is installed. install(...) and uninstall(...) belong to the storage owner, not normal app code.
Storage is keyed by logical tablet UUID. Physical tablets sharing that UUID intentionally share installed apps, app data, bindings, routes and SCM workspace data.
Declare cross-app records in TabletAppDefinition.sharedDataKeys. shared(...) and updateShared(...) reject undeclared keys and keep ownership under the source app.
TabletNotification is the immutable persisted notification value. TabletNotifications supplies an app-owned inbox. Post with a stable notification ID to create or replace one entry, then dismiss or clear it when resolved. The tablet status bar and app badges use the shared count.
TabletInteractionMode owns the persisted STANDARD, READER and PUSH values.
Register a TabletAppClientRenderer with TabletAppClientRegistry during client setup. Its TabletAppClientContext supplies the app snapshot, safe canvas and action sender. Do not execute server mutations directly from the renderer; send a declared action and validate it again in the server handler.
The following tables are the complete supported top-level surface for 1.2.x. Nested records and interfaces are listed with their owning type. Lifecycle-only types are marked and mixin implementation classes are excluded.
| Package | Types |
|---|---|
lib |
GadgetsNGizmosLibrary; GadgetsNGizmosLibraryNeoForge (lifecycle); CreateThrustersLibrary; CreateThrustersLibraryNeoForge (deprecated aliases); PhysicsStaffPowerEvents (lifecycle)
|
lib.client |
GadgetsNGizmosLibraryClientBootstrap; GadgetsNGizmosLibraryClientNeoForge (lifecycle); CreateThrustersLibraryClientBootstrap; CreateThrustersLibraryClientNeoForge (deprecated aliases)
|
lib.config |
GadgetsNGizmosLibraryConfigs (Server); CTLibraryConfigs (deprecated alias)
|
lib.compat |
PhysicsStaffPowerHooks (StaffActionFailure); PhysicsStaffPowerTracker; PhysicsStaffInteractionGuard
|
PhysicsStaffPowerHooks validates Backtank-powered staff actions, consumes pressure, supplies tooltip values and calculates mass-based drag/lock drain. PhysicsStaffPowerTracker owns active operation state. PhysicsStaffInteractionGuard protects SCM initialization targets and applies optional AeroClaims permission checks. These are Physics Staff integration contracts, not a general claims or energy API.
| Package | Types |
|---|---|
lib.probe |
BlockEntityDataProvider; BlockEntityLookupApi (ResolvedBlockPosition); ConnectedBlockEntityProvider
|
lib.control |
AnalogueAxis; AnalogueChannel; AnalogueChannelMode; AnalogueControlChannel; AnalogueSignalPacket; AnalogueTransmissionTarget; ControllerDirectTargetReference; ControllerMechanic; ControllerMechanicBinding; CustomKeyEntry; DirectionalAnalogMath; DirectionalAnalogSnapshot; DirectionalAnalogSource; FrequencyBinding; IDirectControlReceiver; LinkedOrientationSource; OrientationMath; OrientationPayload; OrientationTarget
|
lib.control.hardware |
HardwareControllerBindings (BindingOption); HardwareControllerState
|
lib.control.math |
AdrcControllerMath (State, Result); AdrcControllerNthOrderMath (State, Result); LqrControllerMath; PidControllerMath; Quaternion; RotationMath; Vector3
|
lib.gimbal |
CardinalTiltController (Builder, CardinalPulls) |
lib.discovery |
ControllerDiscoveryKind; ControllerDiscoveryNode; ControllerDiscoveryService; INamedBlockEntity; SableSubLevelResidency (Lease); SubLevelBlockEntityCollector
|
| Package | Types |
|---|---|
lib.kinetics |
BearingAngleDriver (BlockEntitySynchronizer); BearingHead; BearingHeadAccess; GadgetsNGizmosKineticGuard; CTKineticGuard (deprecated alias); DirectionalPreciseKineticOutputAccess; HeldAngleKineticGraph (ApplyResult, KineticTargetSynchronizer); HeldKineticAngleAccess; KineticAngleHelper; KineticGraphHelper; PreciseKineticOutputAccess; PreciseKineticOutputBoundary; PreciseKineticOutputGraph (ApplyResult); ServoMotionController (ServoMotionConfig); SingleFaceRotationConfiguration
|
lib.virtualkinetics |
VirtualKineticBlockEntity; VirtualKineticHostBlock; VirtualKineticPos; VirtualKineticProvider
|
lib.power.alternator |
AlternatorKinetics; AlternatorTuning
|
lib.menuconfig |
ISimulatedMenuOpen; MenuBackedBlockEntityResolver; MenuBackedBlockEntityTarget; MenuConfigTarget; MenuOpenHeader
|
| Type | Nested/public values and use |
|---|---|
SableAssemblyConnection |
Stable structural or carriage-coupler edge |
SableAssemblyConnectionProvider |
Actor-supplied explicit connection contract |
SableAssemblyDynamicsApi |
Snapshot, BodyDynamics, Tensor; samples complete or selected topology dynamics |
SableAssemblyTopologyApi |
ActorFilter, ActorClassifier, Body, Edge, CarriagePartition, Topology; deterministic body graph |
SableAssemblyTopologyCache |
Revision-aware reusable topology cache |
SableAssemblyTopologyEvents |
NeoForge invalidation bridge (lifecycle) |
SableAssemblyTopologyInvalidation |
Explicit topology revision invalidation |
SableConstraintApi |
Supported Sable constraint compatibility facade |
SableLevelApi |
Typed root/SubLevel ownership and lookup |
SableMagneticCaptureApi |
Bounded equal-and-opposite magnetic pull |
SablePointImpulseApi |
Validated point and directional impulses |
SableSubLevelTelemetryApi |
Snapshot; finite loaded-body telemetry |
SableAssemblyBoundsApi |
Envelope; conservative loaded-assembly radius, height and lower-hull offset |
SableTransformApi |
Root/SubLevel point, direction, distance and bounds transforms |
SableYawJointApi |
Joint, ProgressiveYawResponse; constrained yaw joint ownership |
SubLevelAssemblyApi |
AssemblyResult; typed assembly and disassembly |
SubLevelConnectionApi |
Actor dependency resolution and merging |
SubLevelParticleOcclusion |
ProbeCache, SweptBoundsScan; plot collision and occlusion queries |
| Package | Types |
|---|---|
lib.graph |
CompiledGraph (Port); GraphApi; GraphCompiler; GraphEventScheduler (Scheduled); GraphExecutionContext; GraphHostServices; GraphModel (Node, Edge); GraphNodeDefinition; GraphNodeExecutor; GraphNodeRegistry; GraphRuntimeRegistry; GraphServiceKey; GraphValue
|
lib.graph.render |
GraphViewport; GraphWireGeometry (Point, Segment) |
lib.display |
AccDisplaySource; AccDisplaySourceRegistry; DisplayFrameEnvelope; DisplaySurfaceProjection (Point); ShipInformationDisplayModes
|
| Package | Types |
|---|---|
lib.scm |
ScmBuiltinControlModes; ScmControlAuthorityApi (Owner, ClaimResult); ScmControlMode (ControlInput, ControlOutput); ScmControlModeRegistry; ScmControlProbe (Reading); ScmControlProbeRegistry (Context, Factory); ScmFlightBehavior; ScmMapCompositionApi (Fragment, SelectedFragment, Composition); ScmTarget
|
lib.shipping |
ShipDockScheduler (DockSlot, RequestKey, VesselEnvelope, HoldingPlacement, RequestPriority, Lease); ShipLogisticsRun (ResourceType, Endpoint) |
| Package | Types |
|---|---|
lib.tablet |
TabletAction; TabletActionContext; TabletActionHandler (Result); TabletAppDefinition; TabletAppRegistry (Snapshot); TabletInteractionMode; TabletNotification; TabletNotifications; TabletStorage; TabletStorageApi; TabletTabDefinition
|
lib.client.tablet |
TabletAppClientContext (ActionSender); TabletAppClientRegistry; TabletAppClientRenderer
|
lib.client.render |
AreaHighlightRenderTypes; DiagramDataSource; DiagramForceData; DiagramScreenAccess (library bridge); PhysicsGogglesOverlayRegistry (Context, Renderer); SimulatedDiagramMiniRenderer; SubLevelClientRenderApi
|
- Register graph definitions and executors under your namespace.
- Register SCM modes and probe factories.
- Register display sources and tablet app definitions.
- Register kinetic guard exceptions only when the compatible block needs one.
- Keep any registration handle or ID needed for later removal.
- Register tablet renderers and physics-goggles overlays.
- Create mini diagram renderers from the owning screen, not common setup.
- Keep all client render imports behind a client-only class boundary.
- Resolve saved targets through the root/SubLevel APIs.
- Treat unloaded bodies and missing block entities as normal unavailable state.
- Reuse topology caches and per-tick snapshots.
- Claim SCM control before writing outputs.
- Heartbeat dock reservations and release them on every exit path.
- Validate players, targets and declared actions again on the server.
- Close
SableSubLevelResidency.LeaseandSableYawJointApi.Jointowners. - Release SCM authority and dock scheduler requests.
- Clear graph event schedulers owned by removed runtimes.
- Unregister dynamic overlays, display sources, apps, modes, probes and guard exceptions.
- Shut down server-owned schedulers at the correct server lifecycle event.
A missing, removed or unloaded SubLevel is normal. Use the empty, unavailable or loaded=false result supplied by the API. Retry from a real tick, load or connection event when the feature can continue later. Do not force-load a ship just to complete an optional UI or control query.
Maths and physics APIs sanitize non-finite numeric input where documented. Graph, tablet, display and client overlay registries reject normal registration conflicts. SCM mode and probe registration replaces the entry under the same ID, so never register over another mod's namespace. Parsers may return an unavailable value for malformed saved data. Do not replace those outcomes with guessed defaults that could target another body or control.
Keep optional-mod integration in one adapter. Check the mod is loaded before calling it and do not expose its classes through your public contract. Aeroworks and AeroClaims hooks in this library already follow that boundary.
Patch and beta releases may add methods and types without breaking the 1.2.x contract. A removed method, changed serialized ID or changed ownership rule requires a documented compatibility decision. Compile against the same library version you test at runtime.
-
gadgets-and-gizmos-lib-<version>.jaris the reusable library mod. -
gadgets-and-gizmos-<version>.jaris the Gadgets & Gizmos addon and requires the library jar. -
gadgets-and-gizmos-bundled-<version>.jaris the distribution wrapper containing both jars as separate NeoForge Jar-in-Jar entries.
The addon source set may depend on the library source set. The library source set must never import addon classes. If a reusable integration needs addon knowledge, add a typed contract, callback, registry or value object to the library and make the addon implement it.