Module:Resource data

From Beyond These Stars Official Wiki
Revision as of 01:54, 1 October 2026 by Aeredor (talk | contribs) (fixed some skipped resource names; now skips the ones listed as Fake)

Documentation for this module may be created at Module:Resource data/doc

--[[
Test in Scribunto console with:
=mw.dumpObject(p.get_resource("Power"))
=mw.dumpObject(p.get_all_resources())
]]--
local p = {}



--#region MARK: Cargo types

--- Cargo row from querying Resources; all values are strings at runtime.
---@class CargoResourceRecord
---@field page_name string|nil
---@field guid string|nil
---@field Name string|nil
---@field DisplayNameTerm string|nil
---@field DisplayNameTerm_en string|nil
---@field DisplayNamePluralTerm string|nil
---@field DisplayNamePluralTerm_en string|nil
---@field IconAddress string|nil
---@field ID string|nil
---@field PriorityAdjustment string|nil
---@field Type string|nil
---@field DefinedResourceLists string|nil
---@field ProduceType string|nil
---@field PeepCarryAmount string|nil
---@field KnownAtStart string|nil
---@field ProducedAtStart string|nil
---@field PeepExhaustionRemoved string|nil
---@field PeepHappinessAdded string|nil
---@field DontDrop string|nil
---@field ResourceTemperature string|nil
---@field SummaryType string|nil
---@field ResourceCategory string|nil
---@field Renewable string|nil
---@field KnownRecordName string|nil
---@field ProducedRecordName string|nil
---@field PollutionRatio string|nil
---@field PollutionRange string|nil
---@field PeepEnergyAdded string|nil
---@field TerrainTextureValueIndex string|nil
---@field YarnNodeOnSelect string|nil
---@field DefinedResourceLists_1 string|nil
---@field DefinedResourceLists_2 string|nil
---@field DefinedResourceLists_3 string|nil
---@field DefinedResourceLists_4 string|nil
---@field DefinedResourceLists_5 string|nil

--#endregion



--#region MARK: Cargo consts

local QUERIES = {
  RESOURCES = {
    TABLE = "Resources",
    WHERE_NAME = "page_name",
    ORDER_BY = "page_name",
    -- Commented out fields are not used in the current implementation.
    FIELDS = {
      "page_name",
      "guid",
      "Name",
      "DisplayNameTerm_en",
      "DisplayNamePluralTerm_en",
      "IconAddress",
      -- "ID",
      -- "PriorityAdjustment",
      "Type",
      -- "DefinedResourceLists",
      "ProduceType",
      "PeepCarryAmount",
      "KnownAtStart",
      -- "ProducedAtStart",
      "PeepExhaustionRemoved",
      "PeepHappinessAdded",
      -- "DontDrop",
      "ResourceTemperature",
      -- "SummaryType",
      -- "ResourceCategory",
      -- "Renewable",
      -- "KnownRecordName",
      -- "ProducedRecordName",
      -- "PollutionRatio",
      -- "PollutionRange",
      "PeepEnergyAdded",
      -- "TerrainTextureValueIndex",
      -- "YarnNodeOnSelect",
      "DefinedResourceLists_1",
      "DefinedResourceLists_2",
      "DefinedResourceLists_3",
      "DefinedResourceLists_4",
      "DefinedResourceLists_5",
    }
  }
}

--#endregion



--#region MARK: Cargo queries

--- Skips unwanted resources from a query result.
---@param results CargoResourceRecord[]
---@return CargoResourceRecord[]
local function skip_unwanted_resources(results)
  local new_results = {}
  for _, record in ipairs(results) do
    if not p.SKIPPED_RESOURCE_NAMES[record.Name] then
      table.insert(new_results, record)
    end
  end
  return new_results
end

--- Queries cargo for all resource records.
---@return CargoResourceRecord[]
local function query_all_resources()
  local cargo = mw.ext.cargo
  if not cargo then return {} end
  local result = cargo.query(
    QUERIES.RESOURCES.TABLE,
    table.concat(QUERIES.RESOURCES.FIELDS, ","),
    {
      limit = 150,
      orderBy = QUERIES.RESOURCES.ORDER_BY,
    })
  if not result or #result == 0 then return {} end
  result = skip_unwanted_resources(result)
  return result
end

