Skip to content

Relique Developer Architecture

LordOfMyatar edited this page Mar 20, 2026 · 9 revisions

Relique Developer Architecture

Technical documentation for Relique (Item Blueprint Editor) development.


Table of Contents


Overview

Relique edits UTI (Item Blueprint) files for Neverwinter Nights.

Status: Alpha (active development) Namespace: ItemEditor (historical — product renamed to Relique) Dependencies: Radoub.Formats, Radoub.UI, Radoub.Dictionary


Project Structure

Relique/
├── CHANGELOG.md
├── CLAUDE.md (tool-specific guidance)
├── version.json (NBGV: 0.7.0-alpha)
├── Relique/
│   ├── Program.cs
│   ├── App.axaml(.cs)
│   ├── Services/
│   │   ├── CommandLineService.cs
│   │   ├── SettingsService.cs
│   │   ├── BaseItemTypeService.cs
│   │   ├── BaseItemCategoryService.cs
│   │   ├── ItemPropertyService.cs
│   │   ├── ItemNamingService.cs
│   │   └── ItemStatisticsService.cs
│   ├── ViewModels/
│   │   ├── ItemViewModel.cs
│   │   ├── VariableViewModel.cs
│   │   └── BoolToErrorBrushConverter.cs
│   ├── Views/
│   │   ├── MainWindow.axaml(.cs)
│   │   └── NewItemWizardWindow.axaml(.cs)
│   └── Assets/
└── Relique.Tests/
    ├── CommandLineServiceTests.cs
    ├── SettingsServiceTests.cs
    ├── Services/
    │   ├── BaseItemCategoryServiceTests.cs
    │   ├── ItemNamingServiceTests.cs
    │   ├── ItemPropertyServiceTests.cs
    │   ├── ItemPropertyOperationTests.cs
    │   └── ItemStatisticsServiceTests.cs
    └── ViewModels/
        ├── ItemViewModelTests.cs
        ├── ItemViewModelConditionalTests.cs
        ├── ItemEditingRoundTripTests.cs
        └── VariableViewModelTests.cs

Component Architecture

flowchart TD
    subgraph Views
        MW[MainWindow]
        WIZ[NewItemWizardWindow]
    end
    subgraph ViewModels
        IVM[ItemViewModel]
        VVM[VariableViewModel]
    end
    subgraph Services
        CMD[CommandLineService]
        SET[SettingsService]
        BIT[BaseItemTypeService]
        BIC[BaseItemCategoryService]
        IPS[ItemPropertyService]
        INS[ItemNamingService]
        ISS[ItemStatisticsService]
    end
    subgraph SharedLibs["Shared Libraries"]
        RF[Radoub.Formats]
        RU[Radoub.UI]
        RD[Radoub.Dictionary]
    end

    MW --> IVM
    WIZ --> BIT
    WIZ --> BIC
    WIZ --> INS
    IVM --> RF
    IPS --> RF
    BIT --> RF
    MW --> RU
    MW --> RD
    SET --> RU
Loading

Key Services

CommandLineService

Parse CLI arguments: --file, --safemode, --new, --help, -m (module context).

Dependencies: CommandLineParser (Radoub.UI)

SettingsService

Singleton inheriting BaseToolSettingsService. Stores settings in ~/Radoub/ItemEditor/ReliqueSettings.json.

Key settings: BrowserPanelWidth, OpenInEditorAfterCreate

BaseItemTypeService

Loads base item types from baseitems.2da via IGameDataService. Provides dropdown list with TLK-resolved descriptions. Hardcoded fallback if game data unavailable.

BaseItemCategoryService

Categorizes base items by EquipableSlots bitmask into groups: Weapons, Armor, Jewelry, etc. Used by New Item Wizard for filtered type selection. Identifies custom content items.

ItemPropertyService

Walks the 2DA cascade chain to resolve property types, subtypes, cost values, and parameter values. Powers the cascading dropdown UI for property editing.

itempropdef.2daiprp_[subtype].2daiprp_costtable.2daiprp_[param].2da

ItemNamingService

Generates and validates NWN identifiers:

  • Tag: max 32 chars, [a-zA-Z0-9_], typically UPPERCASE
  • ResRef: max 16 chars, [a-z0-9_], lowercase

Handles filename conflict resolution via ResolveResRefConflict().

ItemStatisticsService

Auto-generates formatted statistics description from an item's property list. One line per property with TLK-resolved names.


MVVM Layer

ItemViewModel

