RetroAPI 0.3.4, the whole feature set

Everything a mod can use, in one page. Written to be handed to someone deciding whether the library covers what they need.

This page is not linked from the wiki; it exists to be shared by URL. Each row links to the page that explains it properly. For Minecraft Beta 1.7.3 on Ornithe (Fabric fork) or Babric, with or without StationAPI.

What changed since 0.3.0

0.3.0 was the big release. Everything since has been the same two jobs: fixing what shipped broken, and closing gaps where an API quietly did less than it looked like it did.

VersionWhat it was
0.3.1The client crashed on launch (a mixin shadowed a field name that does not exist, which is only checked when the game loads that class). Tags referencing other tags recursed until the stack died. Contextual tool tiers gained the player. A launch smoke suite now force-applies every mixin on both sides, with and without StationAPI, so this class of crash cannot ship again.
0.3.2Every item shared one set of components: a mutable default was handed out as a single shared instance, so mutating it wrote to every stack at once. Mods no longer inherit 56 unimplemented methods from the injected interfaces. The client stopped trying to load dedicated-server classes.
0.3.3A sweep for one shape of bug. Three placement APIs truncated a 12-bit state index to 4 bits. A tool tier could not refuse. Texture registration silently duplicated atlas slots. State placement could not skip neighbor notification. The conversion test pipeline documented four stages and ran three.
0.3.4Tinted item layers that can be declared on any item, including a subclass you do not own.

Entrypoints

FeatureWhat it gives you
retroapi entrypoint (RetroModInitializer.initRetro())Registration at the one moment it is safe: platform ready, before RetroAPI's own events, before recipes are sorted, before any world assigns ids. Fires identically with and without StationAPI, unlike the registration events.
retroapi-client / retroapi-serverSided halves for renderers, screens, particle factories / dedicated-server-only logic.
Named failuresA mod that throws during registration is reported by mod id and entrypoint, not as an anonymous trace inside RetroAPI.
OSL init still worksNothing is deprecated; both can be used side by side.

Entrypoints & sides →

Registration & ids

FeatureWhat it gives you
32,000 block slots, ids ≥ 256Block/Item arrays are grown; modded ids live outside vanilla's byte range.
Per-world id mapContent is anchored by namespace:name; numbers are leased per world and re-anchored on open.
Automatic id remap repairWhen ids move, RetroAPI repoints crafting and smelting recipes, fuels and achievement icons; the crafting list is re-sorted.
IdRemapCallbackYour own cached ItemStacks and raw ids get fixed too: remap.fix(stack), remap.map(id).
Multiplayer id syncThe server's table is applied on the client before any chunk or inventory packet is read.
Interface injectionBlock/Item expose the builders with no cast, on Ornithe and Babric.

How registration works → · World safety →

Blocks

FeatureCall
Builder, or wrap your own subclassRetroBlockAccess.create(Material), .of(block), .of(Ctor::new), .of(Ctor::new, Material)
Physical properties.strength(h[, r]), .resistance, .light, .opacity, .sounds, .nonOpaque, .bounds
Indestructible.unbreakable()
One texture.texture(id), or .sprite(index) to reuse a vanilla sprite
Per-face textures, no JSON.sided(top, side, front[, bottom]), .column(top, side), .textures(down, up, north, south, west, east)
Per-position color, no model.tint(provider), plus RetroBlockColors.GRASS / .FOLIAGE
Overlay passes, no renderer.overlay(texture[, tint]), .overlay(provider) - vanilla's grass-edge trick for any block
Orientation.facing() (4-way), .facingAll() (6-way, dispenser rule)
Harvest rules.mineable(tools…), .needsTool(tier), .tag(keys…), .alwaysDrops(), .effectiveTool(class)
Render type.renderType(id) + RenderType.register(id, renderer) for a custom renderer
Block itemsCreated automatically; RetroMetaBlockItem for per-meta names, custom factories supported
FlammabilityRetroFlammability (burn + spread chances, follows the block through id remaps)

Blocks →

Block states

