Skip to content

EN Tools

BlaMacfly edited this page Nov 2, 2026 · 44 revisions

Tools

Every tool is a subcommand of the archcore executable (see Installation). Run them from the repository root; they read config/auth.conf and config/world.conf, or those of the folder named by ARCHCORE_CONF_DIR (see Configuration).

Command Role
archcore config migrate <archcore.json> [folder] [--force] Converts a former JSON configuration into auth.conf and world.conf
archcore db-init [--account name pass [gm]] Creates the databases, replays the baseline and applies the missing migrations; with --account, creates or updates an account
archcore db-check Read-only consistency check: schema versions, references between databases, identifier ranges; exits with an error on a serious anomaly (see Database)
archcore decrypt [source] [destination] Decrypts Game/ini (RC4, MD5("1111")) into data/client-ini
archcore import [folder] [--server folder] Imports into archcore_world the episode 8 values (original server tables, --server or data/server-ini, required) with the names, visuals and purely client tables of data/client-ini (CP949 → UTF-8, see "Episode 8 values" below), the ground height from the Game folder's world/b*x.ma2 (map_height, a few minutes), monster spawns, drops and the server map; finally applies the content/*.sql content layer, records each source in import_run and prints the summary of rows kept and dropped per table
archcore export-client-tables <folder> [--game folder] Writes the value tables from the world database in the client format, for ArchRust (see "Export for the client")
archcore migrate-ep8 [--apply | --restore n] Report, then migration of existing characters to the episode 8 values (see "Character migration")
archcore content Applies the content/*.sql content layer to the world database again, without reimporting (see Database)
archcore sim client|move|shop|addon|lang|combat|equip|potion|scroll|patrol|bag|skill|effects|bank|portal|guild|guildlead|guildmark|guildbattle|guildrelation|guildwarehouse|guildstage|gm|trade|quest|mobskill|counter|partyskill|mastery … Simulated clients (see below)
archcore i18n strings [Game] Lists the texts still in English in data/i18n/pending-en.json
archcore i18n coverage [Game] Measures how much of ini_fr is translated
archcore i18n apply [--ascii] [--dry] Applies the translation memory to the client (see [[Translation
archcore i18n db [language] Fills localized_text (world database) for a language: translated NPC titles and the data/i18n/<language>.json memory (see [[Translation
archcore re extract-schemas <files…> Extracts packet schemas from Ghidra pseudocode into data/re/packet-schemas.json

Client simulator

archcore sim client <user> <password> [character] [commands…]

It prints every packet exchanged, the number of NPCs received, and ends with "flux complet OK". Arguments after the character are sent as chat once in game (/GetExp by default), which tests GM commands. It is the quickest way to check a server change without starting the game.

In Git Bash, prefix with MSYS_NO_PATHCONV=1, otherwise /GetExp is turned into a Windows path.

Two-player test

archcore sim move [userA] [passA] [charA] [userB] [passB] [charB]

Two simulated clients enter the world (accounts sima and simb by default, characters created as needed). The test checks that they see each other, that one's movement is relayed to the other, that they lose sight of each other out of range, and that disconnecting removes the character. It moves the characters and saves their position: run it against a test server, for example:

ARCHCORE_CONF_DIR=config/test archcore all      # other ports, other databases
ARCHCORE_CONF_DIR=config/test archcore sim move

The test server has its own three databases, the world included: otherwise archcore db-init run for it would also apply the world migrations to the main server. To create its world database, copy the main server's (CREATE DATABASE archcore_test_world, then mariadb-dump archcore_world | mariadb archcore_test_world), set it in Database.World, also give it its own log database (Database.Logs, for example archcore_test_logs, created by db-init), and run ARCHCORE_CONF_DIR=config/test archcore db-init.

Shop test

ARCHCORE_CONF_DIR=config/test archcore sim shop [user] [pass] [character]

The character (sima / SimA by default) gets 1000 gold and appears next to Darryl (Anchorville). The test opens his shop, checks the list, buys 3 small life potions and sells them back. It changes the character's gold, position and inventory: run it against a test server too.

Combat test

ARCHCORE_CONF_DIR=config/test archcore sim combat [user] [pass] [character] [monster]

The character, a GM account (gmtest / GmTest by default), goes hunting the requested monster (Green Worm by default) north of Anchorville (Limelight North). The test has two parts:

  1. Defeat: it attacks; the monster fights back; it moves 1500 units away and the monster chases it; it dies, asks to be resurrected and comes back to the village with full HP.
  2. Victory: with /invincible 1, it attacks another monster, which no longer wounds it; the monster dies, experience is gained, its loot falls on the ground (at least gold) and the character picks it all up; the corpse disappears and the monster respawns.

It then sets /invincible 0 and brings the character back to the village. Allow about 2 min: a level 1 warrior without a weapon hits a Green Worm (136 HP) for 2 to 3 HP per hit, and the worm kills it (120 HP) in about twenty seconds.

Equipment test

ARCHCORE_CONF_DIR=config/test archcore sim equip [user] [pass] [character]

A GM account (gmtest / GmTest by default) creates a short sword, a human warrior armour (level 2) and a mage wand with /create, wears the sword (damage 11 to 13) then the armour (defense 4), sees the wand refused (class), then puts both away. SimA, standing nearby, must see the sword appear on them and then disappear. The created items stay in the inventory.

Potion and regeneration test

ARCHCORE_CONF_DIR=config/test archcore sim potion [user] [pass] [character]

A GM account (gmtest / GmTest by default) creates 3 Small Life Potions, gets wounded by a Green Worm, becomes invincible and goes back to the village; the test waits for out-of-combat regeneration (HP rising about ten seconds after the last hit), drinks a potion (HP up, stack down, op 4), then checks that a second potion right away is refused.

Scroll and patrol tests

ARCHCORE_CONF_DIR=config/test archcore sim scroll [user] [pass] [character]
ARCHCORE_CONF_DIR=config/test archcore sim patrol [user] [pass] [character]

sim scroll (GM account gmtest by default) creates three scrolls and checks the Tullan passport (fixed destination), the round trip (village, then back to Tullan with op 6) and the plain passport (village). sim patrol (sima by default) stands still among the Green Worms and waits for monsters to wander (walking), then goes back to the village.

Inventory and resurrection test

ARCHCORE_CONF_DIR=config/test archcore sim bag [user] [pass] [character]

A GM account (gmtest by default) creates a new stack of Small Mana Potions, splits it (op 17), merges it back (op 2 onto the original stack's slot) then destroys it (op 21); finally /kill and resurrection: it must come back at Anchorville's resurrection point (-476000, -61000).

Bank and trading test

ARCHCORE_CONF_DIR=config/test archcore sim bank [user] [pass] [character]
ARCHCORE_CONF_DIR=config/test archcore sim portal [user] [pass] [character]
ARCHCORE_CONF_DIR=config/test archcore sim trade [userA passA charA userB passB charB]
ARCHCORE_CONF_DIR=config/test archcore sim party [userA passA charA userB passB charB]
ARCHCORE_CONF_DIR=config/test archcore sim guild [userA passA charA userB passB charB]
ARCHCORE_CONF_DIR=config/test archcore sim gm [user] [pass] [character]
ARCHCORE_CONF_DIR=config/test archcore sim refusal [userA passA charA userB passB charB]

sim bank (GM account gmtest) checks that depositing without a keeper is refused, opens the bank at Holly (south of Anchorville), buys the second page (1,000,000 coins) and is refused the next one, deposits a potion stack and 1000 coins, reconnects and finds them, then withdraws them and destroys the stack. sim portal (GM account gmtest) stands 2500 units from the Anchorville portal and addresses it: the server makes it run then grants; paid trip (100 coins) to the Scout's Grounds, unlinked trip refused, paid return (500 coins) to Anchorville. sim trade puts GmTest (GM) and SimA at the same spot: GmTest offers a potion stack (refused on the Ex grid, kept for the Marvel Scroll of Release, then put on the targeted slot 0,1,2) and 500 coins, SimA 100 coins; requester read from field 2 of op 3; the offered item cannot be destroyed; locks (ops 16 / 18 with the CID), GmTest alone unlocks (SimA's lock stays, its "ready" waits), exchange (SimA receives the stack, money is adjusted on both sides); bound letters (735, 736): refused without a scroll, Marvel Scroll of Release (11256) put on the Ex grid (op 1 then op 0 status 14) and given back on cancel (status 51), only one bound letter per trade, traded with the scroll, used up; then a second request refused with op 5. sim party (SimA and SimB) checks that inviting an unknown name is refused, the invitation and acceptance (party and member list on both sides), party chat, the leader setting experience sharing (refused to the other), the leader handover, then the kick, which disbands the party. sim guild (GmTest master, SimA) refuses a name with a space, creates SimGuild (10,000 coins), meets SimA's refusal as SimA blocks guild invitations (system message 42), invites SimA who accepts, checks guild chat and the notice, a leave request accepted by the master, coming back then being kicked, the guild found again on reconnecting, and finally disbanding (wrong password refused). sim refusal (GmTest, SimA) ticks GmTest's trade and party refusals (op 0x11): SimA gets op 14 for its invitation and op 25 for its trade request, GmTest gets nothing. sim gm (GM account gmtest) checks /speed (run speed ×5 in the factors received, refused above 10, back to ×1) and /additem (potions added, unknown TID refused), then destroys the stack.

Guild tests

ARCHCORE_CONF_DIR=config/test archcore sim guildlead [userA passA charA userB passB charB]
ARCHCORE_CONF_DIR=config/test archcore sim guildmark [userA passA charA userB passB charB]
ARCHCORE_CONF_DIR=config/test archcore sim guildbattle [userA passA charA userB passB charB]
ARCHCORE_CONF_DIR=config/test archcore sim guildrelation [userA passA charA userB passB charB]
ARCHCORE_CONF_DIR=config/test archcore sim guildwarehouse [userA passA charA userB passB charB]
ARCHCORE_CONF_DIR=config/test archcore sim guildstage setup|present|chef|dissoudre|guerre-prep|guerre-defi|guerre-refus|relation-prep|relation-repond|relation-demande|entrepot-prep [seconds]

These scenarios (tools/sim/guilds.rs) create helper accounts simg01… (password equal to the name) in the test database when needed, to reach the head counts Archonia requires. sim guildlead (GmTest master, SimA, 18 helper accounts: 20 members) checks the guild list (page, search, guild not found: code 47), enlarging (not enough gold: code 44, then 60 places for 1,000,000 coins), SimA's appointment refused at level 1 then accepted (op 48, sub-op 2 → 3 → 4 → 8), removing that rank, the handover (5 → 6 → 7 → 8: GmTest rank 1, SimA master), the ranks read again on reconnecting and the disbanding by the new master. sim guildmark (GmTest, SimA, 9 helper accounts) checks the guild mark: nothing under 10 members, missing background (code 58), not enough gold (code 57), purchase (60,000 coins) broadcast to the guild and in the links, a second guild asking for the same mark (code 59) then buying it anyway (op 33), the mark read again on reconnecting. sim guildbattle (GmTest and SimA, each master of a 10-member guild; the test server needs a short Guild.BattleReadySeconds, 10 for instance) checks guild battles: unknown guild (code 27), levels too low (code 22, 100 as the second number), challenge refused (op 15, code 28, then op 17, code 30), challenge accepted (op 16), cancelling too late (code 31), no hit before the start, start (op 21), clock (op 22), an enemy killed (op 23: 1 point), surrender (op 24 → op 25: results 4 and 5, record op 12), cancelling during the battle (op 18 → 19), victory by the enemy master's death (results 1 and 3), record read again on reconnecting and battles refused by option (code 43). sim guildrelation (GmTest and SimA, 38 helper accounts) checks alliances and hostilities: unknown guild (0x3c), not enough members (0x42), request refused (op 34 → 35, 0x44) then accepted (op 36 on both sides, roles 2 and 1, details op 44), already allied (0x3e), hostility towards an ally (0x4b), leaving (op 37: 0x47, and 0x49 for the other one as the alliance is dissolved), hostility refused (op 38 → 39, 0x52) then accepted (op 40, details op 45), already hostile (0x4c), truce refused (op 41 → 39, 0x57) then accepted (op 43, 0x59), hostility read again on reconnecting and removed by disbanding. sim guildwarehouse (GmTest master, SimA, 8 helper accounts) checks the guild warehouse at Holly: keeper grant (function 35, op 3), refusal under 10 members (0x5f), opening (op 0, op 1 result 2), depositing a stack (op 5 → status 53, cell in field 7) and 1000 coins (op 3), a member's rights (no withdrawal), a member's money deposit seen by both, disbanding refused (0x60), read again on reconnecting, taking the stack back (op 6, gone for the other one) and the money (op 4), expansion refused (result 4). sim guildstage prepares ArchRust screenshots: setup creates SimLead (GmTest master, SimA level 20, 18 helper accounts) and leaves the guild in place; present keeps SimA in the game, accepting appointments and handovers; chef brings GmTest in, who offers SimA the sub-master rank then the guild; dissoudre disbands SimLead (and SimWarB); guerre-prep creates SimLead (GmTest) and SimWarB (SimA), 10 members each; guerre-defi has GmTest challenge SimWarB after seconds, wait for the start then surrender; guerre-refus has GmTest refuse the challenges received for seconds; relation-prep like guerre-prep with 20 members per guild; relation-repond has GmTest accept alliances, hostilities and truces for seconds; relation-demande has GmTest declare SimWarB hostile after seconds; entrepot-prep (after guerre-prep) takes SimA to Holly, who deposits a stack and 1000 coins in SimWarB's warehouse and keeps another stack.

Player-versus-player zones, reconnection and /last_refine tests

ARCHCORE_CONF_DIR=config/test archcore sim pvp [user] [pass] [character]
ARCHCORE_CONF_DIR=config/test archcore sim reconnect [userA passA charA userB passB charB]
ARCHCORE_CONF_DIR=config/test archcore sim lastrefine [user] [pass] [character]

sim pvp (GM account gmtest) hits a Green Worm north of Anchorville then stands at the Tullan city portal: its request is ignored in combat, granted ten seconds after the last hit; it travels to the guild arena (a player-versus-player zone), from where "Return" (op 7) brings it back to the Tullan portal; op 7 is refused from an ordinary portal. sim reconnect (GmTest, SimA): key received on entry, GmTest's connection dropped without leaving the world (SimA still sees it), resumption refused with a wrong key, accepted with the right one (new key, view sent again, command on the new connection), then a second drop: GmTest leaves the world after 60 s and the resumption is refused (about 70 s). sim lastrefine (GmTest) checks that /last_refine is refused before any refine, refines recipe 4013, runs it again with /last_refine, then gets result 1 (missing ingredients).

Production test

ARCHCORE_CONF_DIR=config/test archcore sim product [user] [pass] [character]

GM account (gmtest, GmTest): production skills and recipes wiped in the database, empty op 1 on entry, level 20, gold, gathering knife and cooking tools (/additem). At Kauman (Anchorville's Adventurer): Cooking refused (code 1), Collection Skill learnt (300 gold), then already learnt (code 2). North of the village, Green Worms killed then gathered (cast accepted, op 2 → op 3: an item of set 46, experience in "dirt" factor 6) until one succeeds; the first corpse is not gathered twice (code 7, cast refused with action 17). At Lucy (Cook): recipe refused without Cooking (code 5), Cooking learnt, Broiled Meat of Vitality bought then already known, alchemy potion refused; crafting without materials (code 6), then with materials and seasoning (used up) until one succeeds. Reconnection: op 1 returns the recipe. Everything is wiped at the end.

Friends and mail test

ARCHCORE_CONF_DIR=config/test archcore sim buddy [userA passA charA userB passB charB]
ARCHCORE_CONF_DIR=config/test archcore sim mail [userA passA charA userB passB charB]

sim buddy (GmTest GM, SimA; lists wiped in the database at the start and at the end): empty lists on entry (op 9), local ignore file sent by GmTest (op 15: SimB), server refusals (oneself code 4, unknown name code 2, "Buddy" relation code 12, SimA's "refuse friend requests" option: op 3 at once), request accepted (op 1 on both sides, online), duplicate (code 1), the friend's region (op 7); SimA reconnects (op 6 offline then online, list read back from the database), removes GmTest (on its side only) and ignores it with "Block Chat" and "Block Trade": whisper not delivered, trade refused (op 25); party invitation received, then refused (op 14) with "Block Invites"; boxes unticked, the whisper gets through; GmTest comes back and finds its friend and the ignored SimB. sim mail (GmTest GM, SimA; mails wiped): GmTest gets 3 letter paper sheets and 5 potions, is refused an unknown recipient (code 2), itself (code 1) and the attached paper (code 5), writes to SimA while offline with the potions (removed, one sheet taken); SimA enters and gets the mail (op 0), reads it (recorded in the database), cannot delete it before collecting the item (code 11), collects the potions (same item) then deletes it; a second letter arrives at once, SimA in game.

Repair and mounts test

ARCHCORE_CONF_DIR=config/test archcore sim repair [user] [pass] [character]
ARCHCORE_CONF_DIR=config/test archcore sim ride [userA passA charA userB passB charB]

sim repair (GmTest GM; run with Item.WeaponWearChance = 100 in the test server configuration): GmTest wears a Short Sword (DUR 88) and a Halfsteel Armor (DUR 63), hits a Green Worm and sees the sword lose one point per hit (AGPMITEM op 2, field 10: 87, 86, 85); /durability 0: the broken sword no longer counts in the damage; /durability 40, items stored, reconnection: 40 read back on entering the game; at Halo's, opening (op 3 → op 4), wrong cost (code 4), repair (gold debited at the client's price, items full, code 1), items already full (code 3), potion (code 5). sim ride (SimDepart on the GM account, SimA watching): level 40, White Horse (TID 3002); mounting (item worn, run speed 10,500, AgpmRide op 2 for both), reconnecting on horseback (field 18 = 2, op 2 on entry), dismounting (op 4, original speed), mounting refused right after hitting a Green Worm (code 24, horse left in the inventory) then accepted 11 s later, death on horseback (/kill): forced dismount.

Metamorphosis and Scion evolution test

ARCHCORE_CONF_DIR=config/test archcore sim morph [accountA passA charA accountB passB charB]
ARCHCORE_SIM_CREATE_TID=1724 ARCHCORE_CONF_DIR=config/test archcore sim client test test SimScion   # once
ARCHCORE_CONF_DIR=config/test archcore sim evolution [accountA passA charA accountB passB charB]

sim morph (GmTest GM, SimA watching; run with Item.TransformMaxDurationMs = 8000): three Spider Potions (form 272, damage +26 / +28) and a Passport; potion drunk (op 4, op 19 at 600,000 ms, higher damage, op 11 for both), second potion refused (op 27 code 4), Passport refused; SimA comes back and gets GmTest through op 0 (original TID, bit 0) then op 11; end of duration after 8 s (op 12 for both, original damage); GmTest comes back, drinks a potion and cancels it (op 13 → op 12). Under the spider form, a Short Sword is worn then put away (AGPMITEM op 2, statuses 3 and 2) and the trade asked of SimA is refused (op 5, nothing for SimA). Last, with Mutation level 1 set in the database, GmTest casts it on a Green Worm: op 11 (form from the level's list), no hit on the animal, op 12 after 7 s, second Mutation without effect during the immunity. sim evolution (GmTest GM, SimScion a Scion of the test account, placed at Gilliwen's, with no form nor evolution skill at start): level 20 and gold from the GM, Slayer and Orbiter of Evolution learnt, Power Stunner refused (code 5); Slayer of Evolution (Slayer factors, STR 83, op 4, op 26 → 1722 for both), Orbiter of Evolution (op 27 → 1724 then op 26 → 1723), active form cast again refused, reconnection (TID 1723, field 18 = 4, op 4 on entry, GM's view), cancellation by AGPMSKILL op 7 action 4 (op 5, op 27 → 1724, form cleared in the database).

Auction house, equipment switch and weather test

ARCHCORE_CONF_DIR=config/test archcore sim auction [accountA passA charA accountB passB charB]
ARCHCORE_CONF_DIR=config/test archcore sim itemset [account] [password] [character]
ARCHCORE_CONF_DIR=config/test archcore sim nature [accountA passA charA accountB passB charB]

sim auction (GmTest GM seller, SimA buyer; sales wiped, gold and CC set in the database): at Fotherbee ("Item Trader"), opening (op 9 → op 10); refusal of a sword without a category, of a price under 100,000 and of a partial stack; 5 potions listed for 150,000 gold and 20 CC (op 4, op 1, potions removed, 4,500 gold fee); SimA finds them by TID (op 12, rowset line), is refused a wrong count (code 5), buys (same IID on her side, gold and CC debited, op 7); GmTest gets op 3 (sold), a second purchase gives code 12; GmTest collects (op 6, gold and CC credited, op 2); a second sale comes back on entering the game (op 1) and is cancelled (potions returned, op 5, op 2). sim itemset (GmTest): field 26 = IID; sword and armour worn, saved in slot 3 (op 3, op 5, no op 4), stored then re-equipped by op 1 (op 4), move (op 6) and removal (op 7) of a set item, empty slot worn (everything taken off), read back on entering (ops 3, 5 then 4), slot cleared (op 2). sim nature: GmTest then SimA 3 s later get the same clock (real gap × speed), clear weather on entering; /weather rain received by both and when SimA reconnects, /weather describes the weather, /weather clear received by both.

Summons test

ARCHCORE_CONF_DIR=config/test archcore sim summons [account] [password] [character]

GmEffets (GM account) gets Griolli (TID 315) and Bomba (619) in the database, goes to level 80, invincible, among the Green Worms. Griolli: creature view (TID 543), state 0x800 then AgpmSummons op 0, in this order (type 1, non-zero timestamps). Attacking a distant worm: the spirit (range 1500) kills it before the master arrives, the experience goes to the master. "Defense" propensity (op 2) sent back; refused for an ordinary monster. /move: op 1 then removal from view. Bomba (Big Tim, 10 s): op 1 on expiry. Griolli then Bomba: the one-summon limit sends Griolli back (op 1) before Big Tim (op 0). Doogie <Rank 1> (item 7564): pet (type 8, forced), sent back by using the item again. Level restored, skills and item removed from the database at the end.

Consumables, resurrection orb and skill reset test

ARCHCORE_CONF_DIR=config/test archcore sim consumables [account] [password] [character]

GmTest (GM account) starts with Dual Slash at level 2 only and an empty "skill init" string. Scorching Stew (TID 111): effect 459 (AGPMSKILL op 4, 300 s), the item's op 4 with the skill's cooldown (420,000 ms), second stew refused (op 5). Janus Talisman of Growth LV1 (50101): effect 1801 for 30 min, talisman consumed. Reverse Orb (1054): refused while alive (op 5); after /kill, resurrection on the spot (op 1 status 0, op 4 then op 18 of 1,800,000 ms); dead again, a second orb is refused during the cooldown (op 18 then op 27 code 3), back to town (op 9). Master (0x3B op 8 without an event): Dual Slash removed (AGPMSKILL op 1), 560 coins refunded, op 23 "1", op 9 result 0; a second request, then another after reconnecting (string read back from the database): result 1. Gem of origin (4876): Dual Slash, put back in the database, removed (op 1), op 4. GmTest's skills, money and string restored at the end.

Items without a skill test (Return Orb, Secret Safe, commands, fireworks, switched-on items)

ARCHCORE_CONF_DIR=config/test archcore sim usables [userA passA charA userB passB charB]

GmTest (GM) starts with Dual Slash at level 2, no extra bank page and a Bastard Sword +1 with two filled sockets; SimA stands next to it. Return Orb (1171): AGPMSKILL op 13 on the normal attack refused, on Dual Slash → op 1, orb used up (op 4), then refused without an orb. Secret Safe (3916) refused without page 2; /safekeeper (4923) opens the bank from afar (AGPMEVENTBANK op 1), page 2 is bought there (op 22); two Secret Safes open pages 3 and 4 (field 23 = 2, 3, message 30), the third is refused (message 29). /merchant (4924): a shop list. Release of Agreement (4877): AGPMITEMCONVERT op 12 → op 0 (+1, 2 sockets, nothing set), item used up; a second try has no effect. Small firecracker (4606): op 4 for GmTest and SimA, a second one refused (op 5). Fortune Manual (4569) and Talisman of Protection (1842): op 26 on then off (op 3, op 23). /nick: 17 characters refused, "Héros" seen by both (field 27) and saved, "Il faut" without the item. /go: absent player refused, GmTest moved away joins SimA, cooldown. GmTest's skills, money, bank pages and signature restored at the end.

Party recall, social actions, quick belt and return to character selection test

ARCHCORE_CONF_DIR=config/test archcore sim recall|social [accountA passA charA accountB passB charB]
ARCHCORE_CONF_DIR=config/test archcore sim quickbelt|returnlogin [account] [password] [character]

sim recall, GmTest (GM account) and SimA: Bead of Summoning (2756) without a party refused (AGPMITEM op 5); party formed, GmTest moves away (/move) and recalls: op 4 to the caster, management op 15 (caster, name) to SimA, who accepts (0x07 op 5 then op 16) and lands next to GmTest, op 16 to the caster; second recall declined (op 17 to the caster); acceptance without a request ignored; Summoning Orb (1174): op 4 with 300,000 ms, second use refused (op 5). sim social: SimA dances (op 16 type 5 received by both), type 17 ignored, an action too soon ignored then allowed. sim quickbelt, GmTest: op 0 with 50 slots, op 1 without answer (skill moved within its row, potion, unknown item emptied, life potion), bar read back on reconnecting (skill by its new id), vanished potion replaced, slot emptied; GmTest's bar cleared at start and end. sim returnlogin, GmTest: 0x2F op 1 → op 5 and the world connection closed; on the login server op 6, hash key, login, op 7, character list; same key refused (AGPMLOGIN op 15); entering the world again.

Titles test

ARCHCORE_CONF_DIR=config/test archcore sim title [accountA passA charA accountB passB charB]

GmTest (GM account, human knight) and SimA. Entering without a title: a single op 5 (0x5C = 0). Warrante ("<Title Manager>", npc.ini 535): op 10 instead of the dialog. Novice Human Knight (140001) set as a goal at level 10: 6.1 result 0; at level 15: 6.1 then 6.3 = 15; at level 16, 6.3 = 16; 6.4 → 6.5 then op 1. Equipped: op 3 (1, 1), op 9 to GmTest and to SimA placed next to him, strength + 2 ("<Title> Novice Knight"); SimA moved away then brought back receives op 9 again. Removing it right after is refused (op 3 result 0, code 3). Deleting the active title: op 9 bUse 0 at SimA's, op 8; goal 10001 set then given up (op 8); /title without an active title. isole.sh empties character_titles, character_title_goals and characters.title_changed_at.

Chat, chat rooms, stylists and wanted posters test

ARCHCORE_CONF_DIR=config/test archcore sim chat|channel|customize|wanted [accountA passA charA accountB passB charB]

GmTest (GM account) and SimA. sim chat: SimA sends like Archonia "/p" and "/g" as type 0 (party and guild refusals, not "Unknown command"), "/s" (type 1 received by GmTest), an unknown command (no answer), "/race" without a trumpet (refused) then with two Race Trumpets given by the GM (AgpmAreaChatting type 19 "[Race Trumpet] [SimA] …" on both sides, one trumpet used up; a second shout within the second refused; the next one uses up the last). sim channel: public room (creation, name taken, joining, already a member, message relayed to both), private room (op 8, wrong password, joining), leaving, invitation without password, player search, unknown room, empty room gone. sim customize: at Gladiol's, opening (op 0 → op 1), hair style 4 refused for lack of gold then bought (gold taken, field 21 for GmTest and for SimA), same hair style refused, hair style 1 restored. sim wanted: GmTest kills SimA (op 6), bounty refused under the base bounty then accepted (op 7 and op 5 for GmTest), second one refused, board at Rembrandt's (op 4 then end of page), SimA at level 60 kills GmTest: bounty paid (op 8 kind 4), op 8 kind 5 and op 7 flag 0 for GmTest; levels restored. Posters (wanted_criminal, wanted_bounty) stay in the database: empty them between two runs.

Quests test

ARCHCORE_CONF_DIR=config/test archcore sim quest [user] [pass] [character]

The GM account (gmtest), raised to level 120 (/questreset first resets the test quests), takes Shattered Roots from the journal, is refused completing it without the 50 Corrupted Root Cores, receives them (/create), completes it (items taken, Tempering Gem received), is refused taking it again and taking Winged Menace (level 25 to 40), takes then abandons Gladiator's Demise; after reconnecting, Shattered Roots is among the completed quests and the abandoned quest is no longer in the journal.

Skills test

ARCHCORE_CONF_DIR=config/test archcore sim skill [user] [pass] [character]

A GM account (gmtest by default, human warrior) checks that it knows "Normal Attack", goes to level 10 (/level), walks to Black, Anchorville's warrior trainer, learns Dual Slash (or is told "already learned"), is refused Flame Core (a mage skill), upgrades Dual Slash, casts it on a Green Worm (cast, damage), checks the refusal during the recast delay, then goes back to its original level.

ARCHCORE_CONF_DIR=config/test archcore sim effects [user] [pass] [character]

The GM account, with a separate character (GmEffets, created if needed, so as not to strengthen the one used by the other tests), is raised to level 25 (at least 456 HP and 108 MP, from GrowUpFactor) and learns Speed Attack, Defense Hold, Linear Blow and Blade Sting from Black (if needed). It checks the passive (defense +20), the buff (effect announced on itself, attack speed +18 %), Linear Blow's area (target and neighbours hit) and Blade Sting's debuff (set on the Green Worm, removed after 6 s). /level refills MP between casts.

ARCHCORE_CONF_DIR=config/test archcore sim status [user] [pass] [character]

The same character (GmEffets, level 25) learns Shield Bash from Black if needed, then casts it on Green Worms, with /recast and /level between tries, until a stun lands (30 % chance, 25 tries at most): the worm switches to state 0x1 (AGPMCHARACTER op 1, field 17), then back to 0 after 3 s.

ARCHCORE_CONF_DIR=config/test archcore sim mastery [user] [pass] [character]
ARCHCORE_CONF_DIR=config/test archcore sim partyskill [userA passA charA userB passB charB]
ARCHCORE_CONF_DIR=config/test archcore sim counter [user] [pass] [character]
ARCHCORE_CONF_DIR=config/test archcore sim mobskill [user] [pass] [character]
ARCHCORE_CONF_DIR=config/test archcore sim convert [user] [pass] [character]
ARCHCORE_CONF_DIR=config/test archcore sim refinery [user] [pass] [character]

sim mastery (GmTest, level 60) forgets Capacitate and Marching Song in the database, is refused Capacitate at Black's ("Marching Song at level 4 required"), learns Marching Song, upgrades it three times, then learns Capacitate. sim partyskill (GmTest, given Marching Song in the database, and SimA) forms a party: Marching Song strengthens SimA next to GmTest (AGPMSKILL op 4 on SimA), not when SimA is 3000 units away. sim counter gives GmTest Counter Attack level 10 in the database (a berserker skill, removed at the end), sets it to level 1, provokes a Green Worm and waits for a hit sent back (attacker = player, result 12), /level 1 restoring HP when needed. sim mobskill (GmTest, level 40) joins Midas, hits it once and waits for it to cast Insanity (the monster's op 7, op 8 on the player with physical and water damage), then to cast it again 6 s later. sim convert (GmTest, GM account) opens the window of Halo the blacksmith in Anchorville, gets a Bastard Sword (with 1 to 3 options and its sockets rolled), a water stone and two reinforcement potions (/additem), adds a socket (repeated until it succeeds), sets the stone (op 7, result 0) then an attack prayer stone (rune, op 8, result 1), reinforces the sword to +1 then +2, logs in again and reads the state back (+2, sockets, stone and rune) from the items received on entry, then destroys the sword. sim refinery (GmTest, GM account) opens an alchemy sphere, is refused a lone potion (result 2), gets the quote then refines 100 Breath Elemental Stones into 10 Gale Elemental Stones (recipe 4013, 5000 gold), refines the recipe again by its id (op 6), is refused without ingredients (result 1), then refines a White Wing Dagger and its stones (recipe 183) into a dagger with one option.

ARCHCORE_CONF_DIR=config/test archcore sim heroic [user] [pass] [character]
ARCHCORE_CONF_DIR=config/test archcore sim divide [userA passA charA userB passB charB]
ARCHCORE_CONF_DIR=config/test archcore sim dispel [user] [pass] [character]
ARCHCORE_CONF_DIR=config/test archcore sim ignore [user] [pass] [character]
ARCHCORE_CONF_DIR=config/test archcore sim rune [user] [pass] [character]
ARCHCORE_CONF_DIR=config/test archcore sim trigger [user] [pass] [character]

Skills and items (tools/sim/competences.rs, GmTest, GM account; skills and items set in the database, then removed). sim heroic goes to levels 89, 100 and 120 and reads the heroic points ("dirt" factors, index 7: 0, 21, 71), earns 300 charisma points with /charisma 300 (status 4) and reads them back after logging in again. sim divide gives GmTest Martyr's Mark level 7, forms a party with SimA and casts the skill (effect on both); a Green Worm hits SimA and GmTest takes 40 % of the hit (AGPMCHARACTER op 1). sim dispel puts Blade Sting level 10 on a Green Worm, then Antimagic (level 100 for its 500 MP) removes it (AGPMSKILL op 5) long before its 33 s. sim ignore sets a water stone into a Short Sword in the database: against a worm with 50 % resistance, the water part of a hit is 3, then 4 under Stunner level 20 (48 % of resistances ignored). sim rune sets an ice prayer stone (TID 588) in the database and hits until Cold Prayer Stone fires (AGPMSKILL op 8, ice damage, then op 4: slow). sim trigger gives the sword option 5658 (28 % chance to stun for 3 s) and hits until a worm is stunned (field 17), the state lifting 3 s later.

ArchRust extensions test

ARCHCORE_CONF_DIR=config/test archcore sim addon [userA passA charA userB passB charB userC passC charC]

Three simulated clients enter the world at the same spot: A and B (sima / SimA, simb / SimB) negotiate the extensions on every connection as ArchRust will, C (gmtest / GmTest) behaves like the original client and must be a GM (archcore db-init --account gmtest gmtest 3). The test checks:

  • an AddOn whisper from A to B (sender filled in by the server, payload intact, no echo for A);
  • a SAY message, received by A and B;
  • every refusal: recipient without extensions, offline recipient, reserved AC. prefix, invalid prefix, 256-byte payload, unsupported party channel, player under /chatban;
  • that an AddOn message sent without negotiation is ignored;
  • the rate limit: out of a burst of 25 messages, 20 go through and 5 are refused;
  • that C never receives a 0xAC packet.

The protocol is described on the ArchRust extensions page.

Language test

ARCHCORE_CONF_DIR=config/test archcore sim lang [user] [pass] [character]

The same character (sima / SimA by default) enters the world several times with the language/1 capability:

  • in French (language announced in HELLO): HELLO_ACK grants language/1, applies fr and lists the offered languages; the NPC names received are recorded;
  • in English: NPC names differ (" Darryl" → " Darryl");
  • TEXT_REQUEST returns the same names as the view packets, then SET_LANGUAGE fr brings them back to French; an unknown language (xx-YY) falls back to World.Language, a malformed code and an unknown kind get INVALID_REQUEST;
  • in "automatic" mode (HELLO without a language): HELLO_ACK announces the default language, then a LANGUAGE_ACK on entry gives the account's language (en), and names are in English;
  • with the original client (no HELLO): no 0xAC packet, names in the account's language;
  • finally the account is set back to French.

archcore db-init must have been run (language and localized_text tables, account.language column); archcore i18n db fr is optional, the translated NPC titles serving as fallback.

Episode 8 values

archcore import takes game values from the original server tables ("EP8 tables") and, from the Archonia client, only names, visuals and purely client tables (tools/ep8.rs):

Rule Detail
Presence A value row (skill, skill level, item, option, rune, template, recipe, region, shop, teleport point) exists only if it exists in the EP8 table; a row of the EP8 table the client does not know (38 shops, 21 "Trainer" / "Event" NPCs, 5 teleport points, the NPC Arena Coin column) is not imported
Values Columns of the EP8 table; Archonia's columns (options' CategoryName, runes' AlwaysSuccess, refining's Keep …, Critical_Defense_Rate, monsters' Regen_HP…) are not read: the rule falls back to the original neutral value (refined item is new, rune by Success_Rate)
Names The client's, joined by TID (ItemName, Name, options' Description)
Skills skilltemplate.ini, skillspec.txt, skillconst.txt, skillconst2.txt; the name → TID join uses the EP8 template (930 is "Skill Upgrade" there, 524's name is badly encoded on the client side); skill_template keeps the client's name and icons
Experience Levels 1 to 100 from the EP8 table, 101 to 121 from the client (only known scale beyond)
Growth growupfactor.ini; template 1276 (ArchLord), missing from the EP8 table, keeps the client's growth
NPCs npc.ini merge: client name; EP8 template, position and events (parallel Function / EventID lists, element by element); quests (27), repair (17) and wanted board (32) from the client, which the EP8 table removed; EP8 shop if imported, otherwise the client's; an NPC moved more than 1,000 units off the client's terrain keeps its position; NPCs with a non-EP8 template (2207) and NPCs 814 and 526 dropped. 35 numbers point to another NPC in the EP8 table (Christmas trees, "Event" NPCs instead of title managers, Battle Square supervisors…): those client NPCs keep their values, the EP8 table's are not imported
Purely client tables Quests (39 removed: the 30 citing a non-EP8 monster or item to bring back, and 9 whose "TID;count" reward is an Archonia item — Shard of Rebirth, Tempering Gem…; their emptied groups too), masteries, titles, production, boss window (13 Archonia bosses removed), sieges: kept, without rows citing a non-EP8 TID
Damage sharing divide column of the EP8 table (Divine Protection 1, Martyr's Mark 2): the caster takes the share of the party; the bit 16 Archonia added is no longer required
Monster regeneration No original column: ArchCore rule (healed when they return to their spawn point)

Summary of the last import (copy databases): 16,973 items kept (3,848 dropped), 2,028 templates (428), 1,825 skills (923), 10,910 skill levels (2,042), 5,025 options (1,097), 532 runes (606), 4,541 recipes (1,190), 300 regions (31), 301 teleport points (5), 557 NPCs (2 from the client, 8 with an Archonia template; 56 of the EP8 table not imported), 144 shops (39), 14 quests (39), 12 bosses (13).

Export for the client

archcore export-client-tables <folder> writes, from the world database (content/ layer included), the value tables in the client's exact format (tools/export.rs), for ArchRust's "server data" folder (server-data/ next to realmlist.wtf, read before the packs):

  • ini/ and every client language folder (ini_fr, ini_de…) that has its own copy of the table; client file names (itemdatatable.txt, SKILL_CONST.txt, RefineryItem2.txt, LevelUpExp.txt…);
  • client headers and column order; a column specific to Archonia stays present and empty;
  • plain text, CRLF line endings, the folder's code page: CP949 for ini/ and ini_ko, Windows-1252 for ini_fr, ini_de, ini_es, Shift-JIS for ini_ja, GBK for ini_zh;
  • in a language folder, the client's translated texts are kept, values come from the database;
  • tables.toml at the root: format, fingerprint ("sha256:…", paths and contents of the files), software, generated.

With Client.TablesDir (see Configuration), the world server reads that fingerprint at start-up and announces it to ArchRust clients (client-tables/1 capability, ArchRust extensions). The client's Game folder comes from Client.DataDir, or --game.

Character migration

archcore migrate-ep8 compares characters with the EP8 world database and writes a report per character: non-EP8 items, options and runes removed, skill levels above the EP8 maximum (140 skills go from 20 to 15 levels), non-EP8 skills. With --apply, in one transaction and without destroying anything (table ep8_quarantine, see Database): non-EP8 items quarantined (with the mail and sales citing them), non-EP8 options and runes removed, levels brought down to the maximum, non-EP8 skills removed, and a free skill reset offered to everyone ("skill init" emptied), as the point costs of levels changed. --restore n undoes pass n. Back up the databases (mariadb-dump) before --apply.

Original server tables

Monster spawns and the server map are not in the client: they come from the original ArchLord server tables, to be placed in data/server-ini (never committed) or pointed to with --server:

File Content Table
spawndatatable.txt What: group, monster template and level, count, respawn delay, siege war. The level kept is the template's in characterdatatable.txt (EP8); boss delays come from the client's boss window (UIBoss.xml) monster_spawn
spawninstancetable.txt Where: position, orientation, radius of each point (a name may have several positions) monster_spawn
world/node_data (next to it or in the sibling folder) Map: 16 × 16 segments of 400 units per sector, blocked ground and region map_segment
itemdroptable.txt Each monster's own items: count, rate out of 100,000 monster_drop
groupdroprate.txt Drop groups: rate, DropMeditation sensitivity, level bonus drop_group
droprankrate.txt Item ranks given by the monster's drop rank drop_rank_rate
aidatatable.txt Monster AI: skills cast (TID;level), HP condition, number of casts, normal hits monster_ai
archcore db-init
archcore import data/client-ini --server path/to/ini

Rows of spawndatatable.txt without a position in spawninstancetable.txt are skipped and counted.

Unit tests

cargo test

Reverse engineering

The findings were made with REA and Ghidra 12. The approach is described on the Reverse engineering page.

Clone this wiki locally