Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
90 commits
Select commit Hold shift + click to select a range
94efb3b
Add script to extract from xml files
BurnySc2 Apr 9, 2026
5f7a16f
Clean up
BurnySc2 Apr 10, 2026
f7a5782
Add full extract pipeline
BurnySc2 Apr 10, 2026
d4cf9b3
Add EffectData for bonus damage
BurnySc2 Apr 10, 2026
95367ca
Add techtree
BurnySc2 Apr 10, 2026
c7e68d2
Sort keys
BurnySc2 Apr 10, 2026
23913c3
Add time for abilities
BurnySc2 Apr 10, 2026
6d75de9
Fix techtree
BurnySc2 Apr 10, 2026
47d403d
Add extra unlocks and requirements for techtree
BurnySc2 Apr 10, 2026
50c3bf3
Split produces and unlocks
BurnySc2 Apr 10, 2026
52fe8a1
Fix techlab name as requirement
BurnySc2 Apr 10, 2026
0eb3660
Add sorted()
BurnySc2 Apr 10, 2026
81096ac
Add missing cycline
BurnySc2 Apr 10, 2026
a711a09
Fix produces for factory and warpgate
BurnySc2 Apr 10, 2026
536e3de
Add researches
BurnySc2 Apr 10, 2026
5f6bcd4
Add builds abilities
BurnySc2 Apr 10, 2026
7019e66
Add swarm units
BurnySc2 Apr 10, 2026
781a270
Add unit morphs and fix json sorting
BurnySc2 Apr 10, 2026
288ec06
Disable core.sc2mod
BurnySc2 Apr 10, 2026
4c67636
Add morphsto key
BurnySc2 Apr 10, 2026
3e4a0c6
Remove structures with no unit info
BurnySc2 Apr 10, 2026
168c941
Fix hive unlocks wiper
BurnySc2 Apr 10, 2026
df8aece
Merge tags ending in Array
BurnySc2 Apr 10, 2026
d0495a7
Reconstruct techtree path from starting units
BurnySc2 Apr 11, 2026
0dc3901
Fix sc2mod order in readme
BurnySc2 Apr 11, 2026
7d36763
Fix Cost and Range array
BurnySc2 Apr 11, 2026
0e488af
Convert "vital" to either "energy" or "life"
BurnySc2 Apr 11, 2026
cc86006
Handle flags better
BurnySc2 Apr 11, 2026
04a98ff
Improve list of unlocks and abilities
BurnySc2 Apr 11, 2026
51d3b81
Fix abilities for structures
BurnySc2 Apr 11, 2026
60de639
Deduplicate lists
BurnySc2 Apr 11, 2026
b4e37a9
Add missing structures from morph and upgrades
BurnySc2 Apr 11, 2026
b175381
Fix produces for OC and PF
BurnySc2 Apr 11, 2026
49c0a11
Add basic tests for json file
BurnySc2 Apr 12, 2026
bfa8afe
Fix nested index
BurnySc2 Apr 12, 2026
2708df3
Remove argparse for merge_xml
BurnySc2 Apr 12, 2026
d6ce851
Simplify merge script
BurnySc2 Apr 12, 2026
0991616
Simplify convert to json script
BurnySc2 Apr 12, 2026
59b02ca
Add techtree tests
BurnySc2 Apr 12, 2026
a7bbd4e
Fix test for thor and add morph from CC to OC
BurnySc2 Apr 12, 2026
547124b
Add broodlord and flying buildings test
BurnySc2 Apr 12, 2026
7d69adc
Improve generating techtree.json
BurnySc2 Apr 12, 2026
7d0f197
Update generate_techtree.py and reconstruct_data.py
BurnySc2 Apr 12, 2026
cee0697
Fix ruff and pyrefly issues
BurnySc2 Apr 12, 2026
7bf5e61
Add more techtree tests
BurnySc2 Apr 12, 2026
45382d9
Add hardcoded fixes to make tests succeed
BurnySc2 Apr 12, 2026
e786931
Fix structures landing in units section
BurnySc2 Apr 12, 2026
02940a2
Update github actions workflow
BurnySc2 Apr 12, 2026
8f015db
Fix ruff issues
BurnySc2 Apr 12, 2026
fc3cdba
Fix setup uv
BurnySc2 Apr 12, 2026
0818c11
Improve merge_xml to update more values
BurnySc2 Apr 20, 2026
67f580e
Fix merge for LayoutButtons
BurnySc2 Apr 21, 2026
62c81e6
Simplify merge_xml.py
BurnySc2 Apr 21, 2026
ddd108b
Implement update
BurnySc2 Apr 21, 2026
c59d434
Implement remove
BurnySc2 Apr 21, 2026
465271c
Fix merging by index name
BurnySc2 Apr 21, 2026
1752c6d
Add exception list to override tags instead of accumulating them
BurnySc2 Apr 21, 2026
fbe83f8
Fix twilight research and relevation cost
BurnySc2 Apr 21, 2026
dbefa5e
Implement xml_to_json and merge_json
BurnySc2 Apr 21, 2026
4f678de
For entries with index and value only, directly present them
BurnySc2 Apr 21, 2026
70714a5
Convert number values
BurnySc2 Apr 21, 2026
74e2f97
Update merge_json and tests
BurnySc2 Apr 21, 2026
2b68fd2
Make tests work for StargateTrain
BurnySc2 Apr 22, 2026
5f2af96
Update readme and merge_json.py
BurnySc2 Apr 22, 2026
34f5f95
Update merge_json and fix test_unit_data
BurnySc2 Apr 23, 2026
73b90d6
Clean up
BurnySc2 Apr 24, 2026
044288a
Fix generate_techtree
BurnySc2 Apr 24, 2026
3989dd5
Refactor and simplify code
BurnySc2 Apr 24, 2026
f176682
Make tests work
BurnySc2 Apr 24, 2026
3c446de
Add stableid.json ids and merge units and structures to Units key
BurnySc2 Apr 24, 2026
0668323
Add .json files and stableid.json
BurnySc2 Apr 24, 2026
c077b48
Add upgrade cost
BurnySc2 Apr 24, 2026
459c8a4
Add ability costs where possible
BurnySc2 Apr 24, 2026
8397636
Fix formatting
BurnySc2 Apr 24, 2026
73d11a2
Refactor load_json
BurnySc2 Apr 24, 2026
dd91fd8
Remove import
BurnySc2 Apr 24, 2026
24a38c0
Parametrize tests
BurnySc2 Apr 25, 2026
9bbd9e8
Add reachable check for computed_data
BurnySc2 Apr 25, 2026
ec36427
Add stimpack cost 10 and 20 life for marine marauder
BurnySc2 Apr 25, 2026
248b3fc
Add unit and structure build times under "time"
BurnySc2 Apr 25, 2026
f98cbc1
Add time for morphs
BurnySc2 Apr 25, 2026
614ed27
Fix morph times for lurker
BurnySc2 Apr 27, 2026
468c582
Add liquipedia data
BurnySc2 Apr 27, 2026
ff8243e
Add missing units
BurnySc2 Apr 27, 2026
9c427fd
Improve code
BurnySc2 Apr 27, 2026
9a54e54
Generalize morphs
BurnySc2 Apr 28, 2026
9674c31
Re-add cocoons
BurnySc2 Apr 28, 2026
0c8e437
Add cocoons test
BurnySc2 Apr 29, 2026
1d24c76
Refactor test_cocoons into test_computed_data
BurnySc2 Apr 29, 2026
4ad3c15
Fix ruff issues
BurnySc2 Apr 29, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 0 additions & 29 deletions .github/workflows/pythonactions.yml

