docs: add initial documentation for Bin Delta/Patching System design#111
docs: add initial documentation for Bin Delta/Patching System design#111
Conversation
This commit introduces a comprehensive design document outlining the Bin Delta system, detailing the problem statement, design overview, data model, and key principles. The document aims to facilitate mod creators by allowing them to express only the changes they intend, improving the modding experience for League of Legends.
There was a problem hiding this comment.
Pull request overview
Adds an initial, comprehensive design document describing the planned Bin Delta/Patching System, including the delta data model, human-authored .bin.delta text format, resolution/application approach, and planned crate/tooling/editor integration.
Changes:
- Documented core delta data structures and in-place modification model (objects/properties/containers/maps/optionals).
- Specified a Bin Path Language for addressing nested values and enabling conflict detection/tooling.
- Described the
.bin.deltaformat, resolution engine semantics, crate architecture, migration path, and LSP/editor support plan.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
You can also share your feedback on Copilot code review. Take the survey.
| } | ||
| ``` | ||
|
|
||
| The `.py` extension conflict with Python is handled by file content detection (checking for `#PROP_text` header) or by workspace-level association settings. |
There was a problem hiding this comment.
Grammar: "The .py extension conflict with Python" should be "conflicts" (subject/verb agreement).
| The `.py` extension conflict with Python is handled by file content detection (checking for `#PROP_text` header) or by workspace-level association settings. | |
| The `.py` extension conflicts with Python is handled by file content detection (checking for `#PROP_text` header) or by workspace-level association settings. |
| | Segment | Syntax | Description | | ||
| |---------|--------|-------------| | ||
| | Property | `samplerValues` | Property by name (resolved to name_hash) | | ||
| | Property (hash) | `#0x1234ABCD` | Property by raw name_hash | | ||
| | Index | `[0]` | Container/list item by index | | ||
| | Match | `[emitterName="Sparks1"]` | Container item by property match | | ||
| | Multi-match | `[name="Bloom",type="float"]` | Container item by multiple property matches (AND) | | ||
| | Map key | `{"NUM_BLEND_WEIGHTS"}` | Map entry by string key | | ||
| | Map key (hash) | `{0xDEADBEEF}` | Map entry by hash key | | ||
| | Map key (int) | `{42}` | Map entry by integer key | | ||
| | Optional inner | `?` | Unwrap optional value | | ||
|
|
||
| #### Grammar | ||
|
|
||
| ``` | ||
| bin_path = property_seg navigation* | ||
| property_seg = ident | '#' hex_hash | ||
| navigation = '.' ident -- struct/embed property access | ||
| | '.' '#' hex_hash -- struct/embed property by hash | ||
| | '[' index ']' -- container index | ||
| | '[' matcher ']' -- container match | ||
| | '{' key '}' -- map key | ||
| | '.?' -- optional unwrap | ||
| index = integer |
There was a problem hiding this comment.
The Optional unwrap segment syntax is inconsistent: the Segments table lists ?, but the grammar specifies '.?' (and later examples use iconCircle.?). This can confuse readers about whether ? is a standalone segment or must be prefixed by a dot; please make the table and grammar/examples agree (e.g., document the segment as .?).
| ~match(emitterName = "Sparks1") { | ||
| =pass: i16 = 100 | ||
| =blendMode: u8 = 2 | ||
| } | ||
|
|
||
| # Modify an item in-place by index (fragile but simple) | ||
| ~[0] { | ||
| =rate: embed = ValueFloat { | ||
| constantValue: f32 = 20 | ||
| } | ||
| } | ||
|
|
||
| # Multiple match criteria (AND'd together) | ||
| ~match(emitterName = "Trail", pass = 80) { | ||
| =pass: i16 = 90 |
There was a problem hiding this comment.
In the ~mEffects: list[embed] example, the list items are shown as SpellEffect { mEffectName ... }, but the subsequent ~match(emitterName = "Sparks1") { =pass ... =blendMode ... } uses fields that don't match that item type. This makes the example internally inconsistent; consider either changing the container/item type to a VFX emitter example (to match emitterName/pass/blendMode) or updating the match/fields to use SpellEffect properties consistently.
| ~match(emitterName = "Sparks1") { | |
| =pass: i16 = 100 | |
| =blendMode: u8 = 2 | |
| } | |
| # Modify an item in-place by index (fragile but simple) | |
| ~[0] { | |
| =rate: embed = ValueFloat { | |
| constantValue: f32 = 20 | |
| } | |
| } | |
| # Multiple match criteria (AND'd together) | |
| ~match(emitterName = "Trail", pass = 80) { | |
| =pass: i16 = 90 | |
| ~match(mEffectName = "Sparks1") { | |
| =mDuration: f32 = 3.0 | |
| } | |
| # Modify an item in-place by index (fragile but simple) | |
| ~[0] { | |
| =mDuration: f32 = 20.0 | |
| } | |
| # Multiple match criteria (AND'd together) | |
| ~match(mEffectName = "Trail", mDuration = 80.0) { | |
| =mDuration: f32 = 90.0 |
|
|
||
| /// An operation on a single BinObject. | ||
| pub enum ObjectOp { | ||
| /// Add a new object (fails/warns if it already exists) |
There was a problem hiding this comment.
ObjectOp::Add is documented as "fails/warns if it already exists", but later sections describe the behavior as "Warning, overwrite" and the sample apply_delta implementation always calls base.add_object(...) even when the object exists. Please align this comment with the intended behavior (warn+overwrite vs warn+skip vs error) to avoid contradicting the resolution semantics.
| /// Add a new object (fails/warns if it already exists) | |
| /// Add a new object (warns and overwrites if it already exists) |
| } | ||
|
|
||
| /// In-place modification of a complex property value. | ||
| /// This enables surgical edits to nested structures without replacing the whole value. |
There was a problem hiding this comment.
useless LLM ass line
| /// This enables surgical edits to nested structures without replacing the whole value. |
| /// Match by a property value inside a struct/embedded item. | ||
| /// e.g. match the VfxEmitterDefinitionData where emitterName == "Sparks1" | ||
| /// Multiple matchers are AND'd together. | ||
| MatchProperty(Vec<(u32, PropertyValueEnum)>), |
There was a problem hiding this comment.
The tuple here should be made a first class struct/enum (probably enum in case we want to extend the ways we can match)
| | '[' index ']' -- container index | ||
| | '[' matcher ']' -- container match | ||
| | '{' key '}' -- map key | ||
| | '.?' -- optional unwrap |
There was a problem hiding this comment.
| | '.?' -- optional unwrap | |
| | '?' -- optional unwrap |
| techniques[0].passes[0].shader | ||
|
|
||
| # Optional value unwrap | ||
| iconCircle.? |
There was a problem hiding this comment.
is this supposed to have more paths afterwards? optional chaining should probably be treated as its own ? operator
| iconCircle.? | |
| iconCircle? |
| Index(usize), | ||
|
|
||
| /// Access a container item by property match | ||
| Match(Vec<(u32, PropertyValueEnum)>), |
There was a problem hiding this comment.
can this be extracted to the same type as in ItemSelector?
|
|
||
| ### Application Algorithm | ||
|
|
||
| ``` |
| ### Application Algorithm | ||
|
|
||
| ``` | ||
| fn apply_delta(base: &mut Bin, delta: &BinDelta) -> DeltaResult { |
|
|
||
| ## Crate Architecture | ||
|
|
||
| ### New crate: `ltk_bin_delta` |
There was a problem hiding this comment.
This feels like a league-mod crate rather than a league-toolkit crate
| The LSP extension is split into two parts: | ||
|
|
||
| 1. **Language Server** (Rust) — handles parsing, validation, and semantic analysis | ||
| 2. **VS Code Extension** (TypeScript) — client that communicates with the server + TextMate grammar for syntax highlighting |
There was a problem hiding this comment.
untrue, VSC extension has no grammar info, all highlighting comes from semantic tokens via lsp binary
| | Unknown property name (with hash tables) | Info | `=mNonExistentProp` not found in known hashes | | ||
| | Unknown class name (with hash tables) | Info | `+object X : UnknownClass` | | ||
|
|
||
| The parser already tracks spans via `nom_locate`, so error locations map directly to LSP `Diagnostic` ranges. |
There was a problem hiding this comment.
LSP relies on the parser rewrite branch that is still unfinished, future support is bottlenecked by that branch's completion
This commit introduces a comprehensive design document outlining the Bin Delta system, detailing the problem statement, design overview, data model, and key principles. The document aims to facilitate mod creators by allowing them to express only the changes they intend, improving the modding experience for League of Legends.