The Forge
A crafting station where recipes aren't handed to you. You find them by trying things.
On this page 6 sections
The Forge is where you spend the piles of stuff you’ve never opened. Old crate keys, fragments nobody trades, that armour piece you’ve had since week two. The Forge is what turns those into something you actually want. And the recipes aren’t printed anywhere. You discover them by trying combinations. Every recipe you land on gets stamped into your Forge journal so you can craft it again, and there’s a whole hidden Experimental category that only shows up once you stumble into one of its recipes.
The Forge exists because “collect keys you’ll never use” is one of the oldest problems on the server. If you’ve been playing a few weeks you probably have 300 low-tier crate keys sitting in a pouch. The Forge lets you smelt them into a Reforge that changes an armour piece you actually wear.
Discovering a recipe
/forgeopens it.- Pick a category, or browse everything you’ve unlocked so far.
- Fill the anvil with the inputs a recipe wants. Currencies, crate keys, fragments, whatever.
- Add a target if the recipe modifies something you own. Reforges and Infusions grab an item off you and change it in place; standalone recipes leave the target slot empty.
- Craft. The Forge rolls success or failure, consumes the inputs, and either awards the payout or fires the failure pool (usually much smaller). The recipe gets marked discovered on the first successful craft, and every discovery counts toward a milestone tally that pays out on top.
Recipes match exactly. A near-miss does nothing. Nothing half-fires, nothing gets eaten while you’re still experimenting.
Recipe categories
| Category | What it does |
|---|---|
| Fusion | A stack of low-tier things becomes a smaller number of higher-tier things. |
| Reforge | Rerolls an item you already own, keeping the item but changing its stats. |
| Infusion | Attaches a buff or a slot to an item you own, using consumables as fuel. |
| Experimental | Hidden until discovered. Weird crossovers that don’t fit anywhere else. |
Each category has its own kill switch. If one of them ships broken we can turn it off without taking the whole Forge down.
The parts that bite
- Recipes are private until you discover them. Your journal is yours; nobody else’s leaks into it.
- Failure eats the inputs. The failure pool exists so a lost roll isn’t nothing, but it’s meant to sting.
- Reforge and Infusion don’t drop new items. Their payout is that they change the item on the anvil; the failure pool is what fires when the roll doesn’t go your way.
- Discovery milestones pay separately. Hitting 5, 15, 30, 50, etc. discovered recipes drops a milestone reward on top of whatever the craft itself gave you.
- A double-clicked craft button only consumes once. A per-player lock swallows the second click.
Why it exists
- Somewhere for hoarded stuff to go. The players who never open their keys finally have a use for them.
- A reason to keep old gear. Reforges give worn-out items a second life instead of dumping them at a vendor.
- A slow-burn collection game on top of the loot game. The journal fills over months, not days.
- Live-ops without shipping code. A seasonal recipe is a config entry, not a deploy.
Architecture
Pluggable ingredient and reward sources
The Forge doesn’t know what a “crate key” or a “coin” is. Each currency, crate type, fragment pool and item
family registers itself with ForgeSourceRegistry as a ForgeSource, and target-editable items register with
ForgeTargetRegistry as a ForgeTargetSource. A recipe references sources by string key
(atlantic.crateKey, atlantic.fragment, and so on), and at craft time the Forge looks them up and calls
consume / award / applyEffect without caring what’s on the other side. Adding Forge content is a config
entry plus, at worst, a new source registration. The crafting engine doesn’t change.
Atomic multi-source crafting with real refunds
A single recipe can pull from several sources at once (say, 3 fragments plus 500 coins plus one crate key).
Each individual source’s consume is atomic, but the whole recipe spanning them is not, so ForgeCraft
walks the inputs one at a time and remembers what it took. If a later input comes up short (usually because
the player’s balance changed on another server between menu-open and click), everything already consumed gets
refunded and the craft reports INSUFFICIENT without having run. The player’s balances end up exactly where
they started rather than half-taken, and the Forge is free to fail loudly instead of guessing.
Refunds also fire when a Reforge or Infusion target slips away between the pre-check and the effect actually applying. Maybe the item was withdrawn, maybe another action deleted it between clicks. The roll may have succeeded, but there’s nothing left to improve, and the inputs go back rather than being burned for nothing.
The lock is released from exactly one place
A double-clicked craft button used to be able to consume inputs twice. The fix is a per-player set of active
crafts and a whenComplete on the result future. Every exit path, normal or exceptional, runs the release.
On top of that the future has a 30-second orTimeout because the storage layer we sit on has paths that
don’t complete their future at all (SimpleAsyncDatabase swallows a SQLException and never calls the
successor). The timeout means a bad query costs the player one craft, not the ability to ever craft again.
Config validation at parse time, not at craft time
A malformed recipe (missing amount, unknown category, effect without a target) is skipped at config parse
with a warning, not at the craft. One bad seasonal edit shouldn’t take every other recipe offline with it.
On top of that a startup pass walks every recipe and milestone and checks that every source and every id
inside it actually resolves. A typo’d reward id is the quieter of the two failure modes and by far the more
expensive. Without the pre-check, giveCrate would happily mint keys for a crate type that doesn’t exist
and the player would carry unopenable keys with nothing logged.
Discovery is one line, not a lookup
ForgeJournal.discover(player, recipeId) returns true iff this was the first time. Which is exactly what
the craft path needs to decide whether to trigger the milestone check. The journal is per-player, keyed by
recipe id, and the milestone list is loaded once and sorted ascending by required discoveries so the menu
reads as a ladder rather than in config order.
Trade-offs
- Exact match, not fuzzy. A recipe with 3 fragments won’t fire on 4. Fuzzy matching sounds nicer but makes near-miss experimentation actively harmful (you’d get half the recipe for free), and it turns the discovery loop into “throw everything on the anvil” instead of a puzzle.
- Failure consumes the inputs. Partial refunds on failure flatten the curve and make high-success recipes irrelevant. The Godly-tier gambles are only meaningful because the loss is total.
- Journals are per-player, not per-island. A co-op island still gets three separate discovery paths. It’s simpler to reason about, and there’s no reasonable rule for “who discovered it first” that isn’t political.
- Effect config is a plain map, not a typed struct. Recipes carry an
effectIdstring and aneffectConfigmap that the target source reads. The target validates its own effects at parse time (supportsEffect), so a typo in the config surfaces at startup rather than at the craft, and adding a new effect doesn’t ripple through the Forge core at all.