This file was deleted.

36 changes: 36 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
name: Tests

on: [ push, pull_request ]

jobs:
test:
name: Test with Python ${{ matrix.python-version }} on ${{ matrix.os }}
runs-on: ${{ matrix.os }}
timeout-minutes: 15
strategy:
fail-fast: false
matrix:
os: [ ubuntu-latest ]
python-version: [ "3.14" ]

steps:
- uses: actions/checkout@v6

- uses: astral-sh/setup-uv@v7
with:
enable-cache: true

- name: Install dependencies
run: uv sync

- name: Run ruff format check
run: uv run ruff format --check

- name: Run ruff check
run: uv run ruff check

- name: Run pyrefly
run: uv run pyrefly check

- name: Run tests
run: uv run pytest
7 changes: 6 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,11 @@ generated/
/.idea

# Misc

sc2
.env*

# Extracted xml and json files
# src/json
src/xml
src/xml_old
# src/extracted
8 changes: 8 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"editor.formatOnSave": true,
"python.testing.pytestArgs": [
"test"
],
"python.testing.unittestEnabled": false,
"python.testing.pytestEnabled": true,
}
126 changes: 126 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
# SC2 Techtree Project

## Overview

This project converts StarCraft 2 mod data (XML) into a structured techtree JSON file.