FeatureWhat it gives you
Up to 4096 states per blockBits 0-3 ride vanilla metadata, bits 4-11 live in the region sidecar
Property typesRetroBoolProperty, RetroIntProperty, RetroEnumProperty, RetroCharProperty ('a'-'z', digits, or a set)
Interned immutable statesstate.with(P, v), state.get(P), getByName, == comparison is valid
Read/write in the worldRetroStates.get/set, with block updates, re-render and server→client sync
Placement that does not notifyRetroStates.setWithoutNotifyingNeighbors and placeWithoutNotifyingNeighbors (block + state in one call), for generation and any code that owns its surroundings. Still marks the position dirty and still syncs, because those are not neighbor updates.
A state index is 12 bitsLow nibble in vanilla metadata, bits 4-11 in the sidecar. Anything taking a bare meta can only carry the nibble, so every placement API has a state-taking form: RetroFeatures.setBlock, RetroWorldGen.setStateInChunk, RetroMultiblock.Match.fill.
Data-declared properties"properties" in a blockstate JSON; code wins on conflict
State-aware drops and placementWide states survive break → drop → place instead of truncating to the nibble

Block states →

Items, tools, food, armor

FeatureCall
Builder, atomic id allocationRetroItemAccess.create(), .of(item), .of(Ctor::new), AUTO_ID
Sprites.texture(id), .layers(base, overlays…), .overlay(id) - layered with no model JSON, flattened into the atlas
Tinted layers on ANY item.overlay(id, tint) draws as a render-time pass, so the 0xRRGGBB multiply survives (the flattened form cannot tint: by stitch time the layers are one image). Declared, not implemented, so it works on a subclass you did not write. .layer(RetroTextureLayer) for full control, getDeclaredLayers() to read them back.
Per-stack looks still winAn item implementing RetroLayeredTexture overrides the declared layers, so component-driven appearances are unaffected.
Held pose.handheld()
Tool kinds.tool(PICKAXE, AXE, …) - multi-kind paxels included
Tool tier.tier(TIER), .tier(stack -> …), .tier((stack, block, player) -> …) (contextual; the player arrived in 0.3.1)
A tier that refusesRetroToolTier.NONE sits below every tier, so it satisfies no requirement. null means "no opinion, fall through", and falling through lands on WOOD, so a lambda previously could not say no. isOre(block) ? DIAMOND : NONE.
Tag name from codeRetroToolTier.getTagName(), for building needs_<tier>_tool ids yourself.
Tools with no ToolMaterial.miningSpeed(f), .attackDamage(n), .durability(n), .damageOnMine(bool)
Vanilla agreementItem.isSuitableFor is answered from tags + tier, so drops, speed and the correct-tool check agree
Food.food(health[, meat][, onEaten]) - a property, not a subclass
ArmorRetroArmor + RetroArmorTexture for full sets

Items → · Tools, food & armor →

Tags

FeatureWhat it gives you
mineable/<tool> and needs_<tier>_toolModern decoupled semantics: kind grants speed, tier and material gate drops
Material-inferred defaultsAn untagged block behaves like the vanilla blocks it is made of, which is what stops "no tool can break my block"
Beta-accurate vanilla membershipCustom tools work on vanilla blocks, not only modded ones
Arbitrary block and item tagsRetroTagKey.block/item, RetroTags.addToTag/isIn/blocksIn/itemsIn/removeFromTag, live and mutable at runtime
Data filesdata/<ns>/tags/{block,blocks,item,items}/… and StationAPI's layout; unioned with code

Tags →

Recipes

FeatureCall
Shaped / shapelessRetroRecipes.addShaped/addShapeless, with a documented wildcard rule (bare Block/Item matches any metadata)
Smelting and fueladdSmelting, addFuel, getTotalFuelTime for custom machines
RemovalremoveRecipe(stack)
OrderingShaped-before-shapeless sorting is applied after registration and again after id remaps

Recipes & fuel →

Block entities & GUIs

FeatureWhat it gives you
RetroBlockEntities.registerString-id registration that round-trips through chunk NBT
BlockEntityLoadedCallbackFires on first tick, after NBT is read and the world exists - the pass beta lacks
RetroGuiRegistry / RetroGuisContainer + screen pairs, opened from either side, with window sync ids
Modded block entities in the sidecarSurvive save/load and world conversion

Block entities & GUIs →

Entities

FeatureWhat it gives you
RetroEntities.register(id, class).factory(…)String-id entity registration, works with or without StationAPI
Spawn networkingModded spawns ride RetroAPI's own channels; queued spawns are flushed when a joining player's channel is ready
RenderersRetroEntityRenderers, forwarded into StationAPI's dispatcher when present
Spawn rulesPer-biome spawn entries and spawn caps for modded mobs

Entities → · A mob in full →

Particles

FeatureCall
Particle registryRetroParticleRegistry.register(id, factory) - beta had no way to add one
Ready-made particleRetroSpriteParticle: .lifetime, .scale, .gravity, .drag, .tint, .shrink
Spawn from common codeRetroParticles.spawn, .spawnCloud, .spawnOnBlock, .spawnVanilla
Multiplayer bridgeThe protocol has no particle packet and vanilla's server listener is empty; RetroAPI forwards to players in range

