A powerful GUI tool for generating hardpoint XML files for Star Wars: Empire at War modding. Built to eliminate the tedious, error-prone process of hand-writing hundreds of nearly identical XML hardpoint entries β letting you define templates once and generate entire fleets of consistent hardpoints in seconds.
- What Is This?
- Requirements & Installation
- File Structure
- Quick Start (5 Minutes to Your First XML)
- Interface Overview
- The Sidebar
- Bone Pool
- Groups
- Group Editor β Settings
- Group Editor β Bones Tab
- Group Editor β Components Tab
- Group Editor β Field Overrides Tab
- Template Browser
- Component Browser
- Template Editor
- Generating XML
- Template File Format
- Field Types & Placeholders Reference
- Template Inheritance
- Components System
- Ship Config Reference
- Exclude / Include Filters
- ALO Bone Import
- XML Hardpoint Import
- Keyboard Shortcuts
- Tips, Tricks & Best Practices
- Troubleshooting
In Empire at War, every ship's weapons, shields, engines, and systems are defined as hardpoints β individual XML entries in files like Hardpoints_Empire_Space.xml. A large capital ship might have 30β80 of these entries, each nearly identical but with different bone names and numbering.
The Hardpoint Generator solves this by letting you:
- Define templates β reusable blueprints for each hardpoint type (e.g., light turbolaser, ion cannon, shield generator).
- Build a bone pool β all the hardpoint bone names from your model's skeleton.
- Organize groups β each group links a template to a set of bones, producing one XML entry per bone.
- Generate the XML β the tool assembles everything into a valid, game-ready XML file in one click.
Instead of writing 40 nearly identical <HardPoint> blocks by hand, you write one template and assign 40 bones. The generator does the rest.
- Python 3.10 or newer (uses
match,X | Ytype hints) - tkinter β included with most Python distributions (on Linux, install
python3-tk) - No external Python packages required
The following files must all be in the same directory:
| File | Required | Purpose |
|---|---|---|
hp_generator_GUI.py |
β Always | The graphical application |
hp_generator.py |
β Always | XML generation engine |
alo_reader.py |
Optional | Enables bone import from .ALO model files |
hp_xml_importer.py |
Optional | Enables hardpoint import from existing .XML files |
Don't worry, these should be packaged with the HardpointGenerator.exe by default!
Simply run HardpointGenerator.exe
HardpointGenerator/
βββ HardpointGenerator.exe
βββ Templates/
β βββ Templates_Weapon_Generic.json
β βββ Templates_Weapon_Ion.json
β βββ Templates_Shield.json
βββ Components/
β βββ Component_Targetable.json
β βββ Component_Turrets.json
βββ Hardpoints/ β Generated XML files go here
β βββ Hardpoints_MyShip.xml
βββ Ship Configs/
βββ MyShip.json
The central file that ties everything together. It tells the generator which templates to use, where to write the output, and defines all the groups and bones for a specific ship.
JSON files defining reusable hardpoint blueprints. One file can contain multiple templates. Templates support inheritance β a "Light Turbolaser Turret" child template can inherit from a "Generic Weapon" parent.
Optional field overrides that can be layered on top of any template, per group. They use the same JSON format as templates. Useful for sharing settings (like Is_Targetable Yes) across many different groups without duplicating fields.
The final output β a valid EaW hardpoint XML file ready to be referenced in ``Hardpointdatafiles.xml` and used in-game.
Launch HardpointGenerator.exe
A new, blank ship config is created automatically.
In the left sidebar:
- Ship Name:
MyShip(used in comments and arguments in the XML and program) - Output File:
Hardpoints/Hardpoints_MyShip.xml(where the XML will be written) - Templates Path:
Templates(the folder containing your template JSON files) - Components Path
Components(the folder containing your component JSON files)
Click the π button to browse for folders, or π to pick a single JSON file.
In the Bones & Groups tab, click + Bone or + Sequence to manually add bone names from your model, or π₯ From ALOβ¦ to extract them automatically from a .ALO model file.
Example bones for a simple ship:
HP_Weapon_Turbolaser_L_01
HP_Weapon_Turbolaser_L_02
HP_Weapon_Turbolaser_R_01
HP_Weapon_Turbolaser_R_02
Click + Group in the Groups panel. In the Group Editor that appears below:
- Template: Select
Hardpoint_Weapon_Generic(or whichever template you have) - Name Prefix:
HP_MyShip_Turbolaser_L - Group Comment:
MyShip, Turbolasers, Port
Select the port turbolaser bones in the Bone Pool, then click βΆ Assign Selected to Group. The assignment dialog lets you choose which bone column to fill (AβE) and from which row.
Press F5 or click β‘ Generate XML. The output file is written and a summary is printed in the Output Log.
The application window has four main areas:
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Toolbar (New, Open, Save, Generate, Reloadβ¦) β
ββββββββββββββββ¬βββββββββββββββββββββββββββββββββββββββββββββββββββ€
β β Notebook Tabs: β
β Sidebar β β’ Bones & Groups (main workflow) β
β (Config, β β’ Template Browser (inspect loaded templates) β
β Paths, β β’ Component Browser (inspect loaded components) β
β Preview) β β’ Template Editor (create/edit β
β β template + component files) β
β β β
ββββββββββββββββ΄βββββββββββββββββββββββββββββββββββββββββββββββββββ€
β Output Log β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
All panes are resizable. Drag the dividers to customise your layout.
The sidebar on the left contains all the global ship configuration fields.
The name of the ship. Used in the auto-generated comment at the bottom of the XML file and as the {shipname} placeholder in group name prefixes and comments.
Example: MyShip β Name prefix HP_{shipname}_{templatename}_L becomes HP_MyShip_Turbolaser_L
Path to write the generated XML. Can be relative to the application folder (e.g., Hardpoints/Hardpoints_MyShip.xml) or absolute. Click β¦ to browse.
The folder containing your template JSON files, or a specific JSON file. Click π for a folder or π for a single file. After changing this, click βΊ Reload Templates (or it reloads automatically when you browse).
Same as Templates Path but for component JSON files. Components are optional β leave blank if you don't want to use them.
Controls the {model_idx} counter:
- Start: The first number (default
1) - Format: Python format string (default
02dβ01,02,03, β¦)
Use this when your template has a field like <Model_To_Attach>T_Turret_Imperial_{model_idx}.ALO</Model_To_Attach>. Each hardpoint gets a unique sequential number.
A live preview of the current ship config as JSON, showing the first 80 lines. Useful for sanity-checking before saving.
Shows the save path, group count, bone count, template count, and component count at a glance.
The Bone Pool is the master list of all hardpoint bones for this ship. It is displayed in the left panel of the Bones & Groups tab.
Bones in the pool are colour-coded:
- Grey β Not yet assigned to any group
- White β Assigned to exactly one group
- Peach/Orange β Assigned to multiple groups
Click + Bone. Enter the bone name exactly as it appears in your .ALO model (case-sensitive). Optionally enter a Custom HP Name β this overrides the auto-generated hardpoint name for that specific bone (useful for a shield or engine hardpoint that needs a fixed name rather than _01, _02, etc.).
Click + Sequence to bulk-add bones that follow a pattern.
| Field | Description | Example |
|---|---|---|
| Prefix | Common name start | HP_MyShip_TL |
| From # | Starting number | 1 |
| Count | How many to generate | 10 |
| Format | Number format | 02d (β 01, 02, β¦) |
| Suffix | Common name end | _L |
The Preview pane shows exactly which names will be added. Check Skip bones already in pool to avoid duplicates when extending an existing sequence.
The β Find Next button scans the existing pool and automatically sets "From #" to one past the highest existing number matching your prefix β perfect for extending a sequence without gaps or overlaps.
Click π₯ From ALOβ¦ to open the ALO Import dialog.
- Click π Browse .ALO File(s)β¦ and select one or more
.ALOmodel files. - The tool extracts every bone name from the skeleton.
- Use the filter and quick-select buttons to choose which bones to add.
- Suggested β selects all bones except those suggested to be excluded
- All excl. Root β everything except the root skeleton node
- All / None β select or deselect everything
- Click Add Selected to Pool.
Colour coding in the dialog:
- White β New bone, will be added
- Grey β Already in the pool
- Yellow β Suggested exclude (shadow meshes, particle emitters, collision objects)
Tip: For most ships, The tool automatically suggests excluding bones like
ShadowMesh,PE_Fire,ObjObject, etc.
- Double-click a bone, or select it and click β Edit, to rename it or change its Custom HP Name.
- Press Delete or click β Delete to remove selected bones. If a bone is assigned to a group, you'll be warned before it's removed from those groups too.
Type in the Filter box to narrow the displayed list by bone name or custom name. The filter is case-insensitive.
Each Group links one template to a set of bones, generating one hardpoint entry per bone. Groups are displayed in the upper-right panel of the Bones & Groups tab.
The Groups list shows:
- # β Group number (order in the XML)
- Comment / Prefix β The group comment or name prefix
- Template β The template assigned to this group (β if not found)
- Bones β How many bones are assigned
- Components β Components applied to this group (hover for full list)
- Field Overrides β Field tags overridden for this group (hover for full list)
Tip: Hover over the Components or Field Overrides cell in the list to see the complete list in a popup β handy when the full list is too long to display.
Click + Group to add a new group. A default group with a placeholder template is created and selected immediately.
Select a group and click β§ Duplicate to copy it with all settings and bone assignments. The duplicate is inserted directly below the original. Useful for quickly creating Port/Starboard or Top/Bottom variants.
Use β Up and β Down to change a group's position in the list. Groups are output in order in the XML file.
Select a group and click β Delete. Bone assignments within the group are lost, but the bones themselves remain in the pool.
When a group is selected, the Group Editor panel appears below the Groups list. Changes are auto-saved as you type β there is no Save button needed.
Appears as an XML comment before the group's hardpoints in the generated file:
<!-- Test Cruiser, Light Turbolasers, Port
-->Supports placeholders:
{shipname}β replaced with the Ship Name (spaces preserved){templatename}β replaced with the template name (spaces preserved)
Example: {shipname}, {templatename} β MyShip, Turbolaser
The prefix for auto-generated hardpoint names. Combined with the start index and format:
Prefix: HP_MyShip_Turbolaser_L
Start: 1
Format: 02d
β HP_MyShip_Turbolaser_L_01, HP_MyShip_Turbolaser_L_02, β¦
Supports placeholders:
{shipname}β Ship Name with spaces removed (e.g.,My ShipβMyShip){templatename}β Template name with spaces removed
Example: HP_{shipname}_{templatename} β HP_MyShip_Hardpoint_Weapon_Generic
The template to use for all hardpoints in this group. Click the dropdown or start typing to search. Click π to jump to that template in the Template Browser.
A warning appears if the template uses {model_idx} (reminding you to check the counters in the sidebar).
The number to start from when auto-naming hardpoints. Normally 1, but useful when you want multiple groups across different files to form a single continuous sequence (e.g., File A uses indices 1β10, File B uses 11β20).
Shared sequences: If two groups share the same Name Prefix, template, and index format, the generator automatically continues the sequence from where the previous group ended β you don't need to calculate start indices manually.
A Python format specification controlling number formatting:
02dβ01,02,03(zero-padded to 2 digits β default)03dβ001,002,003dβ1,2,3(no padding)
Overrides the <Health> field value for this group specifically, without modifying the template. Leave blank to use the template's default.
This is included purely for convenience, as you may manually override <Health> in the Field Overrides tab.
A live preview showing what the first two hardpoint names in this group will be. Updates as you type.
This tab shows all bones assigned to this group, with their bone slot assignments and the generated hardpoint name for each.
| Column | Description |
|---|---|
| # | Row number (determines the auto-index in the HP name) |
| Bone A | Primary bone β replaces {bone_a} / {bone} in template fields |
| Bone B | Secondary fire bone β replaces {bone_b} (defaults to Bone A if blank) |
| Bone C | Tertiary bone β replaces {bone_c} (defaults to Bone A if blank) |
| Bone D | Quaternary bone β replaces {bone_d} (defaults to Bone A if blank) |
| Bone E | Quinary bone β replaces {bone_e} (defaults to empty if blank) |
| Bone F | Senary bone β replaces {bone_f} (defaults to empty if blank) |
| Custom HP Name | Overrides the auto-generated name for this row only |
| Generated HP Name | Preview of the final hardpoint name |
Rows with extra bone slots filled (BβE) appear in teal; simple single-bone rows appear in white.
From the Bone Pool panel:
- Select one or more bones in the Bone Pool.
- Click βΆ Assign Selected to Group (or right-click for the context menu).
- The assignment dialog opens with your selected bones pre-selected.
From the Group Editor:
- Click + From Pool in the Bones tab.
- The same assignment dialog opens.
This dialog gives you full control over how bones are placed:
Column selector (AβE): Which bone slot to fill.
- Column A β Creates new rows, inserted at the chosen start row. Existing rows shift down.
- Columns BβE β Fills empty slots in existing rows from the start row onward. Overflow becomes new rows with Bone A left blank.
Start from Row: Where to begin filling. Click any row in the preview table to snap to it. Click a Bone AβE column header in the preview to also switch the bone column selector.
Preview table: Shows exactly what the group will look like after the assignment, colour-coded:
- White β Unchanged existing row
- Grey β Skipped (before start row)
- Teal β Slot filled in existing row
- Blue β New row with Bone A set
- Yellow β New row where Bone A is blank (overflow into BβE columns)
Dynamic hint: Text above the preview explains exactly what will happen in plain English.
Double-click a row, or select it and click β Edit, to open the bone entry editor. You can set all five bone slots and an optional custom name. Each slot has a searchable dropdown populated from the pool.
Use β and β buttons to reorder bone entries. The Generated HP Name column updates in real time as the numbering changes.
Select one or more rows and press Delete or click β Remove. The bones remain in the pool.
Components are modular, optional field overrides that layer on top of the base template for this group only. They're defined in separate JSON files in the Components folder.
Suppose you have 15 weapon groups, and 8 of them are targetable (<Is_Targetable>Yes</Is_Targetable>). Instead of creating 8 separate templates or using field overrides in every group, you create one Component called Is_Targetable_True and add it to those 8 groups. (This example component is already included in the files by default).
Benefits:
- Change one component β instantly affects all groups using it
- Mix and match: different groups can combine different components
- Cleaner templates: keep the base template minimal
- In the Components tab, use the dropdown at the top to search for and select a component name.
- Click οΌ Add.
Components are applied left-to-right, top-to-bottom. When two components set the same field, the later one wins. Use β and β to control priority.
A warning appears if multiple assigned components override the same field. Click Details⦠to see exactly which fields conflict and which component wins.
Select a component in the list and click π to jump to the Component Browser and inspect its fields.
Field Overrides allow you to override or extend the template's fields for this specific group, with the highest possible priority (applied after the template and all components). Perfect for one-off adjustments without needing a new template or component.
Click the Add: buttons to insert fields:
- Element β A standard XML tag/value pair:
<Tag>Value</Tag> - Section Comment β A block comment:
<!-- LABEL: --> - Inline Comment β A single-line comment:
<!-- text --> - Blank Line β An empty line for visual separation in the XML
Inline editing: Double-click the Tag or Value cell to edit it directly in place. Press Tab to cycle to the next column, Enter or Escape to commit/cancel.
Field Editor panel: Select any row to populate the editor below the table. Changes apply automatically as you type.
Field Editor fields:
- Type β The field type (element, section_comment, inline_comment, blank)
- Tag β For elements: the XML tag name. For comments: the comment text.
- Value β The field value (supports all placeholders)
- Empty tag β When checked, outputs
<Tag/>instead of<Tag></Tag>
Click π Load from Template to populate the overrides list with the fully-resolved fields of the current template (including components). This is useful as a starting point for heavy customisation β you can then modify specific fields.
The effective field order is:
- Template base fields
- Components (in list order)
- Field Overrides (highest priority β always wins)
The Template Browser tab lets you inspect all loaded templates in a searchable, sortable list.
- Click any column header to sort by that column. Click again to reverse.
- Type in the Filter box to search by template name or parent name.
- Blue entries are base templates (no parent). White entries inherit from a parent.
- Click β Edit Template Fileβ¦ to open the source JSON file in the Template Editor.
Selecting a template shows:
- Name, Inherits from, Parent comment β Basic metadata
- Inheritance chain β The full chain from root to this template (e.g.,
Base β Child β GrandChild) - Own fields / Total β How many fields this template defines itself vs. the total after resolution
- Fields table β All fields with their source (own vs. inherited from parent), type, tag, value, and any attributes or bone/model references noted
Toggle Show resolved to switch between viewing only this template's own fields or the fully merged (inheritance-resolved) field list.
Works identically to the Template Browser but for components. Useful for inspecting what fields a component will override before adding it to a group.
The Template Editor tab allows you to create and edit template JSON files directly within the application β no external text editor required.
Click π Open JSON to browse for an existing template file, or click π New File to start fresh.
Tip: In the Template Browser, click β Edit Template Fileβ¦ to open the selected template's source file directly in the editor, with that template automatically selected.
Click π₯ From XMLβ¦ to import hardpoints from an existing EaW .XML file as templates. This is useful for converting vanilla game hardpoints or community mods into the template format. Keep in mind some manual modification may be required.
The importer:
- Parses every
<HardPoint>element - Converts
Fire_Bone_Aβ{bone_a},Fire_Bone_Bβ{bone_b}automatically - Converts
Attachment_BoneandCollision_Meshto{bone_a}when they matchFire_Bone_A - Preserves original bone names in a leading comment field
After import, a selection dialog lets you choose which hardpoints to bring in. Imported templates are appended to the current file β save with πΎ Save Asβ¦.
Shows all templates in the currently open file. Use + New Template, β§ Duplicate, and β Delete to manage the list. β / β reorders templates within the file.
- Name β The template's unique identifier. Referenced by
inherits_fromin child templates and by thetemplatekey in ship configs. - Inherits from β Optional parent template name (searchable dropdown).
- Parent comment β Appears as
<!-- PARENT: ... -->inside each generated<HardPoint>block. Usually the same as the template name. - File comment β Stored as
_commentin the JSON file (informational only, not in XML output).
Metadata changes are applied automatically as you type. Renaming a template automatically updates all child templates in the same file that inherit from it.
Shows all fields for the selected template. Supports multi-select.
Adding fields: Use the Add buttons (Element, Section Comment, Inline Comment, Blank Line) to insert new rows below the selection.
Inline editing: Double-click the Tag or Value cell to edit in-place. Use Tab to cycle columns, Enter to commit.
Field Editor panel: The editor below the table shows the full details of the selected field and updates automatically.
Keyboard shortcuts:
- F2 β Start editing the Tag of the selected row
- Ctrl+β / Ctrl+β β Move selected row(s) up or down
- Ctrl+D β Duplicate selected row(s)
- Delete β Remove selected row(s)
- πΎ Save β Overwrites the current file.
- πΎ Save Asβ¦ β Saves to a new location.
- βΊ Reload into Browser β After saving, reloads the Templates folder so the Template Browser reflects your changes immediately.
Validates the config, then writes the XML file. A summary is printed in the Output Log:
Generated: Hardpoints/Hardpoints_MyShip.xml
Total hardpoints: 42
[Turbolaser] MyShip, Turbolaser, Port β 10 hardpoint(s)
[Turbolaser] MyShip, Turbolaser, Starboard β 10 hardpoint(s)
...
If there are warnings (missing templates, empty groups), a dialog asks whether to continue.
Prints all hardpoint names that would be generated, without writing any file. Use this to verify numbering and naming before committing.
Hardpoints for: MyShip
Total: 42
HP_MyShip_Turbolaser_L_01
HP_MyShip_Turbolaser_L_02
...
Opens a dialog to select a template and prints its fully-resolved field list to the Output Log. Useful for debugging inheritance chains or verifying that a template looks correct before use.
Template files are JSON files containing a list of template objects:
{
"_comment": "Optional file-level comment",
"templates": [
{
"name": "Hardpoint_Weapon_Generic",
"parent_comment": "Hardpoint_Weapon_Generic",
"inherits_from": "",
"fields": [
{ "_type": "section_comment", "text": "FIRE SETTINGS:" },
{ "tag": "Type", "value": "HARD_POINT_WEAPON_LASER" },
{ "tag": "Fire_Bone_A", "value": "{bone_a}" },
{ "tag": "Fire_Bone_B", "value": "{bone_b}" },
{ "_type": "blank" },
{ "tag": "Fire_Projectile_Type", "value": "Proj_ExampleProjectile" },
{
"tag": "Fire_Pulse_Count",
"value": "1",
"attrs": { "Editor_Ignore": "Yes" }
},
{ "tag": "Empty_Tag_Example", "value": "", "empty_tag": true }
]
},
{
"name": "Hardpoint_Weapon_Generic_Fighter",
"inherits_from": "Hardpoint_Weapon_Generic",
"fields": [
{ "tag": "Fire_Cone_Width", "value": "45.0" },
{ "tag": "Fire_Cone_Height", "value": "45.0" }
]
}
]
}| Type | JSON | XML Output |
|---|---|---|
| Element | { "tag": "T", "value": "v" } |
<T>v</T> |
| Empty element | { "tag": "T", "value": "", "empty_tag": true } |
<T/> |
| Empty value | { "tag": "T", "value": "" } |
<T></T> |
| Attributed | { "tag": "T", "value": "1", "attrs": {"Editor_Ignore": "Yes"} } |
<T Editor_Ignore="Yes">1</T> |
| Section comment | { "_type": "section_comment", "text": "LABEL:" } |
<!-- LABEL: --> |
| Inline comment | { "_type": "inline_comment", "text": " note " } |
<!-- note --> |
| Blank line | { "_type": "blank" } |
(empty line) |
These are substituted at generation time for each individual hardpoint:
| Placeholder | Replaced With | Default When Missing |
|---|---|---|
{bone} |
Bone A (primary) β backward-compatible alias | β |
{bone_a} |
Bone A (primary) β the main hardpoint bone | β |
{bone_b} |
Bone B (secondary fire bone) | Falls back to Bone A |
{bone_c} |
Bone C (e.g., attachment bone override) | Falls back to Bone A |
{bone_d} |
Bone D (e.g., collision mesh override) | Falls back to Bone A |
{bone_e} |
Bone E (e.g., damage particles bone override) | No fallback |
{bone_f} |
Bone E (e.g., damage decal bone override) | No fallback |
{model_idx} |
Turret model counter (from sidebar settings) | β |
{shipname} |
Ship name (in name_prefix, spaces removed) | β |
{templatename} |
Template name (in name_prefix, spaces removed) | β |
The bone slots BβE have default intended uses, but you're free to use them for any purpose in your templates:
| Slot | Convention | Template field |
|---|---|---|
| A | Primary fire bone | Fire_Bone_A, Attachment_Bone, Collision_Mesh |
| B | Secondary fire bone | Fire_Bone_B |
| C | Attachment bone | Attachment_Bone |
| D | Collision mesh | Collision_Mesh |
| E | Damage Particles bone | Damage_Particles |
Templates can inherit from a parent template using "inherits_from": "ParentName".
- Same-tag override: If the child defines a field with a tag that the parent also has, the child's version replaces all parent entries for that tag.
- New tags: Child fields with tags not in the parent are appended after the inherited fields.
- Structural fields: Blank lines and comments in the child are always appended (they have no tags, so they can't match parent fields).
parent_comment: Inherited from parent unless the child sets its own.
{
"templates": [
{
"name": "Weapon_Base",
"fields": [
{ "tag": "Type", "value": "HARD_POINT_WEAPON_LASER" },
{ "tag": "Fire_Cone_Width", "value": "160.0" },
{ "tag": "Fire_Cone_Height", "value": "160.0" }
]
},
{
"name": "Weapon_Fighter",
"inherits_from": "Weapon_Base",
"fields": [
{ "tag": "Fire_Cone_Width", "value": "45.0" },
{ "tag": "Fire_Cone_Height", "value": "45.0" }
]
}
]
}Weapon_Fighter resolves to:
<Type>HARD_POINT_WEAPON_LASER</Type>
<Fire_Cone_Width>45.0</Fire_Cone_Width>
<Fire_Cone_Height>45.0</Fire_Cone_Height>Chains are supported (A β B β C). Circular references are detected and reported as errors.
Components are defined in exactly the same JSON format as templates and loaded from the Components folder. They are designed to be applied on top of a base template for specific groups.
{
"templates": [
{
"name": "Is_Targetable_True",
"fields": [
{ "tag": "Is_Targetable", "value": "Yes" },
{ "tag": "Is_Destroyable", "value": "Yes" },
]
}
]
}Add the component name to a group in the Group Editor's Components tab. Multiple components can be stacked. The last component in the list wins any field conflicts.
| Components | Field Overrides | |
|---|---|---|
| Reusable | β Across any group, any ship | β Per-group only |
| Maintainable | β Change once, affects all users | β Must update each group |
| Granularity | Predefined sets of fields | Any individual field |
| Best for | Shared configurations | One-off tweaks |
<HardPoint Name="HP_MyShip_Turbolaser_01">
<!-- PARENT: Hardpoint_Weapon_Turbolaser
-->
<!-- COMPONENTS:
Is_Targetable_True
Turret_Heavy
Has_DamageParticles
-->
<Type>HARD_POINT_WEAPON_LASER</Type>
...
</HardPoint>A complete ship config example with all supported keys:
{
"_comment": "EaW Hardpoint Generator Ship Config",
"ship_name": "MyShip",
"output_file": "Hardpoints/Hardpoints_MyShip.xml",
"templates": "Templates",
"components": "Components",
"template_excludes": ["Templates/Legacy"],
"template_includes": ["../SharedTemplates/Templates_Common.json"],
"component_excludes": [],
"component_includes": [],
"turret_models": { "start": 1, "format": "02d" },
"damage_particles": { "start": 1, "format": "02d" },
"bone_pool": [
"HP_Weapon_TL_L_01",
"HP_Weapon_TL_L_02",
{ "bone_a": "HP_Ion_01", "bone_b": "HP_Ion_02", "name": "HP_Ion_Bank" }
],
"groups": [
{
"group_comment": "MyShip, Turbolasers, Port",
"template": "Hardpoint_Weapon_Turbolaser",
"name_prefix": "HP_MyShip_Turbolaser_L",
"start_index": 1,
"index_format": "02d",
"health_override": "",
"components": ["Is_Targetable_True"],
"field_overrides": [],
"bones": [
"HP_Weapon_TL_L_01",
"HP_Weapon_TL_L_02"
]
}
]
}"bones": [
"HP_TL_01",
{ "bone": "HP_TL_02", "name": "HP_Custom_Name" },
{ "bone_a": "HP_TL_03", "bone_b": "HP_TL_04" },
{
"bone_a": "HP_TL_05",
"bone_b": "HP_TL_06",
"bone_c": "HP_TL_05_ATT_01",
"bone_d": "HP_TL_05_COL_01",
"bone_e": "HP_TL_05_DMG_01",
"bone_f": "HP_TL_05_DMGDCL_01",
"name": "HP_Optional_Custom_Name"
}
]The βΈ Filters panel beneath each path field in the sidebar lets you fine-tune which JSON files are loaded.
Paths to silently skip during loading. Can be a sub-folder or a single file.
Use case: You have a Templates/Legacy/ folder with old templates you no longer want polluting the dropdown, but you don't want to delete them.
Extra files or folders that are always loaded, in addition to the main path. The main path can even be blank if you only use includes.
Use case: A shared Common_Templates.json file sitting outside your main Templates folder that you want always available.
- Excludes take priority over includes β an excluded file is never loaded even if explicitly included.
- Files from includes load after files from the main path; duplicate names are deduplicated (first occurrence wins).
- Paths are stored relative to the application folder in saved configs, so configs are portable.
- π Folder β Browse for a directory to exclude/include
- π File β Browse for a single JSON file
- β β Remove selected entries (also: Delete key or double-click)
- βΈ Filters β Toggle the panel open/closed (auto-expands when the first item is added)
See the Bone Pool section for full documentation. Quick summary:
- Click π₯ From ALOβ¦
- Browse for one or more
.ALOmodel files - Review the extracted bones (yellow = suggested excludes, grey = already in pool)
- Select the ones you want, click Add Selected to Pool
See the Template Editor section for full documentation. Quick summary:
- In the Template Editor tab, click π₯ From XMLβ¦
- Browse for an EaW hardpoints XML file
- Select which
<HardPoint>entries to import - Click Import Selected as Templates
- Review and save the resulting template JSON
| Shortcut | Action |
|---|---|
| Ctrl+N | New config |
| Ctrl+O | Open config |
| Ctrl+S | Save config |
| Ctrl+Shift+S | Save config as⦠|
| F5 | Generate XML |
| F6 | List hardpoints |
| F7 | Dump template |
| Delete | Delete selected item (bones, fields, etc.) |
| F2 | Inline-edit Tag of selected field row (Template Editor / Overrides) |
| Ctrl+β | Move selected field row up |
| Ctrl+β | Move selected field row down |
| Ctrl+D | Duplicate selected field row(s) |
| Tab | Cycle between inline-edit columns (Tag β Value β Attrs) |
| Enter | Commit inline edit |
| Escape | Cancel inline edit / close dialogs |
- One file per weapon type works well for large projects:
Templates_Weapon_Turbolaser.json,Templates_Weapon_Ion.json, etc. - Use inheritance liberally. A hierarchy like
Weapon_Base β Weapon_Turbolaser β Weapon_Turbolaser_Light_Greenkeeps each template small and focused. - Keep the base template lean β only put fields that are truly universal. Use inheritance for variants.
Consistent naming makes configs easier to maintain:
- Templates:
Hardpoint_WeaponType_Variant(e.g.,Hardpoint_Turbolaser_Light) - Components:
ComponentName_Value(e.g.,Is_Targetable_True,Turret_Heavy_Imperial) - Name prefix:
HP_{shipname}_{type}_{side}(e.g.,HP_MyShip_Turbolaser_L)
For symmetrical ships with port and starboard weapon groups:
- Create the port group, assign its bones.
- Select it and click β§ Duplicate.
- Edit the duplicate's comment (
Starboard), prefix (_R), and reassign the starboard bones.
Because the prefixes differ, each group keeps its own counter.
You may also simply pair bot Port and Starboard weapon groups together in one group, of course.
When hardpoints on the same ship form a single logical sequence regardless of which group they're in (e.g., all turbolasers numbered 01β24 across port and starboard groups), give both groups the same Name Prefix. The generator automatically continues the count from where the previous group left off.
For weapons with two alternating firing positions, use a bone entry with both Bone A and Bone B set:
{ "bone_a": "HP_TL_Fire_01_A", "bone_b": "HP_TL_Fire_01_B" }In the template, {bone_a} β Fire_Bone_A and {bone_b} β Fire_Bone_B. Both get unique values in the generated XML.
Rather than creating separate templates just to change a health value, use the Health Override field in the Group Editor. Keep one template and tweak health per group.
Use F7 (Dump Template) while building templates. It shows the fully-resolved field list after inheritance, making it easy to spot mistakes before generating the XML.
The sidebar's JSON Preview is a quick sanity check. If something looks wrong in the config, check here before saving.
The application always stores paths relative to its own folder. This makes configs fully portable β you can share a .json ship config and it will work on any machine with the same folder structure.
Ensure hp_generator.py is in the same directory as hp_generator_GUI.py. The generation features are disabled without it.
- Check the Templates Path in the sidebar is correct.
- Make sure your JSON files have a
"templates"array key at the top level. - Click βΊ Reload Templates after changing the path.
- Check the Output Log for specific error messages (invalid JSON, missing keys, etc.).
The template name assigned to that group doesn't match any loaded template. This can happen after renaming a template or changing the templates path. Edit the group and reselect the correct template.
- Check that every group has at least one bone assigned.
- Verify the template name in each group matches a loaded template exactly (case-sensitive).
- Run F6 (List Hardpoints) to see what would be generated without writing the file.
- Check that the template uses
{bone_a},{bone_b}, etc. (with curly braces) as the field value. - In the bone entry, verify Bone A is set. Bone BβE default to Bone A if blank.
- Use F7 (Dump Template) to confirm the field values in the template.
- The
.ALOfile may not contain a rigged skeleton (e.g., it's a particle effect or purely a render object). - The file may use a format variant not yet supported by
alo_reader.py. - Check the Output Log for specific warnings from the reader.
- Check that the output directory exists or that the application has write permission.
- If paths contain special characters, try using forward slashes or a simpler path.
For questions, bug reports, or contributions, see the GitHub repository or contact Venator Vicain: venatorvicain on Discord, venatorvicain@gmail.com on Gmail.
*GUI Style Attributions: Catpuccin Mocha