## Pipeline

```
XML (mod files) → JSON → Merged JSON → techtree.json
```

### 1. xml_to_json.py

Converts SC2 mod XML files to JSON format. Each mod's XML is converted to JSON in-place (same directory).

**Mod processing order** (important for merge conflict resolution):
1. liberty.sc2mod
2. libertymulti.sc2mod
3. swarm.sc2mod
4. swarmmulti.sc2mod
5. void.sc2mod
6. voidmulti.sc2mod

**Data types converted**: UnitData, AbilData, UpgradeData, WeaponData, EffectData

### 2. merge_json.py

Merges the converted JSON files using **second-file-wins** conflict resolution. The mod order above means later mods override earlier ones (void > voidmulti > swarm > ...).

**Key merge behaviors:**
- **Records matched by `id`**: Units with the same id are merged rather than duplicated
- **Index-based arrays**: Entries with an `index` field update existing entries at that index
- **Removal markers**: `{SomeField: {index: N, removed: "1"}}` removes the base entry at index N
- **LayoutButtons**: Special merging logic for button layouts
- **Array tags** (Attributes, FlagArray, WeaponArray, CardLayouts, InfoArray): handled specially

### Index-Based Array Operations

The merge uses `index` fields to target specific entries in arrays:

#### Updating (`index` + value)
```json
// In override record targeting base at index "0":
{
"LayoutButtons": { "SomeButton": "value", "index": "0" },
"index": "0"
}
```
- `merge_values` matches entries by `base[index] == override[index]` (lines 118, 142)
- Matches also occur when base has no explicit index and override requests index "0" at position 0 (line 145)
- `_merge_layout_buttons` handles LayoutButtons specially, updating matched button fields or extending the array

#### Adding (index without removal marker)
```json
// Adding at index 2 (extends base_lb if needed):
{ "Button": {...}, "index": "2" }
```
- `_merge_layout_buttons` at lines 67-88: if no button matches the index, extends base and places at that position
- `merge_values` at lines 174-175: unmatched indexed entries are appended to the base array

#### Removing (`removed: "1"` pattern)
```json
// In override record, marking base entry at index "SomeId" for removal:
{
"SomeField": { "index": "0", "removed": "1" },
"index": "SomeId"
}
```
- `merge_values` at lines 118-135: detects `{field: {index: N, removed: "1"}}` pattern
- When found, finds and pops the base entry where `base_child["index"] == override_child["index"]`
- The `index` in `SomeField` value is the target position; the outer `index` is the entry identifier

### 3. generate_techtree.py

Processes the merged JSON into a clean techtree structure with:
- **structures**: Buildings (detected via EditorCategories or TECH_LABS set)
- **units**: Non-structure entities
- **abilities**: MorphTo, UpgradeTo, LiftOff abilities