Particles →

Sounds

FeatureWhat it gives you
AutoloaderDrop .ogg files in sounds/; numbered files become variants automatically
Explicit registrationRetroSounds for effects, streaming music and records
Multiplayer bridgeVanilla's server-side playSound is empty; RetroAPI forwards world sounds to players in range, with client-side de-duplication

Sounds & music →

Item components

FeatureWhat it gives you
RetroComponents.register(id, default, type)Typed per-stack data on a version with none: int, string, compound records, lists
Mutable defaults are per-stackA List/Set/Map default is copied for each stack that reads it, so mutating what get returns can never leak onto every other item. registerSupplied(id, supplier, type) covers a mutable default of your own type.
Persistence & networkingWritten into a namespaced NBT sub-tag; survives saves, inventories, dropped items and packets
PresentationComponent-driven tooltips and dynamic item textures

Item components →

Dimensions, biomes, world features

FeatureCall
DimensionsRetroDimensions.register(id, factory), stable serial ids, DIM<n> folders, forwarded into StationAPI when present
PortalsCustomPortal + teleporters, walk-in both directions, per-dimension travel messages
BiomesBiomeBuilder (colors, weather, spawn weights), StationAPI-shaped
Editing existing biomesRetroBiomes.addPassiveSpawn/addMonsterSpawn/…, additive so mods do not clobber each other
World featuresRetroFeatures.ore/cluster/custom with .size, .count, .heightRange, .rarity, .meta, .replace(blocks…), .dimensions(…) - no mixin into the generator
Custom chunk generatorsRetroWorldGen.createChunk/setBlockInChunk, correct in both storage models

Dimensions & portals → · Worldgen →

Rendering

FeatureWhat it gives you
Expanded texture atlasSprites beyond vanilla's 256, animated textures from .mcmeta or from code
JSON models & blockstatesMulti-element models, variant tables, cullfaces, custom UVs, tint indices
Render layersCutout and translucent passes for modded blocks
Custom block renderersBlockRenderContext: lit faces with smooth lighting, spriteOverride, flipTexture, faceRotation, renderAllFaces, renderFaceUv, renderFaceCorner - enough for connected textures
Voxel shapesMulti-box outlines, collision and raytracing for non-cube blocks

Models & render layers → · Voxel shapes →

Positions, directions, multiblocks

FeatureWhat it gives you
RetroVec3iImmutable block position: arithmetic, offsets, rotation, distances, and world access (blockId, state, setBlock, blockEntity)
RetroDirection / RetroFacingSix and four directions with opposite, rotateLeft/Right, vector, face, fromPlacer, nearest
RetroMultiblockPatterns drawn as ASCII layers, matched in one facing or all four, with per-character position lists and fill(…), by block + meta or by full state

Positions & multiblocks →

Networking, achievements, misc

FeatureWhat it gives you
Custom packetsOSL channels with typed buffers, both directions, main-thread hand-off
AchievementsRetroAchievements: own pages, icons from modded content, granting from gameplay
LangMod lang files, auto-generated fallback names
World eventsBlockSetCallback and the registration callbacks for reacting to other mods

Networking → · Achievements →

World safety

GuaranteeHow
Vanilla region data is never rewrittenModded ids ≥ 256, extra state bits and modded item data live in a sidecar beside the region files
Removing the mod does not corrupt the worldThe vanilla half was never touched; the modded half is simply absent
Ids may move between sessionsPer-world id_map.dat re-anchors everything by name
BackupsThe retroapi/ folder is copied aside before structural changes
Verified, not assertedHeadless test: place modded content, save, reload, assert; then convert vanilla → flattened → vanilla and assert again

World safety →

StationAPI interop

With StationAPI installedOwner
Registration, ids, storage, atlas, recipesStationAPI (RetroAPI forwards and stands down)
Entities, dimensions, components, particles, world features, multiblocks, sound/particle bridgesRetroAPI, unchanged
Your codeUnchanged, if you register from the retroapi entrypoint

StationAPI interop →

Toolchain

FeatureDetail
Two loader buildsretroapi-0.3.0.jar (Ornithe + OSL) and retroapi-0.3.0-babric.jar (self-contained)
Mavenhttps://matthewperiut.github.io/repositorycom.periut:retroapi:0.3.0
Templatesbare and feature showcase, both building against 0.3.0
Test harnessHeadless server self-checks and a vanilla↔StationAPI world-conversion round trip that fails the build on modded-data loss

← the full wiki