Skip to main content

High-level Python toolkit for editing AoE2 DE DAT files

Project description

aoe2-genie-tooling

High-level Python toolkit for editing Age of Empires II Definitive Edition DAT files.

An object-oriented API with proper wrappers that handle multi-civ propagation automatically.

Installation

pip install aoe2-genie-tooling

Documentation

Full documentation is available in the docs/ directory or at https://gokumodder.github.io/aoe2-genie-tooling/.

Why This Library?

  • Proper Objects – Units, Graphics, Sounds return handle objects with typed properties
  • Multi-Civ Propagation – Changes automatically apply across all civilizations
  • Attribute Flattening – Access deeply nested properties directly (unit.move_sound instead of unit.bird.move_sound)
  • Type-Safe Datasets – IntEnum constants for resources, tasks, attack classes
  • Fluent Builders - Easy-to-use builders for tasks (unit.add_task.combat()) and effects

Quick Start

from aoe2_genie_tooling import GenieWorkspace

# Load workspace
workspace = GenieWorkspace.load("empires2_x2_p1.dat")

# Get managers
unit_manager = workspace.unit_manager
graphic_manager = workspace.graphic_manager
sound_manager = workspace.sound_manager
tech_manager = workspace.tech_manager
civ_manager = workspace.civ_manager

# Create a custom unit
unit = unit_manager.create("Elite Guard", base_unit_id=4)  # Clone from Archer
unit.hit_points = 120
unit.max_range = 6.0

# Save changes
workspace.save("output.dat")

Units: Create, Clone, Move, Delete

Creating Units

unit_manager = workspace.unit_manager

# Create new unit (clones from base_unit_id)
unit = unit_manager.create(
    name="My Unit",
    base_unit_id=4,               # Clone from Archer
    unit_id=1500,                 # Optional: specific ID (auto-assigns if None)
    enable_for_civs=[0, 1, 2],    # Optional: specific civs (all if None)
)

Cloning Units

unit_manager = workspace.unit_manager

# Clone existing unit to a new ID
clone = unit_manager.clone_into(
    src_unit_id=4,       # Source: Archer
    dst_unit_id=2000,    # Destination ID
    name="Archer Clone",
    on_conflict="overwrite",  # "error" | "overwrite"
)

Moving Units

unit_manager = workspace.unit_manager

# Move unit to different ID (leaves placeholder at source)
unit_manager.move(
    src_unit_id=2000,
    dst_unit_id=2500,
    on_conflict="swap",  # "error" | "overwrite" | "swap"
)

Getting Existing Units

unit_manager = workspace.unit_manager

# Get handle for existing unit
archer = unit_manager.get(4)
print(archer.name)       # "Archer"
print(archer.hit_points) # 30

Attacks & Armors

unit_manager = workspace.unit_manager
unit = unit_manager.get(4)  # Archer

# Read current attacks
for attack in unit.attacks:
    print(f"Class {attack.class_}: {attack.amount} damage")

# Add new attack (pierce damage)
unit.add_attack(class_=3, amount=6)

# Add armor (melee armor)
unit.add_armour(class_=4, amount=2)

Tasks (Unit Commands)

from Datasets import Task, Resource

unit_manager = workspace.unit_manager
unit = unit_manager.get(83)  # Villager

# List all tasks
for task in unit.tasks.list_tasks():
    print(f"Task {task.id}: type={task.task_type}")

# Add a gather task using builder
unit.add_task.gather(
    resource_in=Resource.FOOD,
    resource_out=Resource.FOOD,
    work_range=0.5,
)

# Remove a task by ID
unit.remove_task(0)

# Clear all tasks
unit.clear_tasks()

Graphics: Create and Assign

graphic_manager = workspace.graphic_manager
unit_manager = workspace.unit_manager

# Create a new graphic
graphic = graphic_manager.add_graphic(
    file_name="my_unit_attack.slp",
    frame_count=15,
    angle_count=8,
)

print(f"Created graphic ID: {graphic.id}")

# Assign to unit
unit = unit_manager.create("Slinger", base_unit_id=4)
unit.standing_graphic_1 = graphic.id
unit.attack_graphic = graphic.id

Sounds: Create and Assign

sound_manager = workspace.sound_manager
unit_manager = workspace.unit_manager

# Create a new sound
sound = sound_manager.add_new("Custom Attack")
sound.new_sound(filename="custom_attack.wav", probability=100)

print(f"Created sound ID: {sound.id}")

