Upgrade a game
Follow these steps to move a framework v1 or v2 game to this framework. upgrade_framework answers this section when it moves a game here.
This is a rewrite of the game logic and the client, not an edit. Port one rule at a time and keep the old files open to read from until the last step.
Use what Boardweaver provides
Boardweaver now provides features that a framework v1 or v2 game had to build for itself. When the old game has its own version of one of these features, use Boardweaver's version. Never port the game's own version. Delete its code and its state, and wire the game to the feature in the table below.
| The old game built its own | Use this instead |
|---|---|
Undo: an undo stack, saved snapshots, Immer patches or an undo intent |
table.allow_undo() in the game logic, and the Undo button from useUndo() in the client (Changing the state) |
| A move made in parts: selection state, tentative moves or arrange-then-commit in the client | A decision of several steps: choice offers, then a confirm offer. The client shows the steps so far with useDraft() (Offers, intents and decisions) |
Match history: a move log, a last-move banner, a replay, or a list of moves kept in metaData |
table.log(line) on each step (Changing the state). Boardweaver shows each step to the other players with its log lines, gives Back, Forward and Skip to now, and replays a finished match. The client reads the lines with useLastChange() and the board's place with usePlayback() (The React client) |
| Move animations from a diff of the old and new state | The movements that Table's piece methods record. Animate useLastChange() movements, and set the time per step with useStepDuration() |
| Hidden hand order: shuffling ids, decoy pieces or sorting tricks | .collection() on the space, .hiding() on the piece and .revealing() on the offer (Hidden information) |
| Random numbers: a seed or a generator kept in the state | The rng argument of setup and apply_action (Randomness and determinism) |
Bots: extra seats added in preGameInitialization, or bot moves picked in the client or on a timer |
A Bot in the game logic. The lobby seats it (Bots) |
| Player names and avatars kept in the state | usePlayers() |
| A queue of moves on their way, or an offline banner | usePending(), and useFailures() for refused moves |
| An end screen built into the board | Boardweaver's own end screen, or a GameOver export with useMatchEnd() (The React client) |
| Rules, sound, full screen or leave buttons drawn by the client | Nothing: Boardweaver draws them in the bar under the board |
What is new
| Framework v1 or v2 | This framework |
|---|---|
Game logic in TypeScript, in /src/game.ts |
Game logic in Rust, in /src/lib.rs and the modules it declares |
gameConfig and preGameInitialization |
setup |
getAvailableActions or getSelectableItems, and getButtons |
offers: one Offer per legal step, each an action, an intent and a label |
applyActions changes the state in place |
apply_action changes the state only through Table, and refuses a move with Err |
getPlayerScores, scoreLabels, isGameOver |
scores, score_labels, is_game_over |
PieceDef and SpaceDef classes, each with a kind |
Piece::new(public_kind) and Space::new(space_id, kind) values |
A piece has a pieceId |
A piece has no id: it is named by its space and its index there |
static constants of a kind |
A const or a data file in /src/data/ |
publicState, privateState |
public_state, private_state, the piece's owner, and private_kind for a hidden face |
metaData, activePlayerIds |
meta_data, active_player_ids |
v1: Boardweaver draws from render(). v2: useGameState, useAvailableActions and match.click |
useBoard, useOffers and useAct in /src/frontend.tsx |
These carry over unchanged: uploaded art (the client reads it with useImage(key)), /theme.json, the rules pages and the marketing page.
1. Read the new contract
Read How a game works. Call get_example with tic-tac-toe-rust and tic-tac-toe-rust-client.
Done when you can point to each of the six game functions in the example, and to the place where its client takes an offer.
2. Map the state
Write down how each def, bucket and map of the old game becomes a space, a piece or a map of the new state. A piece the old code found by pieceId needs another way to be found: its space and index, or a field in public_state. Decide who owns each private part. Leave out every field that only served a feature in Use what Boardweaver provides, such as an undo stack, a move log or a random seed.
References: The state, Hidden information.
Done when every field the old game read or wrote has a place in the new state.
3. Port the game logic
Write /src/lib.rs with the six game functions and export_game!. Port the old rules one at a time. Write a #[test] for each rule as you port it. Draw randomness only from the rng argument.
References: The game functions, Changing the state, Offers, intents and decisions, Randomness and determinism, Testing a game.
Done when validate_code answers no Rust error, its tests counts a passed test for each rule, a start_game session plays to the end at each seat count, and the game logic has no own version of a feature in Use what Boardweaver provides.
4. Rewrite the client
Rewrite /src/frontend.tsx against boardweaver/react of this framework. Draw from useBoard(), make only the offers of useOffers() clickable, and take them with useAct().
References: The React client, boardweaver/react reference.
Done when validate_code answers no error that names /src/frontend.tsx, and the client has no own version of a feature in Use what Boardweaver provides.
5. Delete the old game logic
Delete /src/game.ts, /src/pieces/, /src/spaces/ and every other TypeScript file that only the old game logic imported.
Done when list_files shows no TypeScript game logic and validate_code answers valid: true.
6. Commit
Call commit. The commit builds against this framework and pins the game to it.
Done when commit succeeds.
Tips
- Port the rules, not the code. TypeScript that mutates a piece found by id does not translate line by line: rewrite each rule against
Table. - A move that took one v2 action and picked several values is several steps here, one value each. Mark the last step
confirm. - Mark every offer whose result depends on hidden information with
.revealing(). - A
PlayerIdis opaque. Never assume seats are 1, 2, 3. - To stay on the old framework, call
upgrade_frameworkwith the game's committed major before you commit. It removes the pending upgrade, and your file changes stay.