Pluggable game support#98
Draft
oMaN-Rod wants to merge 23 commits into
Draft
Conversation
Port of the palworld branch onto the reworked archive architecture: - games/palworld module with typed parsers for data embedded in RawData byte arrays (characters, items, groups, guilds, base camps, map objects) - Pal struct types wired into StructType/StructValue via the type macros - post-read/pre-write archive hooks convert embedded byte arrays to typed struct values and back, driven by the Types path registry and recorded schemas; nested archives share version/types/scope/schemas - schema-driven JSON deserialization seeds for Pal structs, accepting byte arrays for empty/unparsed payloads - transparent decompression of compressed saves (Palworld PLM via optional oodle feature), Save::write_compressed for writing them - lossy UTF-16/UTF-8 string decoding fallback with warnings - CLI: --palworld on to-json/edit, --compress-oodle on from-json/edit
Two concerns in one commit (shared edits in serialization.rs): - box the larger Pal StructValue variants to keep the enum size down - accept externally tagged byte arrays for unparsed Pal payloads when deserializing from JSON
Team mission assignments, breed farm and lamp fields, weapon item name, guild roles/markers, three new modules, and a work codec covering the new Progress_MultiType work and its assignments.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Pluggable per-game save support, with Palworld as the first implementation
Why
Palworld saves are GVAS with two extra layers:
PLM/PLZ/CNK)RawDatabyte arrays that need their own parsingMy first pass added
PalXxxvariants directly toStructValueandStructType. That worked, but it didn't feel like the right long-term design since every new game would need more core enum variants.Instead, this PR adds a
Gametrait as an extension point. Palworld is the first implementation and lives entirely underuesave/src/games/palworld/. Most of this grew out of work I was already doing for Palworld Save Pal. After a few iterations, this ended up feeling like a cleaner direction than baking Palworld-specific logic into the core types.What it does
The
Gametrait provides hooks for:RawDatabyte arrays to typed values (and back)Most methods have defaults. Games that only need a custom container format only implement those hooks. Games with custom struct parsing implement the required struct methods.
Save<G>andSaveReader<G>are now generic over a game type, andStructValuegains aGamevariant viaArchiveType::Game.There's also an optional runtime registry (behind the
clifeature) so tools can select games by name (--game palworld) without referring to Rust types.Oodle
Palworld's
PLMformat uses Oodle compression, which requires an external decoder. This PR adds an optionaloodlefeature backed byooz-rs.The licensing for
oozis GPL-3.0, whileuesaveis MIT, so enabling theoodlefeature makes the resulting binary GPL as well.That feature is now opt-in everywhere:
--features oodleThe downside is that a default build can't read normal Palworld (
PLM) saves. Instead it reports:I think keeping the default build MIT is the better tradeoff.
Compatibility
Save<G = NoGame>andSaveReader<G = NoGame>default to a no-op implementation, so normal GVAS usage is unchanged.I verified this by building an existing consumer against both versions without modifying any code.
There are three breaking API changes:
StructTypegains aGamevariant.StructValuegains aGamevariant.ArchiveTypegets a required associated type and method, which affects external implementors.The enum changes are straightforward. The
ArchiveTypechange is the one I'm less happy with, and I'm open to alternatives.Other changes
These aren't related to game support:
serde_json'sfloat_roundtripfeature for exact float parsing.to-json,from-json, andeditcould truncate the destination file before a parse failure.The truncation fix currently depends on the new CLI registry, so it isn't an easy cherry-pick. If you'd rather have that fixed independently, I can split it into a separate PR.
Testing
--all-features(46 withoutoodle)Known issue
test-resave --game palworldcurrently reports failures for compressed saves because it compares the original compressed file against the uncompressed output fromSave::write. The round trip itself was verified as part of the Palworld save testing above.I left this alone because the right fix depends on what
test-resaveis intended to verify. Comparing against the decompressed original seems like the simplest option, but I wanted to get feedback first.Questions
uesave, or belong in tooling?Gametrait, even if it means fewer extension points?