X Tutup
Skip to content

Add context-based station economic industries#6199

Merged
sturnclaw merged 41 commits intopioneerspacesim:masterfrom
sturnclaw:econ-conditions
Jan 10, 2026
Merged

Add context-based station economic industries#6199
sturnclaw merged 41 commits intopioneerspacesim:masterfrom
sturnclaw:econ-conditions

Conversation

@sturnclaw
Copy link
Member

@sturnclaw sturnclaw commented Aug 4, 2025

In short, this PR finishes the placeholder economic simulation that was introduced in #5474. It replaces the three-factor random roll which determined whether a commodity was imported or exported at a station with a set of context-dependent starport industries which consume and produce goods, adds a local "trade neighborhood" modelling short-hop NPC trading between stations around the same primary body, and models long-term oversaturation of commodity trades at markets.

Please consider this PR an open call for content!

I've provided a basic set of starter industries, but this is by no means a complete set and I would welcome contributions! New industries do not have to have a wholly unique set of commodities; additional variants of existing industries tailored for unique situations (e.g. high-temperature volcanic worlds might have a special metal smelting industry?) are strongly encouraged.

At current, the PR is "feature complete" however there are some aspects I'd like to explore adding before final merge:

  • Add a neighborhood context for condition tags (e.g. propagate the gas giant tag to starports on its moons). Not used at this time. No current use, introduces hierarchical constraints.
  • Add govtype condition tags to system-wide context. (This would allow for government or economy-specific industries, e.g. Collective Industry for communist govtypes instead of Civil Industry.) Not used at this time. Trivial to add.
  • Add a more intelligent system for selecting starport industries. Current thought is a set of "upgrade trees" which are predicated on condition tags (e.g. build ore mine, then build refinery, then build heavy industry). Starport industries would be selected from the valid set of upgrade trees. Implemented as per-industry build-next list, with condition tag and random-chance support.
  • Balancing existing commodity prices and quantities.
  • Adding additional commodities to round out production chains and create more rational supply/demand networks. (e.g. Rare Ores, Luxury Goods, medical precursors that aren't food, etc...)
  • Displaying industries present at a station in the map screens and on the station's comms page. Not relevant at this time.
  • Write a full system description for developers in codedoc.
  • Write a full system description for modders / content authors in devdocs.

The condition tags system should be somewhat self-documenting; it works by comparing named fields of the SystemBody object to a literal number or string. A few additional condition tags are directly injected into the context evaluated by industries so as to reduce the number of custom-authored condition definitions. An additional documentation pass is probably required on the conditions system, as Conditions.lua is somewhat lacking in documentation.

Copy link
Contributor

@mwerle mwerle left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Initial quick look, no playtesting yet.

Some questions, a few nitpicks. Overall LGTM (as far as I understand what's going on, which isn't very). Would appreciate some more detailed docs of how this is all supposed to work so reviews can compare against the design.

-- be imported from distant planets or via interstellar trade.
--

local AU = 149598000000
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nitpick:

Common constants should really be somewhere centralised.. (utils?)

@Bodasey
Copy link

Bodasey commented Aug 4, 2025

Hard to contribute something without visualisation...but let's try some thoughts, hoping they are what you are looking for.

  • Adding additional commodities to round out production chains

We can make a commodity of every chemical element and base chemical compound (CH4, NH3, H2O, CO2, SiO2, FeO2, ...) depending on how detailed we want to model space mining and trade. E.g. "fertilizer" yet is a tailor made mixture of mainly Nitrogen, Phosphor, Kalium and other elements for different plants and environments.

Condition tags? Ok, let's list some natural resources on the bodies for the surface, crust, hydrosphere and atmosphere.

  • Add a neighborhood context for condition tags (e.g. propagate the gas giant tag to starports on its moons).

Can be made, but even Hydrogen needs to be scooped and transported, and what about Venus and her CO2? => extended scoop equipment and even scoop missions?

Condition tags have to include type and intensity of energy sources (electric current from magnetic fields, wind, geothermal energy, solar radiation).

  • Add a more intelligent system for selecting starport industries.

Ok, I appreciate your model as intelligent enough if it generates a starport in the orbit around Venus who processes CO2 from her atmosphere with H2 from the outer solar system to Carbon ore and plastics with O2 as byproduct, or even better imports H2O from ice moons to get the H2 from fuel cells because you can directly use electric current from more than 2000W/m2 solar radiation which is far more efficient than the 1340W/m2 we get in Earth's orbit. O2 may then be shipped back to the gas giants to be used in fuel cells, which could be another additional commodity. And oh yes, fuel cells are a source of energy to be tagged if no other source is available, meaning a demand for H2 and O2.

(Airships would be a better solution to scoop gas for permanent industrial supply, shall we model them as orbiting objects?)

@sturnclaw
Copy link
Member Author

We can make a commodity of every chemical element and base chemical compound

I appreciate the enthusiasm, but this is definitely not the direction we want to go. New commodities should be added because they fill a logical "gap" in a production chain or in commodity pricing, i.e. adding a "Chemicals" commodity produced at a refinery and consumed at a laboratory, or adding a high-value commodity to fill the gap between Robots and Precious Metals.

Can be made, but even Hydrogen needs to be scooped and transported, and what about Venus and her CO2? => extended scoop equipment and even scoop missions?

Adding additional mission types, equipment, etc. is decidedly outside of the scope of this PR. It is the underlying assumption of this economic simulation that this sort of NPC trade is happening "in the background", and making these equilibrium activities visible to the player is a different topic.

if it generates a starport in the orbit around Venus who processes CO2 from her atmosphere with H2 from the outer solar system to Carbon ore and plastics with O2 as byproduct, or even better imports H2O from ice moons to get the H2 from fuel cells because you can directly use electric current from more than 2000W/m2 solar radiation which is far more efficient than the 1340W/m2 we get in Earth's orbit. O2 may then be shipped back to the gas giants to be used in fuel cells, which could be another additional commodity. And oh yes, fuel cells are a source of energy to be tagged if no other source is available, meaning a demand for H2 and O2.

Condensing solid commodities from atmospheric gas is unlikely to be efficient enough to make a material difference to trade. Energy is not addressed by this economic simulation, as it is assumed that solar power and advanced microfusion using H2 provides more than enough power for industrial purposes.

For the most part, the complexity of simulation you describe above is not the focus of Pioneer. It can certainly be implied that all of this is happening in the background, carried out by the millions of people who inhabit star systems, but Pioneer is not a "tycoon" or economic-resource-management game and the player owning and managing a space station, etc. is a stated anti-goal of the project.

@sturnclaw
Copy link
Member Author

Here's the very short skeleton of the high-level design of this system for review purposes:

  1. Conditions are a data-driven way for mods (and the base game!) to express named semantics about individual bodies. They are meant to eventually be determined at system generation time in C++. Because they have access to a random number generator, they can be used by more than just the economic system; for example, conditions can be used as a way to designate planets with valuable flora/fauna (for scanning missions), rare ores (for @impaktor's mining machinery) or any other kind of "planetary feature" developers/modders can think of.

  2. Industries express the economic endeavors of a (logical) subregion of a starport. For surface ports, this is a number of buildings, for orbitals it's a chunk of the ring. Starports have a certain number of industry "slots" based on their population. Workforce is an abstract logarithmic quantity meant to express the amount of population required to operate an industry, but currently has no interaction with any of the systems in this PR.

  3. Each industry expresses its production and consumption in a dimensionless logarithmic rate quantity called "flow". The rules for flow are simple, but intentionally inconsistent. An industry which produces a commodity with flow N can supply one other industry at that station with demand flow N, and two or more industries each with demand flow N-1. Two or more industries with supply flow N can supply a single industry with demand flow N+1, but can never satisfy an industry with demand flow N+2. The precise base of the logarithm used in flow is intentionally not defined, but varies from 2 to 10+.

    This "rule quirk" regarding industries satisfying N+1 demand is meant to provide a meaningful (if mostly invisible) effect to randomly generating multiple industries which produce or consume the same commodity at the same rate. Its concrete effect is that the rare station which consumes 6 flow of ore twice will have a higher sell price for ore than a station which only has one industry which consumes 6 flow of ore.

  4. Flow is converted to a physical quantity via the supply/demand rates. The natural logarithm is used to determine how many discrete units of a commodity the station produces and consumes over an intentionally undefined period of time. Supply/demand rates determine the trade price of a commodity at a station, and are affected by the market's history value which records the player's interactions with the market.

  5. All stations are assumed (currently) to be at an implicit equilibrium. This means that all commodity demand will be satisfied, regardless of how much of that demand is actually produced at the station. This is modeled via two mechanics: local and interstellar trade. Local trade allows any surplus flow (flow that meets or exceeds indigenous demand) from a nearby station to be consumed by the station with a deficit, and is imported at lower prices. Interstellar trade is the assumed source of the remaining deficit not satisfied by local trade, and is imported at significantly higher prices. Both local and interstellar trade are currently assumed to be happening in the background, and the responsibility for "visualizing" this process by instantiating NPCs is left to other modules like TradeShips.

@Bodasey
Copy link

Bodasey commented Aug 5, 2025

Pioneer is not a "tycoon" or economic-resource-management game and the player owning and managing a space station, etc. is a stated anti-goal of the project.

As long as there are tradeable goods, you can play Pioneer in a "Transport Tycoon" or "Simutrans" mode...

Condensing solid commodities from atmospheric gas is unlikely to be efficient enough to make a material difference to trade.

Maybe it is if you don't have an Earth nearby full of accumulated fossil carbon - or maybe it is if you have an Earth nearby with a mankind who finally has learnt the lesson how to handle them wisely...

Demanding Efficiency would, in the end, mean that spaceports must be generated by an economy simulation code based on natural resources. Even the starports on earth are mostly at the wrong place.

To make suggestions for what you want: What is the wished and upper limit target quantity of industries and tradeable commodities? How are byproducts handled, means can industries have more than one commodity as output, more than two commodities as output, as rubbish as commodity yet exists?

@sturnclaw
Copy link
Member Author

To make suggestions for what you want: What is the wished and upper limit target quantity of industries and tradeable commodities? How are byproducts handled, means can industries have more than one commodity as output, more than two commodities as output, as rubbish as commodity yet exists?

The number of industry definitions has no hard limit. Avoiding too much granularity at this stage is desired (i.e. don't add a Mining Machinery Factory industry) as the industry system and number of discrete industries at a station are currently balanced around somewhat generic aggregations of multiple factories/companies/buildings into a logical "industry type".

As mentioned above, the number of commodities is something I'd like to avoid bloating, to keep each commodity feeling like it has an "identity" rather than disappearing into a sea of incredibly specific commodities. Additions for commodities should have a clear and defensible purpose.

Industries have any number of input and output commodities. Condition tags can be associated with modifiers to an industry's input and output commodities, which can increase and decrease commodity quantity and add new I/O commodities entirely.

- Returns the path relative to the file source (without the protocol part) for use with existing file APIs which take a legacy path.
- Provide more consistent profit margins and station stocking of low-value commodities.
- Conditions allow expressing body attributes as named boolean values for efficient selection/restriction of industries.
- Conditions represent a data-driven way to associate semantic names with specific value thresholds for bodies and systems.
- Conditions represent "local conditions" at a specific starport, and are chained together, combining system -> parent planet -> starport conditions.
- An Industry is a representative of one or more economic producers which present at a starport, and are the primary mechanism by which starports are differentiated from each other.
- Each Industry has a set of commodity input values which it consumes in the course of its work, and a set of outputs which it likewise produces.
- Input/output values are specified in a non-physical "flow" value representing orders of magnitude over an unspecified time unit.
- Starport economies are based on the aggregate of all Industries present at their location, plus the effects of their Population, a special Industry.
-  l10n_key values for industries are not currently used and do not have a language resource.
- workforce values for industries are not currently used.
- population.json is a special definition which defines the commodity inputs/outputs for a size 1 starport.
- Basic commodity coverage has been provided, but the list of industries is by no means exhaustive.
- Industrial supply and demand is used to inform commodity stock availability and price.
- Local supply networks model realistic saturation of local trade, yielding economic opportunitities for the player to import goods from other networks.
- Flow units are used to express commodity trade over an indeterminate standard time period, and are related to instantaneous stock quantities by powers of e.
- Add a debug interface for economic conditions showing domestic supply/demand numbers, local supply network effects, and stock equilibrium and price values.
- Each station tracks supply, demand, and current stock levels for each commodity.
- These levels are constantly changing at a configurable rate, yielding a market that feels "alive" yet remains close to equilibrium over a sufficiently long time period
- The current supply and demand values influence commodity pricing, perturbing the profitability of trades slightly over time.
- The system is intended to support injecting external events which affect supply/demand/stock levels.
- The first such external event is the player's "history register" which records buy/sell amounts per-commodity and perturbs the price of goods over a long timescale.
  This behavior is intended to encourage the player to run multiple different trade routes, and prevents trade gameplay from devolving to a singular maximally-profitable route.
- Differentiate between persistent and transient commodity markets; persistent markets receive updates and are serialized in the savefile.
- Transient markets are intended for generating data for distant systems, for use by e.g. the trade computer.
- Implement market serialization, including an optimization that saves ~50kb in a Sol start.
- All markets in the current system are stored as persistent markets and receive updates at runtime.
- The commodity market widget and commodity price debug screen have not yet received updates for the new economy semantics.
- Modify supply/demand values rather than commodity stocks directly.
- The economic simulation tracks demand as an instantaneous rate, rather than a discrete quantity.
  Consequently, there is no longer a demand limit on how many goods the player can sell to the market; instead, the player's actions are recorded to persistent history and influence the commodity price.
- Also fix mis-spellings of the medicines commodity ID.
- The prior concept of demand as an instantaneous quantity has been removed and replaced with a rate value; this means demand is no longer needed as a SpaceStation API.
- Update CMakeLists.txt to invoke NaturalDocs with modern options.
- Update codedoc workflow to use options from ND project file, and use ND 2.3.1.
- Update gitignore for new NaturalDocs working directory.
- Both functions can be used to generate an array from the key-part or value-part of a table.
- Filter predicate is optional on both functions.
- CPPEconomyInfo is likely to be deprecated once condition-based economies are hoisted to C++ code.
- CPPCommodityInfo will likely be read as raw JSON instead of a special structure.
- Meant to fill the gap between carbon ore and medicines, chemicals are produced from organic and inorganic sources.
- They replace grain as the input to a number of industries.
- Medicines and industrial equipment are made more expensive, and chemicals take the price point previously assigned to ind. equipment.
- This value was originally intended to drive station population based on industry, or to compute the commodity consumption of the population at the station, or to restrict industries based on the station's population.
- It has not been used and no concrete plan exists to make it relevant to the current state of starport generation.
- This allows modelling some level of intelligent design and planning when generating starport industries, allowing human authors to express relationships between industries.
- Only a single industry can be built from the list.
- The list of industries is evaluated every time an industry is selected, including for industries that were built as a follow-on  industry.
- Condition tags can be used to optionally filter the choice of industry.
- The percentage-based chance system provides variance between stations on the same body, keeping industry selection from appearing identical or guaranteed. A default chance of 50% is applied for each item if not specified.
- Currently only works for Latin names due to string.upper's lack of support for UTF-8.
- Returns a commodity name capitalized to serve as a label or standalone list item.
- Better handling for commodity-route bookmarks.
- Add button to bookmark route destination as well as origin.
- Better sorting of bookmarks with routes.
- Fix error when displaying a commodity bookmark with an unknown commodity.
- Fix formatting of economic indicator icons.
- Normalize stylistic conventions with other sidebar widgets (use of framing, child window padding, etc.)
- Update debug mode to work with new economic simulation. Now displays equilibrium prices of stations in the selected system, caches station market data, and autoloads the current station's data.
- Debug mode does not display the current persistent market state at the given station. It only displays what the market state would be if initialized at the present time.
- Metal alloys are more expensive per-ton than their ores.
- Battle weapons fit between slaves precious metals as the second-most expensive commodity per-ton.
- Textiles and fertilizer are more expensive per ton.
- Farm machinery was absurdly cheap per ton. Given it includes the catch-all of hydroponics and outdoor agricultural equipment, boosted to between industrial machinery and robots.
- These price changes are intended to reflect the production and consumption quantities used in the industry simulation. The lower the maximum production amount of a commodity, the more expensive it should be (with variance to account for desirability, monopoly, etc.)
@sturnclaw
Copy link
Member Author

sturnclaw commented Jan 5, 2026

I am happy with this branch as-is. I've addressed all of the TODOs I had, improved the selection process for starport industries, tweaked balance on commodity prices and flows, and added a new commodity, Chemicals.

Chemicals are used as an intermediate step between grain/carbon ore and medicines, robots, and more. They occupy the price point Industrial Machinery had prior, with both industrial and farm machinery receiving a large boost in price to match their relatively small supply and demand quantities.

This branch attempts to remain a balance between commodity price and availability, with more widely produced commodities receiving lower prices. Additionally, the changes to commodity restock and long-term effects on supply and demand mean that higher-priced commodities are not necessarily going to be widely tradeable in large quantities (though the effectively infinite nature of inhabited space does limit the amount of impact any one station's market will have on trade viability).

I will not expect a rigorous re-review. I intend to document the data formats introduced in this PR more thoroughly in a content-creation page on the devdocs, but I will not be waiting on that for merge.

! I intend to merge this PR no later than Friday, Jan 09 to allow adequate time for bugs to be found !

@impaktor this will likely be a headlining feature for the release notes with multiple points related to how the economy now works. Please ping me on IRC once you start drafting the notes and I'll try to write a player-comprehensible introduction to the economy sim.

@sturnclaw sturnclaw linked an issue Jan 5, 2026 that may be closed by this pull request
@sturnclaw sturnclaw merged commit 6db612f into pioneerspacesim:master Jan 10, 2026
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Traders' stock/demand values don't get updated on sell or purchase

4 participants

X Tutup