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.
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.
| Version | What it was |
| 0.3.1 | The 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.2 | Every 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.3 | A 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.4 | Tinted item layers that can be declared on any item, including a subclass you do not own. |
| Feature | What 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-server | Sided halves for renderers, screens, particle factories / dedicated-server-only logic. |
| Named failures | A mod that throws during registration is reported by mod id and entrypoint, not as an anonymous trace inside RetroAPI. |
OSL init still works | Nothing is deprecated; both can be used side by side. |
| Feature | What it gives you |
| 32,000 block slots, ids ≥ 256 | Block/Item arrays are grown; modded ids live outside vanilla's byte range. |
| Per-world id map | Content is anchored by namespace:name; numbers are leased per world and re-anchored on open. |
| Automatic id remap repair | When ids move, RetroAPI repoints crafting and smelting recipes, fuels and achievement icons; the crafting list is re-sorted. |
IdRemapCallback | Your own cached ItemStacks and raw ids get fixed too: remap.fix(stack), remap.map(id). |
| Multiplayer id sync | The server's table is applied on the client before any chunk or inventory packet is read. |
| Interface injection | Block/Item expose the builders with no cast, on Ornithe and Babric. |
| Feature | Call |
| Builder, or wrap your own subclass | RetroBlockAccess.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 items | Created automatically; RetroMetaBlockItem for per-meta names, custom factories supported |
| Flammability | RetroFlammability (burn + spread chances, follows the block through id remaps) |
| Feature | What it gives you |
| Up to 4096 states per block | Bits 0-3 ride vanilla metadata, bits 4-11 live in the region sidecar |
| Property types | RetroBoolProperty, RetroIntProperty, RetroEnumProperty, RetroCharProperty ('a'-'z', digits, or a set) |
| Interned immutable states | state.with(P, v), state.get(P), getByName, == comparison is valid |
| Read/write in the world | RetroStates.get/set, with block updates, re-render and server→client sync |
| Placement that does not notify | RetroStates.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 bits | Low 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 placement | Wide states survive break → drop → place instead of truncating to the nibble |
| Feature | Call |
| Builder, atomic id allocation | RetroItemAccess.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 win | An 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 refuses | RetroToolTier.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 code | RetroToolTier.getTagName(), for building needs_<tier>_tool ids yourself. |
Tools with no ToolMaterial | .miningSpeed(f), .attackDamage(n), .durability(n), .damageOnMine(bool) |
| Vanilla agreement | Item.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 |
| Armor | RetroArmor + RetroArmorTexture for full sets |
| Feature | What it gives you |
mineable/<tool> and needs_<tier>_tool | Modern decoupled semantics: kind grants speed, tier and material gate drops |
| Material-inferred defaults | An untagged block behaves like the vanilla blocks it is made of, which is what stops "no tool can break my block" |
| Beta-accurate vanilla membership | Custom tools work on vanilla blocks, not only modded ones |
| Arbitrary block and item tags | RetroTagKey.block/item, RetroTags.addToTag/isIn/blocksIn/itemsIn/removeFromTag, live and mutable at runtime |
| Data files | data/<ns>/tags/{block,blocks,item,items}/… and StationAPI's layout; unioned with code |
| Feature | What it gives you |
RetroBlockEntities.register | String-id registration that round-trips through chunk NBT |
BlockEntityLoadedCallback | Fires on first tick, after NBT is read and the world exists - the pass beta lacks |
RetroGuiRegistry / RetroGuis | Container + screen pairs, opened from either side, with window sync ids |
| Modded block entities in the sidecar | Survive save/load and world conversion |
| Feature | Call |
| Particle registry | RetroParticleRegistry.register(id, factory) - beta had no way to add one |
| Ready-made particle | RetroSpriteParticle: .lifetime, .scale, .gravity, .drag, .tint, .shrink |
| Spawn from common code | RetroParticles.spawn, .spawnCloud, .spawnOnBlock, .spawnVanilla |
| Multiplayer bridge | The protocol has no particle packet and vanilla's server listener is empty; RetroAPI forwards to players in range |
| Feature | What 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-stack | A 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 & networking | Written into a namespaced NBT sub-tag; survives saves, inventories, dropped items and packets |
| Presentation | Component-driven tooltips and dynamic item textures |
| Feature | Call |
| Dimensions | RetroDimensions.register(id, factory), stable serial ids, DIM<n> folders, forwarded into StationAPI when present |
| Portals | CustomPortal + teleporters, walk-in both directions, per-dimension travel messages |
| Biomes | BiomeBuilder (colors, weather, spawn weights), StationAPI-shaped |
| Editing existing biomes | RetroBiomes.addPassiveSpawn/addMonsterSpawn/…, additive so mods do not clobber each other |
| World features | RetroFeatures.ore/cluster/custom with .size, .count, .heightRange, .rarity, .meta, .replace(blocks…), .dimensions(…) - no mixin into the generator |
| Custom chunk generators | RetroWorldGen.createChunk/setBlockInChunk, correct in both storage models |
| Feature | What it gives you |
| Expanded texture atlas | Sprites beyond vanilla's 256, animated textures from .mcmeta or from code |
| JSON models & blockstates | Multi-element models, variant tables, cullfaces, custom UVs, tint indices |
| Render layers | Cutout and translucent passes for modded blocks |
| Custom block renderers | BlockRenderContext: lit faces with smooth lighting, spriteOverride, flipTexture, faceRotation, renderAllFaces, renderFaceUv, renderFaceCorner - enough for connected textures |
| Voxel shapes | Multi-box outlines, collision and raytracing for non-cube blocks |
| Feature | What it gives you |
RetroVec3i | Immutable block position: arithmetic, offsets, rotation, distances, and world access (blockId, state, setBlock, blockEntity) |
RetroDirection / RetroFacing | Six and four directions with opposite, rotateLeft/Right, vector, face, fromPlacer, nearest |
RetroMultiblock | Patterns 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 |
| Guarantee | How |
| Vanilla region data is never rewritten | Modded ids ≥ 256, extra state bits and modded item data live in a sidecar beside the region files |
| Removing the mod does not corrupt the world | The vanilla half was never touched; the modded half is simply absent |
| Ids may move between sessions | Per-world id_map.dat re-anchors everything by name |
| Backups | The retroapi/ folder is copied aside before structural changes |
| Verified, not asserted | Headless test: place modded content, save, reload, assert; then convert vanilla → flattened → vanilla and assert again |
| With StationAPI installed | Owner |
| Registration, ids, storage, atlas, recipes | StationAPI (RetroAPI forwards and stands down) |
| Entities, dimensions, components, particles, world features, multiblocks, sound/particle bridges | RetroAPI, unchanged |
| Your code | Unchanged, if you register from the retroapi entrypoint |