Spent a Whole Day Writing a Parser, Then Found Out Tencent Had Already Done It for Me

Built a League of Legends skill value parser using CDragon, debugged to 93% coverage. Then someone dropped a Tencent API link — zero parsing, 100% coverage.

· 5 min read

Spent a Whole Day Writing a Parser, Then Found Out Tencent Had Already Done It for Me

This story has three acts.

Act One: I thought the problem was simple. Act Two: I discovered the problem was complex. Act Three: I discovered the problem shouldn’t have been solved this way at all.


First, some background

I built a League of Legends desktop assistant. Tauri + Rust + React, overlay window — players can see full skill values in-game: damage per rank, cooldown, mana cost.

Skill descriptions in the game look like this:

Deals @BaseDamage@ physical damage

Riot doesn’t store them as “30/60/90/120/150” directly. Instead:

  • Template string: Deals @BaseDamage@ physical damage
  • Value table: BaseDamage = [0, 30, 60, 90, 120, 150]

Index 0 is a placeholder; 1-5 are the per-rank values. The game does the substitution at runtime.

So my job was — write a substitution engine.

Sounds simple, right?


Act One: I thought this wouldn’t be hard

There are two data sources:

  • LCU (League Client local HTTP API, port 2999) → gives you skill description templates
  • CDragon (community-maintained data mirror) → gives you the full value tables

I first wrote unit tests to validate the CDragon parsing layer. Eight tests, all green.

Then I ran it live — every skill value was 0.


Act Two: Debug hell

Bug 1: Case sensitivity

CDragon’s HashMap stored keys as "Q", "W", "E", "R". LCU returned spellKey as "q", "w", "e", "r".

Rust’s HashMap is case-sensitive. get_spell("q") always returned None.

Fixed.

Bug 2: Slicing

The value table was [0, 30, 60, 90, 120, 150]. Index 0 is a placeholder and should be skipped. The code didn’t skip it. Displayed 0/30/60/90/120/150.

Fixed.

Bug 3: Cross-skill references

Some templates have @spell.GnarE:Damage@, which means “go find Damage in the E ability.” But the code only searched within the current ability.

Fixed.

Bug 4: f1 tokens

Another reference syntax pointing to the effectAmount array instead of DataValues. The two formats are completely different and need separate handling.

Fixed.

Then I built a “scout”

audit_token_coverage — a one-shot scanner across all 191 champions that tells me which tokens aren’t being correctly substituted.

Ran it: 178/191 perfect. 93% coverage.

The remaining 13 were all edge cases — some champion’s some ability using some obscure reference syntax.


Then someone said something

Are you sure you even need this feature?

I paused.

Then they continued:

What’s the core value of your app? Looking at your screenshots, it’s champion select intelligence — ratings, recent 6-match history, loss streak warnings, one-trick labels. Those are the selling points.

Skill values? Players can mouse over the skill icon for 0.5 seconds and see them. Your overlay only shows up after the game starts. Is your panel really better than the in-game one?

At the time, I didn’t really think about it. I was stuck in the loop of “how do I fix the remaining 13.”


Act Three: The truth

Later, someone dropped a link:

https://game.gtimg.cn/images/lol/act/img/js/hero/{champId}.js

This is data that Tencent maintains themselves for operating the Chinese server. I took one look —

{
  "cooldown": "4/4/4/4/4",
  "cost": "60/65/70/75/80",
  "description": "Deals 【80/125/170/215/260】+80%【Ability Power】..."
}

Cooldown: directly a string. No token parsing needed. Mana cost: directly a string. Damage values: already substituted in.

Tencent had done, for me, everything I spent the entire day doing.

And not 93%. 100%.


Actual workload comparison

  • CDragon approach: 93% coverage, manual translation needed for Chinese, 4-layer fallback + 8 types of formula parts for parsing, one full day invested, maintenance burden of new tokens every patch
  • Tencent API: 100% coverage, native Chinese, zero parsing, half a day to integrate, Tencent maintains it themselves

There’s a Chinese project called frank that uses this exact API for skill value display. Stable, complete, won’t get you banned.


What I learned from this

1. Research first, build later.

If I had searched “League of Legends skill data API” on day one, I’d have known about Tencent’s endpoint 8 hours earlier. If I’d seen the frank project 8 hours sooner, I’d have saved 90% of today’s work.

2. Green unit tests don’t mean no bugs.

The tests covered the “parsing layer,” but the bugs were in the “calling layer.” The gap between the two layers — tests can’t reach it.

3. Sometimes the best code is the code you don’t write.

The CDragon parser was over a thousand lines. The Tencent API: zero parsing. The answer was there all along. I just didn’t look for it.

4. Soul-searching questions are sometimes more important than debugging.

When someone asked “Are you sure you even need this feature?”, I didn’t take it seriously. If I had stopped to think for 5 minutes, I might have searched for alternative solutions instead of continuing into rounds 5, 6, and beyond.

5. But it wasn’t a total waste.

Today’s CDragon parser, the audit tool, the understanding of token parsing, the collaboration experience with Claude Code — those stay with me. Not sunk cost. Technical accumulation.


The ending

The current approach:

  • Tencent API as primary data source (100% coverage, native Chinese, zero parsing)
  • CDragon as fallback (in case Tencent’s API goes down)
  • LCU for supplemental runtime info (current rank, skill icons)

Less code, more accurate data, easier maintenance.


Sometimes the answer to a problem you spend an entire day solving is a link you never bothered to search for.

It’s not a capability issue. It’s a direction issue.