--- Queries cargo for the resource record with the given name.
---@param resource_name string the name of the resource to fetch
---@return CargoResourceRecord|nil
local function query_resource(resource_name)
  local cargo = mw.ext.cargo
  if not cargo then return nil end
  local result = cargo.query(
    QUERIES.RESOURCES.TABLE,
    table.concat(QUERIES.RESOURCES.FIELDS, ","),
    {
      where = QUERIES.RESOURCES.WHERE_NAME .. '="' .. resource_name .. '"',
    })
  if not result or #result == 0 then return nil end
  result = skip_unwanted_resources(result)
  return result[1]
end

--#endregion



--#region MARK: Local helpers

--- Makes an array out of multiple optional fields from a resource record.
---@param record CargoResourceRecord
---@return string[]
local function restructure_resource_list(record)
  local resource_list = {}
  for i = 1, p.MAX_RESOURCE_LISTS do
    local item = record[string.format("DefinedResourceLists_%d", i)]
    if item then
      table.insert(resource_list, item)
    end
  end
  return resource_list
end

--- Restructures a resource record from the database into a more usable format.
---@param record CargoResourceRecord the resource record retrieved from the database
---@return Resource
local function restructure_resource_record(record)
  local resource = {
    name = record.page_name,
    category = record.Type,
    produce_type = record.ProduceType,
    display_name = record.DisplayNameTerm_en,
    display_name_plural = record.DisplayNamePluralTerm_en,
    icon = record.IconAddress,
    peep_carry_amount = tonumber(record.PeepCarryAmount),
    known_at_start = record.KnownAtStart,
    peep_temperature_effect = record.ResourceTemperature,
    peep_exhaustion_removed = tonumber(record.PeepExhaustionRemoved),
    peep_happiness_added = tonumber(record.PeepHappinessAdded),
    peep_energy_added = tonumber(record.PeepEnergyAdded),
    resource_list = {},
  }
  resource.resource_list = restructure_resource_list(record)
  return resource
end



--#region MARK: Public interface

---@class ResourceDataModule
---@field get_all_resources fun(): Resource[] gets all resources
---@field get_resource fun(resource_name: string): Resource|nil looks up a resource by name

p.MAX_RESOURCE_LISTS = 5
p.POWER_RESOURCE_NAME = "Power"
p.SKIPPED_RESOURCE_NAMES = {
  ["Astrobaleenium_Ground"] = true,
  ["Crystal_Ground"] = true,
  ["FieldSeed"] = true,
  ["Gold_Ground"] = true,
  ["Honeycomb_Ground"] = true,
  ["Mystery_Ground"] = true,
  ["Peep"] = true,
  ["Shell_Ground"] = true,
  ["Trash_Ground"] = true,
  -- these are listed as "Fake"
  ["Beverage"] = true,
  ["Drink"] = true,
  ["Food"] = true,
  ["Meal"] = true,

}

---@class Resource
---@field name string|nil the in-game codename for the resource
---@field category string|nil the category of the resource
---@field produce_type string|nil the produce type of the resource
---@field display_name string|nil the display name of the resource
---@field display_name_plural string|nil the plural display name of the resource
---@field icon string|nil the icon filename for the resource
---@field peep_carry_amount number|nil how many a peep can carry at once
---@field known_at_start boolean|nil whether the resource is known at start
---@field peep_temperature_effect string|nil the temperature effect of the resource
---@field peep_exhaustion_removed number|nil the amount of exhaustion removed per peep per second
---@field peep_happiness_added number|nil the amount of happiness added per peep per second
---@field peep_energy_added number|nil the amount of energy added per peep per second
---@field resource_list string[]|nil the defined resource lists for the resource

--- Fetches a resource record from the database.
---@param resource_name string the in-game name of the resource to fetch
---@return Resource|nil
function p.get_resource(resource_name)
  if not resource_name or resource_name == "" then return nil end
  local raw_record = query_resource(resource_name)
  if not raw_record then return nil end
  local record = restructure_resource_record(raw_record)
  return record
end

--- Fetches all resource records from the database.
---@return Resource[]
function p.get_all_resources()
  local raw_records = query_all_resources()
  if not raw_records or #raw_records == 0 then return {} end
  local records = {}
  for _, raw_record in ipairs(raw_records) do
    local record = restructure_resource_record(raw_record)
    table.insert(records, record)
  end
  return records
end

---@cast p ResourceDataModule
return p

--#endregion