package main import ( "sort" "strings" ) // dbItemTemplates is the merged, sorted list of item templates. var dbItemTemplates []string // ── domain types ───────────────────────────────────────────────────────────── type playerInfo struct { ID int64 `json:"id"` AccountID int64 `json:"account_id"` ControllerID int64 `json:"controller_id"` FLSID string `json:"fls_id"` Name string `json:"name"` Class string `json:"class"` Map string `json:"map"` FactionID int16 `json:"faction_id"` OnlineStatus string `json:"online_status"` } // gmIdentity is the seeded "GM/Server" persona used as the sender for admin chat // (whisper, map announcement). HexID is the AMQP user_id (accounts."user") the // game resolves the visible sender name from; FuncomID is the chat id shown // in-game (m_FuncomIdFrom). type gmIdentity struct { AccountID int64 `json:"account_id"` HexID string `json:"hex_id"` FuncomID string `json:"funcom_id"` } type journeyNode struct { NodeID string `json:"node_id"` IsComplete bool `json:"is_complete"` IsRevealed bool `json:"is_revealed"` HasPendingReward bool `json:"has_pending_reward"` } type itemInfo struct { ID int64 `json:"id"` TemplateID string `json:"template_id"` Name string `json:"name"` StackSize int64 `json:"stack_size"` Quality int64 `json:"quality"` Durability string `json:"durability"` MaxDurability string `json:"max_durability"` } type currencyRow struct { PlayerID int64 `json:"player_id"` CurrencyID int16 `json:"currency_id"` Balance int64 `json:"balance"` } type factionRep struct { ActorID int64 `json:"actor_id"` FactionID int16 `json:"faction_id"` FactionName string `json:"faction_name"` Reputation int32 `json:"reputation"` Scrips int64 `json:"scrips"` } type specTrack struct { PlayerID int64 `json:"player_id"` TrackType string `json:"track_type"` XP int32 `json:"xp"` Level float32 `json:"level"` } type itemRule struct { Name string `json:"name"` StackMax int64 `json:"stack_max"` Volume float64 `json:"volume"` Tier int `json:"tier"` Rarity string `json:"rarity"` Category string `json:"category"` IsSchematic bool `json:"is_schematic"` MaxDurability *float64 `json:"max_durability,omitempty"` Icon *string `json:"icon"` } type itemDataFile struct { DefaultStackMax int64 `json:"default_stack_max"` DefaultVolume float64 `json:"default_volume"` Names map[string]string `json:"names"` Items map[string]itemRule `json:"items"` } // tagsDataFile is the output of dune-item-data/build-tags-data.sh — maps from // journey story node IDs / contract names to the gameplay tags those in-game // completions would emit. The admin tool uses these to apply tags when an // admin clicks Mark Complete (since the DB-only completion bypasses the // in-game effects). type tagsDataFile struct { JourneyNodeTags map[string][]string `json:"journey_node_tags"` ContractTags map[string][]string `json:"contract_tags"` ContractAliases map[string]string `json:"contract_aliases"` // ContractSkillGrants[contract_id] = skill-block tags this contract's // SkillsKeyRewards would unlock in-game (e.g. "Skills.Key.Trooper3"). // Without applying these the trainer contract's tags land but the skill // tree branch stays locked. ContractSkillGrants map[string][]string `json:"contract_skill_grants"` // JobSkillBlocks["Trooper"] = every bExternal Skills.Key.* module in the // Trooper skill tree (tier 1/2/3 + capstones). Used by Unlock Trainer to // grant the *entire* job's block set, since only ~10 of 30 are // contract-granted (the rest are normally unlocked by dialogue or auto). JobSkillBlocks map[string][]string `json:"job_skill_blocks"` // JobAllModules["Trooper"] = every module (Key, Ability, Attribute, // Perk) whose SkillArea is ESkillTree::Trooper. Used by Reset Job Skills // to fully nuke a class tree — the trainer Key blocks alone aren't // enough because the game auto-grants the corresponding tier-1 ability // (e.g. Skills.Ability.SuspensorGrenade_Reduction) which then sticks // around as a refundable 1-SP phantom unless we remove it here. JobAllModules map[string][]string `json:"job_all_modules"` } type blueprintRow struct { ID int64 `json:"id"` OwnerName string `json:"owner_name"` ItemID int64 `json:"item_id"` Pieces int64 `json:"pieces"` Placeables int64 `json:"placeables"` Name string `json:"name"` } type baseRow struct { ID int64 `json:"id"` Name string `json:"name"` Pieces int64 `json:"pieces"` Placeables int64 `json:"placeables"` } // mapMarker is one plottable entity on the Live Map: a player pawn, a vehicle, // or (Phase 2b) a base. Position is the location vector of dune.actors.transform. // Pixel placement and "last seen" age are computed client-side. type mapMarker struct { Type string `json:"type"` // "player" | "vehicle" | "base" ID int64 `json:"id"` Name string `json:"name"` Class string `json:"class,omitempty"` Map string `json:"map"` PartitionID int64 `json:"partition_id"` X float64 `json:"x"` Y float64 `json:"y"` Z float64 `json:"z"` OnlineStatus string `json:"online_status,omitempty"` FLSID string `json:"fls_id,omitempty"` } // ── message types (used by db.go cmd* functions) ────────────────────────────── type msgConnect struct{ err error } type msgPlayers struct { rows []playerInfo err error } type msgInventory struct { rows []itemInfo err error } type msgCurrency struct { rows []currencyRow err error } type msgFactions struct { rows []factionRep scripCurrencyID int16 err error } type msgSpecs struct { rows []specTrack err error } type msgSQL struct { result string headers []string rows [][]string truncated bool err error } type msgMutate struct { ok string err error } type msgPlayerPosition struct { pos playerPosition err error } type msgRepairGear struct { repaired int scanned int err error } type msgRepairVehicle struct { repaired int skipped int total int err error } type msgJourney struct { rows []journeyNode err error } type msgBlueprintList struct { rows []blueprintRow err error } type msgBaseList struct { rows []baseRow err error } type msgItemTemplates struct { templates []string } type vehicleRow struct { ID int64 `json:"id"` Class string `json:"class"` Map string `json:"map"` ChassisDurability float64 `json:"chassis_durability"` VehicleName string `json:"vehicle_name"` IsRecovered bool `json:"is_recovered"` IsBackup bool `json:"is_backup"` } type cheatEntry struct { FLSID string `json:"fls_id"` CheatType string `json:"cheat_type"` EventTime string `json:"event_time"` CharacterName string `json:"character_name"` } type gameEvent struct { ActorID int64 `json:"actor_id"` UniverseTime string `json:"universe_time"` Map string `json:"map"` EventType int32 `json:"event_type"` X float64 `json:"x"` Y float64 `json:"y"` Z float64 `json:"z"` CustomData string `json:"custom_data"` } type dungeonRecord struct { DungeonID string `json:"dungeon_id"` Difficulty string `json:"difficulty"` DurationMs int64 `json:"duration_ms"` PlayersNum int `json:"players_num"` CompletionID int64 `json:"completion_id"` } // ── market board types ──────────────────────────────────────────────────────── type marketItem struct { TemplateID string `json:"template_id"` Quality int64 `json:"quality"` DisplayName string `json:"display_name"` Category string `json:"category"` Tier int `json:"tier"` Rarity string `json:"rarity"` LowestPrice int64 `json:"lowest_price"` TotalStock int64 `json:"total_stock"` BotStock int64 `json:"bot_stock"` ListingCount int64 `json:"listing_count"` Icon *string `json:"icon"` } type marketListing struct { OrderID int64 `json:"order_id"` TemplateID string `json:"template_id"` OwnerType string `json:"owner_type"` // "bot" or "player" OwnerName string `json:"owner_name"` Price int64 `json:"price"` Stock int64 `json:"stock"` Quality int64 `json:"quality"` } type marketSale struct { OrderID int64 `json:"order_id"` TemplateID string `json:"template_id"` SellerType string `json:"seller_type"` // "bot" or "player" SellerName string `json:"seller_name"` Price int64 `json:"price"` Quantity int64 `json:"quantity"` } type marketStats struct { TotalListings int64 `json:"total_listings"` BotListings int64 `json:"bot_listings"` PlayerListings int64 `json:"player_listings"` TotalStock int64 `json:"total_stock"` BotStock int64 `json:"bot_stock"` PlayerStock int64 `json:"player_stock"` UniqueItems int64 `json:"unique_items"` } type msgMarketItems struct { rows []marketItem err error } type msgMarketListings struct { rows []marketListing err error } type msgMarketSales struct { rows []marketSale err error } type msgMarketStats struct { stats marketStats err error } type teleportLocation struct { Name string `json:"name"` X float64 `json:"x"` Y float64 `json:"y"` Z float64 `json:"z"` } type msgVehicles struct { rows []vehicleRow err error } type msgCheatLog struct { rows []cheatEntry err error } type msgEvents struct { rows []gameEvent err error } type msgDungeons struct { rows []dungeonRecord err error } type msgPartitions struct { rows []teleportLocation err error } type msgKeystones struct { ids []int16 err error } type msgTags struct { rows []string err error } // ── item template merge (called after connect) ──────────────────────────────── func mergeItemTemplates(dbTemplates []string) { seen := make(map[string]string) for _, t := range dbTemplates { seen[strings.ToLower(t)] = t } for k := range itemData.Names { if _, ok := seen[k]; !ok { seen[k] = k } } if itemData.Items != nil { for k := range itemData.Items { if _, ok := seen[k]; !ok { seen[k] = k } } } merged := make([]string, 0, len(seen)) for _, v := range seen { merged = append(merged, v) } sort.Strings(merged) dbItemTemplates = merged }