Verifying a feature - rebaserHEAD/NexusForever GitHub Wiki

guide, committed verified 2026-10-14 stable a4e75b18 run 2026-10-13

This guide checks a table-driven feature on a local server before it reaches stable: predict the outcome from the game tables, drive the feature from the server, compare what got saved against the prediction row by row, then look at it in game.

Before you start

What you'll have

A row-by-row comparison between what the server saved and what the game's own data says it should have saved, plus a look at the result from the player's side. A feature isn't done when it compiles, or when the logs look right. It's done when both of those hold.

How it works

Most of WildStar's behaviour is driven by its game tables, so the tables say what should happen. That gives every table-driven feature the same check.

flowchart TD
    T["Game tables"] -->|script| P["Prediction"]
    WC["Commands to the server"] --> DB[("Saved rows")]
    P --> CMP{"Compare"}
    DB --> CMP
    CMP -->|match| G["Check in game"]
    CMP -->|mismatch| FIX["Find which side is wrong"]

Run the check

Start clean

Delete the test character's rows for the feature, along with anything that would short-circuit the run. For the archive that meant its archive rows, its achievements and its titles: an achievement the character already has won't complete again. A local test database holds nothing worth keeping, so clear what you need.

[!TIP] Build in Debug. It's the only build that checks each game table model against its file at start-up.

Build the prediction from the tables

Write the prediction from the tables, never from the server code. If you derive it from the code you're testing, a mistake in the code shows up on both sides and the comparison passes anyway.

Export the tables you need to CSV and compute the prediction with a short script. For the archive, each article's predicted unlocked word is:

  • bit 31, the moment anything unlocks the article;
  • the slot bit of every entry whose rule names one of the granted achievements, in every article that holds that entry;
  • the slot bits of the entries flagged to unlock with the article.

Galactic Archive messages and storage has the bit layout and the flags.

Drive the feature from the server

Use the web console with the test character's name in the Character box, so each command runs as that character (Using the web console). For a long run, script it over the console's socket instead of typing.

[!NOTE] Most commands answer nothing when they work, so the run itself proves nothing. The proof comes next.

Read what was saved

Query the character database. The Aspire host starts phpMyAdmin beside MySQL, and the dashboard links to it. For the archive:

SELECT articleId, HEX(unlockedFlags), HEX(viewedFlags)
FROM character_archive_article
WHERE id = <character id>
ORDER BY articleId;

The character's id is in the character table.

Compare

Compare every row with its prediction. A mismatch means one of the two is wrong, and either answer is worth having: a bug in the feature, or a gap in how we read the tables.

Check it in game

Logs and rows don't show what the player sees. Open the client and check the feature from the player's side: the panel lists what it should, counts update, and state holds across a world change and a fresh login.

When the client has to act

Some things only start from the client. A quest counts as complete only when the player hands it in, and the hand-in comes from the client. To set one up:

  1. Pick a quest the character's faction can hand in. A quest for the other faction shows no hand-in at all.
  2. Check that the quest's receiver has a spawn in the world database, or there's nobody to hand it in to.
  3. From the console: teleport location <id> to the receiver's location, then quest add <id> and quest achieve <id>.
  4. Hand it in from the client.

Anything that needs two characters online, such as trading, needs two clients. Two run side by side on one machine.

Troubleshooting

Symptom Cause Fix
Nothing saved after a run The character never saved, or the commands had no character Check the console replies for "Invalid target", or run character save
Every row is off by the same bits The prediction misses a rule, such as entries that unlock with the article Check the prediction against the table flags
A quest shows no hand-in The quest is for the other faction, or its receiver has no spawn Pick another quest

Example: the Galactic Archive run

The run behind #588:

Step Result
Start-up, Debug build 251 articles and 847 unlock rules loaded
Prediction Built from ArchiveEntryUnlockRule, ArchiveArticle and ArchiveEntry
Drive 180 achievement grant commands, every achievement that unlocks something
Saved 134 articles, opening 214 of their 464 entry slots; 63 articles complete
Compare Every saved word matched its prediction: 0 mismatches
Quests Two hand-ins in game, each updating the expected articles to the predicted words
In game The panel's count of updated articles matched the saved rows, and read state held across world changes

The same run was repeated, from a cleared character, after the code was reworked for review, with the same result.