Skip to content

docs: add initial documentation for Bin Delta/Patching System design#111

Open
Crauzer wants to merge 1 commit intomainfrom
bin-delta-patch-design
Open

docs: add initial documentation for Bin Delta/Patching System design#111
Crauzer wants to merge 1 commit intomainfrom
bin-delta-patch-design

Conversation

@Crauzer
Copy link
Member

@Crauzer Crauzer commented Mar 5, 2026

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.

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.
@Crauzer Crauzer requested a review from Copilot March 5, 2026 11:23
@Crauzer Crauzer self-assigned this Mar 5, 2026
@Crauzer Crauzer added documentation Improvements or additions to documentation crate:ltk_meta BIN metadata crate labels Mar 5, 2026
@Crauzer Crauzer added crate:ltk_ritobin Ritobin text format crate area:api Public API design needs-research Requires reverse engineering/research format:bin BIN property format labels Mar 5, 2026
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.delta format, 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.
Copy link

Copilot AI Mar 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Grammar: "The .py extension conflict with Python" should be "conflicts" (subject/verb agreement).

Suggested change
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.

Copilot uses AI. Check for mistakes.
Comment on lines +227 to +250
| 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
Copy link

Copilot AI Mar 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 .?).

Copilot uses AI. Check for mistakes.
Comment on lines +444 to +458
~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
Copy link

Copilot AI Mar 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Suggested change
~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

Copilot uses AI. Check for mistakes.

/// An operation on a single BinObject.
pub enum ObjectOp {
/// Add a new object (fails/warns if it already exists)
Copy link

Copilot AI Mar 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Suggested change
/// Add a new object (fails/warns if it already exists)
/// Add a new object (warns and overwrites if it already exists)

Copilot uses AI. Check for mistakes.
@Crauzer Crauzer moved this to In Progress in league-toolkit Mar 5, 2026
}

/// In-place modification of a complex property value.
/// This enables surgical edits to nested structures without replacing the whole value.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

useless LLM ass line

Suggested change
/// 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)>),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
| '.?' -- optional unwrap
| '?' -- optional unwrap

techniques[0].passes[0].shader

# Optional value unwrap
iconCircle.?
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is this supposed to have more paths afterwards? optional chaining should probably be treated as its own ? operator

Suggested change
iconCircle.?
iconCircle?

Index(usize),

/// Access a container item by property match
Match(Vec<(u32, PropertyValueEnum)>),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can this be extracted to the same type as in ItemSelector?


### Application Algorithm

```
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
```
```rs

### Application Algorithm

```
fn apply_delta(base: &mut Bin, delta: &BinDelta) -> DeltaResult {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should be Bin::apply_delta


## Crate Architecture

### New crate: `ltk_bin_delta`
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LSP relies on the parser rewrite branch that is still unfinished, future support is bottlenecked by that branch's completion

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

Labels

area:api Public API design crate:ltk_meta BIN metadata crate crate:ltk_ritobin Ritobin text format crate documentation Improvements or additions to documentation format:bin BIN property format needs-research Requires reverse engineering/research

Projects

Status: In Progress

Development

Successfully merging this pull request may close these issues.

3 participants