Wraps UtiFile. Exposes all editable fields via INotifyPropertyChanged: Name, Description, Tag, ResRef, BaseItem, Cost, StackSize, Charges, flags (Plot, Stolen, Cursed, Identified), model parts, colors, local variables, scripts.

Property changes update the underlying UTI directly.

VariableViewModel

Wraps a single local variable (Int/Float/String) with validation. Converts via FromVariable() / ToVariable().

Views

View Purpose
MainWindow Primary editor: menu bar, status bar, browser panel, editing sections (Basic, Properties, Appearance, Variables)
NewItemWizardWindow Guided creation: Step 1 (base type) → Step 2 (name/tag/ResRef) → Step 3 (palette category) → Step 4 (finish)

Item Property System (2DA Cascade)

flowchart LR
    PD[itempropdef.2da] -->|SubTypeResRef| ST["iprp_[subtype].2da"]
    PD -->|CostTableResRef| CT[iprp_costtable.2da]
    CT -->|"table name"| CV["iprp_[cost].2da"]
    PD -->|Param1ResRef| PT[iprp_paramtable.2da]
    PT -->|"table name"| PV["iprp_[param].2da"]
Loading

ItemPropertyService walks this chain to:

  1. List available property types from itempropdef.2da
  2. Load subtypes, cost values, param values on demand
  3. Provide cascading dropdowns in the UI
  4. Validate property combinations before save

File Format: UTI

GFF-based binary format parsed by Radoub.Formats/Uti/.

Section Key Fields
Identity LocName, Tag (32 chars), TemplateResRef (16 chars), Description
Base Properties BaseItem (baseitems.2da index), Cost, AddCost, Weight, StackSize, Charges
Flags Plot, Stolen, Cursed, Identified, Droppable, Pickpocketable
Properties PropertiesList — enchantments via 2DA cascade
Appearance ModelPart1/2/3, ArmorPart_*, Cloth/Leather/MetalColor
Variables Local variables (Int/Float/String)
Scripts OnActivate, OnAcquire, OnUnacquire, OnEquip, OnUnequip

Startup Lifecycle

sequenceDiagram
    participant P as Program.cs
    participant A as App.axaml.cs
    participant MW as MainWindow

    P->>P: Parse CLI args
    P->>P: Init UnifiedLogger
    P->>A: Build Avalonia app
    A->>A: Register tool path
    A->>A: Apply theme/font
    A->>MW: Create MainWindow
    MW->>MW: Constructor (light init)
    MW->>MW: Loaded (restore window state)
    MW->>MW: Opened (async: GameData, palettes, startup file)
Loading

Integration Points

Tool Integration
Trebuchet Registers Relique for discovery and file launch via --file
Fence Context menu "Edit Item" → launches Relique with --file
Quartermaster Context menu "Edit Item" → launches Relique with --file

Testing

Category Focus Key Files
Service tests Business logic isolation ItemPropertyServiceTests, ItemNamingServiceTests, ItemStatisticsServiceTests, BaseItemCategoryServiceTests
ViewModel tests Data binding, property changes ItemViewModelTests, VariableViewModelTests
Conditional logic Field visibility by base item type ItemViewModelConditionalTests
Round-trip File save → load cycle integrity ItemEditingRoundTripTests
CLI Command-line parsing, --new wizard NewItemCommandLineTests, CommandLineServiceTests
dotnet test Relique/Relique.Tests

Settings & Persistence

Tool settings: ~/Radoub/ItemEditor/ReliqueSettings.json

Shared settings (RadoubSettings): CurrentModulePath, ReliquePath, game paths, TLK, theme/font

DocumentState (Radoub.UI): Centralized dirty tracking, title bar updates with [*] marker.


Home | Index

Page freshness: 2026-03-19


Parley

Getting Started

User Guide

Features

Help


Manifest


Quartermaster


Relique


Reliquary


Fence

  • Fence - Merchant/Store Editor

Trebuchet


Shared Features


Developers

Parley Internals

Manifest Internals

Quartermaster Internals

Relique Internals

Reliquary Internals

Fence Internals

Marlinspike (Search Engine)

Trebuchet Internals

Radoub.UI


Radoub.Formats

Library

Low-Level Formats

High-Level Parsers


Legacy Bioware Docs

Original BioWare Aurora Engine file format specifications.

Core Formats

Object Blueprints

Module/Area Files

Reference


Page freshness: 2026-05-24

Index

Clone this wiki locally