Skip to content

inventory-manager: read both deed register formats, add CSV export - #7531

Open
SekmehtDR wants to merge 1 commit into
elanthia-online:mainfrom
SekmehtDR:fix/deed-register-both-formats
Open

inventory-manager: read both deed register formats, add CSV export#7531
SekmehtDR wants to merge 1 commit into
elanthia-online:mainfrom
SekmehtDR:fix/deed-register-both-formats

Conversation

@SekmehtDR

Copy link
Copy Markdown
Contributor

Special thanks to JadedSoul (Illiahanna) for the collaboration on this one. She hit the register failure, worked out that the crafting display toggle was behind it, supplied a working parser for the second format, and keeping the deed type came from her version.


1. The deed register only understood one of its two formats

read my register returns different output depending on whether the crafting display toggle is on, and the parser required the bordered-table form. With the toggle off there are no pipes, so every line was rejected and the register saved zero deeds -- silently, with nothing to explain it.

Both are now parsed, and to the same stored row, so a register reads identically whichever way the toggle is set:

toggle on    |   7 | Metal | an agonite ingot | 3V 98Q - pure --Sekmeht |
toggle off       7 -- [Metal]  a deed for an agonite ingot (3V 98Q - pure --Sekmeht)

stored       an agonite ingot (deed page 7, Metal - 3V 98Q - pure --Sekmeht)

Two normalisations get them to agree: the plain listing prefixes every entry with a deed for, and parenthesises the note onto the deed text instead of giving it a column. Both are undone.

The deed type is now kept. Metal, Wood, Skin, Fabric, Stone were previously discarded, and the type is the only place the game tells you a large atheldalm fragment is Metal rather than Stone.

Existing data still reads

The browser now captures the whole annotation rather than matching it field by field, so rows written by earlier versions -- no type, with or without a note -- read back unchanged:

stored row name note
some mistwood lumber (deed page 1) some mistwood lumber page 1
some glaes ingots (deed page 8 - sell trade) some glaes ingots page 8 - sell trade
an agonite ingot (deed page 7, Metal - 3V 98Q ...) an agonite ingot page 7, Metal - 3V 98Q ...

Checked against a live 250-row register: all parsed, all with notes, no annotation text leaking into item names. Nothing needs re-saving, though a re-save is what picks up the type.

The totals line also differs in capitalisation between the two formats (Currently Stored: versus Currently stored: on its own line), so the filter that hides pre-parser rows from an old database now matches either.

2. Export to CSV

A new button in the browser, placed against the character dropdown so it reads as exporting whatever that dropdown is showing.

Scope follows the dropdown and nothing else. Someone exporting a character wants everything on that character, not whatever the search box happens to be narrowing the tree to. The dialog states this outright rather than leaving it to be discovered:

Exporting 250 items for Sekmeht.
Scope follows the character dropdown. The search box does not limit the export.

The dialog lists every column with all of them on by default. One of them is the verbatim database row, so an export is never lossy even with columns turned off.

Character,Source,Item,Container,Nested,Worn,Note,Stored row
Sekmeht,Deed Register,a coralite ingot,,no,no,"page 10, Metal - 2V 90Q - 67.00% Coralite, 19.80% Platinum","a coralite ingot (deed page 10, Metal - ...) (register)"

Fields are escaped per RFC 4180 rather than joined, because item names routinely contain commas and notes contain quotes -- joining would silently corrupt the file.

Files go to Lich's DATA_DIR, which is absolute and honours a --data= override, so exports land wherever the install actually keeps its data. They are timestamped so a second export cannot overwrite the first. The full path is reported to the game window, and shown in the status bar as a link that opens the file.

Rendering that link means the status bar renders markup, which would then break a search containing & or <. Every status write now goes through one helper that turns markup back off first.

Scope

One file, comments and behaviour only within inventory-manager -- no shared helpers or data files touched.

Verification

ruby -c and rubocop (including Custom/AsciiOnlySource) pass.

Harnesses cover:

  • Both register formats parsing to identical rows, asserted row for row across nine deeds spanning every type and both note styles, including the awkward 44 vol. @ 87, haralun ingot --Hanryu.
  • Borders, headers and totals lines rejected in both formats.
  • Backward compatibility with rows written by the current released version.
  • CSV escaping, plus a quote-aware field counter proving all 250 rows of a live export come back as exactly 8 fields.
  • Column selection, and the no-columns and empty-scope paths writing nothing rather than an empty file.
  • Path resolution, including a simulated --data= override with spaces in the directory name.

Tested in game against a real 250-deed register with the toggle on, and by Illiahanna with it off.

Deed register
"read my register" has two output formats depending on the crafting display
toggle, and the parser only understood one of them. With the toggle off there
are no table pipes, so every line was rejected and the register saved zero
deeds -- silently, with no error to explain it.

Both formats are now parsed, and to the same stored row, so a register reads
identically whichever way the toggle is set:

  toggle on   |   7 | Metal | an agonite ingot | 3V 98Q - pure --Sekmeht |
  toggle off      7 -- [Metal]  a deed for an agonite ingot (3V 98Q - pure --Sekmeht)
  stored      an agonite ingot (deed page 7, Metal - 3V 98Q - pure --Sekmeht)

Getting there needs two normalisations: the plain listing prefixes every entry
with "a deed for", and parenthesises the note onto the deed text rather than
giving it a column. Both are undone so the two formats agree exactly.

The deed type (Metal, Wood, Skin, Fabric, Stone) is now kept. It was previously
discarded, and it is the only place the game says a "large atheldalm fragment"
is Metal rather than Stone.

The reader in the browser captures the whole annotation instead of matching
field by field, so rows written by earlier versions -- with no type, with or
without a note -- still read back. Verified against a live 250-row database.
The totals line differs in capitalisation between the formats, so the filter
that hides pre-parser rows now matches either.

Export to CSV
New button in the browser, sitting against the character dropdown so it reads
as exporting whatever that is showing. Scope deliberately follows the dropdown
and nothing else -- someone exporting a character wants everything on that
character, not whatever the search box happens to be narrowing to -- and the
dialog says so rather than leaving it to be discovered.

The dialog offers each column with all of them on by default. One column is the
verbatim database row, so an export is never lossy even with columns turned off.

Fields are escaped per RFC 4180 rather than joined, because item names routinely
contain commas and notes contain quotes. Files are written to Lich's DATA_DIR,
which is absolute and honours a --data= override, and are timestamped so a
second export cannot overwrite the first. The full path is reported to the game
window and shown in the status bar as a link that opens the file.

Making the status bar render a link means it renders markup, which would then
break a search containing & or <. Every status write now goes through one
helper that turns markup back off first.

Special thanks to JadedSoul (Illiahanna) for the collaboration on this one: she
hit the register failure, worked out that the crafting toggle was behind it,
supplied a working parser for the second format, and her version is where
keeping the deed type came from.

Verified: ruby -c and rubocop pass. Harnesses cover both register formats
parsing to identical rows, backward compatibility with already-saved rows, CSV
escaping and field counts across a live 250-row export, column selection, the
empty-scope and no-column paths, and path resolution including a --data=
override with spaces in it.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Aug 12, 2026

Copy link
Copy Markdown
Contributor

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 6bf16490-d2e7-4325-9648-4f75b9d28cc1

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant