Skip to content

Latest commit

 

History

History
487 lines (365 loc) · 21.8 KB

File metadata and controls

487 lines (365 loc) · 21.8 KB

Data Layer

Overview

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:

  1. Hardcoded -- data is defined as static arrays/dictionaries in source code (e.g., CompanionDatabase, GalaxyDatabase). These are updated manually when game patches change values.

  2. 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, and WordDatabase are all JSON-loaded with full localisation support via _LocStr keys.


Database Classes

CompanionDatabase / CreaturePartDatabase

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.


ElementDatabase

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.


FrigateTraitDatabase

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.


GalaxyDatabase

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.


GameItemDatabase / GameItem

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.


IconManager

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.


InventoryStackDatabase

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.


JsonNameMapper

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).


LeveledStatDatabase / BaseStatLimits

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.


ProceduralStubs

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).


RecipeDatabase

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

RewardDatabase

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

SettlementPerkDatabase

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.


TechAdjacencyDatabase

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.


TechPackDatabase

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.


TitleDatabase

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.


WikiGuideDatabase

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.


WordDatabase

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.


LocalisationService

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:

  1. LocalisationService.LoadLanguage(tag) loads the language JSON file.
  2. GameItemDatabase.ApplyLocalisation(service) swaps item Name/Description/Subtitle with localised values (English originals are backed up internally).
  3. RewardDatabase.ApplyLocalisation(service) swaps reward names.
  4. WordDatabase.ApplyLocalisation(service) swaps word display text via TextLocStr, falling back to group keys when the primary key returns untranslated English.
  5. RecipeDatabase.ApplyLocalisation(service) swaps recipe names.
  6. TitleDatabase.ApplyLocalisation(service) swaps title names/descriptions via NameLocStr.
  7. FrigateTraitDatabase.ApplyLocalisation(service) swaps trait names via NameLocStr.
  8. SettlementPerkDatabase.ApplyLocalisation(service) swaps perk names/descriptions.
  9. WikiGuideDatabase.ApplyLocalisation(service) swaps topic names/categories.
  10. FrigatePanel.RefreshTraitCombos() and SettlementPanel.RefreshPerkCombos() repopulate combo boxes so they display the newly localised trait/perk names.
  11. RecipePanel.RefreshLanguage() rebuilds the recipe grid with localised item names.
  12. AppConfig.Language is persisted so the selection is remembered on next startup.
  13. 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).


CoordinateHelper

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.


Dependency Graph

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)