# Assign to unit
unit = unit_manager.get(4)
unit.attack_sound = sound.id
unit.move_sound = sound.id

Complete Example: Custom Unit with Assets

from aoe2_genie_tooling import GenieWorkspace
from Datasets import Resource, UnitClass

workspace = GenieWorkspace.load("empires2_x2_p1.dat")

# Get managers
unit_manager = workspace.unit_manager
graphic_manager = workspace.graphic_manager
sound_manager = workspace.sound_manager

# 1. Create custom graphics
idle_gfx = graphic_manager.add_graphic("hero_idle.slp", frame_count=10, angle_count=8)
attack_gfx = graphic_manager.add_graphic("hero_attack.slp", frame_count=15, angle_count=8)

# 2. Create custom sound
attack_sound = sound_manager.add_new("hero_attack")
attack_sound.new_sound("hero_attack.wav")

# 3. Create the unit (clone from Knight)
hero = unit_manager.create("Hero Knight", base_unit_id=38)

# 4. Set basic stats
hero.hit_points = 200
hero.speed = 1.5
hero.class_ = UnitClass.CAVALRY

# 5. Assign graphics
hero.standing_graphic_1 = idle_gfx.id
hero.attack_graphic = attack_gfx.id

# 6. Assign sound
hero.attack_sound = attack_sound.id

# 7. Set attacks and armor
hero.set_attack(class_=4, amount=15)   # Melee
hero.set_attack(class_=11, amount=10)  # Bonus vs Buildings
hero.add_armour(class_=3, amount=5)    # Pierce armor

# 8. Set cost
hero.cost.food = 100
hero.cost.gold = 80

# 9. Set resource storage (drops gold on death)
hero.resource_1(type=Resource.GOLD, amount=50.0, flag=2)

# 10. Save
workspace.save("output.dat")

print(f"Created Hero Knight at ID {hero.id}")

Datasets (Constants)

from Datasets import (
    Resource,      # FOOD, WOOD, GOLD, STONE, etc.
    UnitClass,     # INFANTRY, ARCHER, CAVALRY, etc.
    Attribute,     # Object attributes for effects
    Task,          # GATHER, BUILD, ATTACK, etc.
    StoreMode,     # Resource storage flags
)

unit.class_ = UnitClass.ARCHER

Exceptions

Exception When Raised
UnitIdConflictError Target ID exists with on_conflict="error"
GapNotAllowedError Would create gaps with fill_gaps="error"
InvalidIdError Negative or non-existent ID
TemplateNotFoundError No template unit for cloning
ValidationError Workspace validation failed

Requirements

  • Python 3.11+
  • GenieDatParser (local dependency - Rust-backed DAT parser)

License

LGPL-3.0

Author

GoKuModder

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

aoe2_genie_tooling-1.2.4.tar.gz (161.2 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

aoe2_genie_tooling-1.2.4-py3-none-any.whl (251.5 kB view details)

Uploaded Python 3

File details

Details for the file aoe2_genie_tooling-1.2.4.tar.gz.

File metadata

  • Download URL: aoe2_genie_tooling-1.2.4.tar.gz
  • Upload date:
  • Size: 161.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for aoe2_genie_tooling-1.2.4.tar.gz
Algorithm Hash digest
SHA256 3071fe40bfbf1ee8b765b62b77bb3614f0f318a9499cf3b807a067630157f89a
MD5 5fdc028d2614b1c661ab229d62edb858
BLAKE2b-256 0796a9a577bf7ba6cdcc99491cec5deced912f42b0105dafca7be293dfd3e4a7

See more details on using hashes here.

Provenance

The following attestation bundles were made for aoe2_genie_tooling-1.2.4.tar.gz:

Publisher: pypi-publish.yml on GoKuModder/aoe2-genie-tooling

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file aoe2_genie_tooling-1.2.4-py3-none-any.whl.

File metadata

File hashes

Hashes for aoe2_genie_tooling-1.2.4-py3-none-any.whl
Algorithm Hash digest
SHA256 caf0f6e9dfe265f2e0af06815322360f1208d9f1aaf79fd93d5cd21083c006cd
MD5 1aa1d1d4f11bd5f9ef090bdfdad87bc0
BLAKE2b-256 b0e0e981eed081de880b2a5d5426caeb136a63eb5db399d777c0217d40fa00a3

See more details on using hashes here.

Provenance

The following attestation bundles were made for aoe2_genie_tooling-1.2.4-py3-none-any.whl:

Publisher: pypi-publish.yml on GoKuModder/aoe2-genie-tooling

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page