The Data layer (Data/) provides game reference databases, icon management, coordinate
utilities, and the key name mapper. Most database classes are static with data either
hardcoded in source or loaded from JSON files at startup. The JSON database files are
produced by the NMSE.Extractor tool (see extractor.md).
Databases fall into two categories:
-
Hardcoded -- data is defined as static arrays/dictionaries in source code (e.g.,
CompanionDatabase,GalaxyDatabase). These are updated manually when game patches change values. -
Dynamic (JSON-loaded) -- data is loaded from JSON files in the
Resources/json/directory at runtime (e.g.,GameItemDatabase,RecipeDatabase,LeveledStatDatabase). These files are regenerated by the extractor.TitleDatabase,FrigateTraitDatabase,SettlementPerkDatabase,WikiGuideDatabase, andWordDatabaseare all JSON-loaded with full localisation support via_LocStrkeys.
| File | Data/CompanionDatabase.cs |
| Purpose | Hardcoded catalogs of companion creature species and creature appearance parts |
CompanionDatabase holds 100+ CompanionEntry records (ID and species name) for all
tameable creature archetypes (antelope, bird, cat, etc.). Provides Entries as a read-only
list and ById as a case-insensitive dictionary.
CreaturePartDatabase (same file) catalogs creature appearance customization parts. Each
CreaturePartEntry has a PartType and Groups array of DescriptorGroup instances, each
containing DescriptorOption name/value pairs. Used by the Companion panel for the creature
appearance editor.
| File | Data/ElementDatabase.cs |
| Purpose | Map NMS resource names to chemical element symbols |
A small static dictionary of 65+ entries that maps resource names like "Carbon" to symbols
like "C". Includes exotic elements (Di-hydrogen as H3, Chromatic Metal as Cm, etc.).
Used for compact display in inventory grids and tooltips.
| File | Data/FrigateTraitDatabase.cs |
| JSON | Resources/json/FrigateTraits.json (178 entries) |
| Purpose | Frigate traits with stat effects, loaded from JSON with localisation support |
All trait data is loaded from FrigateTraits.json at startup via LoadFromFile().
Each FrigateTrait record has: Id, display Name, NameLocStr (localisation key from
FRIGATETRAITTABLE.MXML's DisplayName field, e.g. "FLEET_TRAIT_SEC_FUEL_1"),
stat Type, numeric Strength, Beneficial flag, and Primary/Secondary fleet class
associations. Supports ApplyLocalisation() / RevertLocalisation() for language switching.
The class starts empty and is populated from JSON - no hardcoded fallback data.
| File | Data/GalaxyDatabase.cs |
| Purpose | Catalog of all 256 NMS galaxies |
A static array of tuples: (Name, Type, Number) for every galaxy. Types are Normal, Harsh,
Empty, or Lush. Example: Euclid is Normal #1; Eissentam is Lush #10. Used by the Discovery
panel for galaxy selection and coordinate display.
| File | Data/GameItemDatabase.cs |
| Purpose | Load and manage all game items from extractor-generated JSON database files |
An instance class (not static) because it is initialized after the application locates the
database directory. Loads all *.json files from the directory in parallel, skipping
non-item files (Rewards, Recipes, Words, FrigateTraits, SettlementPerks,
WikiGuide, Titles, none) which are loaded by their own databases. Each file becomes an
item type named after the filename.
GameItem properties: Id, Name, NameLower, Icon, Symbol, Description,
Category, ItemType, IsCooking, MaxStackSize, ChargeValue, IsChargeable,
Rarity, Quality, and BuildableShipTechID (for corvette base part mapping).
Localisation keys: GameItem also stores nullable _LocStr properties for localised
string lookups: NameLocStr, NameLowerLocStr, SubtitleLocStr, DescriptionLocStr.
These are the raw NMS localisation keys (e.g. "UI_FUEL_1_NAME") loaded from the
Name_LocStr, NameLower_LocStr, Subtitle_LocStr, Description_LocStr fields in the
extractor-produced JSON files. They allow looking up localised text from per-language JSON
files via LocalisationService.
| Method | Description |
|---|---|
LoadItemsFromJsonDirectory(dir) |
Parallel-loads all JSON files; returns true if at least one loaded |
GetItem(itemId) |
Case-insensitive lookup by ID |
Items |
Read-only dictionary of all items keyed by ID |
CorvetteBasePartTechMap |
Maps CV_ tech IDs to possible base part product IDs |
ApplyLocalisation(service) |
Swaps display fields (Name, NameLower, Subtitle, Description) with localised values from the active language; backs up English originals internally. For Name, falls back to {LocStr}_NAME, then tries a level-specific key extracted from the item ID suffix (e.g. {LocStr}3_NAME for UP_SHLD3, {LocStr}_X_NAME for UP_BOLTX), then {LocStr}1_NAME as final fallback. When the Name_LocStr chain fails (common for procedural tech whose Name_LocStr base differs from the lang-file base), derives the name key from DescriptionLocStr by replacing _DESC -> _NAME; also tries inserting _ before terminal X for illegal variants (e.g. UP_SHOTGUNX_DESC -> UP_SHOTGUN_X_NAME). Similarly derives NameLower (_NAME_L) and Subtitle (_SUB) from DescriptionLocStr when the primary LocStr fields are empty. For NameLower, falls back to {LocStr}_L. |
RevertLocalisation() |
Restores all display fields to their original English values from backup |
Design choice: Parallel JSON parsing with Task.WhenAll keeps startup fast even with
15+ database files containing thousands of items.
| File | Data/IconManager.cs |
| Purpose | Load, cache, and downscale item icon images for inventory grids |
An IDisposable instance class initialized with the path to the icons directory. Icons are
downscaled to a maximum of 128 px on load (the originals are 256x256) using bilinear
interpolation, saving roughly 75% memory while remaining sharp at the 96 px display size
used in grids.
PreloadIcons(database) loads all database icons in parallel on background threads, capped
at Environment.ProcessorCount to avoid GDI+ contention. GetIcon(filename) returns the
cached image or loads on demand. GetIconForItem(itemId, database) combines database lookup
with icon retrieval.
Design choice: Bilinear (not bicubic) interpolation is used because the quality difference is imperceptible at 128 px and bilinear is measurably faster during bulk preload.
| File | Data/InventoryStackDatabase.cs |
| Purpose | Stack size limits per difficulty level and inventory group |
Contains StackSizeEntry records organized by 3 difficulty levels (High, Normal, Low). Each
entry specifies Group (inventory type), Product max stack, and Substance max stack.
There are 13 inventory groups: Personal, PersonalCargo, Ship, ShipCargo, Freighter, Chest,
and so on.
Used by inventory editing to enforce maximum quantities when the user modifies stack counts.
| File | Data/JsonNameMapper.cs |
| Purpose | Bidirectional translation between obfuscated 3-character JSON keys and human-readable names |
NMS save files use obfuscated keys (e.g., "F2P" instead of "PlayerStateData"). The
mapper loads a mapping table from Resources/db/mapping.json -- a JSON file with a
"Mapping" array of {Key, Value} pairs.
| Method | Description |
|---|---|
Load(stream) / Load(filePath) |
Parse the mapping file |
ToName(key) |
Obfuscated -> human-readable (returns key unchanged if unknown) |
ToKey(name) |
Human-readable -> obfuscated (returns name unchanged if unknown) |
IsObfuscatedKey(key) |
Check if a string is a known obfuscated key |
Count |
Total number of loaded mappings |
The mapper is set globally on JsonParser via SetDefaultMapper() so that all parsed
JsonObject instances automatically translate keys during access. When serializing back to
disk, keys are reverse-mapped to their obfuscated form so the game can read the file.
Design choice: The mapper is separate from the JSON model so that the same JsonObject
code works with both obfuscated and clear-text saves (different platforms use different
formats).
| File | Data/LeveledStatDatabase.cs, Data/BaseStatLimits.cs |
| Purpose | Stat progression tables and validation ranges for ships, weapons, and freighters |
LeveledStatDatabase loads from LeveledStats.json. Each LeveledStat has a Name, Id,
Icon, IsFloat flag, and an array of LeveledStatLevel entries (one per class: C, B, A,
S). Each level holds a dictionary of value keys to integers.
BaseStatLimits provides three static dictionaries (ShipStats, WeaponStats,
FreighterStats) mapping entity types and stat IDs to BaseStatRange (min/max).
ClampStatValue validates and clamps user input to the allowed range. Loaded from
BaseStatLimits.json.
| File | Data/ProceduralStubs.cs |
| Purpose | Lookup data for procedural product items not in the main database |
Some items (prefixed with PROC_ or UP_FR) are procedurally generated and do not appear
in the extractor output. This static class provides 25 hardcoded Entry records with Id,
Name, Icon, Category, Subtitle, and Description. Accessed via Items (list) or
ById (case-insensitive dictionary).
| File | Data/RecipeDatabase.cs |
| Purpose | Crafting and refining recipe lookup |
An instance class loaded from Recipes.json. Stores Recipe objects (see
models.md) indexed by result item and by ingredient item for fast bidirectional
lookup.
| Method | Description |
|---|---|
LoadFromFile(jsonPath) |
Parse recipes JSON; returns true on success |
GetRecipesForResult(itemId) |
What recipes produce this item? |
GetRecipesUsingIngredient(itemId) |
What recipes consume this item? |
GetRefiningRecipes() |
Filter to refining-type recipes |
GetCookingRecipes() |
Filter to cooking-type recipes |
| File | Data/RewardDatabase.cs |
| Purpose | Expedition, Twitch, and platform reward catalog |
A static class with lazy-loaded lists. Loads from Rewards.json in the database directory.
Each RewardEntry has Id, Name, Category (season / twitch / platform), Unlock flag,
ProductId, NameLocStr, and SubtitleLocStr. Provides filtered views: SeasonRewards,
TwitchRewards, PlatformRewards.
| Method | Description |
|---|---|
LoadFromJsonDirectory(dir) |
Loads rewards from Rewards.json in the specified directory |
ApplyLocalisation(service) |
Swaps reward names with localised values; backs up English originals |
RevertLocalisation() |
Restores reward names to English defaults |
| File | Data/SettlementPerkDatabase.cs |
| JSON | Resources/json/SettlementPerks.json (90 entries) |
| Purpose | Settlement perk definitions with stat effects, loaded from JSON with localisation support |
Contains 90 SettlementPerk records loaded from SettlementPerks.json (both starter and
procedural). Each perk has Id, Name, NameLocStr (from SETTLEMENTPERKSTABLE.MXML's
Name field), Description, DescriptionLocStr, Beneficial flag, and an array of
PerkStatChange entries. Stat changes use PerkStatType (Population, Happiness, Production,
etc.) and PerkStatStrength enums. Supports ApplyLocalisation() / RevertLocalisation()
for language switching. A PerkStatRanges dictionary maps each stat type to integer ranges
per strength level. The class starts empty and is populated from JSON - no hardcoded fallback.
| File | Data/TechAdjacencyDatabase.cs |
| Purpose | Technology adjacency/synergy grouping data for inventory grid rendering |
A large static dictionary mapping item IDs (without ^ prefix) to TechAdjacencyInfo
records. Each record has BaseStatType (adjacency group ordinal), TechnologyCategory
(category ordinal), and LinkColourHex (synergy border color, e.g., "#44FDFF").
Items with the same BaseStatType value are considered adjacent and receive colored synergy
borders in the inventory grid. Contains 300+ entries.
| File | Data/TechPackDatabase.cs |
| Purpose | Predefined technology packs with unique hash keys |
A static dictionary mapping hash strings to TechPack records. Each pack has Id (e.g.,
"^T_TOX"), Hash (unique hash like "^808001BC85F7"), Icon filename, and Class
(C/B/A/S/NONE).
This is a partial class -- the extractor can generate TechPackDatabase.Generated.cs
with additional packs discovered from game data. Contains 300+ entries in the base file.
| File | Data/TitleDatabase.cs |
| JSON | Resources/json/Titles.json (318 entries) |
| Purpose | Player titles loaded from JSON with localisation support |
Contains 318 TitleEntry records loaded from Titles.json. Each entry has Id, Name
(with {0} placeholder for the player's name), NameLocStr, UnlockDescription,
UnlockDescriptionLocStr, AlreadyUnlockedDescription, AlreadyUnlockedDescriptionLocStr,
UnlockedByStat, and UnlockedByStatValue. Supports ApplyLocalisation() /
RevertLocalisation() for language switching. The {0} placeholder is preserved across
all localised translations. The class starts empty and is populated from JSON - no hardcoded
fallback.
| File | Data/WikiGuideDatabase.cs |
| JSON | Resources/json/WikiGuide.json (57 entries) |
| Purpose | Wiki guide topics loaded from JSON with localisation support |
Contains 57 WikiGuideTopic records loaded from WikiGuide.json. Each topic has Id
(with ^ prefix), Name, NameLocStr (the topic's localisation key from WIKI.MXML),
Category, CategoryLocStr, and IconKey (extracted from the MXML's Icon > Filename
texture path, e.g. "SURVIVALBASICS"). Topics are grouped into categories (Survival Basics,
Getting Around, Making Discoveries, etc.) with localised category names. Supports
ApplyLocalisation() / RevertLocalisation() for language switching.
GetEnglishCategory(topicId) returns the original English category (from backup when
localisation is active) for stable grid placement regardless of active language. The class
starts empty and is populated from JSON - no hardcoded fallback.
| File | Data/WordDatabase.cs |
| Purpose | Alien word translations for language knowledge management |
An instance class loaded from Words.json (produced by NMSE.Extractor from the game's
NMS_DIALOG_GCALIENSPEECHTABLE.MXML). Contains 2149 WordEntry records. Each entry has
Id, Text, a TextLocStr key for localisation lookups (derived from the first group key
by race ordinal, e.g. "TRA_ABOMINATION" for word "ABOMINATION"), and a Groups
dictionary mapping group names to race ordinals. Race mapping: 0=Gek, 1=Vy'keen, 2=Korvax,
4=Atlas, 8=Autophage. The TextLocStr allows looking up the translated word text from
per-language JSON files (e.g. Japanese "嫌悪" for "abomination").
| Method | Description |
|---|---|
LoadFromFile(jsonPath) |
Loads word data from Words.json |
ApplyLocalisation(service) |
Swaps word text with localised values; backs up English originals. Tries the primary TextLocStr key first, then falls back to all group keys (stripped of ^ prefix) if the primary lookup returns untranslated English text. This handles cases like "TRA_ACCESS" returning "access" while "BUI_ACCESS" contains the actual Japanese "アクセス". |
RevertLocalisation() |
Restores word text to English defaults |
Used by the Discovery panel to display and edit learned alien words.
| File | Data/LocalisationService.cs |
| Purpose | Per-language string lookups for localised item display |
An instance class that loads one language JSON file at a time from the Resources/json/lang/
directory. Each file (e.g. ja-JP.json) is a flat Dictionary<string, string> mapping NMS
localisation keys (like "UI_FUEL_1_NAME") to translated strings.
Language JSON files use unescaped UTF-8 so characters display as natural language text
(e.g. "炭素" not "\u70AD\u7D20"). The LocalisationBuilder serialises with
JavaScriptEncoder.UnsafeRelaxedJsonEscaping to achieve this.
SupportedLanguages is a static dictionary of 16 NMS language names to IETF BCP 47 tags:
en-GB, fr-FR, it-IT, de-DE, es-ES, ru-RU, pl-PL, nl-NL, pt-PT, es-419, pt-BR, zh-CN,
zh-TW, ko-KR, ja-JP, en-US. (TencentChinese excluded.)
| Method | Description |
|---|---|
SetLangDirectory(dir) |
Sets the lang/ directory path |
LoadLanguage(bcp47Tag) |
Loads a language file; pass null to revert to English defaults |
Lookup(locKey) |
Raw key lookup; returns null if not found or no language active |
GetName(item) |
Localised name via NameLocStr, falls back to item.Name |
GetDescription(item) |
Localised description via DescriptionLocStr, falls back to item.Description |
GetSubtitle(item) |
Localised subtitle via SubtitleLocStr, falls back to item.Subtitle |
ActiveLanguageTag |
Currently active BCP 47 tag (null when using defaults) |
IsActive |
Whether a non-default language is loaded |
Language switching flow: When a language is selected from the Language menu:
LocalisationService.LoadLanguage(tag)loads the language JSON file.GameItemDatabase.ApplyLocalisation(service)swaps item Name/Description/Subtitle with localised values (English originals are backed up internally).RewardDatabase.ApplyLocalisation(service)swaps reward names.WordDatabase.ApplyLocalisation(service)swaps word display text viaTextLocStr, falling back to group keys when the primary key returns untranslated English.RecipeDatabase.ApplyLocalisation(service)swaps recipe names.TitleDatabase.ApplyLocalisation(service)swaps title names/descriptions viaNameLocStr.FrigateTraitDatabase.ApplyLocalisation(service)swaps trait names viaNameLocStr.SettlementPerkDatabase.ApplyLocalisation(service)swaps perk names/descriptions.WikiGuideDatabase.ApplyLocalisation(service)swaps topic names/categories.FrigatePanel.RefreshTraitCombos()andSettlementPanel.RefreshPerkCombos()repopulate combo boxes so they display the newly localised trait/perk names.RecipePanel.RefreshLanguage()rebuilds the recipe grid with localised item names.AppConfig.Languageis persisted so the selection is remembered on next startup.- Reverting to English calls
RevertLocalisation()on each database, restoring the backed-up English values.
Startup language: ApplyStartupLanguage() is called during form construction (after
LoadDatabase()). It reads AppConfig.Instance.Language (defaults to "en-GB") and applies
the saved language to all databases, then refreshes combo boxes and the recipe panel.
Design choice: All internal editor logic runs against the default English values from the DB JSON files. The in-place swap approach is used for display: when localisation is active, display fields (Name, Description, Subtitle) are overwritten with localised strings. When reverted, the original English values are restored from backup. This avoids modifying panel code while keeping string comparison logic safe (comparisons use IDs, not display names).
| File | Data/CoordinateHelper.cs |
| Purpose | NMS galactic coordinate conversions -- portal codes, signal booster format, distance calculations |
A public static class that converts between voxel coordinates, 12-character portal codes,
and XXXX:YYYY:ZZZZ:SSSS signal booster format. Provides distance-to-center calculations
and jump count estimates.
| Method | Description |
|---|---|
VoxelToPortalCode(x, y, z, system, planet) |
Encode as 12-char hex portal code |
VoxelToSignalBooster(x, y, z, system) |
Encode as colon-separated hex |
PortalCodeToVoxel(code, ...) |
Decode portal code back to voxel coordinates |
GetDistanceToCenter(x, y, z) |
Straight-line distance in light-years |
GetJumpsToCenter(distance, perJump) |
Estimated warp jumps needed |
PortalHexToDec(code) |
Convert hex digits to decimal+1 comma-separated |
On WinForms builds (conditional compilation), also provides glyph image rendering:
GetGlyphImage(hexDigit) returns a cached PNG, and CreateGlyphPanel / UpdateGlyphPanel
create or refresh a FlowLayoutPanel of portal glyph images.
GameItemDatabase <-- IconManager (icon filenames from items)
<-- InventoryGridPanel (item lookup for picker)
<-- SettlementLogic (production item filtering)
RecipeDatabase <-- RecipePanel (recipe display)
RewardDatabase <-- AccountLogic (reward unlock management)
JsonNameMapper <-- JsonParser (global default mapper)
<-- JsonObject (per-instance mapper for key translation)
CompanionDatabase <-- CompanionLogic (species name lookup)
TechAdjacencyDatabase <-- InventoryGridPanel (synergy border rendering)
TechPackDatabase <-- InventoryGridPanel (hash-based tech lookup)
BaseStatLimits <-- StarshipLogic, FreighterLogic (stat clamping)
LeveledStatDatabase <-- Frigate/Squadron panels (class progression)