**Entry structure per unit/structure:**
```json
{
"race": "Terran|Zerg|Protoss",
"produces": ["UnitNames"], // trained units
"builds": ["BuildingNames"], // built structures
"researches": ["UpgradeNames"], // researched upgrades
"unlocks": ["UnitNames"], // units this structure unlocks
"morphsto": "Target|[]", // morph/transform target
"requires": ["StructureNames"] // required structures
}
```

**Key mappings in generate_techtree.py:**
- `RACE_MAP`: Terr/Zerg/Prot → Terran/Zerg/Protoss
- `UNIT_REQUIREMENT_FIXES`: Manual fixes for inconsistent game data (e.g., Roach requires RoachWarren)
- `MORPH_EXCLUDE`: Cocoon-type units to exclude from morph targets
- `REQUIREMENT_NAME_FIXES`: Corrects garbled names (e.g., "RoboticsFa" → "RoboticsFacility")
- `RESEARCH_NAME_MAP`: Maps upgrade ability names to canonical upgrade names
- `ABILITY_STRUCTURE_MAP`: Shared abilities (e.g., SpireResearch belongs to GreaterSpire)
- `SHARED_RESEARCH_EXCLUDE`: Research that shouldn't appear on certain structures

**Filtering:**
- Campaign units excluded (EditorCategories contains "ObjectFamily:Campaign")
- Mercenary buildings excluded (Race is N/A or NOT_FOUND)

## Usage

```bash
uv run src/xml_to_json.py # Convert XMLs to JSON
uv run src/merge_json.py # Merge JSONs
uv run src/generate_techtree.py # Generate computed/techtree.json
uv run src/reconstruct_data.py # Generate computed/data.json
```

## Verify
```bash
uv run pytest
```

## Formatting and linting
```bash
uv run ruff check
uv run ruff format
uv run pyrefly check
```
64 changes: 64 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,70 @@ uv run --env-file=.env python run.py

to generate a new `/data/data.json`.

# src data
From the SC2 data, .xml files can be extracted. Use the Dockerfile for this step:

```sh
docker build -t stormex-image ./src

docker run -v "path/to/starcraft/StarCraft II:/data/sc2data:ro" -v ./src/xml:/data/output stormex-image /data/sc2data -s .xml -x -o /data/output
```

```sh
# Creates src/extracted/stableid.json
docker run -v "path/to/starcraft/StarCraft II:/data/sc2data:ro" -v ./src/extracted:/data/output/mods/core.sc2mod/base.sc2data/GameData stormex-image /data/sc2data -s stableid.json -x -o /data/output
```

Convert the data from .xml to .json with
```sh
# Creates .../*Data.json
uv run src/xml_to_json.py
```

Then merge relevant .json files using order
```
liberty.sc2mod -> libertymulti.sc2mod -> swarm.sc2mod -> swarmmulti.sc2mod -> void.sc2mod -> voidmulti.sc2mod
```
Run
```sh
# Creates src/merged/*Data.xml
uv run src/merge_json.py
```

From here we can generate the techtree (all units, all abilities)
```sh
# Creates src/json/techtree.json
uv run src/generate_techtree.py
```

A smaller version of the techtree (with only real units and hardcoded suppressions) can be generated with
```sh
# Creates src/computed/data.json
uv run src/reconstruct_data.py
```

All in one:
```sh
uv run src/xml_to_json.py && uv run src/merge_json.py && uv run src/generate_techtree.py && uv run src/reconstruct_data.py
```

Resulting files should be:
```sh
src/
├── Dockerfile
├── merge_xml.py
├── convert_xml_to_json.py
├── xml/ # srced from SC2
│ ├── campaigns/
│ └── mods/ # Load order
│ ├── liberty.sc2mod/
│ ├── libertymulti.sc2mod/
│ ├── balancemulti.sc2mod/
│ └── voidmulti.sc2mod/
├── merged/ # Merged XML
└── json/ # Final JSON output
```

# Missing data? Invalid data? Other issues?

Please [open a new issue in GitHub](https://github.com/BurnySc2/sc2-techtree/issues/new).
Expand Down
Empty file removed generate/__init__.py
Empty file.
Loading